@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.
- package/dist/ai/model-registry.d.ts +0 -1
- package/dist/ai/model-registry.js +1 -205
- package/dist/ai/structured-output.d.ts +0 -1
- package/dist/ai/structured-output.js +1 -78
- package/dist/errors/app-error.d.ts +0 -1
- package/dist/errors/app-error.js +1 -95
- package/dist/errors/error-codes.d.ts +0 -1
- package/dist/errors/error-codes.js +1 -115
- package/dist/errors/error-factory.d.ts +0 -1
- package/dist/errors/error-factory.js +1 -86
- package/dist/errors/error-utils.d.ts +0 -1
- package/dist/errors/error-utils.js +1 -188
- package/dist/errors/index.d.ts +0 -1
- package/dist/errors/index.js +1 -5
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1 -12
- package/dist/log-control.d.ts +0 -1
- package/dist/log-control.js +1 -15
- package/dist/pipeline/age-eligibility.d.ts +0 -1
- package/dist/pipeline/age-eligibility.js +1 -176
- package/dist/pipeline/candidate-context.d.ts +0 -1
- package/dist/pipeline/candidate-context.js +1 -31
- package/dist/pipeline/candidate-utils.d.ts +0 -1
- package/dist/pipeline/candidate-utils.js +1 -33
- package/dist/pipeline/classification.d.ts +0 -1
- package/dist/pipeline/classification.js +1 -206
- package/dist/pipeline/context-builder.d.ts +0 -1
- package/dist/pipeline/context-builder.js +1 -404
- package/dist/pipeline/pipeline-progress.d.ts +0 -1
- package/dist/pipeline/pipeline-progress.js +1 -33
- package/dist/pipeline/reply-gate.d.ts +0 -1
- package/dist/pipeline/reply-gate.js +1 -139
- package/dist/pipeline/smart-reply.d.ts +0 -1
- package/dist/pipeline/smart-reply.js +1 -418
- package/dist/pipeline.d.ts +0 -1
- package/dist/pipeline.js +1 -12
- package/dist/services/brand-alias.d.ts +0 -1
- package/dist/services/brand-alias.js +1 -184
- package/dist/services/brand-config-selectors.d.ts +0 -1
- package/dist/services/brand-config-selectors.js +1 -30
- package/dist/services/config-loader.d.ts +0 -1
- package/dist/services/config-loader.js +1 -45
- package/dist/services/duliday-api.d.ts +0 -1
- package/dist/services/duliday-api.js +1 -160
- package/dist/services/duliday-mapper.d.ts +0 -1
- package/dist/services/duliday-mapper.js +1 -536
- package/dist/tools/generate-reply.d.ts +0 -1
- package/dist/tools/generate-reply.js +1 -132
- package/dist/tools/sync-brand-data.d.ts +0 -1
- package/dist/tools/sync-brand-data.js +1 -114
- package/dist/types/brand-resolution.d.ts +0 -1
- package/dist/types/brand-resolution.js +1 -37
- package/dist/types/classification.d.ts +0 -1
- package/dist/types/classification.js +1 -30
- package/dist/types/config.d.ts +0 -1
- package/dist/types/config.js +1 -7
- package/dist/types/duliday-api.d.ts +0 -1
- package/dist/types/duliday-api.js +1 -235
- package/dist/types/geocoding.d.ts +0 -1
- package/dist/types/geocoding.js +1 -12
- package/dist/types/reply-policy.d.ts +0 -1
- package/dist/types/reply-policy.js +1 -332
- package/dist/types/zhipin.d.ts +0 -1
- package/dist/types/zhipin.js +1 -123
- package/package.json +3 -3
- package/dist/ai/model-registry.d.ts.map +0 -1
- package/dist/ai/model-registry.js.map +0 -1
- package/dist/ai/structured-output.d.ts.map +0 -1
- package/dist/ai/structured-output.js.map +0 -1
- package/dist/errors/app-error.d.ts.map +0 -1
- package/dist/errors/app-error.js.map +0 -1
- package/dist/errors/error-codes.d.ts.map +0 -1
- package/dist/errors/error-codes.js.map +0 -1
- package/dist/errors/error-factory.d.ts.map +0 -1
- package/dist/errors/error-factory.js.map +0 -1
- package/dist/errors/error-utils.d.ts.map +0 -1
- package/dist/errors/error-utils.js.map +0 -1
- package/dist/errors/index.d.ts.map +0 -1
- package/dist/errors/index.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/log-control.d.ts.map +0 -1
- package/dist/log-control.js.map +0 -1
- package/dist/pipeline/age-eligibility.d.ts.map +0 -1
- package/dist/pipeline/age-eligibility.js.map +0 -1
- package/dist/pipeline/candidate-context.d.ts.map +0 -1
- package/dist/pipeline/candidate-context.js.map +0 -1
- package/dist/pipeline/candidate-utils.d.ts.map +0 -1
- package/dist/pipeline/candidate-utils.js.map +0 -1
- package/dist/pipeline/classification.d.ts.map +0 -1
- package/dist/pipeline/classification.js.map +0 -1
- package/dist/pipeline/context-builder.d.ts.map +0 -1
- package/dist/pipeline/context-builder.js.map +0 -1
- package/dist/pipeline/pipeline-progress.d.ts.map +0 -1
- package/dist/pipeline/pipeline-progress.js.map +0 -1
- package/dist/pipeline/reply-gate.d.ts.map +0 -1
- package/dist/pipeline/reply-gate.js.map +0 -1
- package/dist/pipeline/smart-reply.d.ts.map +0 -1
- package/dist/pipeline/smart-reply.js.map +0 -1
- package/dist/pipeline.d.ts.map +0 -1
- package/dist/pipeline.js.map +0 -1
- package/dist/services/brand-alias.d.ts.map +0 -1
- package/dist/services/brand-alias.js.map +0 -1
- package/dist/services/brand-config-selectors.d.ts.map +0 -1
- package/dist/services/brand-config-selectors.js.map +0 -1
- package/dist/services/config-loader.d.ts.map +0 -1
- package/dist/services/config-loader.js.map +0 -1
- package/dist/services/duliday-api.d.ts.map +0 -1
- package/dist/services/duliday-api.js.map +0 -1
- package/dist/services/duliday-mapper.d.ts.map +0 -1
- package/dist/services/duliday-mapper.js.map +0 -1
- package/dist/tools/generate-reply.d.ts.map +0 -1
- package/dist/tools/generate-reply.js.map +0 -1
- package/dist/tools/sync-brand-data.d.ts.map +0 -1
- package/dist/tools/sync-brand-data.js.map +0 -1
- package/dist/types/brand-resolution.d.ts.map +0 -1
- package/dist/types/brand-resolution.js.map +0 -1
- package/dist/types/classification.d.ts.map +0 -1
- package/dist/types/classification.js.map +0 -1
- package/dist/types/config.d.ts.map +0 -1
- package/dist/types/config.js.map +0 -1
- package/dist/types/duliday-api.d.ts.map +0 -1
- package/dist/types/duliday-api.js.map +0 -1
- package/dist/types/geocoding.d.ts.map +0 -1
- package/dist/types/geocoding.js.map +0 -1
- package/dist/types/reply-policy.d.ts.map +0 -1
- package/dist/types/reply-policy.js.map +0 -1
- package/dist/types/zhipin.d.ts.map +0 -1
- 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)}
|