【Ionic+AngularJS 开发】之『个人日常管理』App(二)

准备工作

资源

预装工具

安装bower

 npm install -g bower

 
安装ngCordova

bower install ngCordova

 
(*由于网络获取资源的原因,后面几次建项目后都无法下载到,自己便复制了原来的ngCordova目录(到YourProjectwwwwlib目录下),发现也是可以使用的)


下载好后,在项目的index.hmtl进行引用:

<script src="lib/ngCordova/dist/ng-cordova.js">

日历工具

FullCalendar

安装插件

本项目需要(安装)的插件有:

插件名说明扩展阅读
cordova-plugin-x-toast 消息提示,使用方法如:$cordovaToast.showShortBottom('屏幕下方提示');
(*仅限平台运行,浏览器调试无效,所以在PC调试时应注意其引起的错误而导致后面代码没执行)
cordova ionic消息提示
cordova-sqlite-storage sqlite数据库 cordova调用本地SQLite数据库的方法
more...
cordova-plugin-x-socialsharing 内容分享  


插件的安装基本命令是:

 cordova plugin add XXXX

 
安装好后可在YourProjectwwwwlib目录下看到新增的插件目录,这样就可以在项目中引用了(不用使用<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                 // 执行sql
100                 _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                         Delete
23                     </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>&nbsp;
39                     <input type="date" ng-model="currDA.RecordDate">
40                 </div>
41                 <div class="item item-input-inset">
42                     <select
43                             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>&nbsp;
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>&nbsp;
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=" 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                         Save
68                     </button>
69                 </div>
70             </ion-content>
71         </ion-modal-view>
72     </script>
73 </ion-view>
View Code

JavaScript部分

  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.SuitType
169                     , $scope.currDA.ItemText
170                     , _moneyFlowDirection
171                     , $scope.currDA.Cash
172                     , '我的钱包'
173                     , dateFormat($scope.currDA.RecordDate, 'ymd')
174                     , $scope.currDA.Remark
175                 );
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.id
192                                     , $scope.currDA.SuitType
193                                     , $scope.currDA.ItemText
194                                     , _moneyFlowDirection
195                                     , $scope.currDA.Cash
196                                     , '我的钱包'
197                                     , dateFormat($scope.currDA.RecordDate, 'ymd')
198                                     , $scope.currDA.Remark
199                                 );
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         // start
247         $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>&nbsp;
19                         <span>{{act.tDate}}</span>
20                     </label>
21                     &nbsp;
22                     <span>{{act.id}}</span>
23                     &nbsp;
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 Code

JavaScript部分

  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.Remark
100             );
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('
','|').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         // start
198         $scope.initData();
199 
200     }])
201 ;
View Code

说明:

  • 日常数据的录入,采用了“即变即更新”的模式,这里使用$watch函数来监听数据变化。同时为了数据更新功能的便利性,在用户点击某一日弹框时,自动判断当日数据是否存在,不存在则插入空数据。

打包发布

生成Android平台安装包

使用命令:

cordova platform add android
cordova build android

 (*注意,如果以上步骤出错,常见原因有:

  • 安装的Android SDK和打包的SDK版本不对,下载相应SDK
  • 环境变量没有配置好
  • 安装最新node.js

*附录

【源码文件】

【APK文件】

原文地址:https://www.cnblogs.com/glife/p/PDM2.html