@roll-agent/smart-reply-agent 0.1.0 → 0.1.1

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.
Files changed (129) hide show
  1. package/dist/ai/model-registry.d.ts +0 -1
  2. package/dist/ai/model-registry.js +1 -205
  3. package/dist/ai/structured-output.d.ts +0 -1
  4. package/dist/ai/structured-output.js +1 -78
  5. package/dist/errors/app-error.d.ts +0 -1
  6. package/dist/errors/app-error.js +1 -95
  7. package/dist/errors/error-codes.d.ts +0 -1
  8. package/dist/errors/error-codes.js +1 -115
  9. package/dist/errors/error-factory.d.ts +0 -1
  10. package/dist/errors/error-factory.js +1 -86
  11. package/dist/errors/error-utils.d.ts +0 -1
  12. package/dist/errors/error-utils.js +1 -188
  13. package/dist/errors/index.d.ts +0 -1
  14. package/dist/errors/index.js +1 -5
  15. package/dist/index.d.ts +0 -1
  16. package/dist/index.js +1 -12
  17. package/dist/log-control.d.ts +0 -1
  18. package/dist/log-control.js +1 -15
  19. package/dist/pipeline/age-eligibility.d.ts +0 -1
  20. package/dist/pipeline/age-eligibility.js +1 -176
  21. package/dist/pipeline/candidate-context.d.ts +0 -1
  22. package/dist/pipeline/candidate-context.js +1 -31
  23. package/dist/pipeline/candidate-utils.d.ts +0 -1
  24. package/dist/pipeline/candidate-utils.js +1 -33
  25. package/dist/pipeline/classification.d.ts +0 -1
  26. package/dist/pipeline/classification.js +1 -206
  27. package/dist/pipeline/context-builder.d.ts +0 -1
  28. package/dist/pipeline/context-builder.js +1 -404
  29. package/dist/pipeline/pipeline-progress.d.ts +0 -1
  30. package/dist/pipeline/pipeline-progress.js +1 -33
  31. package/dist/pipeline/reply-gate.d.ts +0 -1
  32. package/dist/pipeline/reply-gate.js +1 -139
  33. package/dist/pipeline/smart-reply.d.ts +0 -1
  34. package/dist/pipeline/smart-reply.js +1 -418
  35. package/dist/pipeline.d.ts +0 -1
  36. package/dist/pipeline.js +1 -12
  37. package/dist/services/brand-alias.d.ts +0 -1
  38. package/dist/services/brand-alias.js +1 -184
  39. package/dist/services/brand-config-selectors.d.ts +0 -1
  40. package/dist/services/brand-config-selectors.js +1 -30
  41. package/dist/services/config-loader.d.ts +0 -1
  42. package/dist/services/config-loader.js +1 -45
  43. package/dist/services/duliday-api.d.ts +0 -1
  44. package/dist/services/duliday-api.js +1 -160
  45. package/dist/services/duliday-mapper.d.ts +0 -1
  46. package/dist/services/duliday-mapper.js +1 -536
  47. package/dist/tools/generate-reply.d.ts +0 -1
  48. package/dist/tools/generate-reply.js +1 -132
  49. package/dist/tools/sync-brand-data.d.ts +0 -1
  50. package/dist/tools/sync-brand-data.js +1 -114
  51. package/dist/types/brand-resolution.d.ts +0 -1
  52. package/dist/types/brand-resolution.js +1 -37
  53. package/dist/types/classification.d.ts +0 -1
  54. package/dist/types/classification.js +1 -30
  55. package/dist/types/config.d.ts +0 -1
  56. package/dist/types/config.js +1 -7
  57. package/dist/types/duliday-api.d.ts +0 -1
  58. package/dist/types/duliday-api.js +1 -235
  59. package/dist/types/geocoding.d.ts +0 -1
  60. package/dist/types/geocoding.js +1 -12
  61. package/dist/types/reply-policy.d.ts +0 -1
  62. package/dist/types/reply-policy.js +1 -332
  63. package/dist/types/zhipin.d.ts +0 -1
  64. package/dist/types/zhipin.js +1 -123
  65. package/package.json +3 -3
  66. package/dist/ai/model-registry.d.ts.map +0 -1
  67. package/dist/ai/model-registry.js.map +0 -1
  68. package/dist/ai/structured-output.d.ts.map +0 -1
  69. package/dist/ai/structured-output.js.map +0 -1
  70. package/dist/errors/app-error.d.ts.map +0 -1
  71. package/dist/errors/app-error.js.map +0 -1
  72. package/dist/errors/error-codes.d.ts.map +0 -1
  73. package/dist/errors/error-codes.js.map +0 -1
  74. package/dist/errors/error-factory.d.ts.map +0 -1
  75. package/dist/errors/error-factory.js.map +0 -1
  76. package/dist/errors/error-utils.d.ts.map +0 -1
  77. package/dist/errors/error-utils.js.map +0 -1
  78. package/dist/errors/index.d.ts.map +0 -1
  79. package/dist/errors/index.js.map +0 -1
  80. package/dist/index.d.ts.map +0 -1
  81. package/dist/index.js.map +0 -1
  82. package/dist/log-control.d.ts.map +0 -1
  83. package/dist/log-control.js.map +0 -1
  84. package/dist/pipeline/age-eligibility.d.ts.map +0 -1
  85. package/dist/pipeline/age-eligibility.js.map +0 -1
  86. package/dist/pipeline/candidate-context.d.ts.map +0 -1
  87. package/dist/pipeline/candidate-context.js.map +0 -1
  88. package/dist/pipeline/candidate-utils.d.ts.map +0 -1
  89. package/dist/pipeline/candidate-utils.js.map +0 -1
  90. package/dist/pipeline/classification.d.ts.map +0 -1
  91. package/dist/pipeline/classification.js.map +0 -1
  92. package/dist/pipeline/context-builder.d.ts.map +0 -1
  93. package/dist/pipeline/context-builder.js.map +0 -1
  94. package/dist/pipeline/pipeline-progress.d.ts.map +0 -1
  95. package/dist/pipeline/pipeline-progress.js.map +0 -1
  96. package/dist/pipeline/reply-gate.d.ts.map +0 -1
  97. package/dist/pipeline/reply-gate.js.map +0 -1
  98. package/dist/pipeline/smart-reply.d.ts.map +0 -1
  99. package/dist/pipeline/smart-reply.js.map +0 -1
  100. package/dist/pipeline.d.ts.map +0 -1
  101. package/dist/pipeline.js.map +0 -1
  102. package/dist/services/brand-alias.d.ts.map +0 -1
  103. package/dist/services/brand-alias.js.map +0 -1
  104. package/dist/services/brand-config-selectors.d.ts.map +0 -1
  105. package/dist/services/brand-config-selectors.js.map +0 -1
  106. package/dist/services/config-loader.d.ts.map +0 -1
  107. package/dist/services/config-loader.js.map +0 -1
  108. package/dist/services/duliday-api.d.ts.map +0 -1
  109. package/dist/services/duliday-api.js.map +0 -1
  110. package/dist/services/duliday-mapper.d.ts.map +0 -1
  111. package/dist/services/duliday-mapper.js.map +0 -1
  112. package/dist/tools/generate-reply.d.ts.map +0 -1
  113. package/dist/tools/generate-reply.js.map +0 -1
  114. package/dist/tools/sync-brand-data.d.ts.map +0 -1
  115. package/dist/tools/sync-brand-data.js.map +0 -1
  116. package/dist/types/brand-resolution.d.ts.map +0 -1
  117. package/dist/types/brand-resolution.js.map +0 -1
  118. package/dist/types/classification.d.ts.map +0 -1
  119. package/dist/types/classification.js.map +0 -1
  120. package/dist/types/config.d.ts.map +0 -1
  121. package/dist/types/config.js.map +0 -1
  122. package/dist/types/duliday-api.d.ts.map +0 -1
  123. package/dist/types/duliday-api.js.map +0 -1
  124. package/dist/types/geocoding.d.ts.map +0 -1
  125. package/dist/types/geocoding.js.map +0 -1
  126. package/dist/types/reply-policy.d.ts.map +0 -1
  127. package/dist/types/reply-policy.js.map +0 -1
  128. package/dist/types/zhipin.d.ts.map +0 -1
  129. package/dist/types/zhipin.js.map +0 -1
