@skopon-cool/form-sdk 0.6.1 → 0.6.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/README.md +16 -0
- package/dist/adapter/formSchema.d.ts +3 -0
- package/dist/adapter/formSchema.d.ts.map +1 -1
- package/dist/blocks/resume_multiselect/adapter.d.ts.map +1 -1
- package/dist/catalog/contentSearchContext.d.ts +35 -0
- package/dist/catalog/contentSearchContext.d.ts.map +1 -0
- package/dist/catalog/pairResumeContent.d.ts +20 -0
- package/dist/catalog/pairResumeContent.d.ts.map +1 -0
- package/dist/catalog/skoponResumeSelect.d.ts.map +1 -1
- package/dist/client/contentSearchClient.d.ts +36 -0
- package/dist/client/contentSearchClient.d.ts.map +1 -0
- package/dist/client/resumeSearchClient.d.ts.map +1 -1
- package/dist/client/skoponSdkClients.d.ts +4 -0
- package/dist/client/skoponSdkClients.d.ts.map +1 -1
- package/dist/components/AskUserFormCard.d.ts +3 -0
- package/dist/components/AskUserFormCard.d.ts.map +1 -1
- package/dist/components/SkoponA2uiStreamRenderer.d.ts +4 -1
- package/dist/components/SkoponA2uiStreamRenderer.d.ts.map +1 -1
- package/dist/components/SkoponFormRenderer.d.ts +3 -0
- package/dist/components/SkoponFormRenderer.d.ts.map +1 -1
- package/dist/form-sdk.css +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1858 -1557
- package/dist/types/index.d.ts +25 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/adapter/formSchema.test.ts +8 -0
- package/src/adapter/formSchema.ts +49 -0
- package/src/blocks/resume_multiselect/adapter.ts +31 -0
- package/src/catalog/contentSearchContext.tsx +53 -0
- package/src/catalog/pairResumeContent.test.ts +34 -0
- package/src/catalog/pairResumeContent.ts +55 -0
- package/src/catalog/skoponResumeSelect.tsx +348 -153
- package/src/catalog/skoponSelectLoading.test.tsx +84 -5
- package/src/client/contentSearchClient.test.ts +123 -0
- package/src/client/contentSearchClient.ts +156 -0
- package/src/client/resumeSearchClient.test.ts +5 -0
- package/src/client/resumeSearchClient.ts +5 -0
- package/src/client/skoponSdkClients.ts +9 -0
- package/src/components/AskUserFormCard.tsx +5 -0
- package/src/components/SkoponA2uiStreamRenderer.tsx +15 -9
- package/src/components/SkoponFormRenderer.tsx +20 -12
- package/src/index.ts +16 -0
- package/src/styles/a2ui-preview.css +4 -4
- package/src/styles/index.css +158 -13
- package/src/submit/submit.test.ts +1 -0
- package/src/types/index.ts +26 -1
package/dist/types/index.d.ts
CHANGED
|
@@ -40,12 +40,30 @@ export interface FormBlockCondition {
|
|
|
40
40
|
/** 简历多选组件:渲染时用于 /univ/resume/search 的筛选条件 */
|
|
41
41
|
export interface FormResumeFilter {
|
|
42
42
|
names?: string[];
|
|
43
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* 智能体类型 unique_id。
|
|
45
|
+
* 运行时作为 agent_type:先找出该类型的智能体,再查他们的简历。
|
|
46
|
+
*/
|
|
44
47
|
agentKind?: string;
|
|
45
48
|
agentUniqueIds?: string[];
|
|
49
|
+
/** 智能体标签 unique_id,多值 AND;与 agentKind 一起定位智能体后再查简历 */
|
|
50
|
+
tagUniqueIds?: string[];
|
|
46
51
|
resumeUniqueIds?: string[];
|
|
47
52
|
pageSize?: number;
|
|
48
53
|
}
|
|
54
|
+
/** 内容制作搜索:渲染时用于 /univ/flow/list?owner_scope=content */
|
|
55
|
+
export interface FormContentFilter {
|
|
56
|
+
/** 流程类型 unique_id,默认 content-production */
|
|
57
|
+
flowType?: string;
|
|
58
|
+
/** 流程类别 unique_id */
|
|
59
|
+
category?: string;
|
|
60
|
+
/** 内容标签 unique_id */
|
|
61
|
+
tagUniqueIds?: string[];
|
|
62
|
+
/** 多标签匹配方式;all=全部命中,any=命中任一 */
|
|
63
|
+
tagMatch?: 'all' | 'any';
|
|
64
|
+
/** 每次向内容接口请求的条数,不是一屏展示张数 */
|
|
65
|
+
pageSize?: number;
|
|
66
|
+
}
|
|
49
67
|
/** 案例多选组件:渲染时用于 /univ/case/list 的筛选条件 */
|
|
50
68
|
export interface FormCaseFilter {
|
|
51
69
|
/** Agent 类型(编辑器辅助,运行时不用) */
|
|
@@ -94,8 +112,14 @@ export interface FormBlock {
|
|
|
94
112
|
resumeMinCount?: number;
|
|
95
113
|
/** 简历多选:最多选中数量,配置值 ≥ 1 */
|
|
96
114
|
resumeMaxCount?: number;
|
|
115
|
+
/** 简历多选:一轮展示几张,默认 5。不是最多可选数,也不是接口 page_size */
|
|
116
|
+
/** content-only 仅选内容,提交 flow_unique_id;默认仍为简历与内容组合。 */
|
|
117
|
+
resumeDisplayMode?: 'profile-content' | 'content-only';
|
|
118
|
+
resumeDisplayCount?: number;
|
|
97
119
|
/** 简历多选:列表筛选条件(持久化进 block json) */
|
|
98
120
|
resumeFilter?: FormResumeFilter;
|
|
121
|
+
/** 简历多选:内容制作筛选(持久化进 block json) */
|
|
122
|
+
contentFilter?: FormContentFilter;
|
|
99
123
|
/** 案例单选:是否显示「换一批」 */
|
|
100
124
|
caseEnableRefresh?: boolean;
|
|
101
125
|
/** 案例多选:最少选中数量,配置值 ≥ 1 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAEjD,MAAM,MAAM,iBAAiB,GACzB,QAAQ,GACR,KAAK,GACL,MAAM,GACN,OAAO,GACP,OAAO,GACP,aAAa,GACb,WAAW,GACX,UAAU,GACV,cAAc,GACd,eAAe,GACf,YAAY,GACZ,aAAa,GACb,WAAW,GACX,cAAc,GACd,oBAAoB,GACpB,kBAAkB,CAAA;AAEtB,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,iBAAiB,GAAG,MAAM,CAAA;IACrC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,iBAAiB,EAAE,CAAA;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;CAC1E;AAED,eAAO,MAAM,qBAAqB,EAAG,MAAe,CAAA;AAEpD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEpD,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,WAAW,GACX,MAAM,GACN,UAAU,GACV,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,aAAa,GACb,OAAO,GACP,UAAU,GACV,QAAQ,GACR,KAAK,GACL,KAAK,GACL,UAAU,GACV,MAAM,GACN,MAAM,GACN,oBAAoB,GACpB,kBAAkB;AACpB,4CAA4C;GAC1C,mBAAmB,GACnB,OAAO,GACP,OAAO,GACP,OAAO,GACP,KAAK,CAAA;AAET,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAA;AAE1E,MAAM,MAAM,uBAAuB,GAC/B,OAAO,GACP,OAAO,GACP,OAAO,GACP,MAAM,GACN,aAAa,GACb,UAAU,CAAA;AAEd,eAAO,MAAM,gBAAgB,EAAE,aAAa,EAM3C,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,MAAM,qBAAqB,GAAG,IAAI,GAAG,IAAI,GAAG,OAAO,GAAG,UAAU,CAAA;AAEtE,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -188,6 +188,7 @@ describe('normalizeFormDefinition preserves needLLM and editor fields', () => {
|
|
|
188
188
|
agentKind: 'management',
|
|
189
189
|
names: [],
|
|
190
190
|
agentUniqueIds: [],
|
|
191
|
+
tagUniqueIds: ['tag-hot'],
|
|
191
192
|
resumeUniqueIds: [],
|
|
192
193
|
pageSize: 20,
|
|
193
194
|
},
|
|
@@ -196,6 +197,13 @@ describe('normalizeFormDefinition preserves needLLM and editor fields', () => {
|
|
|
196
197
|
jsonSchema: {},
|
|
197
198
|
})
|
|
198
199
|
expect(def.blocks[0]?.resumeFilter?.agentKind).toBe('management')
|
|
200
|
+
expect(def.blocks[0]?.resumeFilter?.tagUniqueIds).toEqual(['tag-hot'])
|
|
201
|
+
expect(def.blocks[0]?.resumeDisplayCount).toBe(5)
|
|
202
|
+
expect(def.blocks[0]?.contentFilter).toMatchObject({
|
|
203
|
+
flowType: 'content-production',
|
|
204
|
+
tagUniqueIds: [],
|
|
205
|
+
pageSize: 20,
|
|
206
|
+
})
|
|
199
207
|
})
|
|
200
208
|
})
|
|
201
209
|
|
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
FormBlock,
|
|
3
3
|
FormBlockType,
|
|
4
4
|
FormCaseFilter,
|
|
5
|
+
FormContentFilter,
|
|
5
6
|
FormResumeFilter,
|
|
6
7
|
FormJsonSchema,
|
|
7
8
|
FormSchema,
|
|
@@ -136,6 +137,9 @@ function normalizeResumeFilter(raw: FormResumeFilter | undefined): FormResumeFil
|
|
|
136
137
|
agentUniqueIds: Array.isArray(raw?.agentUniqueIds)
|
|
137
138
|
? raw!.agentUniqueIds.map(String).filter(Boolean)
|
|
138
139
|
: [],
|
|
140
|
+
tagUniqueIds: Array.isArray(raw?.tagUniqueIds)
|
|
141
|
+
? raw!.tagUniqueIds.map(String).filter(Boolean)
|
|
142
|
+
: [],
|
|
139
143
|
resumeUniqueIds: Array.isArray(raw?.resumeUniqueIds)
|
|
140
144
|
? raw!.resumeUniqueIds.map(String).filter(Boolean)
|
|
141
145
|
: [],
|
|
@@ -143,6 +147,35 @@ function normalizeResumeFilter(raw: FormResumeFilter | undefined): FormResumeFil
|
|
|
143
147
|
}
|
|
144
148
|
}
|
|
145
149
|
|
|
150
|
+
export const DEFAULT_CONTENT_FLOW_TYPE = 'content-production'
|
|
151
|
+
export const DEFAULT_RESUME_DISPLAY_COUNT = 5
|
|
152
|
+
|
|
153
|
+
export function normalizeResumeDisplayCount(raw: unknown): number {
|
|
154
|
+
const num = typeof raw === 'number' ? raw : Number(raw)
|
|
155
|
+
if (!Number.isFinite(num) || num < 1) return DEFAULT_RESUME_DISPLAY_COUNT
|
|
156
|
+
return Math.min(100, Math.floor(num))
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function normalizeContentFilter(raw: FormContentFilter | undefined): FormContentFilter {
|
|
160
|
+
const pageSizeRaw = typeof raw?.pageSize === 'number' ? raw.pageSize : Number(raw?.pageSize)
|
|
161
|
+
const pageSize =
|
|
162
|
+
Number.isFinite(pageSizeRaw) && pageSizeRaw >= 1 && pageSizeRaw <= 100
|
|
163
|
+
? Math.floor(pageSizeRaw)
|
|
164
|
+
: 20
|
|
165
|
+
const flowType = raw?.flowType?.trim() || DEFAULT_CONTENT_FLOW_TYPE
|
|
166
|
+
const category = raw?.category?.trim() || undefined
|
|
167
|
+
const tagMatch = raw?.tagMatch === 'any' ? 'any' : 'all'
|
|
168
|
+
return {
|
|
169
|
+
flowType,
|
|
170
|
+
...(category ? { category } : {}),
|
|
171
|
+
tagUniqueIds: Array.isArray(raw?.tagUniqueIds)
|
|
172
|
+
? raw.tagUniqueIds.map(String).filter(Boolean)
|
|
173
|
+
: [],
|
|
174
|
+
tagMatch,
|
|
175
|
+
pageSize,
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
146
179
|
function migrateLegacyBlock(raw: FormBlock): FormBlock {
|
|
147
180
|
if (raw.type !== 'case_singleselect') return raw
|
|
148
181
|
const defaultValue =
|
|
@@ -204,8 +237,17 @@ function normalizeBlock(raw: FormBlock): FormBlock {
|
|
|
204
237
|
type === 'resume_multiselect' && migrated.resumeMaxCount != null
|
|
205
238
|
? normalizeMultiselectCount(migrated.resumeMaxCount, 1)
|
|
206
239
|
: undefined,
|
|
240
|
+
resumeDisplayMode: type === 'resume_multiselect'
|
|
241
|
+
? (migrated.resumeDisplayMode === 'content-only' ? 'content-only' : 'profile-content')
|
|
242
|
+
: undefined,
|
|
243
|
+
resumeDisplayCount:
|
|
244
|
+
type === 'resume_multiselect'
|
|
245
|
+
? normalizeResumeDisplayCount(migrated.resumeDisplayCount)
|
|
246
|
+
: undefined,
|
|
207
247
|
resumeFilter:
|
|
208
248
|
type === 'resume_multiselect' ? normalizeResumeFilter(migrated.resumeFilter) : undefined,
|
|
249
|
+
contentFilter:
|
|
250
|
+
type === 'resume_multiselect' ? normalizeContentFilter(migrated.contentFilter) : undefined,
|
|
209
251
|
caseEnableRefresh:
|
|
210
252
|
type === 'case_multiselect' ? migrated.caseEnableRefresh !== false : undefined,
|
|
211
253
|
caseMinCount:
|
|
@@ -460,9 +502,16 @@ export function createEmptyBlock(type: FormBlockType): FormBlock {
|
|
|
460
502
|
block.resumeEnableRefresh = true
|
|
461
503
|
block.resumeMinCount = 1
|
|
462
504
|
block.resumeMaxCount = 1
|
|
505
|
+
block.resumeDisplayCount = DEFAULT_RESUME_DISPLAY_COUNT
|
|
506
|
+
block.contentFilter = {
|
|
507
|
+
flowType: DEFAULT_CONTENT_FLOW_TYPE,
|
|
508
|
+
tagUniqueIds: [],
|
|
509
|
+
pageSize: 20,
|
|
510
|
+
}
|
|
463
511
|
block.resumeFilter = {
|
|
464
512
|
names: [],
|
|
465
513
|
agentUniqueIds: [],
|
|
514
|
+
tagUniqueIds: [],
|
|
466
515
|
resumeUniqueIds: [],
|
|
467
516
|
pageSize: 20,
|
|
468
517
|
}
|
|
@@ -24,9 +24,22 @@ export function resumeMultiselectToComponent(
|
|
|
24
24
|
placeholder: block.placeholder ?? '',
|
|
25
25
|
help: block.help ?? '',
|
|
26
26
|
enableRefresh: block.resumeEnableRefresh !== false,
|
|
27
|
+
resumeDisplayMode: block.resumeDisplayMode ?? 'profile-content',
|
|
28
|
+
resumeDisplayCount: block.resumeDisplayCount ?? 5,
|
|
29
|
+
contentFilter: {
|
|
30
|
+
flowType: block.contentFilter?.flowType?.trim() || 'content-production',
|
|
31
|
+
...(block.contentFilter?.category?.trim()
|
|
32
|
+
? { category: block.contentFilter.category.trim() }
|
|
33
|
+
: {}),
|
|
34
|
+
tagUniqueIds: block.contentFilter?.tagUniqueIds ?? [],
|
|
35
|
+
tagMatch: block.contentFilter?.tagMatch === 'any' ? 'any' : 'all',
|
|
36
|
+
pageSize: block.contentFilter?.pageSize ?? 20,
|
|
37
|
+
},
|
|
27
38
|
resumeFilter: {
|
|
28
39
|
names: block.resumeFilter?.names ?? [],
|
|
40
|
+
...(block.resumeFilter?.agentKind ? { agentKind: block.resumeFilter.agentKind } : {}),
|
|
29
41
|
agentUniqueIds: block.resumeFilter?.agentUniqueIds ?? [],
|
|
42
|
+
tagUniqueIds: block.resumeFilter?.tagUniqueIds ?? [],
|
|
30
43
|
resumeUniqueIds: block.resumeFilter?.resumeUniqueIds ?? [],
|
|
31
44
|
pageSize: block.resumeFilter?.pageSize ?? 20,
|
|
32
45
|
},
|
|
@@ -46,6 +59,7 @@ export function resumeMultiselectFromComponent(
|
|
|
46
59
|
...base('resume_multiselect'),
|
|
47
60
|
name,
|
|
48
61
|
resumeEnableRefresh: node.enableRefresh !== false,
|
|
62
|
+
resumeDisplayMode: node.resumeDisplayMode === 'content-only' ? 'content-only' : 'profile-content',
|
|
49
63
|
}
|
|
50
64
|
const placeholder = helpers.asLiteral(node.placeholder)
|
|
51
65
|
if (placeholder) block.placeholder = placeholder
|
|
@@ -53,13 +67,30 @@ export function resumeMultiselectFromComponent(
|
|
|
53
67
|
if (help) block.help = help
|
|
54
68
|
if (node.resumeFilter && typeof node.resumeFilter === 'object') {
|
|
55
69
|
const rf = node.resumeFilter as Record<string, unknown>
|
|
70
|
+
const agentKind = helpers.asLiteral(rf.agentKind)?.trim()
|
|
56
71
|
block.resumeFilter = {
|
|
57
72
|
names: Array.isArray(rf.names) ? rf.names.map(String) : [],
|
|
73
|
+
...(agentKind ? { agentKind } : {}),
|
|
58
74
|
agentUniqueIds: Array.isArray(rf.agentUniqueIds) ? rf.agentUniqueIds.map(String) : [],
|
|
75
|
+
tagUniqueIds: Array.isArray(rf.tagUniqueIds) ? rf.tagUniqueIds.map(String).filter(Boolean) : [],
|
|
59
76
|
resumeUniqueIds: Array.isArray(rf.resumeUniqueIds) ? rf.resumeUniqueIds.map(String) : [],
|
|
60
77
|
pageSize: typeof rf.pageSize === 'number' ? rf.pageSize : 20,
|
|
61
78
|
}
|
|
62
79
|
}
|
|
80
|
+
const displayCount = readOptionalCount(node.resumeDisplayCount)
|
|
81
|
+
if (displayCount !== undefined) block.resumeDisplayCount = displayCount
|
|
82
|
+
if (node.contentFilter && typeof node.contentFilter === 'object') {
|
|
83
|
+
const cf = node.contentFilter as Record<string, unknown>
|
|
84
|
+
const flowType = helpers.asLiteral(cf.flowType)?.trim()
|
|
85
|
+
const category = helpers.asLiteral(cf.category)?.trim()
|
|
86
|
+
block.contentFilter = {
|
|
87
|
+
flowType: flowType || 'content-production',
|
|
88
|
+
...(category ? { category } : {}),
|
|
89
|
+
tagUniqueIds: Array.isArray(cf.tagUniqueIds) ? cf.tagUniqueIds.map(String).filter(Boolean) : [],
|
|
90
|
+
tagMatch: cf.tagMatch === 'any' ? 'any' : 'all',
|
|
91
|
+
pageSize: typeof cf.pageSize === 'number' ? cf.pageSize : 20,
|
|
92
|
+
}
|
|
93
|
+
}
|
|
63
94
|
const minCount = readOptionalCount(node.minCount)
|
|
64
95
|
if (minCount !== undefined) block.resumeMinCount = minCount
|
|
65
96
|
const maxCount = readOptionalCount(node.maxCount)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createContext, useContext, type ReactNode } from 'react'
|
|
2
|
+
import type { FormContentFilter } from '../types/index'
|
|
3
|
+
|
|
4
|
+
export interface ContentSearchItem {
|
|
5
|
+
flowUniqueId: string
|
|
6
|
+
flowId?: number
|
|
7
|
+
name: string
|
|
8
|
+
description?: string
|
|
9
|
+
/** 内容方案标签的展示文案 */
|
|
10
|
+
tagLabels?: string[]
|
|
11
|
+
/** 最新案例名;没有案例时用流程名 */
|
|
12
|
+
title: string
|
|
13
|
+
platform?: string | null
|
|
14
|
+
coverUrl?: string | null
|
|
15
|
+
/** 可播放的视频地址;没有视频时为空 */
|
|
16
|
+
mediaUrl?: string | null
|
|
17
|
+
mediaKind?: 'video' | 'image' | null
|
|
18
|
+
link?: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ContentSearchParams {
|
|
22
|
+
filter: FormContentFilter
|
|
23
|
+
page: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ContentSearchResult {
|
|
27
|
+
list: ContentSearchItem[]
|
|
28
|
+
total: number
|
|
29
|
+
page: number
|
|
30
|
+
pageSize: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type ContentSearchFn = (params: ContentSearchParams) => Promise<ContentSearchResult>
|
|
34
|
+
|
|
35
|
+
const ContentSearchContext = createContext<ContentSearchFn | null>(null)
|
|
36
|
+
|
|
37
|
+
export function ContentSearchProvider({
|
|
38
|
+
contentSearch,
|
|
39
|
+
children,
|
|
40
|
+
}: {
|
|
41
|
+
contentSearch: ContentSearchFn | null | undefined
|
|
42
|
+
children: ReactNode
|
|
43
|
+
}) {
|
|
44
|
+
return (
|
|
45
|
+
<ContentSearchContext.Provider value={contentSearch ?? null}>
|
|
46
|
+
{children}
|
|
47
|
+
</ContentSearchContext.Provider>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function useContentSearch(): ContentSearchFn | null {
|
|
52
|
+
return useContext(ContentSearchContext)
|
|
53
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { advanceCursor, nextPageForWindow, windowIndexes } from './pairResumeContent'
|
|
3
|
+
|
|
4
|
+
describe('resume and content windows', () => {
|
|
5
|
+
it('pairs independent cursors and wraps only the side that is used up', () => {
|
|
6
|
+
let resumeCursor = 0
|
|
7
|
+
let contentCursor = 0
|
|
8
|
+
const displayCount = 3
|
|
9
|
+
const rounds = [
|
|
10
|
+
[[1, 2, 3], [1, 2, 3]],
|
|
11
|
+
[[4, 5, 6], [4, 5, 6]],
|
|
12
|
+
[[7, 8, 9], [7, 8, 9]],
|
|
13
|
+
[[10, 1, 2], [10, 11, 12]],
|
|
14
|
+
]
|
|
15
|
+
for (const [resumes, contents] of rounds) {
|
|
16
|
+
expect(windowIndexes(resumeCursor, displayCount, 10).map((index) => index + 1)).toEqual(resumes)
|
|
17
|
+
expect(windowIndexes(contentCursor, displayCount, 100).map((index) => index + 1)).toEqual(contents)
|
|
18
|
+
resumeCursor = advanceCursor(resumeCursor, displayCount, 10)
|
|
19
|
+
contentCursor = advanceCursor(contentCursor, displayCount, 100)
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('fetches the next page only when a window index is past the cache and more pages exist', () => {
|
|
24
|
+
const cached = { itemCount: 20, total: 100, fetchedPage: 1, pageSize: 20 }
|
|
25
|
+
expect(nextPageForWindow(cached, windowIndexes(0, 3, 100))).toBeNull()
|
|
26
|
+
expect(nextPageForWindow(cached, windowIndexes(18, 3, 100))).toBe(2)
|
|
27
|
+
expect(
|
|
28
|
+
nextPageForWindow(
|
|
29
|
+
{ itemCount: 10, total: 10, fetchedPage: 1, pageSize: 20 },
|
|
30
|
+
windowIndexes(9, 3, 10),
|
|
31
|
+
),
|
|
32
|
+
).toBeNull()
|
|
33
|
+
})
|
|
34
|
+
})
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export const DEFAULT_RESUME_DISPLAY_COUNT = 5
|
|
2
|
+
|
|
3
|
+
export interface PageCacheSnapshot {
|
|
4
|
+
itemCount: number
|
|
5
|
+
total: number
|
|
6
|
+
fetchedPage: number
|
|
7
|
+
pageSize: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function normalizeDisplayCount(raw: unknown, fallback = DEFAULT_RESUME_DISPLAY_COUNT): number {
|
|
11
|
+
const num = typeof raw === 'number' ? raw : Number(raw)
|
|
12
|
+
if (!Number.isFinite(num) || num < 1) return fallback
|
|
13
|
+
return Math.min(100, Math.floor(num))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function pairKey(resumeUniqueId: string, flowUniqueId: string): string {
|
|
17
|
+
return `${resumeUniqueId}|${flowUniqueId}`
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function hasMorePages(cache: PageCacheSnapshot): boolean {
|
|
21
|
+
if (cache.total <= 0 || cache.pageSize <= 0) return false
|
|
22
|
+
return cache.fetchedPage * cache.pageSize < cache.total
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function advanceCursor(cursor: number, displayCount: number, total: number): number {
|
|
26
|
+
if (total <= 0) return 0
|
|
27
|
+
const step = Math.max(1, displayCount)
|
|
28
|
+
return (((cursor % total) + total) % total + step) % total
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** 一轮要展示的下标。总数不够展示条数时只取总数那么多。 */
|
|
32
|
+
export function windowIndexes(cursor: number, displayCount: number, total: number): number[] {
|
|
33
|
+
if (total <= 0 || displayCount <= 0) return []
|
|
34
|
+
const count = Math.min(displayCount, total)
|
|
35
|
+
const start = ((cursor % total) + total) % total
|
|
36
|
+
return Array.from({ length: count }, (_, index) => (start + index) % total)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 窗口里有下标还没进缓存,并且接口还有下一页时,返回要请求的页码。
|
|
41
|
+
* 已经拿完则返回 null,调用方用缓存开头接上。
|
|
42
|
+
*/
|
|
43
|
+
export function nextPageForWindow(cache: PageCacheSnapshot, indexes: number[]): number | null {
|
|
44
|
+
if (indexes.length === 0) return null
|
|
45
|
+
if (!indexes.some((index) => index >= cache.itemCount)) return null
|
|
46
|
+
if (!hasMorePages(cache)) return null
|
|
47
|
+
return cache.fetchedPage + 1
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function takeWindow<T>(items: T[], cursor: number, displayCount: number, total: number): T[] {
|
|
51
|
+
const indexes = windowIndexes(cursor, displayCount, total)
|
|
52
|
+
if (indexes.length === 0) return []
|
|
53
|
+
if (indexes.some((index) => index >= items.length)) return []
|
|
54
|
+
return indexes.map((index) => items[index])
|
|
55
|
+
}
|