jj.js 0.8.8 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/pagination.js CHANGED
@@ -1,183 +1,222 @@
1
- const {page: cfg_page} = require('./config');
2
- const Context = require('./context');
3
-
4
- class Pagination extends Context
5
- {
6
- constructor(ctx) {
7
- super(ctx);
8
- this._page = 1;
9
- this._pageSize = 10;
10
- this._total = 0;
11
- this._totalPage = 0;
12
- this.init();
13
- }
14
-
15
- // 分页配置
16
- init(options) {
17
- this.options = {...cfg_page, ...options};
18
- this._pageKey = this.options.page_key;
19
- this._keyOrigin = this.options.key_origin;
20
- this._ctxPage = this.ctx
21
- && this.ctx[this._keyOrigin]
22
- && this.ctx[this._keyOrigin][this._pageKey]
23
- && +this.ctx[this._keyOrigin][this._pageKey];
24
- this.page(this._ctxPage);
25
- this.pageSize(this.options.page_size);
26
- return this;
27
- }
28
-
29
- // 设置或获取当前页
30
- page(page) {
31
- if(typeof page != 'undefined') {
32
- this._page = parseInt(page) || 1;
33
- return this;
34
- } else {
35
- return this._page;
36
- }
37
- }
38
-
39
- // 设置或获取分页大小
40
- pageSize(page_size) {
41
- if(page_size) {
42
- this._pageSize = page_size;
43
- return this;
44
- } else {
45
- return this._pageSize;
46
- }
47
- }
48
-
49
- // 设置或获取总数
50
- total(total) {
51
- if(typeof total != 'undefined') {
52
- this._total = parseInt(total) || 0;
53
- return this;
54
- } else {
55
- return this._total;
56
- }
57
- }
58
-
59
- // 渲染html
60
- render(total, page, page_size) {
61
- this.total(total);
62
- this.page(page);
63
- this.pageSize(page_size);
64
- this._totalPage = Math.ceil(this._total / this._pageSize);
65
-
66
- return this._initRule().options['template'].replace(/\$\{(\w+)\}/g, (...args) => {
67
- return this['_' + args[1]]();
68
- });
69
- }
70
-
71
- // 首页
72
- _index() {
73
- return !this._totalPage || this._page == 1 ? '' : this._parseTpl('index_tpl', 1);
74
- }
75
-
76
- // 末页
77
- _end() {
78
- return !this._totalPage || this._page == this._totalPage ? '' : this._parseTpl('end_tpl', this._totalPage);
79
- }
80
-
81
- // 上一页
82
- _prev() {
83
- return !this._totalPage || this._page == 1 ? '' : this._parseTpl('prev_tpl', this._page - 1);
84
- }
85
-
86
- // 下一页
87
- _next() {
88
- return !this._totalPage || this._page == this._totalPage ? '' : this._parseTpl('next_tpl', this._page + 1);
89
- }
90
-
91
- // 信息
92
- _info() {
93
- return this._parseTpl('info_tpl', this._totalPage);
94
- }
95
-
96
- // 分页
97
- _list() {
98
- let list = '';
99
- let list_start = 1;
100
- let list_end = this.options.page_length;
101
- const list_left = parseInt(this.options.page_length / 2);
102
-
103
- if(this._page >= list_end) {
104
- list_start = this._page - list_left;
105
- list_end = this._page + this.options.page_length - list_left - 1;
106
- }
107
- if(list_end > this._totalPage) {
108
- list_end = this._totalPage;
109
- list_start = this._totalPage - this.options.page_length + 1;
110
- }
111
- if(list_start < 1) {
112
- list_start = 1;
113
- }
114
-
115
- for(list_start; list_start <= list_end; list_start++) {
116
- list += this._parseTpl(list_start == this._page ? 'active_tpl' : 'list_tpl', list_start);
117
- }
118
-
119
- return list;
120
- }
121
-
122
- // 解析模块
123
- _parseTpl(tpl_key, num) {
124
- return this.options[tpl_key].replace(/\$\{(\w+)\}/g, (...args) => {
125
- return args[1] == 'url' ? this._parseUrl(num) : args[1] == 'page' ? num : args[1] == 'total' ? this._total : this._totalPage;
126
- });
127
- }
128
-
129
- // 解析网址
130
- _parseUrl(page) {
131
- return (page == 1 ? this._urlIndex : this._urlPage).replace('${page}', page);
132
- }
133
-
134
- // 初始网址规则
135
- _initRule() {
136
- let url_index = this.options.url_index;
137
- let url_page = this.options.url_page;
138
-
139
- if(url_index.slice(0, 1) == ':') {
140
- url_index = this.$url.ruleUrl(url_index.substr(1), {[this._pageKey]: '__page__'}).replace('__page__', '${page}');
141
- }
142
-
143
- if(url_page.slice(0, 1) == ':') {
144
- url_page = this.$url.ruleUrl(url_page.substr(1), {[this._pageKey]: '__page__'}).replace('__page__', '${page}');
145
- }
146
-
147
- if(url_index == '' || url_page == '') {
148
- const url = this.ctx.url;
149
- const arr = url.split('?');
150
- let url_rule = '';
151
- if(this._ctxPage) {
152
- url_rule =
153
- this._keyOrigin == 'query'
154
- ?
155
- url.replace(this._pageKey + '=' + this._page, this._pageKey + '=${page}')
156
- :
157
- arr[0].replace(/(\d+)/g, (...args) => {
158
- return args[1] == this._page ? '${page}' : args[1];
159
- }) + (arr[1] ? ('?' + arr[1]) : '');
160
-
161
- url_index || (url_index = url_rule);
162
- url_page || (url_page = url_rule);
163
- } else {
164
- url_index || (url_index = url);
165
- url_rule =
166
- this._keyOrigin == 'query'
167
- ?
168
- url + (arr[1] ? '&' : '?') + this._pageKey + '=${page}'
169
- :
170
- arr[0].replace(/\/$/g, '') + '/${page}' + (arr[1] ? ('?' + arr[1]) : '');
171
- url_index || (url_index = url);
172
- url_page || (url_page = url_rule);
173
- }
174
- }
175
-
176
- this._urlIndex = url_index;
177
- this._urlPage = url_page;
178
-
179
- return this;
180
- }
181
- }
182
-
1
+ const {page: cfg_page} = require('./config');
2
+ const Context = require('./context');
3
+
4
+ /**
5
+ * @extends Context
6
+ */
7
+ class Pagination extends Context
8
+ {
9
+ /**
10
+ * Initialize a new `Pagination`
11
+ * @public
12
+ * @param {import('../types').KoaCtx} ctx
13
+ */
14
+ constructor(ctx) {
15
+ super(ctx);
16
+ this._page = 1;
17
+ this._pageSize = 10;
18
+ this._total = 0;
19
+ this._totalPage = 0;
20
+ this.init();
21
+ }
22
+
23
+ /**
24
+ * 分页配置
25
+ * @public
26
+ * @param {import('../types').PageConfig} [options]
27
+ * @returns {this}
28
+ */
29
+ init(options) {
30
+ /**
31
+ * @type {import('../types').PageConfig}
32
+ * @private
33
+ */
34
+ this.options = {...cfg_page, ...options};
35
+ this._pageKey = this.options.page_key;
36
+ this._keyOrigin = this.options.key_origin;
37
+ this._ctxPage = this.ctx
38
+ && this.ctx[this._keyOrigin]
39
+ && this.ctx[this._keyOrigin][this._pageKey]
40
+ && +this.ctx[this._keyOrigin][this._pageKey];
41
+ this.page(this._ctxPage);
42
+ this.pageSize(this.options.page_size);
43
+ return this;
44
+ }
45
+
46
+ /**
47
+ * 设置或获取当前页码
48
+ * @public
49
+ * @param {number} [page]
50
+ * @returns {(this|number)}
51
+ */
52
+ page(page) {
53
+ if(typeof page != 'undefined') {
54
+ this._page = page || 1;
55
+ return this;
56
+ } else {
57
+ return this._page;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * 设置或获取分页大小
63
+ * @public
64
+ * @param {number} [page_size]
65
+ * @returns {(this|number)}
66
+ */
67
+ pageSize(page_size) {
68
+ if(page_size) {
69
+ this._pageSize = page_size;
70
+ return this;
71
+ } else {
72
+ return this._pageSize;
73
+ }
74
+ }
75
+
76
+ /**
77
+ * 设置或获取总数
78
+ * @public
79
+ * @param {number} [total]
80
+ * @returns {(this|number)}
81
+ */
82
+ total(total) {
83
+ if(typeof total != 'undefined') {
84
+ this._total = total || 0;
85
+ return this;
86
+ } else {
87
+ return this._total;
88
+ }
89
+ }
90
+
91
+ /**
92
+ * 渲染生成分页html
93
+ * @public
94
+ * @param {number} [total] - 数据总数
95
+ * @param {number} [page] - 当前分页
96
+ * @param {number} [page_size] - 分页大小
97
+ * @returns {string}
98
+ */
99
+ render(total, page, page_size) {
100
+ this.total(total);
101
+ this.page(page);
102
+ this.pageSize(page_size);
103
+ this._totalPage = Math.ceil(this._total / this._pageSize);
104
+
105
+ return this._initRule().options['template'].replace(/\$\{(\w+)\}/g, (...args) => {
106
+ return this['_' + args[1]]();
107
+ });
108
+ }
109
+
110
+ // 首页
111
+ _index() {
112
+ return !this._totalPage || this._page == 1 ? '' : this._parseTpl('index_tpl', 1);
113
+ }
114
+
115
+ // 末页
116
+ _end() {
117
+ return !this._totalPage || this._page == this._totalPage ? '' : this._parseTpl('end_tpl', this._totalPage);
118
+ }
119
+
120
+ // 上一页
121
+ _prev() {
122
+ return !this._totalPage || this._page == 1 ? '' : this._parseTpl('prev_tpl', this._page - 1);
123
+ }
124
+
125
+ // 下一页
126
+ _next() {
127
+ return !this._totalPage || this._page == this._totalPage ? '' : this._parseTpl('next_tpl', this._page + 1);
128
+ }
129
+
130
+ // 信息
131
+ _info() {
132
+ return this._parseTpl('info_tpl', this._totalPage);
133
+ }
134
+
135
+ // 分页
136
+ _list() {
137
+ let list = '';
138
+ let list_start = 1;
139
+ let list_end = this.options.page_length;
140
+ const list_left = this.options.page_length / 2;
141
+
142
+ if(this._page >= list_end) {
143
+ list_start = this._page - list_left;
144
+ list_end = this._page + this.options.page_length - list_left - 1;
145
+ }
146
+ if(list_end > this._totalPage) {
147
+ list_end = this._totalPage;
148
+ list_start = this._totalPage - this.options.page_length + 1;
149
+ }
150
+ if(list_start < 1) {
151
+ list_start = 1;
152
+ }
153
+
154
+ for(list_start; list_start <= list_end; list_start++) {
155
+ list += this._parseTpl(list_start == this._page ? 'active_tpl' : 'list_tpl', list_start);
156
+ }
157
+
158
+ return list;
159
+ }
160
+
161
+ // 解析模块
162
+ _parseTpl(tpl_key, num) {
163
+ return this.options[tpl_key].replace(/\$\{(\w+)\}/g, (...args) => {
164
+ return args[1] == 'url' ? this._parseUrl(num) : args[1] == 'page' ? num : args[1] == 'total' ? this._total : this._totalPage;
165
+ });
166
+ }
167
+
168
+ // 解析网址
169
+ _parseUrl(page) {
170
+ return (page == 1 ? this._urlIndex : this._urlPage).replace('${page}', page);
171
+ }
172
+
173
+ // 初始网址规则
174
+ _initRule() {
175
+ let url_index = this.options.url_index;
176
+ let url_page = this.options.url_page;
177
+
178
+ if(url_index.slice(0, 1) == ':') {
179
+ url_index = this.$url.ruleUrl(url_index.substr(1), {[this._pageKey]: '__page__'}).replace('__page__', '${page}');
180
+ }
181
+
182
+ if(url_page.slice(0, 1) == ':') {
183
+ url_page = this.$url.ruleUrl(url_page.substr(1), {[this._pageKey]: '__page__'}).replace('__page__', '${page}');
184
+ }
185
+
186
+ if(url_index == '' || url_page == '') {
187
+ const url = this.ctx.url;
188
+ const arr = url.split('?');
189
+ let url_rule = '';
190
+ if(this._ctxPage) {
191
+ url_rule =
192
+ this._keyOrigin == 'query'
193
+ ?
194
+ url.replace(this._pageKey + '=' + this._page, this._pageKey + '=${page}')
195
+ :
196
+ arr[0].replace(/(\d+)/g, (...args) => {
197
+ return args[1] == this._page ? '${page}' : args[1];
198
+ }) + (arr[1] ? ('?' + arr[1]) : '');
199
+
200
+ url_index || (url_index = url_rule);
201
+ url_page || (url_page = url_rule);
202
+ } else {
203
+ url_index || (url_index = url);
204
+ url_rule =
205
+ this._keyOrigin == 'query'
206
+ ?
207
+ url + (arr[1] ? '&' : '?') + this._pageKey + '=${page}'
208
+ :
209
+ arr[0].replace(/\/$/g, '') + '/${page}' + (arr[1] ? ('?' + arr[1]) : '');
210
+ url_index || (url_index = url);
211
+ url_page || (url_page = url_rule);
212
+ }
213
+ }
214
+
215
+ this._urlIndex = url_index;
216
+ this._urlPage = url_page;
217
+
218
+ return this;
219
+ }
220
+ }
221
+
183
222
  module.exports = Pagination;
package/lib/response.js CHANGED
@@ -2,61 +2,115 @@ const {tpl: cfg_tpl} = require('./config');
2
2
  const {parseError} = require('./utils/error');
3
3
  const Context = require('./context');
4
4
 
5
+ /**
6
+ * @extends Context
7
+ */
5
8
  class Response extends Context
6
9
  {
10
+ /**
11
+ * Initialize a new `Response`
12
+ * @public
13
+ * @param {import('../types').KoaCtx} ctx
14
+ */
7
15
  constructor(ctx) {
8
16
  super(ctx);
9
- this.tpl_jump = cfg_tpl.jump;
10
- this.wait = 3;
11
- this.tpl_exception = cfg_tpl.exception;
17
+ this._tpl_jump = cfg_tpl.jump;
18
+ this._wait = 3;
19
+ this._tpl_exception = cfg_tpl.exception;
12
20
  }
13
21
 
22
+ /**
23
+ * 直接输出内容
24
+ * @public
25
+ * @param {*} data
26
+ */
14
27
  show(data) {
15
28
  this.ctx.body = data;
16
29
  }
17
30
 
31
+ /**
32
+ * 跳转重定向
33
+ * @public
34
+ * @param {*} url
35
+ * @param {number} status
36
+ */
18
37
  redirect(url, status=302) {
19
38
  this.ctx.status = status;
20
39
  this.ctx.redirect(this.$url.build(url));
21
40
  }
22
41
 
42
+ /**
43
+ * 输出成功提示(html|json)
44
+ * @public
45
+ * @param {(string|object)} [msg]
46
+ * @param {(string|object)} [url]
47
+ */
23
48
  success(msg='操作成功!', url) {
24
49
  typeof msg == 'object' && ([msg, url] = ['操作成功!', msg]);
25
50
  url = typeof url == 'string' ? this.$url.build(url) : (url || this.ctx.header.referer);
26
51
  this.jump(msg, url, 1);
27
52
  }
28
53
 
54
+ /**
55
+ * 输出错误提示(html|json)
56
+ * @public
57
+ * @param {(string|object)} [msg]
58
+ * @param {(string|object)} [url]
59
+ */
29
60
  error(msg='操作失败!', url) {
30
61
  typeof msg == 'object' && ([msg, url] = ['操作失败!', msg]);
31
62
  url = typeof url == 'string' ? this.$url.build(url) : (url || 'javascript:history.back(-1);');
32
63
  this.jump(msg, url, 0);
33
64
  }
34
65
 
66
+ /**
67
+ * jump
68
+ * @api protected
69
+ * @param {(string|object)} msg
70
+ * @param {(string|object)} url
71
+ * @param {number} state
72
+ */
35
73
  jump(msg, url, state=1) {
36
- const tplData = {state, msg, url, wait: this.wait};
37
- this.ctx.body = this.isAjax() ? {state, msg, data: url} : this.tpl_jump.replace(/\{\$(\w+)\}/g, (...args) => {
74
+ const tplData = {state, msg, url, wait: this._wait};
75
+ this.ctx.body = this.isAjax() ? {state, msg, data: url} : this._tpl_jump.replace(/\{\$(\w+)\}/g, (...args) => {
38
76
  return tplData[args[1]];
39
77
  });
40
78
  }
41
79
 
80
+ /**
81
+ * 设置跳转等待时间
82
+ * @public
83
+ * @param {number} time - 单位秒
84
+ * @returns {this}
85
+ */
42
86
  wait(time) {
43
- this.wait = time;
87
+ this._wait = time;
44
88
  return this;
45
89
  }
46
90
 
91
+ /**
92
+ * 输出异常信息(html|json)
93
+ * @public
94
+ * @param {Error} err
95
+ */
47
96
  exception(err) {
48
97
  const escapeHtml = require('escape-html');
49
98
  const tplData = parseError(err);
50
99
  tplData.msg = escapeHtml(tplData.msg);
51
100
  tplData.code = '<span class="line">' + tplData.code.map(str => escapeHtml(str)).join('</span><span class="line">') + '</span>';
52
101
  tplData.stack = tplData.stack.map(str => escapeHtml(str)).join('<br>');
53
- this.ctx.body = this.isAjax() ? {state: 0, msg: tplData.msg} : this.tpl_exception.replace(/\{\$(\w+)\}/g, (...args) => {
102
+ this.ctx.body = this.isAjax() ? {state: 0, msg: tplData.msg} : this._tpl_exception.replace(/\{\$(\w+)\}/g, (...args) => {
54
103
  return tplData[args[1]];
55
104
  });
56
105
  }
57
106
 
107
+ /**
108
+ * 判断是否ajax请求
109
+ * @public
110
+ * @returns {boolean}
111
+ */
58
112
  isAjax() {
59
- return this.ctx.headers['x-requested-with'] && this.ctx.headers['x-requested-with'].toLowerCase() == 'xmlhttprequest'
113
+ return this.ctx.headers['x-requested-with'] && String(this.ctx.headers['x-requested-with']).toLowerCase() == 'xmlhttprequest'
60
114
  || this.ctx.request.type.toLowerCase() == 'application/json'
61
115
  || this.ctx.query.is_ajax
62
116
  || this.ctx.request.body && this.ctx.request.body.is_ajax
package/lib/router.js CHANGED
@@ -1,4 +1,4 @@
1
- const router = require('@koa/router')();
1
+ const router = new (require('@koa/router'));
2
2
  const {app: cfg_app, routes: cfg_routes} = require('./config');
3
3
  const {toLine} = require('./utils/str');
4
4
  const run = require('./run');
@@ -11,7 +11,7 @@ if (cfg_routes) {
11
11
  if(!~methods.indexOf(item.method)) {
12
12
  throw new Error(`RouteError: 未知路由方法:${item.method}`);
13
13
  }
14
- if(typeof item.path === 'function'){
14
+ if(typeof item.path === 'function') {
15
15
  router[item.method](item.url, item.path);
16
16
  continue;
17
17
  }
@@ -39,7 +39,7 @@ router.all(cfg_app.app_multi ? '/:APP?/:CONTROLLER?/:ACTION?' : '/:CONTROLLER?/:
39
39
  delete ctx.params.APP;
40
40
  delete ctx.params.CONTROLLER;
41
41
  delete ctx.params.ACTION;
42
- await run(ctx, next);
42
+ ctx.APP != 'favicon.ico' && ctx.CONTROLLER != 'favicon.ico' && await run(ctx, next);
43
43
  });
44
44
 
45
45
  module.exports = router;
package/lib/run.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const path = require('path');
2
2
  const loader = require('./loader');
3
- const {readFile} = require('./utils/fs');
3
+ const {readFile} = require('fs').promises;
4
4
  const {toHump} = require('./utils/str');
5
5
  const {app: cfg_app, view: cfg_view, db, page, log, cache, cookie, tpl} = require('./config');
6
6
  const compose = require('koa-compose');
@@ -8,11 +8,11 @@ const Logger = require('./logger');
8
8
 
9
9
  async function run(ctx, next, control_type=cfg_app.controller_folder) {
10
10
  if(cfg_app.app_debug) {
11
- Logger.debug(ctx.request);
12
- Logger.debug(`Router(${control_type}): {APP: '${ctx.APP}', CONTROLLER: '${ctx.CONTROLLER}', ACTION: '${ctx.ACTION}'}`);
13
- Object.keys(ctx.params).length && Logger.debug({Params: ctx.params});
14
- Object.keys(ctx.query).length && Logger.debug({Get: ctx.query});
15
- Object.keys(ctx.request.body || {}).length && Logger.debug({Post: ctx.request.body});
11
+ Logger.http('Request:', ctx.request);
12
+ Logger.http(`Router(${control_type}): {APP: '${ctx.APP}', CONTROLLER: '${ctx.CONTROLLER}', ACTION: '${ctx.ACTION}'}`);
13
+ Object.keys(ctx.params).length && Logger.http('Params:', ctx.params);
14
+ Object.keys(ctx.query).length && Logger.http('Get:', ctx.query);
15
+ Object.keys(ctx.request.body || {}).length && Logger.http('Post:', ctx.request.body);
16
16
  }
17
17
 
18
18
  // 设置根加载器