apass-opensdk-hugong 1.0.5 → 1.0.7
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/apass/object_.d.ts +86 -0
- package/apass/object_.js +150 -33
- package/index.d.ts +79 -0
- package/index.js +70 -149
- package/package.json +2 -1
- package/readme.md +39 -97
- package/utils/date_.d.ts +35 -0
- package/utils/date_.js +9 -2
- package/utils/file_.d.ts +77 -0
- package/utils/file_.js +29 -9
- package/utils/index.d.ts +44 -0
- package/utils/index.js +49 -6
- package/opensdk/contract.js +0 -17
- package/opensdk/document.js +0 -46
- package/opensdk/employee.js +0 -18
- package/opensdk/users.js +0 -17
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Object_.d.ts
|
|
2
|
+
export = Object_;
|
|
3
|
+
|
|
4
|
+
declare class Object_ {
|
|
5
|
+
constructor(hg: any);
|
|
6
|
+
|
|
7
|
+
/* ===== 查询 ===== */
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 清空表中满足条件的数据
|
|
11
|
+
* @param table 表名
|
|
12
|
+
* @param where 条件对象;省略时全部清空
|
|
13
|
+
*/
|
|
14
|
+
clearData(table: string, where?: any): Promise<void>;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 查询列表
|
|
18
|
+
* @param table 表名
|
|
19
|
+
* @param field 需要返回的字段,默认 ['_id','_name']
|
|
20
|
+
* @param where 过滤条件
|
|
21
|
+
* @param callback 每批记录回调;提供时方法返回 void
|
|
22
|
+
* @param orderby 排序字段,默认 '_id'
|
|
23
|
+
* @returns 无 callback 时返回全部记录
|
|
24
|
+
*/
|
|
25
|
+
findList<T = any>(
|
|
26
|
+
table: string,
|
|
27
|
+
field?: string[] | null,
|
|
28
|
+
where?: any,
|
|
29
|
+
callback?: (records: T[]) => Promise<void> | void,
|
|
30
|
+
orderby?: string
|
|
31
|
+
): Promise<T[] | void>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 查询单条记录
|
|
35
|
+
*/
|
|
36
|
+
findOne<T = any>(
|
|
37
|
+
table: string,
|
|
38
|
+
field?: string[] | null,
|
|
39
|
+
where?: any
|
|
40
|
+
): Promise<T | null>;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 根据主键查询单条记录
|
|
44
|
+
*/
|
|
45
|
+
findOneById<T = any>(
|
|
46
|
+
table: string,
|
|
47
|
+
id: string | number,
|
|
48
|
+
field?: string[] | null
|
|
49
|
+
): Promise<T | null>;
|
|
50
|
+
|
|
51
|
+
/* ===== 写入 ===== */
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 批量创建
|
|
55
|
+
*/
|
|
56
|
+
batchCreate<T = any>(table: string, list: T[]): Promise<any>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 创建单条记录
|
|
60
|
+
*/
|
|
61
|
+
create<T = any>(table: string, data: T): Promise<any>;
|
|
62
|
+
|
|
63
|
+
/* ===== 更新 ===== */
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 批量更新
|
|
67
|
+
*/
|
|
68
|
+
batchUpdate<T = any>(table: string, list: T[]): Promise<any>;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 更新单条记录
|
|
72
|
+
*/
|
|
73
|
+
update<T = any>(table: string, data: T): Promise<any>;
|
|
74
|
+
|
|
75
|
+
/* ===== 删除 ===== */
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 删除单条记录(按 _id)
|
|
79
|
+
*/
|
|
80
|
+
delete(table: string, _id: string | number): Promise<any>;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 批量删除(按 _ids)
|
|
84
|
+
*/
|
|
85
|
+
delete(table: string, _ids: (string | number)[]): Promise<any>;
|
|
86
|
+
}
|
package/apass/object_.js
CHANGED
|
@@ -1,69 +1,186 @@
|
|
|
1
|
-
class Object_{
|
|
1
|
+
class Object_ {
|
|
2
2
|
#hg = null
|
|
3
|
-
constructor(hg){
|
|
3
|
+
constructor(hg) {
|
|
4
4
|
this.#hg = hg
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* 清空表中满足条件的数据
|
|
9
|
+
* @param table 表名
|
|
10
|
+
* @param where 条件对象;省略时全部清空
|
|
11
|
+
* @param useSystemAuth 是否使用系统权限;默认 false
|
|
12
|
+
*/
|
|
13
|
+
async clearData(table, where, useSystemAuth = false) {
|
|
14
|
+
const object = application.data.object(table).select('_id').where(where ? where : { _id: application.operator.gte(0) })
|
|
15
|
+
if (useSystemAuth) {
|
|
16
|
+
object.useSystemAuth()
|
|
17
|
+
}
|
|
18
|
+
await object.findStream(async records => {
|
|
9
19
|
this.#hg.log4('clear data len', records.length)
|
|
10
|
-
|
|
20
|
+
const object = application.data.object(table)
|
|
21
|
+
if (useSystemAuth) {
|
|
22
|
+
object.useSystemAuth()
|
|
23
|
+
}
|
|
24
|
+
await object.batchDelete(records.map(it => ({ _id: it._id })))
|
|
11
25
|
})
|
|
12
26
|
}
|
|
13
27
|
|
|
14
|
-
|
|
28
|
+
/**
|
|
29
|
+
* 查询列表
|
|
30
|
+
* @param table 表名
|
|
31
|
+
* @param field 需要返回的字段,默认 ['_id','_name']
|
|
32
|
+
* @param where 过滤条件
|
|
33
|
+
* @param callback 每批记录回调;提供时方法返回 void
|
|
34
|
+
* @param orderby 排序字段,默认 '_id'
|
|
35
|
+
* @param useSystemAuth 是否使用系统权限;默认 false
|
|
36
|
+
* @returns 无 callback 时返回全部记录
|
|
37
|
+
*/
|
|
38
|
+
async findList(table, fields, where, callback, orderby, useSystemAuth = false) {
|
|
15
39
|
const list = []
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
40
|
+
const object = application.data.object(table).select(fields || ['_id', '_name']).where(where || { _id: application.operator.gte(0) }).orderByDesc(orderby || '_id')
|
|
41
|
+
if (useSystemAuth) {
|
|
42
|
+
object.useSystemAuth()
|
|
43
|
+
}
|
|
44
|
+
await object.findStream(async records => {
|
|
45
|
+
if (callback) {
|
|
46
|
+
this.#hg.log4('find all len', records.length)
|
|
19
47
|
await callback(records)
|
|
20
|
-
}else{
|
|
21
|
-
this.#hg.log4('find all size',
|
|
48
|
+
} else {
|
|
49
|
+
this.#hg.log4('find all size', records.length)
|
|
22
50
|
list.push(...records)
|
|
23
51
|
}
|
|
24
52
|
})
|
|
25
|
-
if(!callback){
|
|
53
|
+
if (!callback) {
|
|
26
54
|
this.#hg.log4('find all len', list.length)
|
|
27
55
|
}
|
|
28
56
|
return list
|
|
29
57
|
}
|
|
30
|
-
|
|
31
|
-
|
|
58
|
+
/**
|
|
59
|
+
* 查询单条记录
|
|
60
|
+
* @param table 表名
|
|
61
|
+
* @param field 需要返回的字段,默认 ['_id','_name']
|
|
62
|
+
* @param where 过滤条件
|
|
63
|
+
* @param useSystemAuth 是否使用系统权限;默认 false
|
|
64
|
+
* @returns 记录对象或 null
|
|
65
|
+
*/
|
|
66
|
+
async findOne(table, fields, where, useSystemAuth = false) {
|
|
67
|
+
const object = application.data.object(table).select(fields || ['_id', '_name']).where(where || { _id: application.operator.gte(0) })
|
|
68
|
+
if (useSystemAuth) {
|
|
69
|
+
object.useSystemAuth()
|
|
70
|
+
}
|
|
71
|
+
return await object.findOne()
|
|
32
72
|
}
|
|
33
|
-
|
|
34
|
-
|
|
73
|
+
/**
|
|
74
|
+
* 根据 ID 查询单条记录
|
|
75
|
+
* @param table 表名
|
|
76
|
+
* @param id 记录 ID
|
|
77
|
+
* @param fields 需要返回的字段,默认 ['_id','_name']
|
|
78
|
+
* @param useSystemAuth 是否使用系统权限;默认 false
|
|
79
|
+
* @returns 记录对象或 null
|
|
80
|
+
*/
|
|
81
|
+
async findOneById(table, id, fields, useSystemAuth = false) {
|
|
82
|
+
const object = application.data.object(table).select(fields || ['_id', '_name']).where({ _id: id })
|
|
83
|
+
if (useSystemAuth) {
|
|
84
|
+
object.useSystemAuth()
|
|
85
|
+
}
|
|
86
|
+
return await object.findOne()
|
|
35
87
|
}
|
|
36
88
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
89
|
+
/**
|
|
90
|
+
* 批量创建记录
|
|
91
|
+
* @param table 表名
|
|
92
|
+
* @param list 记录列表
|
|
93
|
+
* @param useSystemAuth 是否使用系统权限;默认 false
|
|
94
|
+
* @returns 创建的记录 ID 列表或 null
|
|
95
|
+
*/
|
|
96
|
+
async batchCreate(table, list, useSystemAuth = false) {
|
|
97
|
+
if (list.length) {
|
|
98
|
+
const object = application.data.object(table)
|
|
99
|
+
if (useSystemAuth) {
|
|
100
|
+
object.useSystemAuth()
|
|
101
|
+
}
|
|
102
|
+
return await object.batchCreate(list)
|
|
40
103
|
}
|
|
41
104
|
return null
|
|
42
105
|
}
|
|
43
|
-
|
|
44
|
-
|
|
106
|
+
/**
|
|
107
|
+
* 创建单条记录
|
|
108
|
+
* @param table 表名
|
|
109
|
+
* @param data 记录数据
|
|
110
|
+
* @param useSystemAuth 是否使用系统权限;默认 false
|
|
111
|
+
* @returns 创建的记录 ID 或 null
|
|
112
|
+
*/
|
|
113
|
+
async create(table, data, useSystemAuth = false) {
|
|
114
|
+
const object = application.data.object(table)
|
|
115
|
+
if (useSystemAuth) {
|
|
116
|
+
object.useSystemAuth()
|
|
117
|
+
}
|
|
118
|
+
return await object.create(data)
|
|
45
119
|
}
|
|
46
120
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
121
|
+
/**
|
|
122
|
+
* 批量更新记录
|
|
123
|
+
* @param table 表名
|
|
124
|
+
* @param list 记录列表
|
|
125
|
+
* @param useSystemAuth 是否使用系统权限;默认 false
|
|
126
|
+
* @returns 更新的记录 ID 列表或 null
|
|
127
|
+
*/
|
|
128
|
+
async batchUpdate(table, list, useSystemAuth = false) {
|
|
129
|
+
if (list.length) {
|
|
130
|
+
const object = application.data.object(table)
|
|
131
|
+
if (useSystemAuth) {
|
|
132
|
+
object.useSystemAuth()
|
|
133
|
+
}
|
|
134
|
+
return await object.batchUpdate(list)
|
|
50
135
|
}
|
|
51
136
|
return null
|
|
52
137
|
}
|
|
53
|
-
|
|
54
|
-
|
|
138
|
+
/**
|
|
139
|
+
* 更新单条记录
|
|
140
|
+
* @param table 表名
|
|
141
|
+
* @param data 记录数据
|
|
142
|
+
* @param useSystemAuth 是否使用系统权限;默认 false
|
|
143
|
+
* @returns 更新的记录 ID 或 null
|
|
144
|
+
*/
|
|
145
|
+
async update(table, data, useSystemAuth = false) {
|
|
146
|
+
const object = application.data.object(table)
|
|
147
|
+
if (useSystemAuth) {
|
|
148
|
+
object.useSystemAuth()
|
|
149
|
+
}
|
|
150
|
+
return await object.update(data)
|
|
55
151
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
152
|
+
/**
|
|
153
|
+
* 删除单条记录
|
|
154
|
+
* @param table 表名
|
|
155
|
+
* @param _id 记录 ID
|
|
156
|
+
* @param useSystemAuth 是否使用系统权限;默认 false
|
|
157
|
+
* @returns 删除的记录 ID 或 null
|
|
158
|
+
*/
|
|
159
|
+
async deleteOne(table, _id, useSystemAuth = false) {
|
|
160
|
+
const object = application.data.object(table)
|
|
161
|
+
if (useSystemAuth) {
|
|
162
|
+
object.useSystemAuth()
|
|
163
|
+
}
|
|
164
|
+
return await object.delete(_id)
|
|
59
165
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
166
|
+
/**
|
|
167
|
+
* 批量删除记录
|
|
168
|
+
* @param table 表名
|
|
169
|
+
* @param _ids 记录 ID 列表
|
|
170
|
+
* @param useSystemAuth 是否使用系统权限;默认 false
|
|
171
|
+
* @returns 删除的记录 ID 列表或 null
|
|
172
|
+
*/
|
|
173
|
+
async deleteBatchByIds(table, _ids, useSystemAuth = false) {
|
|
174
|
+
if (_ids.length) {
|
|
175
|
+
const object = application.data.object(table)
|
|
176
|
+
if (useSystemAuth) {
|
|
177
|
+
object.useSystemAuth()
|
|
178
|
+
}
|
|
179
|
+
return await object.batchDelete(_ids)
|
|
63
180
|
}
|
|
64
181
|
return null
|
|
65
182
|
}
|
|
66
|
-
|
|
183
|
+
|
|
67
184
|
|
|
68
185
|
}
|
|
69
186
|
module.exports = Object_
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
declare module 'HG' {
|
|
2
|
+
import { AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
3
|
+
|
|
4
|
+
export interface HGLogger {
|
|
5
|
+
log: (...args: any[]) => void;
|
|
6
|
+
error: (...args: any[]) => void;
|
|
7
|
+
warn: (...args: any[]) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface MultilingualData {
|
|
11
|
+
zh?: string;
|
|
12
|
+
en?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default class HG {
|
|
16
|
+
constructor(logger: HGLogger);
|
|
17
|
+
|
|
18
|
+
/* 属性 */
|
|
19
|
+
readonly object: any; // 对应 new Object_(this)
|
|
20
|
+
readonly utils: any; // 对应 new Utils(this)
|
|
21
|
+
private _time: number | null;
|
|
22
|
+
|
|
23
|
+
/* 公有方法 */
|
|
24
|
+
setLogger(logger: HGLogger): Promise<void>;
|
|
25
|
+
|
|
26
|
+
/* 计时相关 */
|
|
27
|
+
timeRun<T = any>(fn?: () => T | Promise<T>): Promise<T>;
|
|
28
|
+
newTime(): void;
|
|
29
|
+
printTime(): void;
|
|
30
|
+
|
|
31
|
+
/* 工具方法 */
|
|
32
|
+
sleep(time?: number): Promise<void>;
|
|
33
|
+
|
|
34
|
+
/* 网络请求 */
|
|
35
|
+
request<T = any>(config: AxiosRequestConfig): Promise<T>;
|
|
36
|
+
axios<T = any>(config: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
37
|
+
|
|
38
|
+
/* 多语言 */
|
|
39
|
+
toMultilingualByOpenPlatform(
|
|
40
|
+
zh: string | any[],
|
|
41
|
+
en?: string
|
|
42
|
+
): application.constants.type.Multilingual;
|
|
43
|
+
|
|
44
|
+
toTextByMultilingual(
|
|
45
|
+
textArr: Array<{ language_code: string; text: string }>
|
|
46
|
+
): string;
|
|
47
|
+
|
|
48
|
+
/* JSON 取值 */
|
|
49
|
+
toValue<T = any>(
|
|
50
|
+
obj: any,
|
|
51
|
+
path: string,
|
|
52
|
+
defaultValue?: T
|
|
53
|
+
): T | undefined;
|
|
54
|
+
|
|
55
|
+
/* 数组辅助 */
|
|
56
|
+
listFind<T = any>(
|
|
57
|
+
list: T[],
|
|
58
|
+
key: keyof T,
|
|
59
|
+
target: any,
|
|
60
|
+
defValue?: T
|
|
61
|
+
): T | undefined;
|
|
62
|
+
|
|
63
|
+
listMap<T = any, K extends keyof T = keyof T>(
|
|
64
|
+
list: T[],
|
|
65
|
+
key: K
|
|
66
|
+
): Array<T[K]>;
|
|
67
|
+
|
|
68
|
+
/* 字符串转数字 */
|
|
69
|
+
textToFloat(textAmount: string | number | null | undefined, defValue?: number): number;
|
|
70
|
+
|
|
71
|
+
/* 日志 */
|
|
72
|
+
log(...arg: any[]): void;
|
|
73
|
+
log4(...arg: any[]): void;
|
|
74
|
+
log8(...arg: any[]): void;
|
|
75
|
+
logm(space: number, ...arg: any[]): void;
|
|
76
|
+
error(...arg: any[]): void;
|
|
77
|
+
warn(...arg: any[]): void;
|
|
78
|
+
}
|
|
79
|
+
}
|
package/index.js
CHANGED
|
@@ -1,25 +1,14 @@
|
|
|
1
|
-
const Users = require('./opensdk/users')
|
|
2
|
-
const Document = require('./opensdk/document')
|
|
3
1
|
const Utils = require('./utils/index')
|
|
4
|
-
const Employee = require('./opensdk/employee')
|
|
5
|
-
const Contract = require('./opensdk/contract')
|
|
6
2
|
const Object_ = require('./apass/object_')
|
|
7
|
-
class HG{
|
|
3
|
+
class HG {
|
|
8
4
|
#logger
|
|
9
|
-
|
|
10
|
-
#app_secret
|
|
11
|
-
constructor(logger){
|
|
5
|
+
constructor(logger) {
|
|
12
6
|
this.setLogger(logger)
|
|
13
|
-
this.users = new Users(this)
|
|
14
|
-
this.document = new Document(this)
|
|
15
|
-
this.employee = new Employee(this)
|
|
16
|
-
this.contract = new Contract(this)
|
|
17
7
|
this.object = new Object_(this)
|
|
18
|
-
|
|
19
8
|
this.utils = new Utils(this)
|
|
20
9
|
this._time = null
|
|
21
10
|
}
|
|
22
|
-
setLogger(logger){
|
|
11
|
+
async setLogger(logger) {
|
|
23
12
|
this.#logger = logger
|
|
24
13
|
}
|
|
25
14
|
/**
|
|
@@ -27,10 +16,10 @@ class HG{
|
|
|
27
16
|
* @param {*} fn
|
|
28
17
|
* @returns
|
|
29
18
|
*/
|
|
30
|
-
async timeRun(fn){
|
|
19
|
+
async timeRun(fn) {
|
|
31
20
|
this.newTime()
|
|
32
21
|
let result = null
|
|
33
|
-
if(fn){
|
|
22
|
+
if (fn) {
|
|
34
23
|
result = await fn()
|
|
35
24
|
}
|
|
36
25
|
this.printTime()
|
|
@@ -41,16 +30,16 @@ class HG{
|
|
|
41
30
|
* @param {*} time 毫秒
|
|
42
31
|
* @returns
|
|
43
32
|
*/
|
|
44
|
-
async sleep(time){
|
|
45
|
-
return new Promise((r)=>setTimeout(()=>{ this.log4(`sleep ${(time || 1000)/1000}s`);r();},time || 1000))
|
|
33
|
+
async sleep(time) {
|
|
34
|
+
return new Promise((r) => setTimeout(() => { this.log4(`sleep ${(time || 1000) / 1000}s`); r(); }, time || 1000))
|
|
46
35
|
}
|
|
47
36
|
|
|
48
37
|
/**
|
|
49
38
|
* 时间计划-记录
|
|
50
39
|
*/
|
|
51
|
-
newTime(){
|
|
52
|
-
if(this._time){
|
|
53
|
-
this.log4('#time reset to before',(Date.now() - this._time)/1000, 's')
|
|
40
|
+
newTime() {
|
|
41
|
+
if (this._time) {
|
|
42
|
+
this.log4('#time reset to before', (Date.now() - this._time) / 1000, 's')
|
|
54
43
|
}
|
|
55
44
|
this.log4('#time reset')
|
|
56
45
|
this._time = Date.now()
|
|
@@ -58,175 +47,107 @@ class HG{
|
|
|
58
47
|
/**
|
|
59
48
|
* 时间计划-打印耗时
|
|
60
49
|
*/
|
|
61
|
-
printTime(){
|
|
62
|
-
if(!this._time){
|
|
63
|
-
return this.#logger.error('#time Error','The time has not been initialized ')
|
|
50
|
+
printTime() {
|
|
51
|
+
if (!this._time) {
|
|
52
|
+
return this.#logger.error('#time Error', 'The time has not been initialized ')
|
|
64
53
|
}
|
|
65
|
-
this.log4('#time',(Date.now() - this._time)/1000, 's')
|
|
54
|
+
this.log4('#time', (Date.now() - this._time) / 1000, 's')
|
|
66
55
|
}
|
|
67
56
|
|
|
68
57
|
/**
|
|
69
|
-
*
|
|
70
|
-
* @param {*}
|
|
71
|
-
* @param {*} app_secret
|
|
72
|
-
*/
|
|
73
|
-
setAppId(app_id,app_secret){
|
|
74
|
-
this.#app_id = app_id
|
|
75
|
-
this.#app_secret = app_secret
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* 开平token
|
|
58
|
+
* 统一网络请求(使用axios)
|
|
59
|
+
* @param {*} config
|
|
80
60
|
* @returns
|
|
81
61
|
*/
|
|
82
|
-
async
|
|
83
|
-
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async requestGet(url, params, headers=true){
|
|
88
|
-
return this.request([url, params], null, headers, 'GET')
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* 统一网络请求
|
|
93
|
-
* @param {*} url
|
|
94
|
-
* @param {*} params
|
|
95
|
-
* @param {*} data
|
|
96
|
-
* @param {*} headers
|
|
97
|
-
* @param {*} method
|
|
98
|
-
* @returns
|
|
99
|
-
*/
|
|
100
|
-
async request(url, data, headers = true, method = 'POST'){
|
|
101
|
-
let newHeaders = { 'Content-Type': 'application/json; charset=utf-8' }
|
|
102
|
-
if(typeof headers === 'boolean' && headers === true){
|
|
103
|
-
newHeaders['Authorization'] = `Bearer ${ await this.getToken() }`
|
|
104
|
-
}else{
|
|
105
|
-
newHeaders = { ...newHeaders,...(headers || {}) }
|
|
106
|
-
}
|
|
107
|
-
this.log4('req =',url,data,newHeaders)
|
|
108
|
-
let _url = url
|
|
109
|
-
let params = null
|
|
110
|
-
if(Array.isArray(url)){
|
|
111
|
-
_url = url[0]
|
|
112
|
-
params = url[1]
|
|
113
|
-
}
|
|
114
|
-
return new Promise((r,s)=>{
|
|
62
|
+
async request(config) {
|
|
63
|
+
this.log4('req =', config)
|
|
64
|
+
return new Promise((r, s) => {
|
|
115
65
|
const now = Date.now()
|
|
116
|
-
axios(
|
|
117
|
-
this.log8('resp =',(Date.now() - now) / 1000, 's',response.status, response.statusText,response.data)
|
|
66
|
+
axios(config).then(response => {
|
|
67
|
+
this.log8('resp =', (Date.now() - now) / 1000, 's', response.status, response.statusText, response.data)
|
|
118
68
|
r(response.data)
|
|
119
|
-
}).catch(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
s(e.response.data)
|
|
69
|
+
}).catch(err => {
|
|
70
|
+
this.#logger.error('resp =', (Date.now() - now) / 1000, 's', err.response.data)
|
|
71
|
+
s(err.response.data)
|
|
123
72
|
})
|
|
124
73
|
})
|
|
125
74
|
}
|
|
126
75
|
/**
|
|
127
|
-
*
|
|
128
|
-
* @param {*}
|
|
129
|
-
* @
|
|
130
|
-
* @param {*} callback callback(items) 结果回调(根据总数可能多次调用)- 可选
|
|
131
|
-
* @returns 如果callback为传递则一次性返回所有的数据
|
|
132
|
-
*/
|
|
133
|
-
async paginatedSearchGet(url,params,callback){
|
|
134
|
-
return this.paginatedSearch(url, params, null, callback, 'GET')
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* 分页返回开放平台数据
|
|
138
|
-
* @param {*} url
|
|
139
|
-
* @param {*} params
|
|
140
|
-
* @param {*} data
|
|
141
|
-
* @param {*} callback callback(items) 结果回调(根据总数可能多次调用)- 可选
|
|
142
|
-
* @returns 如果callback为传递则一次性返回所有的数据
|
|
76
|
+
* 直接调用axios
|
|
77
|
+
* @param {*} config
|
|
78
|
+
* @returns
|
|
143
79
|
*/
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
let page_token = null
|
|
147
|
-
let has_more = false
|
|
148
|
-
do {
|
|
149
|
-
const result = await this.request([url, {...(params || {page_size: 100}), page_token}],data,true,method)
|
|
150
|
-
page_token = result.data.page_token
|
|
151
|
-
has_more = result.data.has_more
|
|
152
|
-
if(callback){
|
|
153
|
-
await callback(result.data.hasOwnProperty('items') ? result.data.items || [] : result.data)
|
|
154
|
-
}else{
|
|
155
|
-
if(result.data.hasOwnProperty('items')){
|
|
156
|
-
list.push(...(result.data.items || []))
|
|
157
|
-
}else{
|
|
158
|
-
list.push(result.data)
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
} while (has_more);
|
|
162
|
-
return list
|
|
80
|
+
axios(config) {
|
|
81
|
+
return axios(config)
|
|
163
82
|
}
|
|
164
|
-
|
|
165
83
|
/**
|
|
166
|
-
* 生成多语言对象
|
|
84
|
+
* 生成多语言对象(将开放平台返回的多语言对象转换为application.constants.type.Multilingual)
|
|
167
85
|
* @param {*} zh
|
|
168
86
|
* @param {*} en
|
|
169
87
|
* @returns
|
|
170
88
|
*/
|
|
171
|
-
|
|
172
|
-
if(Array.isArray(zh)){
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
const _en = this.toSafeValue(zh.find(it=>it.lang == 'en-US'),'value')
|
|
89
|
+
toMultilingualByOpenPlatform(zh, en) {
|
|
90
|
+
if (Array.isArray(zh)) {
|
|
91
|
+
if (zh[0].hasOwnProperty('lang')) {
|
|
92
|
+
const _zh = this.toValue(zh.find(it => it.lang == 'zh-CN'), 'value')
|
|
93
|
+
const _en = this.toValue(zh.find(it => it.lang == 'en-US'), 'value')
|
|
177
94
|
return new application.constants.type.Multilingual({ zh: _zh || _en, en: _en || _zh })
|
|
178
95
|
}
|
|
179
|
-
if(zh[0].hasOwnProperty('locale')){
|
|
180
|
-
const _zh = this.
|
|
181
|
-
const _en = this.
|
|
96
|
+
if (zh[0].hasOwnProperty('locale')) {
|
|
97
|
+
const _zh = this.toValue(zh.find(it => it.locale == 'zh_CN' || it.locale == 'zh-CN'), 'value')
|
|
98
|
+
const _en = this.toValue(zh.find(it => it.locale == 'en_US' || it.locale == 'en-US'), 'value')
|
|
182
99
|
return new application.constants.type.Multilingual({ zh: _zh || _en, en: _en || _zh })
|
|
183
100
|
}
|
|
184
101
|
}
|
|
185
102
|
return new application.constants.type.Multilingual({ zh: zh || en, en: en || zh })
|
|
186
103
|
}
|
|
187
|
-
|
|
188
104
|
/**
|
|
189
|
-
*
|
|
105
|
+
* 从多语言对象中获取中文
|
|
106
|
+
* @param {*} textArr
|
|
107
|
+
* @returns
|
|
108
|
+
*/
|
|
109
|
+
toTextByMultilingual(textArr) {
|
|
110
|
+
if (!textArr || !textArr.length) return '--'
|
|
111
|
+
return textArr.find(it => it.language_code == '2052').text
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 从JSON中根据路径获取值
|
|
190
115
|
* @param {*} obj
|
|
191
|
-
* @param {*}
|
|
192
|
-
* @param {*}
|
|
116
|
+
* @param {*} path
|
|
117
|
+
* @param {*} defaultValue
|
|
193
118
|
* @returns
|
|
194
119
|
*/
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if(!_obj){
|
|
198
|
-
return defValue
|
|
199
|
-
}
|
|
200
|
-
if(!_obj.hasOwnProperty(key)){
|
|
201
|
-
return defValue
|
|
202
|
-
}
|
|
203
|
-
return _obj[key] || defValue
|
|
120
|
+
toValue(obj, path, defaultValue = undefined) {
|
|
121
|
+
return path.split('.').reduce((acc, key) => acc?.[key], obj) ?? defaultValue;
|
|
204
122
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
return list.find(it=>it[ key ] == target) || defValue
|
|
123
|
+
listFind(list, key, target, defValue) {
|
|
124
|
+
return list.find(it => it[key] == target) || defValue
|
|
208
125
|
}
|
|
209
|
-
listMap(list,key){
|
|
210
|
-
return list.map(it=>it[
|
|
126
|
+
listMap(list, key) {
|
|
127
|
+
return list.map(it => it[key])
|
|
211
128
|
}
|
|
212
|
-
|
|
213
|
-
textToFloat(textAmount,defValue = 0) {
|
|
129
|
+
textToFloat(textAmount, defValue = 0) {
|
|
214
130
|
return parseFloat((textAmount || '').replace(/,/g, '') || defValue);
|
|
215
131
|
}
|
|
216
132
|
|
|
217
|
-
log(...arg){
|
|
133
|
+
log(...arg) {
|
|
218
134
|
this.#logger.log(...arg)
|
|
219
135
|
}
|
|
220
|
-
log4(...arg){
|
|
221
|
-
this.logm(4
|
|
136
|
+
log4(...arg) {
|
|
137
|
+
this.logm(4, ...arg)
|
|
222
138
|
}
|
|
223
|
-
log8(...arg){
|
|
224
|
-
this.logm(8
|
|
139
|
+
log8(...arg) {
|
|
140
|
+
this.logm(8, ...arg)
|
|
225
141
|
}
|
|
226
|
-
logm(space
|
|
142
|
+
logm(space, ...arg) {
|
|
227
143
|
const result = ''.padEnd(space, "-");
|
|
228
|
-
this.#logger.log(result
|
|
144
|
+
this.#logger.log(result, ...arg)
|
|
145
|
+
}
|
|
146
|
+
error(...arg) {
|
|
147
|
+
this.#logger.error(...arg)
|
|
148
|
+
}
|
|
149
|
+
warn(...arg) {
|
|
150
|
+
this.#logger.warn(...arg)
|
|
229
151
|
}
|
|
230
|
-
|
|
231
152
|
}
|
|
232
153
|
module.exports = HG
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,56 +1,54 @@
|
|
|
1
1
|
# apass-opensdk-hugong
|
|
2
2
|
## 简介
|
|
3
|
-
apass-opensdk-hugong
|
|
3
|
+
apass-opensdk-hugong 是一个Nodejs的SDK,提供了一些常用的功能
|
|
4
4
|
- 什么人可以使用这个SDK
|
|
5
|
-
- 从事飞书低代码平台(APASS
|
|
5
|
+
- 从事飞书低代码平台(APASS)开发人员.传统Nodejs开发人员.
|
|
6
6
|
|
|
7
7
|
## 安装
|
|
8
8
|
|
|
9
9
|
```
|
|
10
10
|
在飞书低代码平台(云函数)依赖管理-右侧-搜索: apass-opensdk-hugong
|
|
11
|
-
|
|
12
|
-
最近有同学私聊我说Apass无法安装1.0.0以上的包,解决思路: 先安装1.0.0版本,然后打开yarn.lock文件
|
|
13
|
-
====== 找到这一行 =====
|
|
14
|
-
apass-opensdk-hugong@1.0.0:
|
|
15
|
-
version "1.0.0"
|
|
16
|
-
resolved "https://registry.npmmirror.com/apass-opensdk-hugong/-/apass-opensdk-hugong-1.0.0.tgz#ef2d0a19e793358784cb764de4b885fd86befd66"
|
|
17
|
-
integrity sha512-Q8Gpo9v8a/2G43y/Lh2POyDEOcealFuUlGdqGSA9wyfjET4+LWs/PnzK9EB1YZCjQotW7cGO/9a0MiQ6Sgw1LA==
|
|
18
|
-
====== 找到这一行 =====
|
|
19
|
-
|
|
20
|
-
将版本改为最新的版本号后,然后保存,重写部署即可使用NPM源最新的版本
|
|
21
|
-
修改后的yarn.lock文件如下, 一共三处地方:
|
|
22
|
-
apass-opensdk-hugong@1.0.3:
|
|
23
|
-
version "1.0.3"
|
|
24
|
-
resolved "https://registry.npmmirror.com/apass-opensdk-hugong/-/apass-opensdk-hugong-1.0.3.tgz#ef2d0a19e793358784cb764de4b885fd86befd66"
|
|
25
|
-
integrity sha512-Q8Gpo9v8a/2G43y/Lh2POyDEOcealFuUlGdqGSA9wyfjET4+LWs/PnzK9EB1YZCjQotW7cGO/9a0MiQ6Sgw1LA==
|
|
26
11
|
```
|
|
27
12
|
|
|
28
13
|
## 如何使用
|
|
29
14
|
```
|
|
30
15
|
const Hugong = require('apass-opensdk-hugong');
|
|
31
|
-
|
|
16
|
+
初始化(主函数内),函数外不需要入参logger
|
|
32
17
|
const hg = new Hugong(logger)
|
|
18
|
+
|
|
19
|
+
也可以单独初始化logger模块
|
|
20
|
+
hg.setLogger(logger)
|
|
33
21
|
```
|
|
34
22
|
## 常用
|
|
35
23
|
```
|
|
36
|
-
|
|
24
|
+
记录时间
|
|
37
25
|
hg.newTime()
|
|
26
|
+
打印运行时间
|
|
38
27
|
hg.printTime()
|
|
39
28
|
|
|
29
|
+
安全的取值
|
|
30
|
+
hg.toValue({....},'a.b.c','default value')
|
|
31
|
+
|
|
40
32
|
线程睡眠(毫秒)
|
|
41
33
|
await hg.sleep(2000)
|
|
42
34
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
35
|
+
数组操作
|
|
36
|
+
1)生成指定范围的数组
|
|
37
|
+
const rangeValue = hg.utils.range(5,50, 3)
|
|
38
|
+
out=[ 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50 ]
|
|
39
|
+
2)数组分块
|
|
40
|
+
const chunkValue = hg.utils.chunkAll(rangeValue, 5)
|
|
41
|
+
out=[ [ 5, 8, 11, 14, 17 ], [ 20, 23, 26, 29, 32 ], [ 35, 38, 41, 44, 47 ], [ 50 ] ]
|
|
42
|
+
数组分块输出1
|
|
43
|
+
hg.utils.splitArray([....], 5) 输出 [ [50],[50] ]
|
|
44
|
+
out=[ [ 5, 8, 11, 14, 17 ], [ 20, 23, 26, 29, 32 ], [ 35, 38, 41, 44, 47 ], [ 50 ] ]
|
|
45
|
+
数组分块输出2,每次输出50条 处理完成后继续下次执行
|
|
46
|
+
await hg.utils.splitArray([...], 10, async (items)=>{ // do something })
|
|
47
|
+
移除重复项
|
|
48
|
+
hg.utils.unique([1,2,3,1,2,3]) // [1,2,3]
|
|
51
49
|
|
|
52
50
|
```
|
|
53
|
-
##
|
|
51
|
+
## Apass相关,文件上传/下载
|
|
54
52
|
|
|
55
53
|
```
|
|
56
54
|
1)从网络下载文件后上传到飞书租户空间,返回上传后的文件信息
|
|
@@ -61,18 +59,25 @@ await hg.utils.file.downloadFileToUpload(url,{ Authorization: `...`})
|
|
|
61
59
|
saveDataToEnv(data,path)
|
|
62
60
|
|
|
63
61
|
1)从飞书租户空间下载文件到本地环境中
|
|
64
|
-
file_info={ id, mime_type,
|
|
65
|
-
file_path=存储地址可选,不填写则默认当前时间戳
|
|
62
|
+
file_info={ id, mime_type, ...}
|
|
63
|
+
file_path=存储地址可选,不填写则默认当前时间戳
|
|
66
64
|
await hg.utils.file.downloadFileToTmp(fileInfo,file_path)
|
|
65
|
+
如果是token文件
|
|
66
|
+
file_info={ token, mime_type, ...}
|
|
67
|
+
await hg.utils.file.downloadFileByToeknToTmp(file_info,file_path)
|
|
67
68
|
|
|
68
69
|
2)解析csv文件,file_path必须是本地环境的文件路径 /tep/aaa.csv 可以使用上面的方法downloadFileToTmp下载文件到本地环境中
|
|
69
70
|
await hg.utils.file.csvRead(file_path,callback)
|
|
70
71
|
示例1 读取完成后返回数组
|
|
71
72
|
const list = await hg.utils.file.csvRead(file_path)
|
|
72
|
-
示例2
|
|
73
|
+
示例2 读取完成后回调, 超过5000条建议使用此方法防止内存溢出
|
|
73
74
|
await hg.utils.file.csvRead(file_path,async (row)=>{
|
|
74
75
|
// do something
|
|
75
76
|
})
|
|
77
|
+
|
|
78
|
+
3)解析excel文件,file_path必须是本地环境的文件路径 /tep/aaa.xlsx 可以使用上面的方法downloadFileToTmp下载文件到本地环境中
|
|
79
|
+
const list = hg.utils.file.xlsxReaderAll(file_path)
|
|
80
|
+
list是excel所有的内容,建议小文件使用(10M以下),如果是大文件10M以上转换成csv使用上面的方法,亲自测试10万条csv读取正常
|
|
76
81
|
```
|
|
77
82
|
|
|
78
83
|
## 小工具/多语言
|
|
@@ -80,75 +85,12 @@ await hg.utils.file.csvRead(file_path,async (row)=>{
|
|
|
80
85
|
```
|
|
81
86
|
对象数据新增多语言对象
|
|
82
87
|
|
|
83
|
-
生成多语言对象
|
|
84
|
-
hg.
|
|
85
|
-
hg.
|
|
86
|
-
|
|
87
|
-
安全的取值
|
|
88
|
-
hg.toSafeValue(obj={},key,defValue)
|
|
88
|
+
生成多语言对象(将开放平台返回的多语言对象转换为application.constants.type.Multilingual)
|
|
89
|
+
hg.toMultilingualByOpenPlatform([{ lang: 'en-US', value: 'Regular' },{ lang: 'zh-CN', value: '正式' }])
|
|
90
|
+
hg.toMultilingualByOpenPlatform(zh,en)
|
|
89
91
|
|
|
90
92
|
```
|
|
91
93
|
|
|
92
|
-
## 飞书人事
|
|
93
|
-
|
|
94
|
-
搜索员工信息
|
|
95
|
-
|
|
96
|
-
```
|
|
97
|
-
设置appid和appsecret
|
|
98
|
-
await hg.setAppId('cli_000000000','0000000000000')
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* 搜索员工信息
|
|
102
|
-
* @param {*} params
|
|
103
|
-
* @param {*} data
|
|
104
|
-
* @param {*} callback callback(items) 结果回调(根据总数可能多次调用)- 可选
|
|
105
|
-
* @returns 如果callback为传递则一次性返回所有的数据
|
|
106
|
-
*/
|
|
107
|
-
await hg.employee.search(params,data,callback)
|
|
108
|
-
|
|
109
|
-
// 示例[具体参数请参考开放平台定义](https://open.feishu.cn/document/server-docs/corehr-v1/employee/search)
|
|
110
|
-
await hg.employee.search({ page_size:100,user_id_type:'user_id',},{ /* 要查询的字段 */}, async (items)=>{
|
|
111
|
-
// do something 假设服务端有300条数据,每次返回100条,会调用3次, 如果希望一次性返回所有数据,callback传null即可
|
|
112
|
-
})
|
|
113
|
-
const list = await hg.employee.search(params,data) //这将一次性返回所有数据
|
|
114
|
-
```
|
|
115
|
-
## 开放平台分页获取所有数据
|
|
116
|
-
|
|
117
|
-
所有的分页接口都可以使用
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
设置appid和appsecret
|
|
121
|
-
await hg.setAppId('cli_000000000','0000000000000')
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* GET类型接口分页返回开放平台数据
|
|
125
|
-
* @param {*} url
|
|
126
|
-
* @param {*} params
|
|
127
|
-
* @param {*} callback callback(items) 结果回调(根据总数可能多次调用)- 可选
|
|
128
|
-
* @returns callback为null,则一次性返回所有的数据
|
|
129
|
-
*/
|
|
130
|
-
hg.paginatedSearchGet(url,params,callback)
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* POST接口分页返回开放平台数据
|
|
134
|
-
* @param {*} url
|
|
135
|
-
* @param {*} params
|
|
136
|
-
* @param {*} data
|
|
137
|
-
* @param {*} callback callback(items) 结果回调(根据总数可能多次调用)- 可选
|
|
138
|
-
* @returns callback为null,则一次性返回所有的数据
|
|
139
|
-
*/
|
|
140
|
-
await hg.paginatedSearch(url,params,data,callback)
|
|
141
|
-
|
|
142
|
-
示例1
|
|
143
|
-
const list = await hg.paginatedSearchGet(url, params, data)
|
|
144
|
-
示例2
|
|
145
|
-
await hg.paginatedSearchGet(url, params, async (items)=>{
|
|
146
|
-
// do something 假设服务端有300条数据,每次返回100条,会调用3次, 如果希望一次性返回所有数据,callback传null即可
|
|
147
|
-
})
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
94
|
## 交流学习
|
|
153
95
|
|
|
154
96
|
从事飞书低代码平台(APASS)开发人员3年,欢迎交流学习
|
package/utils/date_.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Date_.d.ts
|
|
2
|
+
export = Date_;
|
|
3
|
+
|
|
4
|
+
declare class Date_ {
|
|
5
|
+
constructor(hg: any);
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 把日期字符串解析成时间戳(毫秒)
|
|
9
|
+
*/
|
|
10
|
+
dateStringToTimestamp(dateString: string): number;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 返回 moment-timezone 实例(已默认 Asia/Shanghai)
|
|
14
|
+
*/
|
|
15
|
+
moment(date?: string | number | Date): import('moment-timezone').Moment;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 当前时间按指定格式输出(默认 YYYY-MM-DD HH:mm:ss)
|
|
19
|
+
*/
|
|
20
|
+
nowFormat(format?: string): string;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 把起止日期按指定月份跨度拆分成若干段
|
|
24
|
+
*/
|
|
25
|
+
splitDateRange(
|
|
26
|
+
startDate: string,
|
|
27
|
+
endDate: string,
|
|
28
|
+
splitMonths: number
|
|
29
|
+
): Array<{
|
|
30
|
+
begin: string; // yyyy-mm-dd
|
|
31
|
+
end: string; // yyyy-mm-dd
|
|
32
|
+
len: number; // 实际月份数
|
|
33
|
+
days: number; // 实际天数
|
|
34
|
+
}>;
|
|
35
|
+
}
|
package/utils/date_.js
CHANGED
|
@@ -4,10 +4,17 @@ class Date_{
|
|
|
4
4
|
constructor(hg){
|
|
5
5
|
this.#hg = hg
|
|
6
6
|
}
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
dateStringToTimestamp(dateString){
|
|
9
|
+
const timestamp = Date.parse(dateString);
|
|
10
|
+
//this.#hg.log4(`dateString=${dateString}, timestamp=${timestamp}`)
|
|
11
|
+
return timestamp
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
moment(date){
|
|
8
15
|
const moment = require('moment-timezone');
|
|
9
16
|
moment.tz.setDefault("Asia/Shanghai");
|
|
10
|
-
return moment()
|
|
17
|
+
return moment(date || Date.now())
|
|
11
18
|
}
|
|
12
19
|
nowFormat(format) {
|
|
13
20
|
const moment = require('moment-timezone');
|
package/utils/file_.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// File_.d.ts
|
|
2
|
+
export = File_;
|
|
3
|
+
|
|
4
|
+
declare class File_ {
|
|
5
|
+
constructor(hg: any);
|
|
6
|
+
|
|
7
|
+
/** 生成当前时间文件夹名:yyyy-MM-dd_HH-mm-ss */
|
|
8
|
+
getCurrentTimeFolderName(): string;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 网络下载文件并上传到租户空间
|
|
12
|
+
* @param url 网络文件地址
|
|
13
|
+
* @param header 可选请求头
|
|
14
|
+
* @returns 上传后的文件信息
|
|
15
|
+
*/
|
|
16
|
+
downloadFileToUpload(
|
|
17
|
+
url: string,
|
|
18
|
+
header?: Record<string, string>
|
|
19
|
+
): Promise<FileInfo>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 下载租户空间的文件到环境 tmp 目录
|
|
23
|
+
* @param file_info 文件元数据
|
|
24
|
+
* @param file_path 本地存储路径(可选)
|
|
25
|
+
* @returns 本地文件路径
|
|
26
|
+
*/
|
|
27
|
+
downloadFileToTmp(
|
|
28
|
+
file_info: FileInfo,
|
|
29
|
+
file_path?: string
|
|
30
|
+
): Promise<string>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 使用 token 下载文件到环境 tmp 目录
|
|
34
|
+
* @param file_info 必须包含 token 与 mime_type
|
|
35
|
+
* @param file_path 本地存储路径(可选)
|
|
36
|
+
* @returns 本地文件路径
|
|
37
|
+
*/
|
|
38
|
+
downloadFileByToeknToTmp(
|
|
39
|
+
file_info: Pick<FileInfo, 'token' | 'mime_type'>,
|
|
40
|
+
file_path?: string
|
|
41
|
+
): Promise<string>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 将数据追加写入文件
|
|
45
|
+
* @param data 写入内容
|
|
46
|
+
* @param fileName 文件名(可选)
|
|
47
|
+
*/
|
|
48
|
+
saveDataToEnv(data: string, fileName?: string): void;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 读取 CSV 文件(依赖 csv-parser)
|
|
52
|
+
* @param path 文件路径
|
|
53
|
+
* @param callback 每行回调,返回 void 时一次性返回所有行
|
|
54
|
+
* @returns 无回调时返回全部行
|
|
55
|
+
*/
|
|
56
|
+
csvRead<T = Record<string, any>>(
|
|
57
|
+
path: string,
|
|
58
|
+
callback: (row: T, index: number) => void
|
|
59
|
+
): Promise<void>;
|
|
60
|
+
csvRead<T = Record<string, any>>(path: string): Promise<T[]>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 读取 Excel 文件(依赖 xlsx@0.18.5)
|
|
64
|
+
* @param filePath 文件路径
|
|
65
|
+
* @returns 工作表第一页的全部数据
|
|
66
|
+
*/
|
|
67
|
+
xlsxReaderAll(filePath: string): any[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* ── 依赖类型 ─────────────────────────────── */
|
|
71
|
+
interface FileInfo {
|
|
72
|
+
id?: string;
|
|
73
|
+
token?: string;
|
|
74
|
+
mime_type: string;
|
|
75
|
+
name?: string;
|
|
76
|
+
[key: string]: any;
|
|
77
|
+
}
|
package/utils/file_.js
CHANGED
|
@@ -41,6 +41,13 @@ class File_{
|
|
|
41
41
|
this.#hg.log4(`download success, path=` + _file_path)
|
|
42
42
|
return _file_path
|
|
43
43
|
}
|
|
44
|
+
async downloadFileByToeknToTmp(file_info, file_path){
|
|
45
|
+
this.#hg.log4(`download input=${ JSON.stringify(file_info)}`)
|
|
46
|
+
const _file_path = file_path || `/tmp/${Date.now()}.${ file_info.mime_type }`
|
|
47
|
+
await application.resources.file.download(file_info.token, _file_path);
|
|
48
|
+
this.#hg.log4(`download success, path=` + _file_path)
|
|
49
|
+
return _file_path
|
|
50
|
+
}
|
|
44
51
|
/**
|
|
45
52
|
* 写入文件
|
|
46
53
|
* @param {*} data 写入的内容
|
|
@@ -50,7 +57,7 @@ class File_{
|
|
|
50
57
|
fs.writeFileSync(fileName || `${ Date.now() }.txt`,data, { flag: 'a' })
|
|
51
58
|
}
|
|
52
59
|
/**
|
|
53
|
-
* 读取
|
|
60
|
+
* 读取csv文件(需要安装依赖:csv-parser)
|
|
54
61
|
* @param {*} path
|
|
55
62
|
* @param {*} callback(row) 每一行的回调
|
|
56
63
|
* @returns callback为null时,返回全部读取的结果list
|
|
@@ -59,10 +66,11 @@ class File_{
|
|
|
59
66
|
const csv = require('csv-parser');
|
|
60
67
|
return await new Promise((resolve, reject) => {
|
|
61
68
|
const list = []
|
|
69
|
+
let index = 0
|
|
62
70
|
fs.createReadStream(path).pipe(csv())
|
|
63
71
|
.on('data', (row) => {
|
|
64
72
|
if(callback){
|
|
65
|
-
callback(row)
|
|
73
|
+
callback(row,index++)
|
|
66
74
|
}else{
|
|
67
75
|
list.push(row)
|
|
68
76
|
}
|
|
@@ -76,14 +84,26 @@ class File_{
|
|
|
76
84
|
})
|
|
77
85
|
}
|
|
78
86
|
|
|
79
|
-
|
|
87
|
+
/**
|
|
88
|
+
* 读取Excel文件(需要安装依赖:xlsx@0.18.5)
|
|
89
|
+
* @param {*} filePath
|
|
90
|
+
* @returns 返回文件内容
|
|
91
|
+
*/
|
|
92
|
+
xlsxReaderAll(filePath){
|
|
80
93
|
const XLSX = require('xlsx');
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
94
|
+
let data = []
|
|
95
|
+
try {
|
|
96
|
+
const buffer = fs.readFileSync(filePath)
|
|
97
|
+
const workbook = XLSX.read(buffer, { type: 'buffer' });
|
|
98
|
+
const sheetName = workbook.SheetNames[0];
|
|
99
|
+
this.#hg.log4('Sheet Name:', sheetName);
|
|
100
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
101
|
+
data = XLSX.utils.sheet_to_json(worksheet);
|
|
102
|
+
this.#hg.log4('Data:', data);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
this.#hg.error('xlsxReaderAll - Error parsing Excel file:', error);
|
|
105
|
+
}
|
|
106
|
+
return data
|
|
87
107
|
}
|
|
88
108
|
}
|
|
89
109
|
module.exports = File_
|
package/utils/index.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
|
|
2
|
+
// Utils.d.ts
|
|
3
|
+
export = Utils;
|
|
4
|
+
|
|
5
|
+
declare class Utils {
|
|
6
|
+
constructor(hg: any);
|
|
7
|
+
|
|
8
|
+
/** 网络/文件/日期 子模块 */
|
|
9
|
+
readonly url: import('./url');
|
|
10
|
+
readonly file: import('./file_');
|
|
11
|
+
readonly date: import('./date_');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 数组分块(支持同步/异步回调)
|
|
15
|
+
* @param list 原始数组
|
|
16
|
+
* @param chunkSize 每块长度
|
|
17
|
+
* @param callback 每块回调;如提供,则整体返回 void
|
|
18
|
+
* @returns 无回调时返回分块后的二维数组
|
|
19
|
+
*/
|
|
20
|
+
splitArray<T = any>(
|
|
21
|
+
list: T[],
|
|
22
|
+
chunkSize: number,
|
|
23
|
+
callback?: (batch: T[]) => Promise<void> | void
|
|
24
|
+
): Promise<T[][] | void>;
|
|
25
|
+
|
|
26
|
+
/** 计算字符串 MD5 */
|
|
27
|
+
toMD5(data: string): string;
|
|
28
|
+
|
|
29
|
+
/** 按区域与币种格式化金额 */
|
|
30
|
+
formatCurrency(
|
|
31
|
+
amount: number,
|
|
32
|
+
locale?: string,
|
|
33
|
+
currency?: string
|
|
34
|
+
): string;
|
|
35
|
+
|
|
36
|
+
/** 将数组按固定大小分块(同步) */
|
|
37
|
+
chunkAll<T = any>(arr: T[], size: number): T[][];
|
|
38
|
+
|
|
39
|
+
/** 生成指定步长的数值范围数组 */
|
|
40
|
+
range(start: number, end: number, step?: number): number[];
|
|
41
|
+
|
|
42
|
+
/** 数组去重 */
|
|
43
|
+
unique<T = any>(arr: T[]): T[];
|
|
44
|
+
}
|
package/utils/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
const Url = require('./url')
|
|
2
2
|
const File_ = require('./file_')
|
|
3
3
|
const Date_ = require('./date_')
|
|
4
|
-
class Utils{
|
|
4
|
+
class Utils {
|
|
5
5
|
#hg = null
|
|
6
|
-
constructor(hg){
|
|
6
|
+
constructor(hg) {
|
|
7
7
|
this.#hg = hg
|
|
8
8
|
|
|
9
9
|
this.url = new Url(hg)
|
|
@@ -18,13 +18,13 @@ class Utils{
|
|
|
18
18
|
* @param {*} callback(item) 分割后回调(不传递则方法返回切割长度后的数组)
|
|
19
19
|
* @returns
|
|
20
20
|
*/
|
|
21
|
-
|
|
21
|
+
async splitArray(list, chunkSize, callback) {
|
|
22
22
|
const result = [];
|
|
23
23
|
this.#hg.log4('splitArray len ', list.length)
|
|
24
24
|
for (let i = 0; i < list.length; i += chunkSize) {
|
|
25
25
|
const batch = list.slice(i, i + chunkSize)
|
|
26
|
-
this.#hg.log8('splitArray item ',i, i + chunkSize)
|
|
27
|
-
if(callback){
|
|
26
|
+
this.#hg.log8('splitArray item ', i, i + chunkSize)
|
|
27
|
+
if (callback) {
|
|
28
28
|
await callback(batch)
|
|
29
29
|
continue
|
|
30
30
|
}
|
|
@@ -33,7 +33,7 @@ class Utils{
|
|
|
33
33
|
return result;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
toMD5(data){
|
|
36
|
+
toMD5(data) {
|
|
37
37
|
const crypto = require('crypto');
|
|
38
38
|
const hash = crypto.createHash('md5');
|
|
39
39
|
hash.update(data);
|
|
@@ -42,5 +42,48 @@ class Utils{
|
|
|
42
42
|
return md5Hash
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 格式化货币
|
|
48
|
+
* @param {*} amount
|
|
49
|
+
* @param {*} locale
|
|
50
|
+
* @param {*} currency
|
|
51
|
+
* @returns
|
|
52
|
+
*/
|
|
53
|
+
formatCurrency(amount, locale = 'en-US', currency = 'USD') {
|
|
54
|
+
return new Intl.NumberFormat(locale, { style: 'currency', currency, }).format(amount);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 分块数组
|
|
59
|
+
* @param {*} arr
|
|
60
|
+
* @param {*} size
|
|
61
|
+
* @returns
|
|
62
|
+
*/
|
|
63
|
+
chunkAll(arr, size) {
|
|
64
|
+
return Array.from({ length: Math.ceil(arr.length / size) }, (_, i) => arr.slice(i * size, i * size + size));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 范围生成器
|
|
70
|
+
* @param {*} start
|
|
71
|
+
* @param {*} end
|
|
72
|
+
* @param {*} step
|
|
73
|
+
* @returns
|
|
74
|
+
*/
|
|
75
|
+
range(start, end, step = 1) {
|
|
76
|
+
return Array.from({ length: (end - start) / step + 1 }, (_, i) => start + i * step);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 移除重复项
|
|
81
|
+
* @param {*} arr
|
|
82
|
+
* @returns
|
|
83
|
+
*/
|
|
84
|
+
unique(arr) {
|
|
85
|
+
return [...new Set(arr)];
|
|
86
|
+
}
|
|
87
|
+
|
|
45
88
|
}
|
|
46
89
|
module.exports = Utils
|
package/opensdk/contract.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
class Contract{
|
|
2
|
-
#hg = null
|
|
3
|
-
constructor(hg){
|
|
4
|
-
this.#hg = hg
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* 通过手机号或邮箱获取用户 ID
|
|
9
|
-
* @param {*} user_id_type user_id、open_id、union_id
|
|
10
|
-
* @returns
|
|
11
|
-
*/
|
|
12
|
-
async batch_get_id(data,user_id_type){
|
|
13
|
-
return await this.#hg.request(`https://open.feishu.cn/open-apis/contact/v3/users/batch_get_id?user_id_type=${user_id_type || 'open_id'}`,data,true)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
module.exports = Contract
|
package/opensdk/document.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
class Document{
|
|
2
|
-
#hg = null
|
|
3
|
-
constructor(hg){
|
|
4
|
-
this.#hg = hg
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* 增加协作者权限 https://open.feishu.cn/document/server-docs/docs/permission/permission-member/create
|
|
8
|
-
* @param {*} app_token app_token 多维表格 App 的唯一标识
|
|
9
|
-
* @param {*} type 文件类型 bitable:多维表格
|
|
10
|
-
* @param {*} data {
|
|
11
|
-
"member_type": "openchat",
|
|
12
|
-
"member_id": "oc_b962e8debdc37712a1d60bb97087a8e8",
|
|
13
|
-
"perm": "edit",
|
|
14
|
-
"perm_type": "container",
|
|
15
|
-
"type": "chat"
|
|
16
|
-
}
|
|
17
|
-
*/
|
|
18
|
-
async permissions(app_token,type,data){
|
|
19
|
-
if(!type){
|
|
20
|
-
throw 'type is not empty'
|
|
21
|
-
}
|
|
22
|
-
return await this.#hg.request(`https://open.feishu.cn/open-apis/drive/v1/permissions/${app_token}/members?type=${type}&need_notification=false`,data,true)
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* 复制多维表格 https://open.feishu.cn/document/server-docs/docs/bitable-v1/app/copy
|
|
26
|
-
* @param {*} app_token 要复制的多维表格 App 的唯一标识
|
|
27
|
-
* @param {*} name 多维表格 App 名称。最长为 255 个字符
|
|
28
|
-
* @param {*} folder_token 文件夹
|
|
29
|
-
* @returns
|
|
30
|
-
*/
|
|
31
|
-
async copy(app_token,name,folder_token,without_content,time_zone){
|
|
32
|
-
return await this.#hg.request(`https://open.feishu.cn/open-apis/bitable/v1/apps/${app_token}/copy`,{ name,folder_token,without_content: without_content || false,time_zone: time_zone || 'Asia/Shanghai' },true)
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* 创建多维表格 https://open.feishu.cn/document/server-docs/docs/bitable-v1/app/create
|
|
36
|
-
* @param {*} name 多维表格 App 名称
|
|
37
|
-
* @param {*} folder_token 多维表格 App 归属文件夹
|
|
38
|
-
* @param {*} time_zone
|
|
39
|
-
* @returns
|
|
40
|
-
*/
|
|
41
|
-
async create(name, folder_token, time_zone){
|
|
42
|
-
return await this.#hg.request('https://open.feishu.cn/open-apis/bitable/v1/apps',{ name, folder_token, time_zone: time_zone || 'Asia/Shanghai' },true)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
module.exports = Document
|
package/opensdk/employee.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
class Employee{
|
|
2
|
-
#hg = null
|
|
3
|
-
constructor(hg){
|
|
4
|
-
this.#hg = hg
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* 搜索员工信息
|
|
9
|
-
* @param {*} params
|
|
10
|
-
* @param {*} data
|
|
11
|
-
* @param {*} callback(items) 结果回调(根据总数可能多次调用)
|
|
12
|
-
*/
|
|
13
|
-
async search(params,data,callback){
|
|
14
|
-
return await this.#hg.paginatedSearch(`https://open.feishu.cn/open-apis/corehr/v2/employees/search`,params,data,callback)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
module.exports = Employee
|
package/opensdk/users.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
class Users{
|
|
2
|
-
#hg = null
|
|
3
|
-
constructor(hg){
|
|
4
|
-
this.#hg = hg
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* 通过手机号或邮箱获取用户 ID
|
|
9
|
-
* @param {*} user_id_type user_id、open_id、union_id
|
|
10
|
-
* @returns
|
|
11
|
-
*/
|
|
12
|
-
async batch_get_id(data,user_id_type){
|
|
13
|
-
return await this.#hg.request(`https://open.feishu.cn/open-apis/contact/v3/users/batch_get_id?user_id_type=${user_id_type || 'open_id'}`,data,true)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
module.exports = Users
|