mobx-lark 2.8.0 → 2.9.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/ReadMe.md +2 -0
- package/dist/Lark.d.ts +1 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/module/BITable/index.d.ts +105 -53
- package/dist/module/BITable/utility.d.ts +1 -0
- package/dist/module/Document/component/Block.d.ts +1 -1
- package/dist/module/DocumentAI/index.d.ts +17 -1
- package/dist/module/DocumentAI/type.d.ts +81 -0
- package/package.json +14 -22
- package/pnpm-workspace.yaml +9 -0
- package/src/Lark.ts +1 -1
- package/src/module/BITable/index.ts +58 -34
- package/src/module/BITable/utility.ts +11 -11
- package/src/module/DocumentAI/index.ts +66 -2
- package/src/module/DocumentAI/type.ts +129 -0
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
TableRecordFields,
|
|
14
14
|
TableView
|
|
15
15
|
} from './type';
|
|
16
|
-
import { makeSimpleFilter } from './utility';
|
|
16
|
+
import { makeSimpleFilter, mapKeys } from './utility';
|
|
17
17
|
|
|
18
18
|
export * from './type';
|
|
19
19
|
export * from './utility';
|
|
@@ -31,13 +31,13 @@ export interface BiDataQueryOptions {
|
|
|
31
31
|
/**
|
|
32
32
|
* @see {@link https://open.feishu.cn/document/ukTMukTMukTM/uUDN04SN0QjL1QDN/bitable-overview}
|
|
33
33
|
*/
|
|
34
|
-
export function BiDataTable<
|
|
34
|
+
export function BiDataTable<D extends DataObject, F extends Filter<D> = Filter<D>>(
|
|
35
35
|
Base = ListModel
|
|
36
36
|
) {
|
|
37
|
-
abstract class BiDataTableModel extends Stream<
|
|
38
|
-
requiredKeys: readonly (keyof
|
|
37
|
+
abstract class BiDataTableModel extends Stream<D, F>(Base) {
|
|
38
|
+
requiredKeys: readonly (keyof D)[] = [];
|
|
39
39
|
|
|
40
|
-
sort: Partial<Record<keyof
|
|
40
|
+
sort: Partial<Record<keyof D, 'ASC' | 'DESC'>> = {};
|
|
41
41
|
|
|
42
42
|
queryOptions: BiDataQueryOptions = {
|
|
43
43
|
text_field_as_array: true,
|
|
@@ -50,7 +50,15 @@ export function BiDataTable<T extends DataObject, F extends Filter<T> = Filter<T
|
|
|
50
50
|
this.baseURI = `bitable/v1/apps/${appId}/tables/${tableId}/records`;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
keyMap?: Partial<Record<keyof D, string>>;
|
|
54
|
+
|
|
55
|
+
get nameMap() {
|
|
56
|
+
return this.keyMap
|
|
57
|
+
? Object.fromEntries(Object.entries(this.keyMap).map(([key, name]) => [name, key]))
|
|
58
|
+
: {};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
extractFields({ fields, ...meta }: TableRecord<D>): D {
|
|
54
62
|
return { ...meta, ...fields };
|
|
55
63
|
}
|
|
56
64
|
|
|
@@ -59,8 +67,19 @@ export function BiDataTable<T extends DataObject, F extends Filter<T> = Filter<T
|
|
|
59
67
|
*/
|
|
60
68
|
normalize = this.extractFields;
|
|
61
69
|
|
|
70
|
+
/**
|
|
71
|
+
* @protected
|
|
72
|
+
*/
|
|
73
|
+
mapFields({ fields, ...meta }: TableRecord<DataObject>) {
|
|
74
|
+
const { nameMap } = this;
|
|
75
|
+
|
|
76
|
+
const mappedData = isEmpty(nameMap) ? (fields as D) : (mapKeys(fields, nameMap) as D);
|
|
77
|
+
|
|
78
|
+
return this.normalize({ fields: mappedData, ...meta });
|
|
79
|
+
}
|
|
80
|
+
|
|
62
81
|
wrapFields(fields: F) {
|
|
63
|
-
return fields as unknown as
|
|
82
|
+
return fields as unknown as D;
|
|
64
83
|
}
|
|
65
84
|
|
|
66
85
|
/**
|
|
@@ -68,10 +87,10 @@ export function BiDataTable<T extends DataObject, F extends Filter<T> = Filter<T
|
|
|
68
87
|
*/
|
|
69
88
|
@toggle('downloading')
|
|
70
89
|
async getOne(id: string) {
|
|
71
|
-
const { body } = await this.client.get<TableRecordData<
|
|
90
|
+
const { body } = await this.client.get<TableRecordData<D>>(
|
|
72
91
|
`${this.baseURI}/${id}?${buildURLData(this.queryOptions)}`
|
|
73
92
|
);
|
|
74
|
-
return (this.currentOne = this.
|
|
93
|
+
return (this.currentOne = this.mapFields(body!.data!.record));
|
|
75
94
|
}
|
|
76
95
|
|
|
77
96
|
/**
|
|
@@ -80,29 +99,31 @@ export function BiDataTable<T extends DataObject, F extends Filter<T> = Filter<T
|
|
|
80
99
|
*/
|
|
81
100
|
@toggle('uploading')
|
|
82
101
|
async updateOne(data: F, id?: string) {
|
|
83
|
-
const
|
|
102
|
+
const rawData = this.wrapFields(data);
|
|
103
|
+
|
|
104
|
+
const fields = isEmpty(this.keyMap) ? rawData : (mapKeys(rawData, this.keyMap) as D);
|
|
84
105
|
|
|
85
106
|
const { body } = await (id
|
|
86
|
-
? this.client.put<TableRecordData<
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
107
|
+
? this.client.put<TableRecordData<D>>(`${this.baseURI}/${id}`, { fields })
|
|
108
|
+
: this.client.post<TableRecordData<D>>(this.baseURI, { fields }));
|
|
109
|
+
|
|
110
|
+
return (this.currentOne = this.mapFields(body!.data!.record));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
mapFilter(filter: DataObject) {
|
|
114
|
+
return isEmpty(this.keyMap) ? (filter as F) : (mapKeys(filter, this.keyMap) as F);
|
|
93
115
|
}
|
|
94
116
|
|
|
95
117
|
makeFilter(filter: F) {
|
|
96
|
-
|
|
118
|
+
const requiredFilter =
|
|
97
119
|
this.requiredKeys[0] &&
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
.join('&&');
|
|
120
|
+
makeSimpleFilter(
|
|
121
|
+
this.mapFilter(Object.fromEntries(this.requiredKeys.map(key => [key, '']))),
|
|
122
|
+
'!='
|
|
123
|
+
);
|
|
124
|
+
const customFilter = !isEmpty(filter) && makeSimpleFilter(this.mapFilter(filter));
|
|
125
|
+
|
|
126
|
+
return [requiredFilter, customFilter].filter(Boolean).join('&&');
|
|
106
127
|
}
|
|
107
128
|
|
|
108
129
|
/**
|
|
@@ -118,13 +139,13 @@ export function BiDataTable<T extends DataObject, F extends Filter<T> = Filter<T
|
|
|
118
139
|
Object.entries(this.sort).map(([key, order]) => `${key} ${order}`)
|
|
119
140
|
)
|
|
120
141
|
};
|
|
121
|
-
const stream = createPageStream<TableRecord<
|
|
142
|
+
const stream = createPageStream<TableRecord<DataObject>>(
|
|
122
143
|
this.client,
|
|
123
144
|
this.baseURI,
|
|
124
145
|
total => (this.totalCount = total),
|
|
125
146
|
{ ...searchParams, ...this.queryOptions }
|
|
126
147
|
);
|
|
127
|
-
for await (const item of stream) yield this.
|
|
148
|
+
for await (const item of stream) yield this.mapFields(item);
|
|
128
149
|
}
|
|
129
150
|
|
|
130
151
|
async getViewList(
|
|
@@ -156,13 +177,14 @@ export type BiSearchFilter<D extends DataObject> = Filter<D> & {
|
|
|
156
177
|
keywords?: string;
|
|
157
178
|
};
|
|
158
179
|
|
|
159
|
-
export function BiSearch<
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
180
|
+
export function BiSearch<
|
|
181
|
+
D extends DataObject,
|
|
182
|
+
F extends BiSearchFilter<D> = BiSearchFilter<D>,
|
|
183
|
+
M extends ReturnType<typeof BiDataTable<D, F>> = ReturnType<typeof BiDataTable<D, F>>
|
|
184
|
+
>(Model: M) {
|
|
185
|
+
abstract class BiSearchModel extends (Model as ReturnType<typeof BiDataTable<D, F>>) {
|
|
163
186
|
declare baseURI: string;
|
|
164
187
|
declare client: RESTClient;
|
|
165
|
-
declare loadPage: (pageIndex: number, pageSize: number, filter: F) => Promise<PageData<D>>;
|
|
166
188
|
|
|
167
189
|
abstract searchKeys: readonly (keyof TableRecordFields)[];
|
|
168
190
|
|
|
@@ -170,7 +192,9 @@ export function BiSearch<D extends DataObject, F extends BiSearchFilter<D> = BiS
|
|
|
170
192
|
accessor keywords = '';
|
|
171
193
|
|
|
172
194
|
makeFilter(filter: F) {
|
|
173
|
-
return isEmpty(filter)
|
|
195
|
+
return isEmpty(filter)
|
|
196
|
+
? ''
|
|
197
|
+
: makeSimpleFilter(this.mapFilter(filter), 'contains', 'OR');
|
|
174
198
|
}
|
|
175
199
|
|
|
176
200
|
async getList(
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { DataObject } from 'mobx-restful';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import { TableCellLink, TableCellLocation, TableCellRelation, TableCellText } from './type';
|
|
3
|
+
|
|
4
|
+
export const mapKeys = <I extends DataObject, O extends DataObject>(
|
|
5
|
+
data: I,
|
|
6
|
+
map: Partial<Record<keyof I, PropertyKey>>
|
|
7
|
+
) =>
|
|
8
|
+
Object.fromEntries(
|
|
9
|
+
Object.entries(data).map(([key, value]) => [map[key as keyof I] || key, value])
|
|
10
|
+
) as O;
|
|
8
11
|
|
|
9
12
|
export type FilterOperator = '<' | '<=' | '=' | '!=' | '=>' | '>' | 'contains';
|
|
10
13
|
|
|
@@ -34,9 +37,7 @@ export function makeSimpleFilter(
|
|
|
34
37
|
return list[1] ? `${relation}(${list})` : list[0];
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
export const normalizeText = (
|
|
38
|
-
value: TableCellText | TableCellLink | TableCellRelation
|
|
39
|
-
) =>
|
|
40
|
+
export const normalizeText = (value: TableCellText | TableCellLink | TableCellRelation) =>
|
|
40
41
|
(value && typeof value === 'object' && 'text' in value && value.text) || '';
|
|
41
42
|
|
|
42
43
|
export const normalizeTextArray = (list: TableCellText[]) =>
|
|
@@ -50,8 +51,7 @@ export const normalizeTextArray = (list: TableCellText[]) =>
|
|
|
50
51
|
['']
|
|
51
52
|
);
|
|
52
53
|
export function coordinateOf(location: TableCellLocation): [number, number] {
|
|
53
|
-
const [longitude, latitude] =
|
|
54
|
-
(location as TableCellLocation)?.location.split(',') || [];
|
|
54
|
+
const [longitude, latitude] = (location as TableCellLocation)?.location.split(',') || [];
|
|
55
55
|
|
|
56
56
|
return [+latitude, +longitude];
|
|
57
57
|
}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
import { makeFormData } from 'koajax';
|
|
1
|
+
import { makeFormData, readAs } from 'koajax';
|
|
2
2
|
import { BaseModel, RESTClient, toggle } from 'mobx-restful';
|
|
3
3
|
|
|
4
4
|
import { LarkData } from '../../type';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
BankCardEntity,
|
|
7
|
+
Contract,
|
|
8
|
+
Resume,
|
|
9
|
+
TaxiInvoice,
|
|
10
|
+
TrainInvoice,
|
|
11
|
+
VatInvoice,
|
|
12
|
+
VehicleInvoice
|
|
13
|
+
} from './type';
|
|
6
14
|
|
|
7
15
|
export * from './type';
|
|
8
16
|
|
|
@@ -58,4 +66,60 @@ export abstract class DocumentAIModel extends BaseModel {
|
|
|
58
66
|
|
|
59
67
|
return body!.data!.vehicle_invoice;
|
|
60
68
|
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @see {@link https://open.feishu.cn/document/server-docs/ai/optical_char_recognition-v1/basic_recognize}
|
|
72
|
+
*/
|
|
73
|
+
@toggle('uploading')
|
|
74
|
+
async recognizeText(image: File) {
|
|
75
|
+
const URI = (await readAs(image, 'dataURL').result) as string;
|
|
76
|
+
|
|
77
|
+
const [, base64] = URI.split(',');
|
|
78
|
+
|
|
79
|
+
const { body } = await this.client.post<LarkData<{ text_list: string[] }>>(
|
|
80
|
+
'optical_char_recognition/v1/image/basic_recognize',
|
|
81
|
+
{ image: base64 }
|
|
82
|
+
);
|
|
83
|
+
return body!.data!.text_list;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @see {@link https://open.feishu.cn/document/ai/document_ai-v1/bank_card/recognize}
|
|
88
|
+
*/
|
|
89
|
+
@toggle('uploading')
|
|
90
|
+
async recognizeBankCard(file: File) {
|
|
91
|
+
const { body } = await this.client.post<
|
|
92
|
+
LarkData<{ bank_card: { entities: BankCardEntity[] } }>
|
|
93
|
+
>(`${this.baseURI}/bank_card/recognize`, makeFormData({ file }));
|
|
94
|
+
|
|
95
|
+
return body!.data!.bank_card.entities;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @see {@link https://open.feishu.cn/document/ai/document_ai-v1/resume/parse}
|
|
100
|
+
*/
|
|
101
|
+
@toggle('uploading')
|
|
102
|
+
async parseResume(file: File) {
|
|
103
|
+
const { body } = await this.client.post<LarkData<{ resumes: Resume[] }>>(
|
|
104
|
+
`${this.baseURI}/resume/parse`,
|
|
105
|
+
makeFormData({ file })
|
|
106
|
+
);
|
|
107
|
+
return body!.data!.resumes;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @see {@link https://open.feishu.cn/document/server-docs/ai/document_ai-v1/contract/field_extraction}
|
|
112
|
+
*/
|
|
113
|
+
@toggle('uploading')
|
|
114
|
+
async extractContract(
|
|
115
|
+
file: File,
|
|
116
|
+
ocr_mode: 'unused' | 'force' | 'auto' = 'auto',
|
|
117
|
+
pdf_page_limit = 100
|
|
118
|
+
) {
|
|
119
|
+
const { body } = await this.client.post<LarkData<Contract>>(
|
|
120
|
+
`${this.baseURI}/contract/field_extraction`,
|
|
121
|
+
makeFormData({ file, ocr_mode, pdf_page_limit })
|
|
122
|
+
);
|
|
123
|
+
return body!.data!;
|
|
124
|
+
}
|
|
61
125
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Gender } from '../User/type';
|
|
2
|
+
|
|
1
3
|
export type InvoiceEntityType =
|
|
2
4
|
| `invoice_${'code' | 'no' | 'special_seal'}`
|
|
3
5
|
| `seller_${'name' | 'taxpayer_no'}_in_seal`;
|
|
@@ -67,3 +69,130 @@ export interface VehicleInvoice {
|
|
|
67
69
|
| `total_price${'' | '_little'}`;
|
|
68
70
|
value: string;
|
|
69
71
|
}
|
|
72
|
+
|
|
73
|
+
export interface BankCardEntity {
|
|
74
|
+
type: 'card_number' | 'date_of_expiry';
|
|
75
|
+
value: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export type ResumePeriod = Record<`${'start' | 'end'}_${'date' | 'time'}`, string>;
|
|
79
|
+
|
|
80
|
+
export enum EducationQualification {
|
|
81
|
+
PrimarySchool = 1,
|
|
82
|
+
JuniorHighSchool = 2,
|
|
83
|
+
VocationalHighSchool = 3,
|
|
84
|
+
HighSchool = 4,
|
|
85
|
+
AssociateDegree = 5,
|
|
86
|
+
BachelorDegree = 6,
|
|
87
|
+
MasterDegree = 7,
|
|
88
|
+
Doctorate = 8,
|
|
89
|
+
Other = 9
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface ResumeEducation
|
|
93
|
+
extends ResumePeriod, Record<'school' | 'major' | 'degree', string> {
|
|
94
|
+
qualification: EducationQualification;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export enum CareerType {
|
|
98
|
+
Internship = 1,
|
|
99
|
+
FullTime = 2
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface ResumeCareer
|
|
103
|
+
extends ResumePeriod, Record<'company' | 'title' | 'type_str' | 'job_description', string> {
|
|
104
|
+
type: CareerType;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export type ResumeProject = ResumePeriod & Record<'name' | 'title' | 'description', string>;
|
|
108
|
+
|
|
109
|
+
export interface ResumeLanguage {
|
|
110
|
+
level: number;
|
|
111
|
+
description: string;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export type ResumeAward = Record<'award' | 'date' | 'description', string>;
|
|
115
|
+
|
|
116
|
+
export type ResumeCertificate = Record<'name' | 'desc', string>;
|
|
117
|
+
|
|
118
|
+
export type ResumeCompetition = ResumeCertificate;
|
|
119
|
+
|
|
120
|
+
export interface Resume
|
|
121
|
+
extends
|
|
122
|
+
Record<
|
|
123
|
+
| 'file_md5'
|
|
124
|
+
| `${'' | 'new_'}content`
|
|
125
|
+
| 'name'
|
|
126
|
+
| 'email'
|
|
127
|
+
| 'mobile'
|
|
128
|
+
| 'country_code'
|
|
129
|
+
| 'date_of_birth'
|
|
130
|
+
| `${'current' | 'home'}_location`
|
|
131
|
+
| 'self_evaluation',
|
|
132
|
+
string
|
|
133
|
+
>,
|
|
134
|
+
Record<`willing_${'positions' | 'locations'}` | 'urls' | 'social_links', string[]> {
|
|
135
|
+
mobile_is_virtual: boolean;
|
|
136
|
+
educations: ResumeEducation[];
|
|
137
|
+
careers: ResumeCareer[];
|
|
138
|
+
projects: ResumeProject[];
|
|
139
|
+
work_year: number | null;
|
|
140
|
+
gender: Gender;
|
|
141
|
+
languages: ResumeLanguage[];
|
|
142
|
+
awards: ResumeAward[];
|
|
143
|
+
certificates: ResumeCertificate[];
|
|
144
|
+
competitions: ResumeCompetition[];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface ContractPrice {
|
|
148
|
+
contract_price: number;
|
|
149
|
+
contract_price_original: string;
|
|
150
|
+
text: string;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export type ContractInitialTerm = Record<`initial_${'time' | 'unit'}`, string>;
|
|
154
|
+
|
|
155
|
+
export interface ContractTime extends Record<
|
|
156
|
+
`${'' | 'original_'}time_${'start' | 'end'}` | `text_${'start' | 'end' | 'initial_term'}`,
|
|
157
|
+
string
|
|
158
|
+
> {
|
|
159
|
+
initial_term: ContractInitialTerm;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface ContractCopy extends Record<'original_copy' | 'key' | 'text', string> {
|
|
163
|
+
copy_num: number;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export type ContractCurrency = Record<`currency_${'name' | 'text'}`, string>;
|
|
167
|
+
|
|
168
|
+
export type ContractBodyType = 'buy' | 'sell' | 'third';
|
|
169
|
+
|
|
170
|
+
export type ContractContact = Record<
|
|
171
|
+
'contacts' | 'id_number' | 'phone' | 'email' | 'address',
|
|
172
|
+
string
|
|
173
|
+
>;
|
|
174
|
+
export type ContractBodyEntity = ContractContact & Record<'legal_representative' | 'party', string>;
|
|
175
|
+
|
|
176
|
+
export interface ContractBodyInfo {
|
|
177
|
+
body_type: ContractBodyType;
|
|
178
|
+
value: ContractBodyEntity;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export type ContractBankType = `${'buy' | 'sell' | 'third' | 'uncertain'}_bank`;
|
|
182
|
+
|
|
183
|
+
export type ContractBankEntity = ContractContact &
|
|
184
|
+
Record<'bank_name' | `account_${'name' | 'number'}` | 'tax_number', string>;
|
|
185
|
+
|
|
186
|
+
export interface ContractBankInfo {
|
|
187
|
+
bank_type: ContractBankType;
|
|
188
|
+
value: ContractBankEntity;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export interface Contract extends Record<'file_id' | 'header', string> {
|
|
192
|
+
price: ContractPrice;
|
|
193
|
+
time: ContractTime;
|
|
194
|
+
copy: ContractCopy;
|
|
195
|
+
currency: ContractCurrency;
|
|
196
|
+
body_info: ContractBodyInfo[];
|
|
197
|
+
bank_info: ContractBankInfo[];
|
|
198
|
+
}
|