@@ -1,536 +1 @@
1
- import { DulidayNewPositionSchema } from "../types/duliday-api.js";
2
- // ========== 解析入口 ==========
3
- function parsePosition(raw) {
4
- const parsed = DulidayNewPositionSchema.safeParse(raw);
5
- if (!parsed.success)
6
- return null;
7
- const pos = parsed.data;
8
- const basic = pos.basicInfo;
9
- const store = basic.storeInfo;
10
- const salary = pos.jobSalary;
11
- const hiring = pos.hiringRequirement;
12
- const resolvedSalary = salary.salary ??
13
- salary.salaryScenarioList?.find((s) => s.salaryType === "正式")?.basicSalary?.basicSalary ??
14
- salary.salaryScenarioList?.[0]?.basicSalary?.basicSalary ??
15
- 0;
16
- const resolvedSalaryUnit = salary.salaryUnitStr ??
17
- salary.salaryScenarioList?.find((s) => s.salaryType === "正式")?.basicSalary?.basicSalaryUnit ??
18
- salary.salaryScenarioList?.[0]?.basicSalary?.basicSalaryUnit ??
19
- "元/小时";
20
- // storeId fallback: hash from storeName+address
21
- let storeId = store?.storeId;
22
- if (storeId == null) {
23
- const source = `${store?.storeName ?? ""}|${store?.storeAddress ?? ""}`;
24
- storeId = Array.from(source).reduce((acc, char) => (acc * 31 + char.charCodeAt(0)) >>> 0, 7);
25
- }
26
- return {
27
- jobId: basic.jobId,
28
- jobName: basic.jobName,
29
- jobContent: basic.jobContent ?? null,
30
- brandId: basic.brandId !== undefined
31
- ? String(basic.brandId)
32
- : basic.projectId !== undefined
33
- ? String(basic.projectId)
34
- : undefined,
35
- brandName: basic.brandName,
36
- projectId: basic.projectId,
37
- projectName: basic.projectName,
38
- storeId,
39
- storeName: store?.storeName ?? "未知门店",
40
- storeCityName: store?.storeCityName ?? "",
41
- storeRegionName: store?.storeRegionName,
42
- storeAddress: store?.storeAddress ?? "",
43
- longitude: store?.longitude,
44
- latitude: store?.latitude,
45
- salary: resolvedSalary,
46
- salaryUnitStr: resolvedSalaryUnit,
47
- salaryScenarioList: salary.salaryScenarioList ?? null,
48
- welfare: pos.welfare,
49
- cooperationMode: hiring.cooperationMode ?? 0,
50
- requirementNum: hiring.requirementNum ?? 0,
51
- thresholdNum: hiring.thresholdNum ?? 0,
52
- signUpNum: hiring.signUpNum ?? null,
53
- basicPersonalRequirements: hiring.basicPersonalRequirements
54
- ? {
55
- minAge: hiring.basicPersonalRequirements.minAge ?? null,
56
- maxAge: hiring.basicPersonalRequirements.maxAge ?? null,
57
- genderRequirement: hiring.basicPersonalRequirements.genderRequirement ?? null,
58
- }
59
- : null,
60
- certificate: hiring.certificate
61
- ? {
62
- education: hiring.certificate.education ?? null,
63
- healthCertificate: hiring.certificate.healthCertificate ?? null,
64
- }
65
- : null,
66
- workTime: pos.workTime,
67
- };
68
- }
69
- // ========== 核心入口 ==========
70
- export function convertPositionsToZhipinData(rawPositions, preferredDefaultBrandName, cityName) {
71
- const brands = new Map();
72
- let defaultBrandId;
73
- for (let i = 0; i < rawPositions.length; i++) {
74
- const parsed = parsePosition(rawPositions[i]);
75
- if (!parsed)
76
- continue;
77
- const resolvedBrandName = parsed.brandName ?? preferredDefaultBrandName ?? "未知品牌";
78
- const resolvedBrandId = parsed.brandId ?? `name:${resolvedBrandName}`;
79
- if (defaultBrandId === undefined &&
80
- (preferredDefaultBrandName === undefined || resolvedBrandName === preferredDefaultBrandName)) {
81
- defaultBrandId = resolvedBrandId;
82
- }
83
- let brand = brands.get(resolvedBrandId);
84
- if (!brand) {
85
- brand = {
86
- id: resolvedBrandId,
87
- name: resolvedBrandName,
88
- stores: [],
89
- };
90
- brands.set(resolvedBrandId, brand);
91
- }
92
- const storeKey = `store_${parsed.storeId}`;
93
- let store = brand.stores.find((item) => item.id === storeKey);
94
- if (!store) {
95
- store = convertToStore(parsed, resolvedBrandId, cityName);
96
- brand.stores.push(store);
97
- }
98
- const position = convertToPosition(parsed);
99
- store.positions.push(position);
100
- }
101
- return {
102
- meta: {
103
- ...((defaultBrandId ?? brands.values().next().value?.id)
104
- ? { defaultBrandId: defaultBrandId ?? brands.values().next().value?.id }
105
- : {}),
106
- syncedAt: new Date().toISOString(),
107
- source: "duliday",
108
- },
109
- brands: Array.from(brands.values()),
110
- };
111
- }
112
- // ========== Store / Position 转换 ==========
113
- function convertToStore(p, brandId, fallbackCity) {
114
- return {
115
- id: `store_${p.storeId}`,
116
- brandId,
117
- name: p.storeName,
118
- city: p.storeCityName || fallbackCity,
119
- location: p.storeAddress,
120
- district: extractDistrict(p.storeAddress, p.storeRegionName),
121
- subarea: extractSubarea(p.storeName),
122
- coordinates: typeof p.latitude === "number" && typeof p.longitude === "number"
123
- ? { lat: p.latitude, lng: p.longitude }
124
- : { lat: 0, lng: 0 },
125
- positions: [],
126
- };
127
- }
128
- function convertToPosition(p) {
129
- const wta = normalizeNewWorkTime(p.workTime);
130
- let timeSlots = [];
131
- if (wta.combinedArrangementTimes?.length) {
132
- timeSlots = convertTimeSlots(wta.combinedArrangementTimes);
133
- }
134
- else if (wta.fixedArrangementTimes?.length) {
135
- timeSlots = convertTimeSlots(wta.fixedArrangementTimes.map((s) => ({ ...s, weekdays: [] })));
136
- }
137
- return {
138
- id: `pos_${p.jobId}`,
139
- name: extractPositionType(p.jobName),
140
- brandId: p.brandId,
141
- brandName: p.brandName,
142
- projectId: p.projectId !== undefined ? String(p.projectId) : undefined,
143
- projectName: p.projectName,
144
- timeSlots,
145
- salary: {
146
- ...parseSalaryDetails(p.salary, p.welfare),
147
- scenarioSummary: buildScenarioSummary(p.salaryScenarioList),
148
- settlementCycle: extractSettlementCycle(p.salaryScenarioList),
149
- },
150
- workHours: String(wta.perDayMinWorkHours ?? 8),
151
- benefits: parseBenefits(p.welfare),
152
- requirements: generateRequirements(p),
153
- urgent: p.requirementNum > 3,
154
- scheduleType: p.cooperationMode === 2 ? "flexible" : "fixed",
155
- attendancePolicy: generateAttendancePolicy(p.cooperationMode),
156
- availableSlots: generateAvailableSlots(p, wta),
157
- schedulingFlexibility: generateSchedulingFlexibility(p, wta),
158
- minHoursPerWeek: calculateMinHoursPerWeek(wta),
159
- maxHoursPerWeek: calculateMaxHoursPerWeek(wta),
160
- attendanceRequirement: generateAttendanceRequirement(wta),
161
- hiringRequirements: extractHiringRequirements(p),
162
- description: p.jobContent || undefined,
163
- };
164
- }
165
- function normalizeNewWorkTime(nwt) {
166
- const week = nwt.weekWorkTime;
167
- const day = nwt.dayWorkTime;
168
- const schedule = nwt.dailyShiftSchedule;
169
- const employmentFormMap = {
170
- 长期用工: 1,
171
- 临时用工: 2,
172
- 短期用工: 2,
173
- };
174
- const arrangementTypeMap = { 固定排班制: 1, 组合排班制: 3 };
175
- const employmentForm = Number(nwt.employmentForm) || (employmentFormMap[String(nwt.employmentForm)] ?? 1);
176
- const arrangementType = Number(schedule?.arrangementType) ||
177
- (arrangementTypeMap[String(schedule?.arrangementType)] ?? 0);
178
- const rawPerDay = day?.perDayMinWorkHours != null ? Number(day.perDayMinWorkHours) : null;
179
- const perDayMinWorkHours = rawPerDay !== null && Number.isFinite(rawPerDay) ? rawPerDay : null;
180
- const customWorkTimes = week?.customnWorkTimeList?.map((item) => ({
181
- weekdays: Array.isArray(item.customWorkWeekdays)
182
- ? item.customWorkWeekdays.map((d) => Number(d)).filter((d) => Number.isFinite(d))
183
- : [],
184
- minWorkDays: item.customMinWorkDays ?? null,
185
- maxWorkDays: item.customMaxWorkDays ?? null,
186
- })) ?? null;
187
- const fixedArrangementTimes = schedule?.fixedScheduleList?.map((item) => ({
188
- startTime: item.startTime ?? parseTimeStringToSeconds(item.fixedShiftStartTime),
189
- endTime: item.endTime ?? parseTimeStringToSeconds(item.fixedShiftEndTime),
190
- })) ?? null;
191
- const combinedArrangementTimes = schedule?.combinedArrangement?.map((item) => {
192
- const rawWeekdays = item.weekdays ??
193
- (typeof item.CombinedArrangementWeekdays === "string"
194
- ? [Number(item.CombinedArrangementWeekdays)]
195
- : Array.isArray(item.CombinedArrangementWeekdays)
196
- ? item.CombinedArrangementWeekdays
197
- : []);
198
- const weekdays = rawWeekdays
199
- .map((d) => (typeof d === "number" ? d : Number(d)))
200
- .filter((d) => Number.isFinite(d));
201
- return {
202
- startTime: item.startTime ?? item.CombinedArrangementStartTime ?? 0,
203
- endTime: item.endTime ?? item.CombinedArrangementEndTime ?? 0,
204
- weekdays,
205
- };
206
- }) ?? null;
207
- return {
208
- employmentForm,
209
- perDayMinWorkHours,
210
- perWeekWorkDays: week?.perWeekWorkDays ?? null,
211
- perWeekNeedWorkDays: week?.perWeekNeedWorkDays != null ? Number(week.perWeekNeedWorkDays) : null,
212
- perWeekRestDays: week?.perWeekRestDays ?? null,
213
- arrangementType,
214
- maxWorkTakingTime: nwt.maxWorkTakingTime ?? 0,
215
- workTimeRemark: nwt.workTimeRemark ?? null,
216
- fixedArrangementTimes,
217
- combinedArrangementTimes,
218
- customWorkTimes,
219
- };
220
- }
221
- // ========== 薪资 ==========
222
- export function parseSalaryDetails(baseSalary, welfare) {
223
- const memo = welfare.memo || "";
224
- const rangeMatch = memo.match(/(\d+元?-\d+元?)/);
225
- const range = rangeMatch ? rangeMatch[1] : undefined;
226
- const bonusMatch = memo.match(/(奖金[\d~\-~元]+)/);
227
- const bonus = bonusMatch ? bonusMatch[1] : undefined;
228
- return { base: baseSalary, range, bonus, memo };
229
- }
230
- export function buildScenarioSummary(scenarios) {
231
- if (!scenarios || scenarios.length === 0)
232
- return undefined;
233
- const parts = [];
234
- for (const s of scenarios) {
235
- if (s.salaryType === "培训期")
236
- continue;
237
- if (s.stairSalaries?.length) {
238
- const stairs = s.stairSalaries
239
- .filter((st) => st.salary != null)
240
- .map((st) => {
241
- const unit = st.salaryUnit ?? "元/时";
242
- return `满${st.fullWorkTime ?? "?"}${st.fullWorkTimeUnit ?? "小时"}后${st.salary}${unit}`;
243
- })
244
- .join(",");
245
- if (stairs)
246
- parts.push(stairs);
247
- }
248
- const comp = s.comprehensiveSalary;
249
- if (comp?.minComprehensiveSalary != null && comp?.maxComprehensiveSalary != null) {
250
- parts.push(`综合${comp.minComprehensiveSalary}-${comp.maxComprehensiveSalary}${comp.comprehensiveSalaryUnit ?? "元/月"}`);
251
- }
252
- const holiday = s.holidaySalary;
253
- if (holiday) {
254
- if (holiday.holidaySalaryMultiple) {
255
- parts.push(`节假日${holiday.holidaySalaryMultiple}倍`);
256
- }
257
- else if (holiday.holidayFixedSalary != null) {
258
- parts.push(`节假日${holiday.holidayFixedSalary}${holiday.holidayFixedSalaryUnit ?? "元/时"}`);
259
- }
260
- }
261
- }
262
- return parts.length > 0 ? parts.join(";") : undefined;
263
- }
264
- export function extractSettlementCycle(scenarios) {
265
- if (!scenarios || scenarios.length === 0)
266
- return undefined;
267
- const cycleMap = {
268
- 日结算: "日结",
269
- 周结算: "周结",
270
- 月结算: "月结",
271
- 完结算: "完结",
272
- 半月结算: "半月结",
273
- };
274
- const primary = scenarios.find((s) => s.salaryType === "正式") ?? scenarios[0];
275
- return cycleMap[primary?.salaryPeriod ?? ""] ?? undefined;
276
- }
277
- // ========== 福利 ==========
278
- export function parseBenefits(welfare) {
279
- const benefitItems = [];
280
- if (welfare.haveInsurance && welfare.haveInsurance !== "无" && welfare.haveInsurance !== "0") {
281
- benefitItems.push("五险一金");
282
- }
283
- if (welfare.accommodation && welfare.accommodation !== "无" && welfare.accommodation !== "0") {
284
- benefitItems.push("住宿");
285
- }
286
- if (welfare.catering && welfare.catering !== "无" && welfare.catering !== "0") {
287
- benefitItems.push("餐饮");
288
- }
289
- if (welfare.moreWelfares && Array.isArray(welfare.moreWelfares)) {
290
- for (const item of welfare.moreWelfares) {
291
- const content = item.content;
292
- const benefitKeywords = ["保险", "年假", "补贴", "福利", "股票", "学历提升"];
293
- for (const keyword of benefitKeywords) {
294
- if (content.includes(keyword) &&
295
- !benefitItems.some((existing) => existing.includes(keyword))) {
296
- const match = content.match(new RegExp(`\\d*[天个月年]*${keyword}[^,。]*`));
297
- benefitItems.push(match ? match[0] : keyword);
298
- }
299
- }
300
- }
301
- }
302
- if (welfare.memo) {
303
- const benefitKeywords = ["年假", "补贴", "商保", "股票", "学历提升"];
304
- for (const keyword of benefitKeywords) {
305
- if (welfare.memo.includes(keyword) && !benefitItems.some((item) => item.includes(keyword))) {
306
- benefitItems.push(keyword);
307
- }
308
- }
309
- }
310
- if (benefitItems.length === 0) {
311
- benefitItems.push("按国家规定");
312
- }
313
- return {
314
- items: benefitItems,
315
- promotion: welfare.promotionWelfare || undefined,
316
- };
317
- }
318
- export function generateRequirements(p) {
319
- const reqs = [];
320
- const bpr = p.basicPersonalRequirements;
321
- const cert = p.certificate;
322
- if (bpr?.minAge != null || bpr?.maxAge != null) {
323
- const min = bpr?.minAge ?? "不限";
324
- const max = bpr?.maxAge ?? "不限";
325
- reqs.push(`年龄${min}-${max}岁`);
326
- }
327
- if (bpr?.genderRequirement && bpr.genderRequirement !== "0") {
328
- const noRestriction = /男性.*女性|女性.*男性|不限/.test(bpr.genderRequirement);
329
- if (!noRestriction) {
330
- const genderMap = {
331
- 男性: "限男性",
332
- 女性: "限女性",
333
- };
334
- reqs.push(genderMap[bpr.genderRequirement] ?? `性别要求:${bpr.genderRequirement}`);
335
- }
336
- }
337
- if (cert?.education && cert.education !== "不限") {
338
- const eduMap = {
339
- 本科: "本科及以上",
340
- 专科: "专科及以上",
341
- 高中: "高中及以上",
342
- 初中: "初中及以上",
343
- };
344
- reqs.push(eduMap[cert.education] ?? `学历${cert.education}`);
345
- }
346
- if (cert?.healthCertificate) {
347
- const hcMap = {
348
- 食品健康证: "需食品健康证",
349
- 零售健康证: "需零售健康证",
350
- };
351
- reqs.push(hcMap[cert.healthCertificate] ?? "需健康证");
352
- }
353
- if (reqs.length === 0) {
354
- return generateDefaultRequirements(p.jobName);
355
- }
356
- return reqs;
357
- }
358
- function generateDefaultRequirements(jobName) {
359
- const base = ["工作认真负责", "团队合作精神"];
360
- if (jobName.includes("服务员")) {
361
- return [...base, "有服务行业经验优先", "沟通能力强"];
362
- }
363
- if (jobName.includes("经理")) {
364
- return [...base, "有管理经验", "责任心强"];
365
- }
366
- return [...base, "有相关工作经验者优先"];
367
- }
368
- function extractHiringRequirements(p) {
369
- const bpr = p.basicPersonalRequirements;
370
- const cert = p.certificate;
371
- if (!bpr && !cert)
372
- return undefined;
373
- return {
374
- minAge: bpr?.minAge ?? null,
375
- maxAge: bpr?.maxAge ?? null,
376
- genderRequirement: bpr?.genderRequirement ?? null,
377
- education: cert?.education ?? null,
378
- healthCertificate: cert?.healthCertificate ?? null,
379
- };
380
- }
381
- // ========== 考勤 ==========
382
- function generateAttendancePolicy(cooperationMode) {
383
- const isFullTime = cooperationMode === 3;
384
- return {
385
- punctualityRequired: isFullTime,
386
- lateToleranceMinutes: isFullTime ? 5 : 15,
387
- attendanceTracking: isFullTime ? "strict" : "flexible",
388
- makeupShiftsAllowed: !isFullTime,
389
- };
390
- }
391
- function generateAvailableSlots(p, wta) {
392
- const slots = [];
393
- let timeSlots = [];
394
- if (wta.combinedArrangementTimes?.length) {
395
- timeSlots = convertTimeSlots(wta.combinedArrangementTimes);
396
- }
397
- else if (wta.fixedArrangementTimes?.length) {
398
- timeSlots = convertTimeSlots(wta.fixedArrangementTimes.map((s) => ({ ...s, weekdays: [] })));
399
- }
400
- for (const slot of timeSlots) {
401
- slots.push({
402
- slot,
403
- maxCapacity: p.requirementNum,
404
- currentBooked: p.signUpNum || 0,
405
- isAvailable: (p.signUpNum || 0) < p.requirementNum,
406
- priority: p.requirementNum > 3 ? "high" : "medium",
407
- });
408
- }
409
- return slots;
410
- }
411
- function generateSchedulingFlexibility(p, wta) {
412
- const isFlexible = p.cooperationMode === 2;
413
- return {
414
- canSwapShifts: wta.arrangementType === 3 || isFlexible,
415
- advanceNoticeHours: wta.maxWorkTakingTime / 60,
416
- partTimeAllowed: isFlexible,
417
- weekendRequired: hasWeekendInSchedule(wta),
418
- holidayRequired: false,
419
- };
420
- }
421
- function hasWeekendInSchedule(wta) {
422
- if (!wta.combinedArrangementTimes)
423
- return false;
424
- return wta.combinedArrangementTimes.some((slot) => slot.weekdays.includes(0) || slot.weekdays.includes(6));
425
- }
426
- function calculateMinHoursPerWeek(wta) {
427
- const dailyHours = wta.perDayMinWorkHours ?? 8;
428
- let workDays = null;
429
- if (wta.perWeekWorkDays != null) {
430
- workDays = wta.perWeekWorkDays;
431
- }
432
- if (workDays === null && wta.customWorkTimes?.length) {
433
- const minWorkDaysArray = wta.customWorkTimes
434
- .map((ct) => ct.minWorkDays)
435
- .filter((days) => days !== null && days !== undefined);
436
- if (minWorkDaysArray.length > 0) {
437
- workDays = Math.min(...minWorkDaysArray);
438
- }
439
- }
440
- if (workDays === null && wta.perWeekNeedWorkDays != null) {
441
- workDays = wta.perWeekNeedWorkDays;
442
- }
443
- if (workDays === null) {
444
- workDays = 5;
445
- }
446
- return dailyHours * workDays;
447
- }
448
- function calculateMaxHoursPerWeek(wta) {
449
- const dailyHours = wta.perDayMinWorkHours ?? 8;
450
- return dailyHours * 7;
451
- }
452
- function generateAttendanceRequirement(wta) {
453
- let requiredDays = [];
454
- if (wta.combinedArrangementTimes?.length) {
455
- const allDays = new Set();
456
- for (const slot of wta.combinedArrangementTimes) {
457
- for (const day of slot.weekdays) {
458
- if (day != null && Number.isFinite(day))
459
- allDays.add(day);
460
- }
461
- }
462
- requiredDays = Array.from(allDays).sort();
463
- }
464
- else if (wta.customWorkTimes?.length) {
465
- const allDays = new Set();
466
- for (const customTime of wta.customWorkTimes) {
467
- for (const day of customTime.weekdays) {
468
- if (day != null && Number.isFinite(day))
469
- allDays.add(day);
470
- }
471
- }
472
- requiredDays = Array.from(allDays).sort();
473
- }
474
- let minimumDays = null;
475
- if (wta.perWeekWorkDays != null) {
476
- minimumDays = wta.perWeekWorkDays;
477
- }
478
- if (minimumDays === null && wta.customWorkTimes?.length) {
479
- const minWorkDaysArray = wta.customWorkTimes
480
- .map((ct) => ct.minWorkDays)
481
- .filter((days) => days !== null && days !== undefined);
482
- if (minWorkDaysArray.length > 0) {
483
- minimumDays = Math.min(...minWorkDaysArray);
484
- }
485
- }
486
- if (minimumDays === null && wta.perWeekNeedWorkDays != null) {
487
- minimumDays = wta.perWeekNeedWorkDays;
488
- }
489
- if (minimumDays === null) {
490
- minimumDays = 5;
491
- }
492
- return {
493
- minimumDays,
494
- requiredDays: convertWeekdays(requiredDays),
495
- description: wta.workTimeRemark || "",
496
- };
497
- }
498
- // ========== 时间工具 ==========
499
- export function parseTimeStringToSeconds(timeStr) {
500
- if (typeof timeStr === "number")
501
- return timeStr;
502
- if (typeof timeStr !== "string" || !timeStr)
503
- return 0;
504
- const match = timeStr.match(/^(\d{1,2}):(\d{2})$/);
505
- if (!match)
506
- return Number(timeStr) || 0;
507
- return Number(match[1]) * 3600 + Number(match[2]) * 60;
508
- }
509
- function convertTimeSlots(slots) {
510
- return slots.map((slot) => {
511
- const startHour = Math.floor(slot.startTime / 3600);
512
- const startMin = Math.floor((slot.startTime % 3600) / 60);
513
- const endHour = Math.floor(slot.endTime / 3600);
514
- const endMin = Math.floor((slot.endTime % 3600) / 60);
515
- return `${startHour.toString().padStart(2, "0")}:${startMin.toString().padStart(2, "0")}~${endHour.toString().padStart(2, "0")}:${endMin.toString().padStart(2, "0")}`;
516
- });
517
- }
518
- // ========== 地理 / 名称工具 ==========
519
- function extractDistrict(storeAddress, storeRegionName) {
520
- if (storeRegionName)
521
- return storeRegionName;
522
- const parts = storeAddress.split("-");
523
- return parts[1] || "未知区域";
524
- }
525
- function extractSubarea(storeName) {
526
- const match = storeName.match(/(.+?)(附近|周边|旁边|店)/);
527
- return match?.[1] ?? storeName;
528
- }
529
- function extractPositionType(jobName) {
530
- const parts = jobName.split("-");
531
- return parts[parts.length - 2] || "服务员";
532
- }
533
- function convertWeekdays(dulidayWeekdays) {
534
- return dulidayWeekdays.filter((day) => Number.isFinite(day)).map((day) => (day === 0 ? 7 : day));
535
- }
536
- //# sourceMappingURL=duliday-mapper.js.map
1
+ import{DulidayNewPositionSchema as e}from"../types/duliday-api.js";function r(r){const n=e.safeParse(r);if(!n.success)return null;const t=n.data,i=t.basicInfo,a=i.storeInfo,o=t.jobSalary,s=t.hiringRequirement,m=o.salary??o.salaryScenarioList?.find(e=>"正式"===e.salaryType)?.basicSalary?.basicSalary??o.salaryScenarioList?.[0]?.basicSalary?.basicSalary??0,l=o.salaryUnitStr??o.salaryScenarioList?.find(e=>"正式"===e.salaryType)?.basicSalary?.basicSalaryUnit??o.salaryScenarioList?.[0]?.basicSalary?.basicSalaryUnit??"元/小时";let u=a?.storeId;if(null==u){const e=`${a?.storeName??""}|${a?.storeAddress??""}`;u=Array.from(e).reduce((e,r)=>31*e+r.charCodeAt(0)>>>0,7)}return{jobId:i.jobId,jobName:i.jobName,jobContent:i.jobContent??null,brandId:void 0!==i.brandId?String(i.brandId):void 0!==i.projectId?String(i.projectId):void 0,brandName:i.brandName,projectId:i.projectId,projectName:i.projectName,storeId:u,storeName:a?.storeName??"未知门店",storeCityName:a?.storeCityName??"",storeRegionName:a?.storeRegionName,storeAddress:a?.storeAddress??"",longitude:a?.longitude,latitude:a?.latitude,salary:m,salaryUnitStr:l,salaryScenarioList:o.salaryScenarioList??null,welfare:t.welfare,cooperationMode:s.cooperationMode??0,requirementNum:s.requirementNum??0,thresholdNum:s.thresholdNum??0,signUpNum:s.signUpNum??null,basicPersonalRequirements:s.basicPersonalRequirements?{minAge:s.basicPersonalRequirements.minAge??null,maxAge:s.basicPersonalRequirements.maxAge??null,genderRequirement:s.basicPersonalRequirements.genderRequirement??null}:null,certificate:s.certificate?{education:s.certificate.education??null,healthCertificate:s.certificate.healthCertificate??null}:null,workTime:t.workTime}}export function convertPositionsToZhipinData(e,i,a){const o=new Map;let s;for(let m=0;m<e.length;m++){const l=r(e[m]);if(!l)continue;const u=l.brandName??i??"未知品牌",c=l.brandId??`name:${u}`;void 0!==s||void 0!==i&&u!==i||(s=c);let d=o.get(c);d||(d={id:c,name:u,stores:[]},o.set(c,d));const y=`store_${l.storeId}`;let f=d.stores.find(e=>e.id===y);f||(f=n(l,c,a),d.stores.push(f));const p=t(l);f.positions.push(p)}return{meta:{...s??o.values().next().value?.id?{defaultBrandId:s??o.values().next().value?.id}:{},syncedAt:(new Date).toISOString(),source:"duliday"},brands:Array.from(o.values())}}function n(e,r,n){return{id:`store_${e.storeId}`,brandId:r,name:e.storeName,city:e.storeCityName||n,location:e.storeAddress,district:p(e.storeAddress,e.storeRegionName),subarea:g(e.storeName),coordinates:"number"==typeof e.latitude&&"number"==typeof e.longitude?{lat:e.latitude,lng:e.longitude}:{lat:0,lng:0},positions:[]}}function t(e){const r=i(e.workTime);let n=[];return r.combinedArrangementTimes?.length?n=f(r.combinedArrangementTimes):r.fixedArrangementTimes?.length&&(n=f(r.fixedArrangementTimes.map(e=>({...e,weekdays:[]})))),{id:`pos_${e.jobId}`,name:h(e.jobName),brandId:e.brandId,brandName:e.brandName,projectId:void 0!==e.projectId?String(e.projectId):void 0,projectName:e.projectName,timeSlots:n,salary:{...parseSalaryDetails(e.salary,e.welfare),scenarioSummary:buildScenarioSummary(e.salaryScenarioList),settlementCycle:extractSettlementCycle(e.salaryScenarioList)},workHours:String(r.perDayMinWorkHours??8),benefits:parseBenefits(e.welfare),requirements:generateRequirements(e),urgent:e.requirementNum>3,scheduleType:2===e.cooperationMode?"flexible":"fixed",attendancePolicy:s(e.cooperationMode),availableSlots:m(e,r),schedulingFlexibility:l(e,r),minHoursPerWeek:c(r),maxHoursPerWeek:d(r),attendanceRequirement:y(r),hiringRequirements:o(e),description:e.jobContent||void 0}}function i(e){const r=e.weekWorkTime,n=e.dayWorkTime,t=e.dailyShiftSchedule,i=Number(e.employmentForm)||({"长期用工":1,"临时用工":2,"短期用工":2}[String(e.employmentForm)]??1),a=Number(t?.arrangementType)||({"固定排班制":1,"组合排班制":3}[String(t?.arrangementType)]??0),o=null!=n?.perDayMinWorkHours?Number(n.perDayMinWorkHours):null,s=null!==o&&Number.isFinite(o)?o:null,m=r?.customnWorkTimeList?.map(e=>({weekdays:Array.isArray(e.customWorkWeekdays)?e.customWorkWeekdays.map(e=>Number(e)).filter(e=>Number.isFinite(e)):[],minWorkDays:e.customMinWorkDays??null,maxWorkDays:e.customMaxWorkDays??null}))??null,l=t?.fixedScheduleList?.map(e=>({startTime:e.startTime??parseTimeStringToSeconds(e.fixedShiftStartTime),endTime:e.endTime??parseTimeStringToSeconds(e.fixedShiftEndTime)}))??null,u=t?.combinedArrangement?.map(e=>{const r=(e.weekdays??("string"==typeof e.CombinedArrangementWeekdays?[Number(e.CombinedArrangementWeekdays)]:Array.isArray(e.CombinedArrangementWeekdays)?e.CombinedArrangementWeekdays:[])).map(e=>"number"==typeof e?e:Number(e)).filter(e=>Number.isFinite(e));return{startTime:e.startTime??e.CombinedArrangementStartTime??0,endTime:e.endTime??e.CombinedArrangementEndTime??0,weekdays:r}})??null;return{employmentForm:i,perDayMinWorkHours:s,perWeekWorkDays:r?.perWeekWorkDays??null,perWeekNeedWorkDays:null!=r?.perWeekNeedWorkDays?Number(r.perWeekNeedWorkDays):null,perWeekRestDays:r?.perWeekRestDays??null,arrangementType:a,maxWorkTakingTime:e.maxWorkTakingTime??0,workTimeRemark:e.workTimeRemark??null,fixedArrangementTimes:l,combinedArrangementTimes:u,customWorkTimes:m}}export function parseSalaryDetails(e,r){const n=r.memo||"",t=n.match(/(\d+元?-\d+元?)/),i=t?t[1]:void 0,a=n.match(/(奖金[\d~\-~元]+)/);return{base:e,range:i,bonus:a?a[1]:void 0,memo:n}}export function buildScenarioSummary(e){if(!e||0===e.length)return;const r=[];for(const n of e){if("培训期"===n.salaryType)continue;if(n.stairSalaries?.length){const e=n.stairSalaries.filter(e=>null!=e.salary).map(e=>{const r=e.salaryUnit??"元/时";return`满${e.fullWorkTime??"?"}${e.fullWorkTimeUnit??"小时"}后${e.salary}${r}`}).join(",");e&&r.push(e)}const e=n.comprehensiveSalary;null!=e?.minComprehensiveSalary&&null!=e?.maxComprehensiveSalary&&r.push(`综合${e.minComprehensiveSalary}-${e.maxComprehensiveSalary}${e.comprehensiveSalaryUnit??"元/月"}`);const t=n.holidaySalary;t&&(t.holidaySalaryMultiple?r.push(`节假日${t.holidaySalaryMultiple}倍`):null!=t.holidayFixedSalary&&r.push(`节假日${t.holidayFixedSalary}${t.holidayFixedSalaryUnit??"元/时"}`))}return r.length>0?r.join(";"):void 0}export function extractSettlementCycle(e){if(!e||0===e.length)return;const r=e.find(e=>"正式"===e.salaryType)??e[0];return{"日结算":"日结","周结算":"周结","月结算":"月结","完结算":"完结","半月结算":"半月结"}[r?.salaryPeriod??""]??void 0}export function parseBenefits(e){const r=[];if(e.haveInsurance&&"无"!==e.haveInsurance&&"0"!==e.haveInsurance&&r.push("五险一金"),e.accommodation&&"无"!==e.accommodation&&"0"!==e.accommodation&&r.push("住宿"),e.catering&&"无"!==e.catering&&"0"!==e.catering&&r.push("餐饮"),e.moreWelfares&&Array.isArray(e.moreWelfares))for(const n of e.moreWelfares){const e=n.content,t=["保险","年假","补贴","福利","股票","学历提升"];for(const n of t)if(e.includes(n)&&!r.some(e=>e.includes(n))){const t=e.match(new RegExp(`\\d*[天个月年]*${n}[^,。]*`));r.push(t?t[0]:n)}}if(e.memo){const n=["年假","补贴","商保","股票","学历提升"];for(const t of n)e.memo.includes(t)&&!r.some(e=>e.includes(t))&&r.push(t)}return 0===r.length&&r.push("按国家规定"),{items:r,promotion:e.promotionWelfare||void 0}}export function generateRequirements(e){const r=[],n=e.basicPersonalRequirements,t=e.certificate;if(null!=n?.minAge||null!=n?.maxAge){const e=n?.minAge??"不限",t=n?.maxAge??"不限";r.push(`年龄${e}-${t}岁`)}if(n?.genderRequirement&&"0"!==n.genderRequirement){if(!/男性.*女性|女性.*男性|不限/.test(n.genderRequirement)){const e={"男性":"限男性","女性":"限女性"};r.push(e[n.genderRequirement]??`性别要求:${n.genderRequirement}`)}}if(t?.education&&"不限"!==t.education){const e={"本科":"本科及以上","专科":"专科及以上","高中":"高中及以上","初中":"初中及以上"};r.push(e[t.education]??`学历${t.education}`)}if(t?.healthCertificate){const e={"食品健康证":"需食品健康证","零售健康证":"需零售健康证"};r.push(e[t.healthCertificate]??"需健康证")}return 0===r.length?a(e.jobName):r}function a(e){const r=["工作认真负责","团队合作精神"];return e.includes("服务员")?[...r,"有服务行业经验优先","沟通能力强"]:e.includes("经理")?[...r,"有管理经验","责任心强"]:[...r,"有相关工作经验者优先"]}function o(e){const r=e.basicPersonalRequirements,n=e.certificate;if(r||n)return{minAge:r?.minAge??null,maxAge:r?.maxAge??null,genderRequirement:r?.genderRequirement??null,education:n?.education??null,healthCertificate:n?.healthCertificate??null}}function s(e){const r=3===e;return{punctualityRequired:r,lateToleranceMinutes:r?5:15,attendanceTracking:r?"strict":"flexible",makeupShiftsAllowed:!r}}function m(e,r){const n=[];let t=[];r.combinedArrangementTimes?.length?t=f(r.combinedArrangementTimes):r.fixedArrangementTimes?.length&&(t=f(r.fixedArrangementTimes.map(e=>({...e,weekdays:[]}))));for(const r of t)n.push({slot:r,maxCapacity:e.requirementNum,currentBooked:e.signUpNum||0,isAvailable:(e.signUpNum||0)<e.requirementNum,priority:e.requirementNum>3?"high":"medium"});return n}function l(e,r){const n=2===e.cooperationMode;return{canSwapShifts:3===r.arrangementType||n,advanceNoticeHours:r.maxWorkTakingTime/60,partTimeAllowed:n,weekendRequired:u(r),holidayRequired:!1}}function u(e){return!!e.combinedArrangementTimes&&e.combinedArrangementTimes.some(e=>e.weekdays.includes(0)||e.weekdays.includes(6))}function c(e){const r=e.perDayMinWorkHours??8;let n=null;if(null!=e.perWeekWorkDays&&(n=e.perWeekWorkDays),null===n&&e.customWorkTimes?.length){const r=e.customWorkTimes.map(e=>e.minWorkDays).filter(e=>null!=e);r.length>0&&(n=Math.min(...r))}return null===n&&null!=e.perWeekNeedWorkDays&&(n=e.perWeekNeedWorkDays),null===n&&(n=5),r*n}function d(e){return 7*(e.perDayMinWorkHours??8)}function y(e){let r=[];if(e.combinedArrangementTimes?.length){const n=new Set;for(const r of e.combinedArrangementTimes)for(const e of r.weekdays)null!=e&&Number.isFinite(e)&&n.add(e);r=Array.from(n).sort()}else if(e.customWorkTimes?.length){const n=new Set;for(const r of e.customWorkTimes)for(const e of r.weekdays)null!=e&&Number.isFinite(e)&&n.add(e);r=Array.from(n).sort()}let n=null;if(null!=e.perWeekWorkDays&&(n=e.perWeekWorkDays),null===n&&e.customWorkTimes?.length){const r=e.customWorkTimes.map(e=>e.minWorkDays).filter(e=>null!=e);r.length>0&&(n=Math.min(...r))}return null===n&&null!=e.perWeekNeedWorkDays&&(n=e.perWeekNeedWorkDays),null===n&&(n=5),{minimumDays:n,requiredDays:k(r),description:e.workTimeRemark||""}}export function parseTimeStringToSeconds(e){if("number"==typeof e)return e;if("string"!=typeof e||!e)return 0;const r=e.match(/^(\d{1,2}):(\d{2})$/);return r?3600*Number(r[1])+60*Number(r[2]):Number(e)||0}function f(e){return e.map(e=>{const r=Math.floor(e.startTime/3600),n=Math.floor(e.startTime%3600/60),t=Math.floor(e.endTime/3600),i=Math.floor(e.endTime%3600/60);return`${r.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}~${t.toString().padStart(2,"0")}:${i.toString().padStart(2,"0")}`})}function p(e,r){if(r)return r;return e.split("-")[1]||"未知区域"}function g(e){const r=e.match(/(.+?)(附近|周边|旁边|店)/);return r?.[1]??e}function h(e){const r=e.split("-");return r[r.length-2]||"服务员"}function k(e){return e.filter(e=>Number.isFinite(e)).map(e=>0===e?7:e)}
@@ -70,4 +70,3 @@ export declare const generateReply: import("@roll-agent/sdk").ToolDefinition<{
70
70
  detailLevel: "minimal" | "focused";
71
71
  } | undefined;
72
72
  }>;
73
- //# sourceMappingURL=generate-reply.d.ts.map