准备工作
资源
预装工具
安装bower
npm install -g bower
安装ngCordovabower install ngCordova
(*由于网络获取资源的原因,后面几次建项目后都无法下载到,自己便复制了原来的ngCordova目录(到YourProject\wwww\lib目录下),发现也是可以使用的)
下载好后,在项目的index.hmtl进行引用:<script src="lib/ngCordova/dist/ng-cordova.js">日历工具
FullCalendar
安装插件
本项目需要(安装)的插件有:
插件名 说明 扩展阅读 cordova-plugin-x-toast消息提示,使用方法如:$cordovaToast.showShortBottom('屏幕下方提示');
(*仅限平台运行,浏览器调试无效,所以在PC调试时应注意其引起的错误而导致后面代码没执行)cordova ionic消息提示 cordova-sqlite-storagesqlite数据库 cordova调用本地SQLite数据库的方法
more... cordova-plugin-x-socialsharing内容分享
插件的安装基本命令是:cordova plugin add XXXX
安装好后可在YourProject\wwww\lib目录下看到新增的插件目录,这样就可以在项目中引用了(不用使用<script src="xxx">)。
在生成platform后,或需再用cordova prepare该命令用以复制文件到平台(并更改一些xml文件的内容)
概念理解
service服务
AngularJS服务是一种单例对象,其主要功能是为实现应用的功能提供数据和对象,通过直接调用服务,可以将复杂的应用功能进行简化或分块化。 按功能的不同,分为内置服务和自定义服务。
AngularJS提供的常用内置服务有:$scope、$http、$window、$location等
自定义服务主要包含以下两种:
1)使用内置的$provide服务
2)调用模块中的服务注册(如factory、service、constant、value等方法)
本项目主要采用service来创建服务(service方法与factory不同的是,它可以接收一个构造函数)设计与开发
app.js
1 angular.module('pdm' 2 , ['ionic' 3 , 'ngCordova' 4 ]) 5 .config(function ($stateProvider, $urlRouterProvider, $ionicConfigProvider) { 6 7 //在android下,tab位置为top,如果想修改其位置在底部,加上下面一句代码: 8 $ionicConfigProvider.tabs.position('bottom'); 9 10 //... 11 12 }) 13 .run(function ($ionicPlatform) { 14 //... 15 }) 16 17 // 自定义服务:$alertPopup 18 .service('$alertPopup', 19 ['$ionicPopup' 20 , function ($ionicPopup) { 21 return function (content, title) { 22 if (title == undefined || title == null)title = '提示'; 23 var alertPopup = $ionicPopup.alert({ 24 title: title, 25 template: content 26 }); 27 28 alertPopup.then(function (res) { 29 log('alertPopup.then: ' + res); 30 }); 31 } 32 }]) 33 34 // 自定义服务:$db 35 .service('$db', ['$cordovaSQLite', '$alertPopup', '$cordovaToast' 36 , function ($cordovaSQLite, $alertPopup, $cordovaToast) { 37 // 初始化数据表 38 var db = null; 39 try { 40 var _dbName = 'sk'; 41 if (!(window.cordova && window.SQLitePlugin)) { 42 // 创建数据库对象 43 db = window.openDatabase(_dbName, '1.0', _dbName, 100 * 1024 * 1024); 44 45 // web-sql 执行sql方式 46 // 首次创建记账表 47 db.transaction( 48 function (transaction) { 49 transaction.executeSql("CREATE TABLE IF NOT EXISTS Finacial_KeepAccount " + 50 "( id integer primary key" + 51 ", account text " + 52 ", SuitType text " + 53 ", ItemText text " + 54 ", MoneyFlowDirect text " + 55 ", Cash REAL " + 56 ", AccountType text " + 57 ", RecordDate text " + 58 ", Remark text" + 59 ")"); 60 } 61 ); 62 63 // 自定义执行sql方式 64 // 首次创建日常表 65 $cordovaSQLite.execute(db, 'CREATE TABLE IF NOT EXISTS Life_DailyActivity(id integer primary key' + 66 ', account text' + 67 ', Date text' + 68 ', Business text' + 69 ', Study text' + 70 ', Health text' + 71 ', Sport text' + 72 ', Others text' + 73 ', Remark text' + 74 ')'); 75 76 } 77 else { 78 $alertPopup('fail create ' + _dbName + '.db'); 79 } 80 } catch (e) { 81 $alertPopup('fail init: ' + e.toString(), '$db Err'); 82 } 83 84 // 内部函数 85 function db_exec(sql, param, succ_callback, err_callback){ 86 if (param == undefined || param == null) param = []; 87 $cordovaSQLite.execute(db, sql, param) 88 .then(function (rst) { 89 if (succ_callback == undefined)log('exec: ' + sql); 90 else succ_callback(rst); 91 }, function (err) { 92 if (err_callback == undefined)$alertPopup('exec error: ' + err.message); 93 else err_callback(err); 94 }); 95 } 96 97 // 外部可调用接口 98 return { 99 // 执行sql100 _exec: function (sql, param, succ_callback, err_callback) {101 db_exec(sql, param, succ_callback, err_callback);102 },103 // 获取数据104 get: function (tbl, cndt, callback) {105 var sql = 'SELECT * FROM ' + tbl + ' WHERE 1=1 ';106 if (cndt != undefined && cndt != '')sql += (' AND ' + cndt);107 db_exec(sql, [],108 function (rst) {109 var data = [];110 for (var i = 0; i < rst.rows.length; i++) data.push(rst.rows.item(i));111 callback(data);112 });113 },114 // 添加115 add: function (tbl, fields, valueArr, silenceExec) {116 var _param = '';117 for (var i = 0; i < fields.split(',').length; i++)_param += ',?';118 _param = _param.substr(1);119 var sql = 'INSERT INTO ' + tbl + '(' + fields + ') values(' + _param + ')';120 db_exec(sql, valueArr,121 function (rst) {122 if (silenceExec == undefined || silenceExec != true)123 if(!g_debug)124 $cordovaToast.showShortCenter('add to ' + tbl + ' success');125 });126 },127 // 更新128 update: function (tbl, fields, valueArr, cndt, silenceExec) {129 var fv = '';130 var flds = fields.split(',');131 for (var i = 0; i < flds.length; i++) fv += (', ' + flds[i] + '=? ');132 fv = fv.substr(1);133 var sql = 'UPDATE ' + tbl + ' SET ' + fv + ' WHERE ' + cndt;134 db_exec(sql, valueArr,135 function (rst) {136 if (silenceExec == undefined || silenceExec != true)137 if(!g_debug)138 $cordovaToast.showShortCenter('update ' + tbl + ' success');139 });140 },141 // 删除142 delete: function (tbl, cndt, silenceExec) {143 var sql = 'DELETE FROM ' + tbl + ' WHERE ' + cndt;144 db_exec(sql, [],145 function (rst) {146 if (silenceExec == undefined || silenceExec != true)147 if(!g_debug)148 $cordovaToast.showShortCenter('delete from ' + tbl + ' success');149 });150 }151 152 }153 }])154 155 156 ;View Code自定义服务:$alertPopup
为方便项目内调用,对$ionicPopup进行封装,也方便日后扩展。
自定义服务:$db
此$db服务基本就是一个DAL层了,封装了基本的CRUD功能,并根据项目需要做了一些"默认处理"(在程序初始化时,自动创建记账和日常表等)。
(*这个sqlite文件物理路径很难找,有什么方法可以快速定位,还望知道的园友赐教:))记账视图
HTML部分
1 <ion-view view-title="DailyKeeper"> 2 <ion-nav-title><b>记账</b></ion-nav-title> 3 <div class="bar bar-subheader bar-dark"> 4 <h2 class="title"> 5 <a class="button button-icon icon ion-plus-circled" ng-click="showDetail()"></a> 6 </h2> 7 </div> 8 9 <ion-content class="has-tabs has-subheader">10 <ion-list>11 <div ng-repeat="da in dailyAccount">12 <div class="item item-divider" style="display: {{da.ext_displayDivider}}">13 {{da.RecordDate}}14 </div>15 <ion-item class="item-remove-animate item-icon-right"16 type="item-text-wrap" ng-click="showDetail({{da}})" style="color: {{da.ext_TextColor}}">17 【{{da.SuitType}}】{{da.ItemText}}18 <br/>{{da.Cash}}19 <i class="icon ion-chevron-right icon-accessory"></i>20 21 <ion-option-button class="button-assertive" ng-click="remove(da)">22 Delete23 </ion-option-button>24 </ion-item>25 </div>26 </ion-list>27 </ion-content>28 29 <!--弹出内容-->30 <script id="detail.html" type="text/ng-template">31 <ion-modal-view>32 <ion-header-bar>33 <h1 class="title">{{currDA.title}}</h1>34 <button class="button" ng-click="closeDetail()">关闭</button>35 </ion-header-bar>36 <ion-content>37 <div class="item-input-inset">38 <i class="icon ion-android-calendar"></i> 39 <input type="date" ng-model="currDA.RecordDate">40 </div>41 <div class="item item-input-inset">42 <select43 ng-model="currDA.SuitType"44 ng-options="value.SuitType as value.SuitType group by value.MainClass for value in Finacial_SuitClass">45 <option value=""> -账目类型- </option>46 </select> 47 <label class="item-input-wrapper">48 <input type="text" ng-model="currDA.ItemText" placeholder="消费项">49 </label>50 </div>51 <div class="item item-input-inset">52 <label class="item-input-wrapper">53 <input type="number" ng-model="currDA.Cash" placeholder="金额">54 </label> 55 <label class="toggle">56 <input type="checkbox" ng-model="currDA.Income">57 <div class="track">58 <div class="handle"></div>59 </div>60 </label>(入账)61 </div>62 <div class="item item-input-inset">63 <textarea style="width: 100%" ng-model="currDA.Remark" placeholder="备注"></textarea>64 </div>65 <div class="item-input-inset">66 <button class="button button-block button-positive" ng-click="save()">67 Save68 </button>69 </div>70 </ion-content>71 </ion-modal-view>72 </script>73 </ion-view>View CodeJavaScript部分
1 angular.module('pdm') 2 .controller('Ctrl_DailyKeeper', 3 ['$scope', '$ionicModal', '$db', '$cordovaToast', '$ionicPopup', '$alertPopup' 4 , function ($scope, $ionicModal, $db, $cordovaToast, $ionicPopup, $alertPopup) { 5 6 // BLL 7 $scope.getKA = function (callback, cndt) { 8 var sql = "SELECT * FROM Finacial_KeepAccount WHERE 1=1 "; 9 if (cndt != undefined && cndt != '')sql += (' AND ' + cndt); 10 sql += ' ORDER BY RecordDate desc'; 11 $db._exec(sql, [], function (rst) { 12 if (rst.rows.length == 0) { 13 if(!g_debug) 14 $cordovaToast.showShortCenter('load ka success but no data'); 15 //return; 16 } 17 var data = []; 18 for (var i = 0; i < rst.rows.length; i++) data.push(rst.rows.item(i)); 19 callback(data); 20 }); 21 }; 22 $scope.addKA = function (SuitType, ItemText, MoneyFlowDirect, Cash, AccountType, RecordDate, Remark) { 23 $db.add('Finacial_KeepAccount' 24 , 'SuitType,ItemText,MoneyFlowDirect,Cash,AccountType,RecordDate,Remark, account' 25 , [SuitType, ItemText, MoneyFlowDirect, Cash, AccountType, RecordDate, Remark, g_user]); 26 }; 27 $scope.updateKA = function (id, SuitType, ItemText, MoneyFlowDirect, Cash, AccountType, RecordDate, Remark) { 28 $db.update('Finacial_KeepAccount' 29 , 'SuitType,ItemText,MoneyFlowDirect,Cash,AccountType,RecordDate,Remark' 30 , [SuitType, ItemText, MoneyFlowDirect, Cash, AccountType, RecordDate, Remark] 31 , 'id=' + id.toString()); 32 }; 33 $scope.deleteKA = function (id) { 34 $db.delete('Finacial_KeepAccount', 'id=' + id.toString()); 35 }; 36 37 38 $scope.Finacial_SuitClass = [ 39 {MainClass: '基本生活', SuitType: '餐饮饮食'} 40 , {MainClass: '基本生活', SuitType: '柴米油盐'} 41 , {MainClass: '美容化妆', SuitType: '服饰装扮'} 42 , {MainClass: '收入', SuitType: '福利津贴'} 43 , {MainClass: '收入', SuitType: '工资'} 44 , {MainClass: '美容化妆', SuitType: '化妆品美容'} 45 , {MainClass: '交通通讯', SuitType: '话费网费'} 46 , {MainClass: '交通通讯', SuitType: '交通费'} 47 , {MainClass: '人情往来', SuitType: '借出'} 48 , {MainClass: '投资', SuitType: '理财投资'} 49 , {MainClass: '文化娱乐', SuitType: '旅游娱乐'} 50 , {MainClass: '收入', SuitType: '其他收入'} 51 , {MainClass: '其他支出', SuitType: '其他支出'} 52 , {MainClass: '人情往来', SuitType: '人际往来'} 53 , {MainClass: '基本生活', SuitType: '日常用品'} 54 , {MainClass: '文化娱乐', SuitType: '书报音像'} 55 , {MainClass: '文化娱乐', SuitType: '数码产品'} 56 , {MainClass: '基本生活', SuitType: '水果零食'} 57 , {MainClass: '基本生活', SuitType: '物业水电'} 58 , {MainClass: '人情往来', SuitType: '孝敬长辈'} 59 , {MainClass: '基本生活', SuitType: '医药保健'} 60 , {MainClass: '文化娱乐', SuitType: '运动健身'} 61 ]; 62 $scope.currDA = { 63 title: '新增' 64 , id: 0 65 , RecordDate: new Date() 66 , SuitType: '' 67 , ItemText: '' 68 , Cash: 0 69 , Income: false 70 , Remark: '' 71 } 72 73 $scope.arrageData = function () { 74 var _data = $scope.dailyAccount; 75 76 if (_data.length > 0) { 77 _data[0].ext_displayDivider = ''; 78 79 if (_data.length > 1) { 80 var lastDA = _data[0]; 81 for (var i = 1; i < _data.length; i++) { 82 _data[i].ext_displayDivider = 'none'; 83 if (new Date(_data[i].RecordDate) < new Date(lastDA.RecordDate)) { 84 _data[i].ext_displayDivider = ''; 85 lastDA = _data[i]; 86 } 87 } 88 } 89 } 90 }; 91 92 $scope.remove = function (da) { 93 $ionicPopup.confirm({ 94 title: 'Confrim', 95 template: 'Do you really want to delete?', 96 scope: $scope, 97 buttons: [ 98 { 99 text: '<b>Yes</b>',100 type: 'button-positive',101 onTap: function (e) {102 //$scope.dailyAccount.splice($scope.dailyAccount.indexOf(da), 1);103 $scope.deleteKA(da.id);104 $scope.loadDate();105 }106 },107 {108 type: 'button-canceldark',109 text: '<b>Cancel</b>',110 onTap: function (e) {111 console.log('cancel delete');112 }113 }114 ]115 });116 };117 118 $scope.showDetail = function (da) {119 if (da == undefined) {120 // 新增121 $scope.currDA.title = '新增';122 123 $scope.currDA.id = 0;124 $scope.currDA.RecordDate = new Date();125 $scope.currDA.SuitType = '';126 $scope.currDA.ItemText = '';127 $scope.currDA.Cash = 0;128 $scope.currDA.Income = false;129 $scope.currDA.Remark = '';130 } else {131 // 读取132 $scope.currDA.title = '编辑';133 134 $scope.getKA(function (data) {135 if (data.length > 0) {136 var item = data[0];137 138 $scope.currDA.id = item.id;139 $scope.currDA.RecordDate = new Date(item.RecordDate);140 $scope.currDA.SuitType = item.SuitType;141 $scope.currDA.ItemText = item.ItemText;142 $scope.currDA.Cash = item.Cash;143 $scope.currDA.Income = (item.MoneyFlowDirect == '入账');144 $scope.currDA.Remark = item.Remark;145 }146 }147 , ' id = ' + da.id);148 }149 150 $scope.openModal();151 }152 153 $scope.save = function () {154 //log(angular.toJson($scope.currDA));155 156 if ($scope.currDA.SuitType == ''157 || $scope.currDA.SuitType.indexOf('账目类型') >= 0) {158 $alertPopup('账目类型没有选定哦');159 return;160 }161 162 var _moneyFlowDirection = '出账';163 if ($scope.currDA.Income) _moneyFlowDirection = '入账';164 165 if ($scope.currDA.id == 0) {166 // 新增167 $scope.addKA(168 $scope.currDA.SuitType169 , $scope.currDA.ItemText170 , _moneyFlowDirection171 , $scope.currDA.Cash172 , '我的钱包'173 , dateFormat($scope.currDA.RecordDate, 'ymd')174 , $scope.currDA.Remark175 );176 $scope.closeDetail();177 $scope.loadDate();178 }179 else {180 // 更新181 $ionicPopup.confirm({182 title: 'Confrim',183 template: 'Do you really want to update?',184 scope: $scope,185 buttons: [186 {187 text: '<b>Yes</b>',188 type: 'button-positive',189 onTap: function (e) {190 $scope.updateKA(191 $scope.currDA.id192 , $scope.currDA.SuitType193 , $scope.currDA.ItemText194 , _moneyFlowDirection195 , $scope.currDA.Cash196 , '我的钱包'197 , dateFormat($scope.currDA.RecordDate, 'ymd')198 , $scope.currDA.Remark199 );200 $scope.closeDetail();201 $scope.loadDate();202 }203 },204 {205 type: 'button-canceldark',206 text: '<b>Cancel</b>',207 onTap: function (e) {208 console.log('cancel update');209 }210 }211 ]212 });213 }214 }215 216 // 弹窗217 $ionicModal.fromTemplateUrl('detail.html', {218 scope: $scope,219 animation: 'slide-in-up'220 }).then(function (modal) {221 $scope.modal = modal;222 });223 $scope.openModal = function () {224 $scope.modal.show();225 };226 $scope.closeDetail = function () {227 $scope.modal.hide();228 }229 $scope.$on('$destroy', function () {230 $scope.modal.remove();231 });232 233 $scope.loadDate = function () {234 $scope.getKA(function (data) {235 for (var i = 0; i < data.length; i++) {236 var _d = data[i];237 _d['ext_displayDivider'] = 'none';238 _d['ext_TextColor'] = 'black';239 if (_d.MoneyFlowDirect == '入账')_d['ext_TextColor'] = 'blue';240 }241 $scope.dailyAccount = data;242 $scope.arrageData();243 });244 }245 246 // start247 $scope.loadDate();248 249 }])250 ;View Code说明:
arrageData()函数根据(按日期倒序)排序好的数据,设置当日最后一条数据(因为是倒序,所以采用最后一条)的ext_displayDivider属性为none,如此实现在"日期-当日各项收支项"的显示效果--按日分割后来发觉也可以用Ionic的Card,当然也许也有第三方控件可以直接用了。$ionicModal调用的弹窗功能,弹出的是一个完整的页面,本项目为了简便,就直接写在了同页面里"< script id="detail.html" type="text/ng-template">"日常视图
HTML部分
1 <ion-view view-title="DailyActivity"> 2 <ion-nav-title><b>日常</b></ion-nav-title> 3 <ion-content class="has-tabs"> 4 <br/> 5 <div id='calendar'></div> 6 </ion-content> 7 8 <!--弹出内容--> 9 <script id="detail.html" type="text/ng-template">10 <ion-modal-view>11 <ion-header-bar>12 <h1 class="title">活动 / 计划</h1>13 <button class="button" ng-click="closeDetail()">关闭</button>14 </ion-header-bar>15 <ion-content>16 <div class="item-input-inset">17 <label class="item-input-wrapper">18 <i class="icon ion-android-calendar"></i> 19 <span>{{act.tDate}}</span>20 </label>21 22 <span>{{act.id}}</span>23 24 <!--<a class="button button-small" ng-click="save()">Save</a>-->25 </div>26 <div class="list card">27 <div class="item item-divider">28 事务29 </div>30 <div class="item item-body">31 <label class="item-input">32 <textarea style="background-color: whitesmoke" ng-model="act.Business"></textarea>33 </label>34 </div>35 <div class="item item-divider">36 学习37 </div>38 <div class="item item-body">39 <label class="item-input">40 <textarea style="background-color: whitesmoke" ng-model="act.Study"></textarea>41 </label>42 </div>43 <div class="item item-divider">44 健康45 </div>46 <div class="item item-body">47 <label class="item-input">48 <textarea style="background-color: whitesmoke" ng-model="act.Health"></textarea>49 </label>50 </div>51 <div class="item item-divider">52 运动53 </div>54 <div class="item item-body">55 <label class="item-input">56 <textarea style="background-color: whitesmoke" ng-model="act.Sport"></textarea>57 </label>58 </div>59 <div class="item item-divider">60 其他61 </div>62 <div class="item item-body">63 <label class="item-input">64 <textarea style="background-color: whitesmoke" ng-model="act.Others"></textarea>65 </label>66 </div>67 </div>68 </ion-content>69 </ion-modal-view>70 </script>71 </ion-view>View CodeJavaScript部分
1 angular.module('pdm') 2 .controller('Ctrl_DailyActivity', 3 ['$scope', '$ionicModal', '$db', '$cordovaToast', '$alertPopup' 4 , function ($scope, $ionicModal, $db, $cordovaToast, $alertPopup) { 5 6 // BLL 7 $scope.getDA = function (callback, cndt) { 8 var sql = "SELECT * FROM Life_DailyActivity WHERE 1=1 "; 9 if (cndt != undefined && cndt != '')sql += (' AND ' + cndt); 10 sql += ' ORDER BY Date'; 11 $db._exec(sql, [], function (rst) { 12 var data = []; 13 for (var i = 0; i < rst.rows.length; i++) data.push(rst.rows.item(i)); 14 callback(data); 15 }); 16 }; 17 $scope.addDA = function (Date, Business, Study, Health, Sport, Others, Remark, callback) { 18 var tbl = 'Life_DailyActivity'; 19 var fields = 'account,Date,Business,Study,Health,Sport,Others,Remark'; 20 var valueArr = [g_user, Date, Business, Study, Health, Sport, Others, Remark]; 21 var _param = ''; 22 for (var i = 0; i < fields.split(',').length; i++)_param += ',?'; 23 _param = _param.substr(1); 24 var sql = 'INSERT INTO ' + tbl + '(' + fields + ') values(' + _param + ')'; 25 $db._exec(sql, valueArr, 26 function (rst) { 27 if (callback != undefined && callback != null) callback(rst); 28 else $cordovaToast.showShortCenter('add to ' + tbl + ' success'); 29 }); 30 }; 31 $scope.updateDA = function (Date, Business, Study, Health, Sport, Others, Remark) { 32 $db.update('Life_DailyActivity' 33 , 'Business,Study,Health,Sport,Others,Remark' 34 , [Business, Study, Health, Sport, Others, Remark] 35 , "Date='" + Date + "'" 36 , true); 37 } 38 39 40 $scope.editing = false; 41 $scope.act = { 42 id: 0, 43 tDate: dateFormat(new Date(), 'ymd'), 44 Business: '', 45 Study: '', 46 Health: '', 47 Sport: '', 48 Others: '', 49 Remark: '' 50 }; 51 var _lastDate = $scope.act.tDate; 52 53 $scope.loadData = function () { 54 $scope.getDA(function (data) { 55 $scope.act.Business = ''; 56 $scope.act.Study = ''; 57 $scope.act.Health = ''; 58 $scope.act.Sport = ''; 59 $scope.act.Others = ''; 60 $scope.act.Remark = ''; 61 62 if (data.length > 0) { 63 var item = data[0]; 64 $scope.act.id = item.id; 65 $scope.act.Business = item.Business; 66 $scope.act.Study = item.Study; 67 $scope.act.Health = item.Health; 68 $scope.act.Sport = item.Sport; 69 $scope.act.Others = item.Others; 70 $scope.act.Remark = item.Remark; 71 72 if ($scope.act.id > 0) { 73 $db._exec("delete from Life_DailyActivity where Date='" + $scope.act.tDate + "' and id!=" + $scope.act.id); 74 } 75 } else { 76 $scope.addDA($scope.act.tDate 77 , $scope.act.Business 78 , $scope.act.Study 79 , $scope.act.Health 80 , $scope.act.Sport 81 , $scope.act.Others 82 , $scope.act.Remark 83 , function (rst) { 84 $scope.act.id = rst.insertId; 85 } 86 ); 87 } 88 }, 89 "Date='" + $scope.act.tDate + "'"); 90 } 91 92 $scope.save = function () { 93 $scope.updateDA($scope.act.tDate 94 , $scope.act.Business 95 , $scope.act.Study 96 , $scope.act.Health 97 , $scope.act.Sport 98 , $scope.act.Others 99 , $scope.act.Remark100 );101 }102 103 // 监听数据变化104 $scope.$watch('act.Business', function (newValue, oldValue, scope) {105 if ($scope.editing && newValue != oldValue)$scope.save();106 });107 $scope.$watch('act.Study', function (newValue, oldValue, scope) {108 if ($scope.editing && newValue != oldValue)$scope.save();109 });110 $scope.$watch('act.Health', function (newValue, oldValue, scope) {111 if ($scope.editing && newValue != oldValue)$scope.save();112 });113 $scope.$watch('act.Sport', function (newValue, oldValue, scope) {114 if ($scope.editing && newValue != oldValue)$scope.save();115 });116 $scope.$watch('act.Others', function (newValue, oldValue, scope) {117 if ($scope.editing && newValue != oldValue)$scope.save();118 });119 120 121 $scope.initData = function () {122 var events_data = [];123 124 // 日常125 $scope.getDA(function (data) {126 var op = [];127 op['Business'] = '#387EF5';128 op['Study'] = '#FFC900';129 op['Health'] = '#EF473A';130 op['Sport'] = '#33CD5F';131 op['Others'] = '#B2B2B2';132 133 for (var i = 0; i < data.length; i++) {134 var dd = data[i];135 for (var k in op) {136 if (dd[k.toString()] != undefined && dd[k.toString()] != '') {137 var item = [];138 item['color'] = op[k];139 item['title'] = dd[k.toString()].replace('\n','|').substring(0, 10);140 item['start'] = new Date(dd['Date']);141 events_data.push(item);142 }143 }144 }145 146 $('#calendar').fullCalendar('destroy');147 $('#calendar').fullCalendar({148 header: {149 left: 'prev,next today',150 center: 'title',151 right: 'month'//,agendaWeek,agendaDay'152 },153 firstDay: 1,154 events: events_data,155 // 点击空白156 dayClick: function (date, allDay, jsEvent, view) {157 var selDate = $.fullCalendar.formatDate(date, 'yyyy-MM-dd');//格式化日期158 $scope.act.tDate = selDate;159 160 $scope.loadData();161 $scope.openModal();162 },163 //单击事件项时触发164 eventClick: function (calEvent, jsEvent, view) {165 $scope.act.tDate = dateFormat(calEvent.start,'ymd');166 167 $scope.loadData();168 $scope.openModal();169 }170 });171 });172 }173 174 175 // 弹窗176 $ionicModal.fromTemplateUrl('detail.html', {177 scope: $scope,178 animation: 'slide-in-up'179 }).then(function (modal) {180 $scope.modal = modal;181 });182 $scope.openModal = function () {183 $scope.modal.show();184 185 $scope.editing = true;186 };187 $scope.closeDetail = function () {188 $scope.initData();189 $scope.editing = false;190 191 $scope.modal.hide();192 }193 $scope.$on('$destroy', function () {194 $scope.modal.remove();195 });196 197 // start198 $scope.initData();199 200 }])201 ;View Code说明:
日常数据的录入,采用了"即变即更新"的模式,这里使用$watch函数来监听数据变化。同时为了数据更新功能的便利性,在用户点击某一日弹框时,自动判断当日数据是否存在,不存在则插入空数据。扩展阅读AngularJS数据监听函数$watch
打包发布
生成Android平台安装包
使用命令:
cordova platform add androidcordova build android(*注意,如果以上步骤出错,常见原因有:
安装的Android SDK和打包的SDK版本不对,下载相应SDK环境变量没有配置好安装最新node.js)
*附录
【源码文件】
【APK文件】
作者:Ken
出处:http://www.cnblogs.com/glife/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。