apass-opensdk-hugong 1.0.0 → 1.0.2
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/index.js +107 -7
- package/opensdk/contract.js +19 -0
- package/opensdk/document.js +44 -44
- package/opensdk/employee.js +20 -0
- package/opensdk/users.js +16 -16
- package/package.json +1 -1
- package/readme.md +133 -0
- package/utils/file_.js +81 -0
- package/utils/index.js +41 -0
- package/utils/url.js +20 -0
package/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
const Users = require('./opensdk/users')
|
|
2
2
|
const Document = require('./opensdk/document')
|
|
3
|
+
const Utils = require('./utils/index')
|
|
4
|
+
const Employee = require('./opensdk/employee')
|
|
5
|
+
const Contract = require('./opensdk/contract')
|
|
6
|
+
|
|
3
7
|
class HG{
|
|
4
8
|
#logger
|
|
5
9
|
#app_id
|
|
@@ -8,6 +12,10 @@ class HG{
|
|
|
8
12
|
this.#logger = logger
|
|
9
13
|
this.users = new Users(logger, this)
|
|
10
14
|
this.document = new Document(logger, this)
|
|
15
|
+
this.employee = new Employee(logger, this)
|
|
16
|
+
this.contract = new Contract(logger, this)
|
|
17
|
+
|
|
18
|
+
this.utils = new Utils(logger, this)
|
|
11
19
|
this._time = null
|
|
12
20
|
}
|
|
13
21
|
/**
|
|
@@ -62,41 +70,133 @@ class HG{
|
|
|
62
70
|
this.#app_id = app_id
|
|
63
71
|
this.#app_secret = app_secret
|
|
64
72
|
}
|
|
73
|
+
|
|
65
74
|
/**
|
|
66
75
|
* 开平token
|
|
67
76
|
* @returns
|
|
68
77
|
*/
|
|
69
78
|
async getToken(){
|
|
70
|
-
const result = await this.request('https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal',{ app_id: this.#app_id, app_secret: this.#app_secret})
|
|
79
|
+
const result = await this.request('https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal',{ app_id: this.#app_id, app_secret: this.#app_secret},false)
|
|
71
80
|
return result.tenant_access_token
|
|
72
81
|
}
|
|
73
82
|
|
|
83
|
+
async requestGet(url, params, headers=true){
|
|
84
|
+
return this.request([url, params], null, headers, 'GET')
|
|
85
|
+
}
|
|
86
|
+
|
|
74
87
|
/**
|
|
75
88
|
* 统一网络请求
|
|
76
89
|
* @param {*} url
|
|
90
|
+
* @param {*} params
|
|
77
91
|
* @param {*} data
|
|
78
92
|
* @param {*} headers
|
|
93
|
+
* @param {*} method
|
|
79
94
|
* @returns
|
|
80
95
|
*/
|
|
81
|
-
async request(url, data, headers){
|
|
82
|
-
let
|
|
96
|
+
async request(url, data, headers = true, method = 'POST'){
|
|
97
|
+
let newHeaders = { 'Content-Type': 'application/json; charset=utf-8' }
|
|
83
98
|
if(typeof headers === 'boolean' && headers === true){
|
|
84
|
-
|
|
99
|
+
newHeaders['Authorization'] = `Bearer ${ await this.getToken() }`
|
|
85
100
|
}else{
|
|
86
|
-
|
|
101
|
+
newHeaders = { ...newHeaders,...(headers || {}) }
|
|
102
|
+
}
|
|
103
|
+
this.#logger.log('req=',url,data,newHeaders)
|
|
104
|
+
let _url = url
|
|
105
|
+
let params = null
|
|
106
|
+
if(Array.isArray(url)){
|
|
107
|
+
_url = url[0]
|
|
108
|
+
params = url[1]
|
|
87
109
|
}
|
|
88
|
-
this.#logger.log('req=',url,data,HGheader)
|
|
89
110
|
return new Promise((r,s)=>{
|
|
90
111
|
const now = Date.now()
|
|
91
|
-
axios({ method
|
|
112
|
+
axios({ method, params, url: _url, data, headers: newHeaders}).then(response=>{
|
|
92
113
|
this.#logger.info('resp=',(Date.now() - now) / 1000, 's',response.status, response.statusText,response.data)
|
|
93
114
|
r(response.data)
|
|
94
115
|
}).catch(e=>{
|
|
116
|
+
console.log(e)
|
|
95
117
|
this.#logger.error('resp=',(Date.now() - now) / 1000, 's',e.response.data)
|
|
96
118
|
s(e.response.data)
|
|
97
119
|
})
|
|
98
120
|
})
|
|
99
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* 分页返回开放平台数据
|
|
124
|
+
* @param {*} url
|
|
125
|
+
* @param {*} params
|
|
126
|
+
* @param {*} callback callback(items) 结果回调(根据总数可能多次调用)- 可选
|
|
127
|
+
* @returns 如果callback为传递则一次性返回所有的数据
|
|
128
|
+
*/
|
|
129
|
+
async paginatedSearchGet(url,params,callback){
|
|
130
|
+
return this.paginatedSearch(url, params, null, callback, 'GET')
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 分页返回开放平台数据
|
|
134
|
+
* @param {*} url
|
|
135
|
+
* @param {*} params
|
|
136
|
+
* @param {*} data
|
|
137
|
+
* @param {*} callback callback(items) 结果回调(根据总数可能多次调用)- 可选
|
|
138
|
+
* @returns 如果callback为传递则一次性返回所有的数据
|
|
139
|
+
*/
|
|
140
|
+
async paginatedSearch(url,params,data,callback,method='POST'){
|
|
141
|
+
let list = []
|
|
142
|
+
let page_token = null
|
|
143
|
+
let has_more = false
|
|
144
|
+
do {
|
|
145
|
+
const result = await this.request([url, {...(params || {page_size: 100}), page_token}],data,true,method)
|
|
146
|
+
page_token = result.data.page_token
|
|
147
|
+
has_more = result.data.has_more
|
|
148
|
+
if(callback){
|
|
149
|
+
await callback(result.data.items || [])
|
|
150
|
+
}else{
|
|
151
|
+
list.push(...(result.data.items || []))
|
|
152
|
+
}
|
|
153
|
+
} while (has_more);
|
|
154
|
+
return list
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async getAllUser(field){
|
|
158
|
+
const list = []
|
|
159
|
+
await application.data.object('_user').select(field || ['_id','_name']).findStream(async records=>list.push(...records))
|
|
160
|
+
return list
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* 生成多语言对象
|
|
165
|
+
* @param {*} zh
|
|
166
|
+
* @param {*} en
|
|
167
|
+
* @returns
|
|
168
|
+
*/
|
|
169
|
+
toMultilingual(zh,en){
|
|
170
|
+
if(Array.isArray(zh)){
|
|
171
|
+
//开放平台一般返回内容
|
|
172
|
+
if(zh[0].hasOwnProperty('lang')){
|
|
173
|
+
const _zh = this.toSafeValue(zh.find(it=>it.lang == 'zh-CN'),'value')
|
|
174
|
+
const _en = this.toSafeValue(zh.find(it=>it.lang == 'en-US'),'value')
|
|
175
|
+
return new application.constants.type.Multilingual({ zh: _zh || _en, en: _en || _zh })
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return new application.constants.type.Multilingual({ zh: zh || en, en: en || zh })
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* 安全的取值
|
|
183
|
+
* @param {*} obj
|
|
184
|
+
* @param {*} key
|
|
185
|
+
* @param {*} defValue
|
|
186
|
+
* @returns
|
|
187
|
+
*/
|
|
188
|
+
toSafeValue(obj,key,defValue){
|
|
189
|
+
const _obj = obj || {}
|
|
190
|
+
if(!_obj){
|
|
191
|
+
return defValue
|
|
192
|
+
}
|
|
193
|
+
if(!_obj.hasOwnProperty(key)){
|
|
194
|
+
return defValue
|
|
195
|
+
}
|
|
196
|
+
return _obj[key] || defValue
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
100
200
|
|
|
101
201
|
}
|
|
102
202
|
module.exports = HG
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
class Contract{
|
|
2
|
+
#hg = null
|
|
3
|
+
#logger = null
|
|
4
|
+
constructor(logger,hg){
|
|
5
|
+
this.#logger = logger
|
|
6
|
+
this.#hg = hg
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 通过手机号或邮箱获取用户 ID
|
|
11
|
+
* @param {*} user_id_type user_id、open_id、union_id
|
|
12
|
+
* @returns
|
|
13
|
+
*/
|
|
14
|
+
async batch_get_id(data,user_id_type){
|
|
15
|
+
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)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
module.exports = Contract
|
package/opensdk/document.js
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
1
|
class Document{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
*/
|
|
20
|
-
async permissions(app_token,type,data){
|
|
21
|
-
if(!type){
|
|
22
|
-
throw 'type is not empty'
|
|
2
|
+
#logger = null
|
|
3
|
+
#hg = null
|
|
4
|
+
constructor(logger,hg){
|
|
5
|
+
this.#logger = logger
|
|
6
|
+
this.#hg = hg
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 增加协作者权限 https://open.feishu.cn/document/server-docs/docs/permission/permission-member/create
|
|
10
|
+
* @param {*} app_token app_token 多维表格 App 的唯一标识
|
|
11
|
+
* @param {*} type 文件类型 bitable:多维表格
|
|
12
|
+
* @param {*} data {
|
|
13
|
+
"member_type": "openchat",
|
|
14
|
+
"member_id": "oc_b962e8debdc37712a1d60bb97087a8e8",
|
|
15
|
+
"perm": "edit",
|
|
16
|
+
"perm_type": "container",
|
|
17
|
+
"type": "chat"
|
|
23
18
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
* @param {*} app_token 要复制的多维表格 App 的唯一标识
|
|
29
|
-
* @param {*} name 多维表格 App 名称。最长为 255 个字符
|
|
30
|
-
* @param {*} folder_token 文件夹
|
|
31
|
-
* @returns
|
|
32
|
-
*/
|
|
33
|
-
async copy(app_token,name,folder_token,without_content,time_zone){
|
|
34
|
-
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)
|
|
19
|
+
*/
|
|
20
|
+
async permissions(app_token,type,data){
|
|
21
|
+
if(!type){
|
|
22
|
+
throw 'type is not empty'
|
|
35
23
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
24
|
+
return await this.#hg.request(`https://open.feishu.cn/open-apis/drive/v1/permissions/${app_token}/members?type=${type}&need_notification=false`,data,true)
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 复制多维表格 https://open.feishu.cn/document/server-docs/docs/bitable-v1/app/copy
|
|
28
|
+
* @param {*} app_token 要复制的多维表格 App 的唯一标识
|
|
29
|
+
* @param {*} name 多维表格 App 名称。最长为 255 个字符
|
|
30
|
+
* @param {*} folder_token 文件夹
|
|
31
|
+
* @returns
|
|
32
|
+
*/
|
|
33
|
+
async copy(app_token,name,folder_token,without_content,time_zone){
|
|
34
|
+
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)
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 创建多维表格 https://open.feishu.cn/document/server-docs/docs/bitable-v1/app/create
|
|
38
|
+
* @param {*} name 多维表格 App 名称
|
|
39
|
+
* @param {*} folder_token 多维表格 App 归属文件夹
|
|
40
|
+
* @param {*} time_zone
|
|
41
|
+
* @returns
|
|
42
|
+
*/
|
|
43
|
+
async create(name, folder_token, time_zone){
|
|
44
|
+
return await this.#hg.request('https://open.feishu.cn/open-apis/bitable/v1/apps',{ name, folder_token, time_zone: time_zone || 'Asia/Shanghai' },true)
|
|
47
45
|
}
|
|
48
|
-
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
module.exports = Document
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class Employee{
|
|
2
|
+
#hg = null
|
|
3
|
+
#logger = null
|
|
4
|
+
constructor(logger,hg){
|
|
5
|
+
this.#logger = logger
|
|
6
|
+
this.#hg = hg
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 搜索员工信息
|
|
11
|
+
* @param {*} params
|
|
12
|
+
* @param {*} data
|
|
13
|
+
* @param {*} callback(items) 结果回调(根据总数可能多次调用)
|
|
14
|
+
*/
|
|
15
|
+
async search(params,data,callback){
|
|
16
|
+
return await this.#hg.paginatedSearch(`https://open.feishu.cn/open-apis/corehr/v2/employees/search`,params,data,callback)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
module.exports = Employee
|
package/opensdk/users.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
class Users{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 通过手机号或邮箱获取用户 ID
|
|
11
|
-
* @param {*} user_id_type user_id、open_id、union_id
|
|
12
|
-
* @returns
|
|
13
|
-
*/
|
|
14
|
-
async batch_get_id(data,user_id_type){
|
|
15
|
-
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)
|
|
16
|
-
}
|
|
2
|
+
#hg = null
|
|
3
|
+
#logger = null
|
|
4
|
+
constructor(logger,hg){
|
|
5
|
+
this.#logger = logger
|
|
6
|
+
this.#hg = hg
|
|
7
|
+
}
|
|
17
8
|
|
|
9
|
+
/**
|
|
10
|
+
* 通过手机号或邮箱获取用户 ID
|
|
11
|
+
* @param {*} user_id_type user_id、open_id、union_id
|
|
12
|
+
* @returns
|
|
13
|
+
*/
|
|
14
|
+
async batch_get_id(data,user_id_type){
|
|
15
|
+
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)
|
|
18
16
|
}
|
|
19
|
-
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
module.exports = Users
|
package/package.json
CHANGED
package/readme.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# apass-opensdk-hugong
|
|
2
|
+
## 简介
|
|
3
|
+
apass-opensdk-hugong 是一个基于apass-opensdk的封装,提供了一些常用的功能
|
|
4
|
+
- 什么人可以使用这个SDK
|
|
5
|
+
- 从事飞书低代码平台(APASS)开发人员.
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
在飞书低代码平台(云函数)依赖管理-右侧-搜索: apass-opensdk-hugong
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 如何使用
|
|
14
|
+
```
|
|
15
|
+
const Hugong = require('apass-opensdk-hugong');
|
|
16
|
+
初始化
|
|
17
|
+
const hg = new Hugong(logger)
|
|
18
|
+
```
|
|
19
|
+
## 常用
|
|
20
|
+
```
|
|
21
|
+
显示运行时间
|
|
22
|
+
hg.newTime()
|
|
23
|
+
hg.printTime()
|
|
24
|
+
|
|
25
|
+
线程睡眠(毫秒)
|
|
26
|
+
await hg.sleep(2000)
|
|
27
|
+
|
|
28
|
+
支持将数组分割成指定长度分段数组
|
|
29
|
+
第一种用法,一次性返还分割后的数组
|
|
30
|
+
const list = hg.utils.splitArray([], 50) 输出 [ [50],[50] ]
|
|
31
|
+
|
|
32
|
+
第二种用法,每次输出50条 处理完成后继续下次执行
|
|
33
|
+
await hg.utils.splitArray([], 10, async (items)=>{
|
|
34
|
+
// do something
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
## 文件上传/下载
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
1)从网络下载文件后上传到飞书租户空间,返回上传后的文件信息
|
|
42
|
+
await hg.utils.file.downloadFileToUpload(url)
|
|
43
|
+
2)如果有鉴权, 可以传递header参数
|
|
44
|
+
await hg.utils.file.downloadFileToUpload(url,{ Authorization: `...`})
|
|
45
|
+
3)保存数据到本地环境中,比如接口返回的数据需要保存到本地环境中方便查看
|
|
46
|
+
saveDataToEnv(data,path)
|
|
47
|
+
|
|
48
|
+
1)从飞书租户空间下载文件到本地环境中
|
|
49
|
+
file_info={ id, mime_type, name, ...}
|
|
50
|
+
file_path=存储地址可选,不填写则默认当前时间戳
|
|
51
|
+
await hg.utils.file.downloadFileToTmp(fileInfo,file_path)
|
|
52
|
+
|
|
53
|
+
2)解析csv文件,file_path必须是本地环境的文件路径 /tep/aaa.csv 可以使用上面的方法downloadFileToTmp下载文件到本地环境中
|
|
54
|
+
await hg.utils.file.csvRead(file_path,callback)
|
|
55
|
+
示例1 读取完成后返回数组
|
|
56
|
+
const list = await hg.utils.file.csvRead(file_path)
|
|
57
|
+
示例2 读取完成后回调
|
|
58
|
+
await hg.utils.file.csvRead(file_path,async (row)=>{
|
|
59
|
+
// do something
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 小工具/多语言
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
对象数据新增多语言对象
|
|
67
|
+
|
|
68
|
+
生成多语言对象
|
|
69
|
+
hg.toMultilingual([{ lang: 'en-US', value: 'Regular' },{ lang: 'zh-CN', value: '正式' }]) 常用于开放平台返回的多语言数据转换
|
|
70
|
+
hg.toMultilingual(zh,en)
|
|
71
|
+
|
|
72
|
+
安全的取值
|
|
73
|
+
hg.toSafeValue(obj={},key,defValue)
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 飞书人事
|
|
78
|
+
|
|
79
|
+
搜索员工信息
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
设置appid和appsecret
|
|
83
|
+
await hg.setAppId('cli_000000000','0000000000000')
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 搜索员工信息
|
|
87
|
+
* @param {*} params
|
|
88
|
+
* @param {*} data
|
|
89
|
+
* @param {*} callback callback(items) 结果回调(根据总数可能多次调用)- 可选
|
|
90
|
+
* @returns 如果callback为传递则一次性返回所有的数据
|
|
91
|
+
*/
|
|
92
|
+
await hg.employee.search(params,data,callback)
|
|
93
|
+
|
|
94
|
+
// 示例[具体参数请参考开放平台定义](https://open.feishu.cn/document/server-docs/corehr-v1/employee/search)
|
|
95
|
+
await hg.employee.search({ page_size:100,user_id_type:'user_id',},{ /* 要查询的字段 */}, async (items)=>{
|
|
96
|
+
// do something 假设服务端有300条数据,每次返回100条,会调用3次, 如果希望一次性返回所有数据,callback传null即可
|
|
97
|
+
})
|
|
98
|
+
const list = await hg.employee.search(params,data) //这将一次性返回所有数据
|
|
99
|
+
```
|
|
100
|
+
## 开放平台分页获取所有数据
|
|
101
|
+
|
|
102
|
+
所有的分页接口都可以使用
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
设置appid和appsecret
|
|
106
|
+
await hg.setAppId('cli_000000000','0000000000000')
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* GET类型接口分页返回开放平台数据
|
|
110
|
+
* @param {*} url
|
|
111
|
+
* @param {*} params
|
|
112
|
+
* @param {*} callback callback(items) 结果回调(根据总数可能多次调用)- 可选
|
|
113
|
+
* @returns callback为null,则一次性返回所有的数据
|
|
114
|
+
*/
|
|
115
|
+
hg.paginatedSearchGet(url,params,callback)
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* POST接口分页返回开放平台数据
|
|
119
|
+
* @param {*} url
|
|
120
|
+
* @param {*} params
|
|
121
|
+
* @param {*} data
|
|
122
|
+
* @param {*} callback callback(items) 结果回调(根据总数可能多次调用)- 可选
|
|
123
|
+
* @returns callback为null,则一次性返回所有的数据
|
|
124
|
+
*/
|
|
125
|
+
await hg.paginatedSearch(url,params,data,callback)
|
|
126
|
+
|
|
127
|
+
示例1
|
|
128
|
+
const list = await hg.paginatedSearchGet(url, params, data)
|
|
129
|
+
示例2
|
|
130
|
+
await hg.paginatedSearchGet(url, params, async (items)=>{
|
|
131
|
+
// do something 假设服务端有300条数据,每次返回100条,会调用3次, 如果希望一次性返回所有数据,callback传null即可
|
|
132
|
+
})
|
|
133
|
+
```
|
package/utils/file_.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
class File_{
|
|
3
|
+
#hg = null
|
|
4
|
+
#logger = null
|
|
5
|
+
constructor(logger,hg){
|
|
6
|
+
this.#logger = logger
|
|
7
|
+
this.#hg = hg
|
|
8
|
+
}
|
|
9
|
+
getCurrentTimeFolderName() {
|
|
10
|
+
const now = new Date();
|
|
11
|
+
const year = now.getFullYear();
|
|
12
|
+
const month = String(now.getMonth() + 1).padStart(2, '0');
|
|
13
|
+
const day = String(now.getDate()).padStart(2, '0');
|
|
14
|
+
const hours = String(now.getHours()).padStart(2, '0');
|
|
15
|
+
const minutes = String(now.getMinutes()).padStart(2, '0');
|
|
16
|
+
const seconds = String(now.getSeconds()).padStart(2, '0');
|
|
17
|
+
return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* * 网络下载文件并上传到租户空间
|
|
21
|
+
* @param {*} url 网络文件地址
|
|
22
|
+
* @param {*} header 可选
|
|
23
|
+
* @returns
|
|
24
|
+
*/
|
|
25
|
+
async downloadFileToUpload(url, header = {}){
|
|
26
|
+
this.#logger.log(`download url=${url}`)
|
|
27
|
+
const resp = await axios({ url, method: 'get', responseType: 'stream', headers: {...header} });
|
|
28
|
+
// 上传文件获取文件 token
|
|
29
|
+
const file_info = await application.resources.file.upload(resp.data);
|
|
30
|
+
this.#logger.log('file_info',file_info)
|
|
31
|
+
return file_info
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 下载租户空间的文件到环境tmp目录中
|
|
35
|
+
* @param {*} file_info { id, mime_type, name, ...}
|
|
36
|
+
* @param {*} file_path 存储地址可选,不填写则默认当前时间戳
|
|
37
|
+
* @returns
|
|
38
|
+
*/
|
|
39
|
+
async downloadFileToTmp(file_info, file_path){
|
|
40
|
+
this.#logger.log(`download input=${ JSON.stringify(file_info)}`)
|
|
41
|
+
const _file_path = file_path || `/tmp/${Date.now()}.${ file_info.mime_type }`
|
|
42
|
+
await application.resources.file.download({id: file_info.id}, _file_path);
|
|
43
|
+
this.#logger.log(`download success, path=` + _file_path)
|
|
44
|
+
return _file_path
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 写入文件
|
|
48
|
+
* @param {*} data 写入的内容
|
|
49
|
+
* @param {*} fileName 存储地址
|
|
50
|
+
*/
|
|
51
|
+
saveDataToEnv(data,fileName){
|
|
52
|
+
fs.writeFileSync(fileName || `${ Date.now() }.txt`,data, { flag: 'a' })
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 读取Excel文件(需要安装依赖:csv-parser)
|
|
56
|
+
* @param {*} path
|
|
57
|
+
* @param {*} callback(row) 每一行的回调
|
|
58
|
+
* @returns callback为null时,返回全部读取的结果list
|
|
59
|
+
*/
|
|
60
|
+
async csvRead(path,callback) {
|
|
61
|
+
const csv = require('csv-parser');
|
|
62
|
+
return await new Promise((resolve, reject) => {
|
|
63
|
+
const list = []
|
|
64
|
+
fs.createReadStream(path).pipe(csv())
|
|
65
|
+
.on('data', (row) => {
|
|
66
|
+
if(callback){
|
|
67
|
+
callback(row)
|
|
68
|
+
}else{
|
|
69
|
+
list.push(row)
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
.on('end', () => {
|
|
73
|
+
resolve(list)
|
|
74
|
+
})
|
|
75
|
+
.on('error',()=>{
|
|
76
|
+
reject()
|
|
77
|
+
});
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
module.exports = File_
|
package/utils/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const Url = require('./url')
|
|
2
|
+
const File_ = require('./file_')
|
|
3
|
+
class Utils{
|
|
4
|
+
#hg = null
|
|
5
|
+
#logger = null
|
|
6
|
+
constructor(logger,hg){
|
|
7
|
+
this.#logger = logger
|
|
8
|
+
this.#hg = hg
|
|
9
|
+
|
|
10
|
+
this.url = new Url(logger,hg)
|
|
11
|
+
this.file = new File_(logger,hg)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 数组分割
|
|
16
|
+
* @param {*} list
|
|
17
|
+
* @param {*} chunkSize 分割长度
|
|
18
|
+
* @param {*} callback(item) 分割后回调(不传递则方法返回切割长度后的数组)
|
|
19
|
+
* @returns
|
|
20
|
+
*/
|
|
21
|
+
async splitArray(list, chunkSize, callback) {
|
|
22
|
+
const result = [];
|
|
23
|
+
for (let i = 0; i < list.length; i += chunkSize) {
|
|
24
|
+
const batch = list.slice(i, i + chunkSize)
|
|
25
|
+
if(callback){
|
|
26
|
+
await callback(batch)
|
|
27
|
+
continue
|
|
28
|
+
}
|
|
29
|
+
result.push(batch); // 使用 slice 方法按 chunkSize 进行切割
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
module.exports = Utils
|
package/utils/url.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
class Url{
|
|
3
|
+
#hg = null
|
|
4
|
+
#logger = null
|
|
5
|
+
constructor(logger,hg){
|
|
6
|
+
this.#logger = logger
|
|
7
|
+
this.#hg = hg
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
jsonToUrlParams(jsonData) {
|
|
11
|
+
const params = new URLSearchParams();
|
|
12
|
+
for (const key in jsonData) {
|
|
13
|
+
if (jsonData[key]) {
|
|
14
|
+
params.append(key, jsonData[key]);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return params.toString();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
module.exports = Url
|