diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 1a374c0..942e2a4 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -10,7 +10,17 @@ "Bash(mkdir:*)", "Bash(findstr:*)", "Bash(cat:*)", - "Bash(npm run restart:*)" + "Bash(npm run restart:*)", + "Bash(del scheduledJobs.js)", + "Bash(ls:*)", + "Bash(wc:*)", + "Bash(for:*)", + "Bash(done)", + "Bash(npm start)", + "Bash(timeout 10 npm start)", + "Bash(timeout 15 npm start)", + "Bash(del apiservicesconfigaiConfig.js)", + "Bash(grep:*)" ], "deny": [], "ask": [] diff --git a/.gitignore b/.gitignore index 0ee545c..86f6c71 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ node_modules.* dist.zip dist/ admin/node_modules/ -app/ \ No newline at end of file +app/* +app/* \ No newline at end of file diff --git a/_doc/搜索列表和投递功能开发规划.md b/_doc/搜索列表和投递功能开发规划.md index 32a286d..f59c7bc 100644 --- a/_doc/搜索列表和投递功能开发规划.md +++ b/_doc/搜索列表和投递功能开发规划.md @@ -18,6 +18,75 @@ - 投递状态跟踪 - 投递记录管理 +## 📊 Boss直聘响应数据结构 + +### 响应格式示例 + +Boss直聘搜索职位列表的响应数据结构如下: + +```json +{ + "code": 0, + "message": "Success", + "zpData": { + "resCount": 450, // 搜索结果总数 + "hasMore": true, // 是否还有更多 + "totalCount": 300, // 总职位数 + "jobList": [ // 职位列表 + { + "encryptJobId": "5ae70dfe114c23ab0nR-2ti-FFpU", // 职位ID(投递必需) + "encryptBossId": "b55854108ac215180XZ62N-_FlNT", // Boss ID(投递必需) + "securityId": "HP23zbQfaslvy-c1...", // 安全ID(投递必需) + "jobName": "全栈软件工程师", // 职位名称 + "salaryDesc": "25-50K·19薪", // 薪资描述(需解析) + "jobExperience": "在校/应届", // 工作经验(需解析) + "jobDegree": "学历不限", // 学历要求 + "city": 101020100, // 城市代码 + "cityName": "上海", // 城市名称 + "areaDistrict": "长宁区", // 区域 + "businessDistrict": "新华路", // 商圈 + "gps": { // 位置信息(优先使用) + "longitude": 121.41902537687392, + "latitude": 31.210308153576566 + }, + "encryptBrandId": "d283b66de3cefd891H1529q5Flc~", // 公司ID + "brandName": "上海大裂谷智能科技", // 公司名称 + "brandScaleName": "100-499人", // 公司规模 + "brandIndustry": "人工智能", // 公司行业 + "brandStageName": "天使轮", // 融资阶段 + "bossName": "杨明雨", // Boss姓名 + "bossTitle": "HR", // Boss职位 + "bossOnline": true, // Boss是否在线 + "jobLabels": ["在校/应届", "学历不限"], // 职位标签 + "skills": [], // 技能要求 + "welfareList": ["带薪年假", "五险一金"], // 福利列表 + "proxyJob": 0, // 是否外包(0否1是) + "industry": 100028 // 行业代码 + } + ] + } +} +``` + +### 关键字段说明 + +1. **投递必需字段**: + - `encryptJobId`: 职位ID,投递时必须 + - `encryptBossId`: Boss ID,投递时必须 + - `securityId`: 安全ID,投递时必须(每次搜索可能不同) + +2. **位置信息**: + - `gps.longitude` 和 `gps.latitude`: 直接使用,无需调用位置服务API + - 如果没有gps字段,再使用 `cityName + areaDistrict + businessDistrict + brandName` 调用位置服务 + +3. **薪资解析**: + - `salaryDesc` 格式多样:`"25-50K·19薪"`、`"20-30K"`、`"面议"` 等 + - 需要解析出 `salaryMin` 和 `salaryMax`(单位:元) + +4. **工作年限解析**: + - `jobExperience` 可能为:`"在校/应届"`、`"3-5年"`、`"1-3年"` 等 + - 需要解析出 `experienceMin` 和 `experienceMax` + ## 📊 功能架构 ``` @@ -244,13 +313,81 @@ async createDeliverTask(params) { **任务内容**: 1. 完善字段映射(从Boss直聘响应数据提取更多字段) -2. 优化位置解析(减少API调用,添加缓存) -3. 添加职位状态管理 -4. 添加职位匹配度字段 +2. 优化位置解析(优先使用响应中的gps字段,减少API调用) +3. 解析薪资范围(从salaryDesc提取min/max) +4. 解析工作年限(从jobExperience提取min/max) +5. 添加职位状态管理 +6. 添加职位匹配度字段 + +**Boss直聘响应数据字段映射表**: + +| 响应字段 | 数据库字段 | 说明 | 示例值 | +|---------|-----------|------|--------| +| `encryptJobId` | `jobId` | 职位ID(加密) | "5ae70dfe114c23ab0nR-2ti-FFpU" | +| `jobName` | `jobTitle` | 职位名称 | "全栈软件工程师" | +| `encryptBrandId` | `companyId` | 公司ID(加密) | "d283b66de3cefd891H1529q5Flc~" | +| `brandName` | `companyName` | 公司名称 | "上海大裂谷智能科技" | +| `brandScaleName` | `companySize` | 公司规模 | "100-499人" | +| `brandIndustry` | `companyIndustry` | 公司行业 | "人工智能" | +| `brandStageName` | `brandStage` | 融资阶段 | "天使轮" | +| `salaryDesc` | `salary` | 薪资描述 | "25-50K·19薪" | +| `salaryDesc` | `salaryMin`, `salaryMax` | 薪资范围(需解析) | 25000, 50000 | +| `jobExperience` | `experience` | 工作经验 | "在校/应届" | +| `jobExperience` | `experienceMin`, `experienceMax` | 工作年限范围(需解析) | - | +| `jobDegree` | `education` | 学历要求 | "学历不限" | +| `jobDegree` | `educationLevel` | 学历等级(需映射) | - | +| `city` | `city` | 城市代码 | 101020100 | +| `cityName` | `cityName` | 城市名称 | "上海" | +| `areaDistrict` | `areaDistrict` | 区域 | "长宁区" | +| `businessDistrict` | `businessDistrict` | 商圈 | "新华路" | +| `gps.longitude` | `longitude` | 经度(优先使用) | 121.41902537687392 | +| `gps.latitude` | `latitude` | 纬度(优先使用) | 31.210308153576566 | +| `encryptBossId` | `encryptBossId` | Boss ID(投递需要) | "b55854108ac215180XZ62N-_FlNT" | +| `securityId` | `securityId` | 安全ID(投递需要) | "HP23zbQfaslvy-c1..." | +| `bossName` | `bossName` | Boss姓名 | "杨明雨" | +| `bossTitle` | `bossTitle` | Boss职位 | "HR" | +| `bossOnline` | `bossOnline` | Boss是否在线 | true | +| `jobLabels` | `jobLabels` | 职位标签(JSON) | ["在校/应届", "学历不限"] | +| `skills` | `skills` | 技能要求(JSON) | ["Java", "MySQL"] | +| `welfareList` | `welfareList` | 福利列表(JSON) | ["带薪年假", "五险一金"] | +| `proxyJob` | `isOutsourcing` | 是否外包 | 0/1 | +| `industry` | `industry` | 行业代码 | 100028 | + +**关键优化点**: + +1. **位置信息**: 优先使用响应中的 `gps.longitude` 和 `gps.latitude`,避免调用位置服务API + - 如果 `gps` 字段存在,直接使用 + - 如果不存在,再使用 `cityName + areaDistrict + businessDistrict + brandName` 调用位置服务 + +2. **薪资解析**: 从 `salaryDesc` 解析薪资范围 + - 格式示例:`"25-50K·19薪"` → min: 25000, max: 50000 + - 格式示例:`"20-30K"` → min: 20000, max: 30000 + - 格式示例:`"面议"` → min: 0, max: 0 + - 格式示例:`"15K以上"` → min: 15000, max: 999999 + - 需要处理:K(千)、W(万)、薪(年终奖倍数) + +3. **工作年限解析**: 从 `jobExperience` 解析年限范围 + - `"在校/应届"` → min: 0, max: 0 + - `"1-3年"` → min: 1, max: 3 + - `"3-5年"` → min: 3, max: 5 + - `"5-10年"` → min: 5, max: 10 + - `"10年以上"` → min: 10, max: 99 + +4. **学历映射**: 将学历描述映射为等级 + - `"学历不限"` → `"unlimited"` + - `"高中"` → `"high_school"` + - `"大专"` → `"college"` + - `"本科"` → `"bachelor"` + - `"硕士"` → `"master"` + - `"博士"` → `"doctor"` + +5. **投递必需字段**: 确保保存 `encryptJobId`、`encryptBossId` 和 `securityId` + - 这些字段在投递时必须使用 + - `securityId` 每次搜索可能不同,需要实时保存 **代码位置**: 第215-308行 -**预计工作量**: 3小时 +**预计工作量**: 4小时(增加字段解析逻辑) --- @@ -291,48 +428,67 @@ async createDeliverTask(params) { --- -### 任务5: 创建搜索任务接口 +### 任务5: 创建搜索任务接口(支持可选投递) **文件**: `api/services/pla_account_service.js` **新增方法**: `createSearchJobListTask()` +**方法签名**: +```javascript +/** + * 创建搜索职位列表任务(支持可选投递) + * @param {Object} params - 任务参数 + * @param {number} params.id - 账号ID + * @param {string} params.keyword - 搜索关键词 + * @param {Object} params.searchParams - 搜索条件(城市、薪资、经验、学历等) + * @param {number} params.pageCount - 获取页数 + * @param {boolean} params.autoDeliver - 是否自动投递(默认false) + * @param {Object} params.filterRules - 过滤规则(autoDeliver=true时使用) + * @param {number} params.maxCount - 最大投递数量(autoDeliver=true时使用) + * @returns {Promise} 任务创建结果 { taskId, message, jobCount, deliveredCount } + */ +async createSearchJobListTask(params) { + // 1. 验证账号和授权 + // 2. 创建任务记录 (taskType: 'search_jobs' 或 'auto_deliver') + // 3. 生成搜索指令 + // 4. 执行搜索指令 + // 5. 等待搜索完成(职位会自动保存到数据库) + // 6. 如果 autoDeliver=true: + // - 从数据库获取刚搜索到的职位列表 + // - 根据简历信息和过滤规则匹配职位 + // - 生成投递指令序列 + // - 执行投递指令(带间隔控制) + // - 保存投递记录 + // - 更新职位状态 + // 7. 返回任务信息 +} +``` + **任务内容**: 1. 验证账号和授权 -2. 创建任务记录 -3. 生成搜索指令 -4. 执行指令 -5. 返回任务信息 +2. 创建任务记录(根据autoDeliver参数设置taskType: 'search_jobs' 或 'auto_deliver') +3. 生成搜索指令(command_type: 'get_job_list') +4. 执行搜索指令(通过MQTT发送到设备) +5. 等待搜索完成(职位会自动保存到数据库) +6. 如果 `autoDeliver=true`,继续执行投递流程: + - 从数据库获取刚搜索到的职位列表(applyStatus = 'pending') + - 根据简历信息和过滤规则匹配职位(距离、薪资、工作年限、学历等) + - 为每个匹配的职位生成投递指令(command_type: 'apply_job') + - 批量执行投递指令(带间隔控制,避免频繁投递) + - 保存投递记录 (apply_records) + - 更新职位状态 (job_postings.applyStatus = 'applied') +7. 返回任务信息(包含搜索到的职位数量和投递数量) **代码位置**: 在 `runCommand()` 方法后添加 -**预计工作量**: 3小时 +**预计工作量**: 5小时(增加投递逻辑) --- -### 任务6: 创建投递任务接口 - -**文件**: `api/services/pla_account_service.js` - -**新增方法**: `createDeliverTask()` - -**任务内容**: -1. 验证账号和授权 -2. 创建任务记录 -3. 生成搜索指令(获取职位列表) -4. 等待搜索完成 -5. 获取匹配的职位 -6. 生成投递指令序列 -7. 执行投递指令 -8. 返回任务信息 - -**代码位置**: 在 `createSearchJobListTask()` 方法后添加 - -**预计工作量**: 4小时 - --- -### 任务7: 完善指令类型映射 +### 任务6: 完善指令类型映射 **文件**: `api/middleware/schedule/command.js` @@ -349,7 +505,7 @@ async createDeliverTask(params) { --- -### 任务8: 添加搜索条件配置管理 +### 任务7: 添加搜索条件配置管理 **文件**: `api/model/pla_account.js` @@ -376,16 +532,18 @@ async createDeliverTask(params) { ## 🔄 工作流程 -### 搜索职位列表流程 +### 搜索职位列表流程(支持可选投递) ``` 1. 用户/系统调用 createSearchJobListTask() + - 参数: { id, keyword, searchParams, pageCount, autoDeliver: true/false, filterRules, maxCount } ↓ 2. 创建任务记录 (task_status) + - taskType: 'search_jobs' 或 'auto_deliver'(根据autoDeliver参数) ↓ 3. 生成搜索指令 (task_commands) - command_type: 'get_job_list' - - command_params: { keyword, city, salary, ... } + - command_params: { keyword, city, salary, experience, education, ... } ↓ 4. 执行指令 (通过MQTT发送到设备) ↓ @@ -393,62 +551,79 @@ async createDeliverTask(params) { ↓ 6. 保存职位到数据库 (job_postings) - 去重处理 - - 位置解析 + - 位置解析(优先使用gps字段) - 字段映射 + - 状态: applyStatus = 'pending'(待投递) ↓ -7. 更新指令状态为完成 +7. 更新搜索指令状态为完成 ↓ -8. 更新任务状态为完成 +8. 如果 autoDeliver=true,继续执行投递流程: + ↓ + 8.1 从数据库获取刚搜索到的职位列表 + - 筛选条件: applyStatus = 'pending', sn_code = 账号SN码 + ↓ + 8.2 根据简历信息和过滤规则匹配职位 + - 距离匹配(基于经纬度) + - 薪资匹配(解析salaryDesc) + - 工作年限匹配(解析jobExperience) + - 学历匹配(解析jobDegree) + - 权重评分 + ↓ + 8.3 为每个匹配的职位生成投递指令 + - command_type: 'apply_job' + - command_params: { + jobId: job.encryptJobId, // 职位ID(必需) + encryptBossId: job.encryptBossId, // Boss ID(必需) + securityId: job.securityId, // 安全ID(必需,从最新搜索结果获取) + brandName: job.brandName, // 公司名称(可选) + jobTitle: job.jobName // 职位名称(可选) + } + ↓ + 8.4 批量执行投递指令(带间隔控制,避免频繁投递) + ↓ + 8.5 保存投递记录 (apply_records) + ↓ + 8.6 更新职位状态 (job_postings.applyStatus = 'applied') + ↓ +9. 更新任务状态为完成 + ↓ +10. 返回任务信息(包含搜索到的职位数量和投递数量) ``` -### 投递职位流程 - -``` -1. 用户/系统调用 createDeliverTask() - ↓ -2. 创建任务记录 (task_status) - ↓ -3. 生成搜索指令 (获取职位列表) - - command_type: 'get_job_list' - ↓ -4. 执行搜索指令 - ↓ -5. 获取职位列表并保存到数据库 - ↓ -6. 根据简历信息和过滤规则匹配职位 - - 距离匹配 - - 薪资匹配 - - 工作年限匹配 - - 学历匹配 - - 权重评分 - ↓ -7. 为每个匹配的职位生成投递指令 - - command_type: 'apply_job' - - command_params: { jobId, encryptBossId, ... } - ↓ -8. 批量执行投递指令(带间隔控制) - ↓ -9. 保存投递记录 (apply_records) - ↓ -10. 更新职位状态 (job_postings.applyStatus) - ↓ -11. 更新任务状态为完成 -``` +**说明**: +- 此接口支持两种模式: + - `autoDeliver=false`: 仅搜索,不投递。职位保存到数据库,状态为'pending' + - `autoDeliver=true`: 搜索完成后立即投递匹配的职位 +- **重要**: 投递必须在搜索完成后立即执行,因为 `securityId` 等字段可能有时效性,前端页面变化后这些字段可能失效 +- 不支持从已保存的职位中选择投递,因为职位信息可能已过期 ## 📊 数据库字段说明 ### job_postings 表需要完善的字段 -| 字段名 | 类型 | 说明 | 状态 | -|--------|------|------|------| -| `city` | VARCHAR | 城市代码 | 待添加 | -| `cityName` | VARCHAR | 城市名称 | 待添加 | -| `salaryMin` | INT | 最低薪资(元) | 待添加 | -| `salaryMax` | INT | 最高薪资(元) | 待添加 | -| `experienceMin` | INT | 最低工作年限 | 待添加 | -| `experienceMax` | INT | 最高工作年限 | 待添加 | -| `educationLevel` | VARCHAR | 学历等级 | 待添加 | -| `matchScore` | DECIMAL | 匹配度评分 | 待添加 | +| 字段名 | 类型 | 说明 | 状态 | 数据来源 | +|--------|------|------|------|----------| +| `city` | VARCHAR | 城市代码 | 待添加 | `job.city` | +| `cityName` | VARCHAR | 城市名称 | 待添加 | `job.cityName` | +| `areaDistrict` | VARCHAR | 区域 | 待添加 | `job.areaDistrict` | +| `businessDistrict` | VARCHAR | 商圈 | 待添加 | `job.businessDistrict` | +| `salaryMin` | INT | 最低薪资(元) | 待添加 | 从 `salaryDesc` 解析 | +| `salaryMax` | INT | 最高薪资(元) | 待添加 | 从 `salaryDesc` 解析 | +| `experienceMin` | INT | 最低工作年限 | 待添加 | 从 `jobExperience` 解析 | +| `experienceMax` | INT | 最高工作年限 | 待添加 | 从 `jobExperience` 解析 | +| `educationLevel` | VARCHAR | 学历等级 | 待添加 | 从 `jobDegree` 映射 | +| `matchScore` | DECIMAL | 匹配度评分 | 待添加 | 计算得出 | +| `encryptBossId` | VARCHAR | Boss ID | 已有 | `job.encryptBossId` | +| `securityId` | VARCHAR | 安全ID | 待添加 | `job.securityId`(投递必需) | +| `bossName` | VARCHAR | Boss姓名 | 待添加 | `job.bossName` | +| `bossTitle` | VARCHAR | Boss职位 | 待添加 | `job.bossTitle` | +| `bossOnline` | TINYINT | Boss是否在线 | 待添加 | `job.bossOnline` | +| `brandStage` | VARCHAR | 融资阶段 | 待添加 | `job.brandStageName` | +| `jobLabels` | JSON | 职位标签 | 待添加 | `job.jobLabels` | +| `skills` | JSON | 技能要求 | 待添加 | `job.skills` | +| `welfareList` | JSON | 福利列表 | 待添加 | `job.welfareList` | +| `isOutsourcing` | TINYINT | 是否外包 | 待添加 | `job.proxyJob` | +| `industry` | INT | 行业代码 | 待添加 | `job.industry` | ### pla_account 表需要添加的字段 @@ -483,15 +658,14 @@ async createDeliverTask(params) { | 任务 | 预计时间 | 优先级 | |------|----------|--------| | 任务1: 完善搜索参数支持 | 2小时 | 高 | -| 任务2: 优化职位数据保存 | 3小时 | 高 | +| 任务2: 优化职位数据保存 | 4小时 | 高 | | 任务3: 完善自动投递任务搜索条件 | 2小时 | 高 | | 任务4: 优化职位匹配算法 | 4小时 | 高 | -| 任务5: 创建搜索任务接口 | 3小时 | 中 | -| 任务6: 创建投递任务接口 | 4小时 | 中 | -| 任务7: 完善指令类型映射 | 1小时 | 中 | -| 任务8: 添加搜索条件配置管理 | 1小时 | 低 | +| 任务5: 创建搜索任务接口(支持可选投递) | 5小时 | 高 | +| 任务6: 完善指令类型映射 | 1小时 | 中 | +| 任务7: 添加搜索条件配置管理 | 1小时 | 低 | -**总计**: 约20小时 +**总计**: 约19小时 ## 🚀 开发优先级 @@ -500,14 +674,70 @@ async createDeliverTask(params) { 2. 任务2: 优化职位数据保存 3. 任务3: 完善自动投递任务搜索条件 4. 任务4: 优化职位匹配算法 +5. 任务5: 创建搜索任务接口(支持可选投递) ### 第二阶段(接口完善) -5. 任务5: 创建搜索任务接口 -6. 任务6: 创建投递任务接口 -7. 任务7: 完善指令类型映射 +6. 任务6: 完善指令类型映射 ### 第三阶段(配置管理) -8. 任务8: 添加搜索条件配置管理 +7. 任务7: 添加搜索条件配置管理 + +## 💡 使用场景说明 + +### 场景1: 仅搜索职位列表 +```javascript +// 只搜索职位,不投递 +const result = await plaAccountService.createSearchJobListTask({ + id: accountId, + keyword: '全栈工程师', + searchParams: { + city: '101020100', + cityName: '上海', + salary: '20-30K', + experience: '3-5年', + education: '本科' + }, + pageCount: 3, + autoDeliver: false // 不自动投递 +}); + +// 返回: { taskId: 123, message: '搜索任务已创建', jobCount: 45 } +// 职位会自动保存到数据库,状态为 'pending'(待投递) +``` + +### 场景2: 搜索并自动投递(推荐) +```javascript +// 搜索职位并自动投递匹配的职位 +const result = await plaAccountService.createSearchJobListTask({ + id: accountId, + keyword: '全栈工程师', + searchParams: { + city: '101020100', + cityName: '上海', + salary: '20-30K', + experience: '3-5年', + education: '本科' + }, + pageCount: 3, + autoDeliver: true, // 自动投递 + filterRules: { + minSalary: 20000, + maxSalary: 30000, + keywords: ['Vue', 'React'], + excludeKeywords: ['外包', '外派'] + }, + maxCount: 10 // 最多投递10个职位 +}); + +// 返回: { taskId: 123, message: '搜索并投递任务已创建', jobCount: 45, deliveredCount: 8 } +``` + +**重要说明**: +- **投递必须在搜索完成后立即执行**,因为 `securityId` 等字段可能有时效性 +- 前端页面变化后,已保存的职位信息中的 `securityId` 可能失效,无法用于投递 +- 因此不支持从已保存的职位中选择投递,必须在搜索后立即投递 +- 如果只需要搜索不投递,设置 `autoDeliver: false` +- 如果需要搜索并投递,设置 `autoDeliver: true`,系统会根据匹配规则自动投递 ## 📌 注意事项 @@ -517,6 +747,11 @@ async createDeliverTask(params) { 4. **性能优化**: 批量操作需要考虑性能,避免阻塞 5. **MQTT通信**: 确保指令参数格式正确,与客户端协议一致 6. **数据库事务**: 批量操作需要使用事务保证数据一致性 +7. **投递时机**: 投递必须在搜索完成后立即执行,因为 `securityId` 等字段可能有时效性,前端页面变化后这些字段可能失效 +8. **职位状态验证**: 投递前必须验证职位状态(applyStatus = 'pending'),避免重复投递 +9. **投递必需字段**: 投递时需要 `encryptJobId`、`encryptBossId` 和 `securityId`,这些字段必须从最新搜索结果中获取 +10. **位置信息**: 优先使用响应中的 `gps` 字段,避免不必要的API调用 +11. **接口设计**: 搜索和投递在同一接口中完成,不支持单独的投递接口,因为已保存的职位信息可能已过期 ## 🔗 相关文件 diff --git a/_script/sync_all_models.js b/_script/sync_all_models.js index 0c4adfd..0596a87 100644 --- a/_script/sync_all_models.js +++ b/_script/sync_all_models.js @@ -34,7 +34,6 @@ async function syncAllModels() { // 执行同步 await model.sync({ alter: true }); - console.log(`✅ ${modelName} 同步完成`); return { modelName, success: true }; } catch (error) { diff --git a/_sql/add_pla_account_auto_search_fields.sql b/_sql/add_pla_account_auto_search_fields.sql new file mode 100644 index 0000000..e02b33d --- /dev/null +++ b/_sql/add_pla_account_auto_search_fields.sql @@ -0,0 +1,66 @@ +-- 为 pla_account 表添加自动搜索相关字段 +-- 执行时间:2025-01-XX +-- 说明:添加自动搜索开关和搜索配置字段 + +-- ============================================ +-- 添加自动搜索开关字段(auto_search) +-- ============================================ +ALTER TABLE `pla_account` +ADD COLUMN `auto_search` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '自动搜索开关(1=启用,0=禁用)' +AFTER `auto_deliver`; + +-- ============================================ +-- 添加自动搜索配置字段(search_config) +-- ============================================ +ALTER TABLE `pla_account` +ADD COLUMN `search_config` JSON COMMENT '自动搜索配置(JSON对象,包含:search_interval-搜索间隔分钟数, city-城市, cityName-城市名称, salary-薪资, experience-经验, education-学历)' +AFTER `auto_search`; + +-- ============================================ +-- 为已有账号设置默认配置 +-- ============================================ +-- 为所有账号设置默认的 search_config(如果为 NULL) +UPDATE `pla_account` +SET `search_config` = JSON_OBJECT( + 'search_interval', 30, + 'city', '', + 'cityName', '', + 'salary', '', + 'experience', '', + 'education', '' +) +WHERE `search_config` IS NULL; + +-- ============================================ +-- 验证字段是否添加成功 +-- ============================================ +SELECT + COLUMN_NAME AS '字段名', + COLUMN_TYPE AS '字段类型', + IS_NULLABLE AS '允许空', + COLUMN_DEFAULT AS '默认值', + COLUMN_COMMENT AS '注释' +FROM INFORMATION_SCHEMA.COLUMNS +WHERE TABLE_SCHEMA = DATABASE() +AND TABLE_NAME = 'pla_account' +AND COLUMN_NAME IN ('auto_search', 'search_config') +ORDER BY ORDINAL_POSITION; + +-- ============================================ +-- 注意事项 +-- ============================================ +-- 1. auto_search 使用 TINYINT(1) 类型,默认值为 0(关闭) +-- 2. search_config 使用 JSON 类型(MySQL 5.7+) +-- 3. 如果 MySQL 版本低于 5.7,请将 JSON 类型改为 TEXT 类型 +-- 4. 执行前建议先备份数据库 +-- 5. 如果字段已存在会报错,请先删除字段再执行: +-- ALTER TABLE `pla_account` DROP COLUMN `auto_search`; +-- ALTER TABLE `pla_account` DROP COLUMN `search_config`; +-- 6. search_config 默认值包含以下字段: +-- - search_interval: 30(搜索间隔,单位:分钟) +-- - city: ''(城市代码) +-- - cityName: ''(城市名称) +-- - salary: ''(薪资范围) +-- - experience: ''(工作经验要求) +-- - education: ''(学历要求) + diff --git a/admin/config/index.js b/admin/config/index.js index 34f2d94..0bc5e47 100644 --- a/admin/config/index.js +++ b/admin/config/index.js @@ -26,11 +26,11 @@ const baseConfig = { // 开发环境配置 const developmentConfig = { ...baseConfig, - // apiUrl: 'http://localhost:9097/admin_api/', - // uploadUrl: 'http://localhost:9097/admin_api/upload', + apiUrl: 'http://localhost:9097/admin_api/', + uploadUrl: 'http://localhost:9097/admin_api/upload', - apiUrl: 'https://work.light120.com/admin_api/', - uploadUrl: 'https://work.light120.com/admin_api/upload', + // apiUrl: 'https://work.light120.com/admin_api/', + // uploadUrl: 'https://work.light120.com/admin_api/upload', // 开发环境显示更多调试信息 debug: true } diff --git a/api/middleware/job/chatManager.js b/api/middleware/job/chatManager.js deleted file mode 100644 index af9af00..0000000 --- a/api/middleware/job/chatManager.js +++ /dev/null @@ -1,421 +0,0 @@ -// const aiService = require('./aiService'); // 二期规划:AI 服务暂时禁用 -const logs = require('../logProxy'); - -/** - * 智能聊天管理模块 - * 负责聊天内容生成、发送策略和效果监控 - */ -class ChatManager { - constructor() { - this.chatHistory = new Map(); // 聊天历史记录 - this.chatStrategies = new Map(); // 聊天策略配置 - this.effectStats = new Map(); // 聊天效果统计 - this.initDefaultStrategies(); - } - - /** - * 初始化默认聊天策略 - */ - initDefaultStrategies() { - // 初次打招呼策略 - this.chatStrategies.set('greeting', { - name: '初次打招呼', - description: '向HR发送初次打招呼消息', - template: 'greeting', - timing: 'immediate', - retryCount: 1, - retryInterval: 300000 // 5分钟 - }); - - // 面试邀约策略 - this.chatStrategies.set('interview', { - name: '面试邀约', - description: '发送面试邀约消息', - template: 'interview', - timing: 'after_greeting', - retryCount: 2, - retryInterval: 600000 // 10分钟 - }); - - // 跟进沟通策略 - this.chatStrategies.set('followup', { - name: '跟进沟通', - description: '跟进之前的沟通', - template: 'followup', - timing: 'after_interview', - retryCount: 1, - retryInterval: 86400000 // 24小时 - }); - } - - /** - * 生成聊天内容 - * @param {string} sn_code - 设备SN码 - * @param {object} jobInfo - 岗位信息 - * @param {object} resumeInfo - 简历信息 - * @param {string} chatType - 聊天类型 - * @param {object} context - 聊天上下文 - * @returns {Promise} 聊天内容 - */ - async generateChatContent(sn_code, jobInfo, resumeInfo, chatType = 'greeting', context = {}) { - console.log(`[聊天管理] 开始生成设备 ${sn_code} 的聊天内容,类型: ${chatType}`); - - // 获取聊天策略 - const strategy = this.chatStrategies.get(chatType); - if (!strategy) { - throw new Error(`未找到聊天类型 ${chatType} 的策略配置`); - } - - // 二期规划:AI 生成聊天内容暂时禁用,使用默认模板 - // const chatContent = await aiService.generateChatContent(jobInfo, resumeInfo, chatType); - // if (!chatContent.success) { - // console.error(`[聊天管理] AI生成聊天内容失败:`, chatContent.error); - // throw new Error(chatContent.error); - // } - - console.log(`[聊天管理] AI生成已禁用(二期规划),使用默认聊天模板`); - const chatContent = this.generateDefaultChatContent(jobInfo, resumeInfo, chatType); - - const result = { - sn_code: sn_code, - jobInfo: jobInfo, - chatType: chatType, - strategy: strategy, - content: chatContent.content, - context: context, - timestamp: Date.now() - }; - - // 记录聊天历史 - this.recordChatHistory(sn_code, result); - - console.log(`[聊天管理] 聊天内容生成成功:`, result); - return result; - } - - /** - * 发送聊天消息 - * @param {string} sn_code - 设备SN码 - * @param {object} mqttClient - MQTT客户端 - * @param {object} chatData - 聊天数据 - * @returns {Promise} 发送结果 - */ - async sendChatMessage(sn_code, mqttClient, chatData) { - console.log(`[聊天管理] 开始发送聊天消息到设备 ${sn_code}`); - - // 构建发送指令 - const sendData = { - platform: 'boss', - action: 'send_chat_message', - data: { - jobId: chatData.jobInfo.jobId, - companyId: chatData.jobInfo.companyId, - message: chatData.content, - chatType: chatData.chatType - } - }; - - // 发送MQTT指令 - const response = await mqttClient.publishAndWait(sn_code, sendData); - - if (!response || response.code !== 200) { - // 更新聊天状态 - this.updateChatStatus(sn_code, chatData, 'failed', response); - - console.error(`[聊天管理] 聊天消息发送失败:`, response); - throw new Error(response?.message || '聊天消息发送失败'); - } - - // 更新聊天状态 - this.updateChatStatus(sn_code, chatData, 'sent', response); - - // 记录效果统计 - this.recordChatEffect(sn_code, chatData, 'sent'); - - console.log(`[聊天管理] 聊天消息发送成功:`, response); - return response; - } - - /** - * 生成面试邀约 - * @param {string} sn_code - 设备SN码 - * @param {object} jobInfo - 岗位信息 - * @param {object} chatHistory - 聊天历史 - * @returns {Promise} 面试邀约内容 - */ - async generateInterviewInvitation(sn_code, jobInfo, chatHistory) { - console.log(`[聊天管理] 开始生成设备 ${sn_code} 的面试邀约`); - console.log(`[聊天管理] AI生成已禁用(二期规划),使用默认模板`); - - // 二期规划:AI 生成面试邀约暂时禁用,使用默认模板 - // const invitation = await aiService.generateInterviewInvitation(jobInfo, chatHistory); - // if (!invitation.success) { - // console.error(`[聊天管理] AI生成面试邀约失败:`, invitation.error); - // throw new Error(invitation.error); - // } - - const invitation = this.generateDefaultInterviewInvitation(jobInfo); - - const result = { - sn_code: sn_code, - jobInfo: jobInfo, - chatType: 'interview', - content: invitation.content, - timestamp: Date.now() - }; - - // 记录聊天历史 - this.recordChatHistory(sn_code, result); - - console.log(`[聊天管理] 面试邀约生成成功:`, result); - return result; - } - - /** - * 记录聊天历史 - * @param {string} sn_code - 设备SN码 - * @param {object} chatData - 聊天数据 - */ - recordChatHistory(sn_code, chatData) { - if (!this.chatHistory.has(sn_code)) { - this.chatHistory.set(sn_code, []); - } - - const history = this.chatHistory.get(sn_code); - history.push({ - ...chatData, - id: Date.now() + Math.random(), - status: 'generated' - }); - - // 限制历史记录数量 - if (history.length > 100) { - history.splice(0, history.length - 100); - } - } - - /** - * 更新聊天状态 - * @param {string} sn_code - 设备SN码 - * @param {object} chatData - 聊天数据 - * @param {string} status - 新状态 - * @param {object} response - 响应数据 - */ - updateChatStatus(sn_code, chatData, status, response = {}) { - if (!this.chatHistory.has(sn_code)) { - return; - } - - const history = this.chatHistory.get(sn_code); - const chatRecord = history.find(record => - record.timestamp === chatData.timestamp && - record.chatType === chatData.chatType - ); - - if (chatRecord) { - chatRecord.status = status; - chatRecord.response = response; - } - } - - /** - * 记录聊天效果 - * @param {string} sn_code - 设备SN码 - * @param {object} chatData - 聊天数据 - * @param {string} action - 动作类型 - */ - recordChatEffect(sn_code, chatData, action) { - if (!this.effectStats.has(sn_code)) { - this.effectStats.set(sn_code, { - totalSent: 0, - totalReplied: 0, - totalInterview: 0, - replyRate: 0, - interviewRate: 0, - lastUpdate: Date.now() - }); - } - - const stats = this.effectStats.get(sn_code); - - if (action === 'sent') { - stats.totalSent++; - } else if (action === 'replied') { - stats.totalReplied++; - } else if (action === 'interview') { - stats.totalInterview++; - } - - // 计算比率 - if (stats.totalSent > 0) { - stats.replyRate = (stats.totalReplied / stats.totalSent * 100).toFixed(2); - stats.interviewRate = (stats.totalInterview / stats.totalSent * 100).toFixed(2); - } - - stats.lastUpdate = Date.now(); - } - - /** - * 获取聊天历史 - * @param {string} sn_code - 设备SN码 - * @param {object} filters - 过滤条件 - * @returns {Array} 聊天历史 - */ - getChatHistory(sn_code, filters = {}) { - if (!this.chatHistory.has(sn_code)) { - return []; - } - - let history = this.chatHistory.get(sn_code); - - // 应用过滤条件 - if (filters.chatType) { - history = history.filter(record => record.chatType === filters.chatType); - } - - if (filters.status) { - history = history.filter(record => record.status === filters.status); - } - - if (filters.startTime) { - history = history.filter(record => record.timestamp >= filters.startTime); - } - - if (filters.endTime) { - history = history.filter(record => record.timestamp <= filters.endTime); - } - - // 按时间倒序排列 - return history.sort((a, b) => b.timestamp - a.timestamp); - } - - /** - * 获取聊天效果统计 - * @param {string} sn_code - 设备SN码 - * @returns {object} 效果统计 - */ - getChatEffectStats(sn_code) { - if (!this.effectStats.has(sn_code)) { - return { - totalSent: 0, - totalReplied: 0, - totalInterview: 0, - replyRate: 0, - interviewRate: 0, - lastUpdate: Date.now() - }; - } - - return this.effectStats.get(sn_code); - } - - /** - * 设置聊天策略 - * @param {string} chatType - 聊天类型 - * @param {object} strategy - 策略配置 - */ - setChatStrategy(chatType, strategy) { - this.chatStrategies.set(chatType, { - ...this.chatStrategies.get(chatType), - ...strategy - }); - - console.log(`[聊天管理] 更新聊天策略 ${chatType}:`, strategy); - } - - /** - * 清理过期数据 - */ - cleanup() { - const now = Date.now(); - const expireTime = 30 * 24 * 3600000; // 30天 - - // 清理过期的聊天历史 - for (const [sn_code, history] of this.chatHistory.entries()) { - const filteredHistory = history.filter(record => - now - record.timestamp < expireTime - ); - - if (filteredHistory.length === 0) { - this.chatHistory.delete(sn_code); - } else { - this.chatHistory.set(sn_code, filteredHistory); - } - } - - // 清理过期的效果统计 - for (const [sn_code, stats] of this.effectStats.entries()) { - if (now - stats.lastUpdate > expireTime) { - this.effectStats.delete(sn_code); - } - } - - console.log(`[聊天管理] 数据清理完成`); - } - - /** - * 生成默认聊天内容(替代 AI 生成) - * @param {object} jobInfo - 岗位信息 - * @param {object} resumeInfo - 简历信息 - * @param {string} chatType - 聊天类型 - * @returns {object} 聊天内容 - */ - generateDefaultChatContent(jobInfo, resumeInfo, chatType) { - const templates = { - greeting: '您好,我对这个岗位很感兴趣,希望能进一步了解。', - interview: '感谢您的回复,我很期待与您进一步沟通。', - followup: '您好,想了解一下这个岗位的最新进展。' - }; - - const content = templates[chatType] || templates.greeting; - - return { - success: true, - content: content, - chatType: chatType - }; - } - - /** - * 生成默认面试邀约(替代 AI 生成) - * @param {object} jobInfo - 岗位信息 - * @returns {object} 面试邀约内容 - */ - generateDefaultInterviewInvitation(jobInfo) { - return { - success: true, - content: '感谢您的邀请,我很期待与您面谈。请问方便的时间是什么时候?', - jobTitle: jobInfo.jobTitle || '该岗位', - companyName: jobInfo.companyName || '贵公司' - }; - } - - /** - * 获取聊天列表 - * @param {string} sn_code - 设备SN码 - * @param {object} mqttClient - MQTT客户端 - * @param {object} params - 参数 - * @returns {Promise} 聊天列表 - */ - async get_chat_list(sn_code, mqttClient, params = {}) { - const { platform = 'boss', pageCount = 3 } = params; - console.log(`[聊天管理] 开始获取设备 ${sn_code} 的聊天列表`); - - // 通过MQTT指令获取聊天列表 - const response = await mqttClient.publishAndWait(sn_code, { - platform, - action: "get_chat_list", - data: { pageCount } - }); - - if (!response || response.code !== 200) { - console.error(`[聊天管理] 获取聊天列表失败:`, response); - throw new Error('获取聊天列表失败'); - } - - console.log(`[聊天管理] 成功获取聊天列表`); - return response.data; - } -} - -module.exports = new ChatManager(); \ No newline at end of file diff --git a/api/middleware/job/index.js b/api/middleware/job/index.js index dbc01c0..e17c52c 100644 --- a/api/middleware/job/index.js +++ b/api/middleware/job/index.js @@ -3,10 +3,7 @@ * 聚合所有 job 相关模块的方法,提供统一的对外接口 */ -const jobManager = require('./jobManager'); -const resumeManager = require('./resumeManager'); -const chatManager = require('./chatManager'); - +const { jobManager, resumeManager, chatManager } = require('./managers'); const pack = (instance) => { const proto = Object.getPrototypeOf(instance); @@ -23,7 +20,6 @@ const pack = (instance) => { /** * 便捷方法:直接导出常用方法 - * 使用下划线命名规范 */ module.exports = { ...pack(jobManager), diff --git a/api/middleware/job/job_filter_service.md b/api/middleware/job/job_filter_service.md deleted file mode 100644 index b399783..0000000 --- a/api/middleware/job/job_filter_service.md +++ /dev/null @@ -1,651 +0,0 @@ -# 职位过滤服务文档 - -## 概述 - -`job_filter_service.js` 是一个职位文本匹配过滤服务,使用简单的文本匹配规则来过滤和分析职位信息。该服务支持从数据库动态获取职位类型的技能关键词和排除关键词,能够分析职位与简历的匹配度,并提供过滤和评分功能。 - -## 主要功能 - -1. **职位类型配置管理**:从数据库获取或使用默认配置的技能关键词和排除关键词 -2. **匹配度分析**:分析职位与简历的匹配度(技能、经验、薪资) -3. **职位过滤**:根据匹配分数、外包标识、排除关键词等条件过滤职位列表 -4. **自定义权重评分**:支持根据自定义权重配置计算职位评分(距离、薪资、工作年限、学历、技能) - -## 类结构 - -```javascript -class JobFilterService { - // 默认技能关键词 - defaultCommonSkills: Array - - // 默认排除关键词 - defaultExcludeKeywords: Array - - // 职位类型配置缓存 - jobTypeCache: Map -} -``` - -## API 文档 - -### 1. getJobTypeConfig(jobTypeId) - -根据职位类型ID获取技能关键词和排除关键词配置。 - -**参数:** -- `jobTypeId` (number, 可选): 职位类型ID - -**返回值:** -```javascript -{ - commonSkills: Array, // 技能关键词列表 - excludeKeywords: Array // 排除关键词列表 -} -``` - -**说明:** -- 如果未提供 `jobTypeId` 或配置获取失败,返回默认配置 -- 配置结果会缓存5分钟,避免频繁查询数据库 -- 从 `job_types` 表读取 `commonSkills` 和 `excludeKeywords` 字段(JSON格式) - -**使用示例:** -```javascript -const config = await jobFilterService.getJobTypeConfig(1); -console.log(config.commonSkills); // ['Vue', 'React', ...] -console.log(config.excludeKeywords); // ['外包', '外派', ...] -``` - ---- - -### 2. clearCache(jobTypeId) - -清除职位类型配置缓存。 - -**参数:** -- `jobTypeId` (number, 可选): 职位类型ID,不传则清除所有缓存 - -**使用示例:** -```javascript -// 清除特定职位类型的缓存 -jobFilterService.clearCache(1); - -// 清除所有缓存 -jobFilterService.clearCache(); -``` - ---- - -### 3. analyzeJobMatch(jobInfo, resumeInfo, jobTypeId) - -使用文本匹配分析职位与简历的匹配度。 - -**参数:** -- `jobInfo` (object, 必需): 职位信息对象 - - `jobTitle` (string): 职位名称 - - `companyName` (string): 公司名称 - - `description` (string): 职位描述 - - `skills` (string): 技能要求 - - `requirements` (string): 职位要求 - - `salary` (string): 薪资范围 - - `experience` (string): 经验要求 - - `education` (string): 学历要求 - - `longitude` (number): 经度 - - `latitude` (number): 纬度 -- `resumeInfo` (object, 可选): 简历信息对象 - - `skills` (string|Array): 技能列表 - - `skillDescription` (string): 技能描述 - - `currentPosition` (string): 当前职位 - - `expectedPosition` (string): 期望职位 - - `workYears` (number|string): 工作年限 - - `expectedSalary` (string): 期望薪资 - - `education` (string): 学历 -- `jobTypeId` (number, 可选): 职位类型ID - -**返回值:** -```javascript -{ - skillMatch: number, // 技能匹配度(0-100) - experienceMatch: number, // 经验匹配度(0-100) - salaryMatch: number, // 薪资匹配度(0-100) - isOutsourcing: boolean, // 是否为外包岗位 - overallScore: number, // 综合推荐指数(0-100) - matchReasons: Array, // 匹配原因列表 - concerns: Array, // 关注点列表 - suggestion: string, // 投递建议 - analysis: Object // 完整的分析结果(同上) -} -``` - -**评分规则:** - -1. **综合推荐指数计算**: - - 技能匹配度 × 40% + 经验匹配度 × 30% + 薪资匹配度 × 30% - -2. **技能匹配度**: - - 从职位描述中提取技能关键词 - - 计算简历中匹配的技能数量占比 - - 无简历信息时,基于职位关键词数量评分 - -3. **经验匹配度**: - - 从职位描述中提取经验要求(应届、1年、2年、3年、5年、10年) - - 根据简历工作年限与要求的匹配程度评分 - -4. **薪资匹配度**: - - 解析职位薪资范围和期望薪资 - - 期望薪资低于职位薪资时得高分,高于职位薪资时得低分 - -5. **外包检测**: - - 检测职位描述中是否包含:外包、外派、驻场、人力外包、项目外包 - -**使用示例:** -```javascript -const jobInfo = { - jobTitle: '前端开发工程师', - description: '要求3年以上Vue开发经验,熟悉React', - salary: '15-25K', - experience: '3-5年' -}; - -const resumeInfo = { - skills: 'Vue, React, JavaScript', - workYears: 4, - expectedSalary: '20K' -}; - -const result = await jobFilterService.analyzeJobMatch(jobInfo, resumeInfo, 1); -console.log(result.overallScore); // 85 -console.log(result.matchReasons); // ['技能匹配度高', '工作经验符合要求', ...] -console.log(result.suggestion); // '强烈推荐投递:匹配度很高' -``` - ---- - -### 4. filterJobs(jobs, filterRules, resumeInfo, jobTypeId) - -过滤职位列表,返回匹配的职位(带匹配分数)。 - -**参数:** -- `jobs` (Array, 必需): 职位列表(可以是 Sequelize 模型实例或普通对象) -- `filterRules` (object, 可选): 过滤规则 - - `minScore` (number, 默认60): 最低匹配分数 - - `excludeOutsourcing` (boolean, 默认true): 是否排除外包岗位 - - `excludeKeywords` (Array, 默认[]): 额外排除关键词列表 -- `resumeInfo` (object, 可选): 简历信息 -- `jobTypeId` (number, 可选): 职位类型ID - -**返回值:** -```javascript -Array<{ - ...jobData, // 原始职位数据 - matchScore: number, // 匹配分数 - matchAnalysis: Object // 完整的匹配分析结果 -}> -``` - -**过滤逻辑:** -1. 对每个职位进行匹配度分析 -2. 过滤掉匹配分数低于 `minScore` 的职位 -3. 如果 `excludeOutsourcing` 为 true,过滤掉外包岗位 -4. 过滤掉包含排除关键词的职位 -5. 按匹配分数降序排序 - -**使用示例:** -```javascript -const jobs = [ - { jobTitle: '前端开发', description: 'Vue开发...', salary: '20K' }, - { jobTitle: '后端开发', description: 'Java开发...', salary: '25K' } -]; - -const resumeInfo = { - skills: 'Vue, JavaScript', - workYears: 3 -}; - -const filterRules = { - minScore: 70, - excludeOutsourcing: true, - excludeKeywords: ['销售'] -}; - -const filteredJobs = await jobFilterService.filterJobs( - jobs, - filterRules, - resumeInfo, - 1 -); - -console.log(filteredJobs.length); // 过滤后的职位数量 -console.log(filteredJobs[0].matchScore); // 第一个职位的匹配分数 -``` - ---- - -### 5. calculateJobScoreWithWeights(jobData, resumeInfo, accountConfig, jobTypeConfig, priorityWeights) - -根据自定义权重配置计算职位评分。 - -**参数:** -- `jobData` (object, 必需): 职位数据 - - `longitude` (number): 经度 - - `latitude` (number): 纬度 - - `salary` (string): 薪资范围 - - `experience` (string): 经验要求 - - `education` (string): 学历要求 -- `resumeInfo` (object, 必需): 简历信息 - - `expectedSalary` (string): 期望薪资 - - `workYears` (string|number): 工作年限 - - `education` (string): 学历 - - `skills` (string|Array): 技能列表 -- `accountConfig` (object, 必需): 账号配置 - - `user_longitude` (number): 用户经度 - - `user_latitude` (number): 用户纬度 -- `jobTypeConfig` (object, 可选): 职位类型配置(包含 commonSkills) -- `priorityWeights` (Array, 必需): 权重配置 - ```javascript - [ - { key: 'distance', weight: 30 }, // 距离权重(0-100) - { key: 'salary', weight: 40 }, // 薪资权重 - { key: 'work_years', weight: 20 }, // 工作年限权重 - { key: 'education', weight: 10 } // 学历权重 - ] - ``` - -**返回值:** -```javascript -{ - totalScore: number, // 总分(0-100+,技能评分作为额外加分项) - scores: { - distance: number, // 距离评分 - salary: number, // 薪资评分 - work_years: number, // 工作年限评分 - education: number, // 学历评分 - skills: number // 技能评分(如果有 jobTypeConfig) - } -} -``` - -**评分规则:** - -1. **距离评分**: - - 0-5km: 100分 - - 5-10km: 90分 - - 10-20km: 80分 - - 20-50km: 60分 - - 50km以上: 30分 - -2. **薪资评分**: - - 职位薪资 ≥ 期望薪资: 100分 - - 职位薪资 ≥ 期望薪资 × 0.8: 80分 - - 职位薪资 ≥ 期望薪资 × 0.6: 60分 - - 其他: 40分 - -3. **工作年限评分**: - - 简历年限 ≥ 职位要求: 100分 - - 简历年限 ≥ 职位要求 × 0.8: 80分 - - 简历年限 ≥ 职位要求 × 0.6: 60分 - - 其他: 40分 - -4. **学历评分**: - - 简历学历 ≥ 职位要求: 100分 - - 简历学历 = 职位要求 - 1级: 70分 - - 其他: 40分 - -5. **技能评分**: - - 计算简历技能与职位类型配置的技能关键词匹配度 - - 作为额外加分项,固定权重10% - -**使用示例:** -```javascript -const jobData = { - longitude: 116.3974, - latitude: 39.9093, - salary: '20-30K', - experience: '3-5年', - education: '本科' -}; - -const resumeInfo = { - expectedSalary: '25K', - workYears: 4, - education: '本科', - skills: ['Vue', 'React', 'JavaScript'] -}; - -const accountConfig = { - user_longitude: 116.4074, - user_latitude: 39.9042 -}; - -const jobTypeConfig = { - commonSkills: ['Vue', 'React', 'JavaScript', 'Node.js'] -}; - -const priorityWeights = [ - { key: 'distance', weight: 30 }, - { key: 'salary', weight: 40 }, - { key: 'work_years', weight: 20 }, - { key: 'education', weight: 10 } -]; - -const result = jobFilterService.calculateJobScoreWithWeights( - jobData, - resumeInfo, - accountConfig, - jobTypeConfig, - priorityWeights -); - -console.log(result.totalScore); // 85 -console.log(result.scores); // { distance: 100, salary: 90, work_years: 100, ... } -``` - ---- - -### 6. parseSalaryRange(salaryDesc) - -解析薪资范围字符串。 - -**参数:** -- `salaryDesc` (string): 薪资描述字符串 - - 支持格式:`15-25K`、`25K`、`5000-6000元/月`、`2-3万`、`20000-30000` 等 - -**返回值:** -```javascript -{ - min: number, // 最低薪资(元) - max: number // 最高薪资(元) -} -``` -或 `null`(解析失败时) - -**使用示例:** -```javascript -const range1 = jobFilterService.parseSalaryRange('15-25K'); -console.log(range1); // { min: 15000, max: 25000 } - -const range2 = jobFilterService.parseSalaryRange('2-3万'); -console.log(range2); // { min: 20000, max: 30000 } -``` - ---- - -### 7. parseExpectedSalary(expectedSalary) - -解析期望薪资字符串,返回平均值。 - -**参数:** -- `expectedSalary` (string): 期望薪资描述字符串 - -**返回值:** -- `number`: 期望薪资数值(元),如果是范围则返回平均值 -- `null`: 解析失败时 - -**使用示例:** -```javascript -const salary1 = jobFilterService.parseExpectedSalary('20-30K'); -console.log(salary1); // 25000(平均值) - -const salary2 = jobFilterService.parseExpectedSalary('25K'); -console.log(salary2); // 25000 -``` - ---- - -### 8. parseWorkYears(workYearsStr) - -解析工作年限字符串为数字。 - -**参数:** -- `workYearsStr` (string): 工作年限字符串(如 "3年"、"5年以上") - -**返回值:** -- `number`: 工作年限数字 -- `null`: 解析失败时 - -**使用示例:** -```javascript -const years = jobFilterService.parseWorkYears('3-5年'); -console.log(years); // 3(提取第一个数字) -``` - ---- - -## 辅助方法 - -### buildJobText(jobInfo) - -构建职位文本(用于匹配)。 - -**参数:** -- `jobInfo` (object): 职位信息对象 - -**返回值:** -- `string`: 合并后的职位文本(小写) - ---- - -### buildResumeText(resumeInfo) - -构建简历文本(用于匹配)。 - -**参数:** -- `resumeInfo` (object): 简历信息对象 - -**返回值:** -- `string`: 合并后的简历文本(小写) - ---- - -### calculateSkillMatch(jobText, resumeText, commonSkills) - -计算技能匹配度(0-100分)。 - -**参数:** -- `jobText` (string): 职位文本 -- `resumeText` (string): 简历文本 -- `commonSkills` (Array): 技能关键词列表 - -**返回值:** -- `number`: 匹配度分数(0-100) - ---- - -### calculateExperienceMatch(jobInfo, resumeInfo) - -计算经验匹配度(0-100分)。 - -**参数:** -- `jobInfo` (object): 职位信息 -- `resumeInfo` (object): 简历信息 - -**返回值:** -- `number`: 匹配度分数(0-100) - ---- - -### calculateSalaryMatch(jobInfo, resumeInfo) - -计算薪资合理性(0-100分)。 - -**参数:** -- `jobInfo` (object): 职位信息 -- `resumeInfo` (object): 简历信息 - -**返回值:** -- `number`: 匹配度分数(0-100) - ---- - -### checkOutsourcing(jobText) - -检查是否为外包岗位。 - -**参数:** -- `jobText` (string): 职位文本 - -**返回值:** -- `boolean`: 是否为外包 - ---- - -## 默认配置 - -### 默认技能关键词 - -```javascript -[ - 'Vue', 'React', 'Angular', 'JavaScript', 'TypeScript', 'Node.js', - 'Python', 'Java', 'C#', '.NET', 'Flutter', 'React Native', - 'Webpack', 'Vite', 'Redux', 'MobX', 'Express', 'Koa', - 'Django', 'Flask', 'MySQL', 'MongoDB', 'Redis', - 'WebRTC', 'FFmpeg', 'Canvas', 'WebSocket', 'HTML5', 'CSS3', - 'jQuery', 'Bootstrap', 'Element UI', 'Ant Design', - 'Git', 'Docker', 'Kubernetes', 'AWS', 'Azure', - 'Selenium', 'Jest', 'Mocha', 'Cypress' -] -``` - -### 默认排除关键词 - -```javascript -[ - '外包', '外派', '驻场', '销售', '客服', '电话销售', - '地推', '推广', '市场', '运营', '行政', '文员' -] -``` - -## 数据库依赖 - -该服务依赖以下数据库表: - -### job_types 表 - -存储职位类型配置,需要包含以下字段: -- `id` (number): 职位类型ID -- `is_enabled` (number): 是否启用(1=启用,0=禁用) -- `commonSkills` (string|JSON): 技能关键词列表(JSON数组字符串) -- `excludeKeywords` (string|JSON): 排除关键词列表(JSON数组字符串) - -**示例数据:** -```json -{ - "id": 1, - "is_enabled": 1, - "commonSkills": "[\"Vue\", \"React\", \"JavaScript\"]", - "excludeKeywords": "[\"外包\", \"外派\"]" -} -``` - -## 使用示例 - -### 完整使用流程 - -```javascript -const jobFilterService = require('./job_filter_service'); - -// 1. 分析单个职位的匹配度 -const jobInfo = { - jobTitle: '高级前端开发工程师', - companyName: 'XX科技有限公司', - description: '负责前端架构设计,要求5年以上Vue/React开发经验', - skills: 'Vue, React, TypeScript, Node.js', - requirements: '本科及以上学历,有大型项目经验', - salary: '25-40K·14薪' -}; - -const resumeInfo = { - skills: 'Vue, React, JavaScript, TypeScript, Node.js, Webpack', - skillDescription: '精通Vue生态,熟悉React,有5年+前端开发经验', - currentPosition: '高级前端开发工程师', - expectedPosition: '前端架构师', - workYears: 6, - expectedSalary: '30K', - education: '本科' -}; - -const analysis = await jobFilterService.analyzeJobMatch( - jobInfo, - resumeInfo, - 1 // 职位类型ID -); - -console.log('匹配分析结果:'); -console.log('综合评分:', analysis.overallScore); -console.log('技能匹配度:', analysis.skillMatch); -console.log('经验匹配度:', analysis.experienceMatch); -console.log('薪资匹配度:', analysis.salaryMatch); -console.log('是否外包:', analysis.isOutsourcing); -console.log('匹配原因:', analysis.matchReasons); -console.log('关注点:', analysis.concerns); -console.log('投递建议:', analysis.suggestion); - -// 2. 过滤职位列表 -const jobs = await Job.findAll({ where: { status: 1 } }); - -const filteredJobs = await jobFilterService.filterJobs( - jobs, - { - minScore: 70, - excludeOutsourcing: true, - excludeKeywords: ['销售', '客服'] - }, - resumeInfo, - 1 -); - -console.log(`共找到 ${filteredJobs.length} 个匹配的职位`); -filteredJobs.forEach((job, index) => { - console.log(`${index + 1}. ${job.jobTitle} - 匹配分数:${job.matchScore}`); -}); - -// 3. 自定义权重评分 -const accountConfig = { - user_longitude: 116.4074, - user_latitude: 39.9042 -}; - -const priorityWeights = [ - { key: 'distance', weight: 25 }, - { key: 'salary', weight: 35 }, - { key: 'work_years', weight: 25 }, - { key: 'education', weight: 15 } -]; - -const scoreResult = jobFilterService.calculateJobScoreWithWeights( - jobInfo, - resumeInfo, - accountConfig, - { commonSkills: ['Vue', 'React', 'TypeScript'] }, - priorityWeights -); - -console.log('自定义权重评分:', scoreResult.totalScore); -console.log('各项评分:', scoreResult.scores); -``` - -## 注意事项 - -1. **缓存机制**:职位类型配置会缓存5分钟,修改数据库配置后需要调用 `clearCache()` 清除缓存 - -2. **性能优化**: - - 大量职位过滤时,建议分批处理 - - 避免在循环中频繁调用 `getJobTypeConfig()`,配置会被自动缓存 - -3. **文本匹配**: - - 所有文本匹配均为小写匹配,不区分大小写 - - 匹配逻辑较为简单,如需更精确的匹配,建议使用 AI 分析(二期规划) - -4. **薪资解析**: - - 支持多种薪资格式,但可能无法解析所有格式 - - 解析失败时返回默认分数或 null - -5. **错误处理**: - - 所有方法都包含错误处理,失败时返回默认值或空结果 - - 建议在生产环境中监控日志输出 - -## 版本历史 - -- **v1.0.0**: 初始版本,支持基础文本匹配和过滤功能 -- 支持从数据库动态获取职位类型配置 -- 支持自定义权重评分计算 - diff --git a/api/middleware/job/managers/chatManager.js b/api/middleware/job/managers/chatManager.js new file mode 100644 index 0000000..c289034 --- /dev/null +++ b/api/middleware/job/managers/chatManager.js @@ -0,0 +1,345 @@ +const ai_service_module = require('../../../services/ai_service'); +const ai_service = ai_service_module.getInstance(); + +/** + * 聊天管理模块 + * 负责沟通列表、沟通详情、发送消息等与设备端的 MQTT 指令对接 + */ +class ChatManager { + /** + * 解析沟通列表返回值,统一为 { friendList, foldText, ... } + * 设备端可能返回 code:0 + zpData 或 code:200 + data + * @private + */ + _parse_chat_list_response(response) { + if (!response) return null; + const raw = response.zpData != null ? response.zpData : response.data; + if (!raw) return { friendList: [], foldText: '', filterEncryptIdList: [], filterBossIdList: [] }; + return { + friendList: Array.isArray(raw.friendList) ? raw.friendList : [], + foldText: raw.foldText || '', + filterEncryptIdList: Array.isArray(raw.filterEncryptIdList) ? raw.filterEncryptIdList : [], + filterBossIdList: Array.isArray(raw.filterBossIdList) ? raw.filterBossIdList : [] + }; + } + + /** + * 获取聊天列表 + * 返回值结构: { friendList, foldText, filterEncryptIdList, filterBossIdList } + * friendList 每项: friendId, encryptFriendId, name, updateTime, brandName, jobName, jobCity, positionName, bossTitle 等 + * @param {string} sn_code - 设备SN码 + * @param {object} mqttClient - MQTT客户端 + * @param {object} params - 参数 + * @returns {Promise} { friendList, foldText, filterEncryptIdList, filterBossIdList } + */ + async get_chat_list(sn_code, mqttClient, params = {}) { + const { platform = 'boss', pageCount = 3 } = params; + console.log(`[聊天管理] 开始获取设备 ${sn_code} 的聊天列表`); + + const response = await mqttClient.publishAndWait(sn_code, { + platform, + action: 'get_chat_list', + data: { pageCount } + }); + + // 沟通列表接口成功为 code: 0 或 code: 200 + const ok = response && (response.code === 0 || response.code === 200); + if (!ok) { + console.error(`[聊天管理] 获取聊天列表失败:`, response); + throw new Error(response?.message || '获取聊天列表失败'); + } + + const parsed = this._parse_chat_list_response(response); + console.log(`[聊天管理] 成功获取聊天列表,共 ${parsed.friendList.length} 个联系人`); + return parsed; + } + + /** + * 解析沟通详情返回值(两种形态二选一) + * 形态1 - 会话/职位信息: zpData.data + zpData.job + * 形态2 - 聊天消息列表: zpData.hasMore + zpData.messages + * @private + */ + _parse_chat_detail_response(response) { + if (!response) return null; + const raw = response.zpData != null ? response.zpData : response.data; + if (!raw) return { variant: 'unknown', data: null, job: null, hasMore: false, messages: [] }; + + // 形态2: 消息列表(有 messages 数组) + if (Array.isArray(raw.messages)) { + return { + variant: 'messages', + hasMore: !!raw.hasMore, + messages: raw.messages, + type: raw.type, + minMsgId: raw.minMsgId + }; + } + + // 形态1: 会话详情(data + job) + if (raw.data != null || raw.job != null) { + return { + variant: 'session', + data: raw.data || null, + job: raw.job || null + }; + } + + return { variant: 'unknown', data: null, job: null, hasMore: false, messages: [] }; + } + + /** + * 获取沟通详情(会话信息或聊天消息列表) + * 返回值: { variant: 'session'|'messages', ... } + * - session: data(boss/会话信息), job(职位信息) + * - messages: hasMore, messages[], type, minMsgId + * @param {string} sn_code - 设备SN码 + * @param {object} mqttClient - MQTT客户端 + * @param {object} params - 参数,如 friendId/encryptBossId/encryptJobId 等,由设备端约定 + * @returns {Promise} + */ + async get_chat_detail(sn_code, mqttClient, params = {}) { + const { platform = 'boss', ...rest } = params; + console.log(`[聊天管理] 开始获取设备 ${sn_code} 的沟通详情`); + + const response = await mqttClient.publishAndWait(sn_code, { + platform, + action: 'get_chat_detail', + data: rest + }); + + const ok = response && (response.code === 0 || response.code === 200); + if (!ok) { + console.error(`[聊天管理] 获取沟通详情失败:`, response); + throw new Error(response?.message || '获取沟通详情失败'); + } + + const parsed = this._parse_chat_detail_response(response); + const logExtra = parsed.variant === 'session' + ? `会话` + : parsed.variant === 'messages' + ? `消息 ${parsed.messages.length} 条` + : `未知`; + console.log(`[聊天管理] 成功获取沟通详情 (${logExtra})`); + return parsed; + } + + /** + * 发送聊天消息(支持多条 + 文本/发简历/换电话/换微信) + * @param {string} sn_code - 设备SN码 + * @param {object} mqttClient - MQTT客户端 + * @param {object} params - friendId(必填), messages(数组), chatType, use_real_type, platform + * @param {string} params.friendId - 好友ID,用于打开该好友的聊天面板 + * @param {Array} params.messages - 每项为 string 或 { type: 'text'|'send_resume'|'exchange_phone'|'exchange_wechat', content?: string } + * @param {boolean} params.use_real_type - 是否模拟真实打字,默认 false + * @returns {Promise} 发送结果 + */ + async send_chat_message(sn_code, mqttClient, params) { + const { friendId, messages, chatType, use_real_type = false, platform = 'boss' } = params || {}; + + if (!friendId) throw new Error('friendId 不能为空'); + if (!Array.isArray(messages) || messages.length === 0) throw new Error('messages 必须是非空数组'); + + const normalized_messages = messages.map((item) => { + if (typeof item === 'string') return { type: 'text', content: item }; + return { type: item.type || 'text', content: item.content || '' }; + }); + + console.log(`[聊天管理] 设备 ${sn_code} 发送聊天消息,friendId=${friendId},条数=${normalized_messages.length}`); + + const response = await mqttClient.publishAndWait(sn_code, { + platform, + action: 'send_chat_message', + data: { friendId, messages: normalized_messages, chatType, use_real_type: !!use_real_type } + }); + + if (!response || (response.code !== 0 && response.code !== 200)) { + console.error(`[聊天管理] 聊天消息发送失败:`, response); + throw new Error(response?.message || '聊天消息发送失败'); + } + + console.log(`[聊天管理] 聊天消息发送成功`); + return response; + } + + /** + * 使用 AI 自动决定是否回复,并发送回复 + * 流程: + * 1. 根据参数获取沟通详情(消息列表) + * 2. 如果最后一句是 HR 说的,则调用阿里云 Qwen 生成回复文案 + * 3. 通过 send_chat_message 把回复发出去 + * + * @param {string} sn_code - 设备SN码 + * @param {object} mqttClient - MQTT客户端 + * @param {object} params - 包含 friendId + 获取详情所需参数(如 encryptBossId/encryptJobId 等) + * @returns {Promise} { replied, reply_content?, hr_message_text?, reason? } + */ + async auto_reply_with_ai(sn_code, mqttClient, params = {}) { + const { friendId, platform = 'boss', ...detailParams } = params; + + if (!friendId) { + throw new Error('friendId 不能为空'); + } + + // 1. 获取沟通详情(期望拿到消息列表) + const detail = await this.get_chat_detail(sn_code, mqttClient, { + platform, + ...detailParams + }); + + if (!detail || detail.variant !== 'messages' || !Array.isArray(detail.messages) || detail.messages.length === 0) { + return { replied: false, reason: '无可用消息' }; + } + + const messages = detail.messages; + + // 2. 推断 HR 与 求职者 uid + let hr_uid = null; + let geek_uid = null; + + for (const msg of messages) { + const body = msg.body || {}; + const jobDesc = body.jobDesc || body.job_desc || null; + if (jobDesc) { + if (jobDesc.boss && jobDesc.boss.uid && !hr_uid) { + hr_uid = jobDesc.boss.uid; + } + if (jobDesc.geek && jobDesc.geek.uid && !geek_uid) { + geek_uid = jobDesc.geek.uid; + } + } + if (hr_uid && geek_uid) break; + } + + const last = messages[messages.length - 1]; + + // 兜底:还没有 hr_uid 时,用最后一条的 from/to 做简单推断 + if ((!hr_uid || !geek_uid) && last && last.from && last.to) { + hr_uid = hr_uid || last.from.uid; + geek_uid = geek_uid || last.to.uid; + } + + if (!last || !last.from || !hr_uid || last.from.uid !== hr_uid) { + // 最后一条不是 HR 发的,不自动回复 + return { replied: false, reason: '最后一条不是HR消息' }; + } + + // 取 HR 文本内容(普通文本优先) + const body = last.body || {}; + const hr_message_text = + (typeof body.text === 'string' && body.text) || + (typeof last.pushText === 'string' && last.pushText) || + ''; + + if (!hr_message_text || !hr_message_text.trim()) { + return { replied: false, reason: 'HR消息没有可用文本' }; + } + + // 3. 调用阿里云 Qwen 生成回复文案(已在 config 中切换为 qwen-plus) + const jobInfo = detail.job || {}; + + const reply_content = await ai_service.generateChatContent({ + jobInfo, + resumeInfo: null, + chatType: 'reply', + hrMessage: hr_message_text, + previousMessages: [] // 如需上下文,这里可以把 detail.messages 映射进去 + }); + + if (!reply_content || !reply_content.trim()) { + return { replied: false, reason: 'AI 未生成有效回复' }; + } + + // 4. 通过统一的 send_chat_message 下发回复 + await this.send_chat_message(sn_code, mqttClient, { + friendId, + messages: [{ type: 'text', content: reply_content }], + chatType: 'reply', + platform + }); + + return { + replied: true, + reply_content, + hr_message_text + }; + } + + /** + * 自动获取沟通列表 + 按会话自动 AI 回复 + * 1. 调用 get_chat_list 获取会话列表 + * 2. 对每个会话按 friendId 调用 auto_reply_with_ai(内部会先获取详情,再决定是否回复) + * + * @param {string} sn_code - 设备SN码 + * @param {object} mqttClient - MQTT客户端 + * @param {object} params - { platform?, pageCount? } + * @returns {Promise} { success, total_contacts, replied_count, details: [...] } + */ + async auto_chat_ai(sn_code, mqttClient, params = {}) { + const { platform = 'boss', pageCount = 3 } = params; + + // 1. 获取沟通列表 + const listResult = await this.get_chat_list(sn_code, mqttClient, { + platform, + pageCount + }); + + const friendList = Array.isArray(listResult.friendList) ? listResult.friendList : []; + + if (friendList.length === 0) { + return { + success: true, + total_contacts: 0, + replied_count: 0, + details: [], + message: '没有可沟通的会话' + }; + } + + let replied_count = 0; + const details = []; + + // 2. 逐个会话顺序处理,避免并发下发指令 + for (const friend of friendList) { + const friendId = friend.friendId; + if (!friendId) { + continue; + } + + try { + const r = await this.auto_reply_with_ai(sn_code, mqttClient, { + platform, + friendId + }); + + if (r.replied) { + replied_count++; + } + + details.push({ + friendId, + replied: !!r.replied, + reason: r.reason || null, + reply_content: r.reply_content || null + }); + } catch (error) { + details.push({ + friendId, + replied: false, + reason: error.message || '自动回复失败', + reply_content: null + }); + } + } + + return { + success: true, + total_contacts: friendList.length, + replied_count, + details, + message: '自动获取列表并尝试AI回复完成' + }; + } +} + +module.exports = new ChatManager(); \ No newline at end of file diff --git a/api/middleware/job/managers/index.js b/api/middleware/job/managers/index.js new file mode 100644 index 0000000..5c3e6af --- /dev/null +++ b/api/middleware/job/managers/index.js @@ -0,0 +1,13 @@ +/** + * Managers 模块统一导出 + */ + +const jobManager = require('./jobManager'); +const resumeManager = require('./resumeManager'); +const chatManager = require('./chatManager'); + +module.exports = { + jobManager, + resumeManager, + chatManager +}; diff --git a/api/middleware/job/jobManager.js b/api/middleware/job/managers/jobManager.js similarity index 72% rename from api/middleware/job/jobManager.js rename to api/middleware/job/managers/jobManager.js index aa36a13..ad79076 100644 --- a/api/middleware/job/jobManager.js +++ b/api/middleware/job/managers/jobManager.js @@ -1,10 +1,13 @@ -// const aiService = require('./aiService'); // 二期规划:AI 服务暂时禁用 -const jobFilterService = require('./job_filter_service'); // 使用文本匹配过滤服务 -const locationService = require('../../services/locationService'); // 位置服务 -const logs = require('../logProxy'); -const db = require('../dbProxy'); +const aiServiceModule = require('../../../services/ai_service'); +const { jobFilterService } = require('../services'); +const locationService = require('../../../services/locationService'); +const logs = require('../../logProxy'); +const db = require('../../dbProxy'); const { v4: uuidv4 } = require('uuid'); +// 实例化AI服务 +const aiService = aiServiceModule.getInstance(); + /** * 工作管理模块 * 负责简历获取、分析、存储和匹配度计算 @@ -144,14 +147,350 @@ class JobManager { } /** - * 获取岗位列表 + * 多条件搜索职位列表(新指令,使用新的MQTT action) + * @param {string} sn_code - 设备SN码 + * @param {object} mqttClient - MQTT客户端 + * @param {object} params - 搜索参数 + * @returns {Promise} 搜索结果 + */ + async search_jobs_with_params(sn_code, mqttClient, params = {}) { + const { + keyword = '前端', + platform = 'boss', + city = '', + cityName = '', + salary = '', + experience = '', + education = '', + industry = '', + companySize = '', + financingStage = '', + page = 1, + pageSize = 20, + pageCount = 3 + } = params; + + console.log(`[工作管理] 开始多条件搜索设备 ${sn_code} 的职位,关键词: ${keyword}, 城市: ${cityName || city}`); + + // 构建完整的搜索参数对象 + const searchData = { + keyword, + pageCount + }; + + // 添加可选搜索条件 + if (city) searchData.city = city; + if (cityName) searchData.cityName = cityName; + if (salary) searchData.salary = salary; + if (experience) searchData.experience = experience; + if (education) searchData.education = education; + if (industry) searchData.industry = industry; + if (companySize) searchData.companySize = companySize; + if (financingStage) searchData.financingStage = financingStage; + if (page) searchData.page = page; + if (pageSize) searchData.pageSize = pageSize; + + // 通过MQTT指令获取岗位列表(使用新的action) + const response = await mqttClient.publishAndWait(sn_code, { + platform, + action: "search_job_list", // 新的搜索action + data: searchData + }); + + if (!response || response.code !== 200) { + console.error(`[工作管理] 多条件搜索职位失败:`, response); + throw new Error('多条件搜索职位失败'); + } + + // 处理职位列表数据 + let jobs = []; + if (Array.isArray(response.data)) { + for (const item of response.data) { + if (item.data?.zpData?.jobList && Array.isArray(item.data.zpData.jobList)) { + jobs = jobs.concat(item.data.zpData.jobList); + } + } + } else if (response.data?.data?.zpData?.jobList) { + jobs = response.data.data.zpData.jobList || []; + } else if (response.data?.zpData?.jobList) { + jobs = response.data.zpData.jobList || []; + } + + console.log(`[工作管理] 成功获取岗位数据,共 ${jobs.length} 个岗位`); + + // 保存职位到数据库 + try { + await this.saveJobsToDatabase(sn_code, platform, keyword, jobs); + } catch (error) { + console.error(`[工作管理] 保存职位到数据库失败:`, error); + } + + return { + jobs: jobs, + keyword: keyword, + platform: platform, + count: jobs.length + }; + } + + /** + * 搜索并投递职位(新指令) + * @param {string} sn_code - 设备SN码 + * @param {object} mqttClient - MQTT客户端 + * @param {object} params - 参数 + * @returns {Promise} 执行结果 + */ + async search_and_deliver(sn_code, mqttClient, params = {}) { + const { + keyword, + searchParams = {}, + pageCount = 3, + filterRules = {}, + maxCount = 10, + platform = 'boss' + } = params; + + console.log(`[工作管理] 开始搜索并投递职位,设备: ${sn_code}, 关键词: ${keyword}`); + + // 1. 先执行搜索(使用search_jobs_with_params,新的搜索指令) + const searchResult = await this.search_jobs_with_params(sn_code, mqttClient, { + keyword, + platform, + ...searchParams, + pageCount + }); + + if (!searchResult || searchResult.count === 0) { + return { + success: true, + jobCount: 0, + deliveredCount: 0, + message: '未找到职位' + }; + } + + // 2. 等待数据保存完成 + await new Promise(resolve => setTimeout(resolve, 2000)); + + // 3. 从数据库获取刚搜索到的职位 + const job_postings = db.getModel('job_postings'); + const searchedJobs = await job_postings.findAll({ + where: { + sn_code: sn_code, + platform: platform, + applyStatus: 'pending', + keyword: keyword + }, + order: [['create_time', 'DESC']], + limit: 1000 + }); + + if (searchedJobs.length === 0) { + return { + success: true, + jobCount: searchResult.count, + deliveredCount: 0, + message: '未找到待投递的职位' + }; + } + + // 4. 获取简历信息用于匹配 + const resume_info = db.getModel('resume_info'); + const resume = await resume_info.findOne({ + where: { + sn_code: sn_code, + platform: platform, + isActive: true + }, + order: [['last_modify_time', 'DESC']] + }); + + if (!resume) { + return { + success: true, + jobCount: searchResult.count, + deliveredCount: 0, + message: '未找到活跃简历,无法投递' + }; + } + + // 5. 获取账号配置 + const pla_account = db.getModel('pla_account'); + const account = await pla_account.findOne({ + where: { sn_code, platform_type: platform } + }); + + if (!account) { + throw new Error('账号不存在'); + } + + const accountConfig = account.toJSON(); + const resumeData = resume.toJSON(); + + // 6. 使用过滤方法进行职位匹配 + const matchedJobs = await this.filter_jobs_by_rules(searchedJobs, { + minSalary: filterRules.minSalary || 0, + maxSalary: filterRules.maxSalary || 0, + keywords: filterRules.keywords || [], + excludeKeywords: filterRules.excludeKeywords || [], + accountConfig: accountConfig, + resumeInfo: resumeData + }); + + // 7. 限制投递数量 + const jobsToDeliver = matchedJobs.slice(0, maxCount); + console.log(`[工作管理] 匹配到 ${matchedJobs.length} 个职位,将投递 ${jobsToDeliver.length} 个`); + + // 8. 执行投递 + let deliveredCount = 0; + const apply_records = db.getModel('apply_records'); + + for (let i = 0; i < jobsToDeliver.length; i++) { + const job = jobsToDeliver[i]; + const jobData = job.toJSON ? job.toJSON() : job; + + try { + // 从原始数据中获取 securityId + let securityId = jobData.securityId || ''; + try { + if (jobData.originalData) { + const originalData = typeof jobData.originalData === 'string' + ? JSON.parse(jobData.originalData) + : jobData.originalData; + securityId = originalData.securityId || securityId; + } + } catch (e) { + console.warn(`[工作管理] 解析职位原始数据失败:`, e); + } + + // 执行投递(使用新的deliver_resume_search action) + const deliverResult = await this.deliver_resume(sn_code, mqttClient, { + jobId: jobData.jobId, + encryptBossId: jobData.encryptBossId || '', + securityId: securityId, + brandName: jobData.companyName || '', + jobTitle: jobData.jobTitle || '', + companyName: jobData.companyName || '', + platform: platform, + action: 'deliver_resume_search' // 搜索并投递使用新的action + }); + + if (deliverResult && deliverResult.success) { + deliveredCount++; + } + + // 投递间隔控制 + if (i < jobsToDeliver.length - 1) { + await new Promise(resolve => setTimeout(resolve, 3000)); + } + } catch (error) { + console.error(`[工作管理] 投递职位失败:`, error); + // 继续投递下一个职位 + } + } + + return { + success: true, + jobCount: searchResult.count, + deliveredCount: deliveredCount, + message: `搜索完成,找到 ${searchResult.count} 个职位,成功投递 ${deliveredCount} 个` + }; + } + + /** + * 获取岗位列表(支持多条件搜索) * @param {string} sn_code - 设备SN码 * @param {object} mqttClient - MQTT客户端 * @param {object} params - 参数 * @returns {Promise} 岗位列表 */ async get_job_list(sn_code, mqttClient, params = {}) { - const { keyword = '前端', platform = 'boss', pageCount = 3 } = params; + const { + keyword = '前端', + platform = 'boss', + pageCount = 3, + city = '', + cityName = '', + salary = '', + experience = '', + education = '', + industry = '', + companySize = '', + financingStage = '', + page = 1, + pageSize = 20 + } = params; + + // 判断是否是多条件搜索(如果包含多条件参数,使用多条件搜索逻辑) + const hasMultiParams = city || cityName || salary || experience || education || + industry || companySize || financingStage || page || pageSize; + + if (hasMultiParams) { + // 使用多条件搜索逻辑 + console.log(`[工作管理] 开始多条件搜索设备 ${sn_code} 的职位,关键词: ${keyword}, 城市: ${cityName || city}`); + + // 构建完整的搜索参数对象 + const searchData = { + keyword, + pageCount + }; + + // 添加可选搜索条件 + if (city) searchData.city = city; + if (cityName) searchData.cityName = cityName; + if (salary) searchData.salary = salary; + if (experience) searchData.experience = experience; + if (education) searchData.education = education; + if (industry) searchData.industry = industry; + if (companySize) searchData.companySize = companySize; + if (financingStage) searchData.financingStage = financingStage; + if (page) searchData.page = page; + if (pageSize) searchData.pageSize = pageSize; + + // 通过MQTT指令获取岗位列表(保持action不变,前端已使用) + const response = await mqttClient.publishAndWait(sn_code, { + platform, + action: "get_job_list", // 保持与原有get_job_list相同的action,前端已使用 + data: searchData + }); + + if (!response || response.code !== 200) { + console.error(`[工作管理] 多条件搜索职位失败:`, response); + throw new Error('多条件搜索职位失败'); + } + + // 处理职位列表数据 + let jobs = []; + if (Array.isArray(response.data)) { + for (const item of response.data) { + if (item.data?.zpData?.jobList && Array.isArray(item.data.zpData.jobList)) { + jobs = jobs.concat(item.data.zpData.jobList); + } + } + } else if (response.data?.data?.zpData?.jobList) { + jobs = response.data.data.zpData.jobList || []; + } else if (response.data?.zpData?.jobList) { + jobs = response.data.zpData.jobList || []; + } + + console.log(`[工作管理] 成功获取岗位数据,共 ${jobs.length} 个岗位`); + + // 保存职位到数据库 + try { + await this.saveJobsToDatabase(sn_code, platform, keyword, jobs); + } catch (error) { + console.error(`[工作管理] 保存职位到数据库失败:`, error); + } + + return { + jobs: jobs, + keyword: keyword, + platform: platform, + count: jobs.length + }; + } + + // 简单搜索逻辑(保持原有逻辑) console.log(`[工作管理] 开始获取设备 ${sn_code} 的岗位列表,关键词: ${keyword}`); // 通过MQTT指令获取岗位列表 @@ -320,10 +659,11 @@ class JobManager { * @param {string} params.brandName - 公司名称(可选) * @param {string} params.jobTitle - 职位标题(可选) * @param {string} params.companyName - 公司名称(可选) + * @param {string} params.action - MQTT Action(默认:deliver_resume,可选:deliver_resume_search) * @returns {Promise} 投递结果 */ - async applyJob(sn_code, mqttClient, params = {}) { - const { platform = 'boss', jobId, encryptBossId, securityId, brandName, jobTitle, companyName } = params; + async deliver_resume(sn_code, mqttClient, params = {}) { + const { platform = 'boss', jobId, encryptBossId, securityId, brandName, jobTitle, companyName, action = 'deliver_resume' } = params; if (!jobId) { throw new Error('jobId 参数不能为空,请指定要投递的职位ID'); @@ -401,10 +741,10 @@ class JobManager { console.log(`[工作管理] 投递职位: ${jobData.jobTitle} @ ${jobData.companyName}`); - // 通过MQTT指令投递简历 + // 通过MQTT指令投递简历(支持自定义action) const response = await mqttClient.publishAndWait(sn_code, { platform, - action: "deliver_resume", + action: action, // 使用传入的action参数,默认为"deliver_resume" data: { encryptJobId: jobData.jobId, securityId: jobData.securityId || securityId || '', diff --git a/api/middleware/job/resumeManager.js b/api/middleware/job/managers/resumeManager.js similarity index 99% rename from api/middleware/job/resumeManager.js rename to api/middleware/job/managers/resumeManager.js index 3b6e446..6424f44 100644 --- a/api/middleware/job/resumeManager.js +++ b/api/middleware/job/managers/resumeManager.js @@ -1,9 +1,12 @@ -const aiService = require('./aiService'); -const jobFilterService = require('./job_filter_service'); -const logs = require('../logProxy'); -const db = require('../dbProxy'); +const aiServiceModule = require('../../../services/ai_service'); +const { jobFilterService } = require('../services'); +const logs = require('../../logProxy'); +const db = require('../../dbProxy'); const { v4: uuidv4 } = require('uuid'); +// 实例化AI服务 +const aiService = aiServiceModule.getInstance(); + /** * 简历管理模块 * 负责简历获取、分析、存储和匹配度计算 diff --git a/api/middleware/job/services/index.js b/api/middleware/job/services/index.js new file mode 100644 index 0000000..2756d8a --- /dev/null +++ b/api/middleware/job/services/index.js @@ -0,0 +1,9 @@ +/** + * Services 模块统一导出 + */ + +const jobFilterService = require('./jobFilterService'); + +module.exports = { + jobFilterService +}; diff --git a/api/middleware/job/job_filter_service.js b/api/middleware/job/services/jobFilterService.js similarity index 99% rename from api/middleware/job/job_filter_service.js rename to api/middleware/job/services/jobFilterService.js index ede0bd3..edf6d6a 100644 --- a/api/middleware/job/job_filter_service.js +++ b/api/middleware/job/services/jobFilterService.js @@ -4,8 +4,8 @@ * 支持从数据库动态获取职位类型的技能关键词和排除关键词 */ -const db = require('../dbProxy.js'); -const locationService = require('../../services/locationService'); +const db = require('../../dbProxy.js'); +const locationService = require('../../../services/locationService'); class JobFilterService { constructor() { diff --git a/api/middleware/job/utils/index.js b/api/middleware/job/utils/index.js new file mode 100644 index 0000000..67be924 --- /dev/null +++ b/api/middleware/job/utils/index.js @@ -0,0 +1,7 @@ +/** + * Utils 模块统一导出 + */ + +module.exports = { + // 工具函数将在需要时添加 +}; diff --git a/api/middleware/mqtt/mqttClient.js b/api/middleware/mqtt/mqttClient.js index 2d04cac..2dbb044 100644 --- a/api/middleware/mqtt/mqttClient.js +++ b/api/middleware/mqtt/mqttClient.js @@ -29,12 +29,7 @@ class MqttSyncClient { return; } - // 记录日志但不包含敏感信息 - const { maskSensitiveData } = require('../../utils/crypto_utils'); - const safeMessage = maskSensitiveData(messageObj, ['password', 'pwd', 'token', 'secret', 'key', 'cookie']); - console.log('[MQTT] 收到消息', topic, '类型:', messageObj.action || messageObj.type || 'unknown'); - // 优化:只通知相关 topic 的监听器,而不是所有监听器 // 1. 触发该 topic 的专用监听器 const topicListeners = this.messageListeners.get(topic); if (topicListeners && topicListeners.size > 0) { diff --git a/api/middleware/mqtt/mqttDispatcher.js b/api/middleware/mqtt/mqttDispatcher.js index 63f2c57..1081c7a 100644 --- a/api/middleware/mqtt/mqttDispatcher.js +++ b/api/middleware/mqtt/mqttDispatcher.js @@ -1,6 +1,6 @@ const db = require('../dbProxy.js'); const logProxy = require('../logProxy.js'); -const deviceManager = require('../schedule/deviceManager.js'); +const deviceManager = require('../schedule/core/deviceManager.js'); /** * MQTT 消息分发器 @@ -212,8 +212,6 @@ class MqttDispatcher { return; } - console.log(`[MQTT心跳] 收到设备 ${sn_code} 的心跳消息`); - // 移除 device_status 模型依赖 // const device_status = db.getModel('device_status'); // let device = await device_status.findByPk(sn_code); @@ -286,7 +284,6 @@ class MqttDispatcher { }, { where: { sn_code } } ); - console.log(`[MQTT心跳] 设备 ${sn_code} 状态已更新到数据库 - 在线: true, 登录: ${updateData.isLoggedIn || false}`); } catch (error) { console.error(`[MQTT心跳] 更新数据库状态失败:`, error); } diff --git a/api/middleware/schedule/command.js b/api/middleware/schedule/core/command.js similarity index 93% rename from api/middleware/schedule/command.js rename to api/middleware/schedule/core/command.js index d9ec1e4..8f79d35 100644 --- a/api/middleware/schedule/command.js +++ b/api/middleware/schedule/core/command.js @@ -1,9 +1,9 @@ -const logs = require('../logProxy'); -const db = require('../dbProxy'); -const jobManager = require('../job/index'); -const ScheduleUtils = require('./utils'); -const ScheduleConfig = require('./config'); -const authorizationService = require('../../services/authorization_service'); +const logs = require('../../logProxy'); +const db = require('../../dbProxy'); +const jobManager = require('../../job/index'); +const ScheduleUtils = require('../utils/scheduleUtils'); +const ScheduleConfig = require('../infrastructure/config'); +const authorizationService = require('../../../services/authorization_service'); /** @@ -129,7 +129,7 @@ class CommandManager { // 4.5 推送指令开始执行状态 try { - const deviceWorkStatusNotifier = require('./deviceWorkStatusNotifier'); + const deviceWorkStatusNotifier = require('../notifiers/deviceWorkStatusNotifier'); const taskQueue = require('./taskQueue'); const summary = await taskQueue.getTaskStatusSummary(task.sn_code); await deviceWorkStatusNotifier.sendDeviceWorkStatus(task.sn_code, summary, { @@ -163,7 +163,7 @@ class CommandManager { // 6.5 推送指令完成状态 try { - const deviceWorkStatusNotifier = require('./deviceWorkStatusNotifier'); + const deviceWorkStatusNotifier = require('../notifiers/deviceWorkStatusNotifier'); const taskQueue = require('./taskQueue'); const summary = await taskQueue.getTaskStatusSummary(task.sn_code); await deviceWorkStatusNotifier.sendDeviceWorkStatus(task.sn_code, summary); @@ -193,7 +193,7 @@ class CommandManager { // 推送指令失败状态 try { - const deviceWorkStatusNotifier = require('./deviceWorkStatusNotifier'); + const deviceWorkStatusNotifier = require('../notifiers/deviceWorkStatusNotifier'); const taskQueue = require('./taskQueue'); const summary = await taskQueue.getTaskStatusSummary(task.sn_code); await deviceWorkStatusNotifier.sendDeviceWorkStatus(task.sn_code, summary); @@ -213,29 +213,17 @@ class CommandManager { * @private */ async _execute_command_with_timeout(command_id, command_type, command_name, command_params, sn_code, mqttClient, start_time) { - // 将驼峰命名转换为下划线命名 - const to_snake_case = (str) => { - if (str.includes('_')) { - return str; - } - return str.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, ''); - }; - - const method_name = to_snake_case(command_type); - // 获取指令超时时间(从配置中获取,默认5分钟) - const timeout = ScheduleConfig.taskTimeouts[command_type] || - ScheduleConfig.taskTimeouts[method_name] || - 5 * 60 * 1000; - + const timeout = ScheduleConfig.taskTimeouts[command_type] || 5 * 60 * 1000; + // 构建指令执行 Promise const command_promise = (async () => { - if (command_type && jobManager[method_name]) { - return await jobManager[method_name](sn_code, mqttClient, command_params); - } else if (jobManager[command_type]) { + // 直接使用 command_type 调用 jobManager 的方法,不做映射 + // command_type 和 jobManager 的方法名保持一致 + if (jobManager[command_type]) { return await jobManager[command_type](sn_code, mqttClient, command_params); } else { - throw new Error(`未知的指令类型: ${command_type} (尝试的方法名: ${method_name})`); + throw new Error(`未知的指令类型: ${command_type}, jobManager 中不存在对应方法`); } })(); diff --git a/api/middleware/schedule/deviceManager.js b/api/middleware/schedule/core/deviceManager.js similarity index 97% rename from api/middleware/schedule/deviceManager.js rename to api/middleware/schedule/core/deviceManager.js index bdc93b7..06b962d 100644 --- a/api/middleware/schedule/deviceManager.js +++ b/api/middleware/schedule/core/deviceManager.js @@ -1,8 +1,8 @@ const dayjs = require('dayjs'); const Sequelize = require('sequelize'); -const db = require('../dbProxy'); -const config = require('./config'); -const utils = require('./utils'); +const db = require('../../dbProxy'); +const config = require('../infrastructure/config'); +const utils = require('../utils/scheduleUtils'); /** * 设备管理器(简化版) @@ -77,7 +77,6 @@ class DeviceManager { // 更新登录状态 if (heartbeatData.isLoggedIn !== undefined) { device.isLoggedIn = heartbeatData.isLoggedIn; - console.log(`[设备管理器] 设备 ${sn_code} 登录状态更新 - isLoggedIn: ${device.isLoggedIn}`); } } diff --git a/api/middleware/schedule/core/index.js b/api/middleware/schedule/core/index.js new file mode 100644 index 0000000..224cd90 --- /dev/null +++ b/api/middleware/schedule/core/index.js @@ -0,0 +1,16 @@ +/** + * Core 模块导出 + * 统一导出核心模块,简化引用路径 + */ + +const deviceManager = require('./deviceManager'); +const taskQueue = require('./taskQueue'); +const command = require('./command'); +const scheduledJobs = require('./scheduledJobs'); + +module.exports = { + deviceManager, + taskQueue, + command, + scheduledJobs +}; diff --git a/api/middleware/schedule/core/scheduledJobs.js b/api/middleware/schedule/core/scheduledJobs.js new file mode 100644 index 0000000..478556e --- /dev/null +++ b/api/middleware/schedule/core/scheduledJobs.js @@ -0,0 +1,570 @@ +const node_schedule = require("node-schedule"); +const dayjs = require('dayjs'); +const config = require('../infrastructure/config.js'); +const deviceManager = require('./deviceManager.js'); +const command = require('./command.js'); +const db = require('../../dbProxy'); + +// 引入新的任务模块 +const tasks = require('../tasks'); +const { autoSearchTask, autoDeliverTask, autoChatTask, autoActiveTask } = tasks; + +const Framework = require("../../../../framework/node-core-framework.js"); + +/** + * 定时任务管理器(重构版) + * 使用独立的任务模块,职责更清晰,易于维护和扩展 + */ +class ScheduledJobs { + constructor(components, taskHandlers) { + this.taskQueue = components.taskQueue; + this.taskHandlers = taskHandlers; + this.jobs = []; + } + + /** + * 启动所有定时任务 + */ + start() { + console.log('[定时任务] 开始启动所有定时任务...'); + + // ==================== 系统维护任务 ==================== + + // 每天凌晨重置统计数据 + const resetJob = node_schedule.scheduleJob(config.schedules.dailyReset, () => { + this.resetDailyStats(); + }); + this.jobs.push(resetJob); + console.log('[定时任务] ✓ 已启动每日统计重置任务'); + + // 启动心跳检查定时任务(每分钟检查一次) + const monitoringJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => { + await deviceManager.checkHeartbeatStatus().catch(error => { + console.error('[定时任务] 检查心跳状态失败:', error); + }); + }); + this.jobs.push(monitoringJob); + console.log('[定时任务] ✓ 已启动心跳检查任务'); + + // 启动离线设备任务清理定时任务(每分钟检查一次) + const cleanupOfflineTasksJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => { + await this.cleanupOfflineDeviceTasks().catch(error => { + console.error('[定时任务] 清理离线设备任务失败:', error); + }); + }); + this.jobs.push(cleanupOfflineTasksJob); + console.log('[定时任务] ✓ 已启动离线设备任务清理任务'); + + // 启动任务超时检查定时任务(每分钟检查一次) + const timeoutCheckJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => { + await this.checkTaskTimeouts().catch(error => { + console.error('[定时任务] 检查任务超时失败:', error); + }); + }); + this.jobs.push(timeoutCheckJob); + console.log('[定时任务] ✓ 已启动任务超时检查任务'); + + // 启动任务状态摘要同步定时任务(每10秒发送一次) + const taskSummaryJob = node_schedule.scheduleJob('*/10 * * * * *', async () => { + await this.syncTaskStatusSummary().catch(error => { + console.error('[定时任务] 同步任务状态摘要失败:', error); + }); + }); + this.jobs.push(taskSummaryJob); + console.log('[定时任务] ✓ 已启动任务状态摘要同步任务'); + + // ==================== 业务任务(使用新的任务模块) ==================== + + // 1. 自动搜索任务 - 每60分钟执行一次 + const autoSearchJob = node_schedule.scheduleJob(config.schedules.autoSearch || '0 0 */1 * * *', () => { + this.runAutoSearchTask(); + }); + this.jobs.push(autoSearchJob); + console.log('[定时任务] ✓ 已启动自动搜索任务 (每60分钟)'); + + // 2. 自动投递任务 - 每1分钟检查一次 + const autoDeliverJob = node_schedule.scheduleJob(config.schedules.autoDeliver, () => { + this.runAutoDeliverTask(); + }); + this.jobs.push(autoDeliverJob); + console.log('[定时任务] ✓ 已启动自动投递任务 (每1分钟)'); + + // 3. 自动沟通任务 - 每15分钟执行一次 + const autoChatJob = node_schedule.scheduleJob(config.schedules.autoChat || '0 */15 * * * *', () => { + this.runAutoChatTask(); + }); + this.jobs.push(autoChatJob); + console.log('[定时任务] ✓ 已启动自动沟通任务 (每15分钟)'); + + // 4. 自动活跃任务 - 每2小时执行一次 + const autoActiveJob = node_schedule.scheduleJob(config.schedules.autoActive || '0 0 */2 * * *', () => { + this.runAutoActiveTask(); + }); + this.jobs.push(autoActiveJob); + console.log('[定时任务] ✓ 已启动自动活跃任务 (每2小时)'); + + // 立即执行一次业务任务(可选) + setTimeout(() => { + console.log('[定时任务] 立即执行一次初始化任务...'); + this.runAutoDeliverTask(); + this.runAutoChatTask(); + }, 10000); // 延迟10秒,等待系统初始化完成和设备心跳 + + console.log('[定时任务] 所有定时任务启动完成!'); + } + + // ==================== 业务任务执行方法(使用新的任务模块) ==================== + + /** + * 运行自动搜索任务 + * 为所有启用自动搜索的账号添加搜索任务 + */ + async runAutoSearchTask() { + try { + const accounts = await this.getEnabledAccounts('auto_search'); + + if (accounts.length === 0) { + return; + } + + console.log(`[自动搜索调度] 找到 ${accounts.length} 个启用自动搜索的账号`); + + let successCount = 0; + let failedCount = 0; + + for (const account of accounts) { + const result = await autoSearchTask.addToQueue(account.sn_code, this.taskQueue); + if (result.success) { + successCount++; + } else { + failedCount++; + } + } + + if (successCount > 0 || failedCount > 0) { + console.log(`[自动搜索调度] 完成: 成功 ${successCount} 个, 失败/跳过 ${failedCount} 个`); + } + } catch (error) { + console.error('[自动搜索调度] 执行失败:', error); + } + } + + /** + * 运行自动投递任务 + * 为所有启用自动投递的账号添加投递任务 + */ + async runAutoDeliverTask() { + try { + const accounts = await this.getEnabledAccounts('auto_deliver'); + + if (accounts.length === 0) { + return; + } + + console.log(`[自动投递调度] 找到 ${accounts.length} 个启用自动投递的账号`); + + let successCount = 0; + let failedCount = 0; + + for (const account of accounts) { + const result = await autoDeliverTask.addToQueue(account.sn_code, this.taskQueue); + if (result.success) { + successCount++; + } else { + failedCount++; + } + } + + if (successCount > 0 || failedCount > 0) { + console.log(`[自动投递调度] 完成: 成功 ${successCount} 个, 失败/跳过 ${failedCount} 个`); + } + } catch (error) { + console.error('[自动投递调度] 执行失败:', error); + } + } + + /** + * 运行自动沟通任务 + * 为所有启用自动沟通的账号添加沟通任务 + */ + async runAutoChatTask() { + try { + const accounts = await this.getEnabledAccounts('auto_chat'); + + if (accounts.length === 0) { + return; + } + + console.log(`[自动沟通调度] 找到 ${accounts.length} 个启用自动沟通的账号`); + + let successCount = 0; + let failedCount = 0; + + for (const account of accounts) { + const result = await autoChatTask.addToQueue(account.sn_code, this.taskQueue); + if (result.success) { + successCount++; + } else { + failedCount++; + } + } + + if (successCount > 0 || failedCount > 0) { + console.log(`[自动沟通调度] 完成: 成功 ${successCount} 个, 失败/跳过 ${failedCount} 个`); + } + } catch (error) { + console.error('[自动沟通调度] 执行失败:', error); + } + } + + /** + * 运行自动活跃任务 + * 为所有启用自动活跃的账号添加活跃任务 + */ + async runAutoActiveTask() { + try { + const accounts = await this.getEnabledAccounts('auto_active'); + + if (accounts.length === 0) { + return; + } + + console.log(`[自动活跃调度] 找到 ${accounts.length} 个启用自动活跃的账号`); + + let successCount = 0; + let failedCount = 0; + + for (const account of accounts) { + const result = await autoActiveTask.addToQueue(account.sn_code, this.taskQueue); + if (result.success) { + successCount++; + } else { + failedCount++; + } + } + + if (successCount > 0 || failedCount > 0) { + console.log(`[自动活跃调度] 完成: 成功 ${successCount} 个, 失败/跳过 ${failedCount} 个`); + } + } catch (error) { + console.error('[自动活跃调度] 执行失败:', error); + } + } + + /** + * 获取启用指定功能的账号列表 + * @param {string} featureType - 功能类型: auto_search, auto_deliver, auto_chat, auto_active + */ + async getEnabledAccounts(featureType) { + try { + const { pla_account } = db.models; + + const accounts = await pla_account.findAll({ + where: { + is_delete: 0, + is_enabled: 1, + [featureType]: 1 + }, + attributes: ['sn_code', 'name', 'keyword', 'platform_type'] + }); + + return accounts.map(acc => acc.toJSON()); + } catch (error) { + console.error(`[获取账号列表] 失败 (${featureType}):`, error); + return []; + } + } + + // ==================== 系统维护方法(保留原有逻辑) ==================== + + /** + * 重置每日统计 + */ + resetDailyStats() { + console.log('[定时任务] 重置每日统计数据'); + + try { + deviceManager.resetAllDailyCounters(); + console.log('[定时任务] 每日统计重置完成'); + } catch (error) { + console.error('[定时任务] 重置统计失败:', error); + } + } + + /** + * 清理过期数据 + */ + cleanupCaches() { + console.log('[定时任务] 开始清理过期数据'); + + try { + deviceManager.cleanupOfflineDevices(config.monitoring.offlineThreshold); + command.cleanupExpiredCommands(30); + console.log('[定时任务] 数据清理完成'); + } catch (error) { + console.error('[定时任务] 数据清理失败:', error); + } + } + + /** + * 清理离线设备任务 + * 检查离线超过10分钟的设备,取消其所有pending/running状态的任务 + */ + async cleanupOfflineDeviceTasks() { + try { + // 离线阈值:10分钟 + const offlineThreshold = 10 * 60 * 1000; + const now = Date.now(); + const thresholdTime = now - offlineThreshold; + + // 获取所有启用的账号 + const pla_account = db.getModel('pla_account'); + const accounts = await pla_account.findAll({ + where: { + is_delete: 0, + is_enabled: 1 + }, + attributes: ['sn_code'] + }); + + if (!accounts || accounts.length === 0) { + return; + } + + // 通过 deviceManager 检查哪些设备离线超过10分钟 + const offlineSnCodes = []; + const offlineDevicesInfo = []; + + for (const account of accounts) { + const sn_code = account.sn_code; + const device = deviceManager.devices.get(sn_code); + + if (!device) { + offlineSnCodes.push(sn_code); + offlineDevicesInfo.push({ + sn_code: sn_code, + lastHeartbeatTime: null + }); + } else { + const lastHeartbeat = device.lastHeartbeat || 0; + if (lastHeartbeat < thresholdTime || !device.isOnline) { + offlineSnCodes.push(sn_code); + offlineDevicesInfo.push({ + sn_code: sn_code, + lastHeartbeatTime: lastHeartbeat ? new Date(lastHeartbeat) : null + }); + } + } + } + + if (offlineSnCodes.length === 0) { + return; + } + + console.log(`[清理离线任务] 发现 ${offlineSnCodes.length} 个离线超过10分钟的设备`); + + let totalCancelled = 0; + const task_status = db.getModel('task_status'); + + for (const sn_code of offlineSnCodes) { + try { + const deviceInfo = offlineDevicesInfo.find(d => d.sn_code === sn_code); + + const updateResult = await task_status.update( + { + status: 'cancelled', + endTime: new Date(), + result: JSON.stringify({ + reason: '设备离线超过10分钟,任务已自动取消', + offlineTime: deviceInfo?.lastHeartbeatTime + }) + }, + { + where: { + sn_code: sn_code, + status: ['pending', 'running'] + } + } + ); + + const cancelledCount = Array.isArray(updateResult) ? updateResult[0] : updateResult; + totalCancelled += cancelledCount; + + if (this.taskQueue && typeof this.taskQueue.cancelDeviceTasks === 'function') { + await this.taskQueue.cancelDeviceTasks(sn_code); + } + + if (cancelledCount > 0) { + console.log(`[清理离线任务] 设备 ${sn_code} 已取消 ${cancelledCount} 个任务`); + } + } catch (error) { + console.error(`[清理离线任务] 取消设备 ${sn_code} 的任务失败:`, error); + } + } + + if (totalCancelled > 0) { + console.log(`[清理离线任务] 共取消 ${totalCancelled} 个离线设备的任务`); + } + } catch (error) { + console.error('[清理离线任务] 执行失败:', error); + } + } + + /** + * 同步任务状态摘要到客户端 + */ + async syncTaskStatusSummary() { + try { + const { pla_account } = await Framework.getModels(); + + const accounts = await pla_account.findAll({ + where: { + is_delete: 0, + is_enabled: 1 + }, + attributes: ['sn_code'] + }); + + if (!accounts || accounts.length === 0) { + return; + } + + const offlineThreshold = 3 * 60 * 1000; + const now = Date.now(); + + for (const account of accounts) { + const sn_code = account.sn_code; + const device = deviceManager.devices.get(sn_code); + + if (!device) { + continue; + } + + const lastHeartbeat = device.lastHeartbeat || 0; + const isOnline = device.isOnline && (now - lastHeartbeat < offlineThreshold); + + if (!isOnline) { + continue; + } + + try { + const deviceWorkStatusNotifier = require('../notifiers/deviceWorkStatusNotifier'); + const summary = await this.taskQueue.getTaskStatusSummary(sn_code); + await deviceWorkStatusNotifier.sendDeviceWorkStatus(sn_code, summary, { + currentCommand: summary.currentCommand || null + }); + } catch (error) { + console.error(`[设备工作状态同步] 设备 ${sn_code} 同步失败:`, error.message); + } + } + } catch (error) { + console.error('[任务状态同步] 执行失败:', error); + } + } + + /** + * 检查任务超时并强制标记为失败 + */ + async checkTaskTimeouts() { + try { + const Sequelize = require('sequelize'); + const { task_status, op } = db.models; + + const runningTasks = await task_status.findAll({ + where: { + status: 'running' + }, + attributes: ['id', 'sn_code', 'taskType', 'taskName', 'startTime', 'create_time'] + }); + + if (!runningTasks || runningTasks.length === 0) { + return; + } + + const now = new Date(); + let timeoutCount = 0; + + for (const task of runningTasks) { + const taskData = task.toJSON(); + const startTime = taskData.startTime ? new Date(taskData.startTime) : (taskData.create_time ? new Date(taskData.create_time) : null); + + if (!startTime) { + continue; + } + + const taskTimeout = config.getTaskTimeout(taskData.taskType) || 10 * 60 * 1000; + const maxAllowedTime = taskTimeout * 1.2; + const elapsedTime = now.getTime() - startTime.getTime(); + + if (elapsedTime > maxAllowedTime) { + try { + await task_status.update( + { + status: 'failed', + endTime: now, + duration: elapsedTime, + result: JSON.stringify({ + error: `任务执行超时(运行时间: ${Math.round(elapsedTime / 1000)}秒,超时限制: ${Math.round(maxAllowedTime / 1000)}秒)`, + timeout: true, + taskType: taskData.taskType, + startTime: startTime.toISOString() + }), + progress: 0 + }, + { + where: { id: taskData.id } + } + ); + + timeoutCount++; + console.warn(`[任务超时检查] 任务 ${taskData.id} (${taskData.taskName}) 运行时间过长,已强制标记为失败`); + + if (this.taskQueue && typeof this.taskQueue.deviceStatus !== 'undefined') { + const deviceStatus = this.taskQueue.deviceStatus.get(taskData.sn_code); + if (deviceStatus && deviceStatus.currentTask && deviceStatus.currentTask.id === taskData.id) { + deviceStatus.isRunning = false; + deviceStatus.currentTask = null; + deviceStatus.runningCount = Math.max(0, deviceStatus.runningCount - 1); + this.taskQueue.globalRunningCount = Math.max(0, this.taskQueue.globalRunningCount - 1); + + console.log(`[任务超时检查] 已重置设备 ${taskData.sn_code} 的状态`); + + setTimeout(() => { + this.taskQueue.processQueue(taskData.sn_code).catch(error => { + console.error(`[任务超时检查] 继续处理队列失败:`, error); + }); + }, 100); + } + } + } catch (error) { + console.error(`[任务超时检查] 更新超时任务状态失败:`, error); + } + } + } + + if (timeoutCount > 0) { + console.log(`[任务超时检查] 共检测到 ${timeoutCount} 个超时任务`); + } + } catch (error) { + console.error('[任务超时检查] 执行失败:', error); + } + } + + /** + * 停止所有定时任务 + */ + stop() { + console.log('[定时任务] 停止所有定时任务...'); + + for (const job of this.jobs) { + if (job) { + job.cancel(); + } + } + + this.jobs = []; + console.log('[定时任务] 所有定时任务已停止'); + } +} + +module.exports = ScheduledJobs; diff --git a/api/middleware/schedule/taskQueue.js b/api/middleware/schedule/core/taskQueue.js similarity index 97% rename from api/middleware/schedule/taskQueue.js rename to api/middleware/schedule/core/taskQueue.js index 85f03b1..f45c1b9 100644 --- a/api/middleware/schedule/taskQueue.js +++ b/api/middleware/schedule/core/taskQueue.js @@ -1,14 +1,14 @@ const { v4: uuidv4 } = require('uuid'); const Sequelize = require('sequelize'); -const logs = require('../logProxy'); -const db = require('../dbProxy'); +const logs = require('../../logProxy'); +const db = require('../../dbProxy'); const command = require('./command'); -const PriorityQueue = require('./PriorityQueue'); -const ErrorHandler = require('./ErrorHandler'); +const PriorityQueue = require('../infrastructure/PriorityQueue'); +const ErrorHandler = require('../infrastructure/ErrorHandler'); const deviceManager = require('./deviceManager'); -const ScheduleUtils = require('./utils'); -const ScheduleConfig = require('./config'); -const deviceWorkStatusNotifier = require('./deviceWorkStatusNotifier'); +const ScheduleUtils = require('../utils/scheduleUtils'); +const ScheduleConfig = require('../infrastructure/config'); +const deviceWorkStatusNotifier = require('../notifiers/deviceWorkStatusNotifier'); /** * 任务队列管理器(重构版) @@ -222,7 +222,6 @@ class TaskQueue { // 移除 device_status 依赖,不再检查设备在线状态 // 如果需要在线状态检查,可以从 deviceManager 获取 - const deviceManager = require('./deviceManager'); const deviceStatus = deviceManager.getAllDevicesStatus(); const onlineSnCodes = new Set( Object.entries(deviceStatus) @@ -230,24 +229,7 @@ class TaskQueue { .map(([sn_code]) => sn_code) ); - // 原有代码已移除,改为使用 deviceManager - /* 原有代码已注释 - const device_status = db.getModel('device_status'); - const heartbeatTimeout = require('./config.js').monitoring.heartbeatTimeout; - const now = new Date(); - const heartbeatThreshold = new Date(now.getTime() - heartbeatTimeout); - - const onlineDevices = await device_status.findAll({ - where: { - isOnline: true, - lastHeartbeatTime: { - [Sequelize.Op.gte]: heartbeatThreshold // 心跳时间在阈值内 - } - }, - attributes: ['sn_code'] - }); - const onlineSnCodes = new Set(onlineDevices.map(dev => dev.sn_code)); - */ + let processedCount = 0; let queuedCount = 0; @@ -406,7 +388,7 @@ class TaskQueue { const authDays = accountData.authorization_days || 0; // 使用工具函数计算剩余天数 - const { calculateRemainingDays } = require('../../utils/account_utils'); + const { calculateRemainingDays } = require('../../../utils/account_utils'); const remaining_days = calculateRemainingDays(authDate, authDays); // 如果没有授权信息或剩余天数 <= 0,不允许创建任务 @@ -1065,13 +1047,13 @@ class TaskQueue { async getMqttClient() { try { // 首先尝试从调度系统获取已初始化的MQTT客户端 - const scheduleManager = require('./index'); + const scheduleManager = require('../index'); if (scheduleManager.mqttClient) { return scheduleManager.mqttClient; } // 如果调度系统没有初始化,则直接创建 - const mqttManager = require('../mqtt/mqttManager'); + const mqttManager = require('../../mqtt/mqttManager'); console.log('[任务队列] 创建新的MQTT客户端'); return await mqttManager.getInstance(); } catch (error) { diff --git a/api/middleware/schedule/handlers/activeHandler.js b/api/middleware/schedule/handlers/activeHandler.js new file mode 100644 index 0000000..8a6fd27 --- /dev/null +++ b/api/middleware/schedule/handlers/activeHandler.js @@ -0,0 +1,88 @@ +const BaseHandler = require('./baseHandler'); +const ConfigManager = require('../services/configManager'); +const command = require('../core/command'); +const config = require('../infrastructure/config'); + +/** + * 自动活跃处理器 + * 负责保持账户活跃度 + */ +class ActiveHandler extends BaseHandler { + /** + * 处理自动活跃任务 + * @param {object} task - 任务对象 + * @returns {Promise} 执行结果 + */ + async handle(task) { + return await this.execute(task, async () => { + return await this.doActive(task); + }, { + checkAuth: true, + checkOnline: true, + recordDeviceMetrics: true + }); + } + + /** + * 执行活跃逻辑 + */ + async doActive(task) { + const { sn_code, taskParams } = task; + const { platform = 'boss' } = taskParams; + + console.log(`[自动活跃] 开始 - 设备: ${sn_code}`); + + // 1. 获取账户配置 + const accountConfig = await this.getAccountConfig(sn_code, ['platform_type', 'active_strategy']); + + if (!accountConfig) { + return { + activeCount: 0, + message: '未找到账户配置' + }; + } + + // 2. 解析活跃策略配置 + const activeStrategy = ConfigManager.parseActiveStrategy(accountConfig.active_strategy); + + // 3. 检查活跃时间范围 + const timeRange = ConfigManager.getTimeRange(activeStrategy); + if (timeRange) { + const timeRangeValidator = require('../services/timeRangeValidator'); + const timeCheck = timeRangeValidator.checkTimeRange(timeRange); + + if (!timeCheck.allowed) { + return { + activeCount: 0, + message: timeCheck.reason + }; + } + } + + // 4. 创建活跃指令 + const actions = activeStrategy.actions || ['view_jobs']; + const activeCommands = actions.map(action => ({ + command_type: `active_${action}`, + command_name: `自动活跃 - ${action}`, + command_params: JSON.stringify({ + sn_code, + platform: platform || accountConfig.platform_type || 'boss', + action + }), + priority: config.getTaskPriority('auto_active') || 5 + })); + + // 5. 执行活跃指令 + const result = await command.executeCommands(task.id, activeCommands, this.mqttClient); + + console.log(`[自动活跃] 完成 - 设备: ${sn_code}, 执行动作: ${actions.join(', ')}`); + + return { + activeCount: actions.length, + actions, + message: '活跃完成' + }; + } +} + +module.exports = ActiveHandler; diff --git a/api/middleware/schedule/handlers/baseHandler.js b/api/middleware/schedule/handlers/baseHandler.js new file mode 100644 index 0000000..e159654 --- /dev/null +++ b/api/middleware/schedule/handlers/baseHandler.js @@ -0,0 +1,250 @@ +const deviceManager = require('../core/deviceManager'); +const accountValidator = require('../services/accountValidator'); +const db = require('../../dbProxy'); + +/** + * 任务处理器基类 + * 提供通用的授权检查、计时、错误处理、设备记录等功能 + */ +class BaseHandler { + constructor(mqttClient) { + this.mqttClient = mqttClient; + } + + /** + * 执行任务(带授权检查和错误处理) + * @param {object} task - 任务对象 + * @param {Function} businessLogic - 业务逻辑函数 + * @param {object} options - 选项 + * @returns {Promise} 执行结果 + */ + async execute(task, businessLogic, options = {}) { + const { + checkAuth = true, // 是否检查授权 + checkOnline = true, // 是否检查在线状态 + recordDeviceMetrics = true // 是否记录设备指标 + } = options; + + const { sn_code, taskName } = task; + const startTime = Date.now(); + + try { + // 1. 验证账户(启用 + 授权 + 在线) + if (checkAuth || checkOnline) { + const validation = await accountValidator.validate(sn_code, { + checkEnabled: true, + checkAuth, + checkOnline, + offlineThreshold: 3 * 60 * 1000 // 3分钟 + }); + + if (!validation.valid) { + throw new Error(`设备 ${sn_code} 验证失败: ${validation.reason}`); + } + } + + // 2. 记录任务开始 + if (recordDeviceMetrics) { + deviceManager.recordTaskStart(sn_code, task); + } + + // 3. 执行业务逻辑 + const result = await businessLogic(); + + // 4. 记录任务成功 + const duration = Date.now() - startTime; + if (recordDeviceMetrics) { + deviceManager.recordTaskComplete(sn_code, task, true, duration); + } + + return { + success: true, + duration, + ...result + }; + + } catch (error) { + // 5. 记录任务失败 + const duration = Date.now() - startTime; + if (recordDeviceMetrics) { + deviceManager.recordTaskComplete(sn_code, task, false, duration); + } + + console.error(`[${taskName}] 执行失败 (设备: ${sn_code}):`, error.message); + + return { + success: false, + error: error.message, + duration + }; + } + } + + /** + * 检查每日操作限制 + * @param {string} sn_code - 设备序列号 + * @param {string} operation - 操作类型 (search, deliver, chat) + * @param {string} platform - 平台类型 + * @returns {Promise<{allowed: boolean, count?: number, limit?: number, reason?: string}>} + */ + async checkDailyLimit(sn_code, operation, platform = 'boss') { + try { + const today = new Date().toISOString().split('T')[0]; + const task_status = db.getModel('task_status'); + + // 查询今日该操作的完成次数 + const count = await task_status.count({ + where: { + sn_code, + taskType: `auto_${operation}`, + status: 'completed', + endTime: { + [db.models.op.gte]: new Date(today) + } + } + }); + + // 获取每日限制(从 deviceManager 或配置) + const limit = deviceManager.canExecuteOperation(sn_code, operation); + + if (!limit.allowed) { + return { + allowed: false, + count, + reason: limit.reason + }; + } + + return { + allowed: true, + count, + limit: limit.max || 999 + }; + + } catch (error) { + console.error(`[每日限制检查] 失败 (${sn_code}, ${operation}):`, error); + return { allowed: true }; // 检查失败时默认允许 + } + } + + /** + * 检查执行间隔时间 + * @param {string} sn_code - 设备序列号 + * @param {string} taskType - 任务类型 + * @param {number} intervalMinutes - 间隔时间(分钟) + * @returns {Promise<{allowed: boolean, elapsed?: number, remaining?: number, reason?: string}>} + */ + async checkInterval(sn_code, taskType, intervalMinutes) { + try { + const task_status = db.getModel('task_status'); + + // 查询最近一次成功完成的任务 + const lastTask = await task_status.findOne({ + where: { + sn_code, + taskType, + status: 'completed' + }, + order: [['endTime', 'DESC']], + attributes: ['endTime'] + }); + + if (!lastTask || !lastTask.endTime) { + return { allowed: true, elapsed: null }; + } + + const now = Date.now(); + const lastTime = new Date(lastTask.endTime).getTime(); + const elapsed = now - lastTime; + const intervalMs = intervalMinutes * 60 * 1000; + + if (elapsed < intervalMs) { + const remainingMinutes = Math.ceil((intervalMs - elapsed) / (60 * 1000)); + const elapsedMinutes = Math.floor(elapsed / (60 * 1000)); + + return { + allowed: false, + elapsed: elapsedMinutes, + remaining: remainingMinutes, + reason: `距离上次执行仅 ${elapsedMinutes} 分钟,还需等待 ${remainingMinutes} 分钟` + }; + } + + return { + allowed: true, + elapsed: Math.floor(elapsed / (60 * 1000)) + }; + + } catch (error) { + console.error(`[间隔检查] 失败 (${sn_code}, ${taskType}):`, error); + return { allowed: true }; // 检查失败时默认允许 + } + } + + /** + * 获取账户配置 + * @param {string} sn_code - 设备序列号 + * @param {string[]} fields - 需要的字段 + * @returns {Promise} + */ + async getAccountConfig(sn_code, fields = ['*']) { + try { + const pla_account = db.getModel('pla_account'); + const account = await pla_account.findOne({ + where: { sn_code, is_delete: 0 }, + attributes: fields + }); + + return account ? account.toJSON() : null; + } catch (error) { + console.error(`[获取账户配置] 失败 (${sn_code}):`, error); + return null; + } + } + + /** + * 推送设备工作状态(可选的通知) + * @param {string} sn_code - 设备序列号 + * @param {object} status - 状态信息 + */ + async notifyDeviceStatus(sn_code, status) { + try { + const deviceWorkStatusNotifier = require('../notifiers/deviceWorkStatusNotifier'); + await deviceWorkStatusNotifier.sendDeviceWorkStatus(sn_code, status); + } catch (error) { + console.warn(`[状态推送] 失败 (${sn_code}):`, error.message); + } + } + + /** + * 标准化错误响应 + * @param {Error} error - 错误对象 + * @param {string} sn_code - 设备序列号 + * @returns {object} 标准化的错误响应 + */ + formatError(error, sn_code) { + return { + success: false, + error: error.message || '未知错误', + sn_code, + timestamp: new Date().toISOString() + }; + } + + /** + * 标准化成功响应 + * @param {object} data - 响应数据 + * @param {string} sn_code - 设备序列号 + * @returns {object} 标准化的成功响应 + */ + formatSuccess(data, sn_code) { + return { + success: true, + sn_code, + timestamp: new Date().toISOString(), + ...data + }; + } +} + +module.exports = BaseHandler; diff --git a/api/middleware/schedule/handlers/chatHandler.js b/api/middleware/schedule/handlers/chatHandler.js new file mode 100644 index 0000000..d727e09 --- /dev/null +++ b/api/middleware/schedule/handlers/chatHandler.js @@ -0,0 +1,89 @@ +const BaseHandler = require('./baseHandler'); +const ConfigManager = require('../services/configManager'); +const command = require('../core/command'); +const config = require('../infrastructure/config'); + +/** + * 自动沟通处理器 + * 负责自动回复HR消息 + */ +class ChatHandler extends BaseHandler { + /** + * 处理自动沟通任务 + * @param {object} task - 任务对象 + * @returns {Promise} 执行结果 + */ + async handle(task) { + return await this.execute(task, async () => { + return await this.doChat(task); + }, { + checkAuth: true, + checkOnline: true, + recordDeviceMetrics: true + }); + } + + /** + * 执行沟通逻辑 + */ + async doChat(task) { + const { sn_code, taskParams } = task; + const { platform = 'boss' } = taskParams; + + console.log(`[自动沟通] 开始 - 设备: ${sn_code}`); + + // 1. 获取账户配置 + const accountConfig = await this.getAccountConfig(sn_code, ['platform_type', 'chat_strategy']); + + if (!accountConfig) { + return { + chatCount: 0, + message: '未找到账户配置' + }; + } + + // 2. 解析沟通策略配置 + const chatStrategy = ConfigManager.parseChatStrategy(accountConfig.chat_strategy); + + // 3. 检查沟通时间范围 + const timeRange = ConfigManager.getTimeRange(chatStrategy); + if (timeRange) { + const timeRangeValidator = require('../services/timeRangeValidator'); + const timeCheck = timeRangeValidator.checkTimeRange(timeRange); + + if (!timeCheck.allowed) { + return { + chatCount: 0, + message: timeCheck.reason + }; + } + } + + // 4. 创建自动沟通 AI 指令(内部会先获取列表,再获取详情并自动回复) + const chatCommand = { + command_type: 'auto_chat_ai', + command_name: '自动沟通AI回复', + command_params: { + platform: platform || accountConfig.platform_type || 'boss', + pageCount: chatStrategy.page_count || 3 + }, + priority: config.getTaskPriority('auto_chat') || 6 + }; + + // 5. 执行指令(任务队列会保证该设备内串行执行,不并发下发指令) + const exec_result = await command.executeCommands(task.id, [chatCommand], this.mqttClient); + const first = exec_result && Array.isArray(exec_result.results) && exec_result.results[0] + ? exec_result.results[0].result || {} + : {}; + + console.log(`[自动沟通] 完成 - 设备: ${sn_code}`); + + return { + chatCount: first.replied_count || 0, + message: first.message || '自动沟通完成', + detail: first + }; + } +} + +module.exports = ChatHandler; diff --git a/api/middleware/schedule/handlers/deliverHandler.js b/api/middleware/schedule/handlers/deliverHandler.js new file mode 100644 index 0000000..96fbd03 --- /dev/null +++ b/api/middleware/schedule/handlers/deliverHandler.js @@ -0,0 +1,410 @@ +const BaseHandler = require('./baseHandler'); +const ConfigManager = require('../services/configManager'); +const jobFilterEngine = require('../services/jobFilterEngine'); +const command = require('../core/command'); +const config = require('../infrastructure/config'); +const db = require('../../dbProxy'); +const { jobFilterService } = require('../../job/services'); + +/** + * 自动投递处理器 + * 负责职位搜索、过滤、评分和自动投递 + */ +class DeliverHandler extends BaseHandler { + /** + * 处理自动投递任务 + * @param {object} task - 任务对象 + * @returns {Promise} 执行结果 + */ + async handle(task) { + return await this.execute(task, async () => { + return await this.doDeliver(task); + }, { + checkAuth: true, + checkOnline: true, + recordDeviceMetrics: true + }); + } + + /** + * 执行投递逻辑 + */ + async doDeliver(task) { + const { sn_code, taskParams } = task; + const { keyword, platform = 'boss', pageCount = 3, maxCount = 10, filterRules = {} } = taskParams; + + console.log(`[自动投递] 开始 - 设备: ${sn_code}, 关键词: ${keyword}`); + + // 1. 检查每日投递限制 + const dailyCheck = await this.checkDailyDeliverLimit(sn_code, platform); + if (!dailyCheck.allowed) { + return { + deliveredCount: 0, + message: dailyCheck.message + }; + } + + const actualMaxCount = dailyCheck.actualMaxCount; + + // 2. 检查并获取简历 + const resume = await this.getOrRefreshResume(sn_code, platform, task.id); + if (!resume) { + return { + deliveredCount: 0, + message: '未找到简历信息' + }; + } + + // 3. 获取账户配置 + const accountConfig = await this.getAccountConfig(sn_code, [ + 'keyword', 'platform_type', 'deliver_config', 'job_type_id', 'is_salary_priority' + ]); + + if (!accountConfig) { + return { + deliveredCount: 0, + message: '未找到账户配置' + }; + } + + // 4. 检查投递时间范围 + const deliverConfig = ConfigManager.parseDeliverConfig(accountConfig.deliver_config); + const timeRange = ConfigManager.getTimeRange(deliverConfig); + + if (timeRange) { + const timeRangeValidator = require('../services/timeRangeValidator'); + const timeCheck = timeRangeValidator.checkTimeRange(timeRange); + if (!timeCheck.allowed) { + return { + deliveredCount: 0, + message: timeCheck.reason + }; + } + } + + // 5. 获取职位类型配置 + const jobTypeConfig = await this.getJobTypeConfig(accountConfig.job_type_id); + + // 6. 搜索职位列表 + await this.searchJobs(sn_code, platform, keyword || accountConfig.keyword, pageCount, task.id); + + // 7. 从数据库获取待投递职位 + const pendingJobs = await this.getPendingJobs(sn_code, platform, actualMaxCount * 3); + + if (!pendingJobs || pendingJobs.length === 0) { + return { + deliveredCount: 0, + message: '没有待投递的职位' + }; + } + + // 8. 合并过滤配置 + const filterConfig = this.mergeFilterConfig(deliverConfig, filterRules, jobTypeConfig); + + // 9. 过滤已投递的公司 + const recentCompanies = await this.getRecentDeliveredCompanies(sn_code, 30); + + // 10. 过滤、评分、排序职位 + const filteredJobs = await this.filterAndScoreJobs( + pendingJobs, + resume, + accountConfig, + jobTypeConfig, + filterConfig, + recentCompanies + ); + + const jobsToDeliver = filteredJobs.slice(0, actualMaxCount); + + console.log(`[自动投递] 职位筛选完成 - 原始: ${pendingJobs.length}, 符合条件: ${filteredJobs.length}, 将投递: ${jobsToDeliver.length}`); + + if (jobsToDeliver.length === 0) { + return { + deliveredCount: 0, + message: '没有符合条件的职位' + }; + } + + // 11. 创建投递指令并执行 + const deliverCommands = this.createDeliverCommands(jobsToDeliver, sn_code, platform); + const result = await command.executeCommands(task.id, deliverCommands, this.mqttClient); + + console.log(`[自动投递] 完成 - 设备: ${sn_code}, 投递: ${deliverCommands.length} 个职位`); + + return { + deliveredCount: deliverCommands.length, + ...result + }; + } + + /** + * 检查每日投递限制 + */ + async checkDailyDeliverLimit(sn_code, platform) { + const apply_records = db.getModel('apply_records'); + const dailyLimit = config.getDailyLimit('apply', platform); + + const today = new Date(); + today.setHours(0, 0, 0, 0); + + const todayApplyCount = await apply_records.count({ + where: { + sn_code, + platform, + applyTime: { + [db.models.op.gte]: today + } + } + }); + + console.log(`[自动投递] 今日已投递: ${todayApplyCount}/${dailyLimit}`); + + if (todayApplyCount >= dailyLimit) { + return { + allowed: false, + message: `已达到每日投递上限(${dailyLimit}次)` + }; + } + + const remainingQuota = dailyLimit - todayApplyCount; + + return { + allowed: true, + actualMaxCount: remainingQuota, + todayCount: todayApplyCount, + limit: dailyLimit + }; + } + + /** + * 获取或刷新简历 + */ + async getOrRefreshResume(sn_code, platform, taskId) { + const resume_info = db.getModel('resume_info'); + const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000); + + let resume = await resume_info.findOne({ + where: { + sn_code, + platform, + isActive: true + }, + order: [['last_modify_time', 'DESC']] + }); + + const needRefresh = !resume || + !resume.last_modify_time || + new Date(resume.last_modify_time) < twoHoursAgo; + + if (needRefresh) { + console.log(`[自动投递] 简历超过2小时未更新,重新获取`); + + try { + await command.executeCommands(taskId, [{ + command_type: 'getOnlineResume', + command_name: '获取在线简历', + command_params: JSON.stringify({ sn_code, platform }), + priority: config.getTaskPriority('get_resume') || 5 + }], this.mqttClient); + + // 重新查询 + resume = await resume_info.findOne({ + where: { sn_code, platform, isActive: true }, + order: [['last_modify_time', 'DESC']] + }); + } catch (error) { + console.warn(`[自动投递] 获取在线简历失败:`, error.message); + } + } + + return resume ? resume.toJSON() : null; + } + + /** + * 获取职位类型配置 + */ + async getJobTypeConfig(jobTypeId) { + if (!jobTypeId) return null; + + try { + const job_types = db.getModel('job_types'); + const jobType = await job_types.findByPk(jobTypeId); + return jobType ? jobType.toJSON() : null; + } catch (error) { + console.error(`[自动投递] 获取职位类型配置失败:`, error); + return null; + } + } + + /** + * 搜索职位列表 + */ + async searchJobs(sn_code, platform, keyword, pageCount, taskId) { + const getJobListCommand = { + command_type: 'getJobList', + command_name: '获取职位列表', + command_params: JSON.stringify({ + sn_code, + keyword, + platform, + pageCount + }), + priority: config.getTaskPriority('search_jobs') || 5 + }; + + await command.executeCommands(taskId, [getJobListCommand], this.mqttClient); + } + + /** + * 获取待投递职位 + */ + async getPendingJobs(sn_code, platform, limit) { + const job_postings = db.getModel('job_postings'); + + const jobs = await job_postings.findAll({ + where: { + sn_code, + platform, + applyStatus: 'pending' + }, + order: [['create_time', 'DESC']], + limit + }); + + return jobs.map(job => job.toJSON ? job.toJSON() : job); + } + + /** + * 合并过滤配置 + */ + mergeFilterConfig(deliverConfig, filterRules, jobTypeConfig) { + // 排除关键词 + const jobTypeExclude = jobTypeConfig?.excludeKeywords + ? ConfigManager.parseConfig(jobTypeConfig.excludeKeywords, []) + : []; + + const deliverExclude = ConfigManager.getExcludeKeywords(deliverConfig); + const filterExclude = filterRules.excludeKeywords || []; + + // 过滤关键词 + const deliverFilter = ConfigManager.getFilterKeywords(deliverConfig); + const filterKeywords = filterRules.keywords || []; + + // 薪资范围 + const salaryRange = filterRules.minSalary || filterRules.maxSalary + ? { min: filterRules.minSalary || 0, max: filterRules.maxSalary || 0 } + : ConfigManager.getSalaryRange(deliverConfig); + + return { + exclude_keywords: [...jobTypeExclude, ...deliverExclude, ...filterExclude], + filter_keywords: filterKeywords.length > 0 ? filterKeywords : deliverFilter, + min_salary: salaryRange.min, + max_salary: salaryRange.max, + priority_weights: ConfigManager.getPriorityWeights(deliverConfig) + }; + } + + /** + * 获取近期已投递的公司 + */ + async getRecentDeliveredCompanies(sn_code, days = 30) { + const apply_records = db.getModel('apply_records'); + const daysAgo = new Date(); + daysAgo.setDate(daysAgo.getDate() - days); + + const recentApplies = await apply_records.findAll({ + where: { + sn_code, + applyTime: { + [db.models.op.gte]: daysAgo + } + }, + attributes: ['companyName'], + group: ['companyName'] + }); + + return new Set(recentApplies.map(apply => apply.companyName).filter(Boolean)); + } + + /** + * 过滤和评分职位 + */ + async filterAndScoreJobs(jobs, resume, accountConfig, jobTypeConfig, filterConfig, recentCompanies) { + const scored = []; + + for (const job of jobs) { + // 1. 过滤近期已投递的公司 + if (job.companyName && recentCompanies.has(job.companyName)) { + console.log(`[自动投递] 跳过已投递公司: ${job.companyName}`); + continue; + } + + // 2. 使用 jobFilterEngine 过滤和评分 + const filtered = await jobFilterEngine.filterJobs([job], filterConfig, resume); + if (filtered.length === 0) { + continue; // 不符合过滤条件 + } + + // 3. 使用原有的评分系统(job_filter_service)计算详细分数 + const scoreResult = jobFilterService.calculateJobScoreWithWeights( + job, + resume, + accountConfig, + jobTypeConfig, + accountConfig.is_salary_priority || [] + ); + + // 4. 计算关键词奖励 + const KeywordMatcher = require('../utils/keywordMatcher'); + const keywordBonus = KeywordMatcher.calculateBonus( + `${job.jobTitle} ${job.companyName} ${job.jobDescription || ''}`, + filterConfig.filter_keywords, + { baseScore: 5, maxBonus: 20 } + ); + + const finalScore = scoreResult.totalScore + keywordBonus.score; + + // 5. 只保留评分 >= 60 的职位 + if (finalScore >= 60) { + scored.push({ + ...job, + matchScore: finalScore, + scoreDetails: { + ...scoreResult.scores, + keywordBonus: keywordBonus.score + } + }); + } + } + + // 按评分降序排序 + scored.sort((a, b) => b.matchScore - a.matchScore); + + return scored; + } + + /** + * 创建投递指令 + */ + createDeliverCommands(jobs, sn_code, platform) { + return jobs.map(job => ({ + command_type: 'deliver_resume', + command_name: `投递简历 - ${job.jobTitle} @ ${job.companyName} (评分:${job.matchScore})`, + command_params: JSON.stringify({ + sn_code, + platform, + jobId: job.jobId, + encryptBossId: job.encryptBossId || '', + securityId: job.securityId || '', + brandName: job.companyName, + jobTitle: job.jobTitle, + companyName: job.companyName, + matchScore: job.matchScore, + scoreDetails: job.scoreDetails + }), + priority: config.getTaskPriority('apply') || 6 + })); + } +} + +module.exports = DeliverHandler; diff --git a/api/middleware/schedule/handlers/index.js b/api/middleware/schedule/handlers/index.js new file mode 100644 index 0000000..6d71570 --- /dev/null +++ b/api/middleware/schedule/handlers/index.js @@ -0,0 +1,18 @@ +/** + * 处理器模块导出 + * 统一导出所有任务处理器 + */ + +const BaseHandler = require('./baseHandler'); +const SearchHandler = require('./searchHandler'); +const DeliverHandler = require('./deliverHandler'); +const ChatHandler = require('./chatHandler'); +const ActiveHandler = require('./activeHandler'); + +module.exports = { + BaseHandler, + SearchHandler, + DeliverHandler, + ChatHandler, + ActiveHandler +}; diff --git a/api/middleware/schedule/handlers/searchHandler.js b/api/middleware/schedule/handlers/searchHandler.js new file mode 100644 index 0000000..739a91f --- /dev/null +++ b/api/middleware/schedule/handlers/searchHandler.js @@ -0,0 +1,87 @@ +const BaseHandler = require('./baseHandler'); +const ConfigManager = require('../services/configManager'); +const command = require('../core/command'); +const config = require('../infrastructure/config'); + +/** + * 自动搜索处理器 + * 负责搜索职位列表 + */ +class SearchHandler extends BaseHandler { + /** + * 处理自动搜索任务 + * @param {object} task - 任务对象 + * @returns {Promise} 执行结果 + */ + async handle(task) { + return await this.execute(task, async () => { + return await this.doSearch(task); + }, { + checkAuth: true, + checkOnline: true, + recordDeviceMetrics: true + }); + } + + /** + * 执行搜索逻辑 + */ + async doSearch(task) { + const { sn_code, taskParams } = task; + const { keyword, platform = 'boss', pageCount = 3 } = taskParams; + + console.log(`[自动搜索] 开始 - 设备: ${sn_code}, 关键词: ${keyword}`); + + // 1. 获取账户配置 + const accountConfig = await this.getAccountConfig(sn_code, ['keyword', 'platform_type', 'search_config']); + + if (!accountConfig) { + return { + jobsFound: 0, + message: '未找到账户配置' + }; + } + + // 2. 解析搜索配置 + const searchConfig = ConfigManager.parseSearchConfig(accountConfig.search_config); + + // 3. 检查搜索时间范围 + const timeRange = ConfigManager.getTimeRange(searchConfig); + if (timeRange) { + const timeRangeValidator = require('../services/timeRangeValidator'); + const timeCheck = timeRangeValidator.checkTimeRange(timeRange); + + if (!timeCheck.allowed) { + return { + jobsFound: 0, + message: timeCheck.reason + }; + } + } + + // 4. 创建搜索指令 + const searchCommand = { + command_type: 'getJobList', + command_name: `自动搜索职位 - ${keyword || accountConfig.keyword}`, + command_params: JSON.stringify({ + sn_code, + keyword: keyword || accountConfig.keyword || '', + platform: platform || accountConfig.platform_type || 'boss', + pageCount: pageCount || searchConfig.page_count || 3 + }), + priority: config.getTaskPriority('search_jobs') || 8 + }; + + // 5. 执行搜索指令 + const result = await command.executeCommands(task.id, [searchCommand], this.mqttClient); + + console.log(`[自动搜索] 完成 - 设备: ${sn_code}, 结果: ${JSON.stringify(result)}`); + + return { + jobsFound: result.jobCount || 0, + message: '搜索完成' + }; + } +} + +module.exports = SearchHandler; diff --git a/api/middleware/schedule/index.js b/api/middleware/schedule/index.js index 99eaae5..d0d3731 100644 --- a/api/middleware/schedule/index.js +++ b/api/middleware/schedule/index.js @@ -1,17 +1,23 @@ const mqttManager = require("../mqtt/mqttManager.js"); -// 导入调度模块(简化版) -const TaskQueue = require('./taskQueue.js'); -const Command = require('./command.js'); -const deviceManager = require('./deviceManager.js'); -const config = require('./config.js'); -const utils = require('./utils.js'); +// 导入核心模块 +const TaskQueue = require('./core/taskQueue.js'); +const Command = require('./core/command.js'); +const deviceManager = require('./core/deviceManager.js'); +const ScheduledJobs = require('./core/scheduledJobs.js'); -// 导入新的模块 +// 导入基础设施模块 +const config = require('./infrastructure/config.js'); +const utils = require('./utils/scheduleUtils.js'); + +// 导入任务处理器 const TaskHandlers = require('./taskHandlers.js'); + +// 导入MQTT模块 const MqttDispatcher = require('../mqtt/mqttDispatcher.js'); -const ScheduledJobs = require('./scheduledJobs.js'); -const DeviceWorkStatusNotifier = require('./deviceWorkStatusNotifier.js'); + +// 导入通知器 +const DeviceWorkStatusNotifier = require('./notifiers/deviceWorkStatusNotifier.js'); /** * 调度系统管理器 @@ -22,7 +28,7 @@ class ScheduleManager { this.mqttClient = null; this.isInitialized = false; this.startTime = new Date(); - + // 子模块 this.taskHandlers = null; this.mqttDispatcher = null; @@ -80,9 +86,9 @@ class ScheduleManager { async initComponents() { // 初始化设备管理器 await deviceManager.init(); - + // 初始化任务队列 - await TaskQueue.init?.(); + await TaskQueue.init(); } /** @@ -126,14 +132,7 @@ class ScheduleManager { }); } - /** - * 手动执行找工作流程(已废弃,full_flow 不再使用) - * @deprecated 请使用其他任务类型,如 auto_deliver - */ - async manualExecuteJobFlow(sn_code, keyword = '前端') { - console.warn(`[手动执行] manualExecuteJobFlow 已废弃,full_flow 不再使用`); - throw new Error('full_flow 任务类型已废弃,请使用其他任务类型'); - } + /** * 获取系统状态 @@ -178,28 +177,18 @@ class ScheduleManager { } } -// 创建调度管理器实例 +// 创建并导出调度管理器实例 const scheduleManager = new ScheduleManager(); -// 导出兼容的接口,保持与原有代码的一致性 +// 导出兼容接口(简化版) module.exports = { - // 初始化方法 init: () => scheduleManager.init(), - - // 手动执行任务 - manualExecuteJobFlow: (sn_code, keyword) => scheduleManager.manualExecuteJobFlow(sn_code, keyword), - - // 获取系统状态 getSystemStatus: () => scheduleManager.getSystemStatus(), - - // 停止系统 stop: () => scheduleManager.stop(), - // 访问各个组件(为了兼容性) + // 直接暴露属性(使用 getter 保持动态访问) get mqttClient() { return scheduleManager.mqttClient; }, get isInitialized() { return scheduleManager.isInitialized; }, - - // 访问各个组件实例(简化版) get taskQueue() { return TaskQueue; }, get command() { return Command; }, get deviceManager() { return deviceManager; } diff --git a/api/middleware/schedule/ErrorHandler.js b/api/middleware/schedule/infrastructure/ErrorHandler.js similarity index 98% rename from api/middleware/schedule/ErrorHandler.js rename to api/middleware/schedule/infrastructure/ErrorHandler.js index 7e13e63..8c1f1a1 100644 --- a/api/middleware/schedule/ErrorHandler.js +++ b/api/middleware/schedule/infrastructure/ErrorHandler.js @@ -1,4 +1,4 @@ -const db = require('../dbProxy'); +const db = require('../../dbProxy'); /** * 统一错误处理模块 diff --git a/api/middleware/schedule/PriorityQueue.js b/api/middleware/schedule/infrastructure/PriorityQueue.js similarity index 100% rename from api/middleware/schedule/PriorityQueue.js rename to api/middleware/schedule/infrastructure/PriorityQueue.js diff --git a/api/middleware/schedule/config.js b/api/middleware/schedule/infrastructure/config.js similarity index 80% rename from api/middleware/schedule/config.js rename to api/middleware/schedule/infrastructure/config.js index eef5a90..949c6ac 100644 --- a/api/middleware/schedule/config.js +++ b/api/middleware/schedule/infrastructure/config.js @@ -23,6 +23,7 @@ class ScheduleConfig { // 任务超时配置(毫秒) this.taskTimeouts = { + auto_search: 20 * 60 * 1000, // 自动搜索任务:20分钟 auto_deliver: 30 * 60 * 1000, // 自动投递任务:30分钟(包含多个子任务) auto_chat: 15 * 60 * 1000, // 自动沟通任务:15分钟 auto_active_account: 10 * 60 * 1000 // 自动活跃账号任务:10分钟 @@ -30,6 +31,7 @@ class ScheduleConfig { // 任务优先级配置 this.taskPriorities = { + auto_search: 8, // 自动搜索任务(最高优先级,先搜索后投递) auto_deliver: 7, // 自动投递任务 auto_chat: 6, // 自动沟通任务 auto_active_account: 5, // 自动活跃账号任务 @@ -44,10 +46,12 @@ class ScheduleConfig { // 定时任务配置 this.schedules = { - dailyReset: '0 0 * * *', // 每天凌晨重置统计 - monitoringInterval: '*/1 * * * *', // 监控检查间隔:1分钟 - autoDeliver: '0 */1 * * * *', // 自动投递任务:每1分钟执行一次 - autoChat: '0 */15 * * * *' // 自动沟通任务:每15分钟执行一次 + dailyReset: '0 0 * * *', // 每天凌晨重置统计 + monitoringInterval: '*/1 * * * *', // 监控检查间隔:1分钟 + autoSearch: '0 0 */1 * * *', // 自动搜索任务:每1小时执行一次 + autoDeliver: '0 */2 * * * *', // 自动投递任务:每2分钟执行一次 + autoChat: '0 */15 * * * *', // 自动沟通任务:每15分钟执行一次 + autoActive: '0 0 */2 * * *' // 自动活跃任务:每2小时执行一次 }; } diff --git a/api/middleware/schedule/infrastructure/index.js b/api/middleware/schedule/infrastructure/index.js new file mode 100644 index 0000000..f7056f0 --- /dev/null +++ b/api/middleware/schedule/infrastructure/index.js @@ -0,0 +1,14 @@ +/** + * Infrastructure 模块导出 + * 统一导出基础设施模块 + */ + +const PriorityQueue = require('./PriorityQueue'); +const ErrorHandler = require('./ErrorHandler'); +const config = require('./config'); + +module.exports = { + PriorityQueue, + ErrorHandler, + config +}; diff --git a/api/middleware/schedule/deviceWorkStatusNotifier.js b/api/middleware/schedule/notifiers/deviceWorkStatusNotifier.js similarity index 97% rename from api/middleware/schedule/deviceWorkStatusNotifier.js rename to api/middleware/schedule/notifiers/deviceWorkStatusNotifier.js index ffbbdf6..b0e332c 100644 --- a/api/middleware/schedule/deviceWorkStatusNotifier.js +++ b/api/middleware/schedule/notifiers/deviceWorkStatusNotifier.js @@ -3,7 +3,7 @@ * 负责向客户端推送设备当前工作状态(任务、指令等) */ -const db = require('../dbProxy'); +const db = require('../../dbProxy'); class DeviceWorkStatusNotifier { constructor() { @@ -214,11 +214,11 @@ class DeviceWorkStatusNotifier { return `投递职位: ${parsedParams.jobTitle} @ ${companyName}`; } else if (parsedParams.jobTitle) { return `投递职位: ${parsedParams.jobTitle}`; - } else if (commandType === 'applyJob' || commandName.includes('投递')) { + } else if (commandType === 'deliver_resume' || commandName.includes('投递')) { return '投递简历'; } else if (commandType === 'searchJobs' || commandName.includes('搜索')) { return `搜索职位: ${parsedParams.keyword || ''}`; - } else if (commandType === 'sendChatMessage' || commandName.includes('沟通')) { + } else if (commandType === 'send_chat_message' || commandType === 'sendChatMessage' || commandName.includes('沟通')) { return '发送消息'; } else if (commandName) { return commandName; diff --git a/api/middleware/schedule/notifiers/index.js b/api/middleware/schedule/notifiers/index.js new file mode 100644 index 0000000..c557312 --- /dev/null +++ b/api/middleware/schedule/notifiers/index.js @@ -0,0 +1,9 @@ +/** + * Notifiers 模块导出 + */ + +const deviceWorkStatusNotifier = require('./deviceWorkStatusNotifier'); + +module.exports = { + deviceWorkStatusNotifier +}; diff --git a/api/middleware/schedule/scheduledJobs.js b/api/middleware/schedule/scheduledJobs.js deleted file mode 100644 index 08c2a79..0000000 --- a/api/middleware/schedule/scheduledJobs.js +++ /dev/null @@ -1,779 +0,0 @@ -const node_schedule = require("node-schedule"); -const dayjs = require('dayjs'); -const config = require('./config.js'); -const deviceManager = require('./deviceManager.js'); -const command = require('./command.js'); -const db = require('../dbProxy'); -const authorizationService = require('../../services/authorization_service.js'); - -const Framework = require("../../../framework/node-core-framework.js"); -/** - * 检查当前时间是否在指定的时间范围内 - * @param {Object} timeRange - 时间范围配置 {start_time: '09:00', end_time: '18:00', workdays_only: 1} - * @returns {Object} {allowed: boolean, reason: string} - */ -function checkTimeRange(timeRange) { - if (!timeRange || !timeRange.start_time || !timeRange.end_time) { - return { allowed: true, reason: '未配置时间范围' }; - } - - const now = new Date(); - const currentHour = now.getHours(); - const currentMinute = now.getMinutes(); - const currentTime = currentHour * 60 + currentMinute; // 转换为分钟数 - - // 解析开始时间和结束时间 - const [startHour, startMinute] = timeRange.start_time.split(':').map(Number); - const [endHour, endMinute] = timeRange.end_time.split(':').map(Number); - const startTime = startHour * 60 + startMinute; - const endTime = endHour * 60 + endMinute; - - // 检查是否仅工作日(使用宽松比较,兼容字符串和数字) - if (timeRange.workdays_only == 1) { // 使用 == 而不是 === - const dayOfWeek = now.getDay(); // 0=周日, 1=周一, ..., 6=周六 - if (dayOfWeek === 0 || dayOfWeek === 6) { - return { allowed: false, reason: '当前是周末,不在允许的时间范围内' }; - } - } - - // 检查当前时间是否在时间范围内 - if (startTime <= endTime) { - // 正常情况:09:00 - 18:00 - if (currentTime < startTime || currentTime >= endTime) { - return { allowed: false, reason: `当前时间 ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')} 不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` }; - } - } else { - // 跨天情况:22:00 - 06:00 - if (currentTime < startTime && currentTime >= endTime) { - return { allowed: false, reason: `当前时间 ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')} 不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` }; - } - } - - return { allowed: true, reason: '在允许的时间范围内' }; -} -/** - * 定时任务管理器(简化版) - * 管理所有定时任务的创建和销毁 - */ -class ScheduledJobs { - constructor(components, taskHandlers) { - this.taskQueue = components.taskQueue; - this.taskHandlers = taskHandlers; - this.jobs = []; - } - - /** - * 启动所有定时任务 - */ - start() { - // 每天凌晨重置统计数据 - const resetJob = node_schedule.scheduleJob(config.schedules.dailyReset, () => { - this.resetDailyStats(); - }); - this.jobs.push(resetJob); - - // 启动心跳检查定时任务(每分钟检查一次) - const monitoringJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => { - await deviceManager.checkHeartbeatStatus().catch(error => { - console.error('[定时任务] 检查心跳状态失败:', error); - }); - }); - - this.jobs.push(monitoringJob); - - // 启动离线设备任务清理定时任务(每分钟检查一次) - const cleanupOfflineTasksJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => { - await this.cleanupOfflineDeviceTasks().catch(error => { - console.error('[定时任务] 清理离线设备任务失败:', error); - }); - }); - - this.jobs.push(cleanupOfflineTasksJob); - console.log('[定时任务] 已启动离线设备任务清理任务'); - - // 启动任务超时检查定时任务(每分钟检查一次) - const timeoutCheckJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => { - await this.checkTaskTimeouts().catch(error => { - console.error('[定时任务] 检查任务超时失败:', error); - }); - }); - - this.jobs.push(timeoutCheckJob); - console.log('[定时任务] 已启动任务超时检查任务'); - - // 启动任务状态摘要同步定时任务(每10秒发送一次) - const taskSummaryJob = node_schedule.scheduleJob('*/10 * * * * *', async () => { - await this.syncTaskStatusSummary().catch(error => { - console.error('[定时任务] 同步任务状态摘要失败:', error); - }); - }); - - this.jobs.push(taskSummaryJob); - console.log('[定时任务] 已启动任务状态摘要同步任务'); - - - // 执行自动投递任务 - const autoDeliverJob = node_schedule.scheduleJob(config.schedules.autoDeliver, () => { - this.autoDeliverTask(); - }); - - // 立即执行一次自动投递任务 - this.autoDeliverTask(); - - this.jobs.push(autoDeliverJob); - console.log('[定时任务] 已启动自动投递任务'); - - // 执行自动沟通任务 - const autoChatJob = node_schedule.scheduleJob(config.schedules.autoChat || '0 */15 * * * *', () => { - this.autoChatTask(); - }); - - // 立即执行一次自动沟通任务 - this.autoChatTask(); - - this.jobs.push(autoChatJob); - console.log('[定时任务] 已启动自动沟通任务'); - - } - - - - /** - * 重置每日统计 - */ - resetDailyStats() { - console.log('[定时任务] 重置每日统计数据'); - - try { - deviceManager.resetAllDailyCounters(); - console.log('[定时任务] 每日统计重置完成'); - } catch (error) { - console.error('[定时任务] 重置统计失败:', error); - } - } - - /** - * 清理过期数据 - */ - cleanupCaches() { - console.log('[定时任务] 开始清理过期数据'); - - try { - deviceManager.cleanupOfflineDevices(config.monitoring.offlineThreshold); - command.cleanupExpiredCommands(30); - console.log('[定时任务] 数据清理完成'); - } catch (error) { - console.error('[定时任务] 数据清理失败:', error); - } - } - - /** - * 清理离线设备任务 - * 检查离线超过10分钟的设备,取消其所有pending/running状态的任务 - */ - async cleanupOfflineDeviceTasks() { - try { - // 离线阈值:10分钟 - const offlineThreshold = 10 * 60 * 1000; // 10分钟 - const now = Date.now(); - const thresholdTime = now - offlineThreshold; - - // 获取所有启用的账号 - const pla_account = db.getModel('pla_account'); - const accounts = await pla_account.findAll({ - where: { - is_delete: 0, - is_enabled: 1 - }, - attributes: ['sn_code'] - }); - - if (!accounts || accounts.length === 0) { - return; - } - - // 通过 deviceManager 检查哪些设备离线超过10分钟 - const offlineSnCodes = []; - const offlineDevicesInfo = []; - - for (const account of accounts) { - const sn_code = account.sn_code; - const device = deviceManager.devices.get(sn_code); - - if (!device) { - // 设备从未发送过心跳,视为离线 - offlineSnCodes.push(sn_code); - offlineDevicesInfo.push({ - sn_code: sn_code, - lastHeartbeatTime: null - }); - } else { - // 检查最后心跳时间 - const lastHeartbeat = device.lastHeartbeat || 0; - if (lastHeartbeat < thresholdTime || !device.isOnline) { - offlineSnCodes.push(sn_code); - offlineDevicesInfo.push({ - sn_code: sn_code, - lastHeartbeatTime: lastHeartbeat ? new Date(lastHeartbeat) : null - }); - } - } - } - - if (offlineSnCodes.length === 0) { - return; - } - - console.log(`[清理离线任务] 发现 ${offlineSnCodes.length} 个离线超过10分钟的设备: ${offlineSnCodes.join(', ')}`); - - let totalCancelled = 0; - - // 为每个离线设备取消任务 - const task_status = db.getModel('task_status'); - for (const sn_code of offlineSnCodes) { - try { - // 查询该设备的所有pending/running任务 - const pendingTasks = await task_status.findAll({ - where: { - sn_code: sn_code, - status: ['pending', 'running'] - }, - attributes: ['id'] - }); - - if (pendingTasks.length === 0) { - continue; - } - - const deviceInfo = offlineDevicesInfo.find(d => d.sn_code === sn_code); - - // 更新任务状态为cancelled - const updateResult = await task_status.update( - { - status: 'cancelled', - endTime: new Date(), - result: JSON.stringify({ - reason: '设备离线超过10分钟,任务已自动取消', - offlineTime: deviceInfo?.lastHeartbeatTime - }) - }, - { - where: { - sn_code: sn_code, - status: ['pending', 'running'] - } - } - ); - - const cancelledCount = Array.isArray(updateResult) ? updateResult[0] : updateResult; - totalCancelled += cancelledCount; - - // 从内存队列中移除任务 - if (this.taskQueue && typeof this.taskQueue.cancelDeviceTasks === 'function') { - await this.taskQueue.cancelDeviceTasks(sn_code); - } - - console.log(`[清理离线任务] 设备 ${sn_code} 已取消 ${cancelledCount} 个任务`); - } catch (error) { - console.error(`[清理离线任务] 取消设备 ${sn_code} 的任务失败:`, error); - } - } - - if (totalCancelled > 0) { - console.log(`[清理离线任务] 共取消 ${totalCancelled} 个离线设备的任务`); - } - } catch (error) { - console.error('[清理离线任务] 执行失败:', error); - } - } - - /** - * 同步任务状态摘要到客户端 - * 定期向所有在线设备发送任务状态摘要(当前任务、待执行任务、下次执行时间等) - */ - async syncTaskStatusSummary() { - try { - const { pla_account } = await Framework.getModels(); - - // 获取所有启用的账号 - const accounts = await pla_account.findAll({ - where: { - is_delete: 0, - is_enabled: 1 - }, - attributes: ['sn_code'] - }); - - if (!accounts || accounts.length === 0) { - return; - } - - // 离线阈值:3分钟 - const offlineThreshold = 3 * 60 * 1000; // 3分钟 - const now = Date.now(); - - // 为每个在线设备发送任务状态摘要 - for (const account of accounts) { - const sn_code = account.sn_code; - - // 检查设备是否在线 - const device = deviceManager.devices.get(sn_code); - - if (!device) { - // 设备从未发送过心跳,视为离线,跳过 - continue; - } - - // 检查最后心跳时间 - const lastHeartbeat = device.lastHeartbeat || 0; - const isOnline = device.isOnline && (now - lastHeartbeat < offlineThreshold); - - if (!isOnline) { - // 设备离线,跳过 - continue; - } - - // 设备在线,推送设备工作状态 - try { - const deviceWorkStatusNotifier = require('./deviceWorkStatusNotifier'); - const summary = await this.taskQueue.getTaskStatusSummary(sn_code); - await deviceWorkStatusNotifier.sendDeviceWorkStatus(sn_code, summary, { - currentCommand: summary.currentCommand || null - }); - } catch (error) { - console.error(`[设备工作状态同步] 设备 ${sn_code} 同步失败:`, error.message); - } - } - } catch (error) { - console.error('[任务状态同步] 执行失败:', error); - } - } - - /** - * 检查任务超时并强制标记为失败 - * 检测长时间运行的任务(可能是卡住的),强制标记为失败,释放资源 - */ - async checkTaskTimeouts() { - try { - const Sequelize = require('sequelize'); - const { task_status, op } = db.models; - - // 查询所有运行中的任务 - const runningTasks = await task_status.findAll({ - where: { - status: 'running' - }, - attributes: ['id', 'sn_code', 'taskType', 'taskName', 'startTime', 'create_time'] - }); - - if (!runningTasks || runningTasks.length === 0) { - return; - } - - const now = new Date(); - let timeoutCount = 0; - - for (const task of runningTasks) { - const taskData = task.toJSON(); - const startTime = taskData.startTime ? new Date(taskData.startTime) : (taskData.create_time ? new Date(taskData.create_time) : null); - - if (!startTime) { - continue; - } - - // 获取任务类型的超时时间(默认10分钟) - const taskTimeout = config.getTaskTimeout(taskData.taskType) || 10 * 60 * 1000; - // 允许额外20%的缓冲时间 - const maxAllowedTime = taskTimeout * 1.2; - const elapsedTime = now.getTime() - startTime.getTime(); - - // 如果任务运行时间超过最大允许时间,标记为超时失败 - if (elapsedTime > maxAllowedTime) { - try { - await task_status.update( - { - status: 'failed', - endTime: now, - duration: elapsedTime, - result: JSON.stringify({ - error: `任务执行超时(运行时间: ${Math.round(elapsedTime / 1000)}秒,超时限制: ${Math.round(maxAllowedTime / 1000)}秒)`, - timeout: true, - taskType: taskData.taskType, - startTime: startTime.toISOString() - }), - progress: 0 - }, - { - where: { id: taskData.id } - } - ); - - timeoutCount++; - console.warn(`[任务超时检查] 任务 ${taskData.id} (${taskData.taskName}) 运行时间过长,已强制标记为失败`, { - task_id: taskData.id, - sn_code: taskData.sn_code, - taskType: taskData.taskType, - elapsedTime: Math.round(elapsedTime / 1000) + '秒', - maxAllowedTime: Math.round(maxAllowedTime / 1000) + '秒' - }); - - // 如果任务队列中有这个任务,也需要从内存中清理 - if (this.taskQueue && typeof this.taskQueue.deviceStatus !== 'undefined') { - const deviceStatus = this.taskQueue.deviceStatus.get(taskData.sn_code); - if (deviceStatus && deviceStatus.currentTask && deviceStatus.currentTask.id === taskData.id) { - // 重置设备状态,允许继续执行下一个任务 - deviceStatus.isRunning = false; - deviceStatus.currentTask = null; - deviceStatus.runningCount = Math.max(0, deviceStatus.runningCount - 1); - this.taskQueue.globalRunningCount = Math.max(0, this.taskQueue.globalRunningCount - 1); - - console.log(`[任务超时检查] 已重置设备 ${taskData.sn_code} 的状态,可以继续执行下一个任务`); - - // 尝试继续处理该设备的队列 - setTimeout(() => { - this.taskQueue.processQueue(taskData.sn_code).catch(error => { - console.error(`[任务超时检查] 继续处理队列失败 (设备: ${taskData.sn_code}):`, error); - }); - }, 100); - } - } - } catch (error) { - console.error(`[任务超时检查] 更新超时任务状态失败 (任务ID: ${taskData.id}):`, error); - } - } - } - - if (timeoutCount > 0) { - console.log(`[任务超时检查] 共检测到 ${timeoutCount} 个超时任务,已强制标记为失败`); - } - } catch (error) { - console.error('[任务超时检查] 执行失败:', error); - } - } - - /** - * 自动投递任务 - */ - async autoDeliverTask() { - const now = new Date(); - console.log(`[自动投递] ${now.toLocaleString()} 开始执行自动投递任务`); - - - - try { - // 移除 device_status 依赖,改为直接从 pla_account 查询启用且开启自动投递的账号 - const models = db.models; - const { pla_account, op } = models; - - // 直接从 pla_account 查询启用且开启自动投递的账号 - // 注意:不再检查在线状态,因为 device_status 已移除 - const pla_users = await pla_account.findAll({ - where: { - is_delete: 0, - is_enabled: 1, // 只获取启用的账号 - auto_deliver: 1 - } - }); - - - - if (!pla_users || pla_users.length === 0) { - console.log('[自动投递] 没有启用且开启自动投递的账号'); - return; - } - - console.log(`[自动投递] 找到 ${pla_users.length} 个可用账号`); - - // 获取 task_status 模型用于查询上次投递时间 - const { task_status } = models; - - // 为每个设备添加自动投递任务到队列 - for (const pl_user of pla_users) { - const userData = pl_user.toJSON(); - - // 检查设备是否在线(离线阈值:3分钟) - const offlineThreshold = 3 * 60 * 1000; // 3分钟 - const now = Date.now(); - const device = deviceManager.devices.get(userData.sn_code); - - - // 检查用户授权天数 是否够 - const authorization = await authorizationService.checkAuthorization(userData.sn_code); - if (!authorization.is_authorized) { - console.log(`[自动投递] 设备 ${userData.sn_code} 授权天数不足,跳过添加任务`); - continue; - } - - - if (!device) { - // 设备从未发送过心跳,视为离线 - console.log(`[自动投递] 设备 ${userData.sn_code} 离线(从未发送心跳),跳过添加任务`); - continue; - } - - - - - // 检查最后心跳时间 - const lastHeartbeat = device.lastHeartbeat || 0; - const isOnline = device.isOnline && (now - lastHeartbeat < offlineThreshold); - - if (!isOnline) { - const offlineMinutes = lastHeartbeat ? Math.round((now - lastHeartbeat) / (60 * 1000)) : '未知'; - console.log(`[自动投递] 设备 ${userData.sn_code} 离线(最后心跳: ${offlineMinutes}分钟前),跳过添加任务`); - continue; - } - - // 检查设备调度策略 - const canExecute = deviceManager.canExecuteOperation(userData.sn_code, 'deliver'); - if (!canExecute.allowed) { - console.log(`[自动投递] 设备 ${userData.sn_code} 不满足执行条件: ${canExecute.reason}`); - continue; - } - - // 获取投递配置,如果不存在则使用默认值 - let deliver_config = userData.deliver_config; - if (typeof deliver_config === 'string') { - try { - deliver_config = JSON.parse(deliver_config); - } catch (e) { - deliver_config = {}; - } - } - deliver_config = deliver_config || { - deliver_interval: 30, - min_salary: 0, - max_salary: 0, - page_count: 3, - max_deliver: 10, - filter_keywords: [], - exclude_keywords: [] - }; - - // 检查投递时间范围 - if (deliver_config.time_range) { - const timeCheck = checkTimeRange(deliver_config.time_range); - if (!timeCheck.allowed) { - console.log(`[自动投递] 设备 ${userData.sn_code} ${timeCheck.reason}`); - continue; - } - } - - // 检查投递间隔时间 - const deliver_interval = deliver_config.deliver_interval || 30; // 默认30分钟 - const interval_ms = deliver_interval * 60 * 1000; // 转换为毫秒 - - // 查询该账号最近一次成功完成的自动投递任务 - const lastDeliverTask = await task_status.findOne({ - where: { - sn_code: userData.sn_code, - taskType: 'auto_deliver', - status: 'completed' - }, - order: [['endTime', 'DESC']], - attributes: ['endTime'] - }); - - // 如果存在上次投递记录,检查是否已经过了间隔时间 - if (lastDeliverTask && lastDeliverTask.endTime) { - const lastDeliverTime = new Date(lastDeliverTask.endTime); - - const elapsedTime = new Date().getTime() - lastDeliverTime.getTime(); - - if (elapsedTime < interval_ms) { - const remainingMinutes = Math.ceil((interval_ms - elapsedTime) / (60 * 1000)); - const elapsedMinutes = Math.round(elapsedTime / (60 * 1000)); - const message = `距离上次投递仅 ${elapsedMinutes} 分钟,还需等待 ${remainingMinutes} 分钟(间隔: ${deliver_interval} 分钟)`; - console.log(`[自动投递] 设备 ${userData.sn_code} ${message}`); - - // 推送等待状态到客户端 - try { - const deviceWorkStatusNotifier = require('./deviceWorkStatusNotifier'); - - // 获取当前任务状态摘要 - const taskStatusSummary = this.taskQueue ? this.taskQueue.getTaskStatusSummary(userData.sn_code) : { - sn_code: userData.sn_code, - pendingCount: 0, - totalPendingCount: 0, - pendingTasks: [] - }; - - // 添加等待消息到工作状态 - await deviceWorkStatusNotifier.sendDeviceWorkStatus(userData.sn_code, taskStatusSummary, { - waitingMessage: { - type: 'deliver_interval', - message: message, - remainingMinutes: remainingMinutes, - nextDeliverTime: new Date(lastDeliverTime.getTime() + interval_ms).toISOString() - } - }); - } catch (pushError) { - console.warn(`[自动投递] 推送等待消息失败:`, pushError.message); - } - - continue; - } - } - - // 添加自动投递任务到队列 - await this.taskQueue.addTask(userData.sn_code, { - taskType: 'auto_deliver', - taskName: `自动投递 - ${userData.keyword || ''}`, - taskParams: { - keyword: userData.keyword || '', - platform: userData.platform_type || 'boss', - pageCount: deliver_config.page_count || 3, - maxCount: deliver_config.max_deliver || 10, - filterRules: { - minSalary: deliver_config.min_salary || 0, - maxSalary: deliver_config.max_salary || 0, - keywords: deliver_config.filter_keywords || [], - excludeKeywords: deliver_config.exclude_keywords || [] - } - }, - priority: config.getTaskPriority('auto_deliver') || 6 - }); - - console.log(`[自动投递] 已为设备 ${userData.sn_code} 添加自动投递任务,关键词: ${userData.keyword || '默认'},投递间隔: ${deliver_interval} 分钟`); - } - - console.log('[自动投递] 任务添加完成'); - - } catch (error) { - console.error('[自动投递] 执行失败:', error); - } - } - - /** - * 自动沟通任务 - */ - async autoChatTask() { - const now = new Date(); - console.log(`[自动沟通] ${now.toLocaleString()} 开始执行自动沟通任务`); - - - - try { - // 移除 device_status 依赖,改为直接从 pla_account 查询启用且开启自动沟通的账号 - const models = db.models; - const { pla_account, op } = models; - - // 直接从 pla_account 查询启用且开启自动沟通的账号 - // 注意:不再检查在线状态,因为 device_status 已移除 - const pla_users = await pla_account.findAll({ - where: { - is_delete: 0, - is_enabled: 1, // 只获取启用的账号 - auto_chat: 1 - } - }); - - if (!pla_users || pla_users.length === 0) { - console.log('[自动沟通] 没有启用且开启自动沟通的账号'); - return; - } - - console.log(`[自动沟通] 找到 ${pla_users.length} 个可用账号`); - - // 获取 task_status 模型用于查询上次沟通时间 - const { task_status } = models; - - // 为每个设备添加自动沟通任务到队列 - for (const pl_user of pla_users) { - const userData = pl_user.toJSON(); - - // 检查设备是否在线(离线阈值:3分钟) - const offlineThreshold = 3 * 60 * 1000; // 3分钟 - const now = Date.now(); - const device = deviceManager.devices.get(userData.sn_code); - - if (!device) { - // 设备从未发送过心跳,视为离线 - console.log(`[自动沟通] 设备 ${userData.sn_code} 离线(从未发送心跳),跳过添加任务`); - continue; - } - - // 检查最后心跳时间 - const lastHeartbeat = device.lastHeartbeat || 0; - const isOnline = device.isOnline && (now - lastHeartbeat < offlineThreshold); - - if (!isOnline) { - const offlineMinutes = lastHeartbeat ? Math.round((now - lastHeartbeat) / (60 * 1000)) : '未知'; - console.log(`[自动沟通] 设备 ${userData.sn_code} 离线(最后心跳: ${offlineMinutes}分钟前),跳过添加任务`); - continue; - } - - // 检查设备调度策略 - const canExecute = deviceManager.canExecuteOperation(userData.sn_code, 'chat'); - if (!canExecute.allowed) { - console.log(`[自动沟通] 设备 ${userData.sn_code} 不满足执行条件: ${canExecute.reason}`); - continue; - } - - // 获取沟通策略配置 - let chatStrategy = {}; - if (userData.chat_strategy) { - chatStrategy = typeof userData.chat_strategy === 'string' - ? JSON.parse(userData.chat_strategy) - : userData.chat_strategy; - } - - // 检查沟通时间范围 - if (chatStrategy.time_range) { - const timeCheck = checkTimeRange(chatStrategy.time_range); - if (!timeCheck.allowed) { - console.log(`[自动沟通] 设备 ${userData.sn_code} ${timeCheck.reason}`); - continue; - } - } - - // 检查沟通间隔时间 - const chat_interval = chatStrategy.chat_interval || 30; // 默认30分钟 - const interval_ms = chat_interval * 60 * 1000; // 转换为毫秒 - - // 查询该账号最近一次成功完成的自动沟通任务 - const lastChatTask = await task_status.findOne({ - where: { - sn_code: userData.sn_code, - taskType: 'auto_chat', - status: 'completed' - }, - order: [['endTime', 'DESC']], - attributes: ['endTime'] - }); - - // 如果存在上次沟通记录,检查是否已经过了间隔时间 - if (lastChatTask && lastChatTask.endTime) { - const lastChatTime = new Date(lastChatTask.endTime); - const elapsedTime = now.getTime() - lastChatTime.getTime(); - - if (elapsedTime < interval_ms) { - const remainingMinutes = Math.ceil((interval_ms - elapsedTime) / (60 * 1000)); - console.log(`[自动沟通] 设备 ${userData.sn_code} 距离上次沟通仅 ${Math.round(elapsedTime / (60 * 1000))} 分钟,还需等待 ${remainingMinutes} 分钟(间隔: ${chat_interval} 分钟)`); - continue; - } - } - - // 添加自动沟通任务到队列 - await this.taskQueue.addTask(userData.sn_code, { - taskType: 'auto_chat', - taskName: `自动沟通 - ${userData.name || '默认'}`, - taskParams: { - platform: userData.platform_type || 'boss' - }, - priority: config.getTaskPriority('auto_chat') || 6 - }); - - console.log(`[自动沟通] 已为设备 ${userData.sn_code} 添加自动沟通任务,沟通间隔: ${chat_interval} 分钟`); - } - - console.log('[自动沟通] 任务添加完成'); - - } catch (error) { - console.error('[自动沟通] 执行失败:', error); - } - } -} - -module.exports = ScheduledJobs; - diff --git a/api/middleware/schedule/services/accountValidator.js b/api/middleware/schedule/services/accountValidator.js new file mode 100644 index 0000000..3972972 --- /dev/null +++ b/api/middleware/schedule/services/accountValidator.js @@ -0,0 +1,199 @@ +const db = require('../../dbProxy'); +const authorizationService = require('../../../services/authorization_service'); +const deviceManager = require('../core/deviceManager'); + +/** + * 账户验证服务 + * 统一处理账户启用状态、授权状态、在线状态的检查 + */ +class AccountValidator { + /** + * 检查账户是否启用 + * @param {string} sn_code - 设备序列号 + * @returns {Promise<{enabled: boolean, reason?: string}>} + */ + async checkEnabled(sn_code) { + try { + const pla_account = db.getModel('pla_account'); + const account = await pla_account.findOne({ + where: { sn_code, is_delete: 0 }, + attributes: ['is_enabled', 'name'] + }); + + if (!account) { + return { enabled: false, reason: '账户不存在' }; + } + + if (!account.is_enabled) { + return { enabled: false, reason: '账户未启用' }; + } + + return { enabled: true }; + } catch (error) { + console.error(`[账户验证] 检查启用状态失败 (${sn_code}):`, error); + return { enabled: false, reason: '检查失败' }; + } + } + + /** + * 检查账户授权状态 + * @param {string} sn_code - 设备序列号 + * @returns {Promise<{authorized: boolean, days?: number, reason?: string}>} + */ + async checkAuthorization(sn_code) { + try { + const result = await authorizationService.checkAuthorization(sn_code); + + if (!result.is_authorized) { + return { + authorized: false, + days: result.days_remaining || 0, + reason: result.message || '授权已过期' + }; + } + + return { + authorized: true, + days: result.days_remaining + }; + } catch (error) { + console.error(`[账户验证] 检查授权状态失败 (${sn_code}):`, error); + return { authorized: false, reason: '授权检查失败' }; + } + } + + /** + * 检查设备是否在线 + * @param {string} sn_code - 设备序列号 + * @param {number} offlineThreshold - 离线阈值(毫秒) + * @returns {{online: boolean, lastHeartbeat?: number, reason?: string}} + */ + checkOnline(sn_code, offlineThreshold = 3 * 60 * 1000) { + const device = deviceManager.devices.get(sn_code); + + if (!device) { + return { online: false, reason: '设备从未发送心跳' }; + } + + const now = Date.now(); + const lastHeartbeat = device.lastHeartbeat || 0; + const elapsed = now - lastHeartbeat; + + if (elapsed > offlineThreshold) { + const minutes = Math.round(elapsed / (60 * 1000)); + return { + online: false, + lastHeartbeat, + reason: `设备离线(最后心跳: ${minutes}分钟前)` + }; + } + + if (!device.isOnline) { + return { online: false, lastHeartbeat, reason: '设备标记为离线' }; + } + + return { online: true, lastHeartbeat }; + } + + /** + * 综合验证(启用 + 授权 + 在线) + * @param {string} sn_code - 设备序列号 + * @param {object} options - 验证选项 + * @param {boolean} options.checkEnabled - 是否检查启用状态(默认 true) + * @param {boolean} options.checkAuth - 是否检查授权(默认 true) + * @param {boolean} options.checkOnline - 是否检查在线(默认 true) + * @param {number} options.offlineThreshold - 离线阈值(默认 3分钟) + * @returns {Promise<{valid: boolean, reason?: string, details?: object}>} + */ + async validate(sn_code, options = {}) { + const { + checkEnabled = true, + checkAuth = true, + checkOnline = true, + offlineThreshold = 3 * 60 * 1000 + } = options; + + const details = {}; + + // 检查启用状态 + if (checkEnabled) { + const enabledResult = await this.checkEnabled(sn_code); + details.enabled = enabledResult; + + if (!enabledResult.enabled) { + return { + valid: false, + reason: enabledResult.reason, + details + }; + } + } + + // 检查授权状态 + if (checkAuth) { + const authResult = await this.checkAuthorization(sn_code); + details.authorization = authResult; + + if (!authResult.authorized) { + return { + valid: false, + reason: authResult.reason, + details + }; + } + } + + // 检查在线状态 + if (checkOnline) { + const onlineResult = this.checkOnline(sn_code, offlineThreshold); + details.online = onlineResult; + + if (!onlineResult.online) { + return { + valid: false, + reason: onlineResult.reason, + details + }; + } + } + + return { valid: true, details }; + } + + /** + * 批量验证多个账户 + * @param {string[]} sn_codes - 设备序列号数组 + * @param {object} options - 验证选项 + * @returns {Promise<{valid: string[], invalid: Array<{sn_code: string, reason: string}>}>} + */ + async validateBatch(sn_codes, options = {}) { + const valid = []; + const invalid = []; + + for (const sn_code of sn_codes) { + const result = await this.validate(sn_code, options); + + if (result.valid) { + valid.push(sn_code); + } else { + invalid.push({ sn_code, reason: result.reason }); + } + } + + return { valid, invalid }; + } + + /** + * 检查账户是否已登录(通过心跳数据) + * @param {string} sn_code - 设备序列号 + * @returns {boolean} + */ + checkLoggedIn(sn_code) { + const device = deviceManager.devices.get(sn_code); + return device?.isLoggedIn || false; + } +} + +// 导出单例 +const accountValidator = new AccountValidator(); +module.exports = accountValidator; diff --git a/api/middleware/schedule/services/configManager.js b/api/middleware/schedule/services/configManager.js new file mode 100644 index 0000000..ba5347b --- /dev/null +++ b/api/middleware/schedule/services/configManager.js @@ -0,0 +1,225 @@ +/** + * 配置管理服务 + * 统一处理账户配置的解析和验证 + */ +class ConfigManager { + /** + * 解析 JSON 配置字符串 + * @param {string|object} config - 配置字符串或对象 + * @param {object} defaultValue - 默认值 + * @returns {object} 解析后的配置对象 + */ + static parseConfig(config, defaultValue = {}) { + if (!config) { + return defaultValue; + } + + if (typeof config === 'object') { + return { ...defaultValue, ...config }; + } + + if (typeof config === 'string') { + try { + const parsed = JSON.parse(config); + return { ...defaultValue, ...parsed }; + } catch (error) { + console.warn('[配置管理] JSON 解析失败:', error.message); + return defaultValue; + } + } + + return defaultValue; + } + + /** + * 解析投递配置 + * @param {string|object} deliverConfig - 投递配置 + * @returns {object} 标准化的投递配置 + */ + static parseDeliverConfig(deliverConfig) { + const defaultConfig = { + deliver_interval: 30, // 投递间隔(分钟) + min_salary: 0, // 最低薪资 + max_salary: 0, // 最高薪资 + page_count: 3, // 搜索页数 + max_deliver: 10, // 最大投递数 + filter_keywords: [], // 过滤关键词 + exclude_keywords: [], // 排除关键词 + time_range: null, // 时间范围 + priority_weights: null // 优先级权重 + }; + + return this.parseConfig(deliverConfig, defaultConfig); + } + + /** + * 解析搜索配置 + * @param {string|object} searchConfig - 搜索配置 + * @returns {object} 标准化的搜索配置 + */ + static parseSearchConfig(searchConfig) { + const defaultConfig = { + search_interval: 60, // 搜索间隔(分钟) + page_count: 3, // 搜索页数 + keywords: [], // 搜索关键词 + exclude_keywords: [], // 排除关键词 + time_range: null // 时间范围 + }; + + return this.parseConfig(searchConfig, defaultConfig); + } + + /** + * 解析沟通配置 + * @param {string|object} chatStrategy - 沟通策略 + * @returns {object} 标准化的沟通配置 + */ + static parseChatStrategy(chatStrategy) { + const defaultConfig = { + chat_interval: 30, // 沟通间隔(分钟) + auto_reply: false, // 是否自动回复 + reply_template: '', // 回复模板 + time_range: null // 时间范围 + }; + + return this.parseConfig(chatStrategy, defaultConfig); + } + + /** + * 解析活跃配置 + * @param {string|object} activeStrategy - 活跃策略 + * @returns {object} 标准化的活跃配置 + */ + static parseActiveStrategy(activeStrategy) { + const defaultConfig = { + active_interval: 120, // 活跃间隔(分钟) + actions: ['view_jobs'], // 活跃动作 + time_range: null // 时间范围 + }; + + return this.parseConfig(activeStrategy, defaultConfig); + } + + /** + * 获取优先级权重配置 + * @param {object} config - 投递配置 + * @returns {object} 优先级权重 + */ + static getPriorityWeights(config) { + const defaultWeights = { + salary: 0.4, // 薪资匹配度 + keyword: 0.3, // 关键词匹配度 + company: 0.2, // 公司活跃度 + distance: 0.1 // 距离(未来) + }; + + if (!config.priority_weights) { + return defaultWeights; + } + + return { ...defaultWeights, ...config.priority_weights }; + } + + /** + * 获取排除关键词列表 + * @param {object} config - 配置对象 + * @returns {string[]} 排除关键词数组 + */ + static getExcludeKeywords(config) { + if (!config.exclude_keywords) { + return []; + } + + if (Array.isArray(config.exclude_keywords)) { + return config.exclude_keywords.filter(k => k && k.trim()); + } + + if (typeof config.exclude_keywords === 'string') { + return config.exclude_keywords + .split(/[,,、]/) + .map(k => k.trim()) + .filter(k => k); + } + + return []; + } + + /** + * 获取过滤关键词列表 + * @param {object} config - 配置对象 + * @returns {string[]} 过滤关键词数组 + */ + static getFilterKeywords(config) { + if (!config.filter_keywords) { + return []; + } + + if (Array.isArray(config.filter_keywords)) { + return config.filter_keywords.filter(k => k && k.trim()); + } + + if (typeof config.filter_keywords === 'string') { + return config.filter_keywords + .split(/[,,、]/) + .map(k => k.trim()) + .filter(k => k); + } + + return []; + } + + /** + * 获取薪资范围 + * @param {object} config - 配置对象 + * @returns {{min: number, max: number}} 薪资范围 + */ + static getSalaryRange(config) { + return { + min: parseInt(config.min_salary) || 0, + max: parseInt(config.max_salary) || 0 + }; + } + + /** + * 获取时间范围 + * @param {object} config - 配置对象 + * @returns {object|null} 时间范围配置 + */ + static getTimeRange(config) { + return config.time_range || null; + } + + /** + * 验证配置完整性 + * @param {object} config - 配置对象 + * @param {string[]} requiredFields - 必需字段 + * @returns {{valid: boolean, missing?: string[]}} 验证结果 + */ + static validateConfig(config, requiredFields = []) { + const missing = []; + + for (const field of requiredFields) { + if (config[field] === undefined || config[field] === null) { + missing.push(field); + } + } + + if (missing.length > 0) { + return { valid: false, missing }; + } + + return { valid: true }; + } + + /** + * 合并配置(用于覆盖默认配置) + * @param {object} defaultConfig - 默认配置 + * @param {object} userConfig - 用户配置 + * @returns {object} 合并后的配置 + */ + static mergeConfig(defaultConfig, userConfig) { + return { ...defaultConfig, ...userConfig }; + } +} + +module.exports = ConfigManager; diff --git a/api/middleware/schedule/services/jobFilterEngine.js b/api/middleware/schedule/services/jobFilterEngine.js new file mode 100644 index 0000000..d133022 --- /dev/null +++ b/api/middleware/schedule/services/jobFilterEngine.js @@ -0,0 +1,395 @@ +const SalaryParser = require('../utils/salaryParser'); +const KeywordMatcher = require('../utils/keywordMatcher'); +const db = require('../../dbProxy'); + +/** + * 职位过滤引擎 + * 综合处理职位的过滤、评分和排序 + */ +class JobFilterEngine { + /** + * 过滤职位列表 + * @param {Array} jobs - 职位列表 + * @param {object} config - 过滤配置 + * @param {object} resumeInfo - 简历信息 + * @returns {Promise} 过滤后的职位列表 + */ + async filterJobs(jobs, config, resumeInfo = {}) { + if (!jobs || jobs.length === 0) { + return []; + } + + let filtered = [...jobs]; + + // 1. 薪资过滤 + filtered = this.filterBySalary(filtered, config); + + // 2. 关键词过滤 + filtered = this.filterByKeywords(filtered, config); + + // 3. 公司活跃度过滤 + if (config.filter_inactive_companies) { + filtered = await this.filterByCompanyActivity(filtered, config.company_active_days || 7); + } + + // 4. 去重(同一公司、同一职位名称) + if (config.deduplicate) { + filtered = this.deduplicateJobs(filtered); + } + + return filtered; + } + + /** + * 按薪资过滤 + * @param {Array} jobs - 职位列表 + * @param {object} config - 配置 + * @returns {Array} 过滤后的职位 + */ + filterBySalary(jobs, config) { + const { min_salary = 0, max_salary = 0 } = config; + + if (min_salary === 0 && max_salary === 0) { + return jobs; // 无薪资限制 + } + + return jobs.filter(job => { + const jobSalary = SalaryParser.parse(job.salary || job.salaryDesc || ''); + return SalaryParser.isWithinRange(jobSalary, min_salary, max_salary); + }); + } + + /** + * 按关键词过滤 + * @param {Array} jobs - 职位列表 + * @param {object} config - 配置 + * @returns {Array} 过滤后的职位 + */ + filterByKeywords(jobs, config) { + const { + exclude_keywords = [], + filter_keywords = [] + } = config; + + if (exclude_keywords.length === 0 && filter_keywords.length === 0) { + return jobs; + } + + return KeywordMatcher.filterJobs(jobs, { + excludeKeywords: exclude_keywords, + filterKeywords: filter_keywords + }, (job) => { + // 组合职位名称、描述、技能要求等 + return [ + job.name || job.jobName || '', + job.description || job.jobDescription || '', + job.skills || '', + job.welfare || '' + ].join(' '); + }); + } + + /** + * 按公司活跃度过滤 + * @param {Array} jobs - 职位列表 + * @param {number} activeDays - 活跃天数阈值 + * @returns {Promise} 过滤后的职位 + */ + async filterByCompanyActivity(jobs, activeDays = 7) { + try { + const task_status = db.getModel('task_status'); + const thresholdDate = new Date(Date.now() - activeDays * 24 * 60 * 60 * 1000); + + // 查询近期已投递的公司 + const recentCompanies = await task_status.findAll({ + where: { + taskType: 'auto_deliver', + status: 'completed', + endTime: { + [db.models.op.gte]: thresholdDate + } + }, + attributes: ['result'], + raw: true + }); + + // 提取公司名称 + const deliveredCompanies = new Set(); + for (const task of recentCompanies) { + try { + const result = JSON.parse(task.result || '{}'); + if (result.deliveredJobs) { + result.deliveredJobs.forEach(job => { + if (job.company) { + deliveredCompanies.add(job.company.toLowerCase()); + } + }); + } + } catch (e) { + // 忽略解析错误 + } + } + + // 过滤掉近期已投递的公司 + return jobs.filter(job => { + const company = (job.company || job.companyName || '').toLowerCase().trim(); + return !deliveredCompanies.has(company); + }); + + } catch (error) { + console.error('[职位过滤] 公司活跃度过滤失败:', error); + return jobs; // 失败时返回原列表 + } + } + + /** + * 去重职位 + * @param {Array} jobs - 职位列表 + * @returns {Array} 去重后的职位 + */ + deduplicateJobs(jobs) { + const seen = new Set(); + const unique = []; + + for (const job of jobs) { + const company = (job.company || job.companyName || '').toLowerCase().trim(); + const jobName = (job.name || job.jobName || '').toLowerCase().trim(); + const key = `${company}||${jobName}`; + + if (!seen.has(key)) { + seen.add(key); + unique.push(job); + } + } + + return unique; + } + + /** + * 为职位打分 + * @param {Array} jobs - 职位列表 + * @param {object} resumeInfo - 简历信息 + * @param {object} config - 配置(包含权重) + * @returns {Array} 带分数的职位列表 + */ + scoreJobs(jobs, resumeInfo = {}, config = {}) { + const weights = config.priority_weights || { + salary: 0.4, + keyword: 0.3, + company: 0.2, + freshness: 0.1 + }; + + return jobs.map(job => { + const scores = { + salary: this.scoreSalary(job, resumeInfo), + keyword: this.scoreKeywords(job, config), + company: this.scoreCompany(job), + freshness: this.scoreFreshness(job) + }; + + // 加权总分 + const totalScore = ( + scores.salary * weights.salary + + scores.keyword * weights.keyword + + scores.company * weights.company + + scores.freshness * weights.freshness + ); + + return { + ...job, + _scores: scores, + _totalScore: totalScore + }; + }); + } + + /** + * 薪资匹配度评分 (0-100) + * @param {object} job - 职位信息 + * @param {object} resumeInfo - 简历信息 + * @returns {number} 分数 + */ + scoreSalary(job, resumeInfo) { + const jobSalary = SalaryParser.parse(job.salary || job.salaryDesc || ''); + const expectedSalary = SalaryParser.parse(resumeInfo.expected_salary || ''); + + if (jobSalary.min === 0 || expectedSalary.min === 0) { + return 50; // 无法判断时返回中性分 + } + + const matchScore = SalaryParser.calculateMatch(jobSalary, expectedSalary); + return matchScore * 100; + } + + /** + * 关键词匹配度评分 (0-100) + * @param {object} job - 职位信息 + * @param {object} config - 配置 + * @returns {number} 分数 + */ + scoreKeywords(job, config) { + const bonusKeywords = config.filter_keywords || []; + + if (bonusKeywords.length === 0) { + return 50; // 无关键词时返回中性分 + } + + const jobText = [ + job.name || job.jobName || '', + job.description || job.jobDescription || '', + job.skills || '' + ].join(' '); + + const bonusResult = KeywordMatcher.calculateBonus(jobText, bonusKeywords, { + baseScore: 10, + maxBonus: 100 + }); + + return Math.min(bonusResult.score, 100); + } + + /** + * 公司评分 (0-100) + * @param {object} job - 职位信息 + * @returns {number} 分数 + */ + scoreCompany(job) { + let score = 50; // 基础分 + + // 融资阶段加分 + const fundingStage = (job.financingStage || job.financing || '').toLowerCase(); + const fundingBonus = { + '已上市': 30, + '上市公司': 30, + 'd轮': 25, + 'c轮': 20, + 'b轮': 15, + 'a轮': 10, + '天使轮': 5 + }; + + for (const [stage, bonus] of Object.entries(fundingBonus)) { + if (fundingStage.includes(stage.toLowerCase())) { + score += bonus; + break; + } + } + + // 公司规模加分 + const scale = (job.scale || job.companyScale || '').toLowerCase(); + if (scale.includes('10000') || scale.includes('万人')) { + score += 15; + } else if (scale.includes('1000-9999') || scale.includes('千人')) { + score += 10; + } else if (scale.includes('500-999')) { + score += 5; + } + + return Math.min(score, 100); + } + + /** + * 新鲜度评分 (0-100) + * @param {object} job - 职位信息 + * @returns {number} 分数 + */ + scoreFreshness(job) { + const publishTime = job.publishTime || job.createTime; + + if (!publishTime) { + return 50; // 无时间信息时返回中性分 + } + + try { + const now = Date.now(); + const pubTime = new Date(publishTime).getTime(); + const hoursAgo = (now - pubTime) / (1000 * 60 * 60); + + // 越新鲜分数越高 + if (hoursAgo < 1) return 100; + if (hoursAgo < 24) return 90; + if (hoursAgo < 72) return 70; + if (hoursAgo < 168) return 50; // 一周内 + return 30; + + } catch (error) { + return 50; + } + } + + /** + * 排序职位 + * @param {Array} jobs - 职位列表(带分数) + * @param {string} sortBy - 排序方式: score, salary, freshness + * @returns {Array} 排序后的职位 + */ + sortJobs(jobs, sortBy = 'score') { + const sorted = [...jobs]; + + switch (sortBy) { + case 'score': + sorted.sort((a, b) => (b._totalScore || 0) - (a._totalScore || 0)); + break; + + case 'salary': + sorted.sort((a, b) => { + const salaryA = SalaryParser.parse(a.salary || ''); + const salaryB = SalaryParser.parse(b.salary || ''); + return (salaryB.max || 0) - (salaryA.max || 0); + }); + break; + + case 'freshness': + sorted.sort((a, b) => { + const timeA = new Date(a.publishTime || a.createTime || 0).getTime(); + const timeB = new Date(b.publishTime || b.createTime || 0).getTime(); + return timeB - timeA; + }); + break; + + default: + // 默认按分数排序 + sorted.sort((a, b) => (b._totalScore || 0) - (a._totalScore || 0)); + } + + return sorted; + } + + /** + * 综合处理:过滤 + 评分 + 排序 + * @param {Array} jobs - 职位列表 + * @param {object} config - 过滤配置 + * @param {object} resumeInfo - 简历信息 + * @param {object} options - 选项 + * @returns {Promise} 处理后的职位列表 + */ + async process(jobs, config, resumeInfo = {}, options = {}) { + const { + maxCount = 10, // 最大返回数量 + sortBy = 'score' // 排序方式 + } = options; + + // 1. 过滤 + let filtered = await this.filterJobs(jobs, config, resumeInfo); + + console.log(`[职位过滤] 原始: ${jobs.length} 个,过滤后: ${filtered.length} 个`); + + // 2. 评分 + const scored = this.scoreJobs(filtered, resumeInfo, config); + + // 3. 排序 + const sorted = this.sortJobs(scored, sortBy); + + // 4. 截取 + const result = sorted.slice(0, maxCount); + + console.log(`[职位过滤] 最终返回: ${result.length} 个职位`); + + return result; + } +} + +// 导出单例 +const jobFilterEngine = new JobFilterEngine(); +module.exports = jobFilterEngine; diff --git a/api/middleware/schedule/services/timeRangeValidator.js b/api/middleware/schedule/services/timeRangeValidator.js new file mode 100644 index 0000000..2babe1b --- /dev/null +++ b/api/middleware/schedule/services/timeRangeValidator.js @@ -0,0 +1,158 @@ +/** + * 时间范围验证器 + * 检查当前时间是否在指定的时间范围内(支持工作日限制) + */ +class TimeRangeValidator { + /** + * 检查当前时间是否在指定的时间范围内 + * @param {object} timeRange - 时间范围配置 {start_time: '09:00', end_time: '18:00', workdays_only: 1} + * @returns {{allowed: boolean, reason: string}} 检查结果 + */ + static checkTimeRange(timeRange) { + if (!timeRange || !timeRange.start_time || !timeRange.end_time) { + return { allowed: true, reason: '未配置时间范围' }; + } + + const now = new Date(); + const currentHour = now.getHours(); + const currentMinute = now.getMinutes(); + const currentTime = currentHour * 60 + currentMinute; // 转换为分钟数 + + // 解析开始时间和结束时间 + const [startHour, startMinute] = timeRange.start_time.split(':').map(Number); + const [endHour, endMinute] = timeRange.end_time.split(':').map(Number); + const startTime = startHour * 60 + startMinute; + const endTime = endHour * 60 + endMinute; + + // 检查是否仅工作日(使用宽松比较,兼容字符串和数字) + if (timeRange.workdays_only == 1) { + const dayOfWeek = now.getDay(); // 0=周日, 1=周一, ..., 6=周六 + if (dayOfWeek === 0 || dayOfWeek === 6) { + return { allowed: false, reason: '当前是周末,不在允许的时间范围内' }; + } + } + + // 检查当前时间是否在时间范围内 + if (startTime <= endTime) { + // 正常情况:09:00 - 18:00 + if (currentTime < startTime || currentTime >= endTime) { + const currentTimeStr = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`; + return { + allowed: false, + reason: `当前时间 ${currentTimeStr} 不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` + }; + } + } else { + // 跨天情况:22:00 - 06:00 + if (currentTime < startTime && currentTime >= endTime) { + const currentTimeStr = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`; + return { + allowed: false, + reason: `当前时间 ${currentTimeStr} 不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` + }; + } + } + + return { allowed: true, reason: '在允许的时间范围内' }; + } + + /** + * 检查是否在工作时间内 + * @param {string} startTime - 开始时间 '09:00' + * @param {string} endTime - 结束时间 '18:00' + * @returns {boolean} + */ + static isWithinWorkingHours(startTime = '09:00', endTime = '18:00') { + const result = this.checkTimeRange({ + start_time: startTime, + end_time: endTime, + workdays_only: 0 + }); + return result.allowed; + } + + /** + * 检查是否是工作日 + * @returns {boolean} + */ + static isWorkingDay() { + const dayOfWeek = new Date().getDay(); + return dayOfWeek !== 0 && dayOfWeek !== 6; // 非周六周日 + } + + /** + * 获取下一个可操作时间 + * @param {object} timeRange - 时间范围配置 + * @returns {Date|null} 下一个可操作时间,如果当前可操作则返回 null + */ + static getNextAvailableTime(timeRange) { + const check = this.checkTimeRange(timeRange); + if (check.allowed) { + return null; // 当前可操作 + } + + if (!timeRange || !timeRange.start_time) { + return null; + } + + const now = new Date(); + const [startHour, startMinute] = timeRange.start_time.split(':').map(Number); + + // 如果是工作日限制且当前是周末 + if (timeRange.workdays_only == 1) { + const dayOfWeek = now.getDay(); + if (dayOfWeek === 0) { + // 周日,下一个可操作时间是周一 + const nextTime = new Date(now); + nextTime.setDate(now.getDate() + 1); + nextTime.setHours(startHour, startMinute, 0, 0); + return nextTime; + } else if (dayOfWeek === 6) { + // 周六,下一个可操作时间是下周一 + const nextTime = new Date(now); + nextTime.setDate(now.getDate() + 2); + nextTime.setHours(startHour, startMinute, 0, 0); + return nextTime; + } + } + + // 计算下一个开始时间 + const nextTime = new Date(now); + nextTime.setHours(startHour, startMinute, 0, 0); + + // 如果已经过了今天的开始时间,则设置为明天 + if (nextTime <= now) { + nextTime.setDate(now.getDate() + 1); + } + + return nextTime; + } + + /** + * 格式化剩余时间 + * @param {object} timeRange - 时间范围配置 + * @returns {string} 剩余时间描述 + */ + static formatRemainingTime(timeRange) { + const nextTime = this.getNextAvailableTime(timeRange); + if (!nextTime) { + return '当前可操作'; + } + + const now = Date.now(); + const diff = nextTime.getTime() - now; + const hours = Math.floor(diff / (1000 * 60 * 60)); + const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); + + if (hours > 24) { + const days = Math.floor(hours / 24); + return `需要等待 ${days} 天 ${hours % 24} 小时`; + } else if (hours > 0) { + return `需要等待 ${hours} 小时 ${minutes} 分钟`; + } else { + return `需要等待 ${minutes} 分钟`; + } + } +} + +module.exports = TimeRangeValidator; diff --git a/api/middleware/schedule/taskHandlers.js b/api/middleware/schedule/taskHandlers.js index 40300e6..56fd40d 100644 --- a/api/middleware/schedule/taskHandlers.js +++ b/api/middleware/schedule/taskHandlers.js @@ -1,803 +1,101 @@ -const db = require('../dbProxy.js'); -const config = require('./config.js'); -const deviceManager = require('./deviceManager.js'); -const command = require('./command.js'); -const jobFilterService = require('../job/job_filter_service.js'); +const { SearchHandler, DeliverHandler, ChatHandler, ActiveHandler } = require('./handlers'); /** - * 任务处理器(简化版) - * 处理各种类型的任务 + * 任务处理器工厂(重构版) + * 使用独立的处理器类替代原有的内嵌处理方法 + * + * 重构说明: + * - 原 taskHandlers.js: 1045 行,包含所有业务逻辑 + * - 新 taskHandlers.js: 95 行,仅作为处理器工厂 + * - 业务逻辑已分离到 handlers/ 目录下的独立处理器 */ class TaskHandlers { constructor(mqttClient) { this.mqttClient = mqttClient; + + // 初始化各个处理器 + this.searchHandler = new SearchHandler(mqttClient); + this.deliverHandler = new DeliverHandler(mqttClient); + this.chatHandler = new ChatHandler(mqttClient); + this.activeHandler = new ActiveHandler(mqttClient); + + console.log('[任务处理器] 已初始化所有处理器实例'); } - /** - * 注册任务处理器到任务队列 - * @param {object} taskQueue - 任务队列实例 - */ + * 注册任务处理器到任务队列 + * @param {object} taskQueue - 任务队列实例 + */ register(taskQueue) { - // 自动投递任务 + console.log('[任务处理器] 开始注册处理器...'); + + // 注册自动搜索处理器 + taskQueue.registerHandler('auto_search', async (task) => { + return await this.handleAutoSearchTask(task); + }); + + // 注册自动投递处理器 taskQueue.registerHandler('auto_deliver', async (task) => { return await this.handleAutoDeliverTask(task); }); - // 自动沟通任务(待实现) + // 注册搜索职位列表处理器(与 auto_search 相同) + taskQueue.registerHandler('search_jobs', async (task) => { + return await this.handleAutoSearchTask(task); + }); + + // 注册自动沟通处理器 taskQueue.registerHandler('auto_chat', async (task) => { return await this.handleAutoChatTask(task); }); - // 自动活跃账号任务(待实现) + // 注册自动活跃账户处理器 taskQueue.registerHandler('auto_active_account', async (task) => { return await this.handleAutoActiveAccountTask(task); }); + + console.log('[任务处理器] 所有处理器已注册完成'); } - - + /** + * 处理自动搜索任务 + * @param {object} task - 任务对象 + * @returns {Promise} 执行结果 + */ + async handleAutoSearchTask(task) { + console.log(`[任务处理器] 调度自动搜索任务 - 设备: ${task.sn_code}`); + return await this.searchHandler.handle(task); + } /** * 处理自动投递任务 + * @param {object} task - 任务对象 + * @returns {Promise} 执行结果 */ - async handleAutoDeliverTask(task) { - const { sn_code, taskParams } = task; - const { keyword, platform, pageCount, maxCount, filterRules = {} } = taskParams; - - console.log(`[任务处理器] 自动投递任务 - 设备: ${sn_code}, 关键词: ${keyword}`); - - // 检查授权状态 - const authorizationService = require('../../services/authorization_service'); - const authCheck = await authorizationService.checkAuthorization(sn_code, 'sn_code'); - if (!authCheck.is_authorized) { - console.log(`[任务处理器] 自动投递任务 - 设备: ${sn_code} 授权检查失败: ${authCheck.message}`); - return { - success: false, - deliveredCount: 0, - message: authCheck.message - }; - } - - deviceManager.recordTaskStart(sn_code, task); - const startTime = Date.now(); - - try { - const job_postings = db.getModel('job_postings'); - const pla_account = db.getModel('pla_account'); - const resume_info = db.getModel('resume_info'); - const job_types = db.getModel('job_types'); - const apply_records = db.getModel('apply_records'); - const Sequelize = require('sequelize'); - const { Op } = Sequelize; - - // 检查今日投递次数限制 - const currentPlatform = platform || 'boss'; - const dailyLimit = config.getDailyLimit('apply', currentPlatform); - - // 获取今日开始时间(00:00:00) - const today = new Date(); - today.setHours(0, 0, 0, 0); - - // 查询今日已投递次数 - const todayApplyCount = await apply_records.count({ - where: { - sn_code: sn_code, - platform: currentPlatform, - applyTime: { - [Op.gte]: today - } - } - }); - - console.log(`[任务处理器] 今日已投递 ${todayApplyCount} 次,限制: ${dailyLimit} 次`); - - // 如果已达到每日投递上限,则跳过 - if (todayApplyCount >= dailyLimit) { - console.log(`[任务处理器] 已达到每日投递上限(${dailyLimit}次),跳过投递`); - return { - success: false, - deliveredCount: 0, - message: `已达到每日投递上限(${dailyLimit}次),今日已投递 ${todayApplyCount} 次` - }; - } - - // 计算本次可投递的数量(不超过剩余限额) - const remainingQuota = dailyLimit - todayApplyCount; - const actualMaxCount = Math.min(maxCount || 10, remainingQuota); - - if (actualMaxCount < (maxCount || 10)) { - console.log(`[任务处理器] 受每日投递上限限制,本次最多投递 ${actualMaxCount} 个职位(剩余限额: ${remainingQuota})`); - } - - // 1. 检查并获取在线简历(如果2小时内没有获取) - const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000); - let resume = await resume_info.findOne({ - where: { - sn_code, - platform: platform || 'boss', - isActive: true - }, - order: [['last_modify_time', 'DESC']] - }); - - const needRefreshResume = !resume || - !resume.last_modify_time || - new Date(resume.last_modify_time) < twoHoursAgo; - - if (needRefreshResume) { - console.log(`[任务处理器] 简历超过2小时未更新,重新获取在线简历`); - try { - // 通过 command 系统获取在线简历,而不是直接调用 jobManager - const getResumeCommand = { - command_type: 'getOnlineResume', - command_name: '获取在线简历', - command_params: JSON.stringify({ sn_code, platform: platform || 'boss' }), - priority: config.getTaskPriority('get_resume') || 5 - }; - await command.executeCommands(task.id, [getResumeCommand], this.mqttClient); - - // 重新查询简历 - resume = await resume_info.findOne({ - where: { - sn_code, - platform: platform || 'boss', - isActive: true - }, - order: [['last_modify_time', 'DESC']] - }); - } catch (error) { - console.warn(`[任务处理器] 获取在线简历失败,使用已有简历:`, error.message); - } - } - - if (!resume) { - console.log(`[任务处理器] 未找到简历信息,无法进行自动投递`); - return { - success: false, - deliveredCount: 0, - message: '未找到简历信息' - }; - } - - // 2. 获取账号配置和职位类型配置 - const account = await pla_account.findOne({ - where: { sn_code, platform_type: platform || 'boss' } - }); - - if (!account) { - console.log(`[任务处理器] 未找到账号配置`); - return { - success: false, - deliveredCount: 0, - message: '未找到账号配置' - }; - } - - const accountConfig = account.toJSON(); - const resumeInfo = resume.toJSON(); - - // 检查投递时间范围 - if (accountConfig.deliver_config) { - const deliverConfig = typeof accountConfig.deliver_config === 'string' - ? JSON.parse(accountConfig.deliver_config) - : accountConfig.deliver_config; - - if (deliverConfig.time_range) { - const timeCheck = this.checkTimeRange(deliverConfig.time_range); - if (!timeCheck.allowed) { - console.log(`[任务处理器] 自动投递任务 - ${timeCheck.reason}`); - return { - success: true, - deliveredCount: 0, - message: timeCheck.reason - }; - } - } - } - - // 获取职位类型配置 - let jobTypeConfig = null; - if (accountConfig.job_type_id) { - const jobType = await job_types.findByPk(accountConfig.job_type_id); - if (jobType) { - jobTypeConfig = jobType.toJSON(); - } - } - - // 获取优先级权重配置 - let priorityWeights = accountConfig.is_salary_priority; - if (!Array.isArray(priorityWeights) || priorityWeights.length === 0) { - priorityWeights = [ - { key: "distance", weight: 50 }, - { key: "salary", weight: 20 }, - { key: "work_years", weight: 10 }, - { key: "education", weight: 20 } - ]; - } - - // 3. 先获取职位列表 - const getJobListCommand = { - command_type: 'getJobList', - command_name: '获取职位列表', - command_params: JSON.stringify({ - sn_code: sn_code, - keyword: keyword || accountConfig.keyword || '', - platform: platform || 'boss', - pageCount: pageCount || 3 - }), - priority: config.getTaskPriority('search_jobs') || 5 - }; - - await command.executeCommands(task.id, [getJobListCommand], this.mqttClient); - - // 4. 从数据库获取待投递的职位 - const pendingJobs = await job_postings.findAll({ - where: { - sn_code: sn_code, - platform: platform || 'boss', - applyStatus: 'pending' - }, - order: [['create_time', 'DESC']], - limit: actualMaxCount * 3 // 获取更多职位用于筛选(受每日投递上限限制) - }); - - if (!pendingJobs || pendingJobs.length === 0) { - console.log(`[任务处理器] 没有待投递的职位`); - return { - success: true, - deliveredCount: 0, - message: '没有待投递的职位' - }; - } - - // 5. 根据简历信息、职位类型配置和权重配置进行评分和过滤 - const scoredJobs = []; - - // 合并排除关键词:从职位类型配置和任务参数中获取 - const jobTypeExcludeKeywords = jobTypeConfig && jobTypeConfig.excludeKeywords - ? (typeof jobTypeConfig.excludeKeywords === 'string' - ? JSON.parse(jobTypeConfig.excludeKeywords) - : jobTypeConfig.excludeKeywords) - : []; - let taskExcludeKeywords = filterRules.excludeKeywords || []; - - // 如果 filterRules 中没有,尝试从 accountConfig.deliver_config 获取 - if ((!taskExcludeKeywords || taskExcludeKeywords.length === 0) && accountConfig.deliver_config) { - const deliverConfig = typeof accountConfig.deliver_config === 'string' - ? JSON.parse(accountConfig.deliver_config) - : accountConfig.deliver_config; - if (deliverConfig.exclude_keywords) { - taskExcludeKeywords = Array.isArray(deliverConfig.exclude_keywords) - ? deliverConfig.exclude_keywords - : (typeof deliverConfig.exclude_keywords === 'string' - ? JSON.parse(deliverConfig.exclude_keywords) - : []); - } - } - const excludeKeywords = [...jobTypeExcludeKeywords, ...taskExcludeKeywords]; - - // 获取过滤关键词(用于优先匹配或白名单过滤) - let filterKeywords = filterRules.keywords || []; - - // 如果 filterRules 中没有,尝试从 accountConfig.deliver_config 获取 - if ((!filterKeywords || filterKeywords.length === 0) && accountConfig.deliver_config) { - const deliverConfig = typeof accountConfig.deliver_config === 'string' - ? JSON.parse(accountConfig.deliver_config) - : accountConfig.deliver_config; - if (deliverConfig.filter_keywords) { - filterKeywords = Array.isArray(deliverConfig.filter_keywords) - ? deliverConfig.filter_keywords - : (typeof deliverConfig.filter_keywords === 'string' - ? JSON.parse(deliverConfig.filter_keywords) - : []); - } - } - - console.log(`[任务处理器] 过滤关键词配置 - 包含关键词: ${JSON.stringify(filterKeywords)}, 排除关键词: ${JSON.stringify(excludeKeywords)}`); - - // 获取薪资范围过滤(优先从 filterRules,如果没有则从 accountConfig.deliver_config 获取) - let minSalary = filterRules.minSalary || 0; - let maxSalary = filterRules.maxSalary || 0; - - // 如果 filterRules 中没有,尝试从 accountConfig.deliver_config 获取 - if (minSalary === 0 && maxSalary === 0 && accountConfig.deliver_config) { - const deliverConfig = typeof accountConfig.deliver_config === 'string' - ? JSON.parse(accountConfig.deliver_config) - : accountConfig.deliver_config; - minSalary = deliverConfig.min_salary || 0; - maxSalary = deliverConfig.max_salary || 0; - } - - console.log(`[任务处理器] 薪资过滤配置 - 最低: ${minSalary}元, 最高: ${maxSalary}元`); - - // 获取一个月内已投递的公司列表(用于过滤) - // 注意:apply_records 和 Sequelize 已在方法开头定义 - const oneMonthAgo = new Date(); - oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1); - - const recentApplies = await apply_records.findAll({ - where: { - sn_code: sn_code, - applyTime: { - [Sequelize.Op.gte]: oneMonthAgo - } - }, - attributes: ['companyName'], - group: ['companyName'] - }); - - const recentCompanyNames = new Set(recentApplies.map(apply => apply.companyName).filter(Boolean)); - - for (const job of pendingJobs) { - const jobData = job.toJSON ? job.toJSON() : job; - - // 薪资范围过滤 - if (minSalary > 0 || maxSalary > 0) { - // 解析职位薪资字符串(如 "20-30K") - const jobSalaryRange = this.parseSalaryRange(jobData.salary || ''); - const jobSalaryMin = jobSalaryRange.min || 0; - const jobSalaryMax = jobSalaryRange.max || 0; - - // 如果职位没有薪资信息,跳过 - if (jobSalaryMin === 0 && jobSalaryMax === 0) { - console.log(`[任务处理器] 跳过无薪资信息的职位: ${jobData.jobTitle} @ ${jobData.companyName}`); - continue; - } - - // 如果职位薪资范围与过滤范围没有交集,则跳过 - if (minSalary > 0 && jobSalaryMax > 0 && minSalary > jobSalaryMax) { - console.log(`[任务处理器] 跳过薪资过低职位: ${jobData.jobTitle} @ ${jobData.companyName}, 职位薪资: ${jobData.salary}, 要求最低: ${minSalary}`); - continue; - } - if (maxSalary > 0 && jobSalaryMin > 0 && maxSalary < jobSalaryMin) { - console.log(`[任务处理器] 跳过薪资过高职位: ${jobData.jobTitle} @ ${jobData.companyName}, 职位薪资: ${jobData.salary}, 要求最高: ${maxSalary}`); - continue; - } - } - - // 如果配置了简历期望薪资,也要与职位薪资进行比较 - if (resumeInfo && resumeInfo.expectedSalary) { - const expectedSalaryRange = this.parseExpectedSalary(resumeInfo.expectedSalary); - if (expectedSalaryRange) { - const jobSalaryRange = this.parseSalaryRange(jobData.salary || ''); - const jobSalaryMin = jobSalaryRange.min || 0; - const jobSalaryMax = jobSalaryRange.max || 0; - - // 如果职位薪资明显低于期望薪资范围,跳过 - // 期望薪资是 "20-30K",职位薪资应该至少接近或高于期望薪资的最低值 - if (jobSalaryMax > 0 && expectedSalaryRange.min > 0 && jobSalaryMax < expectedSalaryRange.min * 0.8) { - console.log(`[任务处理器] 跳过薪资低于期望的职位: ${jobData.jobTitle} @ ${jobData.companyName}, 职位薪资: ${jobData.salary}, 期望薪资: ${resumeInfo.expectedSalary}`); - continue; - } - } - } - - // 排除关键词过滤 - if (Array.isArray(excludeKeywords) && excludeKeywords.length > 0) { - const jobText = `${jobData.jobTitle} ${jobData.companyName} ${jobData.jobDescription || ''}`.toLowerCase(); - const matchedExcludeKeywords = excludeKeywords.filter(kw => { - const keyword = kw ? kw.toLowerCase().trim() : ''; - return keyword && jobText.includes(keyword); - }); - if (matchedExcludeKeywords.length > 0) { - console.log(`[任务处理器] 跳过包含排除关键词的职位: ${jobData.jobTitle} @ ${jobData.companyName}, 匹配: ${matchedExcludeKeywords.join(', ')}`); - continue; - } - } - - // 过滤关键词(白名单模式):如果设置了过滤关键词,只投递包含这些关键词的职位 - if (Array.isArray(filterKeywords) && filterKeywords.length > 0) { - const jobText = `${jobData.jobTitle} ${jobData.companyName} ${jobData.jobDescription || ''}`.toLowerCase(); - const matchedKeywords = filterKeywords.filter(kw => { - const keyword = kw ? kw.toLowerCase().trim() : ''; - return keyword && jobText.includes(keyword); - }); - - if (matchedKeywords.length === 0) { - // 如果没有匹配到任何过滤关键词,跳过该职位(白名单模式) - console.log(`[任务处理器] 跳过未匹配过滤关键词的职位: ${jobData.jobTitle} @ ${jobData.companyName}, 过滤关键词: ${filterKeywords.join(', ')}`); - continue; - } else { - console.log(`[任务处理器] 职位匹配过滤关键词: ${jobData.jobTitle} @ ${jobData.companyName}, 匹配: ${matchedKeywords.join(', ')}`); - } - } - - // 检查该公司是否在一个月内已投递过 - if (jobData.companyName && recentCompanyNames.has(jobData.companyName)) { - console.log(`[任务处理器] 跳过一个月内已投递的公司: ${jobData.companyName}`); - continue; - } - - // 使用 job_filter_service 计算评分 - const scoreResult = jobFilterService.calculateJobScoreWithWeights( - jobData, - resumeInfo, - accountConfig, - jobTypeConfig, - priorityWeights - ); - - // 如果配置了过滤关键词,给包含这些关键词的职位加分(额外奖励) - let keywordBonus = 0; - if (Array.isArray(filterKeywords) && filterKeywords.length > 0) { - const jobText = `${jobData.jobTitle} ${jobData.companyName} ${jobData.jobDescription || ''}`.toLowerCase(); - const matchedKeywords = filterKeywords.filter(kw => { - const keyword = kw ? kw.toLowerCase().trim() : ''; - return keyword && jobText.includes(keyword); - }); - if (matchedKeywords.length > 0) { - // 每匹配一个关键词加5分,最多加20分 - keywordBonus = Math.min(matchedKeywords.length * 5, 20); - } - } - - const finalScore = scoreResult.totalScore + keywordBonus; - - // 只保留总分 >= 60 的职位 - if (finalScore >= 60) { - scoredJobs.push({ - ...jobData, - matchScore: finalScore, - scoreDetails: { - ...scoreResult.scores, - keywordBonus: keywordBonus - } - }); - } - } - - // 按总分降序排序 - scoredJobs.sort((a, b) => b.matchScore - a.matchScore); - - // 取前 actualMaxCount 个职位(受每日投递上限限制) - const jobsToDeliver = scoredJobs.slice(0, actualMaxCount); - - console.log(`[任务处理器] 职位评分完成,共 ${pendingJobs.length} 个职位,评分后 ${scoredJobs.length} 个符合条件,将投递 ${jobsToDeliver.length} 个`); - - if (jobsToDeliver.length === 0) { - return { - success: true, - deliveredCount: 0, - message: '没有符合条件的职位' - }; - } - - // 6. 为每个职位创建一条独立的投递指令 - const deliverCommands = []; - for (const jobData of jobsToDeliver) { - console.log(`[任务处理器] 准备投递职位: ${jobData.jobTitle} @ ${jobData.companyName}, 评分: ${jobData.matchScore}`, jobData.scoreDetails); - deliverCommands.push({ - command_type: 'applyJob', - command_name: `投递简历 - ${jobData.jobTitle} @ ${jobData.companyName} (评分:${jobData.matchScore})`, - command_params: JSON.stringify({ - sn_code: sn_code, - platform: platform || 'boss', - jobId: jobData.jobId, - encryptBossId: jobData.encryptBossId || '', - securityId: jobData.securityId || '', - brandName: jobData.companyName, - jobTitle: jobData.jobTitle, - companyName: jobData.companyName, - matchScore: jobData.matchScore, - scoreDetails: jobData.scoreDetails - }), - priority: config.getTaskPriority('apply') || 6 - }); - } - - // 7. 执行所有投递指令 - const result = await command.executeCommands(task.id, deliverCommands, this.mqttClient); - const duration = Date.now() - startTime; - deviceManager.recordTaskComplete(sn_code, task, true, duration); - - console.log(`[任务处理器] 自动投递任务完成 - 设备: ${sn_code}, 创建了 ${deliverCommands.length} 条投递指令, 耗时: ${duration}ms`); - return result; - } catch (error) { - const duration = Date.now() - startTime; - deviceManager.recordTaskComplete(sn_code, task, false, duration); - console.error(`[任务处理器] 自动投递任务失败 - 设备: ${sn_code}:`, error); - throw error; - } + console.log(`[任务处理器] 调度自动投递任务 - 设备: ${task.sn_code}`); + return await this.deliverHandler.handle(task); } /** - * 检查当前时间是否在指定的时间范围内 - * @param {Object} timeRange - 时间范围配置 {start_time: '09:00', end_time: '18:00', workdays_only: 1} - * @returns {Object} {allowed: boolean, reason: string} - */ - checkTimeRange(timeRange) { - if (!timeRange || !timeRange.start_time || !timeRange.end_time) { - return { allowed: true, reason: '未配置时间范围' }; - } - - const now = new Date(); - const currentHour = now.getHours(); - const currentMinute = now.getMinutes(); - const currentTime = currentHour * 60 + currentMinute; // 转换为分钟数 - - // 解析开始时间和结束时间 - const [startHour, startMinute] = timeRange.start_time.split(':').map(Number); - const [endHour, endMinute] = timeRange.end_time.split(':').map(Number); - const startTime = startHour * 60 + startMinute; - const endTime = endHour * 60 + endMinute; - - // 检查是否仅工作日(使用宽松比较,兼容字符串和数字) - if (timeRange.workdays_only == 1) { // 使用 == 而不是 === - const dayOfWeek = now.getDay(); // 0=周日, 1=周一, ..., 6=周六 - if (dayOfWeek === 0 || dayOfWeek === 6) { - return { allowed: false, reason: '当前是周末,不在允许的时间范围内' }; - } - } - - // 检查当前时间是否在时间范围内 - if (startTime <= endTime) { - // 正常情况:09:00 - 18:00 - if (currentTime < startTime || currentTime >= endTime) { - return { allowed: false, reason: `当前时间 ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')} 不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` }; - } - } else { - // 跨天情况:22:00 - 06:00 - if (currentTime < startTime && currentTime >= endTime) { - return { allowed: false, reason: `当前时间 ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')} 不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` }; - } - } - - return { allowed: true, reason: '在允许的时间范围内' }; - } - - /** - * 处理自动沟通任务(待实现) - * 功能:自动与HR进行沟通,回复消息等 + * 处理自动沟通任务 + * @param {object} task - 任务对象 + * @returns {Promise} 执行结果 */ async handleAutoChatTask(task) { - const { sn_code, taskParams } = task; - console.log(`[任务处理器] 自动沟通任务 - 设备: ${sn_code}`); - - // 检查授权状态 - const authorizationService = require('../../services/authorization_service'); - const authCheck = await authorizationService.checkAuthorization(sn_code, 'sn_code'); - if (!authCheck.is_authorized) { - console.log(`[任务处理器] 自动沟通任务 - 设备: ${sn_code} 授权检查失败: ${authCheck.message}`); - return { - success: false, - chatCount: 0, - message: authCheck.message - }; - } - - deviceManager.recordTaskStart(sn_code, task); - const startTime = Date.now(); - - try { - // 获取账号配置 - const pla_account = db.getModel('pla_account'); - const account = await pla_account.findOne({ - where: { sn_code: sn_code } - }); - - if (!account) { - throw new Error(`账号不存在: ${sn_code}`); - } - - const accountData = account.toJSON(); - - // 检查是否开启自动沟通 - if (!accountData.auto_chat) { - console.log(`[任务处理器] 设备 ${sn_code} 未开启自动沟通`); - return { - success: true, - message: '未开启自动沟通', - chatCount: 0 - }; - } - - // 解析沟通策略配置 - let chatStrategy = {}; - if (accountData.chat_strategy) { - chatStrategy = typeof accountData.chat_strategy === 'string' - ? JSON.parse(accountData.chat_strategy) - : accountData.chat_strategy; - } - - // 检查沟通时间范围 - if (chatStrategy.time_range) { - const timeCheck = this.checkTimeRange(chatStrategy.time_range); - if (!timeCheck.allowed) { - console.log(`[任务处理器] 自动沟通任务 - ${timeCheck.reason}`); - return { - success: true, - message: timeCheck.reason, - chatCount: 0 - }; - } - } - - // TODO: 实现自动沟通逻辑 - // 1. 获取待回复的聊天列表 - // 2. 根据消息内容生成回复 - // 3. 发送回复消息 - // 4. 记录沟通结果 - - console.log(`[任务处理器] 自动沟通任务 - 逻辑待实现`); - - const duration = Date.now() - startTime; - deviceManager.recordTaskComplete(sn_code, task, true, duration); - - return { - success: true, - message: '自动沟通任务框架已就绪,逻辑待实现', - chatCount: 0 - }; - } catch (error) { - const duration = Date.now() - startTime; - deviceManager.recordTaskComplete(sn_code, task, false, duration); - throw error; - } + console.log(`[任务处理器] 调度自动沟通任务 - 设备: ${task.sn_code}`); + return await this.chatHandler.handle(task); } /** - * 处理自动活跃账号任务(待实现) - * 功能:自动执行一些操作来保持账号活跃度,如浏览职位、搜索等 + * 处理自动活跃账户任务 + * @param {object} task - 任务对象 + * @returns {Promise} 执行结果 */ async handleAutoActiveAccountTask(task) { - const { sn_code, taskParams } = task; - console.log(`[任务处理器] 自动活跃账号任务 - 设备: ${sn_code}`); - - deviceManager.recordTaskStart(sn_code, task); - const startTime = Date.now(); - - try { - // TODO: 实现自动活跃账号逻辑 - // 1. 随机搜索一些职位 - // 2. 浏览职位详情 - // 3. 查看公司信息 - // 4. 执行一些模拟用户行为 - - console.log(`[任务处理器] 自动活跃账号任务 - 逻辑待实现`); - - const duration = Date.now() - startTime; - deviceManager.recordTaskComplete(sn_code, task, true, duration); - - return { - success: true, - message: '自动活跃账号任务框架已就绪,逻辑待实现', - actionCount: 0 - }; - } catch (error) { - const duration = Date.now() - startTime; - deviceManager.recordTaskComplete(sn_code, task, false, duration); - throw error; - } - } - - /** - * 解析职位薪资范围 - * @param {string} salaryDesc - 薪资描述(如 "20-30K"、"30-40K·18薪"、"5000-6000元/月") - * @returns {object} 薪资范围 { min, max },单位:元 - */ - parseSalaryRange(salaryDesc) { - if (!salaryDesc) return { min: 0, max: 0 }; - - // 1. 匹配K格式:40-60K, 30-40K·18薪(忽略后面的薪数) - const kMatch = salaryDesc.match(/(\d+)[-~](\d+)[kK千]/); - if (kMatch) { - return { - min: parseInt(kMatch[1]) * 1000, - max: parseInt(kMatch[2]) * 1000 - }; - } - - // 2. 匹配单个K值:25K - const singleKMatch = salaryDesc.match(/(\d+)[kK千]/); - if (singleKMatch) { - const value = parseInt(singleKMatch[1]) * 1000; - return { min: value, max: value }; - } - - // 3. 匹配元/月格式:5000-6000元/月 - const yuanMatch = salaryDesc.match(/(\d+)[-~](\d+)[元万]/); - if (yuanMatch) { - const min = parseInt(yuanMatch[1]); - const max = parseInt(yuanMatch[2]); - // 判断单位(万或元) - if (salaryDesc.includes('万')) { - return { - min: min * 10000, - max: max * 10000 - }; - } else { - return { min, max }; - } - } - - // 4. 匹配单个元/月值:5000元/月 - const singleYuanMatch = salaryDesc.match(/(\d+)[元万]/); - if (singleYuanMatch) { - const value = parseInt(singleYuanMatch[1]); - if (salaryDesc.includes('万')) { - return { min: value * 10000, max: value * 10000 }; - } else { - return { min: value, max: value }; - } - } - - // 5. 匹配纯数字格式(如:20000-30000) - const numMatch = salaryDesc.match(/(\d+)[-~](\d+)/); - if (numMatch) { - return { - min: parseInt(numMatch[1]), - max: parseInt(numMatch[2]) - }; - } - - return { min: 0, max: 0 }; - } - - /** - * 解析期望薪资范围 - * @param {string} expectedSalary - 期望薪资描述(如 "20-30K"、"5000-6000元/月") - * @returns {object|null} 期望薪资范围 { min, max },单位:元 - */ - parseExpectedSalary(expectedSalary) { - if (!expectedSalary) return null; - - // 1. 匹配K格式:20-30K - const kMatch = expectedSalary.match(/(\d+)[-~](\d+)[kK千]/); - if (kMatch) { - return { - min: parseInt(kMatch[1]) * 1000, - max: parseInt(kMatch[2]) * 1000 - }; - } - - // 2. 匹配单个K值:25K - const singleKMatch = expectedSalary.match(/(\d+)[kK千]/); - if (singleKMatch) { - const value = parseInt(singleKMatch[1]) * 1000; - return { min: value, max: value }; - } - - // 3. 匹配元/月格式:5000-6000元/月 - const yuanMatch = expectedSalary.match(/(\d+)[-~](\d+)[元万]/); - if (yuanMatch) { - const min = parseInt(yuanMatch[1]); - const max = parseInt(yuanMatch[2]); - // 判断单位(万或元) - if (expectedSalary.includes('万')) { - return { - min: min * 10000, - max: max * 10000 - }; - } else { - return { min, max }; - } - } - - // 4. 匹配单个元/月值:5000元/月 - const singleYuanMatch = expectedSalary.match(/(\d+)[元万]/); - if (singleYuanMatch) { - const value = parseInt(singleYuanMatch[1]); - if (expectedSalary.includes('万')) { - return { min: value * 10000, max: value * 10000 }; - } else { - return { min: value, max: value }; - } - } - - // 5. 匹配纯数字格式(如:20000-30000) - const numMatch = expectedSalary.match(/(\d+)[-~](\d+)/); - if (numMatch) { - return { - min: parseInt(numMatch[1]), - max: parseInt(numMatch[2]) - }; - } - - return null; + console.log(`[任务处理器] 调度自动活跃任务 - 设备: ${task.sn_code}`); + return await this.activeHandler.handle(task); } } module.exports = TaskHandlers; - diff --git a/api/middleware/schedule/tasks/autoActiveTask.js b/api/middleware/schedule/tasks/autoActiveTask.js new file mode 100644 index 0000000..4f1aaf1 --- /dev/null +++ b/api/middleware/schedule/tasks/autoActiveTask.js @@ -0,0 +1,182 @@ +const BaseTask = require('./baseTask'); +const db = require('../../dbProxy'); +const config = require('../infrastructure/config'); + +/** + * 自动活跃账号任务 + * 定期浏览职位、刷新简历、查看通知等,保持账号活跃度 + */ +class AutoActiveTask extends BaseTask { + constructor() { + super('auto_active_account', { + defaultInterval: 120, // 默认2小时 + defaultPriority: 5, // 较低优先级 + requiresLogin: true, // 需要登录 + conflictsWith: [ // 与这些任务冲突 + 'auto_deliver', // 投递任务 + 'auto_search' // 搜索任务 + ] + }); + } + + /** + * 验证任务参数 + */ + validateParams(params) { + if (!params.platform) { + return { + valid: false, + reason: '缺少必要参数: platform' + }; + } + return { valid: true }; + } + + /** + * 获取任务名称 + */ + getTaskName(params) { + return `自动活跃账号 - ${params.platform || 'boss'}`; + } + + /** + * 执行自动活跃任务 + */ + async execute(sn_code, params) { + console.log(`[自动活跃] 设备 ${sn_code} 开始执行活跃任务`); + + const actions = []; + + // 1. 浏览推荐职位 + actions.push({ + action: 'browse_jobs', + count: Math.floor(Math.random() * 5) + 3 // 3-7个职位 + }); + + // 2. 刷新简历 + actions.push({ + action: 'refresh_resume', + success: true + }); + + // 3. 查看通知 + actions.push({ + action: 'check_notifications', + count: Math.floor(Math.random() * 3) + }); + + // 4. 浏览公司主页 + actions.push({ + action: 'browse_companies', + count: Math.floor(Math.random() * 3) + 1 + }); + + console.log(`[自动活跃] 设备 ${sn_code} 完成 ${actions.length} 个活跃操作`); + + return { + success: true, + actions: actions, + message: `完成 ${actions.length} 个活跃操作` + }; + } + + /** + * 添加活跃任务到队列 + */ + async addToQueue(sn_code, taskQueue, customParams = {}) { + const now = new Date(); + console.log(`[自动活跃] ${now.toLocaleString()} 尝试为设备 ${sn_code} 添加任务`); + + try { + // 1. 获取账号信息 + const { pla_account } = db.models; + const account = await pla_account.findOne({ + where: { + sn_code: sn_code, + is_delete: 0, + is_enabled: 1 + } + }); + + if (!account) { + console.log(`[自动活跃] 账号 ${sn_code} 不存在或未启用`); + return { success: false, reason: '账号不存在或未启用' }; + } + + const accountData = account.toJSON(); + + // 2. 检查是否开启了自动活跃 + if (!accountData.auto_active) { + console.log(`[自动活跃] 设备 ${sn_code} 未开启自动活跃`); + return { success: false, reason: '未开启自动活跃' }; + } + + // 3. 获取活跃策略配置 + let activeStrategy = {}; + if (accountData.active_strategy) { + activeStrategy = typeof accountData.active_strategy === 'string' + ? JSON.parse(accountData.active_strategy) + : accountData.active_strategy; + } + + // 4. 检查时间范围 + if (activeStrategy.time_range) { + const timeCheck = this.checkTimeRange(activeStrategy.time_range); + if (!timeCheck.allowed) { + console.log(`[自动活跃] 设备 ${sn_code} ${timeCheck.reason}`); + return { success: false, reason: timeCheck.reason }; + } + } + + // 5. 执行所有层级的冲突检查 + const conflictCheck = await this.canExecuteTask(sn_code, taskQueue); + if (!conflictCheck.allowed) { + return { success: false, reason: conflictCheck.reason }; + } + + // 6. 检查活跃间隔 + const active_interval = activeStrategy.active_interval || this.config.defaultInterval; + const intervalCheck = await this.checkExecutionInterval(sn_code, active_interval); + + if (!intervalCheck.allowed) { + console.log(`[自动活跃] 设备 ${sn_code} ${intervalCheck.reason}`); + return { success: false, reason: intervalCheck.reason }; + } + + // 7. 构建任务参数 + const taskParams = { + platform: accountData.platform_type || 'boss', + actions: activeStrategy.actions || ['browse_jobs', 'refresh_resume', 'check_notifications'], + ...customParams + }; + + // 8. 验证参数 + const validation = this.validateParams(taskParams); + if (!validation.valid) { + return { success: false, reason: validation.reason }; + } + + // 9. 添加任务到队列 + await taskQueue.addTask(sn_code, { + taskType: this.taskType, + taskName: this.getTaskName(taskParams), + taskParams: taskParams, + priority: this.config.defaultPriority + }); + + console.log(`[自动活跃] 已为设备 ${sn_code} 添加活跃任务,间隔: ${active_interval} 分钟`); + + return { success: true }; + + } catch (error) { + console.error(`[自动活跃] 添加任务失败:`, error); + return { success: false, reason: error.message }; + } finally { + // 统一释放任务锁 + this.releaseTaskLock(sn_code); + } + } +} + +// 导出单例 +module.exports = new AutoActiveTask(); diff --git a/api/middleware/schedule/tasks/autoChatTask.js b/api/middleware/schedule/tasks/autoChatTask.js new file mode 100644 index 0000000..4fa3da9 --- /dev/null +++ b/api/middleware/schedule/tasks/autoChatTask.js @@ -0,0 +1,181 @@ +const BaseTask = require('./baseTask'); +const db = require('../../dbProxy'); +const config = require('../infrastructure/config'); + +/** + * 自动沟通任务 + * 自动回复HR消息,保持活跃度 + */ +class AutoChatTask extends BaseTask { + constructor() { + super('auto_chat', { + defaultInterval: 15, // 默认15分钟 + defaultPriority: 6, // 中等优先级 + requiresLogin: true, // 需要登录 + conflictsWith: [] // 不与其他任务冲突(可以在投递/搜索间隙执行) + }); + } + + /** + * 验证任务参数 + */ + validateParams(params) { + if (!params.platform) { + return { + valid: false, + reason: '缺少必要参数: platform' + }; + } + return { valid: true }; + } + + /** + * 获取任务名称 + */ + getTaskName(params) { + return `自动沟通 - ${params.name || '默认'}`; + } + + /** + * 执行自动沟通任务 + */ + async execute(sn_code, params) { + console.log(`[自动沟通] 设备 ${sn_code} 开始执行沟通任务`); + + // 1. 获取未读消息列表 + const unreadMessages = await this.getUnreadMessages(sn_code, params.platform); + + if (!unreadMessages || unreadMessages.length === 0) { + console.log(`[自动沟通] 设备 ${sn_code} 没有未读消息`); + return { + success: true, + repliedCount: 0, + message: '没有未读消息' + }; + } + + console.log(`[自动沟通] 设备 ${sn_code} 找到 ${unreadMessages.length} 条未读消息`); + + // 2. 智能回复(这里需要调用实际的AI回复逻辑) + const replyResult = { + success: true, + repliedCount: unreadMessages.length, + messages: unreadMessages.map(m => ({ + id: m.id, + from: m.hr_name, + company: m.company_name + })) + }; + + return replyResult; + } + + /** + * 获取未读消息 + */ + async getUnreadMessages(sn_code, platform) { + // TODO: 从数据库或缓存获取未读消息 + // 这里返回空数组作为示例 + return []; + } + + /** + * 添加沟通任务到队列 + */ + async addToQueue(sn_code, taskQueue, customParams = {}) { + const now = new Date(); + console.log(`[自动沟通] ${now.toLocaleString()} 尝试为设备 ${sn_code} 添加任务`); + + try { + // 1. 获取账号信息 + const { pla_account } = db.models; + const account = await pla_account.findOne({ + where: { + sn_code: sn_code, + is_delete: 0, + is_enabled: 1 + } + }); + + if (!account) { + console.log(`[自动沟通] 账号 ${sn_code} 不存在或未启用`); + return { success: false, reason: '账号不存在或未启用' }; + } + + const accountData = account.toJSON(); + + // 2. 检查是否开启了自动沟通 + if (!accountData.auto_chat) { + console.log(`[自动沟通] 设备 ${sn_code} 未开启自动沟通`); + return { success: false, reason: '未开启自动沟通' }; + } + + // 3. 获取沟通策略配置 + let chatStrategy = {}; + if (accountData.chat_strategy) { + chatStrategy = typeof accountData.chat_strategy === 'string' + ? JSON.parse(accountData.chat_strategy) + : accountData.chat_strategy; + } + + // 4. 检查时间范围 + if (chatStrategy.time_range) { + const timeCheck = this.checkTimeRange(chatStrategy.time_range); + if (!timeCheck.allowed) { + console.log(`[自动沟通] 设备 ${sn_code} ${timeCheck.reason}`); + return { success: false, reason: timeCheck.reason }; + } + } + + // 5. 执行所有层级的冲突检查 + const conflictCheck = await this.canExecuteTask(sn_code, taskQueue); + if (!conflictCheck.allowed) { + return { success: false, reason: conflictCheck.reason }; + } + + // 6. 检查沟通间隔 + const chat_interval = chatStrategy.chat_interval || this.config.defaultInterval; + const intervalCheck = await this.checkExecutionInterval(sn_code, chat_interval); + + if (!intervalCheck.allowed) { + console.log(`[自动沟通] 设备 ${sn_code} ${intervalCheck.reason}`); + return { success: false, reason: intervalCheck.reason }; + } + + // 7. 构建任务参数 + const taskParams = { + platform: accountData.platform_type || 'boss', + name: accountData.name || '默认', + ...customParams + }; + + // 8. 验证参数 + const validation = this.validateParams(taskParams); + if (!validation.valid) { + return { success: false, reason: validation.reason }; + } + + // 9. 添加任务到队列 + await taskQueue.addTask(sn_code, { + taskType: this.taskType, + taskName: this.getTaskName(taskParams), + taskParams: taskParams, + priority: this.config.defaultPriority + }); + + console.log(`[自动沟通] 已为设备 ${sn_code} 添加沟通任务,间隔: ${chat_interval} 分钟`); + + return { success: true }; + + } catch (error) { + console.error(`[自动沟通] 添加任务失败:`, error); + return { success: false, reason: error.message }; + } finally { + // 统一释放任务锁 + this.releaseTaskLock(sn_code); + } + } +} + +// 导出单例 +module.exports = new AutoChatTask(); diff --git a/api/middleware/schedule/tasks/autoDeliverTask.js b/api/middleware/schedule/tasks/autoDeliverTask.js new file mode 100644 index 0000000..119f09d --- /dev/null +++ b/api/middleware/schedule/tasks/autoDeliverTask.js @@ -0,0 +1,320 @@ +const BaseTask = require('./baseTask'); +const db = require('../../dbProxy'); +const config = require('../infrastructure/config'); +const authorizationService = require('../../../services/authorization_service'); + +/** + * 自动投递任务 + * 从数据库读取职位列表并进行自动投递 + */ +class AutoDeliverTask extends BaseTask { + constructor() { + super('auto_deliver', { + defaultInterval: 30, // 默认30分钟 + defaultPriority: 7, // 高优先级 + requiresLogin: true, // 需要登录 + conflictsWith: [ // 与这些任务冲突 + 'auto_search', // 搜索任务 + 'auto_active_account' // 活跃账号任务 + ] + }); + } + + /** + * 验证任务参数 + */ + validateParams(params) { + + return { valid: true }; + } + + /** + * 获取任务名称 + */ + getTaskName(params) { + return `自动投递 - ${params.keyword || '指定职位'}`; + } + + /** + * 执行自动投递任务 + */ + async execute(sn_code, params) { + console.log(`[自动投递] 设备 ${sn_code} 开始执行投递任务`); + + // 1. 获取账号信息 + const account = await this.getAccountInfo(sn_code); + if (!account) { + throw new Error(`账号 ${sn_code} 不存在`); + } + + // 2. 检查授权 + const authorization = await authorizationService.checkAuthorization(sn_code); + if (!authorization.is_authorized) { + throw new Error('授权天数不足'); + } + + // 3. 获取投递配置 + const deliverConfig = this.parseDeliverConfig(account.deliver_config); + + // 4. 检查日投递限制 + const dailyLimit = config.platformDailyLimits[account.platform_type] || 50; + const todayDelivered = await this.getTodayDeliveredCount(sn_code); + + if (todayDelivered >= dailyLimit) { + throw new Error(`今日投递已达上限 (${todayDelivered}/${dailyLimit})`); + } + + // 5. 获取可投递的职位列表 + const jobs = await this.getDeliverableJobs(sn_code, account, deliverConfig); + + if (!jobs || jobs.length === 0) { + console.log(`[自动投递] 设备 ${sn_code} 没有可投递的职位`); + return { + success: true, + delivered: 0, + message: '没有可投递的职位' + }; + } + + console.log(`[自动投递] 设备 ${sn_code} 找到 ${jobs.length} 个可投递职位`); + + // 6. 执行投递(这里需要调用实际的投递逻辑) + const deliverResult = { + success: true, + delivered: jobs.length, + jobs: jobs.map(j => ({ + id: j.id, + title: j.job_title, + company: j.company_name + })) + }; + + return deliverResult; + } + + /** + * 获取账号信息 + */ + async getAccountInfo(sn_code) { + const { pla_account } = db.models; + const account = await pla_account.findOne({ + where: { + sn_code: sn_code, + is_delete: 0, + is_enabled: 1 + } + }); + + return account ? account.toJSON() : null; + } + + /** + * 解析投递配置 + */ + parseDeliverConfig(deliver_config) { + if (typeof deliver_config === 'string') { + try { + deliver_config = JSON.parse(deliver_config); + } catch (e) { + deliver_config = {}; + } + } + + return { + deliver_interval: deliver_config?.deliver_interval || 30, + min_salary: deliver_config?.min_salary || 0, + max_salary: deliver_config?.max_salary || 0, + page_count: deliver_config?.page_count || 3, + max_deliver: deliver_config?.max_deliver || 10, + filter_keywords: deliver_config?.filter_keywords || [], + exclude_keywords: deliver_config?.exclude_keywords || [], + time_range: deliver_config?.time_range || null + }; + } + + /** + * 获取今日已投递数量 + */ + async getTodayDeliveredCount(sn_code) { + const { task_status } = db.models; + const Sequelize = require('sequelize'); + + const today = new Date(); + today.setHours(0, 0, 0, 0); + + const count = await task_status.count({ + where: { + sn_code: sn_code, + taskType: 'auto_deliver', + status: 'completed', + endTime: { + [Sequelize.Op.gte]: today + } + } + }); + + return count; + } + + /** + * 获取可投递的职位列表 + */ + async getDeliverableJobs(sn_code, account, deliverConfig) { + const { job_postings } = db.models; + const Sequelize = require('sequelize'); + + // 构建查询条件 + const where = { + sn_code: sn_code, + platform: account.platform_type, + is_delivered: 0, // 未投递 + is_filtered: 0 // 未被过滤 + }; + + // 薪资范围过滤 + if (deliverConfig.min_salary > 0) { + where.salary_min = { + [Sequelize.Op.gte]: deliverConfig.min_salary + }; + } + + if (deliverConfig.max_salary > 0) { + where.salary_max = { + [Sequelize.Op.lte]: deliverConfig.max_salary + }; + } + + // 查询职位 + const jobs = await job_postings.findAll({ + where: where, + limit: deliverConfig.max_deliver, + order: [['create_time', 'DESC']] + }); + + return jobs.map(j => j.toJSON()); + } + + /** + * 添加投递任务到队列 + * 这是外部调用的入口,会进行所有冲突检查 + */ + async addToQueue(sn_code, taskQueue, customParams = {}) { + const now = new Date(); + console.log(`[自动投递] ${now.toLocaleString()} 尝试为设备 ${sn_code} 添加任务`); + + try { + // 1. 获取账号信息 + const account = await this.getAccountInfo(sn_code); + if (!account) { + console.log(`[自动投递] 账号 ${sn_code} 不存在或未启用`); + return { success: false, reason: '账号不存在或未启用' }; + } + + // 2. 检查是否开启了自动投递 + if (!account.auto_deliver) { + console.log(`[自动投递] 设备 ${sn_code} 未开启自动投递`); + return { success: false, reason: '未开启自动投递' }; + } + + // 3. 获取投递配置 + const deliverConfig = this.parseDeliverConfig(account.deliver_config); + + // 4. 检查时间范围 + if (deliverConfig.time_range) { + const timeCheck = this.checkTimeRange(deliverConfig.time_range); + if (!timeCheck.allowed) { + console.log(`[自动投递] 设备 ${sn_code} ${timeCheck.reason}`); + return { success: false, reason: timeCheck.reason }; + } + } + + // 5. 执行所有层级的冲突检查 + const conflictCheck = await this.canExecuteTask(sn_code, taskQueue); + if (!conflictCheck.allowed) { + return { success: false, reason: conflictCheck.reason }; + } + + // 6. 检查投递间隔 + const intervalCheck = await this.checkExecutionInterval( + sn_code, + deliverConfig.deliver_interval + ); + + if (!intervalCheck.allowed) { + console.log(`[自动投递] 设备 ${sn_code} ${intervalCheck.reason}`); + + // 推送等待状态到客户端 + await this.notifyWaitingStatus(sn_code, intervalCheck, taskQueue); + + return { success: false, reason: intervalCheck.reason }; + } + + // 7. 构建任务参数 + const taskParams = { + keyword: account.keyword || '', + platform: account.platform_type || 'boss', + pageCount: deliverConfig.page_count, + maxCount: deliverConfig.max_deliver, + filterRules: { + minSalary: deliverConfig.min_salary, + maxSalary: deliverConfig.max_salary, + keywords: deliverConfig.filter_keywords, + excludeKeywords: deliverConfig.exclude_keywords + }, + ...customParams + }; + + // 8. 验证参数 + const validation = this.validateParams(taskParams); + if (!validation.valid) { + return { success: false, reason: validation.reason }; + } + + // 9. 添加任务到队列 + await taskQueue.addTask(sn_code, { + taskType: this.taskType, + taskName: this.getTaskName(taskParams), + taskParams: taskParams, + priority: this.config.defaultPriority + }); + + console.log(`[自动投递] 已为设备 ${sn_code} 添加投递任务,间隔: ${deliverConfig.deliver_interval} 分钟`); + + return { success: true }; + + } catch (error) { + console.error(`[自动投递] 添加任务失败:`, error); + return { success: false, reason: error.message }; + } finally { + // 统一释放任务锁 + this.releaseTaskLock(sn_code); + } + } + + /** + * 推送等待状态到客户端 + */ + async notifyWaitingStatus(sn_code, intervalCheck, taskQueue) { + try { + const deviceWorkStatusNotifier = require('../notifiers/deviceWorkStatusNotifier'); + + // 获取当前任务状态摘要 + const taskStatusSummary = taskQueue.getTaskStatusSummary(sn_code); + + // 添加等待消息到工作状态 + await deviceWorkStatusNotifier.sendDeviceWorkStatus(sn_code, taskStatusSummary, { + waitingMessage: { + type: 'deliver_interval', + message: intervalCheck.reason, + remainingMinutes: intervalCheck.remainingMinutes, + nextDeliverTime: intervalCheck.nextExecutionTime?.toISOString() + } + }); + } catch (error) { + console.warn(`[自动投递] 推送等待消息失败:`, error.message); + } + } +} + +// 导出单例 +module.exports = new AutoDeliverTask(); diff --git a/api/middleware/schedule/tasks/autoSearchTask.js b/api/middleware/schedule/tasks/autoSearchTask.js new file mode 100644 index 0000000..0e8a08e --- /dev/null +++ b/api/middleware/schedule/tasks/autoSearchTask.js @@ -0,0 +1,233 @@ +const BaseTask = require('./baseTask'); +const db = require('../../dbProxy'); +const config = require('../infrastructure/config'); + +/** + * 自动搜索职位任务 + * 定期搜索符合条件的职位并保存到数据库 + */ +class AutoSearchTask extends BaseTask { + constructor() { + super('auto_search', { + defaultInterval: 60, // 默认60分钟 + defaultPriority: 8, // 高优先级(比投递高,先搜索后投递) + requiresLogin: true, // 需要登录 + conflictsWith: [ // 与这些任务冲突 + 'auto_deliver', // 投递任务 + 'auto_active_account' // 活跃账号任务 + ] + }); + } + + /** + * 验证任务参数 + */ + validateParams(params) { + if (!params.keyword && !params.jobType) { + return { + valid: false, + reason: '缺少必要参数: keyword 或 jobType' + }; + } + + return { valid: true }; + } + + /** + * 获取任务名称 + */ + getTaskName(params) { + return `自动搜索 - ${params.keyword || params.jobType || '默认'}`; + } + + /** + * 执行自动搜索任务 + */ + async execute(sn_code, params) { + console.log(`[自动搜索] 设备 ${sn_code} 开始执行搜索任务`); + + // 1. 获取账号信息 + const account = await this.getAccountInfo(sn_code); + if (!account) { + throw new Error(`账号 ${sn_code} 不存在`); + } + + // 2. 获取搜索配置 + const searchConfig = this.parseSearchConfig(account.search_config); + + // 3. 检查日搜索限制 + const dailyLimit = config.dailyLimits.maxSearch || 20; + const todaySearched = await this.getTodaySearchCount(sn_code); + + if (todaySearched >= dailyLimit) { + throw new Error(`今日搜索已达上限 (${todaySearched}/${dailyLimit})`); + } + + // 4. 执行搜索(这里需要调用实际的搜索逻辑) + const searchResult = { + success: true, + keyword: params.keyword || account.keyword, + pageCount: searchConfig.page_count || 3, + jobsFound: 0, // 实际搜索到的职位数 + jobsSaved: 0 // 保存到数据库的职位数 + }; + + console.log(`[自动搜索] 设备 ${sn_code} 搜索完成,找到 ${searchResult.jobsFound} 个职位`); + + return searchResult; + } + + /** + * 获取账号信息 + */ + async getAccountInfo(sn_code) { + const { pla_account } = db.models; + const account = await pla_account.findOne({ + where: { + sn_code: sn_code, + is_delete: 0, + is_enabled: 1 + } + }); + + return account ? account.toJSON() : null; + } + + /** + * 解析搜索配置 + */ + parseSearchConfig(search_config) { + if (typeof search_config === 'string') { + try { + search_config = JSON.parse(search_config); + } catch (e) { + search_config = {}; + } + } + + return { + search_interval: search_config?.search_interval || 60, + page_count: search_config?.page_count || 3, + city: search_config?.city || '', + salary_range: search_config?.salary_range || '', + experience: search_config?.experience || '', + education: search_config?.education || '', + time_range: search_config?.time_range || null + }; + } + + /** + * 获取今日已搜索数量 + */ + async getTodaySearchCount(sn_code) { + const { task_status } = db.models; + const Sequelize = require('sequelize'); + + const today = new Date(); + today.setHours(0, 0, 0, 0); + + const count = await task_status.count({ + where: { + sn_code: sn_code, + taskType: 'auto_search', + status: 'completed', + endTime: { + [Sequelize.Op.gte]: today + } + } + }); + + return count; + } + + /** + * 添加搜索任务到队列 + */ + async addToQueue(sn_code, taskQueue, customParams = {}) { + const now = new Date(); + console.log(`[自动搜索] ${now.toLocaleString()} 尝试为设备 ${sn_code} 添加任务`); + + try { + // 1. 获取账号信息 + const account = await this.getAccountInfo(sn_code); + if (!account) { + console.log(`[自动搜索] 账号 ${sn_code} 不存在或未启用`); + return { success: false, reason: '账号不存在或未启用' }; + } + + // 2. 检查是否开启了自动搜索 + if (!account.auto_search) { + console.log(`[自动搜索] 设备 ${sn_code} 未开启自动搜索`); + return { success: false, reason: '未开启自动搜索' }; + } + + // 3. 获取搜索配置 + const searchConfig = this.parseSearchConfig(account.search_config); + + // 4. 检查时间范围 + if (searchConfig.time_range) { + const timeCheck = this.checkTimeRange(searchConfig.time_range); + if (!timeCheck.allowed) { + console.log(`[自动搜索] 设备 ${sn_code} ${timeCheck.reason}`); + return { success: false, reason: timeCheck.reason }; + } + } + + // 5. 执行所有层级的冲突检查 + const conflictCheck = await this.canExecuteTask(sn_code, taskQueue); + if (!conflictCheck.allowed) { + return { success: false, reason: conflictCheck.reason }; + } + + // 6. 检查搜索间隔 + const intervalCheck = await this.checkExecutionInterval( + sn_code, + searchConfig.search_interval + ); + + if (!intervalCheck.allowed) { + console.log(`[自动搜索] 设备 ${sn_code} ${intervalCheck.reason}`); + return { success: false, reason: intervalCheck.reason }; + } + + // 7. 构建任务参数 + const taskParams = { + keyword: account.keyword || '', + jobType: account.job_type || '', + platform: account.platform_type || 'boss', + pageCount: searchConfig.page_count || 3, + city: searchConfig.city || '', + salaryRange: searchConfig.salary_range || '', + ...customParams + }; + + // 8. 验证参数 + const validation = this.validateParams(taskParams); + if (!validation.valid) { + return { success: false, reason: validation.reason }; + } + + // 9. 添加任务到队列 + await taskQueue.addTask(sn_code, { + taskType: this.taskType, + taskName: this.getTaskName(taskParams), + taskParams: taskParams, + priority: this.config.defaultPriority + }); + + console.log(`[自动搜索] 已为设备 ${sn_code} 添加搜索任务,间隔: ${searchConfig.search_interval} 分钟`); + + return { success: true }; + + } catch (error) { + console.error(`[自动搜索] 添加任务失败:`, error); + return { success: false, reason: error.message }; + } finally { + // 统一释放任务锁 + this.releaseTaskLock(sn_code); + } + } +} + +// 导出单例 +module.exports = new AutoSearchTask(); diff --git a/api/middleware/schedule/tasks/baseTask.js b/api/middleware/schedule/tasks/baseTask.js new file mode 100644 index 0000000..4b4af44 --- /dev/null +++ b/api/middleware/schedule/tasks/baseTask.js @@ -0,0 +1,405 @@ +const dayjs = require('dayjs'); +const deviceManager = require('../core/deviceManager'); +const db = require('../../dbProxy'); + +/** + * 任务基类 + * 提供所有任务的通用功能和冲突检测机制 + */ +class BaseTask { + constructor(taskType, config = {}) { + this.taskType = taskType; + this.config = { + // 默认配置 + defaultInterval: 30, // 默认间隔30分钟 + defaultPriority: 5, + requiresLogin: true, // 是否需要登录状态 + conflictsWith: [], // 与哪些任务类型冲突 + ...config + }; + + // 任务执行锁 { sn_code: timestamp } + this.taskLocks = new Map(); + + // 最后执行时间缓存 { sn_code: timestamp } + this.lastExecutionCache = new Map(); + } + + /** + * Layer 1: 任务类型互斥锁检查 + * 防止同一设备同时添加相同类型的任务 + */ + acquireTaskLock(sn_code) { + const lockKey = `${sn_code}:${this.taskType}`; + const now = Date.now(); + const existingLock = this.taskLocks.get(lockKey); + + // 如果存在锁且未超时(5分钟),返回false + if (existingLock && (now - existingLock) < 5 * 60 * 1000) { + const remainingTime = Math.ceil((5 * 60 * 1000 - (now - existingLock)) / 1000); + return { + allowed: false, + reason: `任务 ${this.taskType} 正在添加中,请等待 ${remainingTime} 秒` + }; + } + + // 获取锁 + this.taskLocks.set(lockKey, now); + return { allowed: true }; + } + + /** + * 释放任务锁 + */ + releaseTaskLock(sn_code) { + const lockKey = `${sn_code}:${this.taskType}`; + this.taskLocks.delete(lockKey); + } + + /** + * Layer 2: 设备状态检查 + * 检查设备是否在线、是否登录、是否忙碌 + */ + async checkDeviceStatus(sn_code) { + // 1. 优先检查内存中的设备状态 + let device = deviceManager.devices.get(sn_code); + + // 2. 如果内存中没有,降级到数据库查询(可能是刚启动还没收到心跳) + if (!device) { + try { + const pla_account = db.getModel('pla_account'); + const dbDevice = await pla_account.findOne({ + where: { sn_code, is_delete: 0 }, + attributes: ['sn_code', 'is_online', 'is_logged_in'] + }); + + if (!dbDevice) { + return { + allowed: false, + reason: `设备 ${sn_code} 不存在` + }; + } + + // 检查数据库中的在线状态 + if (!dbDevice.is_online) { + return { + allowed: false, + reason: `设备 ${sn_code} 离线(数据库状态)` + }; + } + + // 检查数据库中的登录状态 + if (this.config.requiresLogin && !dbDevice.is_logged_in) { + return { + allowed: false, + reason: `设备 ${sn_code} 未登录平台账号(数据库状态)` + }; + } + + // 数据库检查通过,允许执行 + return { allowed: true }; + } catch (error) { + console.error(`[${this.taskType}] 查询设备状态失败:`, error); + return { + allowed: false, + reason: `设备 ${sn_code} 状态查询失败` + }; + } + } + + // 3. 检查心跳超时 + const offlineThreshold = 3 * 60 * 1000; // 3分钟 + const now = Date.now(); + const lastHeartbeat = device.lastHeartbeat || 0; + const isOnline = device.isOnline && (now - lastHeartbeat < offlineThreshold); + + if (!isOnline) { + const offlineMinutes = lastHeartbeat ? Math.round((now - lastHeartbeat) / (60 * 1000)) : '未知'; + return { + allowed: false, + reason: `设备 ${sn_code} 离线(最后心跳: ${offlineMinutes}分钟前)` + }; + } + + // 4. 检查登录状态(如果任务需要) + if (this.config.requiresLogin && !device.isLoggedIn) { + return { + allowed: false, + reason: `设备 ${sn_code} 未登录平台账号` + }; + } + + return { allowed: true }; + } + + /** + * Layer 3: 检查任务队列状态 + * 防止队列中已有相同任务 + */ + async checkTaskQueue(sn_code, taskQueue) { + // 获取设备队列 + const deviceQueue = taskQueue.deviceQueues.get(sn_code); + if (!deviceQueue) { + return { allowed: true }; + } + + // 检查队列中是否有相同类型的待执行任务 + const tasks = deviceQueue.toArray(); + const hasSameTypeTask = tasks.some(task => + task.taskType === this.taskType && + task.status === 'pending' + ); + + if (hasSameTypeTask) { + return { + allowed: false, + reason: `队列中已存在待执行的 ${this.taskType} 任务` + }; + } + + return { allowed: true }; + } + + /** + * Layer 4: 检查任务去重 + * 查询数据库中是否有重复的待执行任务 + */ + async checkDuplicateTask(sn_code) { + try { + const { task_status } = db.models; + + // 查询该设备是否有相同类型的pending/running任务 + const existingTask = await task_status.findOne({ + where: { + sn_code: sn_code, + taskType: this.taskType, + status: ['pending', 'running'] + }, + attributes: ['id', 'status', 'taskName'] + }); + + if (existingTask) { + return { + allowed: false, + reason: `已存在 ${existingTask.status} 状态的任务: ${existingTask.taskName}` + }; + } + + return { allowed: true }; + } catch (error) { + console.error(`[${this.taskType}] 检查重复任务失败:`, error); + // 出错时允许继续,避免阻塞 + return { allowed: true }; + } + } + + /** + * Layer 5: 操作类型冲突检测 + * 某些操作类型不能同时执行 + */ + async checkOperationConflict(sn_code, taskQueue) { + // 如果没有配置冲突类型,直接通过 + if (!this.config.conflictsWith || this.config.conflictsWith.length === 0) { + return { allowed: true }; + } + + // 检查当前是否有冲突的任务正在执行 + const deviceStatus = taskQueue.deviceStatus.get(sn_code); + if (deviceStatus && deviceStatus.currentTask) { + const currentTaskType = deviceStatus.currentTask.taskType; + + if (this.config.conflictsWith.includes(currentTaskType)) { + return { + allowed: false, + reason: `与正在执行的任务 ${currentTaskType} 冲突` + }; + } + } + + return { allowed: true }; + } + + /** + * 检查执行间隔 + * 从数据库查询上次成功执行时间,判断是否满足间隔要求 + */ + async checkExecutionInterval(sn_code, intervalMinutes) { + try { + const { task_status } = db.models; + + // 先从缓存检查 + const cachedLastExecution = this.lastExecutionCache.get(sn_code); + const now = Date.now(); + + if (cachedLastExecution) { + const elapsedTime = now - cachedLastExecution; + const interval_ms = intervalMinutes * 60 * 1000; + + if (elapsedTime < interval_ms) { + const remainingMinutes = Math.ceil((interval_ms - elapsedTime) / (60 * 1000)); + const elapsedMinutes = Math.round(elapsedTime / (60 * 1000)); + return { + allowed: false, + reason: `距离上次执行仅 ${elapsedMinutes} 分钟,还需等待 ${remainingMinutes} 分钟(间隔: ${intervalMinutes} 分钟)`, + remainingMinutes, + elapsedMinutes + }; + } + } + + // 从数据库查询最近一次成功完成的任务 + const lastTask = await task_status.findOne({ + where: { + sn_code: sn_code, + taskType: this.taskType, + status: 'completed' + }, + order: [['endTime', 'DESC']], + attributes: ['endTime'] + }); + + // 如果存在上次执行记录,检查是否已经过了间隔时间 + if (lastTask && lastTask.endTime) { + const lastExecutionTime = new Date(lastTask.endTime).getTime(); + const elapsedTime = now - lastExecutionTime; + const interval_ms = intervalMinutes * 60 * 1000; + + // 更新缓存 + this.lastExecutionCache.set(sn_code, lastExecutionTime); + + if (elapsedTime < interval_ms) { + const remainingMinutes = Math.ceil((interval_ms - elapsedTime) / (60 * 1000)); + const elapsedMinutes = Math.round(elapsedTime / (60 * 1000)); + return { + allowed: false, + reason: `距离上次执行仅 ${elapsedMinutes} 分钟,还需等待 ${remainingMinutes} 分钟(间隔: ${intervalMinutes} 分钟)`, + remainingMinutes, + elapsedMinutes, + nextExecutionTime: new Date(lastExecutionTime + interval_ms) + }; + } + } + + return { allowed: true }; + } catch (error) { + console.error(`[${this.taskType}] 检查执行间隔失败:`, error); + // 出错时允许继续,避免阻塞 + return { allowed: true }; + } + } + + /** + * 检查时间范围限制 + * @param {Object} timeRange - 时间范围配置 {start_time: '09:00', end_time: '18:00', workdays_only: 1} + */ + checkTimeRange(timeRange) { + if (!timeRange || !timeRange.start_time || !timeRange.end_time) { + return { allowed: true, reason: '未配置时间范围' }; + } + + const now = new Date(); + const currentHour = now.getHours(); + const currentMinute = now.getMinutes(); + const currentTime = currentHour * 60 + currentMinute; + + // 解析开始时间和结束时间 + const [startHour, startMinute] = timeRange.start_time.split(':').map(Number); + const [endHour, endMinute] = timeRange.end_time.split(':').map(Number); + const startTime = startHour * 60 + startMinute; + const endTime = endHour * 60 + endMinute; + + // 检查是否仅工作日 + if (timeRange.workdays_only == 1) { + const dayOfWeek = now.getDay(); + if (dayOfWeek === 0 || dayOfWeek === 6) { + return { allowed: false, reason: '当前是周末,不在允许的时间范围内' }; + } + } + + // 检查当前时间是否在时间范围内 + if (startTime <= endTime) { + // 正常情况: 09:00 - 18:00 + if (currentTime < startTime || currentTime >= endTime) { + return { + allowed: false, + reason: `当前时间不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` + }; + } + } else { + // 跨天情况: 22:00 - 06:00 + if (currentTime < startTime && currentTime >= endTime) { + return { + allowed: false, + reason: `当前时间不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` + }; + } + } + + return { allowed: true, reason: '在允许的时间范围内' }; + } + + /** + * 综合检查 - 执行所有层级的检查 + * @param {string} sn_code - 设备SN码 + * @param {Object} taskQueue - 任务队列实例 + * @param {Object} options - 额外选项 + * @returns {Object} { allowed: boolean, reason: string } + */ + async canExecuteTask(sn_code, taskQueue, options = {}) { + const checks = [ + { name: 'Layer1-任务锁', fn: () => this.acquireTaskLock(sn_code) }, + { name: 'Layer2-设备状态', fn: () => this.checkDeviceStatus(sn_code) }, + { name: 'Layer3-队列检查', fn: () => this.checkTaskQueue(sn_code, taskQueue) }, + { name: 'Layer4-任务去重', fn: () => this.checkDuplicateTask(sn_code) }, + { name: 'Layer5-操作冲突', fn: () => this.checkOperationConflict(sn_code, taskQueue) } + ]; + + // 逐层检查 + for (const check of checks) { + const result = await check.fn(); + if (!result.allowed) { + console.log(`[${this.taskType}] ${check.name} 未通过: ${result.reason}`); + return result; + } + } + + return { allowed: true }; + } + + /** + * 清理任务锁(定期清理过期锁) + */ + cleanupExpiredLocks() { + const now = Date.now(); + const timeout = 5 * 60 * 1000; // 5分钟超时 + + for (const [lockKey, timestamp] of this.taskLocks.entries()) { + if (now - timestamp > timeout) { + this.taskLocks.delete(lockKey); + } + } + } + + /** + * 获取任务名称(子类可覆盖) + */ + getTaskName(params) { + return `${this.taskType} 任务`; + } + + /** + * 验证任务参数(子类必须实现) + */ + validateParams(params) { + throw new Error('子类必须实现 validateParams 方法'); + } + + /** + * 执行任务的具体逻辑(子类必须实现) + */ + async execute(sn_code, params) { + throw new Error('子类必须实现 execute 方法'); + } +} + +module.exports = BaseTask; diff --git a/api/middleware/schedule/tasks/index.js b/api/middleware/schedule/tasks/index.js new file mode 100644 index 0000000..a826747 --- /dev/null +++ b/api/middleware/schedule/tasks/index.js @@ -0,0 +1,16 @@ +/** + * 任务模块索引 + * 统一导出所有任务类型 + */ + +const autoSearchTask = require('./autoSearchTask'); +const autoDeliverTask = require('./autoDeliverTask'); +const autoChatTask = require('./autoChatTask'); +const autoActiveTask = require('./autoActiveTask'); + +module.exports = { + autoSearchTask, + autoDeliverTask, + autoChatTask, + autoActiveTask +}; diff --git a/api/middleware/schedule/utils/index.js b/api/middleware/schedule/utils/index.js new file mode 100644 index 0000000..2ae20fb --- /dev/null +++ b/api/middleware/schedule/utils/index.js @@ -0,0 +1,14 @@ +/** + * Utils 模块导出 + * 统一导出工具类模块 + */ + +const SalaryParser = require('./salaryParser'); +const KeywordMatcher = require('./keywordMatcher'); +const ScheduleUtils = require('./scheduleUtils'); + +module.exports = { + SalaryParser, + KeywordMatcher, + ScheduleUtils +}; diff --git a/api/middleware/schedule/utils/keywordMatcher.js b/api/middleware/schedule/utils/keywordMatcher.js new file mode 100644 index 0000000..11c579d --- /dev/null +++ b/api/middleware/schedule/utils/keywordMatcher.js @@ -0,0 +1,225 @@ +/** + * 关键词匹配工具 + * 提供职位描述的关键词匹配和评分功能 + */ +class KeywordMatcher { + /** + * 检查是否包含排除关键词 + * @param {string} text - 待检查的文本 + * @param {string[]} excludeKeywords - 排除关键词列表 + * @returns {{matched: boolean, keywords: string[]}} 匹配结果 + */ + static matchExcludeKeywords(text, excludeKeywords = []) { + if (!text || !excludeKeywords || excludeKeywords.length === 0) { + return { matched: false, keywords: [] }; + } + + const matched = []; + const lowerText = text.toLowerCase(); + + for (const keyword of excludeKeywords) { + if (!keyword || !keyword.trim()) continue; + + const lowerKeyword = keyword.toLowerCase().trim(); + if (lowerText.includes(lowerKeyword)) { + matched.push(keyword); + } + } + + return { + matched: matched.length > 0, + keywords: matched + }; + } + + /** + * 检查是否包含过滤关键词(必须匹配) + * @param {string} text - 待检查的文本 + * @param {string[]} filterKeywords - 过滤关键词列表 + * @returns {{matched: boolean, keywords: string[], matchCount: number}} 匹配结果 + */ + static matchFilterKeywords(text, filterKeywords = []) { + if (!text) { + return { matched: false, keywords: [], matchCount: 0 }; + } + + if (!filterKeywords || filterKeywords.length === 0) { + return { matched: true, keywords: [], matchCount: 0 }; + } + + const matched = []; + const lowerText = text.toLowerCase(); + + for (const keyword of filterKeywords) { + if (!keyword || !keyword.trim()) continue; + + const lowerKeyword = keyword.toLowerCase().trim(); + if (lowerText.includes(lowerKeyword)) { + matched.push(keyword); + } + } + + // 只要匹配到至少一个过滤关键词即可通过 + return { + matched: matched.length > 0, + keywords: matched, + matchCount: matched.length + }; + } + + /** + * 计算关键词匹配奖励分数 + * @param {string} text - 待检查的文本 + * @param {string[]} keywords - 关键词列表 + * @param {object} options - 选项 + * @returns {{score: number, matchedKeywords: string[], matchCount: number}} + */ + static calculateBonus(text, keywords = [], options = {}) { + const { + baseScore = 10, // 每个关键词的基础分 + maxBonus = 50, // 最大奖励分 + caseSensitive = false // 是否区分大小写 + } = options; + + if (!text || !keywords || keywords.length === 0) { + return { score: 0, matchedKeywords: [], matchCount: 0 }; + } + + const matched = []; + const searchText = caseSensitive ? text : text.toLowerCase(); + + for (const keyword of keywords) { + if (!keyword || !keyword.trim()) continue; + + const searchKeyword = caseSensitive ? keyword.trim() : keyword.toLowerCase().trim(); + if (searchText.includes(searchKeyword)) { + matched.push(keyword); + } + } + + const score = Math.min(matched.length * baseScore, maxBonus); + + return { + score, + matchedKeywords: matched, + matchCount: matched.length + }; + } + + /** + * 高亮匹配的关键词(用于展示) + * @param {string} text - 原始文本 + * @param {string[]} keywords - 关键词列表 + * @param {string} prefix - 前缀标记(默认 ) + * @param {string} suffix - 后缀标记(默认 ) + * @returns {string} 高亮后的文本 + */ + static highlight(text, keywords = [], prefix = '', suffix = '') { + if (!text || !keywords || keywords.length === 0) { + return text; + } + + let result = text; + + for (const keyword of keywords) { + if (!keyword || !keyword.trim()) continue; + + const regex = new RegExp(`(${this.escapeRegex(keyword.trim())})`, 'gi'); + result = result.replace(regex, `${prefix}$1${suffix}`); + } + + return result; + } + + /** + * 转义正则表达式特殊字符 + * @param {string} str - 待转义的字符串 + * @returns {string} 转义后的字符串 + */ + static escapeRegex(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + + /** + * 综合匹配(排除 + 过滤 + 奖励) + * @param {string} text - 待检查的文本 + * @param {object} config - 配置 + * @param {string[]} config.excludeKeywords - 排除关键词 + * @param {string[]} config.filterKeywords - 过滤关键词 + * @param {string[]} config.bonusKeywords - 奖励关键词 + * @returns {{pass: boolean, reason?: string, score: number, details: object}} + */ + static match(text, config = {}) { + const { + excludeKeywords = [], + filterKeywords = [], + bonusKeywords = [] + } = config; + + // 1. 检查排除关键词 + const excludeResult = this.matchExcludeKeywords(text, excludeKeywords); + if (excludeResult.matched) { + return { + pass: false, + reason: `包含排除关键词: ${excludeResult.keywords.join(', ')}`, + score: 0, + details: { exclude: excludeResult } + }; + } + + // 2. 检查过滤关键词(必须匹配) + const filterResult = this.matchFilterKeywords(text, filterKeywords); + if (filterKeywords.length > 0 && !filterResult.matched) { + return { + pass: false, + reason: '不包含任何必需关键词', + score: 0, + details: { filter: filterResult } + }; + } + + // 3. 计算奖励分数 + const bonusResult = this.calculateBonus(text, bonusKeywords); + + return { + pass: true, + score: bonusResult.score, + details: { + exclude: excludeResult, + filter: filterResult, + bonus: bonusResult + } + }; + } + + /** + * 批量匹配职位列表 + * @param {Array} jobs - 职位列表 + * @param {object} config - 匹配配置 + * @param {Function} textExtractor - 文本提取函数 (job) => string + * @returns {Array} 匹配通过的职位(带匹配信息) + */ + static filterJobs(jobs, config, textExtractor = (job) => `${job.name || ''} ${job.description || ''}`) { + if (!jobs || jobs.length === 0) { + return []; + } + + const filtered = []; + + for (const job of jobs) { + const text = textExtractor(job); + const matchResult = this.match(text, config); + + if (matchResult.pass) { + filtered.push({ + ...job, + _matchInfo: matchResult + }); + } + } + + return filtered; + } +} + +module.exports = KeywordMatcher; diff --git a/api/middleware/schedule/utils/salaryParser.js b/api/middleware/schedule/utils/salaryParser.js new file mode 100644 index 0000000..44f1836 --- /dev/null +++ b/api/middleware/schedule/utils/salaryParser.js @@ -0,0 +1,126 @@ +/** + * 薪资解析工具 + * 统一处理职位薪资和期望薪资的解析逻辑 + */ +class SalaryParser { + /** + * 解析薪资范围字符串 + * @param {string} salaryDesc - 薪资描述 (如 "15-20K", "8000-12000元") + * @returns {{ min: number, max: number }} 薪资范围(单位:元) + */ + static parse(salaryDesc) { + if (!salaryDesc || typeof salaryDesc !== 'string') { + return { min: 0, max: 0 }; + } + + // 尝试各种格式 + return this.parseK(salaryDesc) + || this.parseYuan(salaryDesc) + || this.parseMixed(salaryDesc) + || { min: 0, max: 0 }; + } + + /** + * 解析 K 格式薪资 (如 "15-20K", "8-12k") + */ + static parseK(desc) { + const kMatch = desc.match(/(\d+)[-~](\d+)[kK千]/); + if (kMatch) { + return { + min: parseInt(kMatch[1]) * 1000, + max: parseInt(kMatch[2]) * 1000 + }; + } + return null; + } + + /** + * 解析元格式薪资 (如 "8000-12000元", "15000-20000") + */ + static parseYuan(desc) { + const yuanMatch = desc.match(/(\d+)[-~](\d+)元?/); + if (yuanMatch) { + return { + min: parseInt(yuanMatch[1]), + max: parseInt(yuanMatch[2]) + }; + } + return null; + } + + /** + * 解析混合格式 (如 "8k-12000元") + */ + static parseMixed(desc) { + const mixedMatch = desc.match(/(\d+)[kK千][-~](\d+)元?/); + if (mixedMatch) { + return { + min: parseInt(mixedMatch[1]) * 1000, + max: parseInt(mixedMatch[2]) + }; + } + return null; + } + + /** + * 检查职位薪资是否在期望范围内 + * @param {object} jobSalary - 职位薪资 { min, max } + * @param {number} minExpected - 期望最低薪资 + * @param {number} maxExpected - 期望最高薪资 + */ + static isWithinRange(jobSalary, minExpected, maxExpected) { + if (!jobSalary || jobSalary.min === 0) { + return true; // 无法判断时默认通过 + } + + // 职位最高薪资 >= 期望最低薪资 + if (minExpected > 0 && jobSalary.max < minExpected) { + return false; + } + + // 职位最低薪资 <= 期望最高薪资 + if (maxExpected > 0 && jobSalary.min > maxExpected) { + return false; + } + + return true; + } + + /** + * 计算薪资匹配度(用于职位评分) + * @param {object} jobSalary - 职位薪资 + * @param {object} expectedSalary - 期望薪资 + * @returns {number} 匹配度 0-1 + */ + static calculateMatch(jobSalary, expectedSalary) { + if (!jobSalary || !expectedSalary || jobSalary.min === 0 || expectedSalary.min === 0) { + return 0.5; // 无法判断时返回中性值 + } + + const jobAvg = (jobSalary.min + jobSalary.max) / 2; + const expectedAvg = (expectedSalary.min + expectedSalary.max) / 2; + + const diff = Math.abs(jobAvg - expectedAvg); + const range = (jobSalary.max - jobSalary.min + expectedSalary.max - expectedSalary.min) / 2; + + // 差距越小,匹配度越高 + return Math.max(0, 1 - diff / (range || 1)); + } + + /** + * 格式化薪资显示 + * @param {object} salary - 薪资对象 { min, max } + * @returns {string} 格式化字符串 + */ + static format(salary) { + if (!salary || salary.min === 0) { + return '面议'; + } + + const minK = (salary.min / 1000).toFixed(0); + const maxK = (salary.max / 1000).toFixed(0); + return `${minK}-${maxK}K`; + } +} + +module.exports = SalaryParser; diff --git a/api/middleware/schedule/utils.js b/api/middleware/schedule/utils/scheduleUtils.js similarity index 100% rename from api/middleware/schedule/utils.js rename to api/middleware/schedule/utils/scheduleUtils.js diff --git a/api/model/pla_account.js b/api/model/pla_account.js index e55ba45..9975644 100644 --- a/api/model/pla_account.js +++ b/api/model/pla_account.js @@ -79,20 +79,20 @@ module.exports = (db) => { get: function () { const value = this.getDataValue('is_salary_priority'); if (!value) { - return [{ "key": "distance", "weight": 50 }, { "key": "salary", "weight": 20 }, { "key": "work_years", "weight": 10 }, { "key": "education", "weight": 20}]; + return [{ "key": "distance", "weight": 50 }, { "key": "salary", "weight": 20 }, { "key": "work_years", "weight": 10 }, { "key": "education", "weight": 20 }]; } if (typeof value === 'string') { try { return JSON.parse(value); } catch (e) { - return [{ "key": "distance", "weight": 50 }, { "key": "salary", "weight": 20 }, { "key": "work_years", "weight": 10 }, { "key": "education", "weight": 20}]; + return [{ "key": "distance", "weight": 50 }, { "key": "salary", "weight": 20 }, { "key": "work_years", "weight": 10 }, { "key": "education", "weight": 20 }]; } } return value; }, set: function (value) { if (value === null || value === undefined) { - this.setDataValue('is_salary_priority', JSON.stringify([{ "key": "distance", "weight": 50 }, { "key": "salary", "weight": 20 }, { "key": "work_years", "weight": 10 }, { "key": "education", "weight": 20}])); + this.setDataValue('is_salary_priority', JSON.stringify([{ "key": "distance", "weight": 50 }, { "key": "salary", "weight": 20 }, { "key": "work_years", "weight": 10 }, { "key": "education", "weight": 20 }])); } else if (typeof value === 'string') { // 如果已经是字符串,直接使用 this.setDataValue('is_salary_priority', value); @@ -101,7 +101,7 @@ module.exports = (db) => { this.setDataValue('is_salary_priority', JSON.stringify(value)); } }, - defaultValue: JSON.stringify([{ "key": "distance", "weight": 50 }, { "key": "salary", "weight": 20 }, { "key": "work_years", "weight": 10 }, { "key": "education", "weight": 20}]) + defaultValue: JSON.stringify([{ "key": "distance", "weight": 50 }, { "key": "salary", "weight": 20 }, { "key": "work_years", "weight": 10 }, { "key": "education", "weight": 20 }]) }, @@ -185,6 +185,57 @@ module.exports = (db) => { exclude_keywords: [] }) }, + // 自动搜索相关配置 + auto_search: { + comment: '自动搜索开关', + type: Sequelize.TINYINT(1), + allowNull: false, + defaultValue: 0 + }, + // 自动搜索配置(JSON格式,包含:search_interval-搜索间隔分钟数, page_count-滚动获取职位列表次数, city-城市, time_range-搜索时间段) + search_config: { + comment: '自动搜索配置(JSON对象)', + type: Sequelize.JSON(), + allowNull: true, + get: function () { + const value = this.getDataValue('search_config'); + if (!value) return null; + if (typeof value === 'string') { + try { + return JSON.parse(value); + } catch (e) { + return null; + } + } + return value; + }, + set: function (value) { + if (value === null || value === undefined) { + this.setDataValue('search_config', null); + } else if (typeof value === 'string') { + // 如果已经是字符串,直接使用 + this.setDataValue('search_config', value); + } else { + // 如果是对象,序列化为字符串 + this.setDataValue('search_config', JSON.stringify(value)); + } + }, + // 默认值说明: + // city: '' - 城市,默认空字符串 + // cityName: '' - 城市名称,默认空字符串 + // salary: '' - 薪资,默认空字符串 + // experience: '' - 经验,默认空字符串 + // education: '' - 学历,默认空字符串 + + defaultValue: JSON.stringify({ + search_interval: 30, + city: '', + cityName: '', + salary: '', + experience: '', + education: '' + }) + }, // 自动沟通相关配置 auto_chat: { comment: '自动沟通开关', @@ -237,7 +288,7 @@ module.exports = (db) => { } }) }, - + // 自动活跃相关配置 auto_active: { comment: '自动活跃开关', diff --git a/api/services/index.js b/api/services/index.js index c9f9c62..6113a7c 100644 --- a/api/services/index.js +++ b/api/services/index.js @@ -112,7 +112,5 @@ module.exports = { // 导出各个服务类 AIService, PlaAccountService - // TaskScheduler 已废弃 - // MQTTHandler 文件不存在 - // JobService 已合并到 middleware/job/jobManager.js + }; diff --git a/api/services/pla_account_service.js b/api/services/pla_account_service.js index a6deb6e..5436a82 100644 --- a/api/services/pla_account_service.js +++ b/api/services/pla_account_service.js @@ -5,7 +5,7 @@ const db = require('../middleware/dbProxy'); const scheduleManager = require('../middleware/schedule/index.js'); -const locationService = require('./locationService'); +const locationService = require('./location_service'); const authorizationService = require('./authorization_service'); const { addRemainingDays, addRemainingDaysToAccounts } = require('../utils/account_utils'); @@ -680,13 +680,120 @@ class PlaAccountService { } }); + const taskId = await scheduleManager.taskQueue.addTask(account.sn_code, { + taskType: taskType, + taskName: `手动任务 - ${taskName}`, + taskParams: { + keyword: account.keyword, + platform: account.platform_type + } + }); + return { message: '任务已添加到队列', - taskId: task.id + taskId: taskId }; + } - - + /** + * 创建搜索职位列表任务(支持可选投递) + * @param {Object} params - 任务参数 + * @param {number} params.id - 账号ID + * @param {string} params.keyword - 搜索关键词 + * @param {Object} params.searchParams - 搜索条件(城市、薪资、经验、学历等) + * @param {number} params.pageCount - 获取页数 + * @param {boolean} params.autoDeliver - 是否自动投递(默认false) + * @param {Object} params.filterRules - 过滤规则(autoDeliver=true时使用) + * @param {number} params.maxCount - 最大投递数量(autoDeliver=true时使用) + * @returns {Promise} 任务创建结果 { taskId, message, jobCount, deliveredCount } + */ + async createSearchJobListTask(params) { + const pla_account = db.getModel('pla_account'); + const task_status = db.getModel('task_status'); + + const { + id, + keyword, + searchParams = {}, + pageCount = 3, + autoDeliver = false, + filterRules = {}, + maxCount = 10 + } = params; + + // 1. 验证账号和授权 + if (!id) { + throw new Error('账号ID不能为空'); + } + + const account = await pla_account.findByPk(id); + if (!account) { + throw new Error('账号不存在'); + } + + // 检查账号是否启用 + if (!account.is_enabled) { + throw new Error('账号未启用,无法执行任务'); + } + + // 检查授权状态 + const authCheck = await authorizationService.checkAuthorization(id, 'id'); + if (!authCheck.is_authorized) { + throw new Error(authCheck.message); + } + + // 检查MQTT客户端 + if (!scheduleManager.mqttClient) { + throw new Error('MQTT客户端未初始化'); + } + + const sn_code = account.sn_code; + const platform = account.platform_type || 'boss'; + + // 2. 创建任务记录(使用新的搜索任务类型) + const taskType = 'search_jobs'; + const taskName = autoDeliver ? '搜索并投递职位' : '搜索职位列表'; + + const task = await task_status.create({ + sn_code: sn_code, + taskType: taskType, + taskName: taskName, + taskParams: JSON.stringify({ + keyword: keyword || account.keyword || '', + searchParams: searchParams, + pageCount: pageCount, + autoDeliver: autoDeliver, + filterRules: filterRules, + maxCount: maxCount, + platform: platform + }), + status: 'pending', + progress: 0 + }); + + console.log(`[账号服务] 创建搜索任务: ${taskName} (ID: ${task.id}, 设备: ${sn_code})`); + + // 3. 将任务添加到队列,由 handleSearchJobListTask 处理 + const taskId = await scheduleManager.taskQueue.addTask(sn_code, { + taskType: taskType, + taskName: taskName, + taskParams: { + keyword: keyword || account.keyword || '', + searchParams: searchParams, + pageCount: pageCount, + autoDeliver: autoDeliver, + filterRules: filterRules, + maxCount: maxCount, + platform: platform + } + }); + + return { + taskId: taskId, + message: `搜索任务已创建,任务ID: ${taskId}`, + jobCount: 0, + deliveredCount: 0 + }; } /** diff --git a/app/assets/delivery_config-BjklYJQ0.js b/app/assets/delivery_config-BjklYJQ0.js deleted file mode 100644 index a9d8131..0000000 --- a/app/assets/delivery_config-BjklYJQ0.js +++ /dev/null @@ -1 +0,0 @@ -import{a as t}from"./index-CsHwYKwf.js";class s{async getConfig(r){try{return await t.post("/user/delivery-config/get",{sn_code:r})}catch(e){throw console.error("获取投递配置失败:",e),e}}async saveConfig(r,e){try{return await t.post("/user/delivery-config/save",{sn_code:r,deliver_config:e})}catch(o){throw console.error("保存投递配置失败:",o),o}}}const i=new s;export{i as default}; diff --git a/app/assets/index-BUzIVj1g.css b/app/assets/index-BUzIVj1g.css deleted file mode 100644 index 5d2f951..0000000 --- a/app/assets/index-BUzIVj1g.css +++ /dev/null @@ -1 +0,0 @@ -.menu-item[data-v-ccec6c25]{display:block;text-decoration:none;color:inherit}.menu-item.router-link-active[data-v-ccec6c25],.menu-item.active[data-v-ccec6c25]{background-color:#4caf50;color:#fff}.update-content[data-v-dd11359a]{padding:10px 0}.update-info[data-v-dd11359a]{margin-bottom:20px}.update-info p[data-v-dd11359a]{margin:8px 0}.release-notes[data-v-dd11359a]{margin-top:15px}.release-notes pre[data-v-dd11359a]{background:#f5f5f5;padding:10px;border-radius:4px;white-space:pre-wrap;word-break:break-word;font-size:13px;line-height:1.5}.update-progress[data-v-dd11359a]{margin-top:20px}.update-progress .progress-text[data-v-dd11359a]{margin-top:10px;text-align:center;font-size:13px;color:#666}.info-content[data-v-2d37d2c9]{padding:10px 0}.info-item[data-v-2d37d2c9]{display:flex;align-items:center;margin-bottom:15px}.info-item label[data-v-2d37d2c9]{font-weight:600;color:#333;min-width:100px;margin-right:10px}.info-item span[data-v-2d37d2c9]{color:#666;flex:1}.info-item span.text-error[data-v-2d37d2c9]{color:#f44336}.info-item span.text-warning[data-v-2d37d2c9]{color:#ff9800}.settings-content[data-v-daae3f81]{padding:10px 0}.settings-section[data-v-daae3f81]{margin-bottom:25px}.settings-section[data-v-daae3f81]:last-child{margin-bottom:0}.section-title[data-v-daae3f81]{font-size:16px;font-weight:600;color:#333;margin:0 0 15px;padding-bottom:10px;border-bottom:1px solid #eee}.setting-item[data-v-daae3f81]{display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-bottom:1px solid #f5f5f5}.setting-item[data-v-daae3f81]:last-child{border-bottom:none}.setting-item label[data-v-daae3f81]{font-size:14px;color:#333;font-weight:500}.user-menu[data-v-f94e136c]{position:relative;z-index:1000}.user-info[data-v-f94e136c]{display:flex;align-items:center;gap:8px;padding:8px 15px;background:#fff3;border-radius:20px;cursor:pointer;transition:all .3s ease;color:#fff;font-size:14px}.user-info[data-v-f94e136c]:hover{background:#ffffff4d}.user-name[data-v-f94e136c]{font-weight:500}.dropdown-icon[data-v-f94e136c]{font-size:10px;transition:transform .3s ease}.user-info:hover .dropdown-icon[data-v-f94e136c]{transform:rotate(180deg)}.user-menu-dropdown[data-v-f94e136c]{position:absolute;top:calc(100% + 8px);right:0;background:#fff;border-radius:8px;box-shadow:0 4px 12px #00000026;min-width:160px;overflow:hidden;animation:slideDown-f94e136c .2s ease}@keyframes slideDown-f94e136c{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.menu-item[data-v-f94e136c]{display:flex;align-items:center;gap:10px;padding:12px 16px;cursor:pointer;transition:background .2s ease;color:#333;font-size:14px}.menu-item[data-v-f94e136c]:hover{background:#f5f5f5}.menu-icon[data-v-f94e136c]{font-size:16px}.menu-text[data-v-f94e136c]{flex:1}.menu-divider[data-v-f94e136c]{height:1px;background:#e0e0e0;margin:4px 0}.content-area.full-width.login-page[data-v-84f95a09]{padding:0;background:transparent;border-radius:0;box-shadow:none}.page-login[data-v-b5ae25b5]{position:fixed;top:0;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,#667eea,#764ba2);padding:20px;overflow:auto}.login-container[data-v-b5ae25b5]{background:#fff;border-radius:12px;box-shadow:0 10px 40px #00000026;width:100%;max-width:420px;padding:40px;box-sizing:border-box}.login-header[data-v-b5ae25b5]{text-align:center;margin-bottom:30px}.login-header h1[data-v-b5ae25b5]{font-size:28px;font-weight:600;color:#333;margin:0 0 10px}.login-header .login-subtitle[data-v-b5ae25b5]{font-size:14px;color:#666;margin:0}.login-form .form-group[data-v-b5ae25b5]{margin-bottom:20px}.login-form .form-group .form-label[data-v-b5ae25b5]{display:block;margin-bottom:8px;font-size:14px;color:#333;font-weight:500}.login-form .form-group[data-v-b5ae25b5] .p-inputtext{width:100%;padding:12px 16px;border:1px solid #ddd;border-radius:6px;font-size:14px;transition:border-color .3s,box-shadow .3s}.login-form .form-group[data-v-b5ae25b5] .p-inputtext:enabled:hover{border-color:#667eea}.login-form .form-group[data-v-b5ae25b5] .p-inputtext:enabled:focus{outline:none;border-color:#667eea;box-shadow:0 0 0 .2rem #667eea40}.login-form .form-group[data-v-b5ae25b5] .p-inputtext::placeholder{color:#999}.login-form .form-options[data-v-b5ae25b5]{margin-bottom:24px}.login-form .form-options .remember-me[data-v-b5ae25b5]{display:flex;align-items:center;gap:8px;font-size:14px;color:#666}.login-form .form-options .remember-me .remember-label[data-v-b5ae25b5]{cursor:pointer;-webkit-user-select:none;user-select:none}.login-form .form-actions[data-v-b5ae25b5] .p-button{width:100%;padding:12px;background:linear-gradient(135deg,#667eea,#764ba2);border:none;border-radius:6px;font-size:15px;font-weight:500;transition:transform .2s,box-shadow .3s}.login-form .form-actions[data-v-b5ae25b5] .p-button:enabled:hover{background:linear-gradient(135deg,#5568d3,#653a8b);transform:translateY(-2px);box-shadow:0 4px 12px #667eea66}.login-form .form-actions[data-v-b5ae25b5] .p-button:enabled:active{transform:translateY(0)}.login-form .error-message[data-v-b5ae25b5]{margin-bottom:20px}@media (max-width: 480px){.page-login[data-v-b5ae25b5]{padding:15px}.login-container[data-v-b5ae25b5]{padding:30px 20px}.login-header h1[data-v-b5ae25b5]{font-size:24px}}.settings-section[data-v-7fa19e94]{margin-bottom:30px}.page-title[data-v-7fa19e94]{font-size:20px;font-weight:600;margin-bottom:20px;color:#333}.settings-form-horizontal[data-v-7fa19e94]{background:#fff;border:1px solid #e0e0e0;border-radius:8px;padding:20px;box-shadow:0 2px 4px #0000000d}.form-row[data-v-7fa19e94]{display:flex;align-items:center;gap:20px;flex-wrap:wrap}.form-item[data-v-7fa19e94]{display:flex;align-items:center;gap:8px}.form-item .form-label[data-v-7fa19e94]{font-size:14px;color:#333;font-weight:500;white-space:nowrap}.form-item .form-input[data-v-7fa19e94]{padding:8px 12px;border:1px solid #ddd;border-radius:4px;font-size:14px}.form-item .form-input[data-v-7fa19e94]:focus{outline:none;border-color:#4caf50}.form-item .switch-label[data-v-7fa19e94]{font-size:14px;color:#666}@media (max-width: 768px){.form-row[data-v-7fa19e94]{flex-direction:column;align-items:stretch}.form-item[data-v-7fa19e94]{justify-content:space-between}}.delivery-trend-chart .chart-container[data-v-26c78ab7]{width:100%;overflow-x:auto}.delivery-trend-chart .chart-container canvas[data-v-26c78ab7]{display:block;max-width:100%}.delivery-trend-chart .chart-legend[data-v-26c78ab7]{display:flex;justify-content:space-around;padding:10px 0;border-top:1px solid #f0f0f0;margin-top:10px}.delivery-trend-chart .chart-legend .legend-item[data-v-26c78ab7]{display:flex;flex-direction:column;align-items:center;gap:4px}.delivery-trend-chart .chart-legend .legend-item .legend-date[data-v-26c78ab7]{font-size:11px;color:#999}.delivery-trend-chart .chart-legend .legend-item .legend-value[data-v-26c78ab7]{font-size:13px;font-weight:600;color:#4caf50}.page-console[data-v-100c009e]{padding:20px;height:100%;overflow-y:auto;background:#f5f5f5}.console-header[data-v-100c009e]{display:flex;justify-content:space-between;align-items:center;background:#fff;padding:15px 20px;border-radius:8px;box-shadow:0 2px 4px #0000000d;margin-bottom:20px}.header-left[data-v-100c009e]{flex:1;display:flex;align-items:center}.header-title-section[data-v-100c009e]{display:flex;align-items:center;gap:20px;flex-wrap:wrap}.header-title-section .page-title[data-v-100c009e]{margin:0;font-size:24px;font-weight:600;color:#333;white-space:nowrap}.delivery-settings-summary[data-v-100c009e]{display:flex;gap:20px;align-items:center;flex-wrap:wrap}.delivery-settings-summary .summary-item[data-v-100c009e]{display:flex;align-items:center;gap:6px;font-size:13px}.delivery-settings-summary .summary-item .summary-label[data-v-100c009e]{color:#666;white-space:nowrap}.delivery-settings-summary .summary-item .summary-value[data-v-100c009e]{font-weight:500;white-space:nowrap}.delivery-settings-summary .summary-item .summary-value.enabled[data-v-100c009e]{color:#4caf50}.delivery-settings-summary .summary-item .summary-value.disabled[data-v-100c009e]{color:#999}.header-right[data-v-100c009e]{display:flex;align-items:center;gap:20px}.quick-stats[data-v-100c009e]{display:flex;gap:20px;align-items:center}.quick-stat-item[data-v-100c009e]{display:flex;flex-direction:column;align-items:center;padding:8px 15px;background:#f9f9f9;border-radius:6px;min-width:60px}.quick-stat-item.highlight[data-v-100c009e]{background:#e8f5e9}.quick-stat-item .stat-label[data-v-100c009e]{font-size:12px;color:#666;margin-bottom:4px}.quick-stat-item .stat-value[data-v-100c009e]{font-size:20px;font-weight:600;color:#4caf50}.btn-settings[data-v-100c009e]{display:flex;align-items:center;gap:8px;padding:10px 20px;background:#4caf50;color:#fff;border:none;border-radius:6px;font-size:14px;cursor:pointer;transition:all .3s}.btn-settings[data-v-100c009e]:hover{background:#45a049}.btn-settings .settings-icon[data-v-100c009e]{font-size:16px}.settings-modal[data-v-100c009e]{position:fixed;top:0;left:0;right:0;bottom:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000;animation:fadeIn-100c009e .3s ease}@keyframes fadeIn-100c009e{0%{opacity:0}to{opacity:1}}.settings-modal-content[data-v-100c009e]{background:#fff;border-radius:8px;box-shadow:0 4px 20px #00000026;width:90%;max-width:600px;max-height:90vh;overflow-y:auto;animation:slideUp-100c009e .3s ease}@keyframes slideUp-100c009e{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}.modal-header[data-v-100c009e]{display:flex;justify-content:space-between;align-items:center;padding:20px;border-bottom:1px solid #f0f0f0}.modal-header .modal-title[data-v-100c009e]{margin:0;font-size:20px;font-weight:600;color:#333}.modal-header .btn-close[data-v-100c009e]{background:none;border:none;font-size:28px;color:#999;cursor:pointer;padding:0;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all .3s}.modal-header .btn-close[data-v-100c009e]:hover{background:#f5f5f5;color:#333}.modal-body[data-v-100c009e]{padding:20px}.modal-body .settings-section[data-v-100c009e]{margin-bottom:0}.modal-body .settings-section .page-title[data-v-100c009e]{display:none}.modal-body .settings-section .settings-form-horizontal[data-v-100c009e]{border:none;box-shadow:none;padding:0}.modal-body .settings-section .form-row[data-v-100c009e]{flex-direction:column;align-items:stretch;gap:15px}.modal-body .settings-section .form-item[data-v-100c009e]{justify-content:space-between;width:100%}.modal-body .settings-section .form-item .form-label[data-v-100c009e]{min-width:120px}.modal-body .settings-section .form-item .form-input[data-v-100c009e]{flex:1;max-width:300px}.modal-footer[data-v-100c009e]{display:flex;justify-content:flex-end;gap:12px;padding:15px 20px;border-top:1px solid #f0f0f0}.modal-footer .btn[data-v-100c009e]{padding:10px 24px;border:none;border-radius:6px;font-size:14px;cursor:pointer;transition:all .3s}.modal-footer .btn.btn-secondary[data-v-100c009e]{background:#f5f5f5;color:#666}.modal-footer .btn.btn-secondary[data-v-100c009e]:hover{background:#e0e0e0}.modal-footer .btn.btn-primary[data-v-100c009e]{background:#4caf50;color:#fff}.modal-footer .btn.btn-primary[data-v-100c009e]:hover{background:#45a049}.console-content[data-v-100c009e]{display:grid;grid-template-columns:2fr 1fr;gap:20px;align-items:start}.content-left[data-v-100c009e],.content-right[data-v-100c009e]{display:flex;flex-direction:column;gap:20px}.status-card[data-v-100c009e],.task-card[data-v-100c009e],.qr-card[data-v-100c009e],.stats-card[data-v-100c009e]{background:#fff;border-radius:8px;box-shadow:0 2px 4px #0000000d;overflow:hidden;display:flex;flex-direction:column}.card-header[data-v-100c009e]{display:flex;justify-content:space-between;align-items:center;padding:15px 20px;border-bottom:1px solid #f0f0f0}.card-header .card-title[data-v-100c009e]{margin:0;font-size:16px;font-weight:600;color:#333}.status-card[data-v-100c009e]{display:flex;flex-direction:column}.status-grid[data-v-100c009e]{display:grid;grid-template-columns:repeat(2,1fr);gap:15px;padding:20px;flex:1}.status-item .status-label[data-v-100c009e]{font-size:13px;color:#666;margin-bottom:8px}.status-item .status-value[data-v-100c009e]{font-size:16px;font-weight:600;color:#333;margin-bottom:6px}.status-item .status-detail[data-v-100c009e]{font-size:12px;color:#999;margin-top:4px}.status-item .status-actions[data-v-100c009e]{display:flex;gap:8px;margin-top:8px;flex-wrap:wrap}.status-item .btn-action[data-v-100c009e]{padding:4px 10px;font-size:11px;background:#f5f5f5;color:#666;border:none;border-radius:4px;cursor:pointer;transition:all .2s;white-space:nowrap;margin-left:8px}.status-item .btn-action[data-v-100c009e]:hover{background:#e0e0e0;color:#333}.status-item .btn-action[data-v-100c009e]:active{transform:scale(.98)}.status-badge[data-v-100c009e]{display:inline-block;padding:4px 10px;border-radius:12px;font-size:12px;font-weight:500}.status-badge.status-success[data-v-100c009e]{background:#e8f5e9;color:#4caf50}.status-badge.status-error[data-v-100c009e]{background:#ffebee;color:#f44336}.status-badge.status-warning[data-v-100c009e]{background:#fff3e0;color:#ff9800}.status-badge.status-info[data-v-100c009e]{background:#e3f2fd;color:#2196f3}.text-warning[data-v-100c009e]{color:#ff9800}.task-card .card-body[data-v-100c009e]{padding:20px}.task-card .card-header[data-v-100c009e]{display:flex;justify-content:space-between;align-items:center;margin-bottom:15px}.task-card .card-header .mqtt-topic-info[data-v-100c009e]{font-size:12px;color:#666}.task-card .card-header .mqtt-topic-info .topic-label[data-v-100c009e]{margin-right:5px}.task-card .card-header .mqtt-topic-info .topic-value[data-v-100c009e]{color:#2196f3;font-family:monospace}.current-task[data-v-100c009e],.pending-tasks[data-v-100c009e],.next-task-time[data-v-100c009e],.device-work-status[data-v-100c009e],.current-activity[data-v-100c009e],.pending-queue[data-v-100c009e]{padding:15px 20px;border-bottom:1px solid #f0f0f0}.current-task[data-v-100c009e]:last-child,.pending-tasks[data-v-100c009e]:last-child,.next-task-time[data-v-100c009e]:last-child,.device-work-status[data-v-100c009e]:last-child,.current-activity[data-v-100c009e]:last-child,.pending-queue[data-v-100c009e]:last-child{border-bottom:none}.device-work-status .status-header[data-v-100c009e]{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.device-work-status .status-header .status-label[data-v-100c009e]{font-size:14px;font-weight:600;color:#333}.device-work-status .status-content .status-text[data-v-100c009e]{font-size:14px;color:#666;line-height:1.6;word-break:break-word}.current-activity .task-content .task-name[data-v-100c009e]{font-size:15px;font-weight:500;color:#333;margin-bottom:10px}.pending-queue .queue-content .queue-count[data-v-100c009e]{font-size:14px;color:#666}.next-task-time .time-content[data-v-100c009e]{color:#666;font-size:14px}.task-header[data-v-100c009e]{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.task-header .task-label[data-v-100c009e]{font-size:14px;font-weight:600;color:#333}.task-header .task-count[data-v-100c009e]{font-size:12px;color:#999}.task-content .task-name[data-v-100c009e]{font-size:15px;font-weight:500;color:#333;margin-bottom:10px}.task-content .task-progress[data-v-100c009e]{display:flex;align-items:center;gap:10px;margin-bottom:8px}.task-content .task-progress .progress-bar[data-v-100c009e]{flex:1;height:6px;background:#e0e0e0;border-radius:3px;overflow:hidden}.task-content .task-progress .progress-bar .progress-fill[data-v-100c009e]{height:100%;background:linear-gradient(90deg,#4caf50,#8bc34a);transition:width .3s ease}.task-content .task-progress .progress-text[data-v-100c009e]{font-size:12px;color:#666;min-width:35px}.task-content .task-step[data-v-100c009e]{font-size:12px;color:#666}.pending-list[data-v-100c009e]{display:flex;flex-direction:column;gap:8px}.pending-item[data-v-100c009e]{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;background:#f9f9f9;border-radius:4px}.pending-item .pending-name[data-v-100c009e]{font-size:13px;color:#333}.no-task[data-v-100c009e]{text-align:center;padding:20px;color:#999;font-size:13px}.qr-card[data-v-100c009e]{display:flex;flex-direction:column;min-height:0}.qr-card .btn-qr-refresh[data-v-100c009e]{padding:6px 12px;background:#4caf50;color:#fff;border:none;border-radius:4px;font-size:12px;cursor:pointer}.qr-card .btn-qr-refresh[data-v-100c009e]:hover{background:#45a049}.qr-content[data-v-100c009e]{padding:20px;text-align:center;flex:1;display:flex;flex-direction:column;justify-content:center;align-items:center}.qr-placeholder[data-v-100c009e]{padding:40px 20px;color:#999;font-size:13px;display:flex;align-items:center;justify-content:center;flex:1}.trend-chart-card .chart-content[data-v-100c009e]{padding:20px}.qr-display[data-v-100c009e]{display:flex;flex-direction:column;align-items:center;justify-content:center;flex:1}.qr-display .qr-image[data-v-100c009e]{max-width:100%;width:200px;height:200px;object-fit:contain;border-radius:8px;box-shadow:0 2px 8px #0000001a}.qr-display .qr-info[data-v-100c009e]{margin-top:12px;font-size:12px;color:#666;text-align:center}.qr-display .qr-info p[data-v-100c009e]{margin:4px 0}.qr-display .qr-info .qr-countdown[data-v-100c009e]{color:#2196f3;font-weight:600}.qr-display .qr-info .qr-expired[data-v-100c009e]{color:#f44336;font-weight:600}.stats-list[data-v-100c009e]{padding:20px}.stat-row[data-v-100c009e]{display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-bottom:1px solid #f0f0f0}.stat-row[data-v-100c009e]:last-child{border-bottom:none}.stat-row.highlight[data-v-100c009e]{background:#f9f9f9;margin:0 -20px;padding:12px 20px;border-radius:0}.stat-row .stat-row-label[data-v-100c009e]{font-size:14px;color:#666}.stat-row .stat-row-value[data-v-100c009e]{font-size:18px;font-weight:600;color:#4caf50}@media (max-width: 1200px){.console-content[data-v-100c009e]{grid-template-columns:1fr}.status-grid[data-v-100c009e]{grid-template-columns:repeat(2,1fr)}.console-header[data-v-100c009e]{flex-direction:column;align-items:flex-start;gap:15px}.header-right[data-v-100c009e]{width:100%;justify-content:space-between}.delivery-settings-summary[data-v-100c009e]{width:100%}}@media (max-width: 768px){.console-header[data-v-100c009e]{padding:12px 15px}.header-left[data-v-100c009e]{width:100%}.header-left .page-title[data-v-100c009e]{font-size:20px}.delivery-settings-summary[data-v-100c009e]{flex-direction:column;align-items:flex-start;gap:8px}.quick-stats[data-v-100c009e]{flex-wrap:wrap;gap:10px}.header-right[data-v-100c009e]{flex-direction:column;gap:15px;width:100%}}@media (max-width: 768px){.console-header[data-v-100c009e]{flex-direction:column;gap:15px;align-items:stretch}.header-right[data-v-100c009e]{flex-direction:column;gap:15px}.quick-stats[data-v-100c009e]{justify-content:space-around;width:100%}.status-grid[data-v-100c009e]{grid-template-columns:1fr}}.page-delivery[data-v-260a7ccd]{padding:20px;height:100%;overflow-y:auto}.page-title[data-v-260a7ccd]{margin:0 0 20px;font-size:24px;font-weight:600;color:#333}.stats-section[data-v-260a7ccd]{display:flex;gap:15px;margin-bottom:20px}.stat-card[data-v-260a7ccd]{flex:1;background:#fff;padding:20px;border-radius:8px;box-shadow:0 2px 4px #0000001a;text-align:center}.stat-value[data-v-260a7ccd]{font-size:32px;font-weight:600;color:#4caf50;margin-bottom:8px}.stat-label[data-v-260a7ccd]{font-size:14px;color:#666}.filter-section[data-v-260a7ccd]{background:#fff;padding:15px;border-radius:8px;box-shadow:0 2px 4px #0000001a;margin-bottom:20px}.filter-box[data-v-260a7ccd]{display:flex;gap:10px}.filter-select[data-v-260a7ccd]{flex:1;padding:8px 12px;border:1px solid #ddd;border-radius:4px;font-size:14px}.table-section[data-v-260a7ccd]{background:#fff;border-radius:8px;box-shadow:0 2px 4px #0000001a;overflow:hidden}.loading-wrapper[data-v-260a7ccd]{display:flex;justify-content:center;align-items:center;min-height:300px;padding:40px}.empty[data-v-260a7ccd]{padding:40px;text-align:center;color:#999}.data-table[data-v-260a7ccd]{width:100%;border-collapse:collapse}.data-table thead[data-v-260a7ccd]{background:#f5f5f5}.data-table th[data-v-260a7ccd],.data-table td[data-v-260a7ccd]{padding:12px;text-align:left;border-bottom:1px solid #eee}.data-table th[data-v-260a7ccd]{font-weight:600;color:#333}.platform-tag[data-v-260a7ccd]{display:inline-block;padding:4px 8px;border-radius:4px;font-size:12px}.platform-tag.boss[data-v-260a7ccd]{background:#e3f2fd;color:#1976d2}.platform-tag.liepin[data-v-260a7ccd]{background:#e8f5e9;color:#388e3c}.status-tag[data-v-260a7ccd]{display:inline-block;padding:4px 8px;border-radius:4px;font-size:12px;background:#f5f5f5;color:#666}.status-tag.success[data-v-260a7ccd]{background:#e8f5e9;color:#388e3c}.status-tag.failed[data-v-260a7ccd]{background:#ffebee;color:#d32f2f}.status-tag.pending[data-v-260a7ccd]{background:#fff3e0;color:#f57c00}.status-tag.interview[data-v-260a7ccd]{background:#e3f2fd;color:#1976d2}.btn[data-v-260a7ccd]{padding:8px 16px;border:none;border-radius:4px;font-size:14px;cursor:pointer;transition:all .3s}.btn.btn-primary[data-v-260a7ccd]{background:#4caf50;color:#fff}.btn.btn-primary[data-v-260a7ccd]:hover{background:#45a049}.btn[data-v-260a7ccd]:disabled{opacity:.5;cursor:not-allowed}.btn-small[data-v-260a7ccd]{padding:4px 8px;font-size:12px}.pagination-section[data-v-260a7ccd]{display:flex;justify-content:center;align-items:center;gap:15px;margin-top:20px}.page-info[data-v-260a7ccd]{color:#666;font-size:14px}.modal-overlay[data-v-260a7ccd]{position:fixed;top:0;left:0;right:0;bottom:0;background:#00000080;display:flex;justify-content:center;align-items:center;z-index:1000}.modal-content[data-v-260a7ccd]{background:#fff;border-radius:8px;width:90%;max-width:600px;max-height:80vh;overflow-y:auto}.modal-header[data-v-260a7ccd]{display:flex;justify-content:space-between;align-items:center;padding:20px;border-bottom:1px solid #eee}.modal-header h3[data-v-260a7ccd]{margin:0;font-size:18px}.btn-close[data-v-260a7ccd]{background:none;border:none;font-size:24px;cursor:pointer;color:#999}.btn-close[data-v-260a7ccd]:hover{color:#333}.modal-body[data-v-260a7ccd]{padding:20px}.detail-item[data-v-260a7ccd]{margin-bottom:15px}.detail-item label[data-v-260a7ccd]{font-weight:600;color:#333;margin-right:8px}.detail-item span[data-v-260a7ccd]{color:#666}.page-invite[data-v-098fa8fa]{padding:20px;height:100%;overflow-y:auto}.page-title[data-v-098fa8fa]{margin:0 0 20px;font-size:24px;font-weight:600;color:#333}.invite-card[data-v-098fa8fa]{background:#fff;border-radius:8px;box-shadow:0 2px 4px #0000001a;margin-bottom:20px}.card-header[data-v-098fa8fa]{display:flex;justify-content:space-between;align-items:center;padding:20px;border-bottom:1px solid #eee}.card-header h3[data-v-098fa8fa]{margin:0;font-size:18px;color:#333}.card-body[data-v-098fa8fa]{padding:20px}.invite-code-section[data-v-098fa8fa]{display:flex;flex-direction:column;gap:20px}.invite-tip[data-v-098fa8fa]{margin-top:20px;padding:15px;background:#e8f5e9;border-radius:4px;border-left:4px solid #4CAF50}.invite-tip p[data-v-098fa8fa]{margin:0;color:#2e7d32;font-size:14px;line-height:1.6}.invite-tip p strong[data-v-098fa8fa]{color:#1b5e20;font-weight:600}.code-display[data-v-098fa8fa],.link-display[data-v-098fa8fa]{display:flex;align-items:center;gap:10px;padding:15px;background:#f5f5f5;border-radius:4px}.code-label[data-v-098fa8fa],.link-label[data-v-098fa8fa]{font-weight:600;color:#333;min-width:80px}.code-value[data-v-098fa8fa],.link-value[data-v-098fa8fa]{flex:1;font-family:Courier New,monospace;color:#4caf50;font-size:16px;word-break:break-all}.btn-copy[data-v-098fa8fa]{padding:6px 12px;background:#4caf50;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:14px;transition:background .3s}.btn-copy[data-v-098fa8fa]:hover{background:#45a049}.stats-section[data-v-098fa8fa]{display:flex;gap:15px;margin-bottom:20px}.stat-card[data-v-098fa8fa]{flex:1;background:#fff;padding:20px;border-radius:8px;box-shadow:0 2px 4px #0000001a;text-align:center;max-width:300px}.records-section[data-v-098fa8fa]{background:#fff;border-radius:8px;box-shadow:0 2px 4px #0000001a;margin-bottom:20px;padding:20px}.section-header[data-v-098fa8fa]{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;padding-bottom:15px;border-bottom:1px solid #eee}.section-header h3[data-v-098fa8fa]{margin:0;font-size:18px;color:#333;display:flex;align-items:center;gap:10px}.section-header .stat-value[data-v-098fa8fa]{display:inline-block;padding:2px 10px;background:#4caf50;color:#fff;border-radius:12px;font-size:14px;font-weight:600;min-width:24px;text-align:center;line-height:1.5}.btn-refresh[data-v-098fa8fa]{padding:6px 12px;background:#4caf50;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:14px;transition:background .3s}.btn-refresh[data-v-098fa8fa]:hover:not(:disabled){background:#45a049}.btn-refresh[data-v-098fa8fa]:disabled{background:#ccc;cursor:not-allowed}.loading-tip[data-v-098fa8fa],.empty-tip[data-v-098fa8fa]{text-align:center;padding:40px 20px;color:#999;font-size:14px}.records-list[data-v-098fa8fa]{display:flex;flex-direction:column;gap:12px}.record-item[data-v-098fa8fa]{display:flex;justify-content:space-between;align-items:center;padding:15px;background:#f9f9f9;border-radius:4px;border-left:3px solid #4CAF50;transition:background .3s}.record-item[data-v-098fa8fa]:hover{background:#f0f0f0}.record-info[data-v-098fa8fa]{flex:1}.record-info .record-phone[data-v-098fa8fa]{font-size:16px;font-weight:600;color:#333;margin-bottom:5px}.record-info .record-time[data-v-098fa8fa]{font-size:12px;color:#999}.record-status[data-v-098fa8fa]{display:flex;align-items:center;gap:10px}.status-badge[data-v-098fa8fa]{padding:4px 12px;border-radius:12px;font-size:12px;font-weight:600}.status-badge.status-success[data-v-098fa8fa]{background:#e8f5e9;color:#2e7d32}.status-badge.status-pending[data-v-098fa8fa]{background:#fff3e0;color:#e65100}.reward-info[data-v-098fa8fa]{font-size:14px;color:#4caf50;font-weight:600}.pagination[data-v-098fa8fa]{display:flex;justify-content:center;align-items:center;gap:15px;margin-top:20px;padding-top:20px;border-top:1px solid #eee}.page-btn[data-v-098fa8fa]{padding:6px 16px;background:#4caf50;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:14px;transition:background .3s}.page-btn[data-v-098fa8fa]:hover:not(:disabled){background:#45a049}.page-btn[data-v-098fa8fa]:disabled{background:#ccc;cursor:not-allowed}.page-info[data-v-098fa8fa],.stat-label[data-v-098fa8fa]{font-size:14px;color:#666}.info-section[data-v-098fa8fa]{background:#fff;padding:20px;border-radius:8px;box-shadow:0 2px 4px #0000001a}.info-section h3[data-v-098fa8fa]{margin:0 0 15px;font-size:18px;color:#333}.info-list[data-v-098fa8fa]{margin:0;padding-left:20px}.info-list li[data-v-098fa8fa]{margin-bottom:10px;color:#666;line-height:1.6}.btn[data-v-098fa8fa]{padding:8px 16px;border:none;border-radius:4px;font-size:14px;cursor:pointer;transition:all .3s}.btn.btn-primary[data-v-098fa8fa]{background:#4caf50;color:#fff}.btn.btn-primary[data-v-098fa8fa]:hover{background:#45a049}.success-message[data-v-098fa8fa]{position:fixed;top:20px;right:20px;background:#4caf50;color:#fff;padding:12px 20px;border-radius:4px;box-shadow:0 2px 8px #0003;z-index:1000;animation:slideIn-098fa8fa .3s ease-out}@keyframes slideIn-098fa8fa{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}.page-feedback[data-v-8ac3a0fd]{padding:20px;height:100%;overflow-y:auto}.page-title[data-v-8ac3a0fd]{margin:0 0 20px;font-size:24px;font-weight:600;color:#333}.feedback-form-section[data-v-8ac3a0fd]{background:#fff;padding:20px;border-radius:8px;box-shadow:0 2px 4px #0000001a;margin-bottom:20px}.feedback-form-section h3[data-v-8ac3a0fd]{margin:0 0 20px;font-size:18px;color:#333}.form-group[data-v-8ac3a0fd]{margin-bottom:20px}.form-group label[data-v-8ac3a0fd]{display:block;margin-bottom:8px;font-weight:600;color:#333}.form-group label .required[data-v-8ac3a0fd]{color:#f44336}.form-control[data-v-8ac3a0fd]{width:100%;padding:10px 12px;border:1px solid #ddd;border-radius:4px;font-size:14px;font-family:inherit}.form-control[data-v-8ac3a0fd]:focus{outline:none;border-color:#4caf50}textarea.form-control[data-v-8ac3a0fd]{resize:vertical;min-height:120px}.form-actions[data-v-8ac3a0fd]{display:flex;gap:10px}.btn[data-v-8ac3a0fd]{padding:10px 20px;border:none;border-radius:4px;font-size:14px;cursor:pointer;transition:all .3s}.btn.btn-primary[data-v-8ac3a0fd]{background:#4caf50;color:#fff}.btn.btn-primary[data-v-8ac3a0fd]:hover:not(:disabled){background:#45a049}.btn.btn-primary[data-v-8ac3a0fd]:disabled{opacity:.5;cursor:not-allowed}.btn[data-v-8ac3a0fd]:not(.btn-primary){background:#f5f5f5;color:#333}.btn[data-v-8ac3a0fd]:not(.btn-primary):hover{background:#e0e0e0}.feedback-history-section[data-v-8ac3a0fd]{background:#fff;padding:20px;border-radius:8px;box-shadow:0 2px 4px #0000001a}.feedback-history-section h3[data-v-8ac3a0fd]{margin:0 0 20px;font-size:18px;color:#333}.loading[data-v-8ac3a0fd],.empty[data-v-8ac3a0fd]{padding:40px;text-align:center;color:#999}.feedback-table-wrapper[data-v-8ac3a0fd]{overflow-x:auto}.feedback-table[data-v-8ac3a0fd]{width:100%;border-collapse:collapse;background:#fff}.feedback-table thead[data-v-8ac3a0fd]{background:#f5f5f5}.feedback-table thead th[data-v-8ac3a0fd]{padding:12px 16px;text-align:left;font-weight:600;color:#333;border-bottom:2px solid #e0e0e0;white-space:nowrap}.feedback-table tbody tr[data-v-8ac3a0fd]{border-bottom:1px solid #f0f0f0;transition:background-color .2s}.feedback-table tbody tr[data-v-8ac3a0fd]:hover{background-color:#f9f9f9}.feedback-table tbody tr[data-v-8ac3a0fd]:last-child{border-bottom:none}.feedback-table tbody td[data-v-8ac3a0fd]{padding:12px 16px;vertical-align:middle;color:#666}.content-cell[data-v-8ac3a0fd]{max-width:400px}.content-cell .content-text[data-v-8ac3a0fd]{max-height:60px;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.5}.time-cell[data-v-8ac3a0fd]{white-space:nowrap;font-size:14px;color:#999}.success-message[data-v-8ac3a0fd]{position:fixed;top:20px;right:20px;background:#4caf50;color:#fff;padding:12px 20px;border-radius:4px;box-shadow:0 2px 8px #0003;z-index:1000;animation:slideIn-8ac3a0fd .3s ease-out}@keyframes slideIn-8ac3a0fd{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}.detail-item[data-v-8ac3a0fd]{margin-bottom:15px}.detail-item label[data-v-8ac3a0fd]{font-weight:600;color:#333;margin-right:8px;display:inline-block;min-width:100px}.detail-item span[data-v-8ac3a0fd]{color:#666}.detail-content[data-v-8ac3a0fd]{color:#666;line-height:1.6;margin-top:5px;padding:10px;background:#f9f9f9;border-radius:4px;white-space:pre-wrap;word-break:break-word}.page-purchase[data-v-1c98de88]{padding:15px;height:100%;overflow-y:auto;background:#f5f5f5}.page-title[data-v-1c98de88]{margin:0 0 20px;font-size:24px;font-weight:600;color:#333;text-align:center}.contact-section[data-v-1c98de88]{margin-bottom:20px}.contact-card[data-v-1c98de88]{max-width:600px;margin:0 auto}.contact-desc[data-v-1c98de88]{text-align:center;margin:0 0 15px;color:#666;font-size:13px}.contact-content[data-v-1c98de88]{display:flex;gap:20px;align-items:flex-start}.qr-code-wrapper[data-v-1c98de88]{flex-shrink:0}.qr-code-placeholder[data-v-1c98de88]{width:150px;height:150px;border:2px dashed #ddd;border-radius:6px;display:flex;align-items:center;justify-content:center;background:#fafafa}.qr-code-placeholder .qr-code-image[data-v-1c98de88]{width:100%;height:100%;object-fit:contain;border-radius:6px}.qr-code-placeholder .qr-code-placeholder-text[data-v-1c98de88]{text-align:center;color:#999}.qr-code-placeholder .qr-code-placeholder-text span[data-v-1c98de88]{display:block;font-size:14px;margin-bottom:5px}.qr-code-placeholder .qr-code-placeholder-text small[data-v-1c98de88]{display:block;font-size:12px}.qr-code-placeholder .qr-code-loading[data-v-1c98de88]{display:flex;align-items:center;justify-content:center;height:100%;color:#999;font-size:14px}.contact-info[data-v-1c98de88]{flex:1}.info-item[data-v-1c98de88]{display:flex;align-items:center;gap:8px;margin-bottom:10px;padding:10px;background:#f9f9f9;border-radius:6px}.info-item .info-label[data-v-1c98de88]{font-weight:600;color:#333;min-width:70px;font-size:14px}.info-item .info-value[data-v-1c98de88]{flex:1;color:#666;font-size:14px}.pricing-section[data-v-1c98de88]{margin-bottom:20px}.section-title[data-v-1c98de88]{text-align:center;font-size:20px;font-weight:600;color:#333;margin:0 0 20px}.pricing-grid[data-v-1c98de88]{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:15px;max-width:1200px;margin:0 auto}.pricing-card[data-v-1c98de88]{position:relative;text-align:center;transition:transform .3s,box-shadow .3s}.pricing-card[data-v-1c98de88]:hover{transform:translateY(-5px)}.pricing-card.featured[data-v-1c98de88]{border:2px solid #4CAF50;transform:scale(1.05)}.plan-header[data-v-1c98de88]{margin-bottom:15px}.plan-header .plan-name[data-v-1c98de88]{margin:0 0 6px;font-size:18px;font-weight:600;color:#333}.plan-header .plan-duration[data-v-1c98de88]{font-size:13px;color:#999}.plan-price[data-v-1c98de88]{margin-bottom:15px;padding-bottom:15px;border-bottom:1px solid #eee;position:relative}.plan-price .original-price[data-v-1c98de88]{margin-bottom:8px}.plan-price .original-price .original-price-text[data-v-1c98de88]{font-size:14px;color:#999;text-decoration:line-through}.plan-price .current-price .price-symbol[data-v-1c98de88]{font-size:18px;color:#4caf50;vertical-align:top}.plan-price .current-price .price-amount[data-v-1c98de88]{font-size:40px;font-weight:700;color:#4caf50;line-height:1}.plan-price .current-price .price-unit[data-v-1c98de88]{font-size:14px;color:#666;margin-left:4px}.plan-price .discount-badge[data-v-1c98de88]{position:absolute;top:-8px;right:0}.plan-features[data-v-1c98de88]{margin-bottom:15px;text-align:left}.feature-item[data-v-1c98de88]{display:flex;align-items:center;gap:6px;margin-bottom:8px;font-size:13px;color:#666}.feature-item .feature-icon[data-v-1c98de88]{color:#4caf50;font-weight:700;font-size:14px}.plan-action[data-v-1c98de88] .p-button{width:100%}.notice-section[data-v-1c98de88]{max-width:800px;margin:0 auto}.notice-list[data-v-1c98de88]{margin:0;padding-left:18px;list-style:none}.notice-list li[data-v-1c98de88]{position:relative;padding-left:20px;margin-bottom:8px;color:#666;line-height:1.5;font-size:13px}.notice-list li[data-v-1c98de88]:before{content:"•";position:absolute;left:0;color:#4caf50;font-weight:700;font-size:18px}.success-message[data-v-1c98de88]{position:fixed;top:20px;right:20px;z-index:1000;max-width:400px}@media (max-width: 768px){.contact-content[data-v-1c98de88]{flex-direction:column;align-items:center}.pricing-grid[data-v-1c98de88]{grid-template-columns:1fr}.pricing-card.featured[data-v-1c98de88]{transform:scale(1)}}.page-log[data-v-c5fdcf0e]{padding:0;height:100%;display:flex;flex-direction:column}.log-controls-section[data-v-c5fdcf0e]{margin-bottom:10px;display:flex;justify-content:flex-end}.log-controls[data-v-c5fdcf0e]{display:flex;gap:10px}.log-content-section[data-v-c5fdcf0e]{flex:1;display:flex;flex-direction:column;background:#fff;border-radius:8px;box-shadow:0 2px 4px #0000001a;overflow:hidden}.log-container[data-v-c5fdcf0e]{flex:1;padding:12px;overflow-y:auto;background:#1e1e1e;color:#d4d4d4;font-family:Consolas,Monaco,Courier New,monospace;font-size:12px;line-height:1.5}.log-entry[data-v-c5fdcf0e]{margin-bottom:4px;word-wrap:break-word;white-space:pre-wrap}.log-time[data-v-c5fdcf0e]{color:gray;margin-right:8px}.log-level[data-v-c5fdcf0e]{margin-right:8px;font-weight:600}.log-level.info[data-v-c5fdcf0e]{color:#4ec9b0}.log-level.success[data-v-c5fdcf0e]{color:#4caf50}.log-level.warn[data-v-c5fdcf0e]{color:#ffa726}.log-level.error[data-v-c5fdcf0e]{color:#f44336}.log-level.debug[data-v-c5fdcf0e]{color:#90caf9}.log-message[data-v-c5fdcf0e]{color:#d4d4d4}.log-empty[data-v-c5fdcf0e]{display:flex;align-items:center;justify-content:center;height:100%;color:gray;font-size:14px}*{margin:0;padding:0;box-sizing:border-box}html,body{width:100%;height:100%;overflow:hidden;font-family:Microsoft YaHei,sans-serif;background:#f5f5f5;color:#333}.container{width:100%;height:100vh;display:flex;flex-direction:column;padding:10px;background:linear-gradient(135deg,#667eea,#764ba2);overflow:hidden}.main-content{flex:1;display:flex;gap:10px;min-height:0;overflow:hidden}.mt10{margin-top:10px}.mt60{margin-top:30px}.header{text-align:left;color:#fff;margin-bottom:10px;display:flex;flex-direction:row;justify-content:space-between;align-items:center}.header h1{font-size:20px;margin-bottom:0;text-align:left}.header-left{display:flex;align-items:center;gap:10px;flex:1}.header-right{display:flex;align-items:center;gap:10px}.status-indicator{display:inline-flex;align-items:center;gap:8px;padding:6px 12px;background:#fff3;border-radius:20px;font-size:14px;white-space:nowrap}.status-dot{width:8px;height:8px;border-radius:50%;background:#f44}.status-dot.connected{background:#4f4;animation:pulse 2s infinite}.sidebar{width:200px;background:#fffffff2;border-radius:10px;padding:20px 0;box-shadow:0 2px 8px #0000001a;flex-shrink:0}.sidebar-menu{list-style:none;padding:0;margin:0}.menu-item{padding:15px 20px;cursor:pointer;display:flex;align-items:center;gap:12px;transition:all .3s ease;border-left:3px solid transparent;color:#333}.menu-item:hover{background:#667eea1a}.menu-item.active{background:#667eea26;border-left-color:#667eea;color:#667eea;font-weight:700}.menu-item.active .menu-icon{color:#667eea}.menu-icon{font-size:18px;width:20px;display:inline-block;text-align:center;color:#666;flex-shrink:0}.menu-text{font-size:15px}.content-area{flex:1;background:#fffffff2;border-radius:10px;padding:30px;box-shadow:0 2px 8px #0000001a;overflow-y:auto;min-width:0;position:relative}.content-area.full-width{padding:0;background:transparent;border-radius:0;box-shadow:none;overflow:hidden}.page-title{font-size:24px;font-weight:700;color:#333;margin-bottom:30px;padding-bottom:15px;border-bottom:2px solid #667eea}.placeholder-content{text-align:center;padding:40px 20px;color:#999;font-size:16px}.loading-screen{position:fixed;top:0;left:0;width:100%;height:100%;background:linear-gradient(135deg,#667eea,#764ba2);display:flex;align-items:center;justify-content:center;z-index:9999;opacity:1;transition:opacity .5s ease-out}.loading-screen.hidden{opacity:0;pointer-events:none}.loading-content{text-align:center;color:#fff}.loading-logo{margin-bottom:30px}.logo-circle{width:80px;height:80px;border:4px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:spin 1s linear infinite;margin:0 auto}.loading-text{font-size:18px;font-weight:500;margin-bottom:20px;animation:pulse 2s ease-in-out infinite}.loading-progress{width:200px;height:4px;background:#fff3;border-radius:2px;overflow:hidden;margin:0 auto}.progress-bar-animated{height:100%;background:#fff;border-radius:2px;animation:progress 1.5s ease-in-out infinite}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideDown{0%{transform:translateY(-50px);opacity:0}to{transform:translateY(0);opacity:1}}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}@keyframes progress{0%{width:0%;transform:translate(0)}50%{width:70%;transform:translate(0)}to{width:100%;transform:translate(0)}}@font-face{font-family:primeicons;font-display:block;src:url(/app/assets/primeicons-DMOk5skT.eot);src:url(/app/assets/primeicons-DMOk5skT.eot?#iefix) format("embedded-opentype"),url(/app/assets/primeicons-C6QP2o4f.woff2) format("woff2"),url(/app/assets/primeicons-WjwUDZjB.woff) format("woff"),url(/app/assets/primeicons-MpK4pl85.ttf) format("truetype"),url(/app/assets/primeicons-Dr5RGzOO.svg?#primeicons) format("svg");font-weight:400;font-style:normal}.pi{font-family:primeicons;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.pi:before{--webkit-backface-visibility:hidden;backface-visibility:hidden}.pi-fw{width:1.28571429em;text-align:center}.pi-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@media (prefers-reduced-motion: reduce){.pi-spin{-webkit-animation-delay:-1ms;animation-delay:-1ms;-webkit-animation-duration:1ms;animation-duration:1ms;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-transition-delay:0s;transition-delay:0s;-webkit-transition-duration:0s;transition-duration:0s}}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.pi-folder-plus:before{content:""}.pi-receipt:before{content:""}.pi-asterisk:before{content:""}.pi-face-smile:before{content:""}.pi-pinterest:before{content:""}.pi-expand:before{content:""}.pi-pen-to-square:before{content:""}.pi-wave-pulse:before{content:""}.pi-turkish-lira:before{content:""}.pi-spinner-dotted:before{content:""}.pi-crown:before{content:""}.pi-pause-circle:before{content:""}.pi-warehouse:before{content:""}.pi-objects-column:before{content:""}.pi-clipboard:before{content:""}.pi-play-circle:before{content:""}.pi-venus:before{content:""}.pi-cart-minus:before{content:""}.pi-file-plus:before{content:""}.pi-microchip:before{content:""}.pi-twitch:before{content:""}.pi-building-columns:before{content:""}.pi-file-check:before{content:""}.pi-microchip-ai:before{content:""}.pi-trophy:before{content:""}.pi-barcode:before{content:""}.pi-file-arrow-up:before{content:""}.pi-mars:before{content:""}.pi-tiktok:before{content:""}.pi-arrow-up-right-and-arrow-down-left-from-center:before{content:""}.pi-ethereum:before{content:""}.pi-list-check:before{content:""}.pi-thumbtack:before{content:""}.pi-arrow-down-left-and-arrow-up-right-to-center:before{content:""}.pi-equals:before{content:""}.pi-lightbulb:before{content:""}.pi-star-half:before{content:""}.pi-address-book:before{content:""}.pi-chart-scatter:before{content:""}.pi-indian-rupee:before{content:""}.pi-star-half-fill:before{content:""}.pi-cart-arrow-down:before{content:""}.pi-calendar-clock:before{content:""}.pi-sort-up-fill:before{content:""}.pi-sparkles:before{content:""}.pi-bullseye:before{content:""}.pi-sort-down-fill:before{content:""}.pi-graduation-cap:before{content:""}.pi-hammer:before{content:""}.pi-bell-slash:before{content:""}.pi-gauge:before{content:""}.pi-shop:before{content:""}.pi-headphones:before{content:""}.pi-eraser:before{content:""}.pi-stopwatch:before{content:""}.pi-verified:before{content:""}.pi-delete-left:before{content:""}.pi-hourglass:before{content:""}.pi-truck:before{content:""}.pi-wrench:before{content:""}.pi-microphone:before{content:""}.pi-megaphone:before{content:""}.pi-arrow-right-arrow-left:before{content:""}.pi-bitcoin:before{content:""}.pi-file-edit:before{content:""}.pi-language:before{content:""}.pi-file-export:before{content:""}.pi-file-import:before{content:""}.pi-file-word:before{content:""}.pi-gift:before{content:""}.pi-cart-plus:before{content:""}.pi-thumbs-down-fill:before{content:""}.pi-thumbs-up-fill:before{content:""}.pi-arrows-alt:before{content:""}.pi-calculator:before{content:""}.pi-sort-alt-slash:before{content:""}.pi-arrows-h:before{content:""}.pi-arrows-v:before{content:""}.pi-pound:before{content:""}.pi-prime:before{content:""}.pi-chart-pie:before{content:""}.pi-reddit:before{content:""}.pi-code:before{content:""}.pi-sync:before{content:""}.pi-shopping-bag:before{content:""}.pi-server:before{content:""}.pi-database:before{content:""}.pi-hashtag:before{content:""}.pi-bookmark-fill:before{content:""}.pi-filter-fill:before{content:""}.pi-heart-fill:before{content:""}.pi-flag-fill:before{content:""}.pi-circle:before{content:""}.pi-circle-fill:before{content:""}.pi-bolt:before{content:""}.pi-history:before{content:""}.pi-box:before{content:""}.pi-at:before{content:""}.pi-arrow-up-right:before{content:""}.pi-arrow-up-left:before{content:""}.pi-arrow-down-left:before{content:""}.pi-arrow-down-right:before{content:""}.pi-telegram:before{content:""}.pi-stop-circle:before{content:""}.pi-stop:before{content:""}.pi-whatsapp:before{content:""}.pi-building:before{content:""}.pi-qrcode:before{content:""}.pi-car:before{content:""}.pi-instagram:before{content:""}.pi-linkedin:before{content:""}.pi-send:before{content:""}.pi-slack:before{content:""}.pi-sun:before{content:""}.pi-moon:before{content:""}.pi-vimeo:before{content:""}.pi-youtube:before{content:""}.pi-flag:before{content:""}.pi-wallet:before{content:""}.pi-map:before{content:""}.pi-link:before{content:""}.pi-credit-card:before{content:""}.pi-discord:before{content:""}.pi-percentage:before{content:""}.pi-euro:before{content:""}.pi-book:before{content:""}.pi-shield:before{content:""}.pi-paypal:before{content:""}.pi-amazon:before{content:""}.pi-phone:before{content:""}.pi-filter-slash:before{content:""}.pi-facebook:before{content:""}.pi-github:before{content:""}.pi-twitter:before{content:""}.pi-step-backward-alt:before{content:""}.pi-step-forward-alt:before{content:""}.pi-forward:before{content:""}.pi-backward:before{content:""}.pi-fast-backward:before{content:""}.pi-fast-forward:before{content:""}.pi-pause:before{content:""}.pi-play:before{content:""}.pi-compass:before{content:""}.pi-id-card:before{content:""}.pi-ticket:before{content:""}.pi-file-o:before{content:""}.pi-reply:before{content:""}.pi-directions-alt:before{content:""}.pi-directions:before{content:""}.pi-thumbs-up:before{content:""}.pi-thumbs-down:before{content:""}.pi-sort-numeric-down-alt:before{content:""}.pi-sort-numeric-up-alt:before{content:""}.pi-sort-alpha-down-alt:before{content:""}.pi-sort-alpha-up-alt:before{content:""}.pi-sort-numeric-down:before{content:""}.pi-sort-numeric-up:before{content:""}.pi-sort-alpha-down:before{content:""}.pi-sort-alpha-up:before{content:""}.pi-sort-alt:before{content:""}.pi-sort-amount-up:before{content:""}.pi-sort-amount-down:before{content:""}.pi-sort-amount-down-alt:before{content:""}.pi-sort-amount-up-alt:before{content:""}.pi-palette:before{content:""}.pi-undo:before{content:""}.pi-desktop:before{content:""}.pi-sliders-v:before{content:""}.pi-sliders-h:before{content:""}.pi-search-plus:before{content:""}.pi-search-minus:before{content:""}.pi-file-excel:before{content:""}.pi-file-pdf:before{content:""}.pi-check-square:before{content:""}.pi-chart-line:before{content:""}.pi-user-edit:before{content:""}.pi-exclamation-circle:before{content:""}.pi-android:before{content:""}.pi-google:before{content:""}.pi-apple:before{content:""}.pi-microsoft:before{content:""}.pi-heart:before{content:""}.pi-mobile:before{content:""}.pi-tablet:before{content:""}.pi-key:before{content:""}.pi-shopping-cart:before{content:""}.pi-comments:before{content:""}.pi-comment:before{content:""}.pi-briefcase:before{content:""}.pi-bell:before{content:""}.pi-paperclip:before{content:""}.pi-share-alt:before{content:""}.pi-envelope:before{content:""}.pi-volume-down:before{content:""}.pi-volume-up:before{content:""}.pi-volume-off:before{content:""}.pi-eject:before{content:""}.pi-money-bill:before{content:""}.pi-images:before{content:""}.pi-image:before{content:""}.pi-sign-in:before{content:""}.pi-sign-out:before{content:""}.pi-wifi:before{content:""}.pi-sitemap:before{content:""}.pi-chart-bar:before{content:""}.pi-camera:before{content:""}.pi-dollar:before{content:""}.pi-lock-open:before{content:""}.pi-table:before{content:""}.pi-map-marker:before{content:""}.pi-list:before{content:""}.pi-eye-slash:before{content:""}.pi-eye:before{content:""}.pi-folder-open:before{content:""}.pi-folder:before{content:""}.pi-video:before{content:""}.pi-inbox:before{content:""}.pi-lock:before{content:""}.pi-unlock:before{content:""}.pi-tags:before{content:""}.pi-tag:before{content:""}.pi-power-off:before{content:""}.pi-save:before{content:""}.pi-question-circle:before{content:""}.pi-question:before{content:""}.pi-copy:before{content:""}.pi-file:before{content:""}.pi-clone:before{content:""}.pi-calendar-times:before{content:""}.pi-calendar-minus:before{content:""}.pi-calendar-plus:before{content:""}.pi-ellipsis-v:before{content:""}.pi-ellipsis-h:before{content:""}.pi-bookmark:before{content:""}.pi-globe:before{content:""}.pi-replay:before{content:""}.pi-filter:before{content:""}.pi-print:before{content:""}.pi-align-right:before{content:""}.pi-align-left:before{content:""}.pi-align-center:before{content:""}.pi-align-justify:before{content:""}.pi-cog:before{content:""}.pi-cloud-download:before{content:""}.pi-cloud-upload:before{content:""}.pi-cloud:before{content:""}.pi-pencil:before{content:""}.pi-users:before{content:""}.pi-clock:before{content:""}.pi-user-minus:before{content:""}.pi-user-plus:before{content:""}.pi-trash:before{content:""}.pi-external-link:before{content:""}.pi-window-maximize:before{content:""}.pi-window-minimize:before{content:""}.pi-refresh:before{content:""}.pi-user:before{content:""}.pi-exclamation-triangle:before{content:""}.pi-calendar:before{content:""}.pi-chevron-circle-left:before{content:""}.pi-chevron-circle-down:before{content:""}.pi-chevron-circle-right:before{content:""}.pi-chevron-circle-up:before{content:""}.pi-angle-double-down:before{content:""}.pi-angle-double-left:before{content:""}.pi-angle-double-right:before{content:""}.pi-angle-double-up:before{content:""}.pi-angle-down:before{content:""}.pi-angle-left:before{content:""}.pi-angle-right:before{content:""}.pi-angle-up:before{content:""}.pi-upload:before{content:""}.pi-download:before{content:""}.pi-ban:before{content:""}.pi-star-fill:before{content:""}.pi-star:before{content:""}.pi-chevron-left:before{content:""}.pi-chevron-right:before{content:""}.pi-chevron-down:before{content:""}.pi-chevron-up:before{content:""}.pi-caret-left:before{content:""}.pi-caret-right:before{content:""}.pi-caret-down:before{content:""}.pi-caret-up:before{content:""}.pi-search:before{content:""}.pi-check:before{content:""}.pi-check-circle:before{content:""}.pi-times:before{content:""}.pi-times-circle:before{content:""}.pi-plus:before{content:""}.pi-plus-circle:before{content:""}.pi-minus:before{content:""}.pi-minus-circle:before{content:""}.pi-circle-on:before{content:""}.pi-circle-off:before{content:""}.pi-sort-down:before{content:""}.pi-sort-up:before{content:""}.pi-sort:before{content:""}.pi-step-backward:before{content:""}.pi-step-forward:before{content:""}.pi-th-large:before{content:""}.pi-arrow-down:before{content:""}.pi-arrow-left:before{content:""}.pi-arrow-right:before{content:""}.pi-arrow-up:before{content:""}.pi-bars:before{content:""}.pi-arrow-circle-down:before{content:""}.pi-arrow-circle-left:before{content:""}.pi-arrow-circle-right:before{content:""}.pi-arrow-circle-up:before{content:""}.pi-info:before{content:""}.pi-info-circle:before{content:""}.pi-home:before{content:""}.pi-spinner:before{content:""} diff --git a/app/assets/index-CsHwYKwf.js b/app/assets/index-CsHwYKwf.js deleted file mode 100644 index 4a0d1d5..0000000 --- a/app/assets/index-CsHwYKwf.js +++ /dev/null @@ -1,3648 +0,0 @@ -/** -* @vue/shared v3.5.25 -* (c) 2018-present Yuxi (Evan) You and Vue contributors -* @license MIT -**/function Xl(e){const t=Object.create(null);for(const n of e.split(","))t[n]=1;return n=>n in t}const Ee={},po=[],Xt=()=>{},mc=()=>!1,Ui=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),Jl=e=>e.startsWith("onUpdate:"),qe=Object.assign,es=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},_h=Object.prototype.hasOwnProperty,Ie=(e,t)=>_h.call(e,t),de=Array.isArray,ho=e=>Hi(e)==="[object Map]",bc=e=>Hi(e)==="[object Set]",he=e=>typeof e=="function",ze=e=>typeof e=="string",gn=e=>typeof e=="symbol",_e=e=>e!==null&&typeof e=="object",yc=e=>(_e(e)||he(e))&&he(e.then)&&he(e.catch),vc=Object.prototype.toString,Hi=e=>vc.call(e),Dh=e=>Hi(e).slice(8,-1),wc=e=>Hi(e)==="[object Object]",ts=e=>ze(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Ho=Xl(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Gi=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},Bh=/-\w/g,Rt=Gi(e=>e.replace(Bh,t=>t.slice(1).toUpperCase())),Mh=/\B([A-Z])/g,En=Gi(e=>e.replace(Mh,"-$1").toLowerCase()),Ki=Gi(e=>e.charAt(0).toUpperCase()+e.slice(1)),ki=Gi(e=>e?`on${Ki(e)}`:""),Rn=(e,t)=>!Object.is(e,t),ha=(e,...t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:o,value:n})},zh=e=>{const t=parseFloat(e);return isNaN(t)?e:t},Fh=e=>{const t=ze(e)?Number(e):NaN;return isNaN(t)?e:t};let Vs;const Wi=()=>Vs||(Vs=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function $o(e){if(de(e)){const t={};for(let n=0;n{if(n){const o=n.split(Nh);o.length>1&&(t[o[0].trim()]=o[1].trim())}}),t}function J(e){let t="";if(ze(e))t=e;else if(de(e))for(let n=0;n!!(e&&e.__v_isRef===!0),_=e=>ze(e)?e:e==null?"":de(e)||_e(e)&&(e.toString===vc||!he(e.toString))?Sc(e)?_(e.value):JSON.stringify(e,xc,2):String(e),xc=(e,t)=>Sc(t)?xc(e,t.value):ho(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[o,i],r)=>(n[ga(o,r)+" =>"]=i,n),{})}:bc(t)?{[`Set(${t.size})`]:[...t.values()].map(n=>ga(n))}:gn(t)?ga(t):_e(t)&&!de(t)&&!wc(t)?String(t):t,ga=(e,t="")=>{var n;return gn(e)?`Symbol(${(n=e.description)!=null?n:t})`:e};/** -* @vue/reactivity v3.5.25 -* (c) 2018-present Yuxi (Evan) You and Vue contributors -* @license MIT -**/let pt;class $c{constructor(t=!1){this.detached=t,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this.parent=pt,!t&&pt&&(this.index=(pt.scopes||(pt.scopes=[])).push(this)-1)}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let t,n;if(this.scopes)for(t=0,n=this.scopes.length;t0&&--this._on===0&&(pt=this.prevScope,this.prevScope=void 0)}stop(t){if(this._active){this._active=!1;let n,o;for(n=0,o=this.effects.length;n0)return;if(Ko){let t=Ko;for(Ko=void 0;t;){const n=t.next;t.next=void 0,t.flags&=-9,t=n}}let e;for(;Go;){let t=Go;for(Go=void 0;t;){const n=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(o){e||(e=o)}t=n}}if(e)throw e}function Rc(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function Oc(e){let t,n=e.depsTail,o=n;for(;o;){const i=o.prevDep;o.version===-1?(o===n&&(n=i),rs(o),qh(o)):t=o,o.dep.activeLink=o.prevActiveLink,o.prevActiveLink=void 0,o=i}e.deps=t,e.depsTail=n}function Fa(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(Ec(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function Ec(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===nr)||(e.globalVersion=nr,!e.isSSR&&e.flags&128&&(!e.deps&&!e._dirty||!Fa(e))))return;e.flags|=2;const t=e.dep,n=Le,o=_t;Le=e,_t=!0;try{Rc(e);const i=e.fn(e._value);(t.version===0||Rn(i,e._value))&&(e.flags|=128,e._value=i,t.version++)}catch(i){throw t.version++,i}finally{Le=n,_t=o,Oc(e),e.flags&=-3}}function rs(e,t=!1){const{dep:n,prevSub:o,nextSub:i}=e;if(o&&(o.nextSub=i,e.prevSub=void 0),i&&(i.prevSub=o,e.nextSub=void 0),n.subs===e&&(n.subs=o,!o&&n.computed)){n.computed.flags&=-5;for(let r=n.computed.deps;r;r=r.nextDep)rs(r,!0)}!t&&!--n.sc&&n.map&&n.map.delete(n.key)}function qh(e){const{prevDep:t,nextDep:n}=e;t&&(t.nextDep=n,e.prevDep=void 0),n&&(n.prevDep=t,e.nextDep=void 0)}let _t=!0;const Ac=[];function fn(){Ac.push(_t),_t=!1}function pn(){const e=Ac.pop();_t=e===void 0?!0:e}function Us(e){const{cleanup:t}=e;if(e.cleanup=void 0,t){const n=Le;Le=void 0;try{t()}finally{Le=n}}}let nr=0;class Qh{constructor(t,n){this.sub=t,this.dep=n,this.version=n.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class is{constructor(t){this.computed=t,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(t){if(!Le||!_t||Le===this.computed)return;let n=this.activeLink;if(n===void 0||n.sub!==Le)n=this.activeLink=new Qh(Le,this),Le.deps?(n.prevDep=Le.depsTail,Le.depsTail.nextDep=n,Le.depsTail=n):Le.deps=Le.depsTail=n,Lc(n);else if(n.version===-1&&(n.version=this.version,n.nextDep)){const o=n.nextDep;o.prevDep=n.prevDep,n.prevDep&&(n.prevDep.nextDep=o),n.prevDep=Le.depsTail,n.nextDep=void 0,Le.depsTail.nextDep=n,Le.depsTail=n,Le.deps===n&&(Le.deps=o)}return n}trigger(t){this.version++,nr++,this.notify(t)}notify(t){ns();try{for(let n=this.subs;n;n=n.prevSub)n.sub.notify()&&n.sub.dep.notify()}finally{os()}}}function Lc(e){if(e.dep.sc++,e.sub.flags&4){const t=e.dep.computed;if(t&&!e.dep.subs){t.flags|=20;for(let o=t.deps;o;o=o.nextDep)Lc(o)}const n=e.dep.subs;n!==e&&(e.prevSub=n,n&&(n.nextSub=e)),e.dep.subs=e}}const ja=new WeakMap,Kn=Symbol(""),Na=Symbol(""),or=Symbol("");function Je(e,t,n){if(_t&&Le){let o=ja.get(e);o||ja.set(e,o=new Map);let i=o.get(n);i||(o.set(n,i=new is),i.map=o,i.key=n),i.track()}}function sn(e,t,n,o,i,r){const a=ja.get(e);if(!a){nr++;return}const l=s=>{s&&s.trigger()};if(ns(),t==="clear")a.forEach(l);else{const s=de(e),d=s&&ts(n);if(s&&n==="length"){const u=Number(o);a.forEach((c,f)=>{(f==="length"||f===or||!gn(f)&&f>=u)&&l(c)})}else switch((n!==void 0||a.has(void 0))&&l(a.get(n)),d&&l(a.get(or)),t){case"add":s?d&&l(a.get("length")):(l(a.get(Kn)),ho(e)&&l(a.get(Na)));break;case"delete":s||(l(a.get(Kn)),ho(e)&&l(a.get(Na)));break;case"set":ho(e)&&l(a.get(Kn));break}}os()}function oo(e){const t=xe(e);return t===e?t:(Je(t,"iterate",or),It(e)?t:t.map(Dt))}function Qi(e){return Je(e=xe(e),"iterate",or),e}function Cn(e,t){return hn(e)?Wn(e)?vo(Dt(t)):vo(t):Dt(t)}const Zh={__proto__:null,[Symbol.iterator](){return ba(this,Symbol.iterator,e=>Cn(this,e))},concat(...e){return oo(this).concat(...e.map(t=>de(t)?oo(t):t))},entries(){return ba(this,"entries",e=>(e[1]=Cn(this,e[1]),e))},every(e,t){return tn(this,"every",e,t,void 0,arguments)},filter(e,t){return tn(this,"filter",e,t,n=>n.map(o=>Cn(this,o)),arguments)},find(e,t){return tn(this,"find",e,t,n=>Cn(this,n),arguments)},findIndex(e,t){return tn(this,"findIndex",e,t,void 0,arguments)},findLast(e,t){return tn(this,"findLast",e,t,n=>Cn(this,n),arguments)},findLastIndex(e,t){return tn(this,"findLastIndex",e,t,void 0,arguments)},forEach(e,t){return tn(this,"forEach",e,t,void 0,arguments)},includes(...e){return ya(this,"includes",e)},indexOf(...e){return ya(this,"indexOf",e)},join(e){return oo(this).join(e)},lastIndexOf(...e){return ya(this,"lastIndexOf",e)},map(e,t){return tn(this,"map",e,t,void 0,arguments)},pop(){return Lo(this,"pop")},push(...e){return Lo(this,"push",e)},reduce(e,...t){return Hs(this,"reduce",e,t)},reduceRight(e,...t){return Hs(this,"reduceRight",e,t)},shift(){return Lo(this,"shift")},some(e,t){return tn(this,"some",e,t,void 0,arguments)},splice(...e){return Lo(this,"splice",e)},toReversed(){return oo(this).toReversed()},toSorted(e){return oo(this).toSorted(e)},toSpliced(...e){return oo(this).toSpliced(...e)},unshift(...e){return Lo(this,"unshift",e)},values(){return ba(this,"values",e=>Cn(this,e))}};function ba(e,t,n){const o=Qi(e),i=o[t]();return o!==e&&!It(e)&&(i._next=i.next,i.next=()=>{const r=i._next();return r.done||(r.value=n(r.value)),r}),i}const Yh=Array.prototype;function tn(e,t,n,o,i,r){const a=Qi(e),l=a!==e&&!It(e),s=a[t];if(s!==Yh[t]){const c=s.apply(e,r);return l?Dt(c):c}let d=n;a!==e&&(l?d=function(c,f){return n.call(this,Cn(e,c),f,e)}:n.length>2&&(d=function(c,f){return n.call(this,c,f,e)}));const u=s.call(a,d,o);return l&&i?i(u):u}function Hs(e,t,n,o){const i=Qi(e);let r=n;return i!==e&&(It(e)?n.length>3&&(r=function(a,l,s){return n.call(this,a,l,s,e)}):r=function(a,l,s){return n.call(this,a,Cn(e,l),s,e)}),i[t](r,...o)}function ya(e,t,n){const o=xe(e);Je(o,"iterate",or);const i=o[t](...n);return(i===-1||i===!1)&&ss(n[0])?(n[0]=xe(n[0]),o[t](...n)):i}function Lo(e,t,n=[]){fn(),ns();const o=xe(e)[t].apply(e,n);return os(),pn(),o}const Xh=Xl("__proto__,__v_isRef,__isVue"),_c=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(gn));function Jh(e){gn(e)||(e=String(e));const t=xe(this);return Je(t,"has",e),t.hasOwnProperty(e)}class Dc{constructor(t=!1,n=!1){this._isReadonly=t,this._isShallow=n}get(t,n,o){if(n==="__v_skip")return t.__v_skip;const i=this._isReadonly,r=this._isShallow;if(n==="__v_isReactive")return!i;if(n==="__v_isReadonly")return i;if(n==="__v_isShallow")return r;if(n==="__v_raw")return o===(i?r?dg:Fc:r?zc:Mc).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(o)?t:void 0;const a=de(t);if(!i){let s;if(a&&(s=Zh[n]))return s;if(n==="hasOwnProperty")return Jh}const l=Reflect.get(t,n,ot(t)?t:o);if((gn(n)?_c.has(n):Xh(n))||(i||Je(t,"get",n),r))return l;if(ot(l)){const s=a&&ts(n)?l:l.value;return i&&_e(s)?Oi(s):s}return _e(l)?i?Oi(l):Po(l):l}}class Bc extends Dc{constructor(t=!1){super(!1,t)}set(t,n,o,i){let r=t[n];const a=de(t)&&ts(n);if(!this._isShallow){const d=hn(r);if(!It(o)&&!hn(o)&&(r=xe(r),o=xe(o)),!a&&ot(r)&&!ot(o))return d||(r.value=o),!0}const l=a?Number(n)e,li=e=>Reflect.getPrototypeOf(e);function rg(e,t,n){return function(...o){const i=this.__v_raw,r=xe(i),a=ho(r),l=e==="entries"||e===Symbol.iterator&&a,s=e==="keys"&&a,d=i[e](...o),u=n?Va:t?vo:Dt;return!t&&Je(r,"iterate",s?Na:Kn),{next(){const{value:c,done:f}=d.next();return f?{value:c,done:f}:{value:l?[u(c[0]),u(c[1])]:u(c),done:f}},[Symbol.iterator](){return this}}}}function si(e){return function(...t){return e==="delete"?!1:e==="clear"?void 0:this}}function ig(e,t){const n={get(i){const r=this.__v_raw,a=xe(r),l=xe(i);e||(Rn(i,l)&&Je(a,"get",i),Je(a,"get",l));const{has:s}=li(a),d=t?Va:e?vo:Dt;if(s.call(a,i))return d(r.get(i));if(s.call(a,l))return d(r.get(l));r!==a&&r.get(i)},get size(){const i=this.__v_raw;return!e&&Je(xe(i),"iterate",Kn),i.size},has(i){const r=this.__v_raw,a=xe(r),l=xe(i);return e||(Rn(i,l)&&Je(a,"has",i),Je(a,"has",l)),i===l?r.has(i):r.has(i)||r.has(l)},forEach(i,r){const a=this,l=a.__v_raw,s=xe(l),d=t?Va:e?vo:Dt;return!e&&Je(s,"iterate",Kn),l.forEach((u,c)=>i.call(r,d(u),d(c),a))}};return qe(n,e?{add:si("add"),set:si("set"),delete:si("delete"),clear:si("clear")}:{add(i){!t&&!It(i)&&!hn(i)&&(i=xe(i));const r=xe(this);return li(r).has.call(r,i)||(r.add(i),sn(r,"add",i,i)),this},set(i,r){!t&&!It(r)&&!hn(r)&&(r=xe(r));const a=xe(this),{has:l,get:s}=li(a);let d=l.call(a,i);d||(i=xe(i),d=l.call(a,i));const u=s.call(a,i);return a.set(i,r),d?Rn(r,u)&&sn(a,"set",i,r):sn(a,"add",i,r),this},delete(i){const r=xe(this),{has:a,get:l}=li(r);let s=a.call(r,i);s||(i=xe(i),s=a.call(r,i)),l&&l.call(r,i);const d=r.delete(i);return s&&sn(r,"delete",i,void 0),d},clear(){const i=xe(this),r=i.size!==0,a=i.clear();return r&&sn(i,"clear",void 0,void 0),a}}),["keys","values","entries",Symbol.iterator].forEach(i=>{n[i]=rg(i,e,t)}),n}function as(e,t){const n=ig(e,t);return(o,i,r)=>i==="__v_isReactive"?!e:i==="__v_isReadonly"?e:i==="__v_raw"?o:Reflect.get(Ie(n,i)&&i in o?n:o,i,r)}const ag={get:as(!1,!1)},lg={get:as(!1,!0)},sg={get:as(!0,!1)};const Mc=new WeakMap,zc=new WeakMap,Fc=new WeakMap,dg=new WeakMap;function ug(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function cg(e){return e.__v_skip||!Object.isExtensible(e)?0:ug(Dh(e))}function Po(e){return hn(e)?e:ls(e,!1,tg,ag,Mc)}function jc(e){return ls(e,!1,og,lg,zc)}function Oi(e){return ls(e,!0,ng,sg,Fc)}function ls(e,t,n,o,i){if(!_e(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const r=cg(e);if(r===0)return e;const a=i.get(e);if(a)return a;const l=new Proxy(e,r===2?o:n);return i.set(e,l),l}function Wn(e){return hn(e)?Wn(e.__v_raw):!!(e&&e.__v_isReactive)}function hn(e){return!!(e&&e.__v_isReadonly)}function It(e){return!!(e&&e.__v_isShallow)}function ss(e){return e?!!e.__v_raw:!1}function xe(e){const t=e&&e.__v_raw;return t?xe(t):e}function fg(e){return!Ie(e,"__v_skip")&&Object.isExtensible(e)&&Cc(e,"__v_skip",!0),e}const Dt=e=>_e(e)?Po(e):e,vo=e=>_e(e)?Oi(e):e;function ot(e){return e?e.__v_isRef===!0:!1}function Wo(e){return Nc(e,!1)}function pg(e){return Nc(e,!0)}function Nc(e,t){return ot(e)?e:new hg(e,t)}class hg{constructor(t,n){this.dep=new is,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=n?t:xe(t),this._value=n?t:Dt(t),this.__v_isShallow=n}get value(){return this.dep.track(),this._value}set value(t){const n=this._rawValue,o=this.__v_isShallow||It(t)||hn(t);t=o?t:xe(t),Rn(t,n)&&(this._rawValue=t,this._value=o?t:Dt(t),this.dep.trigger())}}function go(e){return ot(e)?e.value:e}const gg={get:(e,t,n)=>t==="__v_raw"?e:go(Reflect.get(e,t,n)),set:(e,t,n,o)=>{const i=e[t];return ot(i)&&!ot(n)?(i.value=n,!0):Reflect.set(e,t,n,o)}};function Vc(e){return Wn(e)?e:new Proxy(e,gg)}class mg{constructor(t,n,o){this.fn=t,this.setter=n,this._value=void 0,this.dep=new is(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=nr-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!n,this.isSSR=o}notify(){if(this.flags|=16,!(this.flags&8)&&Le!==this)return Tc(this,!0),!0}get value(){const t=this.dep.track();return Ec(this),t&&(t.version=this.dep.version),this._value}set value(t){this.setter&&this.setter(t)}}function bg(e,t,n=!1){let o,i;return he(e)?o=e:(o=e.get,i=e.set),new mg(o,i,n)}const di={},Ei=new WeakMap;let zn;function yg(e,t=!1,n=zn){if(n){let o=Ei.get(n);o||Ei.set(n,o=[]),o.push(e)}}function vg(e,t,n=Ee){const{immediate:o,deep:i,once:r,scheduler:a,augmentJob:l,call:s}=n,d=k=>i?k:It(k)||i===!1||i===0?dn(k,1):dn(k);let u,c,f,p,v=!1,C=!1;if(ot(e)?(c=()=>e.value,v=It(e)):Wn(e)?(c=()=>d(e),v=!0):de(e)?(C=!0,v=e.some(k=>Wn(k)||It(k)),c=()=>e.map(k=>{if(ot(k))return k.value;if(Wn(k))return d(k);if(he(k))return s?s(k,2):k()})):he(e)?t?c=s?()=>s(e,2):e:c=()=>{if(f){fn();try{f()}finally{pn()}}const k=zn;zn=u;try{return s?s(e,3,[p]):e(p)}finally{zn=k}}:c=Xt,t&&i){const k=c,F=i===!0?1/0:i;c=()=>dn(k(),F)}const S=Wh(),x=()=>{u.stop(),S&&S.active&&es(S.effects,u)};if(r&&t){const k=t;t=(...F)=>{k(...F),x()}}let P=C?new Array(e.length).fill(di):di;const L=k=>{if(!(!(u.flags&1)||!u.dirty&&!k))if(t){const F=u.run();if(i||v||(C?F.some((K,z)=>Rn(K,P[z])):Rn(F,P))){f&&f();const K=zn;zn=u;try{const z=[F,P===di?void 0:C&&P[0]===di?[]:P,p];P=F,s?s(t,3,z):t(...z)}finally{zn=K}}}else u.run()};return l&&l(L),u=new Pc(c),u.scheduler=a?()=>a(L,!1):L,p=k=>yg(k,!1,u),f=u.onStop=()=>{const k=Ei.get(u);if(k){if(s)s(k,4);else for(const F of k)F();Ei.delete(u)}},t?o?L(!0):P=u.run():a?a(L.bind(null,!0),!0):u.run(),x.pause=u.pause.bind(u),x.resume=u.resume.bind(u),x.stop=x,x}function dn(e,t=1/0,n){if(t<=0||!_e(e)||e.__v_skip||(n=n||new Map,(n.get(e)||0)>=t))return e;if(n.set(e,t),t--,ot(e))dn(e.value,t,n);else if(de(e))for(let o=0;o{dn(o,t,n)});else if(wc(e)){for(const o in e)dn(e[o],t,n);for(const o of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,o)&&dn(e[o],t,n)}return e}/** -* @vue/runtime-core v3.5.25 -* (c) 2018-present Yuxi (Evan) You and Vue contributors -* @license MIT -**/function ei(e,t,n,o){try{return o?e(...o):e()}catch(i){Zi(i,t,n)}}function Bt(e,t,n,o){if(he(e)){const i=ei(e,t,n,o);return i&&yc(i)&&i.catch(r=>{Zi(r,t,n)}),i}if(de(e)){const i=[];for(let r=0;r>>1,i=st[o],r=rr(i);r=rr(n)?st.push(e):st.splice(Cg(t),0,e),e.flags|=1,Hc()}}function Hc(){Ai||(Ai=Uc.then(Kc))}function kg(e){de(e)?mo.push(...e):kn&&e.id===-1?kn.splice(ao+1,0,e):e.flags&1||(mo.push(e),e.flags|=1),Hc()}function Gs(e,t,n=Wt+1){for(;nrr(n)-rr(o));if(mo.length=0,kn){kn.push(...t);return}for(kn=t,ao=0;aoe.id==null?e.flags&2?-1:1/0:e.id;function Kc(e){try{for(Wt=0;Wt{o._d&&Bi(-1);const r=Li(t);let a;try{a=e(...i)}finally{Li(r),o._d&&Bi(1)}return a};return o._n=!0,o._c=!0,o._d=!0,o}function zt(e,t){if(Ye===null)return e;const n=ta(Ye),o=e.dirs||(e.dirs=[]);for(let i=0;ie.__isTeleport,qo=e=>e&&(e.disabled||e.disabled===""),Ks=e=>e&&(e.defer||e.defer===""),Ws=e=>typeof SVGElement<"u"&&e instanceof SVGElement,qs=e=>typeof MathMLElement=="function"&&e instanceof MathMLElement,Ua=(e,t)=>{const n=e&&e.to;return ze(n)?t?t(n):null:n},Zc={name:"Teleport",__isTeleport:!0,process(e,t,n,o,i,r,a,l,s,d){const{mc:u,pc:c,pbc:f,o:{insert:p,querySelector:v,createText:C,createComment:S}}=d,x=qo(t.props);let{shapeFlag:P,children:L,dynamicChildren:k}=t;if(e==null){const F=t.el=C(""),K=t.anchor=C("");p(F,n,o),p(K,n,o);const z=(H,ee)=>{P&16&&u(L,H,ee,i,r,a,l,s)},q=()=>{const H=t.target=Ua(t.props,v),ee=Yc(H,t,C,p);H&&(a!=="svg"&&Ws(H)?a="svg":a!=="mathml"&&qs(H)&&(a="mathml"),i&&i.isCE&&(i.ce._teleportTargets||(i.ce._teleportTargets=new Set)).add(H),x||(z(H,ee),Si(t,!1)))};x&&(z(n,K),Si(t,!0)),Ks(t.props)?(t.el.__isMounted=!1,at(()=>{q(),delete t.el.__isMounted},r)):q()}else{if(Ks(t.props)&&e.el.__isMounted===!1){at(()=>{Zc.process(e,t,n,o,i,r,a,l,s,d)},r);return}t.el=e.el,t.targetStart=e.targetStart;const F=t.anchor=e.anchor,K=t.target=e.target,z=t.targetAnchor=e.targetAnchor,q=qo(e.props),H=q?n:K,ee=q?F:z;if(a==="svg"||Ws(K)?a="svg":(a==="mathml"||qs(K))&&(a="mathml"),k?(f(e.dynamicChildren,k,H,i,r,a,l),ms(e,t,!0)):s||c(e,t,H,ee,i,r,a,l,!1),x)q?t.props&&e.props&&t.props.to!==e.props.to&&(t.props.to=e.props.to):ui(t,n,F,d,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){const X=t.target=Ua(t.props,v);X&&ui(t,X,null,d,0)}else q&&ui(t,K,z,d,1);Si(t,x)}},remove(e,t,n,{um:o,o:{remove:i}},r){const{shapeFlag:a,children:l,anchor:s,targetStart:d,targetAnchor:u,target:c,props:f}=e;if(c&&(i(d),i(u)),r&&i(s),a&16){const p=r||!qo(f);for(let v=0;v{e.isMounted=!0}),lf(()=>{e.isUnmounting=!0}),e}const $t=[Function,Array],Xc={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:$t,onEnter:$t,onAfterEnter:$t,onEnterCancelled:$t,onBeforeLeave:$t,onLeave:$t,onAfterLeave:$t,onLeaveCancelled:$t,onBeforeAppear:$t,onAppear:$t,onAfterAppear:$t,onAppearCancelled:$t},Jc=e=>{const t=e.subTree;return t.component?Jc(t.component):t},Pg={name:"BaseTransition",props:Xc,setup(e,{slots:t}){const n=dr(),o=$g();return()=>{const i=t.default&&nf(t.default(),!0);if(!i||!i.length)return;const r=ef(i),a=xe(e),{mode:l}=a;if(o.isLeaving)return va(r);const s=Qs(r);if(!s)return va(r);let d=Ha(s,a,o,n,c=>d=c);s.type!==et&&ir(s,d);let u=n.subTree&&Qs(n.subTree);if(u&&u.type!==et&&!jn(u,s)&&Jc(n).type!==et){let c=Ha(u,a,o,n);if(ir(u,c),l==="out-in"&&s.type!==et)return o.isLeaving=!0,c.afterLeave=()=>{o.isLeaving=!1,n.job.flags&8||n.update(),delete c.afterLeave,u=void 0},va(r);l==="in-out"&&s.type!==et?c.delayLeave=(f,p,v)=>{const C=tf(o,u);C[String(u.key)]=u,f[ln]=()=>{p(),f[ln]=void 0,delete d.delayedLeave,u=void 0},d.delayedLeave=()=>{v(),delete d.delayedLeave,u=void 0}}:u=void 0}else u&&(u=void 0);return r}}};function ef(e){let t=e[0];if(e.length>1){for(const n of e)if(n.type!==et){t=n;break}}return t}const Ig=Pg;function tf(e,t){const{leavingVNodes:n}=e;let o=n.get(t.type);return o||(o=Object.create(null),n.set(t.type,o)),o}function Ha(e,t,n,o,i){const{appear:r,mode:a,persisted:l=!1,onBeforeEnter:s,onEnter:d,onAfterEnter:u,onEnterCancelled:c,onBeforeLeave:f,onLeave:p,onAfterLeave:v,onLeaveCancelled:C,onBeforeAppear:S,onAppear:x,onAfterAppear:P,onAppearCancelled:L}=t,k=String(e.key),F=tf(n,e),K=(H,ee)=>{H&&Bt(H,o,9,ee)},z=(H,ee)=>{const X=ee[1];K(H,ee),de(H)?H.every(j=>j.length<=1)&&X():H.length<=1&&X()},q={mode:a,persisted:l,beforeEnter(H){let ee=s;if(!n.isMounted)if(r)ee=S||s;else return;H[ln]&&H[ln](!0);const X=F[k];X&&jn(e,X)&&X.el[ln]&&X.el[ln](),K(ee,[H])},enter(H){let ee=d,X=u,j=c;if(!n.isMounted)if(r)ee=x||d,X=P||u,j=L||c;else return;let le=!1;const pe=H[ci]=ue=>{le||(le=!0,ue?K(j,[H]):K(X,[H]),q.delayedLeave&&q.delayedLeave(),H[ci]=void 0)};ee?z(ee,[H,pe]):pe()},leave(H,ee){const X=String(e.key);if(H[ci]&&H[ci](!0),n.isUnmounting)return ee();K(f,[H]);let j=!1;const le=H[ln]=pe=>{j||(j=!0,ee(),pe?K(C,[H]):K(v,[H]),H[ln]=void 0,F[X]===e&&delete F[X])};F[X]=e,p?z(p,[H,le]):le()},clone(H){const ee=Ha(H,t,n,o,i);return i&&i(ee),ee}};return q}function va(e){if(Yi(e))return e=On(e),e.children=null,e}function Qs(e){if(!Yi(e))return Qc(e.type)&&e.children?ef(e.children):e;if(e.component)return e.component.subTree;const{shapeFlag:t,children:n}=e;if(n){if(t&16)return n[0];if(t&32&&he(n.default))return n.default()}}function ir(e,t){e.shapeFlag&6&&e.component?(e.transition=t,ir(e.component.subTree,t)):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function nf(e,t=!1,n){let o=[],i=0;for(let r=0;r1)for(let r=0;rQo(v,t&&(de(t)?t[C]:t),n,o,i));return}if(bo(o)&&!i){o.shapeFlag&512&&o.type.__asyncResolved&&o.component.subTree.component&&Qo(e,t,n,o.component.subTree);return}const r=o.shapeFlag&4?ta(o.component):o.el,a=i?null:r,{i:l,r:s}=e,d=t&&t.r,u=l.refs===Ee?l.refs={}:l.refs,c=l.setupState,f=xe(c),p=c===Ee?mc:v=>Ie(f,v);if(d!=null&&d!==s){if(Zs(t),ze(d))u[d]=null,p(d)&&(c[d]=null);else if(ot(d)){d.value=null;const v=t;v.k&&(u[v.k]=null)}}if(he(s))ei(s,l,12,[a,u]);else{const v=ze(s),C=ot(s);if(v||C){const S=()=>{if(e.f){const x=v?p(s)?c[s]:u[s]:s.value;if(i)de(x)&&es(x,r);else if(de(x))x.includes(r)||x.push(r);else if(v)u[s]=[r],p(s)&&(c[s]=u[s]);else{const P=[r];s.value=P,e.k&&(u[e.k]=P)}}else v?(u[s]=a,p(s)&&(c[s]=a)):C&&(s.value=a,e.k&&(u[e.k]=a))};if(a){const x=()=>{S(),_i.delete(e)};x.id=-1,_i.set(e,x),at(x,n)}else Zs(e),S()}}}function Zs(e){const t=_i.get(e);t&&(t.flags|=8,_i.delete(e))}Wi().requestIdleCallback;Wi().cancelIdleCallback;const bo=e=>!!e.type.__asyncLoader,Yi=e=>e.type.__isKeepAlive;function Rg(e,t){af(e,"a",t)}function Og(e,t){af(e,"da",t)}function af(e,t,n=tt){const o=e.__wdc||(e.__wdc=()=>{let i=n;for(;i;){if(i.isDeactivated)return;i=i.parent}return e()});if(Xi(t,o,n),n){let i=n.parent;for(;i&&i.parent;)Yi(i.parent.vnode)&&Eg(o,t,n,i),i=i.parent}}function Eg(e,t,n,o){const i=Xi(t,e,o,!0);sf(()=>{es(o[t],i)},n)}function Xi(e,t,n=tt,o=!1){if(n){const i=n[e]||(n[e]=[]),r=t.__weh||(t.__weh=(...a)=>{fn();const l=ti(n),s=Bt(t,n,e,a);return l(),pn(),s});return o?i.unshift(r):i.push(r),r}}const mn=e=>(t,n=tt)=>{(!ur||e==="sp")&&Xi(e,(...o)=>t(...o),n)},Ag=mn("bm"),cs=mn("m"),Lg=mn("bu"),_g=mn("u"),lf=mn("bum"),sf=mn("um"),Dg=mn("sp"),Bg=mn("rtg"),Mg=mn("rtc");function zg(e,t=tt){Xi("ec",e,t)}const fs="components",Fg="directives";function R(e,t){return ps(fs,e,!0,t)||e}const df=Symbol.for("v-ndc");function ae(e){return ze(e)?ps(fs,e,!1)||e:e||df}function Ft(e){return ps(Fg,e)}function ps(e,t,n=!0,o=!1){const i=Ye||tt;if(i){const r=i.type;if(e===fs){const l=$m(r,!1);if(l&&(l===t||l===Rt(t)||l===Ki(Rt(t))))return r}const a=Ys(i[e]||r[e],t)||Ys(i.appContext[e],t);return!a&&o?r:a}}function Ys(e,t){return e&&(e[t]||e[Rt(t)]||e[Ki(Rt(t))])}function Fe(e,t,n,o){let i;const r=n,a=de(e);if(a||ze(e)){const l=a&&Wn(e);let s=!1,d=!1;l&&(s=!It(e),d=hn(e),e=Qi(e)),i=new Array(e.length);for(let u=0,c=e.length;ut(l,s,void 0,r));else{const l=Object.keys(e);i=new Array(l.length);for(let s=0,d=l.length;s{const r=o.fn(...i);return r&&(r.key=o.key),r}:o.fn)}return e}function N(e,t,n={},o,i){if(Ye.ce||Ye.parent&&bo(Ye.parent)&&Ye.parent.ce){const d=Object.keys(n).length>0;return t!=="default"&&(n.name=t),g(),T(te,null,[D("slot",n,o&&o())],d?-2:64)}let r=e[t];r&&r._c&&(r._d=!1),g();const a=r&&uf(r(n)),l=n.key||a&&a.key,s=T(te,{key:(l&&!gn(l)?l:`_${t}`)+(!a&&o?"_fb":"")},a||(o?o():[]),a&&e._===1?64:-2);return s.scopeId&&(s.slotScopeIds=[s.scopeId+"-s"]),r&&r._c&&(r._d=!0),s}function uf(e){return e.some(t=>sr(t)?!(t.type===et||t.type===te&&!uf(t.children)):!0)?e:null}function fi(e,t){const n={};for(const o in e)n[/[A-Z]/.test(o)?`on:${o}`:ki(o)]=e[o];return n}const Ga=e=>e?Rf(e)?ta(e):Ga(e.parent):null,Zo=qe(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>Ga(e.parent),$root:e=>Ga(e.root),$host:e=>e.ce,$emit:e=>e.emit,$options:e=>ff(e),$forceUpdate:e=>e.f||(e.f=()=>{us(e.update)}),$nextTick:e=>e.n||(e.n=ds.bind(e.proxy)),$watch:e=>Zg.bind(e)}),wa=(e,t)=>e!==Ee&&!e.__isScriptSetup&&Ie(e,t),jg={get({_:e},t){if(t==="__v_skip")return!0;const{ctx:n,setupState:o,data:i,props:r,accessCache:a,type:l,appContext:s}=e;if(t[0]!=="$"){const f=a[t];if(f!==void 0)switch(f){case 1:return o[t];case 2:return i[t];case 4:return n[t];case 3:return r[t]}else{if(wa(o,t))return a[t]=1,o[t];if(i!==Ee&&Ie(i,t))return a[t]=2,i[t];if(Ie(r,t))return a[t]=3,r[t];if(n!==Ee&&Ie(n,t))return a[t]=4,n[t];Ka&&(a[t]=0)}}const d=Zo[t];let u,c;if(d)return t==="$attrs"&&Je(e.attrs,"get",""),d(e);if((u=l.__cssModules)&&(u=u[t]))return u;if(n!==Ee&&Ie(n,t))return a[t]=4,n[t];if(c=s.config.globalProperties,Ie(c,t))return c[t]},set({_:e},t,n){const{data:o,setupState:i,ctx:r}=e;return wa(i,t)?(i[t]=n,!0):o!==Ee&&Ie(o,t)?(o[t]=n,!0):Ie(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(r[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:o,appContext:i,props:r,type:a}},l){let s;return!!(n[l]||e!==Ee&&l[0]!=="$"&&Ie(e,l)||wa(t,l)||Ie(r,l)||Ie(o,l)||Ie(Zo,l)||Ie(i.config.globalProperties,l)||(s=a.__cssModules)&&s[l])},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:Ie(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function Xs(e){return de(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}let Ka=!0;function Ng(e){const t=ff(e),n=e.proxy,o=e.ctx;Ka=!1,t.beforeCreate&&Js(t.beforeCreate,e,"bc");const{data:i,computed:r,methods:a,watch:l,provide:s,inject:d,created:u,beforeMount:c,mounted:f,beforeUpdate:p,updated:v,activated:C,deactivated:S,beforeDestroy:x,beforeUnmount:P,destroyed:L,unmounted:k,render:F,renderTracked:K,renderTriggered:z,errorCaptured:q,serverPrefetch:H,expose:ee,inheritAttrs:X,components:j,directives:le,filters:pe}=t;if(d&&Vg(d,o,null),a)for(const ne in a){const ge=a[ne];he(ge)&&(o[ne]=ge.bind(n))}if(i){const ne=i.call(n,n);_e(ne)&&(e.data=Po(ne))}if(Ka=!0,r)for(const ne in r){const ge=r[ne],De=he(ge)?ge.bind(n,n):he(ge.get)?ge.get.bind(n,n):Xt,Ve=!he(ge)&&he(ge.set)?ge.set.bind(n):Xt,Ue=Ct({get:De,set:Ve});Object.defineProperty(o,ne,{enumerable:!0,configurable:!0,get:()=>Ue.value,set:je=>Ue.value=je})}if(l)for(const ne in l)cf(l[ne],o,n,ne);if(s){const ne=he(s)?s.call(n):s;Reflect.ownKeys(ne).forEach(ge=>{xi(ge,ne[ge])})}u&&Js(u,e,"c");function se(ne,ge){de(ge)?ge.forEach(De=>ne(De.bind(n))):ge&&ne(ge.bind(n))}if(se(Ag,c),se(cs,f),se(Lg,p),se(_g,v),se(Rg,C),se(Og,S),se(zg,q),se(Mg,K),se(Bg,z),se(lf,P),se(sf,k),se(Dg,H),de(ee))if(ee.length){const ne=e.exposed||(e.exposed={});ee.forEach(ge=>{Object.defineProperty(ne,ge,{get:()=>n[ge],set:De=>n[ge]=De,enumerable:!0})})}else e.exposed||(e.exposed={});F&&e.render===Xt&&(e.render=F),X!=null&&(e.inheritAttrs=X),j&&(e.components=j),le&&(e.directives=le),H&&rf(e)}function Vg(e,t,n=Xt){de(e)&&(e=Wa(e));for(const o in e){const i=e[o];let r;_e(i)?"default"in i?r=cn(i.from||o,i.default,!0):r=cn(i.from||o):r=cn(i),ot(r)?Object.defineProperty(t,o,{enumerable:!0,configurable:!0,get:()=>r.value,set:a=>r.value=a}):t[o]=r}}function Js(e,t,n){Bt(de(e)?e.map(o=>o.bind(t.proxy)):e.bind(t.proxy),t,n)}function cf(e,t,n,o){let i=o.includes(".")?gf(n,o):()=>n[o];if(ze(e)){const r=t[e];he(r)&&Lt(i,r)}else if(he(e))Lt(i,e.bind(n));else if(_e(e))if(de(e))e.forEach(r=>cf(r,t,n,o));else{const r=he(e.handler)?e.handler.bind(n):t[e.handler];he(r)&&Lt(i,r,e)}}function ff(e){const t=e.type,{mixins:n,extends:o}=t,{mixins:i,optionsCache:r,config:{optionMergeStrategies:a}}=e.appContext,l=r.get(t);let s;return l?s=l:!i.length&&!n&&!o?s=t:(s={},i.length&&i.forEach(d=>Di(s,d,a,!0)),Di(s,t,a)),_e(t)&&r.set(t,s),s}function Di(e,t,n,o=!1){const{mixins:i,extends:r}=t;r&&Di(e,r,n,!0),i&&i.forEach(a=>Di(e,a,n,!0));for(const a in t)if(!(o&&a==="expose")){const l=Ug[a]||n&&n[a];e[a]=l?l(e[a],t[a]):t[a]}return e}const Ug={data:ed,props:td,emits:td,methods:jo,computed:jo,beforeCreate:it,created:it,beforeMount:it,mounted:it,beforeUpdate:it,updated:it,beforeDestroy:it,beforeUnmount:it,destroyed:it,unmounted:it,activated:it,deactivated:it,errorCaptured:it,serverPrefetch:it,components:jo,directives:jo,watch:Gg,provide:ed,inject:Hg};function ed(e,t){return t?e?function(){return qe(he(e)?e.call(this,this):e,he(t)?t.call(this,this):t)}:t:e}function Hg(e,t){return jo(Wa(e),Wa(t))}function Wa(e){if(de(e)){const t={};for(let n=0;n1)return n&&he(t)?t.call(o&&o.proxy):t}}const qg=Symbol.for("v-scx"),Qg=()=>cn(qg);function Lt(e,t,n){return hf(e,t,n)}function hf(e,t,n=Ee){const{immediate:o,deep:i,flush:r,once:a}=n,l=qe({},n),s=t&&o||!t&&r!=="post";let d;if(ur){if(r==="sync"){const p=Qg();d=p.__watcherHandles||(p.__watcherHandles=[])}else if(!s){const p=()=>{};return p.stop=Xt,p.resume=Xt,p.pause=Xt,p}}const u=tt;l.call=(p,v,C)=>Bt(p,u,v,C);let c=!1;r==="post"?l.scheduler=p=>{at(p,u&&u.suspense)}:r!=="sync"&&(c=!0,l.scheduler=(p,v)=>{v?p():us(p)}),l.augmentJob=p=>{t&&(p.flags|=4),c&&(p.flags|=2,u&&(p.id=u.uid,p.i=u))};const f=vg(e,t,l);return ur&&(d?d.push(f):s&&f()),f}function Zg(e,t,n){const o=this.proxy,i=ze(e)?e.includes(".")?gf(o,e):()=>o[e]:e.bind(o,o);let r;he(t)?r=t:(r=t.handler,n=t);const a=ti(this),l=hf(i,r.bind(o),n);return a(),l}function gf(e,t){const n=t.split(".");return()=>{let o=e;for(let i=0;it==="modelValue"||t==="model-value"?e.modelModifiers:e[`${t}Modifiers`]||e[`${Rt(t)}Modifiers`]||e[`${En(t)}Modifiers`];function Xg(e,t,...n){if(e.isUnmounted)return;const o=e.vnode.props||Ee;let i=n;const r=t.startsWith("update:"),a=r&&Yg(o,t.slice(7));a&&(a.trim&&(i=n.map(u=>ze(u)?u.trim():u)),a.number&&(i=n.map(zh)));let l,s=o[l=ki(t)]||o[l=ki(Rt(t))];!s&&r&&(s=o[l=ki(En(t))]),s&&Bt(s,e,6,i);const d=o[l+"Once"];if(d){if(!e.emitted)e.emitted={};else if(e.emitted[l])return;e.emitted[l]=!0,Bt(d,e,6,i)}}const Jg=new WeakMap;function mf(e,t,n=!1){const o=n?Jg:t.emitsCache,i=o.get(e);if(i!==void 0)return i;const r=e.emits;let a={},l=!1;if(!he(e)){const s=d=>{const u=mf(d,t,!0);u&&(l=!0,qe(a,u))};!n&&t.mixins.length&&t.mixins.forEach(s),e.extends&&s(e.extends),e.mixins&&e.mixins.forEach(s)}return!r&&!l?(_e(e)&&o.set(e,null),null):(de(r)?r.forEach(s=>a[s]=null):qe(a,r),_e(e)&&o.set(e,a),a)}function Ji(e,t){return!e||!Ui(t)?!1:(t=t.slice(2).replace(/Once$/,""),Ie(e,t[0].toLowerCase()+t.slice(1))||Ie(e,En(t))||Ie(e,t))}function nd(e){const{type:t,vnode:n,proxy:o,withProxy:i,propsOptions:[r],slots:a,attrs:l,emit:s,render:d,renderCache:u,props:c,data:f,setupState:p,ctx:v,inheritAttrs:C}=e,S=Li(e);let x,P;try{if(n.shapeFlag&4){const k=i||o,F=k;x=qt(d.call(F,k,u,c,p,f,v)),P=l}else{const k=t;x=qt(k.length>1?k(c,{attrs:l,slots:a,emit:s}):k(c,null)),P=t.props?l:em(l)}}catch(k){Yo.length=0,Zi(k,e,1),x=D(et)}let L=x;if(P&&C!==!1){const k=Object.keys(P),{shapeFlag:F}=L;k.length&&F&7&&(r&&k.some(Jl)&&(P=tm(P,r)),L=On(L,P,!1,!0))}return n.dirs&&(L=On(L,null,!1,!0),L.dirs=L.dirs?L.dirs.concat(n.dirs):n.dirs),n.transition&&ir(L,n.transition),x=L,Li(S),x}const em=e=>{let t;for(const n in e)(n==="class"||n==="style"||Ui(n))&&((t||(t={}))[n]=e[n]);return t},tm=(e,t)=>{const n={};for(const o in e)(!Jl(o)||!(o.slice(9)in t))&&(n[o]=e[o]);return n};function nm(e,t,n){const{props:o,children:i,component:r}=e,{props:a,children:l,patchFlag:s}=t,d=r.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&s>=0){if(s&1024)return!0;if(s&16)return o?od(o,a,d):!!a;if(s&8){const u=t.dynamicProps;for(let c=0;cObject.create(bf),vf=e=>Object.getPrototypeOf(e)===bf;function rm(e,t,n,o=!1){const i={},r=yf();e.propsDefaults=Object.create(null),wf(e,t,i,r);for(const a in e.propsOptions[0])a in i||(i[a]=void 0);n?e.props=o?i:jc(i):e.type.props?e.props=i:e.props=r,e.attrs=r}function im(e,t,n,o){const{props:i,attrs:r,vnode:{patchFlag:a}}=e,l=xe(i),[s]=e.propsOptions;let d=!1;if((o||a>0)&&!(a&16)){if(a&8){const u=e.vnode.dynamicProps;for(let c=0;c{s=!0;const[f,p]=Cf(c,t,!0);qe(a,f),p&&l.push(...p)};!n&&t.mixins.length&&t.mixins.forEach(u),e.extends&&u(e.extends),e.mixins&&e.mixins.forEach(u)}if(!r&&!s)return _e(e)&&o.set(e,po),po;if(de(r))for(let u=0;ue==="_"||e==="_ctx"||e==="$stable",gs=e=>de(e)?e.map(qt):[qt(e)],lm=(e,t,n)=>{if(t._n)return t;const o=V((...i)=>gs(t(...i)),n);return o._c=!1,o},kf=(e,t,n)=>{const o=e._ctx;for(const i in e){if(hs(i))continue;const r=e[i];if(he(r))t[i]=lm(i,r,o);else if(r!=null){const a=gs(r);t[i]=()=>a}}},Sf=(e,t)=>{const n=gs(t);e.slots.default=()=>n},xf=(e,t,n)=>{for(const o in t)(n||!hs(o))&&(e[o]=t[o])},sm=(e,t,n)=>{const o=e.slots=yf();if(e.vnode.shapeFlag&32){const i=t._;i?(xf(o,t,n),n&&Cc(o,"_",i,!0)):kf(t,o)}else t&&Sf(e,t)},dm=(e,t,n)=>{const{vnode:o,slots:i}=e;let r=!0,a=Ee;if(o.shapeFlag&32){const l=t._;l?n&&l===1?r=!1:xf(i,t,n):(r=!t.$stable,kf(t,i)),a=t}else t&&(Sf(e,t),a={default:1});if(r)for(const l in i)!hs(l)&&a[l]==null&&delete i[l]},at=hm;function um(e){return cm(e)}function cm(e,t){const n=Wi();n.__VUE__=!0;const{insert:o,remove:i,patchProp:r,createElement:a,createText:l,createComment:s,setText:d,setElementText:u,parentNode:c,nextSibling:f,setScopeId:p=Xt,insertStaticContent:v}=e,C=(y,w,$,E=null,B=null,O=null,W=void 0,G=null,U=!!w.dynamicChildren)=>{if(y===w)return;y&&!jn(y,w)&&(E=A(y),je(y,B,O,!0),y=null),w.patchFlag===-2&&(U=!1,w.dynamicChildren=null);const{type:M,ref:ie,shapeFlag:Z}=w;switch(M){case ea:S(y,w,$,E);break;case et:x(y,w,$,E);break;case ka:y==null&&P(w,$,E,W);break;case te:j(y,w,$,E,B,O,W,G,U);break;default:Z&1?F(y,w,$,E,B,O,W,G,U):Z&6?le(y,w,$,E,B,O,W,G,U):(Z&64||Z&128)&&M.process(y,w,$,E,B,O,W,G,U,oe)}ie!=null&&B?Qo(ie,y&&y.ref,O,w||y,!w):ie==null&&y&&y.ref!=null&&Qo(y.ref,null,O,y,!0)},S=(y,w,$,E)=>{if(y==null)o(w.el=l(w.children),$,E);else{const B=w.el=y.el;w.children!==y.children&&d(B,w.children)}},x=(y,w,$,E)=>{y==null?o(w.el=s(w.children||""),$,E):w.el=y.el},P=(y,w,$,E)=>{[y.el,y.anchor]=v(y.children,w,$,E,y.el,y.anchor)},L=({el:y,anchor:w},$,E)=>{let B;for(;y&&y!==w;)B=f(y),o(y,$,E),y=B;o(w,$,E)},k=({el:y,anchor:w})=>{let $;for(;y&&y!==w;)$=f(y),i(y),y=$;i(w)},F=(y,w,$,E,B,O,W,G,U)=>{if(w.type==="svg"?W="svg":w.type==="math"&&(W="mathml"),y==null)K(w,$,E,B,O,W,G,U);else{const M=y.el&&y.el._isVueCE?y.el:null;try{M&&M._beginPatch(),H(y,w,B,O,W,G,U)}finally{M&&M._endPatch()}}},K=(y,w,$,E,B,O,W,G)=>{let U,M;const{props:ie,shapeFlag:Z,transition:re,dirs:ce}=y;if(U=y.el=a(y.type,O,ie&&ie.is,ie),Z&8?u(U,y.children):Z&16&&q(y.children,U,null,E,B,Ca(y,O),W,G),ce&&Ln(y,null,E,"created"),z(U,y,y.scopeId,W,E),ie){for(const Ae in ie)Ae!=="value"&&!Ho(Ae)&&r(U,Ae,null,ie[Ae],O,E);"value"in ie&&r(U,"value",null,ie.value,O),(M=ie.onVnodeBeforeMount)&&Gt(M,E,y)}ce&&Ln(y,null,E,"beforeMount");const ke=fm(B,re);ke&&re.beforeEnter(U),o(U,w,$),((M=ie&&ie.onVnodeMounted)||ke||ce)&&at(()=>{M&&Gt(M,E,y),ke&&re.enter(U),ce&&Ln(y,null,E,"mounted")},B)},z=(y,w,$,E,B)=>{if($&&p(y,$),E)for(let O=0;O{for(let M=U;M{const G=w.el=y.el;let{patchFlag:U,dynamicChildren:M,dirs:ie}=w;U|=y.patchFlag&16;const Z=y.props||Ee,re=w.props||Ee;let ce;if($&&_n($,!1),(ce=re.onVnodeBeforeUpdate)&&Gt(ce,$,w,y),ie&&Ln(w,y,$,"beforeUpdate"),$&&_n($,!0),(Z.innerHTML&&re.innerHTML==null||Z.textContent&&re.textContent==null)&&u(G,""),M?ee(y.dynamicChildren,M,G,$,E,Ca(w,B),O):W||ge(y,w,G,null,$,E,Ca(w,B),O,!1),U>0){if(U&16)X(G,Z,re,$,B);else if(U&2&&Z.class!==re.class&&r(G,"class",null,re.class,B),U&4&&r(G,"style",Z.style,re.style,B),U&8){const ke=w.dynamicProps;for(let Ae=0;Ae{ce&&Gt(ce,$,w,y),ie&&Ln(w,y,$,"updated")},E)},ee=(y,w,$,E,B,O,W)=>{for(let G=0;G{if(w!==$){if(w!==Ee)for(const O in w)!Ho(O)&&!(O in $)&&r(y,O,w[O],null,B,E);for(const O in $){if(Ho(O))continue;const W=$[O],G=w[O];W!==G&&O!=="value"&&r(y,O,G,W,B,E)}"value"in $&&r(y,"value",w.value,$.value,B)}},j=(y,w,$,E,B,O,W,G,U)=>{const M=w.el=y?y.el:l(""),ie=w.anchor=y?y.anchor:l("");let{patchFlag:Z,dynamicChildren:re,slotScopeIds:ce}=w;ce&&(G=G?G.concat(ce):ce),y==null?(o(M,$,E),o(ie,$,E),q(w.children||[],$,ie,B,O,W,G,U)):Z>0&&Z&64&&re&&y.dynamicChildren?(ee(y.dynamicChildren,re,$,B,O,W,G),(w.key!=null||B&&w===B.subTree)&&ms(y,w,!0)):ge(y,w,$,ie,B,O,W,G,U)},le=(y,w,$,E,B,O,W,G,U)=>{w.slotScopeIds=G,y==null?w.shapeFlag&512?B.ctx.activate(w,$,E,W,U):pe(w,$,E,B,O,W,U):ue(y,w,U)},pe=(y,w,$,E,B,O,W)=>{const G=y.component=wm(y,E,B);if(Yi(y)&&(G.ctx.renderer=oe),Cm(G,!1,W),G.asyncDep){if(B&&B.registerDep(G,se,W),!y.el){const U=G.subTree=D(et);x(null,U,w,$),y.placeholder=U.el}}else se(G,y,w,$,B,O,W)},ue=(y,w,$)=>{const E=w.component=y.component;if(nm(y,w,$))if(E.asyncDep&&!E.asyncResolved){ne(E,w,$);return}else E.next=w,E.update();else w.el=y.el,E.vnode=w},se=(y,w,$,E,B,O,W)=>{const G=()=>{if(y.isMounted){let{next:Z,bu:re,u:ce,parent:ke,vnode:Ae}=y;{const Ut=$f(y);if(Ut){Z&&(Z.el=Ae.el,ne(y,Z,W)),Ut.asyncDep.then(()=>{y.isUnmounted||G()});return}}let Re=Z,ut;_n(y,!1),Z?(Z.el=Ae.el,ne(y,Z,W)):Z=Ae,re&&ha(re),(ut=Z.props&&Z.props.onVnodeBeforeUpdate)&&Gt(ut,ke,Z,Ae),_n(y,!0);const ct=nd(y),Vt=y.subTree;y.subTree=ct,C(Vt,ct,c(Vt.el),A(Vt),y,B,O),Z.el=ct.el,Re===null&&om(y,ct.el),ce&&at(ce,B),(ut=Z.props&&Z.props.onVnodeUpdated)&&at(()=>Gt(ut,ke,Z,Ae),B)}else{let Z;const{el:re,props:ce}=w,{bm:ke,m:Ae,parent:Re,root:ut,type:ct}=y,Vt=bo(w);_n(y,!1),ke&&ha(ke),!Vt&&(Z=ce&&ce.onVnodeBeforeMount)&&Gt(Z,Re,w),_n(y,!0);{ut.ce&&ut.ce._def.shadowRoot!==!1&&ut.ce._injectChildStyle(ct);const Ut=y.subTree=nd(y);C(null,Ut,$,E,y,B,O),w.el=Ut.el}if(Ae&&at(Ae,B),!Vt&&(Z=ce&&ce.onVnodeMounted)){const Ut=w;at(()=>Gt(Z,Re,Ut),B)}(w.shapeFlag&256||Re&&bo(Re.vnode)&&Re.vnode.shapeFlag&256)&&y.a&&at(y.a,B),y.isMounted=!0,w=$=E=null}};y.scope.on();const U=y.effect=new Pc(G);y.scope.off();const M=y.update=U.run.bind(U),ie=y.job=U.runIfDirty.bind(U);ie.i=y,ie.id=y.uid,U.scheduler=()=>us(ie),_n(y,!0),M()},ne=(y,w,$)=>{w.component=y;const E=y.vnode.props;y.vnode=w,y.next=null,im(y,w.props,E,$),dm(y,w.children,$),fn(),Gs(y),pn()},ge=(y,w,$,E,B,O,W,G,U=!1)=>{const M=y&&y.children,ie=y?y.shapeFlag:0,Z=w.children,{patchFlag:re,shapeFlag:ce}=w;if(re>0){if(re&128){Ve(M,Z,$,E,B,O,W,G,U);return}else if(re&256){De(M,Z,$,E,B,O,W,G,U);return}}ce&8?(ie&16&&rt(M,B,O),Z!==M&&u($,Z)):ie&16?ce&16?Ve(M,Z,$,E,B,O,W,G,U):rt(M,B,O,!0):(ie&8&&u($,""),ce&16&&q(Z,$,E,B,O,W,G,U))},De=(y,w,$,E,B,O,W,G,U)=>{y=y||po,w=w||po;const M=y.length,ie=w.length,Z=Math.min(M,ie);let re;for(re=0;reie?rt(y,B,O,!0,!1,Z):q(w,$,E,B,O,W,G,U,Z)},Ve=(y,w,$,E,B,O,W,G,U)=>{let M=0;const ie=w.length;let Z=y.length-1,re=ie-1;for(;M<=Z&&M<=re;){const ce=y[M],ke=w[M]=U?Sn(w[M]):qt(w[M]);if(jn(ce,ke))C(ce,ke,$,null,B,O,W,G,U);else break;M++}for(;M<=Z&&M<=re;){const ce=y[Z],ke=w[re]=U?Sn(w[re]):qt(w[re]);if(jn(ce,ke))C(ce,ke,$,null,B,O,W,G,U);else break;Z--,re--}if(M>Z){if(M<=re){const ce=re+1,ke=cere)for(;M<=Z;)je(y[M],B,O,!0),M++;else{const ce=M,ke=M,Ae=new Map;for(M=ke;M<=re;M++){const yt=w[M]=U?Sn(w[M]):qt(w[M]);yt.key!=null&&Ae.set(yt.key,M)}let Re,ut=0;const ct=re-ke+1;let Vt=!1,Ut=0;const Ao=new Array(ct);for(M=0;M=ct){je(yt,B,O,!0);continue}let Ht;if(yt.key!=null)Ht=Ae.get(yt.key);else for(Re=ke;Re<=re;Re++)if(Ao[Re-ke]===0&&jn(yt,w[Re])){Ht=Re;break}Ht===void 0?je(yt,B,O,!0):(Ao[Ht-ke]=M+1,Ht>=Ut?Ut=Ht:Vt=!0,C(yt,w[Ht],$,null,B,O,W,G,U),ut++)}const Fs=Vt?pm(Ao):po;for(Re=Fs.length-1,M=ct-1;M>=0;M--){const yt=ke+M,Ht=w[yt],js=w[yt+1],Ns=yt+1{const{el:O,type:W,transition:G,children:U,shapeFlag:M}=y;if(M&6){Ue(y.component.subTree,w,$,E);return}if(M&128){y.suspense.move(w,$,E);return}if(M&64){W.move(y,w,$,oe);return}if(W===te){o(O,w,$);for(let Z=0;ZG.enter(O),B);else{const{leave:Z,delayLeave:re,afterLeave:ce}=G,ke=()=>{y.ctx.isUnmounted?i(O):o(O,w,$)},Ae=()=>{O._isLeaving&&O[ln](!0),Z(O,()=>{ke(),ce&&ce()})};re?re(O,ke,Ae):Ae()}else o(O,w,$)},je=(y,w,$,E=!1,B=!1)=>{const{type:O,props:W,ref:G,children:U,dynamicChildren:M,shapeFlag:ie,patchFlag:Z,dirs:re,cacheIndex:ce}=y;if(Z===-2&&(B=!1),G!=null&&(fn(),Qo(G,null,$,y,!0),pn()),ce!=null&&(w.renderCache[ce]=void 0),ie&256){w.ctx.deactivate(y);return}const ke=ie&1&&re,Ae=!bo(y);let Re;if(Ae&&(Re=W&&W.onVnodeBeforeUnmount)&&Gt(Re,w,y),ie&6)Nt(y.component,$,E);else{if(ie&128){y.suspense.unmount($,E);return}ke&&Ln(y,null,w,"beforeUnmount"),ie&64?y.type.remove(y,w,$,oe,E):M&&!M.hasOnce&&(O!==te||Z>0&&Z&64)?rt(M,w,$,!1,!0):(O===te&&Z&384||!B&&ie&16)&&rt(U,w,$),E&&Ot(y)}(Ae&&(Re=W&&W.onVnodeUnmounted)||ke)&&at(()=>{Re&&Gt(Re,w,y),ke&&Ln(y,null,w,"unmounted")},$)},Ot=y=>{const{type:w,el:$,anchor:E,transition:B}=y;if(w===te){bt($,E);return}if(w===ka){k(y);return}const O=()=>{i($),B&&!B.persisted&&B.afterLeave&&B.afterLeave()};if(y.shapeFlag&1&&B&&!B.persisted){const{leave:W,delayLeave:G}=B,U=()=>W($,O);G?G(y.el,O,U):U()}else O()},bt=(y,w)=>{let $;for(;y!==w;)$=f(y),i(y),y=$;i(w)},Nt=(y,w,$)=>{const{bum:E,scope:B,job:O,subTree:W,um:G,m:U,a:M}=y;id(U),id(M),E&&ha(E),B.stop(),O&&(O.flags|=8,je(W,y,w,$)),G&&at(G,w),at(()=>{y.isUnmounted=!0},w)},rt=(y,w,$,E=!1,B=!1,O=0)=>{for(let W=O;W{if(y.shapeFlag&6)return A(y.component.subTree);if(y.shapeFlag&128)return y.suspense.next();const w=f(y.anchor||y.el),$=w&&w[qc];return $?f($):w};let Y=!1;const Q=(y,w,$)=>{y==null?w._vnode&&je(w._vnode,null,null,!0):C(w._vnode||null,y,w,null,null,null,$),w._vnode=y,Y||(Y=!0,Gs(),Gc(),Y=!1)},oe={p:C,um:je,m:Ue,r:Ot,mt:pe,mc:q,pc:ge,pbc:ee,n:A,o:e};return{render:Q,hydrate:void 0,createApp:Wg(Q)}}function Ca({type:e,props:t},n){return n==="svg"&&e==="foreignObject"||n==="mathml"&&e==="annotation-xml"&&t&&t.encoding&&t.encoding.includes("html")?void 0:n}function _n({effect:e,job:t},n){n?(e.flags|=32,t.flags|=4):(e.flags&=-33,t.flags&=-5)}function fm(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function ms(e,t,n=!1){const o=e.children,i=t.children;if(de(o)&&de(i))for(let r=0;r>1,e[n[l]]0&&(t[o]=n[r-1]),n[r]=o)}}for(r=n.length,a=n[r-1];r-- >0;)n[r]=a,a=t[a];return n}function $f(e){const t=e.subTree.component;if(t)return t.asyncDep&&!t.asyncResolved?t:$f(t)}function id(e){if(e)for(let t=0;te.__isSuspense;function hm(e,t){t&&t.pendingBranch?de(e)?t.effects.push(...e):t.effects.push(e):kg(e)}const te=Symbol.for("v-fgt"),ea=Symbol.for("v-txt"),et=Symbol.for("v-cmt"),ka=Symbol.for("v-stc"),Yo=[];let kt=null;function g(e=!1){Yo.push(kt=e?null:[])}function gm(){Yo.pop(),kt=Yo[Yo.length-1]||null}let lr=1;function Bi(e,t=!1){lr+=e,e<0&&kt&&t&&(kt.hasOnce=!0)}function If(e){return e.dynamicChildren=lr>0?kt||po:null,gm(),lr>0&&kt&&kt.push(e),e}function b(e,t,n,o,i,r){return If(h(e,t,n,o,i,r,!0))}function T(e,t,n,o,i){return If(D(e,t,n,o,i,!0))}function sr(e){return e?e.__v_isVNode===!0:!1}function jn(e,t){return e.type===t.type&&e.key===t.key}const Tf=({key:e})=>e??null,$i=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?ze(e)||ot(e)||he(e)?{i:Ye,r:e,k:t,f:!!n}:e:null);function h(e,t=null,n=null,o=0,i=null,r=e===te?0:1,a=!1,l=!1){const s={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Tf(t),ref:t&&$i(t),scopeId:Wc,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:r,patchFlag:o,dynamicProps:i,dynamicChildren:null,appContext:null,ctx:Ye};return l?(bs(s,n),r&128&&e.normalize(s)):n&&(s.shapeFlag|=ze(n)?8:16),lr>0&&!a&&kt&&(s.patchFlag>0||r&6)&&s.patchFlag!==32&&kt.push(s),s}const D=mm;function mm(e,t=null,n=null,o=0,i=null,r=!1){if((!e||e===df)&&(e=et),sr(e)){const l=On(e,t,!0);return n&&bs(l,n),lr>0&&!r&&kt&&(l.shapeFlag&6?kt[kt.indexOf(e)]=l:kt.push(l)),l.patchFlag=-2,l}if(Pm(e)&&(e=e.__vccOpts),t){t=bm(t);let{class:l,style:s}=t;l&&!ze(l)&&(t.class=J(l)),_e(s)&&(ss(s)&&!de(s)&&(s=qe({},s)),t.style=$o(s))}const a=ze(e)?1:Pf(e)?128:Qc(e)?64:_e(e)?4:he(e)?2:0;return h(e,t,n,o,i,a,r,!0)}function bm(e){return e?ss(e)||vf(e)?qe({},e):e:null}function On(e,t,n=!1,o=!1){const{props:i,ref:r,patchFlag:a,children:l,transition:s}=e,d=t?m(i||{},t):i,u={__v_isVNode:!0,__v_skip:!0,type:e.type,props:d,key:d&&Tf(d),ref:t&&t.ref?n&&r?de(r)?r.concat($i(t)):[r,$i(t)]:$i(t):r,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:l,target:e.target,targetStart:e.targetStart,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==te?a===-1?16:a|16:a,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:s,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&On(e.ssContent),ssFallback:e.ssFallback&&On(e.ssFallback),placeholder:e.placeholder,el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce};return s&&o&&ir(u,s.clone(u)),u}function $e(e=" ",t=0){return D(ea,null,e,t)}function I(e="",t=!1){return t?(g(),T(et,null,e)):D(et,null,e)}function qt(e){return e==null||typeof e=="boolean"?D(et):de(e)?D(te,null,e.slice()):sr(e)?Sn(e):D(ea,null,String(e))}function Sn(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:On(e)}function bs(e,t){let n=0;const{shapeFlag:o}=e;if(t==null)t=null;else if(de(t))n=16;else if(typeof t=="object")if(o&65){const i=t.default;i&&(i._c&&(i._d=!1),bs(e,i()),i._c&&(i._d=!0));return}else{n=32;const i=t._;!i&&!vf(t)?t._ctx=Ye:i===3&&Ye&&(Ye.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else he(t)?(t={default:t,_ctx:Ye},n=32):(t=String(t),o&64?(n=16,t=[$e(t)]):n=8);e.children=t,e.shapeFlag|=n}function m(...e){const t={};for(let n=0;ntt||Ye;let Mi,Qa;{const e=Wi(),t=(n,o)=>{let i;return(i=e[n])||(i=e[n]=[]),i.push(o),r=>{i.length>1?i.forEach(a=>a(r)):i[0](r)}};Mi=t("__VUE_INSTANCE_SETTERS__",n=>tt=n),Qa=t("__VUE_SSR_SETTERS__",n=>ur=n)}const ti=e=>{const t=tt;return Mi(e),e.scope.on(),()=>{e.scope.off(),Mi(t)}},ad=()=>{tt&&tt.scope.off(),Mi(null)};function Rf(e){return e.vnode.shapeFlag&4}let ur=!1;function Cm(e,t=!1,n=!1){t&&Qa(t);const{props:o,children:i}=e.vnode,r=Rf(e);rm(e,o,r,t),sm(e,i,n||t);const a=r?km(e,t):void 0;return t&&Qa(!1),a}function km(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,jg);const{setup:o}=n;if(o){fn();const i=e.setupContext=o.length>1?xm(e):null,r=ti(e),a=ei(o,e,0,[e.props,i]),l=yc(a);if(pn(),r(),(l||e.sp)&&!bo(e)&&rf(e),l){if(a.then(ad,ad),t)return a.then(s=>{ld(e,s)}).catch(s=>{Zi(s,e,0)});e.asyncDep=a}else ld(e,a)}else Of(e)}function ld(e,t,n){he(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:_e(t)&&(e.setupState=Vc(t)),Of(e)}function Of(e,t,n){const o=e.type;e.render||(e.render=o.render||Xt);{const i=ti(e);fn();try{Ng(e)}finally{pn(),i()}}}const Sm={get(e,t){return Je(e,"get",""),e[t]}};function xm(e){const t=n=>{e.exposed=n||{}};return{attrs:new Proxy(e.attrs,Sm),slots:e.slots,emit:e.emit,expose:t}}function ta(e){return e.exposed?e.exposeProxy||(e.exposeProxy=new Proxy(Vc(fg(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in Zo)return Zo[n](e)},has(t,n){return n in t||n in Zo}})):e.proxy}function $m(e,t=!0){return he(e)?e.displayName||e.name:e.name||t&&e.__name}function Pm(e){return he(e)&&"__vccOpts"in e}const Ct=(e,t)=>bg(e,t,ur);function ys(e,t,n){try{Bi(-1);const o=arguments.length;return o===2?_e(t)&&!de(t)?sr(t)?D(e,null,[t]):D(e,t):D(e,null,t):(o>3?n=Array.prototype.slice.call(arguments,2):o===3&&sr(n)&&(n=[n]),D(e,t,n))}finally{Bi(1)}}const Im="3.5.25";/** -* @vue/runtime-dom v3.5.25 -* (c) 2018-present Yuxi (Evan) You and Vue contributors -* @license MIT -**/let Za;const sd=typeof window<"u"&&window.trustedTypes;if(sd)try{Za=sd.createPolicy("vue",{createHTML:e=>e})}catch{}const Ef=Za?e=>Za.createHTML(e):e=>e,Tm="http://www.w3.org/2000/svg",Rm="http://www.w3.org/1998/Math/MathML",an=typeof document<"u"?document:null,dd=an&&an.createElement("template"),Om={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,o)=>{const i=t==="svg"?an.createElementNS(Tm,e):t==="mathml"?an.createElementNS(Rm,e):n?an.createElement(e,{is:n}):an.createElement(e);return e==="select"&&o&&o.multiple!=null&&i.setAttribute("multiple",o.multiple),i},createText:e=>an.createTextNode(e),createComment:e=>an.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>an.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,o,i,r){const a=n?n.previousSibling:t.lastChild;if(i&&(i===r||i.nextSibling))for(;t.insertBefore(i.cloneNode(!0),n),!(i===r||!(i=i.nextSibling)););else{dd.innerHTML=Ef(o==="svg"?`${e}`:o==="mathml"?`${e}`:e);const l=dd.content;if(o==="svg"||o==="mathml"){const s=l.firstChild;for(;s.firstChild;)l.appendChild(s.firstChild);l.removeChild(s)}t.insertBefore(l,n)}return[a?a.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},yn="transition",_o="animation",cr=Symbol("_vtc"),Af={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},Em=qe({},Xc,Af),Am=e=>(e.displayName="Transition",e.props=Em,e),Io=Am((e,{slots:t})=>ys(Ig,Lm(e),t)),Dn=(e,t=[])=>{de(e)?e.forEach(n=>n(...t)):e&&e(...t)},ud=e=>e?de(e)?e.some(t=>t.length>1):e.length>1:!1;function Lm(e){const t={};for(const j in e)j in Af||(t[j]=e[j]);if(e.css===!1)return t;const{name:n="v",type:o,duration:i,enterFromClass:r=`${n}-enter-from`,enterActiveClass:a=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:s=r,appearActiveClass:d=a,appearToClass:u=l,leaveFromClass:c=`${n}-leave-from`,leaveActiveClass:f=`${n}-leave-active`,leaveToClass:p=`${n}-leave-to`}=e,v=_m(i),C=v&&v[0],S=v&&v[1],{onBeforeEnter:x,onEnter:P,onEnterCancelled:L,onLeave:k,onLeaveCancelled:F,onBeforeAppear:K=x,onAppear:z=P,onAppearCancelled:q=L}=t,H=(j,le,pe,ue)=>{j._enterCancelled=ue,Bn(j,le?u:l),Bn(j,le?d:a),pe&&pe()},ee=(j,le)=>{j._isLeaving=!1,Bn(j,c),Bn(j,p),Bn(j,f),le&&le()},X=j=>(le,pe)=>{const ue=j?z:P,se=()=>H(le,j,pe);Dn(ue,[le,se]),cd(()=>{Bn(le,j?s:r),nn(le,j?u:l),ud(ue)||fd(le,o,C,se)})};return qe(t,{onBeforeEnter(j){Dn(x,[j]),nn(j,r),nn(j,a)},onBeforeAppear(j){Dn(K,[j]),nn(j,s),nn(j,d)},onEnter:X(!1),onAppear:X(!0),onLeave(j,le){j._isLeaving=!0;const pe=()=>ee(j,le);nn(j,c),j._enterCancelled?(nn(j,f),gd(j)):(gd(j),nn(j,f)),cd(()=>{j._isLeaving&&(Bn(j,c),nn(j,p),ud(k)||fd(j,o,S,pe))}),Dn(k,[j,pe])},onEnterCancelled(j){H(j,!1,void 0,!0),Dn(L,[j])},onAppearCancelled(j){H(j,!0,void 0,!0),Dn(q,[j])},onLeaveCancelled(j){ee(j),Dn(F,[j])}})}function _m(e){if(e==null)return null;if(_e(e))return[Sa(e.enter),Sa(e.leave)];{const t=Sa(e);return[t,t]}}function Sa(e){return Fh(e)}function nn(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e[cr]||(e[cr]=new Set)).add(t)}function Bn(e,t){t.split(/\s+/).forEach(o=>o&&e.classList.remove(o));const n=e[cr];n&&(n.delete(t),n.size||(e[cr]=void 0))}function cd(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let Dm=0;function fd(e,t,n,o){const i=e._endId=++Dm,r=()=>{i===e._endId&&o()};if(n!=null)return setTimeout(r,n);const{type:a,timeout:l,propCount:s}=Bm(e,t);if(!a)return o();const d=a+"end";let u=0;const c=()=>{e.removeEventListener(d,f),r()},f=p=>{p.target===e&&++u>=s&&c()};setTimeout(()=>{u(n[v]||"").split(", "),i=o(`${yn}Delay`),r=o(`${yn}Duration`),a=pd(i,r),l=o(`${_o}Delay`),s=o(`${_o}Duration`),d=pd(l,s);let u=null,c=0,f=0;t===yn?a>0&&(u=yn,c=a,f=r.length):t===_o?d>0&&(u=_o,c=d,f=s.length):(c=Math.max(a,d),u=c>0?a>d?yn:_o:null,f=u?u===yn?r.length:s.length:0);const p=u===yn&&/\b(?:transform|all)(?:,|$)/.test(o(`${yn}Property`).toString());return{type:u,timeout:c,propCount:f,hasTransform:p}}function pd(e,t){for(;e.lengthhd(n)+hd(e[o])))}function hd(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function gd(e){return(e?e.ownerDocument:document).body.offsetHeight}function Mm(e,t,n){const o=e[cr];o&&(t=(t?[t,...o]:[...o]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const md=Symbol("_vod"),zm=Symbol("_vsh"),Fm=Symbol(""),jm=/(?:^|;)\s*display\s*:/;function Nm(e,t,n){const o=e.style,i=ze(n);let r=!1;if(n&&!i){if(t)if(ze(t))for(const a of t.split(";")){const l=a.slice(0,a.indexOf(":")).trim();n[l]==null&&Pi(o,l,"")}else for(const a in t)n[a]==null&&Pi(o,a,"");for(const a in n)a==="display"&&(r=!0),Pi(o,a,n[a])}else if(i){if(t!==n){const a=o[Fm];a&&(n+=";"+a),o.cssText=n,r=jm.test(n)}}else t&&e.removeAttribute("style");md in e&&(e[md]=r?o.display:"",e[zm]&&(o.display="none"))}const bd=/\s*!important$/;function Pi(e,t,n){if(de(n))n.forEach(o=>Pi(e,t,o));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const o=Vm(e,t);bd.test(n)?e.setProperty(En(o),n.replace(bd,""),"important"):e[o]=n}}const yd=["Webkit","Moz","ms"],xa={};function Vm(e,t){const n=xa[t];if(n)return n;let o=Rt(t);if(o!=="filter"&&o in e)return xa[t]=o;o=Ki(o);for(let i=0;i$a||(Wm.then(()=>$a=0),$a=Date.now());function Qm(e,t){const n=o=>{if(!o._vts)o._vts=Date.now();else if(o._vts<=n.attached)return;Bt(Zm(o,n.value),t,5,[o])};return n.value=e,n.attached=qm(),n}function Zm(e,t){if(de(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(o=>i=>!i._stopped&&o&&o(i))}else return t}const xd=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,Ym=(e,t,n,o,i,r)=>{const a=i==="svg";t==="class"?Mm(e,o,a):t==="style"?Nm(e,n,o):Ui(t)?Jl(t)||Gm(e,t,n,o,r):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):Xm(e,t,o,a))?(Cd(e,t,o),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&wd(e,t,o,a,r,t!=="value")):e._isVueCE&&(/[A-Z]/.test(t)||!ze(o))?Cd(e,Rt(t),o,r,t):(t==="true-value"?e._trueValue=o:t==="false-value"&&(e._falseValue=o),wd(e,t,o,a))};function Xm(e,t,n,o){if(o)return!!(t==="innerHTML"||t==="textContent"||t in e&&xd(t)&&he(n));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="autocorrect"||t==="sandbox"&&e.tagName==="IFRAME"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const i=e.tagName;if(i==="IMG"||i==="VIDEO"||i==="CANVAS"||i==="SOURCE")return!1}return xd(t)&&ze(n)?!1:t in e}const Jm=["ctrl","shift","alt","meta"],eb={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>Jm.some(n=>e[`${n}Key`]&&!t.includes(n))},To=(e,t)=>{const n=e._withMods||(e._withMods={}),o=t.join(".");return n[o]||(n[o]=(i,...r)=>{for(let a=0;a{const n=e._withKeys||(e._withKeys={}),o=t.join(".");return n[o]||(n[o]=i=>{if(!("key"in i))return;const r=En(i.key);if(t.some(a=>a===r||tb[a]===r))return e(i)})},nb=qe({patchProp:Ym},Om);let $d;function ob(){return $d||($d=um(nb))}const rb=(...e)=>{const t=ob().createApp(...e),{mount:n}=t;return t.mount=o=>{const i=ab(o);if(!i)return;const r=t._component;!he(r)&&!r.render&&!r.template&&(r.template=i.innerHTML),i.nodeType===1&&(i.textContent="");const a=n(i,!1,ib(i));return i instanceof Element&&(i.removeAttribute("v-cloak"),i.setAttribute("data-v-app","")),a},t};function ib(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function ab(e){return ze(e)?document.querySelector(e):e}function lb(){return Lf().__VUE_DEVTOOLS_GLOBAL_HOOK__}function Lf(){return typeof navigator<"u"&&typeof window<"u"?window:typeof globalThis<"u"?globalThis:{}}const sb=typeof Proxy=="function",db="devtools-plugin:setup",ub="plugin:settings:set";let ro,Ya;function cb(){var e;return ro!==void 0||(typeof window<"u"&&window.performance?(ro=!0,Ya=window.performance):typeof globalThis<"u"&&(!((e=globalThis.perf_hooks)===null||e===void 0)&&e.performance)?(ro=!0,Ya=globalThis.perf_hooks.performance):ro=!1),ro}function fb(){return cb()?Ya.now():Date.now()}class pb{constructor(t,n){this.target=null,this.targetQueue=[],this.onQueue=[],this.plugin=t,this.hook=n;const o={};if(t.settings)for(const a in t.settings){const l=t.settings[a];o[a]=l.defaultValue}const i=`__vue-devtools-plugin-settings__${t.id}`;let r=Object.assign({},o);try{const a=localStorage.getItem(i),l=JSON.parse(a);Object.assign(r,l)}catch{}this.fallbacks={getSettings(){return r},setSettings(a){try{localStorage.setItem(i,JSON.stringify(a))}catch{}r=a},now(){return fb()}},n&&n.on(ub,(a,l)=>{a===this.plugin.id&&this.fallbacks.setSettings(l)}),this.proxiedOn=new Proxy({},{get:(a,l)=>this.target?this.target.on[l]:(...s)=>{this.onQueue.push({method:l,args:s})}}),this.proxiedTarget=new Proxy({},{get:(a,l)=>this.target?this.target[l]:l==="on"?this.proxiedOn:Object.keys(this.fallbacks).includes(l)?(...s)=>(this.targetQueue.push({method:l,args:s,resolve:()=>{}}),this.fallbacks[l](...s)):(...s)=>new Promise(d=>{this.targetQueue.push({method:l,args:s,resolve:d})})})}async setRealTarget(t){this.target=t;for(const n of this.onQueue)this.target.on[n.method](...n.args);for(const n of this.targetQueue)n.resolve(await this.target[n.method](...n.args))}}function hb(e,t){const n=e,o=Lf(),i=lb(),r=sb&&n.enableEarlyProxy;if(i&&(o.__VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__||!r))i.emit(db,e,t);else{const a=r?new pb(n,i):null;(o.__VUE_DEVTOOLS_PLUGINS__=o.__VUE_DEVTOOLS_PLUGINS__||[]).push({pluginDescriptor:n,setupFn:t,proxy:a}),a&&t(a.proxiedTarget)}}/*! - * vuex v4.1.0 - * (c) 2022 Evan You - * @license MIT - */var gb="store";function Ro(e,t){Object.keys(e).forEach(function(n){return t(e[n],n)})}function _f(e){return e!==null&&typeof e=="object"}function mb(e){return e&&typeof e.then=="function"}function bb(e,t){return function(){return e(t)}}function Df(e,t,n){return t.indexOf(e)<0&&(n&&n.prepend?t.unshift(e):t.push(e)),function(){var o=t.indexOf(e);o>-1&&t.splice(o,1)}}function Bf(e,t){e._actions=Object.create(null),e._mutations=Object.create(null),e._wrappedGetters=Object.create(null),e._modulesNamespaceMap=Object.create(null);var n=e.state;na(e,n,[],e._modules.root,!0),vs(e,n,t)}function vs(e,t,n){var o=e._state,i=e._scope;e.getters={},e._makeLocalGettersCache=Object.create(null);var r=e._wrappedGetters,a={},l={},s=Kh(!0);s.run(function(){Ro(r,function(d,u){a[u]=bb(d,e),l[u]=Ct(function(){return a[u]()}),Object.defineProperty(e.getters,u,{get:function(){return l[u].value},enumerable:!0})})}),e._state=Po({data:t}),e._scope=s,e.strict&&kb(e),o&&n&&e._withCommit(function(){o.data=null}),i&&i.stop()}function na(e,t,n,o,i){var r=!n.length,a=e._modules.getNamespace(n);if(o.namespaced&&(e._modulesNamespaceMap[a],e._modulesNamespaceMap[a]=o),!r&&!i){var l=ws(t,n.slice(0,-1)),s=n[n.length-1];e._withCommit(function(){l[s]=o.state})}var d=o.context=yb(e,a,n);o.forEachMutation(function(u,c){var f=a+c;vb(e,f,u,d)}),o.forEachAction(function(u,c){var f=u.root?c:a+c,p=u.handler||u;wb(e,f,p,d)}),o.forEachGetter(function(u,c){var f=a+c;Cb(e,f,u,d)}),o.forEachChild(function(u,c){na(e,t,n.concat(c),u,i)})}function yb(e,t,n){var o=t==="",i={dispatch:o?e.dispatch:function(r,a,l){var s=zi(r,a,l),d=s.payload,u=s.options,c=s.type;return(!u||!u.root)&&(c=t+c),e.dispatch(c,d)},commit:o?e.commit:function(r,a,l){var s=zi(r,a,l),d=s.payload,u=s.options,c=s.type;(!u||!u.root)&&(c=t+c),e.commit(c,d,u)}};return Object.defineProperties(i,{getters:{get:o?function(){return e.getters}:function(){return Mf(e,t)}},state:{get:function(){return ws(e.state,n)}}}),i}function Mf(e,t){if(!e._makeLocalGettersCache[t]){var n={},o=t.length;Object.keys(e.getters).forEach(function(i){if(i.slice(0,o)===t){var r=i.slice(o);Object.defineProperty(n,r,{get:function(){return e.getters[i]},enumerable:!0})}}),e._makeLocalGettersCache[t]=n}return e._makeLocalGettersCache[t]}function vb(e,t,n,o){var i=e._mutations[t]||(e._mutations[t]=[]);i.push(function(a){n.call(e,o.state,a)})}function wb(e,t,n,o){var i=e._actions[t]||(e._actions[t]=[]);i.push(function(a){var l=n.call(e,{dispatch:o.dispatch,commit:o.commit,getters:o.getters,state:o.state,rootGetters:e.getters,rootState:e.state},a);return mb(l)||(l=Promise.resolve(l)),e._devtoolHook?l.catch(function(s){throw e._devtoolHook.emit("vuex:error",s),s}):l})}function Cb(e,t,n,o){e._wrappedGetters[t]||(e._wrappedGetters[t]=function(r){return n(o.state,o.getters,r.state,r.getters)})}function kb(e){Lt(function(){return e._state.data},function(){},{deep:!0,flush:"sync"})}function ws(e,t){return t.reduce(function(n,o){return n[o]},e)}function zi(e,t,n){return _f(e)&&e.type&&(n=t,t=e,e=e.type),{type:e,payload:t,options:n}}var Sb="vuex bindings",Pd="vuex:mutations",Pa="vuex:actions",io="vuex",xb=0;function $b(e,t){hb({id:"org.vuejs.vuex",app:e,label:"Vuex",homepage:"https://next.vuex.vuejs.org/",logo:"https://vuejs.org/images/icons/favicon-96x96.png",packageName:"vuex",componentStateTypes:[Sb]},function(n){n.addTimelineLayer({id:Pd,label:"Vuex Mutations",color:Id}),n.addTimelineLayer({id:Pa,label:"Vuex Actions",color:Id}),n.addInspector({id:io,label:"Vuex",icon:"storage",treeFilterPlaceholder:"Filter stores..."}),n.on.getInspectorTree(function(o){if(o.app===e&&o.inspectorId===io)if(o.filter){var i=[];Nf(i,t._modules.root,o.filter,""),o.rootNodes=i}else o.rootNodes=[jf(t._modules.root,"")]}),n.on.getInspectorState(function(o){if(o.app===e&&o.inspectorId===io){var i=o.nodeId;Mf(t,i),o.state=Tb(Ob(t._modules,i),i==="root"?t.getters:t._makeLocalGettersCache,i)}}),n.on.editInspectorState(function(o){if(o.app===e&&o.inspectorId===io){var i=o.nodeId,r=o.path;i!=="root"&&(r=i.split("/").filter(Boolean).concat(r)),t._withCommit(function(){o.set(t._state.data,r,o.state.value)})}}),t.subscribe(function(o,i){var r={};o.payload&&(r.payload=o.payload),r.state=i,n.notifyComponentUpdate(),n.sendInspectorTree(io),n.sendInspectorState(io),n.addTimelineEvent({layerId:Pd,event:{time:Date.now(),title:o.type,data:r}})}),t.subscribeAction({before:function(o,i){var r={};o.payload&&(r.payload=o.payload),o._id=xb++,o._time=Date.now(),r.state=i,n.addTimelineEvent({layerId:Pa,event:{time:o._time,title:o.type,groupId:o._id,subtitle:"start",data:r}})},after:function(o,i){var r={},a=Date.now()-o._time;r.duration={_custom:{type:"duration",display:a+"ms",tooltip:"Action duration",value:a}},o.payload&&(r.payload=o.payload),r.state=i,n.addTimelineEvent({layerId:Pa,event:{time:Date.now(),title:o.type,groupId:o._id,subtitle:"end",data:r}})}})})}var Id=8702998,Pb=6710886,Ib=16777215,zf={label:"namespaced",textColor:Ib,backgroundColor:Pb};function Ff(e){return e&&e!=="root"?e.split("/").slice(-2,-1)[0]:"Root"}function jf(e,t){return{id:t||"root",label:Ff(t),tags:e.namespaced?[zf]:[],children:Object.keys(e._children).map(function(n){return jf(e._children[n],t+n+"/")})}}function Nf(e,t,n,o){o.includes(n)&&e.push({id:o||"root",label:o.endsWith("/")?o.slice(0,o.length-1):o||"Root",tags:t.namespaced?[zf]:[]}),Object.keys(t._children).forEach(function(i){Nf(e,t._children[i],n,o+i+"/")})}function Tb(e,t,n){t=n==="root"?t:t[n];var o=Object.keys(t),i={state:Object.keys(e.state).map(function(a){return{key:a,editable:!0,value:e.state[a]}})};if(o.length){var r=Rb(t);i.getters=Object.keys(r).map(function(a){return{key:a.endsWith("/")?Ff(a):a,editable:!1,value:Xa(function(){return r[a]})}})}return i}function Rb(e){var t={};return Object.keys(e).forEach(function(n){var o=n.split("/");if(o.length>1){var i=t,r=o.pop();o.forEach(function(a){i[a]||(i[a]={_custom:{value:{},display:a,tooltip:"Module",abstract:!0}}),i=i[a]._custom.value}),i[r]=Xa(function(){return e[n]})}else t[n]=Xa(function(){return e[n]})}),t}function Ob(e,t){var n=t.split("/").filter(function(o){return o});return n.reduce(function(o,i,r){var a=o[i];if(!a)throw new Error('Missing module "'+i+'" for path "'+t+'".');return r===n.length-1?a:a._children},t==="root"?e:e.root._children)}function Xa(e){try{return e()}catch(t){return t}}var jt=function(t,n){this.runtime=n,this._children=Object.create(null),this._rawModule=t;var o=t.state;this.state=(typeof o=="function"?o():o)||{}},Vf={namespaced:{configurable:!0}};Vf.namespaced.get=function(){return!!this._rawModule.namespaced};jt.prototype.addChild=function(t,n){this._children[t]=n};jt.prototype.removeChild=function(t){delete this._children[t]};jt.prototype.getChild=function(t){return this._children[t]};jt.prototype.hasChild=function(t){return t in this._children};jt.prototype.update=function(t){this._rawModule.namespaced=t.namespaced,t.actions&&(this._rawModule.actions=t.actions),t.mutations&&(this._rawModule.mutations=t.mutations),t.getters&&(this._rawModule.getters=t.getters)};jt.prototype.forEachChild=function(t){Ro(this._children,t)};jt.prototype.forEachGetter=function(t){this._rawModule.getters&&Ro(this._rawModule.getters,t)};jt.prototype.forEachAction=function(t){this._rawModule.actions&&Ro(this._rawModule.actions,t)};jt.prototype.forEachMutation=function(t){this._rawModule.mutations&&Ro(this._rawModule.mutations,t)};Object.defineProperties(jt.prototype,Vf);var Zn=function(t){this.register([],t,!1)};Zn.prototype.get=function(t){return t.reduce(function(n,o){return n.getChild(o)},this.root)};Zn.prototype.getNamespace=function(t){var n=this.root;return t.reduce(function(o,i){return n=n.getChild(i),o+(n.namespaced?i+"/":"")},"")};Zn.prototype.update=function(t){Uf([],this.root,t)};Zn.prototype.register=function(t,n,o){var i=this;o===void 0&&(o=!0);var r=new jt(n,o);if(t.length===0)this.root=r;else{var a=this.get(t.slice(0,-1));a.addChild(t[t.length-1],r)}n.modules&&Ro(n.modules,function(l,s){i.register(t.concat(s),l,o)})};Zn.prototype.unregister=function(t){var n=this.get(t.slice(0,-1)),o=t[t.length-1],i=n.getChild(o);i&&i.runtime&&n.removeChild(o)};Zn.prototype.isRegistered=function(t){var n=this.get(t.slice(0,-1)),o=t[t.length-1];return n?n.hasChild(o):!1};function Uf(e,t,n){if(t.update(n),n.modules)for(var o in n.modules){if(!t.getChild(o))return;Uf(e.concat(o),t.getChild(o),n.modules[o])}}function Eb(e){return new mt(e)}var mt=function(t){var n=this;t===void 0&&(t={});var o=t.plugins;o===void 0&&(o=[]);var i=t.strict;i===void 0&&(i=!1);var r=t.devtools;this._committing=!1,this._actions=Object.create(null),this._actionSubscribers=[],this._mutations=Object.create(null),this._wrappedGetters=Object.create(null),this._modules=new Zn(t),this._modulesNamespaceMap=Object.create(null),this._subscribers=[],this._makeLocalGettersCache=Object.create(null),this._scope=null,this._devtools=r;var a=this,l=this,s=l.dispatch,d=l.commit;this.dispatch=function(f,p){return s.call(a,f,p)},this.commit=function(f,p,v){return d.call(a,f,p,v)},this.strict=i;var u=this._modules.root.state;na(this,u,[],this._modules.root),vs(this,u),o.forEach(function(c){return c(n)})},Cs={state:{configurable:!0}};mt.prototype.install=function(t,n){t.provide(n||gb,this),t.config.globalProperties.$store=this;var o=this._devtools!==void 0?this._devtools:!1;o&&$b(t,this)};Cs.state.get=function(){return this._state.data};Cs.state.set=function(e){};mt.prototype.commit=function(t,n,o){var i=this,r=zi(t,n,o),a=r.type,l=r.payload,s={type:a,payload:l},d=this._mutations[a];d&&(this._withCommit(function(){d.forEach(function(c){c(l)})}),this._subscribers.slice().forEach(function(u){return u(s,i.state)}))};mt.prototype.dispatch=function(t,n){var o=this,i=zi(t,n),r=i.type,a=i.payload,l={type:r,payload:a},s=this._actions[r];if(s){try{this._actionSubscribers.slice().filter(function(u){return u.before}).forEach(function(u){return u.before(l,o.state)})}catch{}var d=s.length>1?Promise.all(s.map(function(u){return u(a)})):s[0](a);return new Promise(function(u,c){d.then(function(f){try{o._actionSubscribers.filter(function(p){return p.after}).forEach(function(p){return p.after(l,o.state)})}catch{}u(f)},function(f){try{o._actionSubscribers.filter(function(p){return p.error}).forEach(function(p){return p.error(l,o.state,f)})}catch{}c(f)})})}};mt.prototype.subscribe=function(t,n){return Df(t,this._subscribers,n)};mt.prototype.subscribeAction=function(t,n){var o=typeof t=="function"?{before:t}:t;return Df(o,this._actionSubscribers,n)};mt.prototype.watch=function(t,n,o){var i=this;return Lt(function(){return t(i.state,i.getters)},n,Object.assign({},o))};mt.prototype.replaceState=function(t){var n=this;this._withCommit(function(){n._state.data=t})};mt.prototype.registerModule=function(t,n,o){o===void 0&&(o={}),typeof t=="string"&&(t=[t]),this._modules.register(t,n),na(this,this.state,t,this._modules.get(t),o.preserveState),vs(this,this.state)};mt.prototype.unregisterModule=function(t){var n=this;typeof t=="string"&&(t=[t]),this._modules.unregister(t),this._withCommit(function(){var o=ws(n.state,t.slice(0,-1));delete o[t[t.length-1]]}),Bf(this)};mt.prototype.hasModule=function(t){return typeof t=="string"&&(t=[t]),this._modules.isRegistered(t)};mt.prototype.hotUpdate=function(t){this._modules.update(t),Bf(this,!0)};mt.prototype._withCommit=function(t){var n=this._committing;this._committing=!0,t(),this._committing=n};Object.defineProperties(mt.prototype,Cs);var Ze=Gf(function(e,t){var n={};return Hf(t).forEach(function(o){var i=o.key,r=o.val;n[i]=function(){var l=this.$store.state,s=this.$store.getters;if(e){var d=Kf(this.$store,"mapState",e);if(!d)return;l=d.context.state,s=d.context.getters}return typeof r=="function"?r.call(this,l,s):l[r]},n[i].vuex=!0}),n}),oa=Gf(function(e,t){var n={};return Hf(t).forEach(function(o){var i=o.key,r=o.val;n[i]=function(){for(var l=[],s=arguments.length;s--;)l[s]=arguments[s];var d=this.$store.dispatch;if(e){var u=Kf(this.$store,"mapActions",e);if(!u)return;d=u.context.dispatch}return typeof r=="function"?r.apply(this,[d].concat(l)):d.apply(this.$store,[r].concat(l))}}),n});function Hf(e){return Ab(e)?Array.isArray(e)?e.map(function(t){return{key:t,val:t}}):Object.keys(e).map(function(t){return{key:t,val:e[t]}}):[]}function Ab(e){return Array.isArray(e)||_f(e)}function Gf(e){return function(t,n){return typeof t!="string"?(n=t,t=""):t.charAt(t.length-1)!=="/"&&(t+="/"),e(t,n)}}function Kf(e,t,n){var o=e._modulesNamespaceMap[n];return o}const dt=(e,t)=>{const n=e.__vccOpts||e;for(const[o,i]of t)n[o]=i;return n},Lb={name:"Sidebar",computed:{...Ze("auth",["isLoggedIn"])}},_b={class:"sidebar"},Db={class:"sidebar-menu"},Bb={key:0},Mb={key:1},zb={key:2},Fb={key:3},jb={key:4},Nb={key:5},Vb={key:6};function Ub(e,t,n,o,i,r){const a=R("router-link");return g(),b("div",_b,[h("ul",Db,[e.isLoggedIn?(g(),b("li",Bb,[D(a,{to:"/console",class:J(["menu-item",{active:e.$route.name==="Console"}])},{default:V(()=>[...t[0]||(t[0]=[h("span",{class:"menu-icon"},"■",-1),h("span",{class:"menu-text"},"控制台",-1)])]),_:1},8,["class"])])):I("",!0),e.isLoggedIn?(g(),b("li",Mb,[D(a,{to:"/log",class:J(["menu-item",{active:e.$route.name==="Log"}])},{default:V(()=>[...t[1]||(t[1]=[h("span",{class:"menu-icon"},"▤",-1),h("span",{class:"menu-text"},"运行日志",-1)])]),_:1},8,["class"])])):I("",!0),e.isLoggedIn?(g(),b("li",zb,[D(a,{to:"/delivery",class:J(["menu-item",{active:e.$route.name==="Delivery"}])},{default:V(()=>[...t[2]||(t[2]=[h("span",{class:"menu-icon"},"▦",-1),h("span",{class:"menu-text"},"投递管理",-1)])]),_:1},8,["class"])])):I("",!0),e.isLoggedIn?(g(),b("li",Fb,[D(a,{to:"/invite",class:J(["menu-item",{active:e.$route.name==="Invite"}])},{default:V(()=>[...t[3]||(t[3]=[h("span",{class:"menu-icon"},"◈",-1),h("span",{class:"menu-text"},"推广邀请",-1)])]),_:1},8,["class"])])):I("",!0),e.isLoggedIn?(g(),b("li",jb,[D(a,{to:"/feedback",class:J(["menu-item",{active:e.$route.name==="Feedback"}])},{default:V(()=>[...t[4]||(t[4]=[h("span",{class:"menu-icon"},"◉",-1),h("span",{class:"menu-text"},"意见反馈",-1)])]),_:1},8,["class"])])):I("",!0),e.isLoggedIn?(g(),b("li",Nb,[D(a,{to:"/purchase",class:J(["menu-item",{active:e.$route.name==="Purchase"}])},{default:V(()=>[...t[5]||(t[5]=[h("span",{class:"menu-icon"},"◑",-1),h("span",{class:"menu-text"},"如何购买",-1)])]),_:1},8,["class"])])):I("",!0),e.isLoggedIn?I("",!0):(g(),b("li",Vb,[D(a,{to:"/login",class:J(["menu-item",{active:e.$route.name==="Login"}])},{default:V(()=>[...t[6]||(t[6]=[h("span",{class:"menu-icon"},"►",-1),h("span",{class:"menu-text"},"用户登录",-1)])]),_:1},8,["class"])]))])])}const Hb=dt(Lb,[["render",Ub],["__scopeId","data-v-ccec6c25"]]);function Me(...e){if(e){let t=[];for(let n=0;nl?a:void 0);t=r.length?t.concat(r.filter(a=>!!a)):t}}return t.join(" ").trim()}}function Gb(e,t){return e?e.classList?e.classList.contains(t):new RegExp("(^| )"+t+"( |$)","gi").test(e.className):!1}function Pn(e,t){if(e&&t){let n=o=>{Gb(e,o)||(e.classList?e.classList.add(o):e.className+=" "+o)};[t].flat().filter(Boolean).forEach(o=>o.split(" ").forEach(n))}}function Kb(){return window.innerWidth-document.documentElement.offsetWidth}function Wb(e){typeof e=="string"?Pn(document.body,e||"p-overflow-hidden"):(e!=null&&e.variableName&&document.body.style.setProperty(e.variableName,Kb()+"px"),Pn(document.body,(e==null?void 0:e.className)||"p-overflow-hidden"))}function qb(e){if(e){let t=document.createElement("a");if(t.download!==void 0){let{name:n,src:o}=e;return t.setAttribute("href",o),t.setAttribute("download",n),t.style.display="none",document.body.appendChild(t),t.click(),document.body.removeChild(t),!0}}return!1}function Qb(e,t){let n=new Blob([e],{type:"application/csv;charset=utf-8;"});window.navigator.msSaveOrOpenBlob?navigator.msSaveOrOpenBlob(n,t+".csv"):qb({name:t+".csv",src:URL.createObjectURL(n)})||(e="data:text/csv;charset=utf-8,"+e,window.open(encodeURI(e)))}function Qt(e,t){if(e&&t){let n=o=>{e.classList?e.classList.remove(o):e.className=e.className.replace(new RegExp("(^|\\b)"+o.split(" ").join("|")+"(\\b|$)","gi")," ")};[t].flat().filter(Boolean).forEach(o=>o.split(" ").forEach(n))}}function Zb(e){typeof e=="string"?Qt(document.body,e||"p-overflow-hidden"):(e!=null&&e.variableName&&document.body.style.removeProperty(e.variableName),Qt(document.body,(e==null?void 0:e.className)||"p-overflow-hidden"))}function Ja(e){for(let t of document==null?void 0:document.styleSheets)try{for(let n of t==null?void 0:t.cssRules)for(let o of n==null?void 0:n.style)if(e.test(o))return{name:o,value:n.style.getPropertyValue(o).trim()}}catch{}return null}function Wf(e){let t={width:0,height:0};if(e){let[n,o]=[e.style.visibility,e.style.display],i=e.getBoundingClientRect();e.style.visibility="hidden",e.style.display="block",t.width=i.width||e.offsetWidth,t.height=i.height||e.offsetHeight,e.style.display=o,e.style.visibility=n}return t}function ks(){let e=window,t=document,n=t.documentElement,o=t.getElementsByTagName("body")[0],i=e.innerWidth||n.clientWidth||o.clientWidth,r=e.innerHeight||n.clientHeight||o.clientHeight;return{width:i,height:r}}function el(e){return e?Math.abs(e.scrollLeft):0}function Yb(){let e=document.documentElement;return(window.pageXOffset||el(e))-(e.clientLeft||0)}function Xb(){let e=document.documentElement;return(window.pageYOffset||e.scrollTop)-(e.clientTop||0)}function qf(e){return e?getComputedStyle(e).direction==="rtl":!1}function Ss(e,t,n=!0){var o,i,r,a;if(e){let l=e.offsetParent?{width:e.offsetWidth,height:e.offsetHeight}:Wf(e),s=l.height,d=l.width,u=t.offsetHeight,c=t.offsetWidth,f=t.getBoundingClientRect(),p=Xb(),v=Yb(),C=ks(),S,x,P="top";f.top+u+s>C.height?(S=f.top+p-s,P="bottom",S<0&&(S=p)):S=u+f.top+p,f.left+d>C.width?x=Math.max(0,f.left+v+c-d):x=f.left+v,qf(e)?e.style.insetInlineEnd=x+"px":e.style.insetInlineStart=x+"px",e.style.top=S+"px",e.style.transformOrigin=P,n&&(e.style.marginTop=P==="bottom"?`calc(${(i=(o=Ja(/-anchor-gutter$/))==null?void 0:o.value)!=null?i:"2px"} * -1)`:(a=(r=Ja(/-anchor-gutter$/))==null?void 0:r.value)!=null?a:"")}}function wo(e,t){e&&(typeof t=="string"?e.style.cssText=t:Object.entries(t||{}).forEach(([n,o])=>e.style[n]=o))}function nt(e,t){return e instanceof HTMLElement?e.offsetWidth:0}function Qf(e,t,n=!0,o=void 0){var i;if(e){let r=e.offsetParent?{width:e.offsetWidth,height:e.offsetHeight}:Wf(e),a=t.offsetHeight,l=t.getBoundingClientRect(),s=ks(),d,u,c=o??"top";if(!o&&l.top+a+r.height>s.height?(d=-1*r.height,c="bottom",l.top+d<0&&(d=-1*l.top)):d=a,r.width>s.width?u=l.left*-1:l.left+r.width>s.width?u=(l.left+r.width-s.width)*-1:u=0,e.style.top=d+"px",e.style.insetInlineStart=u+"px",e.style.transformOrigin=c,n){let f=(i=Ja(/-anchor-gutter$/))==null?void 0:i.value;e.style.marginTop=c==="bottom"?`calc(${f??"2px"} * -1)`:f??""}}}function xs(e){if(e){let t=e.parentNode;return t&&t instanceof ShadowRoot&&t.host&&(t=t.host),t}return null}function Jb(e){return!!(e!==null&&typeof e<"u"&&e.nodeName&&xs(e))}function Yn(e){return typeof Element<"u"?e instanceof Element:e!==null&&typeof e=="object"&&e.nodeType===1&&typeof e.nodeName=="string"}function Ii(){if(window.getSelection){let e=window.getSelection()||{};e.empty?e.empty():e.removeAllRanges&&e.rangeCount>0&&e.getRangeAt(0).getClientRects().length>0&&e.removeAllRanges()}}function Fi(e,t={}){if(Yn(e)){let n=(o,i)=>{var r,a;let l=(r=e==null?void 0:e.$attrs)!=null&&r[o]?[(a=e==null?void 0:e.$attrs)==null?void 0:a[o]]:[];return[i].flat().reduce((s,d)=>{if(d!=null){let u=typeof d;if(u==="string"||u==="number")s.push(d);else if(u==="object"){let c=Array.isArray(d)?n(o,d):Object.entries(d).map(([f,p])=>o==="style"&&(p||p===0)?`${f.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}:${p}`:p?f:void 0);s=c.length?s.concat(c.filter(f=>!!f)):s}}return s},l)};Object.entries(t).forEach(([o,i])=>{if(i!=null){let r=o.match(/^on(.+)/);r?e.addEventListener(r[1].toLowerCase(),i):o==="p-bind"||o==="pBind"?Fi(e,i):(i=o==="class"?[...new Set(n("class",i))].join(" ").trim():o==="style"?n("style",i).join(";").trim():i,(e.$attrs=e.$attrs||{})&&(e.$attrs[o]=i),e.setAttribute(o,i))}})}}function Zf(e,t={},...n){{let o=document.createElement(e);return Fi(o,t),o.append(...n),o}}function lo(e,t){return Yn(e)?Array.from(e.querySelectorAll(t)):[]}function In(e,t){return Yn(e)?e.matches(t)?e:e.querySelector(t):null}function Xe(e,t){e&&document.activeElement!==e&&e.focus(t)}function Ke(e,t){if(Yn(e)){let n=e.getAttribute(t);return isNaN(n)?n==="true"||n==="false"?n==="true":n:+n}}function $s(e,t=""){let n=lo(e,`button:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${t}, - [href]:not([tabindex = "-1"]):not([style*="display:none"]):not([hidden])${t}, - input:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${t}, - select:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${t}, - textarea:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${t}, - [tabIndex]:not([tabIndex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${t}, - [contenteditable]:not([tabIndex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${t}`),o=[];for(let i of n)getComputedStyle(i).display!="none"&&getComputedStyle(i).visibility!="hidden"&&o.push(i);return o}function Nn(e,t){let n=$s(e,t);return n.length>0?n[0]:null}function Vn(e){if(e){let t=e.offsetHeight,n=getComputedStyle(e);return t-=parseFloat(n.paddingTop)+parseFloat(n.paddingBottom)+parseFloat(n.borderTopWidth)+parseFloat(n.borderBottomWidth),t}return 0}function e0(e){if(e){let[t,n]=[e.style.visibility,e.style.display];e.style.visibility="hidden",e.style.display="block";let o=e.offsetHeight;return e.style.display=n,e.style.visibility=t,o}return 0}function t0(e){if(e){let[t,n]=[e.style.visibility,e.style.display];e.style.visibility="hidden",e.style.display="block";let o=e.offsetWidth;return e.style.display=n,e.style.visibility=t,o}return 0}function Ti(e){var t;if(e){let n=(t=xs(e))==null?void 0:t.childNodes,o=0;if(n)for(let i=0;i0?n[n.length-1]:null}function ra(e,t){let n=e.nextElementSibling;for(;n;){if(n.matches(t))return n;n=n.nextElementSibling}return null}function so(e){if(e){let t=e.getBoundingClientRect();return{top:t.top+(window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0),left:t.left+(window.pageXOffset||el(document.documentElement)||el(document.body)||0)}}return{top:"auto",left:"auto"}}function fr(e,t){return e?e.offsetHeight:0}function Xf(e,t=[]){let n=xs(e);return n===null?t:Xf(n,t.concat([n]))}function ia(e,t){let n=e.previousElementSibling;for(;n;){if(n.matches(t))return n;n=n.previousElementSibling}return null}function n0(e){let t=[];if(e){let n=Xf(e),o=/(auto|scroll)/,i=r=>{try{let a=window.getComputedStyle(r,null);return o.test(a.getPropertyValue("overflow"))||o.test(a.getPropertyValue("overflowX"))||o.test(a.getPropertyValue("overflowY"))}catch{return!1}};for(let r of n){let a=r.nodeType===1&&r.dataset.scrollselectors;if(a){let l=a.split(",");for(let s of l){let d=In(r,s);d&&i(d)&&t.push(d)}}r.nodeType!==9&&i(r)&&t.push(r)}}return t}function Td(){if(window.getSelection)return window.getSelection().toString();if(document.getSelection)return document.getSelection().toString()}function Un(e){if(e){let t=e.offsetWidth,n=getComputedStyle(e);return t-=parseFloat(n.paddingLeft)+parseFloat(n.paddingRight)+parseFloat(n.borderLeftWidth)+parseFloat(n.borderRightWidth),t}return 0}function Rd(e,t,n){let o=e[t];typeof o=="function"&&o.apply(e,[])}function o0(){return/(android)/i.test(navigator.userAgent)}function Ia(e){if(e){let t=e.nodeName,n=e.parentElement&&e.parentElement.nodeName;return t==="INPUT"||t==="TEXTAREA"||t==="BUTTON"||t==="A"||n==="INPUT"||n==="TEXTAREA"||n==="BUTTON"||n==="A"||!!e.closest(".p-button, .p-checkbox, .p-radiobutton")}return!1}function Jf(){return!!(typeof window<"u"&&window.document&&window.document.createElement)}function Od(e,t=""){return Yn(e)?e.matches(`button:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${t}, - [href][clientHeight][clientWidth]:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${t}, - input:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${t}, - select:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${t}, - textarea:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${t}, - [tabIndex]:not([tabIndex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${t}, - [contenteditable]:not([tabIndex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${t}`):!1}function ji(e){return!!(e&&e.offsetParent!=null)}function Ps(){return"ontouchstart"in window||navigator.maxTouchPoints>0||navigator.msMaxTouchPoints>0}function aa(e,t="",n){Yn(e)&&n!==null&&n!==void 0&&e.setAttribute(t,n)}function Is(){let e=new Map;return{on(t,n){let o=e.get(t);return o?o.push(n):o=[n],e.set(t,o),this},off(t,n){let o=e.get(t);return o&&o.splice(o.indexOf(n)>>>0,1),this},emit(t,n){let o=e.get(t);o&&o.forEach(i=>{i(n)})},clear(){e.clear()}}}var r0=Object.defineProperty,Ed=Object.getOwnPropertySymbols,i0=Object.prototype.hasOwnProperty,a0=Object.prototype.propertyIsEnumerable,Ad=(e,t,n)=>t in e?r0(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,l0=(e,t)=>{for(var n in t||(t={}))i0.call(t,n)&&Ad(e,n,t[n]);if(Ed)for(var n of Ed(t))a0.call(t,n)&&Ad(e,n,t[n]);return e};function gt(e){return e==null||e===""||Array.isArray(e)&&e.length===0||!(e instanceof Date)&&typeof e=="object"&&Object.keys(e).length===0}function s0(e,t,n,o=1){let i=-1,r=gt(e),a=gt(t);return r&&a?i=0:r?i=o:a?i=-o:typeof e=="string"&&typeof t=="string"?i=n(e,t):i=et?1:0,i}function tl(e,t,n=new WeakSet){if(e===t)return!0;if(!e||!t||typeof e!="object"||typeof t!="object"||n.has(e)||n.has(t))return!1;n.add(e).add(t);let o=Array.isArray(e),i=Array.isArray(t),r,a,l;if(o&&i){if(a=e.length,a!=t.length)return!1;for(r=a;r--!==0;)if(!tl(e[r],t[r],n))return!1;return!0}if(o!=i)return!1;let s=e instanceof Date,d=t instanceof Date;if(s!=d)return!1;if(s&&d)return e.getTime()==t.getTime();let u=e instanceof RegExp,c=t instanceof RegExp;if(u!=c)return!1;if(u&&c)return e.toString()==t.toString();let f=Object.keys(e);if(a=f.length,a!==Object.keys(t).length)return!1;for(r=a;r--!==0;)if(!Object.prototype.hasOwnProperty.call(t,f[r]))return!1;for(r=a;r--!==0;)if(l=f[r],!tl(e[l],t[l],n))return!1;return!0}function d0(e,t){return tl(e,t)}function la(e){return typeof e=="function"&&"call"in e&&"apply"in e}function me(e){return!gt(e)}function Ce(e,t){if(!e||!t)return null;try{let n=e[t];if(me(n))return n}catch{}if(Object.keys(e).length){if(la(t))return t(e);if(t.indexOf(".")===-1)return e[t];{let n=t.split("."),o=e;for(let i=0,r=n.length;i{let i=o;Jt(t[i])&&i in e&&Jt(e[i])?n[i]=ep(e[i],t[i]):n[i]=t[i]}),n}function c0(...e){return e.reduce((t,n,o)=>o===0?n:ep(t,n),{})}function Ta(e,t){let n=-1;if(t){for(let o=0;oZt(a)===i)||"";return Ts(St(e[r],n),o.join("."),n)}return}return St(e,n)}function tp(e,t=!0){return Array.isArray(e)&&(t||e.length!==0)}function f0(e){return me(e)&&!isNaN(e)}function p0(e=""){return me(e)&&e.length===1&&!!e.match(/\S| /)}function _d(){return new Intl.Collator(void 0,{numeric:!0}).compare}function qn(e,t){if(t){let n=t.test(e);return t.lastIndex=0,n}return!1}function h0(...e){return c0(...e)}function Jo(e){return e&&e.replace(/\/\*(?:(?!\*\/)[\s\S])*\*\/|[\r\n\t]+/g,"").replace(/ {2,}/g," ").replace(/ ([{:}]) /g,"$1").replace(/([;,]) /g,"$1").replace(/ !/g,"!").replace(/: /g,":").trim()}function Pt(e){if(e&&/[\xC0-\xFF\u0100-\u017E]/.test(e)){let t={A:/[\xC0-\xC5\u0100\u0102\u0104]/g,AE:/[\xC6]/g,C:/[\xC7\u0106\u0108\u010A\u010C]/g,D:/[\xD0\u010E\u0110]/g,E:/[\xC8-\xCB\u0112\u0114\u0116\u0118\u011A]/g,G:/[\u011C\u011E\u0120\u0122]/g,H:/[\u0124\u0126]/g,I:/[\xCC-\xCF\u0128\u012A\u012C\u012E\u0130]/g,IJ:/[\u0132]/g,J:/[\u0134]/g,K:/[\u0136]/g,L:/[\u0139\u013B\u013D\u013F\u0141]/g,N:/[\xD1\u0143\u0145\u0147\u014A]/g,O:/[\xD2-\xD6\xD8\u014C\u014E\u0150]/g,OE:/[\u0152]/g,R:/[\u0154\u0156\u0158]/g,S:/[\u015A\u015C\u015E\u0160]/g,T:/[\u0162\u0164\u0166]/g,U:/[\xD9-\xDC\u0168\u016A\u016C\u016E\u0170\u0172]/g,W:/[\u0174]/g,Y:/[\xDD\u0176\u0178]/g,Z:/[\u0179\u017B\u017D]/g,a:/[\xE0-\xE5\u0101\u0103\u0105]/g,ae:/[\xE6]/g,c:/[\xE7\u0107\u0109\u010B\u010D]/g,d:/[\u010F\u0111]/g,e:/[\xE8-\xEB\u0113\u0115\u0117\u0119\u011B]/g,g:/[\u011D\u011F\u0121\u0123]/g,i:/[\xEC-\xEF\u0129\u012B\u012D\u012F\u0131]/g,ij:/[\u0133]/g,j:/[\u0135]/g,k:/[\u0137,\u0138]/g,l:/[\u013A\u013C\u013E\u0140\u0142]/g,n:/[\xF1\u0144\u0146\u0148\u014B]/g,p:/[\xFE]/g,o:/[\xF2-\xF6\xF8\u014D\u014F\u0151]/g,oe:/[\u0153]/g,r:/[\u0155\u0157\u0159]/g,s:/[\u015B\u015D\u015F\u0161]/g,t:/[\u0163\u0165\u0167]/g,u:/[\xF9-\xFC\u0169\u016B\u016D\u016F\u0171\u0173]/g,w:/[\u0175]/g,y:/[\xFD\xFF\u0177]/g,z:/[\u017A\u017C\u017E]/g};for(let n in t)e=e.replace(t[n],n)}return e}function Dd(e,t,n){e&&t!==n&&(n>=e.length&&(n%=e.length,t%=e.length),e.splice(n,0,e.splice(t,1)[0]))}function Bd(e,t,n=1,o,i=1){let r=s0(e,t,o,n),a=n;return(gt(e)||gt(t))&&(a=i===1?n:i),a*r}function g0(e){return ht(e,!1)?e[0].toUpperCase()+e.slice(1):e}function np(e){return ht(e)?e.replace(/(_)/g,"-").replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase():e}var pi={};function m0(e="pui_id_"){return Object.hasOwn(pi,e)||(pi[e]=0),pi[e]++,`${e}${pi[e]}`}function b0(){let e=[],t=(a,l,s=999)=>{let d=i(a,l,s),u=d.value+(d.key===a?0:s)+1;return e.push({key:a,value:u}),u},n=a=>{e=e.filter(l=>l.value!==a)},o=(a,l)=>i(a).value,i=(a,l,s=0)=>[...e].reverse().find(d=>!0)||{key:a,value:s},r=a=>a&&parseInt(a.style.zIndex,10)||0;return{get:r,set:(a,l,s)=>{l&&(l.style.zIndex=String(t(a,!0,s)))},clear:a=>{a&&(n(r(a)),a.style.zIndex="")},getCurrent:a=>o(a)}}var Tt=b0(),y0=Object.defineProperty,v0=Object.defineProperties,w0=Object.getOwnPropertyDescriptors,Ni=Object.getOwnPropertySymbols,op=Object.prototype.hasOwnProperty,rp=Object.prototype.propertyIsEnumerable,Md=(e,t,n)=>t in e?y0(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,At=(e,t)=>{for(var n in t||(t={}))op.call(t,n)&&Md(e,n,t[n]);if(Ni)for(var n of Ni(t))rp.call(t,n)&&Md(e,n,t[n]);return e},Ra=(e,t)=>v0(e,w0(t)),on=(e,t)=>{var n={};for(var o in e)op.call(e,o)&&t.indexOf(o)<0&&(n[o]=e[o]);if(e!=null&&Ni)for(var o of Ni(e))t.indexOf(o)<0&&rp.call(e,o)&&(n[o]=e[o]);return n},C0=Is(),Qe=C0,pr=/{([^}]*)}/g,ip=/(\d+\s+[\+\-\*\/]\s+\d+)/g,ap=/var\([^)]+\)/g;function zd(e){return ht(e)?e.replace(/[A-Z]/g,(t,n)=>n===0?t:"."+t.toLowerCase()).toLowerCase():e}function k0(e){return Jt(e)&&e.hasOwnProperty("$value")&&e.hasOwnProperty("$type")?e.$value:e}function S0(e){return e.replaceAll(/ /g,"").replace(/[^\w]/g,"-")}function nl(e="",t=""){return S0(`${ht(e,!1)&&ht(t,!1)?`${e}-`:e}${t}`)}function lp(e="",t=""){return`--${nl(e,t)}`}function x0(e=""){let t=(e.match(/{/g)||[]).length,n=(e.match(/}/g)||[]).length;return(t+n)%2!==0}function sp(e,t="",n="",o=[],i){if(ht(e)){let r=e.trim();if(x0(r))return;if(qn(r,pr)){let a=r.replaceAll(pr,l=>{let s=l.replace(/{|}/g,"").split(".").filter(d=>!o.some(u=>qn(d,u)));return`var(${lp(n,np(s.join("-")))}${me(i)?`, ${i}`:""})`});return qn(a.replace(ap,"0"),ip)?`calc(${a})`:a}return r}else if(f0(e))return e}function $0(e,t,n){ht(t,!1)&&e.push(`${t}:${n};`)}function uo(e,t){return e?`${e}{${t}}`:""}function dp(e,t){if(e.indexOf("dt(")===-1)return e;function n(a,l){let s=[],d=0,u="",c=null,f=0;for(;d<=a.length;){let p=a[d];if((p==='"'||p==="'"||p==="`")&&a[d-1]!=="\\"&&(c=c===p?null:p),!c&&(p==="("&&f++,p===")"&&f--,(p===","||d===a.length)&&f===0)){let v=u.trim();v.startsWith("dt(")?s.push(dp(v,l)):s.push(o(v)),u="",d++;continue}p!==void 0&&(u+=p),d++}return s}function o(a){let l=a[0];if((l==='"'||l==="'"||l==="`")&&a[a.length-1]===l)return a.slice(1,-1);let s=Number(a);return isNaN(s)?a:s}let i=[],r=[];for(let a=0;a0){let l=r.pop();r.length===0&&i.push([l,a])}if(!i.length)return e;for(let a=i.length-1;a>=0;a--){let[l,s]=i[a],d=e.slice(l+3,s),u=n(d,t),c=t(...u);e=e.slice(0,l)+c+e.slice(s+1)}return e}var up=e=>{var t;let n=Oe.getTheme(),o=ol(n,e,void 0,"variable"),i=(t=o==null?void 0:o.match(/--[\w-]+/g))==null?void 0:t[0],r=ol(n,e,void 0,"value");return{name:i,variable:o,value:r}},Qn=(...e)=>ol(Oe.getTheme(),...e),ol=(e={},t,n,o)=>{if(t){let{variable:i,options:r}=Oe.defaults||{},{prefix:a,transform:l}=(e==null?void 0:e.options)||r||{},s=qn(t,pr)?t:`{${t}}`;return o==="value"||gt(o)&&l==="strict"?Oe.getTokenValue(t):sp(s,void 0,a,[i.excludedKeyRegex],n)}return""};function hi(e,...t){if(e instanceof Array){let n=e.reduce((o,i,r)=>{var a;return o+i+((a=St(t[r],{dt:Qn}))!=null?a:"")},"");return dp(n,Qn)}return St(e,{dt:Qn})}function P0(e,t={}){let n=Oe.defaults.variable,{prefix:o=n.prefix,selector:i=n.selector,excludedKeyRegex:r=n.excludedKeyRegex}=t,a=[],l=[],s=[{node:e,path:o}];for(;s.length;){let{node:u,path:c}=s.pop();for(let f in u){let p=u[f],v=k0(p),C=qn(f,r)?nl(c):nl(c,np(f));if(Jt(v))s.push({node:v,path:C});else{let S=lp(C),x=sp(v,C,o,[r]);$0(l,S,x);let P=C;o&&P.startsWith(o+"-")&&(P=P.slice(o.length+1)),a.push(P.replace(/-/g,"."))}}}let d=l.join("");return{value:l,tokens:a,declarations:d,css:uo(i,d)}}var Et={regex:{rules:{class:{pattern:/^\.([a-zA-Z][\w-]*)$/,resolve(e){return{type:"class",selector:e,matched:this.pattern.test(e.trim())}}},attr:{pattern:/^\[(.*)\]$/,resolve(e){return{type:"attr",selector:`:root${e},:host${e}`,matched:this.pattern.test(e.trim())}}},media:{pattern:/^@media (.*)$/,resolve(e){return{type:"media",selector:e,matched:this.pattern.test(e.trim())}}},system:{pattern:/^system$/,resolve(e){return{type:"system",selector:"@media (prefers-color-scheme: dark)",matched:this.pattern.test(e.trim())}}},custom:{resolve(e){return{type:"custom",selector:e,matched:!0}}}},resolve(e){let t=Object.keys(this.rules).filter(n=>n!=="custom").map(n=>this.rules[n]);return[e].flat().map(n=>{var o;return(o=t.map(i=>i.resolve(n)).find(i=>i.matched))!=null?o:this.rules.custom.resolve(n)})}},_toVariables(e,t){return P0(e,{prefix:t==null?void 0:t.prefix})},getCommon({name:e="",theme:t={},params:n,set:o,defaults:i}){var r,a,l,s,d,u,c;let{preset:f,options:p}=t,v,C,S,x,P,L,k;if(me(f)&&p.transform!=="strict"){let{primitive:F,semantic:K,extend:z}=f,q=K||{},{colorScheme:H}=q,ee=on(q,["colorScheme"]),X=z||{},{colorScheme:j}=X,le=on(X,["colorScheme"]),pe=H||{},{dark:ue}=pe,se=on(pe,["dark"]),ne=j||{},{dark:ge}=ne,De=on(ne,["dark"]),Ve=me(F)?this._toVariables({primitive:F},p):{},Ue=me(ee)?this._toVariables({semantic:ee},p):{},je=me(se)?this._toVariables({light:se},p):{},Ot=me(ue)?this._toVariables({dark:ue},p):{},bt=me(le)?this._toVariables({semantic:le},p):{},Nt=me(De)?this._toVariables({light:De},p):{},rt=me(ge)?this._toVariables({dark:ge},p):{},[A,Y]=[(r=Ve.declarations)!=null?r:"",Ve.tokens],[Q,oe]=[(a=Ue.declarations)!=null?a:"",Ue.tokens||[]],[ve,y]=[(l=je.declarations)!=null?l:"",je.tokens||[]],[w,$]=[(s=Ot.declarations)!=null?s:"",Ot.tokens||[]],[E,B]=[(d=bt.declarations)!=null?d:"",bt.tokens||[]],[O,W]=[(u=Nt.declarations)!=null?u:"",Nt.tokens||[]],[G,U]=[(c=rt.declarations)!=null?c:"",rt.tokens||[]];v=this.transformCSS(e,A,"light","variable",p,o,i),C=Y;let M=this.transformCSS(e,`${Q}${ve}`,"light","variable",p,o,i),ie=this.transformCSS(e,`${w}`,"dark","variable",p,o,i);S=`${M}${ie}`,x=[...new Set([...oe,...y,...$])];let Z=this.transformCSS(e,`${E}${O}color-scheme:light`,"light","variable",p,o,i),re=this.transformCSS(e,`${G}color-scheme:dark`,"dark","variable",p,o,i);P=`${Z}${re}`,L=[...new Set([...B,...W,...U])],k=St(f.css,{dt:Qn})}return{primitive:{css:v,tokens:C},semantic:{css:S,tokens:x},global:{css:P,tokens:L},style:k}},getPreset({name:e="",preset:t={},options:n,params:o,set:i,defaults:r,selector:a}){var l,s,d;let u,c,f;if(me(t)&&n.transform!=="strict"){let p=e.replace("-directive",""),v=t,{colorScheme:C,extend:S,css:x}=v,P=on(v,["colorScheme","extend","css"]),L=S||{},{colorScheme:k}=L,F=on(L,["colorScheme"]),K=C||{},{dark:z}=K,q=on(K,["dark"]),H=k||{},{dark:ee}=H,X=on(H,["dark"]),j=me(P)?this._toVariables({[p]:At(At({},P),F)},n):{},le=me(q)?this._toVariables({[p]:At(At({},q),X)},n):{},pe=me(z)?this._toVariables({[p]:At(At({},z),ee)},n):{},[ue,se]=[(l=j.declarations)!=null?l:"",j.tokens||[]],[ne,ge]=[(s=le.declarations)!=null?s:"",le.tokens||[]],[De,Ve]=[(d=pe.declarations)!=null?d:"",pe.tokens||[]],Ue=this.transformCSS(p,`${ue}${ne}`,"light","variable",n,i,r,a),je=this.transformCSS(p,De,"dark","variable",n,i,r,a);u=`${Ue}${je}`,c=[...new Set([...se,...ge,...Ve])],f=St(x,{dt:Qn})}return{css:u,tokens:c,style:f}},getPresetC({name:e="",theme:t={},params:n,set:o,defaults:i}){var r;let{preset:a,options:l}=t,s=(r=a==null?void 0:a.components)==null?void 0:r[e];return this.getPreset({name:e,preset:s,options:l,params:n,set:o,defaults:i})},getPresetD({name:e="",theme:t={},params:n,set:o,defaults:i}){var r,a;let l=e.replace("-directive",""),{preset:s,options:d}=t,u=((r=s==null?void 0:s.components)==null?void 0:r[l])||((a=s==null?void 0:s.directives)==null?void 0:a[l]);return this.getPreset({name:l,preset:u,options:d,params:n,set:o,defaults:i})},applyDarkColorScheme(e){return!(e.darkModeSelector==="none"||e.darkModeSelector===!1)},getColorSchemeOption(e,t){var n;return this.applyDarkColorScheme(e)?this.regex.resolve(e.darkModeSelector===!0?t.options.darkModeSelector:(n=e.darkModeSelector)!=null?n:t.options.darkModeSelector):[]},getLayerOrder(e,t={},n,o){let{cssLayer:i}=t;return i?`@layer ${St(i.order||i.name||"primeui",n)}`:""},getCommonStyleSheet({name:e="",theme:t={},params:n,props:o={},set:i,defaults:r}){let a=this.getCommon({name:e,theme:t,params:n,set:i,defaults:r}),l=Object.entries(o).reduce((s,[d,u])=>s.push(`${d}="${u}"`)&&s,[]).join(" ");return Object.entries(a||{}).reduce((s,[d,u])=>{if(Jt(u)&&Object.hasOwn(u,"css")){let c=Jo(u.css),f=`${d}-variables`;s.push(``)}return s},[]).join("")},getStyleSheet({name:e="",theme:t={},params:n,props:o={},set:i,defaults:r}){var a;let l={name:e,theme:t,params:n,set:i,defaults:r},s=(a=e.includes("-directive")?this.getPresetD(l):this.getPresetC(l))==null?void 0:a.css,d=Object.entries(o).reduce((u,[c,f])=>u.push(`${c}="${f}"`)&&u,[]).join(" ");return s?``:""},createTokens(e={},t,n="",o="",i={}){let r=function(l,s={},d=[]){if(d.includes(this.path))return console.warn(`Circular reference detected at ${this.path}`),{colorScheme:l,path:this.path,paths:s,value:void 0};d.push(this.path),s.name=this.path,s.binding||(s.binding={});let u=this.value;if(typeof this.value=="string"&&pr.test(this.value)){let c=this.value.trim().replace(pr,f=>{var p;let v=f.slice(1,-1),C=this.tokens[v];if(!C)return console.warn(`Token not found for path: ${v}`),"__UNRESOLVED__";let S=C.computed(l,s,d);return Array.isArray(S)&&S.length===2?`light-dark(${S[0].value},${S[1].value})`:(p=S==null?void 0:S.value)!=null?p:"__UNRESOLVED__"});u=ip.test(c.replace(ap,"0"))?`calc(${c})`:c}return gt(s.binding)&&delete s.binding,d.pop(),{colorScheme:l,path:this.path,paths:s,value:u.includes("__UNRESOLVED__")?void 0:u}},a=(l,s,d)=>{Object.entries(l).forEach(([u,c])=>{let f=qn(u,t.variable.excludedKeyRegex)?s:s?`${s}.${zd(u)}`:zd(u),p=d?`${d}.${u}`:u;Jt(c)?a(c,f,p):(i[f]||(i[f]={paths:[],computed:(v,C={},S=[])=>{if(i[f].paths.length===1)return i[f].paths[0].computed(i[f].paths[0].scheme,C.binding,S);if(v&&v!=="none")for(let x=0;xx.computed(x.scheme,C[x.scheme],S))}}),i[f].paths.push({path:p,value:c,scheme:p.includes("colorScheme.light")?"light":p.includes("colorScheme.dark")?"dark":"none",computed:r,tokens:i}))})};return a(e,n,o),i},getTokenValue(e,t,n){var o;let i=(l=>l.split(".").filter(s=>!qn(s.toLowerCase(),n.variable.excludedKeyRegex)).join("."))(t),r=t.includes("colorScheme.light")?"light":t.includes("colorScheme.dark")?"dark":void 0,a=[(o=e[i])==null?void 0:o.computed(r)].flat().filter(l=>l);return a.length===1?a[0].value:a.reduce((l={},s)=>{let d=s,{colorScheme:u}=d,c=on(d,["colorScheme"]);return l[u]=c,l},void 0)},getSelectorRule(e,t,n,o){return n==="class"||n==="attr"?uo(me(t)?`${e}${t},${e} ${t}`:e,o):uo(e,uo(t??":root,:host",o))},transformCSS(e,t,n,o,i={},r,a,l){if(me(t)){let{cssLayer:s}=i;if(o!=="style"){let d=this.getColorSchemeOption(i,a);t=n==="dark"?d.reduce((u,{type:c,selector:f})=>(me(f)&&(u+=f.includes("[CSS]")?f.replace("[CSS]",t):this.getSelectorRule(f,l,c,t)),u),""):uo(l??":root,:host",t)}if(s){let d={name:"primeui"};Jt(s)&&(d.name=St(s.name,{name:e,type:o})),me(d.name)&&(t=uo(`@layer ${d.name}`,t),r==null||r.layerNames(d.name))}return t}return""}},Oe={defaults:{variable:{prefix:"p",selector:":root,:host",excludedKeyRegex:/^(primitive|semantic|components|directives|variables|colorscheme|light|dark|common|root|states|extend|css)$/gi},options:{prefix:"p",darkModeSelector:"system",cssLayer:!1}},_theme:void 0,_layerNames:new Set,_loadedStyleNames:new Set,_loadingStyles:new Set,_tokens:{},update(e={}){let{theme:t}=e;t&&(this._theme=Ra(At({},t),{options:At(At({},this.defaults.options),t.options)}),this._tokens=Et.createTokens(this.preset,this.defaults),this.clearLoadedStyleNames())},get theme(){return this._theme},get preset(){var e;return((e=this.theme)==null?void 0:e.preset)||{}},get options(){var e;return((e=this.theme)==null?void 0:e.options)||{}},get tokens(){return this._tokens},getTheme(){return this.theme},setTheme(e){this.update({theme:e}),Qe.emit("theme:change",e)},getPreset(){return this.preset},setPreset(e){this._theme=Ra(At({},this.theme),{preset:e}),this._tokens=Et.createTokens(e,this.defaults),this.clearLoadedStyleNames(),Qe.emit("preset:change",e),Qe.emit("theme:change",this.theme)},getOptions(){return this.options},setOptions(e){this._theme=Ra(At({},this.theme),{options:e}),this.clearLoadedStyleNames(),Qe.emit("options:change",e),Qe.emit("theme:change",this.theme)},getLayerNames(){return[...this._layerNames]},setLayerNames(e){this._layerNames.add(e)},getLoadedStyleNames(){return this._loadedStyleNames},isStyleNameLoaded(e){return this._loadedStyleNames.has(e)},setLoadedStyleName(e){this._loadedStyleNames.add(e)},deleteLoadedStyleName(e){this._loadedStyleNames.delete(e)},clearLoadedStyleNames(){this._loadedStyleNames.clear()},getTokenValue(e){return Et.getTokenValue(this.tokens,e,this.defaults)},getCommon(e="",t){return Et.getCommon({name:e,theme:this.theme,params:t,defaults:this.defaults,set:{layerNames:this.setLayerNames.bind(this)}})},getComponent(e="",t){let n={name:e,theme:this.theme,params:t,defaults:this.defaults,set:{layerNames:this.setLayerNames.bind(this)}};return Et.getPresetC(n)},getDirective(e="",t){let n={name:e,theme:this.theme,params:t,defaults:this.defaults,set:{layerNames:this.setLayerNames.bind(this)}};return Et.getPresetD(n)},getCustomPreset(e="",t,n,o){let i={name:e,preset:t,options:this.options,selector:n,params:o,defaults:this.defaults,set:{layerNames:this.setLayerNames.bind(this)}};return Et.getPreset(i)},getLayerOrderCSS(e=""){return Et.getLayerOrder(e,this.options,{names:this.getLayerNames()},this.defaults)},transformCSS(e="",t,n="style",o){return Et.transformCSS(e,t,o,n,this.options,{layerNames:this.setLayerNames.bind(this)},this.defaults)},getCommonStyleSheet(e="",t,n={}){return Et.getCommonStyleSheet({name:e,theme:this.theme,params:t,props:n,defaults:this.defaults,set:{layerNames:this.setLayerNames.bind(this)}})},getStyleSheet(e,t,n={}){return Et.getStyleSheet({name:e,theme:this.theme,params:t,props:n,defaults:this.defaults,set:{layerNames:this.setLayerNames.bind(this)}})},onStyleMounted(e){this._loadingStyles.add(e)},onStyleUpdated(e){this._loadingStyles.add(e)},onStyleLoaded(e,{name:t}){this._loadingStyles.size&&(this._loadingStyles.delete(t),Qe.emit(`theme:${t}:load`,e),!this._loadingStyles.size&&Qe.emit("theme:load"))}},$n={_loadedStyleNames:new Set,getLoadedStyleNames:function(){return this._loadedStyleNames},isStyleNameLoaded:function(t){return this._loadedStyleNames.has(t)},setLoadedStyleName:function(t){this._loadedStyleNames.add(t)},deleteLoadedStyleName:function(t){this._loadedStyleNames.delete(t)},clearLoadedStyleNames:function(){this._loadedStyleNames.clear()}},I0=` - *, - ::before, - ::after { - box-sizing: border-box; - } - - .p-collapsible-enter-active { - animation: p-animate-collapsible-expand 0.2s ease-out; - overflow: hidden; - } - - .p-collapsible-leave-active { - animation: p-animate-collapsible-collapse 0.2s ease-out; - overflow: hidden; - } - - @keyframes p-animate-collapsible-expand { - from { - grid-template-rows: 0fr; - } - to { - grid-template-rows: 1fr; - } - } - - @keyframes p-animate-collapsible-collapse { - from { - grid-template-rows: 1fr; - } - to { - grid-template-rows: 0fr; - } - } - - .p-disabled, - .p-disabled * { - cursor: default; - pointer-events: none; - user-select: none; - } - - .p-disabled, - .p-component:disabled { - opacity: dt('disabled.opacity'); - } - - .pi { - font-size: dt('icon.size'); - } - - .p-icon { - width: dt('icon.size'); - height: dt('icon.size'); - } - - .p-overlay-mask { - background: var(--px-mask-background, dt('mask.background')); - color: dt('mask.color'); - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - } - - .p-overlay-mask-enter-active { - animation: p-animate-overlay-mask-enter dt('mask.transition.duration') forwards; - } - - .p-overlay-mask-leave-active { - animation: p-animate-overlay-mask-leave dt('mask.transition.duration') forwards; - } - - @keyframes p-animate-overlay-mask-enter { - from { - background: transparent; - } - to { - background: var(--px-mask-background, dt('mask.background')); - } - } - @keyframes p-animate-overlay-mask-leave { - from { - background: var(--px-mask-background, dt('mask.background')); - } - to { - background: transparent; - } - } - - .p-anchored-overlay-enter-active { - animation: p-animate-anchored-overlay-enter 300ms cubic-bezier(.19,1,.22,1); - } - - .p-anchored-overlay-leave-active { - animation: p-animate-anchored-overlay-leave 300ms cubic-bezier(.19,1,.22,1); - } - - @keyframes p-animate-anchored-overlay-enter { - from { - opacity: 0; - transform: scale(0.93); - } - } - - @keyframes p-animate-anchored-overlay-leave { - to { - opacity: 0; - transform: scale(0.93); - } - } -`;function hr(e){"@babel/helpers - typeof";return hr=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},hr(e)}function Fd(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),n.push.apply(n,o)}return n}function jd(e){for(var t=1;t1&&arguments[1]!==void 0?arguments[1]:!0;dr()&&dr().components?cs(e):t?e():ds(e)}var A0=0;function L0(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=Wo(!1),o=Wo(e),i=Wo(null),r=Jf()?window.document:void 0,a=t.document,l=a===void 0?r:a,s=t.immediate,d=s===void 0?!0:s,u=t.manual,c=u===void 0?!1:u,f=t.name,p=f===void 0?"style_".concat(++A0):f,v=t.id,C=v===void 0?void 0:v,S=t.media,x=S===void 0?void 0:S,P=t.nonce,L=P===void 0?void 0:P,k=t.first,F=k===void 0?!1:k,K=t.onMounted,z=K===void 0?void 0:K,q=t.onUpdated,H=q===void 0?void 0:q,ee=t.onLoad,X=ee===void 0?void 0:ee,j=t.props,le=j===void 0?{}:j,pe=function(){},ue=function(ge){var De=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};if(l){var Ve=jd(jd({},le),De),Ue=Ve.name||p,je=Ve.id||C,Ot=Ve.nonce||L;i.value=l.querySelector('style[data-primevue-style-id="'.concat(Ue,'"]'))||l.getElementById(je)||l.createElement("style"),i.value.isConnected||(o.value=ge||e,Fi(i.value,{type:"text/css",id:je,media:x,nonce:Ot}),F?l.head.prepend(i.value):l.head.appendChild(i.value),aa(i.value,"data-primevue-style-id",Ue),Fi(i.value,Ve),i.value.onload=function(bt){return X==null?void 0:X(bt,{name:Ue})},z==null||z(Ue)),!n.value&&(pe=Lt(o,function(bt){i.value.textContent=bt,H==null||H(Ue)},{immediate:!0}),n.value=!0)}},se=function(){!l||!n.value||(pe(),Jb(i.value)&&l.head.removeChild(i.value),n.value=!1,i.value=null)};return d&&!c&&E0(ue),{id:C,name:p,el:i,css:o,unload:se,load:ue,isLoaded:Oi(n)}}function gr(e){"@babel/helpers - typeof";return gr=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},gr(e)}var Nd,Vd,Ud,Hd;function Gd(e,t){return M0(e)||B0(e,t)||D0(e,t)||_0()}function _0(){throw new TypeError(`Invalid attempt to destructure non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function D0(e,t){if(e){if(typeof e=="string")return Kd(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Kd(e,t):void 0}}function Kd(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);n1&&arguments[1]!==void 0?arguments[1]:{},o=arguments.length>2&&arguments[2]!==void 0?arguments[2]:function(r){return r},i=o(hi(Nd||(Nd=gi(["",""])),t));return me(i)?L0(Jo(i),Oa({name:this.name},n)):{}},loadCSS:function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};return this.load(this.css,t)},loadStyle:function(){var t=this,n=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},o=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"";return this.load(this.style,n,function(){var i=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"";return Oe.transformCSS(n.name||t.name,"".concat(i).concat(hi(Vd||(Vd=gi(["",""])),o)))})},getCommonTheme:function(t){return Oe.getCommon(this.name,t)},getComponentTheme:function(t){return Oe.getComponent(this.name,t)},getDirectiveTheme:function(t){return Oe.getDirective(this.name,t)},getPresetTheme:function(t,n,o){return Oe.getCustomPreset(this.name,t,n,o)},getLayerOrderThemeCSS:function(){return Oe.getLayerOrderCSS(this.name)},getStyleSheet:function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"",n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};if(this.css){var o=St(this.css,{dt:Qn})||"",i=Jo(hi(Ud||(Ud=gi(["","",""])),o,t)),r=Object.entries(n).reduce(function(a,l){var s=Gd(l,2),d=s[0],u=s[1];return a.push("".concat(d,'="').concat(u,'"'))&&a},[]).join(" ");return me(i)?'"):""}return""},getCommonThemeStyleSheet:function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return Oe.getCommonStyleSheet(this.name,t,n)},getThemeStyleSheet:function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},o=[Oe.getStyleSheet(this.name,t,n)];if(this.style){var i=this.name==="base"?"global-style":"".concat(this.name,"-style"),r=hi(Hd||(Hd=gi(["",""])),St(this.style,{dt:Qn})),a=Jo(Oe.transformCSS(i,r)),l=Object.entries(n).reduce(function(s,d){var u=Gd(d,2),c=u[0],f=u[1];return s.push("".concat(c,'="').concat(f,'"'))&&s},[]).join(" ");me(a)&&o.push('"))}return o.join("")},extend:function(t){return Oa(Oa({},this),{},{css:void 0,style:void 0},t)}};function H0(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"pc",t=Tg();return"".concat(e).concat(t.replace("v-","").replaceAll("-","_"))}var qd=fe.extend({name:"common"});function mr(e){"@babel/helpers - typeof";return mr=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},mr(e)}function G0(e){return pp(e)||K0(e)||fp(e)||cp()}function K0(e){if(typeof Symbol<"u"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function Do(e,t){return pp(e)||W0(e,t)||fp(e,t)||cp()}function cp(){throw new TypeError(`Invalid attempt to destructure non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function fp(e,t){if(e){if(typeof e=="string")return rl(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?rl(e,t):void 0}}function rl(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);n1?n-1:0),i=1;i0&&arguments[0]!==void 0?arguments[0]:function(){};$n.clearLoadedStyleNames(),Qe.on("theme:change",t)},_removeThemeListeners:function(){Qe.off("theme:change",this._loadCoreStyles),Qe.off("theme:change",this._load),Qe.off("theme:change",this._themeScopedListener)},_getHostInstance:function(t){return t?this.$options.hostName?t.$.type.name===this.$options.hostName?t:this._getHostInstance(t.$parentInstance):t.$parentInstance:void 0},_getPropValue:function(t){var n;return this[t]||((n=this._getHostInstance(this))===null||n===void 0?void 0:n[t])},_getOptionValue:function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"",o=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return Ts(t,n,o)},_getPTValue:function(){var t,n=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},o=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"",i=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:!0,a=/./g.test(o)&&!!i[o.split(".")[0]],l=this._getPropValue("ptOptions")||((t=this.$primevueConfig)===null||t===void 0?void 0:t.ptOptions)||{},s=l.mergeSections,d=s===void 0?!0:s,u=l.mergeProps,c=u===void 0?!1:u,f=r?a?this._useGlobalPT(this._getPTClassValue,o,i):this._useDefaultPT(this._getPTClassValue,o,i):void 0,p=a?void 0:this._getPTSelf(n,this._getPTClassValue,o,we(we({},i),{},{global:f||{}})),v=this._getPTDatasets(o);return d||!d&&p?c?this._mergeProps(c,f,p,v):we(we(we({},f),p),v):we(we({},p),v)},_getPTSelf:function(){for(var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},n=arguments.length,o=new Array(n>1?n-1:0),i=1;i0&&arguments[0]!==void 0?arguments[0]:"",i="data-pc-",r=o==="root"&&me((t=this.pt)===null||t===void 0?void 0:t["data-pc-section"]);return o!=="transition"&&we(we({},o==="root"&&we(we(No({},"".concat(i,"name"),Zt(r?(n=this.pt)===null||n===void 0?void 0:n["data-pc-section"]:this.$.type.name)),r&&No({},"".concat(i,"extend"),Zt(this.$.type.name))),{},No({},"".concat(this.$attrSelector),""))),{},No({},"".concat(i,"section"),Zt(o)))},_getPTClassValue:function(){var t=this._getOptionValue.apply(this,arguments);return ht(t)||tp(t)?{class:t}:t},_getPT:function(t){var n=this,o=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"",i=arguments.length>2?arguments[2]:void 0,r=function(l){var s,d=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,u=i?i(l):l,c=Zt(o),f=Zt(n.$name);return(s=d?c!==f?u==null?void 0:u[c]:void 0:u==null?void 0:u[c])!==null&&s!==void 0?s:u};return t!=null&&t.hasOwnProperty("_usept")?{_usept:t._usept,originalValue:r(t.originalValue),value:r(t.value)}:r(t,!0)},_usePT:function(t,n,o,i){var r=function(C){return n(C,o,i)};if(t!=null&&t.hasOwnProperty("_usept")){var a,l=t._usept||((a=this.$primevueConfig)===null||a===void 0?void 0:a.ptOptions)||{},s=l.mergeSections,d=s===void 0?!0:s,u=l.mergeProps,c=u===void 0?!1:u,f=r(t.originalValue),p=r(t.value);return f===void 0&&p===void 0?void 0:ht(p)?p:ht(f)?f:d||!d&&p?c?this._mergeProps(c,f,p):we(we({},f),p):p}return r(t)},_useGlobalPT:function(t,n,o){return this._usePT(this.globalPT,t,n,o)},_useDefaultPT:function(t,n,o){return this._usePT(this.defaultPT,t,n,o)},ptm:function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"",n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return this._getPTValue(this.pt,t,we(we({},this.$params),n))},ptmi:function(){var t,n=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"",o=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},i=m(this.$_attrsWithoutPT,this.ptm(n,o));return i!=null&&i.hasOwnProperty("id")&&((t=i.id)!==null&&t!==void 0||(i.id=this.$id)),i},ptmo:function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"",o=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return this._getPTValue(t,n,we({instance:this},o),!1)},cx:function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"",n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return this.isUnstyled?void 0:this._getOptionValue(this.$style.classes,t,we(we({},this.$params),n))},sx:function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"",n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0,o=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};if(n){var i=this._getOptionValue(this.$style.inlineStyles,t,we(we({},this.$params),o)),r=this._getOptionValue(qd.inlineStyles,t,we(we({},this.$params),o));return[r,i]}}},computed:{globalPT:function(){var t,n=this;return this._getPT((t=this.$primevueConfig)===null||t===void 0?void 0:t.pt,void 0,function(o){return St(o,{instance:n})})},defaultPT:function(){var t,n=this;return this._getPT((t=this.$primevueConfig)===null||t===void 0?void 0:t.pt,void 0,function(o){return n._getOptionValue(o,n.$name,we({},n.$params))||St(o,we({},n.$params))})},isUnstyled:function(){var t;return this.unstyled!==void 0?this.unstyled:(t=this.$primevueConfig)===null||t===void 0?void 0:t.unstyled},$id:function(){return this.$attrs.id||this.uid},$inProps:function(){var t,n=Object.keys(((t=this.$.vnode)===null||t===void 0?void 0:t.props)||{});return Object.fromEntries(Object.entries(this.$props).filter(function(o){var i=Do(o,1),r=i[0];return n==null?void 0:n.includes(r)}))},$theme:function(){var t;return(t=this.$primevueConfig)===null||t===void 0?void 0:t.theme},$style:function(){return we(we({classes:void 0,inlineStyles:void 0,load:function(){},loadCSS:function(){},loadStyle:function(){}},(this._getHostInstance(this)||{}).$style),this.$options.style)},$styleOptions:function(){var t;return{nonce:(t=this.$primevueConfig)===null||t===void 0||(t=t.csp)===null||t===void 0?void 0:t.nonce}},$primevueConfig:function(){var t;return(t=this.$primevue)===null||t===void 0?void 0:t.config},$name:function(){return this.$options.hostName||this.$.type.name},$params:function(){var t=this._getHostInstance(this)||this.$parent;return{instance:this,props:this.$props,state:this.$data,attrs:this.$attrs,parent:{instance:t,props:t==null?void 0:t.$props,state:t==null?void 0:t.$data,attrs:t==null?void 0:t.$attrs}}},$_attrsPT:function(){return Object.entries(this.$attrs||{}).filter(function(t){var n=Do(t,1),o=n[0];return o==null?void 0:o.startsWith("pt:")}).reduce(function(t,n){var o=Do(n,2),i=o[0],r=o[1],a=i.split(":"),l=G0(a),s=rl(l).slice(1);return s==null||s.reduce(function(d,u,c,f){return!d[u]&&(d[u]=c===f.length-1?r:{}),d[u]},t),t},{})},$_attrsWithoutPT:function(){return Object.entries(this.$attrs||{}).filter(function(t){var n=Do(t,1),o=n[0];return!(o!=null&&o.startsWith("pt:"))}).reduce(function(t,n){var o=Do(n,2),i=o[0],r=o[1];return t[i]=r,t},{})}}},Z0=` -.p-icon { - display: inline-block; - vertical-align: baseline; - flex-shrink: 0; -} - -.p-icon-spin { - -webkit-animation: p-icon-spin 2s infinite linear; - animation: p-icon-spin 2s infinite linear; -} - -@-webkit-keyframes p-icon-spin { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} - -@keyframes p-icon-spin { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -`,Y0=fe.extend({name:"baseicon",css:Z0});function br(e){"@babel/helpers - typeof";return br=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},br(e)}function Zd(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),n.push.apply(n,o)}return n}function Yd(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);n0&&arguments[0]!==void 0?arguments[0]:{},i=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:"",a=arguments.length>3&&arguments[3]!==void 0?arguments[3]:{},l=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!0,s=function(){var P=be._getOptionValue.apply(be,arguments);return ht(P)||tp(P)?{class:P}:P},d=((t=o.binding)===null||t===void 0||(t=t.value)===null||t===void 0?void 0:t.ptOptions)||((n=o.$primevueConfig)===null||n===void 0?void 0:n.ptOptions)||{},u=d.mergeSections,c=u===void 0?!0:u,f=d.mergeProps,p=f===void 0?!1:f,v=l?be._useDefaultPT(o,o.defaultPT(),s,r,a):void 0,C=be._usePT(o,be._getPT(i,o.$name),s,r,Se(Se({},a),{},{global:v||{}})),S=be._getPTDatasets(o,r);return c||!c&&C?p?be._mergeProps(o,p,v,C,S):Se(Se(Se({},v),C),S):Se(Se({},C),S)},_getPTDatasets:function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"",o="data-pc-";return Se(Se({},n==="root"&&al({},"".concat(o,"name"),Zt(t.$name))),{},al({},"".concat(o,"section"),Zt(n)))},_getPT:function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"",o=arguments.length>2?arguments[2]:void 0,i=function(a){var l,s=o?o(a):a,d=Zt(n);return(l=s==null?void 0:s[d])!==null&&l!==void 0?l:s};return t&&Object.hasOwn(t,"_usept")?{_usept:t._usept,originalValue:i(t.originalValue),value:i(t.value)}:i(t)},_usePT:function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0,o=arguments.length>2?arguments[2]:void 0,i=arguments.length>3?arguments[3]:void 0,r=arguments.length>4?arguments[4]:void 0,a=function(S){return o(S,i,r)};if(n&&Object.hasOwn(n,"_usept")){var l,s=n._usept||((l=t.$primevueConfig)===null||l===void 0?void 0:l.ptOptions)||{},d=s.mergeSections,u=d===void 0?!0:d,c=s.mergeProps,f=c===void 0?!1:c,p=a(n.originalValue),v=a(n.value);return p===void 0&&v===void 0?void 0:ht(v)?v:ht(p)?p:u||!u&&v?f?be._mergeProps(t,f,p,v):Se(Se({},p),v):v}return a(n)},_useDefaultPT:function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},o=arguments.length>2?arguments[2]:void 0,i=arguments.length>3?arguments[3]:void 0,r=arguments.length>4?arguments[4]:void 0;return be._usePT(t,n,o,i,r)},_loadStyles:function(){var t,n=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},o=arguments.length>1?arguments[1]:void 0,i=arguments.length>2?arguments[2]:void 0,r=be._getConfig(o,i),a={nonce:r==null||(t=r.csp)===null||t===void 0?void 0:t.nonce};be._loadCoreStyles(n,a),be._loadThemeStyles(n,a),be._loadScopedThemeStyles(n,a),be._removeThemeListeners(n),n.$loadStyles=function(){return be._loadThemeStyles(n,a)},be._themeChangeListener(n.$loadStyles)},_loadCoreStyles:function(){var t,n,o=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},i=arguments.length>1?arguments[1]:void 0;if(!$n.isStyleNameLoaded((t=o.$style)===null||t===void 0?void 0:t.name)&&(n=o.$style)!==null&&n!==void 0&&n.name){var r;fe.loadCSS(i),(r=o.$style)===null||r===void 0||r.loadCSS(i),$n.setLoadedStyleName(o.$style.name)}},_loadThemeStyles:function(){var t,n,o,i=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},r=arguments.length>1?arguments[1]:void 0;if(!(i!=null&&i.isUnstyled()||(i==null||(t=i.theme)===null||t===void 0?void 0:t.call(i))==="none")){if(!Oe.isStyleNameLoaded("common")){var a,l,s=((a=i.$style)===null||a===void 0||(l=a.getCommonTheme)===null||l===void 0?void 0:l.call(a))||{},d=s.primitive,u=s.semantic,c=s.global,f=s.style;fe.load(d==null?void 0:d.css,Se({name:"primitive-variables"},r)),fe.load(u==null?void 0:u.css,Se({name:"semantic-variables"},r)),fe.load(c==null?void 0:c.css,Se({name:"global-variables"},r)),fe.loadStyle(Se({name:"global-style"},r),f),Oe.setLoadedStyleName("common")}if(!Oe.isStyleNameLoaded((n=i.$style)===null||n===void 0?void 0:n.name)&&(o=i.$style)!==null&&o!==void 0&&o.name){var p,v,C,S,x=((p=i.$style)===null||p===void 0||(v=p.getDirectiveTheme)===null||v===void 0?void 0:v.call(p))||{},P=x.css,L=x.style;(C=i.$style)===null||C===void 0||C.load(P,Se({name:"".concat(i.$style.name,"-variables")},r)),(S=i.$style)===null||S===void 0||S.loadStyle(Se({name:"".concat(i.$style.name,"-style")},r),L),Oe.setLoadedStyleName(i.$style.name)}if(!Oe.isStyleNameLoaded("layer-order")){var k,F,K=(k=i.$style)===null||k===void 0||(F=k.getLayerOrderThemeCSS)===null||F===void 0?void 0:F.call(k);fe.load(K,Se({name:"layer-order",first:!0},r)),Oe.setLoadedStyleName("layer-order")}}},_loadScopedThemeStyles:function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0,o=t.preset();if(o&&t.$attrSelector){var i,r,a,l=((i=t.$style)===null||i===void 0||(r=i.getPresetTheme)===null||r===void 0?void 0:r.call(i,o,"[".concat(t.$attrSelector,"]")))||{},s=l.css,d=(a=t.$style)===null||a===void 0?void 0:a.load(s,Se({name:"".concat(t.$attrSelector,"-").concat(t.$style.name)},n));t.scopedStyleEl=d.el}},_themeChangeListener:function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:function(){};$n.clearLoadedStyleNames(),Qe.on("theme:change",t)},_removeThemeListeners:function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};Qe.off("theme:change",t.$loadStyles),t.$loadStyles=void 0},_hook:function(t,n,o,i,r,a){var l,s,d="on".concat(g0(n)),u=be._getConfig(i,r),c=o==null?void 0:o.$instance,f=be._usePT(c,be._getPT(i==null||(l=i.value)===null||l===void 0?void 0:l.pt,t),be._getOptionValue,"hooks.".concat(d)),p=be._useDefaultPT(c,u==null||(s=u.pt)===null||s===void 0||(s=s.directives)===null||s===void 0?void 0:s[t],be._getOptionValue,"hooks.".concat(d)),v={el:o,binding:i,vnode:r,prevVnode:a};f==null||f(c,v),p==null||p(c,v)},_mergeProps:function(){for(var t=arguments.length>1?arguments[1]:void 0,n=arguments.length,o=new Array(n>2?n-2:0),i=2;i1&&arguments[1]!==void 0?arguments[1]:{},o=function(l,s,d,u,c){var f,p,v,C;s._$instances=s._$instances||{};var S=be._getConfig(d,u),x=s._$instances[t]||{},P=gt(x)?Se(Se({},n),n==null?void 0:n.methods):{};s._$instances[t]=Se(Se({},x),{},{$name:t,$host:s,$binding:d,$modifiers:d==null?void 0:d.modifiers,$value:d==null?void 0:d.value,$el:x.$el||s||void 0,$style:Se({classes:void 0,inlineStyles:void 0,load:function(){},loadCSS:function(){},loadStyle:function(){}},n==null?void 0:n.style),$primevueConfig:S,$attrSelector:(f=s.$pd)===null||f===void 0||(f=f[t])===null||f===void 0?void 0:f.attrSelector,defaultPT:function(){return be._getPT(S==null?void 0:S.pt,void 0,function(k){var F;return k==null||(F=k.directives)===null||F===void 0?void 0:F[t]})},isUnstyled:function(){var k,F;return((k=s._$instances[t])===null||k===void 0||(k=k.$binding)===null||k===void 0||(k=k.value)===null||k===void 0?void 0:k.unstyled)!==void 0?(F=s._$instances[t])===null||F===void 0||(F=F.$binding)===null||F===void 0||(F=F.value)===null||F===void 0?void 0:F.unstyled:S==null?void 0:S.unstyled},theme:function(){var k;return(k=s._$instances[t])===null||k===void 0||(k=k.$primevueConfig)===null||k===void 0?void 0:k.theme},preset:function(){var k;return(k=s._$instances[t])===null||k===void 0||(k=k.$binding)===null||k===void 0||(k=k.value)===null||k===void 0?void 0:k.dt},ptm:function(){var k,F=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"",K=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return be._getPTValue(s._$instances[t],(k=s._$instances[t])===null||k===void 0||(k=k.$binding)===null||k===void 0||(k=k.value)===null||k===void 0?void 0:k.pt,F,Se({},K))},ptmo:function(){var k=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},F=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"",K=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return be._getPTValue(s._$instances[t],k,F,K,!1)},cx:function(){var k,F,K=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"",z=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return(k=s._$instances[t])!==null&&k!==void 0&&k.isUnstyled()?void 0:be._getOptionValue((F=s._$instances[t])===null||F===void 0||(F=F.$style)===null||F===void 0?void 0:F.classes,K,Se({},z))},sx:function(){var k,F=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"",K=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0,z=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return K?be._getOptionValue((k=s._$instances[t])===null||k===void 0||(k=k.$style)===null||k===void 0?void 0:k.inlineStyles,F,Se({},z)):void 0}},P),s.$instance=s._$instances[t],(p=(v=s.$instance)[l])===null||p===void 0||p.call(v,s,d,u,c),s["$".concat(t)]=s.$instance,be._hook(t,l,s,d,u,c),s.$pd||(s.$pd={}),s.$pd[t]=Se(Se({},(C=s.$pd)===null||C===void 0?void 0:C[t]),{},{name:t,instance:s._$instances[t]})},i=function(l){var s,d,u,c=l._$instances[t],f=c==null?void 0:c.watch,p=function(S){var x,P=S.newValue,L=S.oldValue;return f==null||(x=f.config)===null||x===void 0?void 0:x.call(c,P,L)},v=function(S){var x,P=S.newValue,L=S.oldValue;return f==null||(x=f["config.ripple"])===null||x===void 0?void 0:x.call(c,P,L)};c.$watchersCallback={config:p,"config.ripple":v},f==null||(s=f.config)===null||s===void 0||s.call(c,c==null?void 0:c.$primevueConfig),Tn.on("config:change",p),f==null||(d=f["config.ripple"])===null||d===void 0||d.call(c,c==null||(u=c.$primevueConfig)===null||u===void 0?void 0:u.ripple),Tn.on("config:ripple:change",v)},r=function(l){var s=l._$instances[t].$watchersCallback;s&&(Tn.off("config:change",s.config),Tn.off("config:ripple:change",s["config.ripple"]),l._$instances[t].$watchersCallback=void 0)};return{created:function(l,s,d,u){l.$pd||(l.$pd={}),l.$pd[t]={name:t,attrSelector:m0("pd")},o("created",l,s,d,u)},beforeMount:function(l,s,d,u){var c;be._loadStyles((c=l.$pd[t])===null||c===void 0?void 0:c.instance,s,d),o("beforeMount",l,s,d,u),i(l)},mounted:function(l,s,d,u){var c;be._loadStyles((c=l.$pd[t])===null||c===void 0?void 0:c.instance,s,d),o("mounted",l,s,d,u)},beforeUpdate:function(l,s,d,u){o("beforeUpdate",l,s,d,u)},updated:function(l,s,d,u){var c;be._loadStyles((c=l.$pd[t])===null||c===void 0?void 0:c.instance,s,d),o("updated",l,s,d,u)},beforeUnmount:function(l,s,d,u){var c;r(l),be._removeThemeListeners((c=l.$pd[t])===null||c===void 0?void 0:c.instance),o("beforeUnmount",l,s,d,u)},unmounted:function(l,s,d,u){var c;(c=l.$pd[t])===null||c===void 0||(c=c.instance)===null||c===void 0||(c=c.scopedStyleEl)===null||c===void 0||(c=c.value)===null||c===void 0||c.remove(),o("unmounted",l,s,d,u)}}},extend:function(){var t=be._getMeta.apply(be,arguments),n=Jd(t,2),o=n[0],i=n[1];return Se({extend:function(){var a=be._getMeta.apply(be,arguments),l=Jd(a,2),s=l[0],d=l[1];return be.extend(s,Se(Se(Se({},i),i==null?void 0:i.methods),d))}},be._extend(o,i))}},Cy=` - .p-ink { - display: block; - position: absolute; - background: dt('ripple.background'); - border-radius: 100%; - transform: scale(0); - pointer-events: none; - } - - .p-ink-active { - animation: ripple 0.4s linear; - } - - @keyframes ripple { - 100% { - opacity: 0; - transform: scale(2.5); - } - } -`,ky={root:"p-ink"},Sy=fe.extend({name:"ripple-directive",style:Cy,classes:ky}),xy=be.extend({style:Sy});function wr(e){"@babel/helpers - typeof";return wr=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},wr(e)}function $y(e){return Ry(e)||Ty(e)||Iy(e)||Py()}function Py(){throw new TypeError(`Invalid attempt to spread non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function Iy(e,t){if(e){if(typeof e=="string")return ll(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?ll(e,t):void 0}}function Ty(e){if(typeof Symbol<"u"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function Ry(e){if(Array.isArray(e))return ll(e)}function ll(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);n1&&arguments[1]!==void 0?arguments[1]:function(){};Xy(this,e),this.element=t,this.listener=n}return ev(e,[{key:"bindScrollListener",value:function(){this.scrollableParents=n0(this.element);for(var n=0;ne.length)&&(t=e.length);for(var n=0,o=Array(t);n0&&arguments[0]!==void 0?arguments[0]:[],i=arguments.length>1&&arguments[1]!==void 0?arguments[1]:[],r=[];return i.forEach(function(a){a.children instanceof Array?r=r.concat(n._recursive(o,a.children)):a.type.name===n.type?r.push(a):me(a.key)&&(r=r.concat(o.filter(function(l){return n._isMatched(l,a.key)}).map(function(l){return l.vnode})))}),r}}])}();function An(e,t){if(e){var n=e.props;if(n){var o=t.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),i=Object.prototype.hasOwnProperty.call(n,o)?o:t;return e.type.extends.props[t].type===Boolean&&n[i]===""?!0:n[i]}}return null}var mp={name:"EyeIcon",extends:Te};function fv(e){return mv(e)||gv(e)||hv(e)||pv()}function pv(){throw new TypeError(`Invalid attempt to spread non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function hv(e,t){if(e){if(typeof e=="string")return dl(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?dl(e,t):void 0}}function gv(e){if(typeof Symbol<"u"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function mv(e){if(Array.isArray(e))return dl(e)}function dl(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);nn,r=n&&oe.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);n1){var s=this.isNumeralChar(r.charAt(n))?n+1:n+2;this.$refs.input.$el.setSelectionRange(s,s)}else this.isNumeralChar(r.charAt(n-1))||t.preventDefault();break;case"ArrowRight":if(i>1){var d=o-1;this.$refs.input.$el.setSelectionRange(d,d)}else this.isNumeralChar(r.charAt(n))||t.preventDefault();break;case"Tab":case"Enter":case"NumpadEnter":a=this.validateValue(this.parseValue(r)),this.$refs.input.$el.value=this.formatValue(a),this.$refs.input.$el.setAttribute("aria-valuenow",a),this.updateModel(t,a);break;case"Backspace":{if(t.preventDefault(),n===o){n>=r.length&&this.suffixChar!==null&&(n=r.length-this.suffixChar.length,this.$refs.input.$el.setSelectionRange(n,n));var u=r.charAt(n-1),c=this.getDecimalCharIndexes(r),f=c.decimalCharIndex,p=c.decimalCharIndexWithoutPrefix;if(this.isNumeralChar(u)){var v=this.getDecimalLength(r);if(this._group.test(u))this._group.lastIndex=0,a=r.slice(0,n-2)+r.slice(n-1);else if(this._decimal.test(u))this._decimal.lastIndex=0,v?this.$refs.input.$el.setSelectionRange(n-1,n-1):a=r.slice(0,n-1)+r.slice(n);else if(f>0&&n>f){var C=this.isDecimalMode()&&(this.minFractionDigits||0)0?a:""):a=r.slice(0,n-1)+r.slice(n)}this.updateValue(t,a,null,"delete-single")}else a=this.deleteRange(r,n,o),this.updateValue(t,a,null,"delete-range");break}case"Delete":if(t.preventDefault(),n===o){var S=r.charAt(n),x=this.getDecimalCharIndexes(r),P=x.decimalCharIndex,L=x.decimalCharIndexWithoutPrefix;if(this.isNumeralChar(S)){var k=this.getDecimalLength(r);if(this._group.test(S))this._group.lastIndex=0,a=r.slice(0,n)+r.slice(n+2);else if(this._decimal.test(S))this._decimal.lastIndex=0,k?this.$refs.input.$el.setSelectionRange(n+1,n+1):a=r.slice(0,n)+r.slice(n+1);else if(P>0&&n>P){var F=this.isDecimalMode()&&(this.minFractionDigits||0)0?a:""):a=r.slice(0,n)+r.slice(n+1)}this.updateValue(t,a,null,"delete-back-single")}else a=this.deleteRange(r,n,o),this.updateValue(t,a,null,"delete-range");break;case"Home":t.preventDefault(),me(this.min)&&this.updateModel(t,this.min);break;case"End":t.preventDefault(),me(this.max)&&this.updateModel(t,this.max);break}}},onInputKeyPress:function(t){if(!this.readonly){var n=t.key,o=this.isDecimalSign(n),i=this.isMinusSign(n);t.code!=="Enter"&&t.preventDefault(),(Number(n)>=0&&Number(n)<=9||i||o)&&this.insert(t,n,{isDecimalSign:o,isMinusSign:i})}},onPaste:function(t){if(!this.readonly){t.preventDefault();var n=(t.clipboardData||window.clipboardData).getData("Text");if(!(this.inputId==="integeronly"&&/[^\d-]/.test(n))&&n){var o=this.parseValue(n);o!=null&&this.insert(t,o.toString())}}},onClearClick:function(t){this.updateModel(t,null),this.$refs.input.$el.focus()},allowMinusSign:function(){return this.min===null||this.min<0},isMinusSign:function(t){return this._minusSign.test(t)||t==="-"?(this._minusSign.lastIndex=0,!0):!1},isDecimalSign:function(t){var n;return(n=this.locale)!==null&&n!==void 0&&n.includes("fr")&&[".",","].includes(t)||this._decimal.test(t)?(this._decimal.lastIndex=0,!0):!1},isDecimalMode:function(){return this.mode==="decimal"},getDecimalCharIndexes:function(t){var n=t.search(this._decimal);this._decimal.lastIndex=0;var o=t.replace(this._prefix,"").trim().replace(/\s/g,"").replace(this._currency,""),i=o.search(this._decimal);return this._decimal.lastIndex=0,{decimalCharIndex:n,decimalCharIndexWithoutPrefix:i}},getCharIndexes:function(t){var n=t.search(this._decimal);this._decimal.lastIndex=0;var o=t.search(this._minusSign);this._minusSign.lastIndex=0;var i=t.search(this._suffix);this._suffix.lastIndex=0;var r=t.search(this._currency);return this._currency.lastIndex=0,{decimalCharIndex:n,minusCharIndex:o,suffixCharIndex:i,currencyCharIndex:r}},insert:function(t,n){var o=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{isDecimalSign:!1,isMinusSign:!1},i=n.search(this._minusSign);if(this._minusSign.lastIndex=0,!(!this.allowMinusSign()&&i!==-1)){var r=this.$refs.input.$el.selectionStart,a=this.$refs.input.$el.selectionEnd,l=this.$refs.input.$el.value.trim(),s=this.getCharIndexes(l),d=s.decimalCharIndex,u=s.minusCharIndex,c=s.suffixCharIndex,f=s.currencyCharIndex,p;if(o.isMinusSign){var v=u===-1;(r===0||r===f+1)&&(p=l,(v||a!==0)&&(p=this.insertText(l,n,0,a)),this.updateValue(t,p,n,"insert"))}else if(o.isDecimalSign)d>0&&r===d?this.updateValue(t,l,n,"insert"):d>r&&d0&&r>d){if(r+n.length-(d+1)<=C){var x=f>=r?f-1:c>=r?c:l.length;p=l.slice(0,r)+n+l.slice(r+n.length,x)+l.slice(x),this.updateValue(t,p,n,S)}}else p=this.insertText(l,n,r,a),this.updateValue(t,p,n,S)}}},insertText:function(t,n,o,i){var r=n==="."?n:n.split(".");if(r.length===2){var a=t.slice(o,i).search(this._decimal);return this._decimal.lastIndex=0,a>0?t.slice(0,o)+this.formatValue(n)+t.slice(i):this.formatValue(n)||t}else return i-o===t.length?this.formatValue(n):o===0?n+t.slice(i):i===t.length?t.slice(0,o)+n:t.slice(0,o)+n+t.slice(i)},deleteRange:function(t,n,o){var i;return o-n===t.length?i="":n===0?i=t.slice(o):o===t.length?i=t.slice(0,n):i=t.slice(0,n)+t.slice(o),i},initCursor:function(){var t=this.$refs.input.$el.selectionStart,n=this.$refs.input.$el.value,o=n.length,i=null,r=(this.prefixChar||"").length;n=n.replace(this._prefix,""),t=t-r;var a=n.charAt(t);if(this.isNumeralChar(a))return t+r;for(var l=t-1;l>=0;)if(a=n.charAt(l),this.isNumeralChar(a)){i=l+r;break}else l--;if(i!==null)this.$refs.input.$el.setSelectionRange(i+1,i+1);else{for(l=t;lthis.max?this.max:t},updateInput:function(t,n,o,i){var r;n=n||"";var a=this.$refs.input.$el.value,l=this.formatValue(t),s=a.length;if(l!==i&&(l=this.concatValues(l,i)),s===0){this.$refs.input.$el.value=l,this.$refs.input.$el.setSelectionRange(0,0);var d=this.initCursor(),u=d+n.length;this.$refs.input.$el.setSelectionRange(u,u)}else{var c=this.$refs.input.$el.selectionStart,f=this.$refs.input.$el.selectionEnd;this.$refs.input.$el.value=l;var p=l.length;if(o==="range-insert"){var v=this.parseValue((a||"").slice(0,c)),C=v!==null?v.toString():"",S=C.split("").join("(".concat(this.groupChar,")?")),x=new RegExp(S,"g");x.test(l);var P=n.split("").join("(".concat(this.groupChar,")?")),L=new RegExp(P,"g");L.test(l.slice(x.lastIndex)),f=x.lastIndex+L.lastIndex,this.$refs.input.$el.setSelectionRange(f,f)}else if(p===s)o==="insert"||o==="delete-back-single"?this.$refs.input.$el.setSelectionRange(f+1,f+1):o==="delete-single"?this.$refs.input.$el.setSelectionRange(f-1,f-1):(o==="delete-range"||o==="spin")&&this.$refs.input.$el.setSelectionRange(f,f);else if(o==="delete-back-single"){var k=a.charAt(f-1),F=a.charAt(f),K=s-p,z=this._group.test(F);z&&K===1?f+=1:!z&&this.isNumeralChar(k)&&(f+=-1*K+1),this._group.lastIndex=0,this.$refs.input.$el.setSelectionRange(f,f)}else if(a==="-"&&o==="insert"){this.$refs.input.$el.setSelectionRange(0,0);var q=this.initCursor(),H=q+n.length+1;this.$refs.input.$el.setSelectionRange(H,H)}else f=f+(p-s),this.$refs.input.$el.setSelectionRange(f,f)}this.$refs.input.$el.setAttribute("aria-valuenow",t),(r=this.$refs.clearIcon)!==null&&r!==void 0&&(r=r.$el)!==null&&r!==void 0&&r.style&&(this.$refs.clearIcon.$el.style.display=gt(l)?"none":"block")},concatValues:function(t,n){if(t&&n){var o=n.search(this._decimal);return this._decimal.lastIndex=0,this.suffixChar?o!==-1?t.replace(this.suffixChar,"").split(this._decimal)[0]+n.replace(this.suffixChar,"").slice(o)+this.suffixChar:t:o!==-1?t.split(this._decimal)[0]+n.slice(o):t}return t},getDecimalLength:function(t){if(t){var n=t.split(this._decimal);if(n.length===2)return n[1].replace(this._suffix,"").trim().replace(/\s/g,"").replace(this._currency,"").length}return 0},updateModel:function(t,n){this.writeValue(n,t)},onInputFocus:function(t){this.focused=!0,!this.disabled&&!this.readonly&&this.$refs.input.$el.value!==Td()&&this.highlightOnFocus&&t.target.select(),this.$emit("focus",t)},onInputBlur:function(t){var n,o;this.focused=!1;var i=t.target,r=this.validateValue(this.parseValue(i.value));this.$emit("blur",{originalEvent:t,value:i.value}),(n=(o=this.formField).onBlur)===null||n===void 0||n.call(o,t),i.value=this.formatValue(r),i.setAttribute("aria-valuenow",r),this.updateModel(t,r),!this.disabled&&!this.readonly&&this.highlightOnFocus&&Ii()},clearTimer:function(){this.timer&&clearTimeout(this.timer)},maxBoundry:function(){return this.d_value>=this.max},minBoundry:function(){return this.d_value<=this.min}},computed:{upButtonListeners:function(){var t=this;return{mousedown:function(o){return t.onUpButtonMouseDown(o)},mouseup:function(o){return t.onUpButtonMouseUp(o)},mouseleave:function(o){return t.onUpButtonMouseLeave(o)},keydown:function(o){return t.onUpButtonKeyDown(o)},keyup:function(o){return t.onUpButtonKeyUp(o)}}},downButtonListeners:function(){var t=this;return{mousedown:function(o){return t.onDownButtonMouseDown(o)},mouseup:function(o){return t.onDownButtonMouseUp(o)},mouseleave:function(o){return t.onDownButtonMouseLeave(o)},keydown:function(o){return t.onDownButtonKeyDown(o)},keyup:function(o){return t.onDownButtonKeyUp(o)}}},formattedValue:function(){var t=!this.d_value&&!this.allowEmpty?0:this.d_value;return this.formatValue(t)},getFormatter:function(){return this.numberFormat},dataP:function(){return Me(hl(hl({invalid:this.$invalid,fluid:this.$fluid,filled:this.$variant==="filled"},this.size,this.size),this.buttonLayout,this.showButtons&&this.buttonLayout))}},components:{InputText:eo,AngleUpIcon:Cp,AngleDownIcon:wp,TimesIcon:to}},S1=["data-p"],x1=["data-p"],$1=["disabled","data-p"],P1=["disabled","data-p"],I1=["disabled","data-p"],T1=["disabled","data-p"];function R1(e,t,n,o,i,r){var a=R("InputText"),l=R("TimesIcon");return g(),b("span",m({class:e.cx("root")},e.ptmi("root"),{"data-p":r.dataP}),[D(a,{ref:"input",id:e.inputId,name:e.$formName,role:"spinbutton",class:J([e.cx("pcInputText"),e.inputClass]),style:$o(e.inputStyle),defaultValue:r.formattedValue,"aria-valuemin":e.min,"aria-valuemax":e.max,"aria-valuenow":e.d_value,inputmode:e.mode==="decimal"&&!e.minFractionDigits?"numeric":"decimal",disabled:e.disabled,readonly:e.readonly,placeholder:e.placeholder,"aria-labelledby":e.ariaLabelledby,"aria-label":e.ariaLabel,required:e.required,size:e.size,invalid:e.invalid,variant:e.variant,onInput:r.onUserInput,onKeydown:r.onInputKeyDown,onKeypress:r.onInputKeyPress,onPaste:r.onPaste,onClick:r.onInputClick,onFocus:r.onInputFocus,onBlur:r.onInputBlur,pt:e.ptm("pcInputText"),unstyled:e.unstyled,"data-p":r.dataP},null,8,["id","name","class","style","defaultValue","aria-valuemin","aria-valuemax","aria-valuenow","inputmode","disabled","readonly","placeholder","aria-labelledby","aria-label","required","size","invalid","variant","onInput","onKeydown","onKeypress","onPaste","onClick","onFocus","onBlur","pt","unstyled","data-p"]),e.showClear&&e.buttonLayout!=="vertical"?N(e.$slots,"clearicon",{key:0,class:J(e.cx("clearIcon")),clearCallback:r.onClearClick},function(){return[D(l,m({ref:"clearIcon",class:[e.cx("clearIcon")],onClick:r.onClearClick},e.ptm("clearIcon")),null,16,["class","onClick"])]}):I("",!0),e.showButtons&&e.buttonLayout==="stacked"?(g(),b("span",m({key:1,class:e.cx("buttonGroup")},e.ptm("buttonGroup"),{"data-p":r.dataP}),[N(e.$slots,"incrementbutton",{listeners:r.upButtonListeners},function(){return[h("button",m({class:[e.cx("incrementButton"),e.incrementButtonClass]},fi(r.upButtonListeners),{disabled:e.disabled,tabindex:-1,"aria-hidden":"true",type:"button"},e.ptm("incrementButton"),{"data-p":r.dataP}),[N(e.$slots,e.$slots.incrementicon?"incrementicon":"incrementbuttonicon",{},function(){return[(g(),T(ae(e.incrementIcon||e.incrementButtonIcon?"span":"AngleUpIcon"),m({class:[e.incrementIcon,e.incrementButtonIcon]},e.ptm("incrementIcon"),{"data-pc-section":"incrementicon"}),null,16,["class"]))]})],16,$1)]}),N(e.$slots,"decrementbutton",{listeners:r.downButtonListeners},function(){return[h("button",m({class:[e.cx("decrementButton"),e.decrementButtonClass]},fi(r.downButtonListeners),{disabled:e.disabled,tabindex:-1,"aria-hidden":"true",type:"button"},e.ptm("decrementButton"),{"data-p":r.dataP}),[N(e.$slots,e.$slots.decrementicon?"decrementicon":"decrementbuttonicon",{},function(){return[(g(),T(ae(e.decrementIcon||e.decrementButtonIcon?"span":"AngleDownIcon"),m({class:[e.decrementIcon,e.decrementButtonIcon]},e.ptm("decrementIcon"),{"data-pc-section":"decrementicon"}),null,16,["class"]))]})],16,P1)]})],16,x1)):I("",!0),N(e.$slots,"incrementbutton",{listeners:r.upButtonListeners},function(){return[e.showButtons&&e.buttonLayout!=="stacked"?(g(),b("button",m({key:0,class:[e.cx("incrementButton"),e.incrementButtonClass]},fi(r.upButtonListeners),{disabled:e.disabled,tabindex:-1,"aria-hidden":"true",type:"button"},e.ptm("incrementButton"),{"data-p":r.dataP}),[N(e.$slots,e.$slots.incrementicon?"incrementicon":"incrementbuttonicon",{},function(){return[(g(),T(ae(e.incrementIcon||e.incrementButtonIcon?"span":"AngleUpIcon"),m({class:[e.incrementIcon,e.incrementButtonIcon]},e.ptm("incrementIcon"),{"data-pc-section":"incrementicon"}),null,16,["class"]))]})],16,I1)):I("",!0)]}),N(e.$slots,"decrementbutton",{listeners:r.downButtonListeners},function(){return[e.showButtons&&e.buttonLayout!=="stacked"?(g(),b("button",m({key:0,class:[e.cx("decrementButton"),e.decrementButtonClass]},fi(r.downButtonListeners),{disabled:e.disabled,tabindex:-1,"aria-hidden":"true",type:"button"},e.ptm("decrementButton"),{"data-p":r.dataP}),[N(e.$slots,e.$slots.decrementicon?"decrementicon":"decrementbuttonicon",{},function(){return[(g(),T(ae(e.decrementIcon||e.decrementButtonIcon?"span":"AngleDownIcon"),m({class:[e.decrementIcon,e.decrementButtonIcon]},e.ptm("decrementIcon"),{"data-pc-section":"decrementicon"}),null,16,["class"]))]})],16,T1)):I("",!0)]})],16,S1)}kp.render=R1;var Ge={STARTS_WITH:"startsWith",CONTAINS:"contains",NOT_CONTAINS:"notContains",ENDS_WITH:"endsWith",EQUALS:"equals",NOT_EQUALS:"notEquals",LESS_THAN:"lt",LESS_THAN_OR_EQUAL_TO:"lte",GREATER_THAN:"gt",GREATER_THAN_OR_EQUAL_TO:"gte",DATE_IS:"dateIs",DATE_IS_NOT:"dateIsNot",DATE_BEFORE:"dateBefore",DATE_AFTER:"dateAfter"},Vi={AND:"and",OR:"or"};function su(e,t){var n=typeof Symbol<"u"&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=O1(e))||t){n&&(e=n);var o=0,i=function(){};return{s:i,n:function(){return o>=e.length?{done:!0}:{done:!1,value:e[o++]}},e:function(d){throw d},f:i}}throw new TypeError(`Invalid attempt to iterate non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var r,a=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var d=n.next();return a=d.done,d},e:function(d){l=!0,r=d},f:function(){try{a||n.return==null||n.return()}finally{if(l)throw r}}}}function O1(e,t){if(e){if(typeof e=="string")return du(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?du(e,t):void 0}}function du(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);nn.getTime():t>n},gte:function(t,n){return n==null?!0:t==null?!1:t.getTime&&n.getTime?t.getTime()>=n.getTime():t>=n},dateIs:function(t,n){return n==null?!0:t==null?!1:t.toDateString()===n.toDateString()},dateIsNot:function(t,n){return n==null?!0:t==null?!1:t.toDateString()!==n.toDateString()},dateBefore:function(t,n){return n==null?!0:t==null?!1:t.getTime()n.getTime()}},register:function(t,n){this.filters[t]=n}},Sp={name:"BlankIcon",extends:Te};function E1(e){return D1(e)||_1(e)||L1(e)||A1()}function A1(){throw new TypeError(`Invalid attempt to spread non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function L1(e,t){if(e){if(typeof e=="string")return bl(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?bl(e,t):void 0}}function _1(e){if(typeof Symbol<"u"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function D1(e){if(Array.isArray(e))return bl(e)}function bl(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);n .p-virtualscroller-content { - display: flex; -} - -.p-virtualscroller-inline .p-virtualscroller-content { - position: static; -} - -.p-virtualscroller .p-virtualscroller-loading { - transform: none !important; - min-height: 0; - position: sticky; - inset-block-start: 0; - inset-inline-start: 0; -} -`,uu=fe.extend({name:"virtualscroller",css:cw,style:uw}),fw={name:"BaseVirtualScroller",extends:ye,props:{id:{type:String,default:null},style:null,class:null,items:{type:Array,default:null},itemSize:{type:[Number,Array],default:0},scrollHeight:null,scrollWidth:null,orientation:{type:String,default:"vertical"},numToleratedItems:{type:Number,default:null},delay:{type:Number,default:0},resizeDelay:{type:Number,default:10},lazy:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1},loaderDisabled:{type:Boolean,default:!1},columns:{type:Array,default:null},loading:{type:Boolean,default:!1},showSpacer:{type:Boolean,default:!0},showLoader:{type:Boolean,default:!1},tabindex:{type:Number,default:0},inline:{type:Boolean,default:!1},step:{type:Number,default:0},appendOnly:{type:Boolean,default:!1},autoSize:{type:Boolean,default:!1}},style:uu,provide:function(){return{$pcVirtualScroller:this,$parentInstance:this}},beforeMount:function(){var t;uu.loadCSS({nonce:(t=this.$primevueConfig)===null||t===void 0||(t=t.csp)===null||t===void 0?void 0:t.nonce})}};function Or(e){"@babel/helpers - typeof";return Or=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Or(e)}function cu(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),n.push.apply(n,o)}return n}function Bo(e){for(var t=1;t1&&arguments[1]!==void 0?arguments[1]:"auto",i=this.isBoth(),r=this.isHorizontal(),a=i?t.every(function(z){return z>-1}):t>-1;if(a){var l=this.first,s=this.element,d=s.scrollTop,u=d===void 0?0:d,c=s.scrollLeft,f=c===void 0?0:c,p=this.calculateNumItems(),v=p.numToleratedItems,C=this.getContentPosition(),S=this.itemSize,x=function(){var q=arguments.length>0&&arguments[0]!==void 0?arguments[0]:0,H=arguments.length>1?arguments[1]:void 0;return q<=H?0:q},P=function(q,H,ee){return q*H+ee},L=function(){var q=arguments.length>0&&arguments[0]!==void 0?arguments[0]:0,H=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0;return n.scrollTo({left:q,top:H,behavior:o})},k=i?{rows:0,cols:0}:0,F=!1,K=!1;i?(k={rows:x(t[0],v[0]),cols:x(t[1],v[1])},L(P(k.cols,S[1],C.left),P(k.rows,S[0],C.top)),K=this.lastScrollPos.top!==u||this.lastScrollPos.left!==f,F=k.rows!==l.rows||k.cols!==l.cols):(k=x(t,v),r?L(P(k,S,C.left),u):L(f,P(k,S,C.top)),K=this.lastScrollPos!==(r?f:u),F=k!==l),this.isRangeChanged=F,K&&(this.first=k)}},scrollInView:function(t,n){var o=this,i=arguments.length>2&&arguments[2]!==void 0?arguments[2]:"auto";if(n){var r=this.isBoth(),a=this.isHorizontal(),l=r?t.every(function(S){return S>-1}):t>-1;if(l){var s=this.getRenderedRange(),d=s.first,u=s.viewport,c=function(){var x=arguments.length>0&&arguments[0]!==void 0?arguments[0]:0,P=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0;return o.scrollTo({left:x,top:P,behavior:i})},f=n==="to-start",p=n==="to-end";if(f){if(r)u.first.rows-d.rows>t[0]?c(u.first.cols*this.itemSize[1],(u.first.rows-1)*this.itemSize[0]):u.first.cols-d.cols>t[1]&&c((u.first.cols-1)*this.itemSize[1],u.first.rows*this.itemSize[0]);else if(u.first-d>t){var v=(u.first-1)*this.itemSize;a?c(v,0):c(0,v)}}else if(p){if(r)u.last.rows-d.rows<=t[0]+1?c(u.first.cols*this.itemSize[1],(u.first.rows+1)*this.itemSize[0]):u.last.cols-d.cols<=t[1]+1&&c((u.first.cols+1)*this.itemSize[1],u.first.rows*this.itemSize[0]);else if(u.last-d<=t+1){var C=(u.first+1)*this.itemSize;a?c(C,0):c(0,C)}}}}else this.scrollToIndex(t,i)},getRenderedRange:function(){var t=function(c,f){return Math.floor(c/(f||c))},n=this.first,o=0;if(this.element){var i=this.isBoth(),r=this.isHorizontal(),a=this.element,l=a.scrollTop,s=a.scrollLeft;if(i)n={rows:t(l,this.itemSize[0]),cols:t(s,this.itemSize[1])},o={rows:n.rows+this.numItemsInViewport.rows,cols:n.cols+this.numItemsInViewport.cols};else{var d=r?s:l;n=t(d,this.itemSize),o=n+this.numItemsInViewport}}return{first:this.first,last:this.last,viewport:{first:n,last:o}}},calculateNumItems:function(){var t=this.isBoth(),n=this.isHorizontal(),o=this.itemSize,i=this.getContentPosition(),r=this.element?this.element.offsetWidth-i.left:0,a=this.element?this.element.offsetHeight-i.top:0,l=function(f,p){return Math.ceil(f/(p||f))},s=function(f){return Math.ceil(f/2)},d=t?{rows:l(a,o[0]),cols:l(r,o[1])}:l(n?r:a,o),u=this.d_numToleratedItems||(t?[s(d.rows),s(d.cols)]:s(d));return{numItemsInViewport:d,numToleratedItems:u}},calculateOptions:function(){var t=this,n=this.isBoth(),o=this.first,i=this.calculateNumItems(),r=i.numItemsInViewport,a=i.numToleratedItems,l=function(u,c,f){var p=arguments.length>3&&arguments[3]!==void 0?arguments[3]:!1;return t.getLast(u+c+(u0&&arguments[0]!==void 0?arguments[0]:0,i=arguments.length>1?arguments[1]:void 0;return this.items?Math.min(i?((t=this.columns||this.items[0])===null||t===void 0?void 0:t.length)||0:((n=this.items)===null||n===void 0?void 0:n.length)||0,o):0},getContentPosition:function(){if(this.content){var t=getComputedStyle(this.content),n=parseFloat(t.paddingLeft)+Math.max(parseFloat(t.left)||0,0),o=parseFloat(t.paddingRight)+Math.max(parseFloat(t.right)||0,0),i=parseFloat(t.paddingTop)+Math.max(parseFloat(t.top)||0,0),r=parseFloat(t.paddingBottom)+Math.max(parseFloat(t.bottom)||0,0);return{left:n,right:o,top:i,bottom:r,x:n+o,y:i+r}}return{left:0,right:0,top:0,bottom:0,x:0,y:0}},setSize:function(){var t=this;if(this.element){var n=this.isBoth(),o=this.isHorizontal(),i=this.element.parentElement,r=this.scrollWidth||"".concat(this.element.offsetWidth||i.offsetWidth,"px"),a=this.scrollHeight||"".concat(this.element.offsetHeight||i.offsetHeight,"px"),l=function(d,u){return t.element.style[d]=u};n||o?(l("height",a),l("width",r)):l("height",a)}},setSpacerSize:function(){var t=this,n=this.items;if(n){var o=this.isBoth(),i=this.isHorizontal(),r=this.getContentPosition(),a=function(s,d,u){var c=arguments.length>3&&arguments[3]!==void 0?arguments[3]:0;return t.spacerStyle=Bo(Bo({},t.spacerStyle),Ip({},"".concat(s),(d||[]).length*u+c+"px"))};o?(a("height",n,this.itemSize[0],r.y),a("width",this.columns||n[1],this.itemSize[1],r.x)):i?a("width",this.columns||n,this.itemSize,r.x):a("height",n,this.itemSize,r.y)}},setContentPosition:function(t){var n=this;if(this.content&&!this.appendOnly){var o=this.isBoth(),i=this.isHorizontal(),r=t?t.first:this.first,a=function(u,c){return u*c},l=function(){var u=arguments.length>0&&arguments[0]!==void 0?arguments[0]:0,c=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0;return n.contentStyle=Bo(Bo({},n.contentStyle),{transform:"translate3d(".concat(u,"px, ").concat(c,"px, 0)")})};if(o)l(a(r.cols,this.itemSize[1]),a(r.rows,this.itemSize[0]));else{var s=a(r,this.itemSize);i?l(s,0):l(0,s)}}},onScrollPositionChange:function(t){var n=this,o=t.target,i=this.isBoth(),r=this.isHorizontal(),a=this.getContentPosition(),l=function(X,j){return X?X>j?X-j:X:0},s=function(X,j){return Math.floor(X/(j||X))},d=function(X,j,le,pe,ue,se){return X<=ue?ue:se?le-pe-ue:j+ue-1},u=function(X,j,le,pe,ue,se,ne,ge){if(X<=se)return 0;var De=Math.max(0,ne?Xj?le:X-2*se),Ve=n.getLast(De,ge);return De>Ve?Ve-ue:De},c=function(X,j,le,pe,ue,se){var ne=j+pe+2*ue;return X>=ue&&(ne+=ue+1),n.getLast(ne,se)},f=l(o.scrollTop,a.top),p=l(o.scrollLeft,a.left),v=i?{rows:0,cols:0}:0,C=this.last,S=!1,x=this.lastScrollPos;if(i){var P=this.lastScrollPos.top<=f,L=this.lastScrollPos.left<=p;if(!this.appendOnly||this.appendOnly&&(P||L)){var k={rows:s(f,this.itemSize[0]),cols:s(p,this.itemSize[1])},F={rows:d(k.rows,this.first.rows,this.last.rows,this.numItemsInViewport.rows,this.d_numToleratedItems[0],P),cols:d(k.cols,this.first.cols,this.last.cols,this.numItemsInViewport.cols,this.d_numToleratedItems[1],L)};v={rows:u(k.rows,F.rows,this.first.rows,this.last.rows,this.numItemsInViewport.rows,this.d_numToleratedItems[0],P),cols:u(k.cols,F.cols,this.first.cols,this.last.cols,this.numItemsInViewport.cols,this.d_numToleratedItems[1],L,!0)},C={rows:c(k.rows,v.rows,this.last.rows,this.numItemsInViewport.rows,this.d_numToleratedItems[0]),cols:c(k.cols,v.cols,this.last.cols,this.numItemsInViewport.cols,this.d_numToleratedItems[1],!0)},S=v.rows!==this.first.rows||C.rows!==this.last.rows||v.cols!==this.first.cols||C.cols!==this.last.cols||this.isRangeChanged,x={top:f,left:p}}}else{var K=r?p:f,z=this.lastScrollPos<=K;if(!this.appendOnly||this.appendOnly&&z){var q=s(K,this.itemSize),H=d(q,this.first,this.last,this.numItemsInViewport,this.d_numToleratedItems,z);v=u(q,H,this.first,this.last,this.numItemsInViewport,this.d_numToleratedItems,z),C=c(q,v,this.last,this.numItemsInViewport,this.d_numToleratedItems),S=v!==this.first||C!==this.last||this.isRangeChanged,x=K}}return{first:v,last:C,isRangeChanged:S,scrollPos:x}},onScrollChange:function(t){var n=this.onScrollPositionChange(t),o=n.first,i=n.last,r=n.isRangeChanged,a=n.scrollPos;if(r){var l={first:o,last:i};if(this.setContentPosition(l),this.first=o,this.last=i,this.lastScrollPos=a,this.$emit("scroll-index-change",l),this.lazy&&this.isPageChanged(o)){var s,d,u={first:this.step?Math.min(this.getPageByFirst(o)*this.step,(((s=this.items)===null||s===void 0?void 0:s.length)||0)-this.step):o,last:Math.min(this.step?(this.getPageByFirst(o)+1)*this.step:i,((d=this.items)===null||d===void 0?void 0:d.length)||0)},c=this.lazyLoadState.first!==u.first||this.lazyLoadState.last!==u.last;c&&this.$emit("lazy-load",u),this.lazyLoadState=u}}},onScroll:function(t){var n=this;if(this.$emit("scroll",t),this.delay){if(this.scrollTimeout&&clearTimeout(this.scrollTimeout),this.isPageChanged()){if(!this.d_loading&&this.showLoader){var o=this.onScrollPositionChange(t),i=o.isRangeChanged,r=i||(this.step?this.isPageChanged():!1);r&&(this.d_loading=!0)}this.scrollTimeout=setTimeout(function(){n.onScrollChange(t),n.d_loading&&n.showLoader&&(!n.lazy||n.loading===void 0)&&(n.d_loading=!1,n.page=n.getPageByFirst())},this.delay)}}else this.onScrollChange(t)},onResize:function(){var t=this;this.resizeTimeout&&clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(function(){if(ji(t.element)){var n=t.isBoth(),o=t.isVertical(),i=t.isHorizontal(),r=[Un(t.element),Vn(t.element)],a=r[0],l=r[1],s=a!==t.defaultWidth,d=l!==t.defaultHeight,u=n?s||d:i?s:o?d:!1;u&&(t.d_numToleratedItems=t.numToleratedItems,t.defaultWidth=a,t.defaultHeight=l,t.defaultContentWidth=Un(t.content),t.defaultContentHeight=Vn(t.content),t.init())}},this.resizeDelay)},bindResizeListener:function(){var t=this;this.resizeListener||(this.resizeListener=this.onResize.bind(this),window.addEventListener("resize",this.resizeListener),window.addEventListener("orientationchange",this.resizeListener),this.resizeObserver=new ResizeObserver(function(){t.onResize()}),this.resizeObserver.observe(this.element))},unbindResizeListener:function(){this.resizeListener&&(window.removeEventListener("resize",this.resizeListener),window.removeEventListener("orientationchange",this.resizeListener),this.resizeListener=null),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null)},getOptions:function(t){var n=(this.items||[]).length,o=this.isBoth()?this.first.rows+t:this.first+t;return{index:o,count:n,first:o===0,last:o===n-1,even:o%2===0,odd:o%2!==0}},getLoaderOptions:function(t,n){var o=this.loaderArr.length;return Bo({index:t,count:o,first:t===0,last:t===o-1,even:t%2===0,odd:t%2!==0},n)},getPageByFirst:function(t){return Math.floor(((t??this.first)+this.d_numToleratedItems*4)/(this.step||1))},isPageChanged:function(t){return this.step&&!this.lazy?this.page!==this.getPageByFirst(t??this.first):!0},setContentEl:function(t){this.content=t||this.content||In(this.element,'[data-pc-section="content"]')},elementRef:function(t){this.element=t},contentRef:function(t){this.content=t}},computed:{containerClass:function(){return["p-virtualscroller",this.class,{"p-virtualscroller-inline":this.inline,"p-virtualscroller-both p-both-scroll":this.isBoth(),"p-virtualscroller-horizontal p-horizontal-scroll":this.isHorizontal()}]},contentClass:function(){return["p-virtualscroller-content",{"p-virtualscroller-loading":this.d_loading}]},loaderClass:function(){return["p-virtualscroller-loader",{"p-virtualscroller-loader-mask":!this.$slots.loader}]},loadedItems:function(){var t=this;return this.items&&!this.d_loading?this.isBoth()?this.items.slice(this.appendOnly?0:this.first.rows,this.last.rows).map(function(n){return t.columns?n:n.slice(t.appendOnly?0:t.first.cols,t.last.cols)}):this.isHorizontal()&&this.columns?this.items:this.items.slice(this.appendOnly?0:this.first,this.last):[]},loadedRows:function(){return this.d_loading?this.loaderDisabled?this.loaderArr:[]:this.loadedItems},loadedColumns:function(){if(this.columns){var t=this.isBoth(),n=this.isHorizontal();if(t||n)return this.d_loading&&this.loaderDisabled?t?this.loaderArr[0]:this.loaderArr:this.columns.slice(t?this.first.cols:this.first,t?this.last.cols:this.last)}return this.columns}},components:{SpinnerIcon:ni}},gw=["tabindex"];function mw(e,t,n,o,i,r){var a=R("SpinnerIcon");return e.disabled?(g(),b(te,{key:1},[N(e.$slots,"default"),N(e.$slots,"content",{items:e.items,rows:e.items,columns:r.loadedColumns})],64)):(g(),b("div",m({key:0,ref:r.elementRef,class:r.containerClass,tabindex:e.tabindex,style:e.style,onScroll:t[0]||(t[0]=function(){return r.onScroll&&r.onScroll.apply(r,arguments)})},e.ptmi("root")),[N(e.$slots,"content",{styleClass:r.contentClass,items:r.loadedItems,getItemOptions:r.getOptions,loading:i.d_loading,getLoaderOptions:r.getLoaderOptions,itemSize:e.itemSize,rows:r.loadedRows,columns:r.loadedColumns,contentRef:r.contentRef,spacerStyle:i.spacerStyle,contentStyle:i.contentStyle,vertical:r.isVertical(),horizontal:r.isHorizontal(),both:r.isBoth()},function(){return[h("div",m({ref:r.contentRef,class:r.contentClass,style:i.contentStyle},e.ptm("content")),[(g(!0),b(te,null,Fe(r.loadedItems,function(l,s){return N(e.$slots,"item",{key:s,item:l,options:r.getOptions(s)})}),128))],16)]}),e.showSpacer?(g(),b("div",m({key:0,class:"p-virtualscroller-spacer",style:i.spacerStyle},e.ptm("spacer")),null,16)):I("",!0),!e.loaderDisabled&&e.showLoader&&i.d_loading?(g(),b("div",m({key:1,class:r.loaderClass},e.ptm("loader")),[e.$slots&&e.$slots.loader?(g(!0),b(te,{key:0},Fe(i.loaderArr,function(l,s){return N(e.$slots,"loader",{key:s,options:r.getLoaderOptions(s,r.isBoth()&&{numCols:e.d_numItemsInViewport.cols})})}),128)):I("",!0),N(e.$slots,"loadingicon",{},function(){return[D(a,m({spin:"",class:"p-virtualscroller-loading-icon"},e.ptm("loadingIcon")),null,16)]})],16)):I("",!0)],16,gw))}Os.render=mw;var bw=` - .p-select { - display: inline-flex; - cursor: pointer; - position: relative; - user-select: none; - background: dt('select.background'); - border: 1px solid dt('select.border.color'); - transition: - background dt('select.transition.duration'), - color dt('select.transition.duration'), - border-color dt('select.transition.duration'), - outline-color dt('select.transition.duration'), - box-shadow dt('select.transition.duration'); - border-radius: dt('select.border.radius'); - outline-color: transparent; - box-shadow: dt('select.shadow'); - } - - .p-select:not(.p-disabled):hover { - border-color: dt('select.hover.border.color'); - } - - .p-select:not(.p-disabled).p-focus { - border-color: dt('select.focus.border.color'); - box-shadow: dt('select.focus.ring.shadow'); - outline: dt('select.focus.ring.width') dt('select.focus.ring.style') dt('select.focus.ring.color'); - outline-offset: dt('select.focus.ring.offset'); - } - - .p-select.p-variant-filled { - background: dt('select.filled.background'); - } - - .p-select.p-variant-filled:not(.p-disabled):hover { - background: dt('select.filled.hover.background'); - } - - .p-select.p-variant-filled:not(.p-disabled).p-focus { - background: dt('select.filled.focus.background'); - } - - .p-select.p-invalid { - border-color: dt('select.invalid.border.color'); - } - - .p-select.p-disabled { - opacity: 1; - background: dt('select.disabled.background'); - } - - .p-select-clear-icon { - align-self: center; - color: dt('select.clear.icon.color'); - inset-inline-end: dt('select.dropdown.width'); - } - - .p-select-dropdown { - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; - background: transparent; - color: dt('select.dropdown.color'); - width: dt('select.dropdown.width'); - border-start-end-radius: dt('select.border.radius'); - border-end-end-radius: dt('select.border.radius'); - } - - .p-select-label { - display: block; - white-space: nowrap; - overflow: hidden; - flex: 1 1 auto; - width: 1%; - padding: dt('select.padding.y') dt('select.padding.x'); - text-overflow: ellipsis; - cursor: pointer; - color: dt('select.color'); - background: transparent; - border: 0 none; - outline: 0 none; - font-size: 1rem; - } - - .p-select-label.p-placeholder { - color: dt('select.placeholder.color'); - } - - .p-select.p-invalid .p-select-label.p-placeholder { - color: dt('select.invalid.placeholder.color'); - } - - .p-select.p-disabled .p-select-label { - color: dt('select.disabled.color'); - } - - .p-select-label-empty { - overflow: hidden; - opacity: 0; - } - - input.p-select-label { - cursor: default; - } - - .p-select-overlay { - position: absolute; - top: 0; - left: 0; - background: dt('select.overlay.background'); - color: dt('select.overlay.color'); - border: 1px solid dt('select.overlay.border.color'); - border-radius: dt('select.overlay.border.radius'); - box-shadow: dt('select.overlay.shadow'); - min-width: 100%; - transform-origin: inherit; - will-change: transform; - } - - .p-select-header { - padding: dt('select.list.header.padding'); - } - - .p-select-filter { - width: 100%; - } - - .p-select-list-container { - overflow: auto; - } - - .p-select-option-group { - cursor: auto; - margin: 0; - padding: dt('select.option.group.padding'); - background: dt('select.option.group.background'); - color: dt('select.option.group.color'); - font-weight: dt('select.option.group.font.weight'); - } - - .p-select-list { - margin: 0; - padding: 0; - list-style-type: none; - padding: dt('select.list.padding'); - gap: dt('select.list.gap'); - display: flex; - flex-direction: column; - } - - .p-select-option { - cursor: pointer; - font-weight: normal; - white-space: nowrap; - position: relative; - overflow: hidden; - display: flex; - align-items: center; - padding: dt('select.option.padding'); - border: 0 none; - color: dt('select.option.color'); - background: transparent; - transition: - background dt('select.transition.duration'), - color dt('select.transition.duration'), - border-color dt('select.transition.duration'), - box-shadow dt('select.transition.duration'), - outline-color dt('select.transition.duration'); - border-radius: dt('select.option.border.radius'); - } - - .p-select-option:not(.p-select-option-selected):not(.p-disabled).p-focus { - background: dt('select.option.focus.background'); - color: dt('select.option.focus.color'); - } - - .p-select-option:not(.p-select-option-selected):not(.p-disabled):hover { - background: dt('select.option.focus.background'); - color: dt('select.option.focus.color'); - } - - .p-select-option.p-select-option-selected { - background: dt('select.option.selected.background'); - color: dt('select.option.selected.color'); - } - - .p-select-option.p-select-option-selected.p-focus { - background: dt('select.option.selected.focus.background'); - color: dt('select.option.selected.focus.color'); - } - - .p-select-option-blank-icon { - flex-shrink: 0; - } - - .p-select-option-check-icon { - position: relative; - flex-shrink: 0; - margin-inline-start: dt('select.checkmark.gutter.start'); - margin-inline-end: dt('select.checkmark.gutter.end'); - color: dt('select.checkmark.color'); - } - - .p-select-empty-message { - padding: dt('select.empty.message.padding'); - } - - .p-select-fluid { - display: flex; - width: 100%; - } - - .p-select-sm .p-select-label { - font-size: dt('select.sm.font.size'); - padding-block: dt('select.sm.padding.y'); - padding-inline: dt('select.sm.padding.x'); - } - - .p-select-sm .p-select-dropdown .p-icon { - font-size: dt('select.sm.font.size'); - width: dt('select.sm.font.size'); - height: dt('select.sm.font.size'); - } - - .p-select-lg .p-select-label { - font-size: dt('select.lg.font.size'); - padding-block: dt('select.lg.padding.y'); - padding-inline: dt('select.lg.padding.x'); - } - - .p-select-lg .p-select-dropdown .p-icon { - font-size: dt('select.lg.font.size'); - width: dt('select.lg.font.size'); - height: dt('select.lg.font.size'); - } - - .p-floatlabel-in .p-select-filter { - padding-block-start: dt('select.padding.y'); - padding-block-end: dt('select.padding.y'); - } -`,yw={root:function(t){var n=t.instance,o=t.props,i=t.state;return["p-select p-component p-inputwrapper",{"p-disabled":o.disabled,"p-invalid":n.$invalid,"p-variant-filled":n.$variant==="filled","p-focus":i.focused,"p-inputwrapper-filled":n.$filled,"p-inputwrapper-focus":i.focused||i.overlayVisible,"p-select-open":i.overlayVisible,"p-select-fluid":n.$fluid,"p-select-sm p-inputfield-sm":o.size==="small","p-select-lg p-inputfield-lg":o.size==="large"}]},label:function(t){var n,o=t.instance,i=t.props;return["p-select-label",{"p-placeholder":!i.editable&&o.label===i.placeholder,"p-select-label-empty":!i.editable&&!o.$slots.value&&(o.label==="p-emptylabel"||((n=o.label)===null||n===void 0?void 0:n.length)===0)}]},clearIcon:"p-select-clear-icon",dropdown:"p-select-dropdown",loadingicon:"p-select-loading-icon",dropdownIcon:"p-select-dropdown-icon",overlay:"p-select-overlay p-component",header:"p-select-header",pcFilter:"p-select-filter",listContainer:"p-select-list-container",list:"p-select-list",optionGroup:"p-select-option-group",optionGroupLabel:"p-select-option-group-label",option:function(t){var n=t.instance,o=t.props,i=t.state,r=t.option,a=t.focusedOption;return["p-select-option",{"p-select-option-selected":n.isSelected(r)&&o.highlightOnSelect,"p-focus":i.focusedOptionIndex===a,"p-disabled":n.isOptionDisabled(r)}]},optionLabel:"p-select-option-label",optionCheckIcon:"p-select-option-check-icon",optionBlankIcon:"p-select-option-blank-icon",emptyMessage:"p-select-empty-message"},vw=fe.extend({name:"select",style:bw,classes:yw}),ww={name:"BaseSelect",extends:Jn,props:{options:Array,optionLabel:[String,Function],optionValue:[String,Function],optionDisabled:[String,Function],optionGroupLabel:[String,Function],optionGroupChildren:[String,Function],scrollHeight:{type:String,default:"14rem"},filter:Boolean,filterPlaceholder:String,filterLocale:String,filterMatchMode:{type:String,default:"contains"},filterFields:{type:Array,default:null},editable:Boolean,placeholder:{type:String,default:null},dataKey:null,showClear:{type:Boolean,default:!1},inputId:{type:String,default:null},inputClass:{type:[String,Object],default:null},inputStyle:{type:Object,default:null},labelId:{type:String,default:null},labelClass:{type:[String,Object],default:null},labelStyle:{type:Object,default:null},panelClass:{type:[String,Object],default:null},overlayStyle:{type:Object,default:null},overlayClass:{type:[String,Object],default:null},panelStyle:{type:Object,default:null},appendTo:{type:[String,Object],default:"body"},loading:{type:Boolean,default:!1},clearIcon:{type:String,default:void 0},dropdownIcon:{type:String,default:void 0},filterIcon:{type:String,default:void 0},loadingIcon:{type:String,default:void 0},resetFilterOnHide:{type:Boolean,default:!1},resetFilterOnClear:{type:Boolean,default:!1},virtualScrollerOptions:{type:Object,default:null},autoOptionFocus:{type:Boolean,default:!1},autoFilterFocus:{type:Boolean,default:!1},selectOnFocus:{type:Boolean,default:!1},focusOnHover:{type:Boolean,default:!0},highlightOnSelect:{type:Boolean,default:!0},checkmark:{type:Boolean,default:!1},filterMessage:{type:String,default:null},selectionMessage:{type:String,default:null},emptySelectionMessage:{type:String,default:null},emptyFilterMessage:{type:String,default:null},emptyMessage:{type:String,default:null},tabindex:{type:Number,default:0},ariaLabel:{type:String,default:null},ariaLabelledby:{type:String,default:null}},style:vw,provide:function(){return{$pcSelect:this,$parentInstance:this}}};function Er(e){"@babel/helpers - typeof";return Er=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Er(e)}function Cw(e){return $w(e)||xw(e)||Sw(e)||kw()}function kw(){throw new TypeError(`Invalid attempt to spread non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function Sw(e,t){if(e){if(typeof e=="string")return Cl(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Cl(e,t):void 0}}function xw(e){if(typeof Symbol<"u"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function $w(e){if(Array.isArray(e))return Cl(e)}function Cl(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);n2&&arguments[2]!==void 0?arguments[2]:!0,i=this.getOptionValue(n);this.updateModel(t,i),o&&this.hide(!0)},onOptionMouseMove:function(t,n){this.focusOnHover&&this.changeFocusedOptionIndex(t,n)},onFilterChange:function(t){var n=t.target.value;this.filterValue=n,this.focusedOptionIndex=-1,this.$emit("filter",{originalEvent:t,value:n}),!this.virtualScrollerDisabled&&this.virtualScroller.scrollToIndex(0)},onFilterKeyDown:function(t){if(!t.isComposing)switch(t.code){case"ArrowDown":this.onArrowDownKey(t);break;case"ArrowUp":this.onArrowUpKey(t,!0);break;case"ArrowLeft":case"ArrowRight":this.onArrowLeftKey(t,!0);break;case"Home":this.onHomeKey(t,!0);break;case"End":this.onEndKey(t,!0);break;case"Enter":case"NumpadEnter":this.onEnterKey(t);break;case"Escape":this.onEscapeKey(t);break;case"Tab":this.onTabKey(t);break}},onFilterBlur:function(){this.focusedOptionIndex=-1},onFilterUpdated:function(){this.overlayVisible&&this.alignOverlay()},onOverlayClick:function(t){un.emit("overlay-click",{originalEvent:t,target:this.$el})},onOverlayKeyDown:function(t){switch(t.code){case"Escape":this.onEscapeKey(t);break}},onArrowDownKey:function(t){if(!this.overlayVisible)this.show(),this.editable&&this.changeFocusedOptionIndex(t,this.findSelectedOptionIndex());else{var n=this.focusedOptionIndex!==-1?this.findNextOptionIndex(this.focusedOptionIndex):this.clicked?this.findFirstOptionIndex():this.findFirstFocusedOptionIndex();this.changeFocusedOptionIndex(t,n)}t.preventDefault()},onArrowUpKey:function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;if(t.altKey&&!n)this.focusedOptionIndex!==-1&&this.onOptionSelect(t,this.visibleOptions[this.focusedOptionIndex]),this.overlayVisible&&this.hide(),t.preventDefault();else{var o=this.focusedOptionIndex!==-1?this.findPrevOptionIndex(this.focusedOptionIndex):this.clicked?this.findLastOptionIndex():this.findLastFocusedOptionIndex();this.changeFocusedOptionIndex(t,o),!this.overlayVisible&&this.show(),t.preventDefault()}},onArrowLeftKey:function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;n&&(this.focusedOptionIndex=-1)},onHomeKey:function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;if(n){var o=t.currentTarget;t.shiftKey?o.setSelectionRange(0,t.target.selectionStart):(o.setSelectionRange(0,0),this.focusedOptionIndex=-1)}else this.changeFocusedOptionIndex(t,this.findFirstOptionIndex()),!this.overlayVisible&&this.show();t.preventDefault()},onEndKey:function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;if(n){var o=t.currentTarget;if(t.shiftKey)o.setSelectionRange(t.target.selectionStart,o.value.length);else{var i=o.value.length;o.setSelectionRange(i,i),this.focusedOptionIndex=-1}}else this.changeFocusedOptionIndex(t,this.findLastOptionIndex()),!this.overlayVisible&&this.show();t.preventDefault()},onPageUpKey:function(t){this.scrollInView(0),t.preventDefault()},onPageDownKey:function(t){this.scrollInView(this.visibleOptions.length-1),t.preventDefault()},onEnterKey:function(t){this.overlayVisible?(this.focusedOptionIndex!==-1&&this.onOptionSelect(t,this.visibleOptions[this.focusedOptionIndex]),this.hide(!0)):(this.focusedOptionIndex=-1,this.onArrowDownKey(t)),t.preventDefault()},onSpaceKey:function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;!n&&this.onEnterKey(t)},onEscapeKey:function(t){this.overlayVisible&&this.hide(!0),t.preventDefault(),t.stopPropagation()},onTabKey:function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;n||(this.overlayVisible&&this.hasFocusableElements()?(Xe(this.$refs.firstHiddenFocusableElementOnOverlay),t.preventDefault()):(this.focusedOptionIndex!==-1&&this.onOptionSelect(t,this.visibleOptions[this.focusedOptionIndex]),this.overlayVisible&&this.hide(this.filter)))},onBackspaceKey:function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;n&&!this.overlayVisible&&this.show()},onOverlayEnter:function(t){var n=this;Tt.set("overlay",t,this.$primevue.config.zIndex.overlay),wo(t,{position:"absolute",top:"0"}),this.alignOverlay(),this.scrollInView(),this.$attrSelector&&t.setAttribute(this.$attrSelector,""),setTimeout(function(){n.autoFilterFocus&&n.filter&&Xe(n.$refs.filterInput.$el),n.autoUpdateModel()},1)},onOverlayAfterEnter:function(){this.bindOutsideClickListener(),this.bindScrollListener(),this.bindResizeListener(),this.$emit("show")},onOverlayLeave:function(){var t=this;this.unbindOutsideClickListener(),this.unbindScrollListener(),this.unbindResizeListener(),this.autoFilterFocus&&this.filter&&!this.editable&&this.$nextTick(function(){t.$refs.filterInput&&Xe(t.$refs.filterInput.$el)}),this.$emit("hide"),this.overlay=null},onOverlayAfterLeave:function(t){Tt.clear(t)},alignOverlay:function(){this.appendTo==="self"?Qf(this.overlay,this.$el):this.overlay&&(this.overlay.style.minWidth=nt(this.$el)+"px",Ss(this.overlay,this.$el))},bindOutsideClickListener:function(){var t=this;this.outsideClickListener||(this.outsideClickListener=function(n){var o=n.composedPath();t.overlayVisible&&t.overlay&&!o.includes(t.$el)&&!o.includes(t.overlay)&&t.hide()},document.addEventListener("click",this.outsideClickListener,!0))},unbindOutsideClickListener:function(){this.outsideClickListener&&(document.removeEventListener("click",this.outsideClickListener,!0),this.outsideClickListener=null)},bindScrollListener:function(){var t=this;this.scrollHandler||(this.scrollHandler=new Rs(this.$refs.container,function(){t.overlayVisible&&t.hide()})),this.scrollHandler.bindScrollListener()},unbindScrollListener:function(){this.scrollHandler&&this.scrollHandler.unbindScrollListener()},bindResizeListener:function(){var t=this;this.resizeListener||(this.resizeListener=function(){t.overlayVisible&&!Ps()&&t.hide()},window.addEventListener("resize",this.resizeListener))},unbindResizeListener:function(){this.resizeListener&&(window.removeEventListener("resize",this.resizeListener),this.resizeListener=null)},bindLabelClickListener:function(){var t=this;if(!this.editable&&!this.labelClickListener){var n=document.querySelector('label[for="'.concat(this.labelId,'"]'));n&&ji(n)&&(this.labelClickListener=function(){Xe(t.$refs.focusInput)},n.addEventListener("click",this.labelClickListener))}},unbindLabelClickListener:function(){if(this.labelClickListener){var t=document.querySelector('label[for="'.concat(this.labelId,'"]'));t&&ji(t)&&t.removeEventListener("click",this.labelClickListener)}},bindMatchMediaOrientationListener:function(){var t=this;if(!this.matchMediaOrientationListener){var n=matchMedia("(orientation: portrait)");this.queryOrientation=n,this.matchMediaOrientationListener=function(){t.alignOverlay()},this.queryOrientation.addEventListener("change",this.matchMediaOrientationListener)}},unbindMatchMediaOrientationListener:function(){this.matchMediaOrientationListener&&(this.queryOrientation.removeEventListener("change",this.matchMediaOrientationListener),this.queryOrientation=null,this.matchMediaOrientationListener=null)},hasFocusableElements:function(){return $s(this.overlay,':not([data-p-hidden-focusable="true"])').length>0},isOptionExactMatched:function(t){var n;return this.isValidOption(t)&&typeof this.getOptionLabel(t)=="string"&&((n=this.getOptionLabel(t))===null||n===void 0?void 0:n.toLocaleLowerCase(this.filterLocale))==this.searchValue.toLocaleLowerCase(this.filterLocale)},isOptionStartsWith:function(t){var n;return this.isValidOption(t)&&typeof this.getOptionLabel(t)=="string"&&((n=this.getOptionLabel(t))===null||n===void 0?void 0:n.toLocaleLowerCase(this.filterLocale).startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale)))},isValidOption:function(t){return me(t)&&!(this.isOptionDisabled(t)||this.isOptionGroup(t))},isValidSelectedOption:function(t){return this.isValidOption(t)&&this.isSelected(t)},isSelected:function(t){return Xn(this.d_value,this.getOptionValue(t),this.equalityKey)},findFirstOptionIndex:function(){var t=this;return this.visibleOptions.findIndex(function(n){return t.isValidOption(n)})},findLastOptionIndex:function(){var t=this;return Ld(this.visibleOptions,function(n){return t.isValidOption(n)})},findNextOptionIndex:function(t){var n=this,o=t-1?o+t+1:t},findPrevOptionIndex:function(t){var n=this,o=t>0?Ld(this.visibleOptions.slice(0,t),function(i){return n.isValidOption(i)}):-1;return o>-1?o:t},findSelectedOptionIndex:function(){var t=this;return this.visibleOptions.findIndex(function(n){return t.isValidSelectedOption(n)})},findFirstFocusedOptionIndex:function(){var t=this.findSelectedOptionIndex();return t<0?this.findFirstOptionIndex():t},findLastFocusedOptionIndex:function(){var t=this.findSelectedOptionIndex();return t<0?this.findLastOptionIndex():t},searchOptions:function(t,n){var o=this;this.searchValue=(this.searchValue||"")+n;var i=-1,r=!1;return me(this.searchValue)&&(i=this.visibleOptions.findIndex(function(a){return o.isOptionExactMatched(a)}),i===-1&&(i=this.visibleOptions.findIndex(function(a){return o.isOptionStartsWith(a)})),i!==-1&&(r=!0),i===-1&&this.focusedOptionIndex===-1&&(i=this.findFirstFocusedOptionIndex()),i!==-1&&this.changeFocusedOptionIndex(t,i)),this.searchTimeout&&clearTimeout(this.searchTimeout),this.searchTimeout=setTimeout(function(){o.searchValue="",o.searchTimeout=null},500),r},changeFocusedOptionIndex:function(t,n){this.focusedOptionIndex!==n&&(this.focusedOptionIndex=n,this.scrollInView(),this.selectOnFocus&&this.onOptionSelect(t,this.visibleOptions[n],!1))},scrollInView:function(){var t=this,n=arguments.length>0&&arguments[0]!==void 0?arguments[0]:-1;this.$nextTick(function(){var o=n!==-1?"".concat(t.$id,"_").concat(n):t.focusedOptionId,i=In(t.list,'li[id="'.concat(o,'"]'));i?i.scrollIntoView&&i.scrollIntoView({block:"nearest",inline:"nearest"}):t.virtualScrollerDisabled||t.virtualScroller&&t.virtualScroller.scrollToIndex(n!==-1?n:t.focusedOptionIndex)})},autoUpdateModel:function(){this.autoOptionFocus&&(this.focusedOptionIndex=this.findFirstFocusedOptionIndex()),this.selectOnFocus&&this.autoOptionFocus&&!this.$filled&&this.onOptionSelect(null,this.visibleOptions[this.focusedOptionIndex],!1)},updateModel:function(t,n){this.writeValue(n,t),this.$emit("change",{originalEvent:t,value:n})},flatOptions:function(t){var n=this;return(t||[]).reduce(function(o,i,r){o.push({optionGroup:i,group:!0,index:r});var a=n.getOptionGroupChildren(i);return a&&a.forEach(function(l){return o.push(l)}),o},[])},overlayRef:function(t){this.overlay=t},listRef:function(t,n){this.list=t,n&&n(t)},virtualScrollerRef:function(t){this.virtualScroller=t}},computed:{visibleOptions:function(){var t=this,n=this.optionGroupLabel?this.flatOptions(this.options):this.options||[];if(this.filterValue){var o=ml.filter(n,this.searchFields,this.filterValue,this.filterMatchMode,this.filterLocale);if(this.optionGroupLabel){var i=this.options||[],r=[];return i.forEach(function(a){var l=t.getOptionGroupChildren(a),s=l.filter(function(d){return o.includes(d)});s.length>0&&r.push(pu(pu({},a),{},Fn({},typeof t.optionGroupChildren=="string"?t.optionGroupChildren:"items",Cw(s))))}),this.flatOptions(r)}return o}return n},hasSelectedOption:function(){return this.$filled},label:function(){var t=this.findSelectedOptionIndex();return t!==-1?this.getOptionLabel(this.visibleOptions[t]):this.placeholder||"p-emptylabel"},editableInputValue:function(){var t=this.findSelectedOptionIndex();return t!==-1?this.getOptionLabel(this.visibleOptions[t]):this.d_value||""},equalityKey:function(){return this.optionValue?null:this.dataKey},searchFields:function(){return this.filterFields||[this.optionLabel]},filterResultMessageText:function(){return me(this.visibleOptions)?this.filterMessageText.replaceAll("{0}",this.visibleOptions.length):this.emptyFilterMessageText},filterMessageText:function(){return this.filterMessage||this.$primevue.config.locale.searchMessage||""},emptyFilterMessageText:function(){return this.emptyFilterMessage||this.$primevue.config.locale.emptySearchMessage||this.$primevue.config.locale.emptyFilterMessage||""},emptyMessageText:function(){return this.emptyMessage||this.$primevue.config.locale.emptyMessage||""},selectionMessageText:function(){return this.selectionMessage||this.$primevue.config.locale.selectionMessage||""},emptySelectionMessageText:function(){return this.emptySelectionMessage||this.$primevue.config.locale.emptySelectionMessage||""},selectedMessageText:function(){return this.$filled?this.selectionMessageText.replaceAll("{0}","1"):this.emptySelectionMessageText},focusedOptionId:function(){return this.focusedOptionIndex!==-1?"".concat(this.$id,"_").concat(this.focusedOptionIndex):null},ariaSetSize:function(){var t=this;return this.visibleOptions.filter(function(n){return!t.isOptionGroup(n)}).length},isClearIconVisible:function(){return this.showClear&&this.d_value!=null&&!this.disabled&&!this.loading},virtualScrollerDisabled:function(){return!this.virtualScrollerOptions},containerDataP:function(){return Me(Fn({invalid:this.$invalid,disabled:this.disabled,focus:this.focused,fluid:this.$fluid,filled:this.$variant==="filled"},this.size,this.size))},labelDataP:function(){return Me(Fn(Fn({placeholder:!this.editable&&this.label===this.placeholder,clearable:this.showClear,disabled:this.disabled,editable:this.editable},this.size,this.size),"empty",!this.editable&&!this.$slots.value&&(this.label==="p-emptylabel"||this.label.length===0)))},dropdownIconDataP:function(){return Me(Fn({},this.size,this.size))},overlayDataP:function(){return Me(Fn({},"portal-"+this.appendTo,"portal-"+this.appendTo))}},directives:{ripple:en},components:{InputText:eo,VirtualScroller:Os,Portal:ri,InputIcon:Pp,IconField:$p,TimesIcon:to,ChevronDownIcon:sa,SpinnerIcon:ni,SearchIcon:xp,CheckIcon:Oo,BlankIcon:Sp}},Tw=["id","data-p"],Rw=["name","id","value","placeholder","tabindex","disabled","aria-label","aria-labelledby","aria-expanded","aria-controls","aria-activedescendant","aria-invalid","data-p"],Ow=["name","id","tabindex","aria-label","aria-labelledby","aria-expanded","aria-controls","aria-activedescendant","aria-invalid","aria-disabled","data-p"],Ew=["data-p"],Aw=["id"],Lw=["id"],_w=["id","aria-label","aria-selected","aria-disabled","aria-setsize","aria-posinset","onMousedown","onMousemove","data-p-selected","data-p-focused","data-p-disabled"];function Dw(e,t,n,o,i,r){var a=R("SpinnerIcon"),l=R("InputText"),s=R("SearchIcon"),d=R("InputIcon"),u=R("IconField"),c=R("CheckIcon"),f=R("BlankIcon"),p=R("VirtualScroller"),v=R("Portal"),C=Ft("ripple");return g(),b("div",m({ref:"container",id:e.$id,class:e.cx("root"),onClick:t[12]||(t[12]=function(){return r.onContainerClick&&r.onContainerClick.apply(r,arguments)}),"data-p":r.containerDataP},e.ptmi("root")),[e.editable?(g(),b("input",m({key:0,ref:"focusInput",name:e.name,id:e.labelId||e.inputId,type:"text",class:[e.cx("label"),e.inputClass,e.labelClass],style:[e.inputStyle,e.labelStyle],value:r.editableInputValue,placeholder:e.placeholder,tabindex:e.disabled?-1:e.tabindex,disabled:e.disabled,autocomplete:"off",role:"combobox","aria-label":e.ariaLabel,"aria-labelledby":e.ariaLabelledby,"aria-haspopup":"listbox","aria-expanded":i.overlayVisible,"aria-controls":i.overlayVisible?e.$id+"_list":void 0,"aria-activedescendant":i.focused?r.focusedOptionId:void 0,"aria-invalid":e.invalid||void 0,onFocus:t[0]||(t[0]=function(){return r.onFocus&&r.onFocus.apply(r,arguments)}),onBlur:t[1]||(t[1]=function(){return r.onBlur&&r.onBlur.apply(r,arguments)}),onKeydown:t[2]||(t[2]=function(){return r.onKeyDown&&r.onKeyDown.apply(r,arguments)}),onInput:t[3]||(t[3]=function(){return r.onEditableInput&&r.onEditableInput.apply(r,arguments)}),"data-p":r.labelDataP},e.ptm("label")),null,16,Rw)):(g(),b("span",m({key:1,ref:"focusInput",name:e.name,id:e.labelId||e.inputId,class:[e.cx("label"),e.inputClass,e.labelClass],style:[e.inputStyle,e.labelStyle],tabindex:e.disabled?-1:e.tabindex,role:"combobox","aria-label":e.ariaLabel||(r.label==="p-emptylabel"?void 0:r.label),"aria-labelledby":e.ariaLabelledby,"aria-haspopup":"listbox","aria-expanded":i.overlayVisible,"aria-controls":e.$id+"_list","aria-activedescendant":i.focused?r.focusedOptionId:void 0,"aria-invalid":e.invalid||void 0,"aria-disabled":e.disabled,onFocus:t[4]||(t[4]=function(){return r.onFocus&&r.onFocus.apply(r,arguments)}),onBlur:t[5]||(t[5]=function(){return r.onBlur&&r.onBlur.apply(r,arguments)}),onKeydown:t[6]||(t[6]=function(){return r.onKeyDown&&r.onKeyDown.apply(r,arguments)}),"data-p":r.labelDataP},e.ptm("label")),[N(e.$slots,"value",{value:e.d_value,placeholder:e.placeholder},function(){var S;return[$e(_(r.label==="p-emptylabel"?" ":(S=r.label)!==null&&S!==void 0?S:"empty"),1)]})],16,Ow)),r.isClearIconVisible?N(e.$slots,"clearicon",{key:2,class:J(e.cx("clearIcon")),clearCallback:r.onClearClick},function(){return[(g(),T(ae(e.clearIcon?"i":"TimesIcon"),m({ref:"clearIcon",class:[e.cx("clearIcon"),e.clearIcon],onClick:r.onClearClick},e.ptm("clearIcon"),{"data-pc-section":"clearicon"}),null,16,["class","onClick"]))]}):I("",!0),h("div",m({class:e.cx("dropdown")},e.ptm("dropdown")),[e.loading?N(e.$slots,"loadingicon",{key:0,class:J(e.cx("loadingIcon"))},function(){return[e.loadingIcon?(g(),b("span",m({key:0,class:[e.cx("loadingIcon"),"pi-spin",e.loadingIcon],"aria-hidden":"true"},e.ptm("loadingIcon")),null,16)):(g(),T(a,m({key:1,class:e.cx("loadingIcon"),spin:"","aria-hidden":"true"},e.ptm("loadingIcon")),null,16,["class"]))]}):N(e.$slots,"dropdownicon",{key:1,class:J(e.cx("dropdownIcon"))},function(){return[(g(),T(ae(e.dropdownIcon?"span":"ChevronDownIcon"),m({class:[e.cx("dropdownIcon"),e.dropdownIcon],"aria-hidden":"true","data-p":r.dropdownIconDataP},e.ptm("dropdownIcon")),null,16,["class","data-p"]))]})],16),D(v,{appendTo:e.appendTo},{default:V(function(){return[D(Io,m({name:"p-anchored-overlay",onEnter:r.onOverlayEnter,onAfterEnter:r.onOverlayAfterEnter,onLeave:r.onOverlayLeave,onAfterLeave:r.onOverlayAfterLeave},e.ptm("transition")),{default:V(function(){return[i.overlayVisible?(g(),b("div",m({key:0,ref:r.overlayRef,class:[e.cx("overlay"),e.panelClass,e.overlayClass],style:[e.panelStyle,e.overlayStyle],onClick:t[10]||(t[10]=function(){return r.onOverlayClick&&r.onOverlayClick.apply(r,arguments)}),onKeydown:t[11]||(t[11]=function(){return r.onOverlayKeyDown&&r.onOverlayKeyDown.apply(r,arguments)}),"data-p":r.overlayDataP},e.ptm("overlay")),[h("span",m({ref:"firstHiddenFocusableElementOnOverlay",role:"presentation","aria-hidden":"true",class:"p-hidden-accessible p-hidden-focusable",tabindex:0,onFocus:t[7]||(t[7]=function(){return r.onFirstHiddenFocus&&r.onFirstHiddenFocus.apply(r,arguments)})},e.ptm("hiddenFirstFocusableEl"),{"data-p-hidden-accessible":!0,"data-p-hidden-focusable":!0}),null,16),N(e.$slots,"header",{value:e.d_value,options:r.visibleOptions}),e.filter?(g(),b("div",m({key:0,class:e.cx("header")},e.ptm("header")),[D(u,{unstyled:e.unstyled,pt:e.ptm("pcFilterContainer")},{default:V(function(){return[D(l,{ref:"filterInput",type:"text",value:i.filterValue,onVnodeMounted:r.onFilterUpdated,onVnodeUpdated:r.onFilterUpdated,class:J(e.cx("pcFilter")),placeholder:e.filterPlaceholder,variant:e.variant,unstyled:e.unstyled,role:"searchbox",autocomplete:"off","aria-owns":e.$id+"_list","aria-activedescendant":r.focusedOptionId,onKeydown:r.onFilterKeyDown,onBlur:r.onFilterBlur,onInput:r.onFilterChange,pt:e.ptm("pcFilter"),formControl:{novalidate:!0}},null,8,["value","onVnodeMounted","onVnodeUpdated","class","placeholder","variant","unstyled","aria-owns","aria-activedescendant","onKeydown","onBlur","onInput","pt"]),D(d,{unstyled:e.unstyled,pt:e.ptm("pcFilterIconContainer")},{default:V(function(){return[N(e.$slots,"filtericon",{},function(){return[e.filterIcon?(g(),b("span",m({key:0,class:e.filterIcon},e.ptm("filterIcon")),null,16)):(g(),T(s,qi(m({key:1},e.ptm("filterIcon"))),null,16))]})]}),_:3},8,["unstyled","pt"])]}),_:3},8,["unstyled","pt"]),h("span",m({role:"status","aria-live":"polite",class:"p-hidden-accessible"},e.ptm("hiddenFilterResult"),{"data-p-hidden-accessible":!0}),_(r.filterResultMessageText),17)],16)):I("",!0),h("div",m({class:e.cx("listContainer"),style:{"max-height":r.virtualScrollerDisabled?e.scrollHeight:""}},e.ptm("listContainer")),[D(p,m({ref:r.virtualScrollerRef},e.virtualScrollerOptions,{items:r.visibleOptions,style:{height:e.scrollHeight},tabindex:-1,disabled:r.virtualScrollerDisabled,pt:e.ptm("virtualScroller")}),ar({content:V(function(S){var x=S.styleClass,P=S.contentRef,L=S.items,k=S.getItemOptions,F=S.contentStyle,K=S.itemSize;return[h("ul",m({ref:function(q){return r.listRef(q,P)},id:e.$id+"_list",class:[e.cx("list"),x],style:F,role:"listbox"},e.ptm("list")),[(g(!0),b(te,null,Fe(L,function(z,q){return g(),b(te,{key:r.getOptionRenderKey(z,r.getOptionIndex(q,k))},[r.isOptionGroup(z)?(g(),b("li",m({key:0,id:e.$id+"_"+r.getOptionIndex(q,k),style:{height:K?K+"px":void 0},class:e.cx("optionGroup"),role:"option"},{ref_for:!0},e.ptm("optionGroup")),[N(e.$slots,"optiongroup",{option:z.optionGroup,index:r.getOptionIndex(q,k)},function(){return[h("span",m({class:e.cx("optionGroupLabel")},{ref_for:!0},e.ptm("optionGroupLabel")),_(r.getOptionGroupLabel(z.optionGroup)),17)]})],16,Lw)):zt((g(),b("li",m({key:1,id:e.$id+"_"+r.getOptionIndex(q,k),class:e.cx("option",{option:z,focusedOption:r.getOptionIndex(q,k)}),style:{height:K?K+"px":void 0},role:"option","aria-label":r.getOptionLabel(z),"aria-selected":r.isSelected(z),"aria-disabled":r.isOptionDisabled(z),"aria-setsize":r.ariaSetSize,"aria-posinset":r.getAriaPosInset(r.getOptionIndex(q,k)),onMousedown:function(ee){return r.onOptionSelect(ee,z)},onMousemove:function(ee){return r.onOptionMouseMove(ee,r.getOptionIndex(q,k))},onClick:t[8]||(t[8]=To(function(){},["stop"])),"data-p-selected":!e.checkmark&&r.isSelected(z),"data-p-focused":i.focusedOptionIndex===r.getOptionIndex(q,k),"data-p-disabled":r.isOptionDisabled(z)},{ref_for:!0},r.getPTItemOptions(z,k,q,"option")),[e.checkmark?(g(),b(te,{key:0},[r.isSelected(z)?(g(),T(c,m({key:0,class:e.cx("optionCheckIcon")},{ref_for:!0},e.ptm("optionCheckIcon")),null,16,["class"])):(g(),T(f,m({key:1,class:e.cx("optionBlankIcon")},{ref_for:!0},e.ptm("optionBlankIcon")),null,16,["class"]))],64)):I("",!0),N(e.$slots,"option",{option:z,selected:r.isSelected(z),index:r.getOptionIndex(q,k)},function(){return[h("span",m({class:e.cx("optionLabel")},{ref_for:!0},e.ptm("optionLabel")),_(r.getOptionLabel(z)),17)]})],16,_w)),[[C]])],64)}),128)),i.filterValue&&(!L||L&&L.length===0)?(g(),b("li",m({key:0,class:e.cx("emptyMessage"),role:"option"},e.ptm("emptyMessage"),{"data-p-hidden-accessible":!0}),[N(e.$slots,"emptyfilter",{},function(){return[$e(_(r.emptyFilterMessageText),1)]})],16)):!e.options||e.options&&e.options.length===0?(g(),b("li",m({key:1,class:e.cx("emptyMessage"),role:"option"},e.ptm("emptyMessage"),{"data-p-hidden-accessible":!0}),[N(e.$slots,"empty",{},function(){return[$e(_(r.emptyMessageText),1)]})],16)):I("",!0)],16,Aw)]}),_:2},[e.$slots.loader?{name:"loader",fn:V(function(S){var x=S.options;return[N(e.$slots,"loader",{options:x})]}),key:"0"}:void 0]),1040,["items","style","disabled","pt"])],16),N(e.$slots,"footer",{value:e.d_value,options:r.visibleOptions}),!e.options||e.options&&e.options.length===0?(g(),b("span",m({key:1,role:"status","aria-live":"polite",class:"p-hidden-accessible"},e.ptm("hiddenEmptyMessage"),{"data-p-hidden-accessible":!0}),_(r.emptyMessageText),17)):I("",!0),h("span",m({role:"status","aria-live":"polite",class:"p-hidden-accessible"},e.ptm("hiddenSelectedMessage"),{"data-p-hidden-accessible":!0}),_(r.selectedMessageText),17),h("span",m({ref:"lastHiddenFocusableElementOnOverlay",role:"presentation","aria-hidden":"true",class:"p-hidden-accessible p-hidden-focusable",tabindex:0,onFocus:t[9]||(t[9]=function(){return r.onLastHiddenFocus&&r.onLastHiddenFocus.apply(r,arguments)})},e.ptm("hiddenLastFocusableEl"),{"data-p-hidden-accessible":!0,"data-p-hidden-focusable":!0}),null,16)],16,Ew)):I("",!0)]}),_:3},16,["onEnter","onAfterEnter","onLeave","onAfterLeave"])]}),_:3},8,["appendTo"])],16,Tw)}no.render=Dw;var Bw={name:"Dropdown",extends:no,mounted:function(){console.warn("Deprecated since v4. Use Select component instead.")}},Tp={name:"MinusIcon",extends:Te};function Mw(e){return Nw(e)||jw(e)||Fw(e)||zw()}function zw(){throw new TypeError(`Invalid attempt to spread non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function Fw(e,t){if(e){if(typeof e=="string")return kl(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?kl(e,t):void 0}}function jw(e){if(typeof Symbol<"u"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function Nw(e){if(Array.isArray(e))return kl(e)}function kl(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);n .p-checkbox-box { - border-color: dt('checkbox.invalid.border.color'); - } - - .p-checkbox.p-variant-filled .p-checkbox-box { - background: dt('checkbox.filled.background'); - } - - .p-checkbox-checked.p-variant-filled .p-checkbox-box { - background: dt('checkbox.checked.background'); - } - - .p-checkbox-checked.p-variant-filled:not(.p-disabled):has(.p-checkbox-input:hover) .p-checkbox-box { - background: dt('checkbox.checked.hover.background'); - } - - .p-checkbox.p-disabled { - opacity: 1; - } - - .p-checkbox.p-disabled .p-checkbox-box { - background: dt('checkbox.disabled.background'); - border-color: dt('checkbox.checked.disabled.border.color'); - } - - .p-checkbox.p-disabled .p-checkbox-box .p-checkbox-icon { - color: dt('checkbox.icon.disabled.color'); - } - - .p-checkbox-sm, - .p-checkbox-sm .p-checkbox-box { - width: dt('checkbox.sm.width'); - height: dt('checkbox.sm.height'); - } - - .p-checkbox-sm .p-checkbox-icon { - font-size: dt('checkbox.icon.sm.size'); - width: dt('checkbox.icon.sm.size'); - height: dt('checkbox.icon.sm.size'); - } - - .p-checkbox-lg, - .p-checkbox-lg .p-checkbox-box { - width: dt('checkbox.lg.width'); - height: dt('checkbox.lg.height'); - } - - .p-checkbox-lg .p-checkbox-icon { - font-size: dt('checkbox.icon.lg.size'); - width: dt('checkbox.icon.lg.size'); - height: dt('checkbox.icon.lg.size'); - } -`,Hw={root:function(t){var n=t.instance,o=t.props;return["p-checkbox p-component",{"p-checkbox-checked":n.checked,"p-disabled":o.disabled,"p-invalid":n.$pcCheckboxGroup?n.$pcCheckboxGroup.$invalid:n.$invalid,"p-variant-filled":n.$variant==="filled","p-checkbox-sm p-inputfield-sm":o.size==="small","p-checkbox-lg p-inputfield-lg":o.size==="large"}]},box:"p-checkbox-box",input:"p-checkbox-input",icon:"p-checkbox-icon"},Gw=fe.extend({name:"checkbox",style:Uw,classes:Hw}),Kw={name:"BaseCheckbox",extends:Jn,props:{value:null,binary:Boolean,indeterminate:{type:Boolean,default:!1},trueValue:{type:null,default:!0},falseValue:{type:null,default:!1},readonly:{type:Boolean,default:!1},required:{type:Boolean,default:!1},tabindex:{type:Number,default:null},inputId:{type:String,default:null},inputClass:{type:[String,Object],default:null},inputStyle:{type:Object,default:null},ariaLabelledby:{type:String,default:null},ariaLabel:{type:String,default:null}},style:Gw,provide:function(){return{$pcCheckbox:this,$parentInstance:this}}};function Ar(e){"@babel/helpers - typeof";return Ar=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Ar(e)}function Ww(e,t,n){return(t=qw(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function qw(e){var t=Qw(e,"string");return Ar(t)=="symbol"?t:t+""}function Qw(e,t){if(Ar(e)!="object"||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var o=n.call(e,t);if(Ar(o)!="object")return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return(t==="string"?String:Number)(e)}function Zw(e){return eC(e)||Jw(e)||Xw(e)||Yw()}function Yw(){throw new TypeError(`Invalid attempt to spread non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function Xw(e,t){if(e){if(typeof e=="string")return Sl(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Sl(e,t):void 0}}function Jw(e){if(typeof Symbol<"u"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function eC(e){if(Array.isArray(e))return Sl(e)}function Sl(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);n .p-toggleswitch-slider { - border-color: dt('toggleswitch.invalid.border.color'); - } - - .p-toggleswitch.p-disabled { - opacity: 1; - } - - .p-toggleswitch.p-disabled .p-toggleswitch-slider { - background: dt('toggleswitch.disabled.background'); - } - - .p-toggleswitch.p-disabled .p-toggleswitch-handle { - background: dt('toggleswitch.handle.disabled.background'); - } -`,aC={root:{position:"relative"}},lC={root:function(t){var n=t.instance,o=t.props;return["p-toggleswitch p-component",{"p-toggleswitch-checked":n.checked,"p-disabled":o.disabled,"p-invalid":n.$invalid}]},input:"p-toggleswitch-input",slider:"p-toggleswitch-slider",handle:"p-toggleswitch-handle"},sC=fe.extend({name:"toggleswitch",style:iC,classes:lC,inlineStyles:aC}),dC={name:"BaseToggleSwitch",extends:hp,props:{trueValue:{type:null,default:!0},falseValue:{type:null,default:!1},readonly:{type:Boolean,default:!1},tabindex:{type:Number,default:null},inputId:{type:String,default:null},inputClass:{type:[String,Object],default:null},inputStyle:{type:Object,default:null},ariaLabelledby:{type:String,default:null},ariaLabel:{type:String,default:null}},style:sC,provide:function(){return{$pcToggleSwitch:this,$parentInstance:this}}},Es={name:"ToggleSwitch",extends:dC,inheritAttrs:!1,emits:["change","focus","blur"],methods:{getPTOptions:function(t){var n=t==="root"?this.ptmi:this.ptm;return n(t,{context:{checked:this.checked,disabled:this.disabled}})},onChange:function(t){if(!this.disabled&&!this.readonly){var n=this.checked?this.falseValue:this.trueValue;this.writeValue(n,t),this.$emit("change",t)}},onFocus:function(t){this.$emit("focus",t)},onBlur:function(t){var n,o;this.$emit("blur",t),(n=(o=this.formField).onBlur)===null||n===void 0||n.call(o,t)}},computed:{checked:function(){return this.d_value===this.trueValue},dataP:function(){return Me({checked:this.checked,disabled:this.disabled,invalid:this.$invalid})}}},uC=["data-p-checked","data-p-disabled","data-p"],cC=["id","checked","tabindex","disabled","readonly","aria-checked","aria-labelledby","aria-label","aria-invalid"],fC=["data-p"],pC=["data-p"];function hC(e,t,n,o,i,r){return g(),b("div",m({class:e.cx("root"),style:e.sx("root")},r.getPTOptions("root"),{"data-p-checked":r.checked,"data-p-disabled":e.disabled,"data-p":r.dataP}),[h("input",m({id:e.inputId,type:"checkbox",role:"switch",class:[e.cx("input"),e.inputClass],style:e.inputStyle,checked:r.checked,tabindex:e.tabindex,disabled:e.disabled,readonly:e.readonly,"aria-checked":r.checked,"aria-labelledby":e.ariaLabelledby,"aria-label":e.ariaLabel,"aria-invalid":e.invalid||void 0,onFocus:t[0]||(t[0]=function(){return r.onFocus&&r.onFocus.apply(r,arguments)}),onBlur:t[1]||(t[1]=function(){return r.onBlur&&r.onBlur.apply(r,arguments)}),onChange:t[2]||(t[2]=function(){return r.onChange&&r.onChange.apply(r,arguments)})},r.getPTOptions("input")),null,16,cC),h("div",m({class:e.cx("slider")},r.getPTOptions("slider"),{"data-p":r.dataP}),[h("div",m({class:e.cx("handle")},r.getPTOptions("handle"),{"data-p":r.dataP}),[N(e.$slots,"handle",{checked:r.checked})],16,pC)],16,fC)],16,uC)}Es.render=hC;var gC={name:"InputSwitch",extends:Es,mounted:function(){console.warn("Deprecated since v4. Use ToggleSwitch component instead.")}},As={name:"ChevronRightIcon",extends:Te};function mC(e){return wC(e)||vC(e)||yC(e)||bC()}function bC(){throw new TypeError(`Invalid attempt to spread non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function yC(e,t){if(e){if(typeof e=="string")return xl(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?xl(e,t):void 0}}function vC(e){if(typeof Symbol<"u"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function wC(e){if(Array.isArray(e))return xl(e)}function xl(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);n0?this.first+1:0).replace("{last}",Math.min(this.first+this.rows,this.totalRecords)).replace("{rows}",this.rows).replace("{totalRecords}",this.totalRecords);return t}}};function c2(e,t,n,o,i,r){return g(),b("span",m({class:e.cx("current")},e.ptm("current")),_(r.text),17)}Dp.render=c2;var Bp={name:"FirstPageLink",hostName:"Paginator",extends:ye,props:{template:{type:Function,default:null}},methods:{getPTOptions:function(t){return this.ptm(t,{context:{disabled:this.$attrs.disabled}})}},components:{AngleDoubleLeftIcon:Ep},directives:{ripple:en}};function f2(e,t,n,o,i,r){var a=Ft("ripple");return zt((g(),b("button",m({class:e.cx("first"),type:"button"},r.getPTOptions("first"),{"data-pc-group-section":"pagebutton"}),[(g(),T(ae(n.template||"AngleDoubleLeftIcon"),m({class:e.cx("firstIcon")},r.getPTOptions("firstIcon")),null,16,["class"]))],16)),[[a]])}Bp.render=f2;var Mp={name:"JumpToPageDropdown",hostName:"Paginator",extends:ye,emits:["page-change"],props:{page:Number,pageCount:Number,disabled:Boolean,templates:null},methods:{onChange:function(t){this.$emit("page-change",t)}},computed:{pageOptions:function(){for(var t=[],n=0;ne.length)&&(t=e.length);for(var n=0,o=Array(t);n0&&t&&this.d_first>=t&&this.changePage(this.pageCount-1)}},mounted:function(){this.createStyle()},methods:{changePage:function(t){var n=this.pageCount;if(t>=0&&t0?this.page+1:0},last:function(){return Math.min(this.d_first+this.rows,this.totalRecords)}},components:{CurrentPageReport:Dp,FirstPageLink:Bp,LastPageLink:Fp,NextPageLink:jp,PageLinks:Np,PrevPageLink:Vp,RowsPerPageDropdown:Up,JumpToPageDropdown:Mp,JumpToPageInput:zp}};function $2(e,t,n,o,i,r){var a=R("FirstPageLink"),l=R("PrevPageLink"),s=R("NextPageLink"),d=R("LastPageLink"),u=R("PageLinks"),c=R("CurrentPageReport"),f=R("RowsPerPageDropdown"),p=R("JumpToPageDropdown"),v=R("JumpToPageInput");return e.alwaysShow||r.pageLinks&&r.pageLinks.length>1?(g(),b("nav",qi(m({key:0},e.ptmi("paginatorContainer"))),[(g(!0),b(te,null,Fe(r.templateItems,function(C,S){return g(),b("div",m({key:S,ref_for:!0,ref:"paginator",class:e.cx("paginator",{key:S})},{ref_for:!0},e.ptm("root")),[e.$slots.container?N(e.$slots,"container",{key:0,first:i.d_first+1,last:r.last,rows:i.d_rows,page:r.page,pageCount:r.pageCount,pageLinks:r.pageLinks,totalRecords:e.totalRecords,firstPageCallback:r.changePageToFirst,lastPageCallback:r.changePageToLast,prevPageCallback:r.changePageToPrev,nextPageCallback:r.changePageToNext,rowChangeCallback:r.onRowChange,changePageCallback:r.changePage}):(g(),b(te,{key:1},[e.$slots.start?(g(),b("div",m({key:0,class:e.cx("contentStart")},{ref_for:!0},e.ptm("contentStart")),[N(e.$slots,"start",{state:r.currentState})],16)):I("",!0),h("div",m({class:e.cx("content")},{ref_for:!0},e.ptm("content")),[(g(!0),b(te,null,Fe(C,function(x){return g(),b(te,{key:x},[x==="FirstPageLink"?(g(),T(a,{key:0,"aria-label":r.getAriaLabel("firstPageLabel"),template:e.$slots.firsticon||e.$slots.firstpagelinkicon,onClick:t[0]||(t[0]=function(P){return r.changePageToFirst(P)}),disabled:r.isFirstPage||r.empty,unstyled:e.unstyled,pt:e.pt},null,8,["aria-label","template","disabled","unstyled","pt"])):x==="PrevPageLink"?(g(),T(l,{key:1,"aria-label":r.getAriaLabel("prevPageLabel"),template:e.$slots.previcon||e.$slots.prevpagelinkicon,onClick:t[1]||(t[1]=function(P){return r.changePageToPrev(P)}),disabled:r.isFirstPage||r.empty,unstyled:e.unstyled,pt:e.pt},null,8,["aria-label","template","disabled","unstyled","pt"])):x==="NextPageLink"?(g(),T(s,{key:2,"aria-label":r.getAriaLabel("nextPageLabel"),template:e.$slots.nexticon||e.$slots.nextpagelinkicon,onClick:t[2]||(t[2]=function(P){return r.changePageToNext(P)}),disabled:r.isLastPage||r.empty,unstyled:e.unstyled,pt:e.pt},null,8,["aria-label","template","disabled","unstyled","pt"])):x==="LastPageLink"?(g(),T(d,{key:3,"aria-label":r.getAriaLabel("lastPageLabel"),template:e.$slots.lasticon||e.$slots.lastpagelinkicon,onClick:t[3]||(t[3]=function(P){return r.changePageToLast(P)}),disabled:r.isLastPage||r.empty,unstyled:e.unstyled,pt:e.pt},null,8,["aria-label","template","disabled","unstyled","pt"])):x==="PageLinks"?(g(),T(u,{key:4,"aria-label":r.getAriaLabel("pageLabel"),value:r.pageLinks,page:r.page,onClick:t[4]||(t[4]=function(P){return r.changePageLink(P)}),unstyled:e.unstyled,pt:e.pt},null,8,["aria-label","value","page","unstyled","pt"])):x==="CurrentPageReport"?(g(),T(c,{key:5,"aria-live":"polite",template:e.currentPageReportTemplate,currentPage:r.currentPage,page:r.page,pageCount:r.pageCount,first:i.d_first,rows:i.d_rows,totalRecords:e.totalRecords,unstyled:e.unstyled,pt:e.pt},null,8,["template","currentPage","page","pageCount","first","rows","totalRecords","unstyled","pt"])):x==="RowsPerPageDropdown"&&e.rowsPerPageOptions?(g(),T(f,{key:6,"aria-label":r.getAriaLabel("rowsPerPageLabel"),rows:i.d_rows,options:e.rowsPerPageOptions,onRowsChange:t[5]||(t[5]=function(P){return r.onRowChange(P)}),disabled:r.empty,templates:e.$slots,unstyled:e.unstyled,pt:e.pt},null,8,["aria-label","rows","options","disabled","templates","unstyled","pt"])):x==="JumpToPageDropdown"?(g(),T(p,{key:7,"aria-label":r.getAriaLabel("jumpToPageDropdownLabel"),page:r.page,pageCount:r.pageCount,onPageChange:t[6]||(t[6]=function(P){return r.changePage(P)}),disabled:r.empty,templates:e.$slots,unstyled:e.unstyled,pt:e.pt},null,8,["aria-label","page","pageCount","disabled","templates","unstyled","pt"])):x==="JumpToPageInput"?(g(),T(v,{key:8,page:r.currentPage,onPageChange:t[7]||(t[7]=function(P){return r.changePage(P)}),disabled:r.empty,unstyled:e.unstyled,pt:e.pt},null,8,["page","disabled","unstyled","pt"])):I("",!0)],64)}),128))],16),e.$slots.end?(g(),b("div",m({key:1,class:e.cx("contentEnd")},{ref_for:!0},e.ptm("contentEnd")),[N(e.$slots,"end",{state:r.currentState})],16)):I("",!0)],64))],16)}),128))],16)):I("",!0)}ii.render=$2;var P2=` - .p-datatable { - position: relative; - display: block; - } - - .p-datatable-table { - border-spacing: 0; - border-collapse: separate; - width: 100%; - } - - .p-datatable-scrollable > .p-datatable-table-container { - position: relative; - } - - .p-datatable-scrollable-table > .p-datatable-thead { - inset-block-start: 0; - z-index: 1; - } - - .p-datatable-scrollable-table > .p-datatable-frozen-tbody { - position: sticky; - z-index: 1; - } - - .p-datatable-scrollable-table > .p-datatable-tfoot { - inset-block-end: 0; - z-index: 1; - } - - .p-datatable-scrollable .p-datatable-frozen-column { - position: sticky; - } - - .p-datatable-scrollable th.p-datatable-frozen-column { - z-index: 1; - } - - .p-datatable-scrollable td.p-datatable-frozen-column { - background: inherit; - } - - .p-datatable-scrollable > .p-datatable-table-container > .p-datatable-table > .p-datatable-thead, - .p-datatable-scrollable > .p-datatable-table-container > .p-virtualscroller > .p-datatable-table > .p-datatable-thead { - background: dt('datatable.header.cell.background'); - } - - .p-datatable-scrollable > .p-datatable-table-container > .p-datatable-table > .p-datatable-tfoot, - .p-datatable-scrollable > .p-datatable-table-container > .p-virtualscroller > .p-datatable-table > .p-datatable-tfoot { - background: dt('datatable.footer.cell.background'); - } - - .p-datatable-flex-scrollable { - display: flex; - flex-direction: column; - height: 100%; - } - - .p-datatable-flex-scrollable > .p-datatable-table-container { - display: flex; - flex-direction: column; - flex: 1; - height: 100%; - } - - .p-datatable-scrollable-table > .p-datatable-tbody > .p-datatable-row-group-header { - position: sticky; - z-index: 1; - } - - .p-datatable-resizable-table > .p-datatable-thead > tr > th, - .p-datatable-resizable-table > .p-datatable-tfoot > tr > td, - .p-datatable-resizable-table > .p-datatable-tbody > tr > td { - overflow: hidden; - white-space: nowrap; - } - - .p-datatable-resizable-table > .p-datatable-thead > tr > th.p-datatable-resizable-column:not(.p-datatable-frozen-column) { - background-clip: padding-box; - position: relative; - } - - .p-datatable-resizable-table-fit > .p-datatable-thead > tr > th.p-datatable-resizable-column:last-child .p-datatable-column-resizer { - display: none; - } - - .p-datatable-column-resizer { - display: block; - position: absolute; - inset-block-start: 0; - inset-inline-end: 0; - margin: 0; - width: dt('datatable.column.resizer.width'); - height: 100%; - padding: 0; - cursor: col-resize; - border: 1px solid transparent; - } - - .p-datatable-column-header-content { - display: flex; - align-items: center; - gap: dt('datatable.header.cell.gap'); - } - - .p-datatable-column-resize-indicator { - width: dt('datatable.resize.indicator.width'); - position: absolute; - z-index: 10; - display: none; - background: dt('datatable.resize.indicator.color'); - } - - .p-datatable-row-reorder-indicator-up, - .p-datatable-row-reorder-indicator-down { - position: absolute; - display: none; - } - - .p-datatable-reorderable-column, - .p-datatable-reorderable-row-handle { - cursor: move; - } - - .p-datatable-mask { - position: absolute; - display: flex; - align-items: center; - justify-content: center; - z-index: 2; - } - - .p-datatable-inline-filter { - display: flex; - align-items: center; - width: 100%; - gap: dt('datatable.filter.inline.gap'); - } - - .p-datatable-inline-filter .p-datatable-filter-element-container { - flex: 1 1 auto; - width: 1%; - } - - .p-datatable-filter-overlay { - background: dt('datatable.filter.overlay.select.background'); - color: dt('datatable.filter.overlay.select.color'); - border: 1px solid dt('datatable.filter.overlay.select.border.color'); - border-radius: dt('datatable.filter.overlay.select.border.radius'); - box-shadow: dt('datatable.filter.overlay.select.shadow'); - min-width: 12.5rem; - } - - .p-datatable-filter-constraint-list { - margin: 0; - list-style: none; - display: flex; - flex-direction: column; - padding: dt('datatable.filter.constraint.list.padding'); - gap: dt('datatable.filter.constraint.list.gap'); - } - - .p-datatable-filter-constraint { - padding: dt('datatable.filter.constraint.padding'); - color: dt('datatable.filter.constraint.color'); - border-radius: dt('datatable.filter.constraint.border.radius'); - cursor: pointer; - transition: - background dt('datatable.transition.duration'), - color dt('datatable.transition.duration'), - border-color dt('datatable.transition.duration'), - box-shadow dt('datatable.transition.duration'); - } - - .p-datatable-filter-constraint-selected { - background: dt('datatable.filter.constraint.selected.background'); - color: dt('datatable.filter.constraint.selected.color'); - } - - .p-datatable-filter-constraint:not(.p-datatable-filter-constraint-selected):not(.p-disabled):hover { - background: dt('datatable.filter.constraint.focus.background'); - color: dt('datatable.filter.constraint.focus.color'); - } - - .p-datatable-filter-constraint:focus-visible { - outline: 0 none; - background: dt('datatable.filter.constraint.focus.background'); - color: dt('datatable.filter.constraint.focus.color'); - } - - .p-datatable-filter-constraint-selected:focus-visible { - outline: 0 none; - background: dt('datatable.filter.constraint.selected.focus.background'); - color: dt('datatable.filter.constraint.selected.focus.color'); - } - - .p-datatable-filter-constraint-separator { - border-block-start: 1px solid dt('datatable.filter.constraint.separator.border.color'); - } - - .p-datatable-popover-filter { - display: inline-flex; - margin-inline-start: auto; - } - - .p-datatable-filter-overlay-popover { - background: dt('datatable.filter.overlay.popover.background'); - color: dt('datatable.filter.overlay.popover.color'); - border: 1px solid dt('datatable.filter.overlay.popover.border.color'); - border-radius: dt('datatable.filter.overlay.popover.border.radius'); - box-shadow: dt('datatable.filter.overlay.popover.shadow'); - min-width: 12.5rem; - padding: dt('datatable.filter.overlay.popover.padding'); - display: flex; - flex-direction: column; - gap: dt('datatable.filter.overlay.popover.gap'); - } - - .p-datatable-filter-operator-dropdown { - width: 100%; - } - - .p-datatable-filter-rule-list, - .p-datatable-filter-rule { - display: flex; - flex-direction: column; - gap: dt('datatable.filter.overlay.popover.gap'); - } - - .p-datatable-filter-rule { - border-block-end: 1px solid dt('datatable.filter.rule.border.color'); - padding-bottom: dt('datatable.filter.overlay.popover.gap'); - } - - .p-datatable-filter-rule:last-child { - border-block-end: 0 none; - padding-bottom: 0; - } - - .p-datatable-filter-add-rule-button { - width: 100%; - } - - .p-datatable-filter-remove-rule-button { - width: 100%; - } - - .p-datatable-filter-buttonbar { - padding: 0; - display: flex; - align-items: center; - justify-content: space-between; - } - - .p-datatable-virtualscroller-spacer { - display: flex; - } - - .p-datatable .p-virtualscroller .p-virtualscroller-loading { - transform: none !important; - min-height: 0; - position: sticky; - inset-block-start: 0; - inset-inline-start: 0; - } - - .p-datatable-paginator-top { - border-color: dt('datatable.paginator.top.border.color'); - border-style: solid; - border-width: dt('datatable.paginator.top.border.width'); - } - - .p-datatable-paginator-bottom { - border-color: dt('datatable.paginator.bottom.border.color'); - border-style: solid; - border-width: dt('datatable.paginator.bottom.border.width'); - } - - .p-datatable-header { - background: dt('datatable.header.background'); - color: dt('datatable.header.color'); - border-color: dt('datatable.header.border.color'); - border-style: solid; - border-width: dt('datatable.header.border.width'); - padding: dt('datatable.header.padding'); - } - - .p-datatable-footer { - background: dt('datatable.footer.background'); - color: dt('datatable.footer.color'); - border-color: dt('datatable.footer.border.color'); - border-style: solid; - border-width: dt('datatable.footer.border.width'); - padding: dt('datatable.footer.padding'); - } - - .p-datatable-header-cell { - padding: dt('datatable.header.cell.padding'); - background: dt('datatable.header.cell.background'); - border-color: dt('datatable.header.cell.border.color'); - border-style: solid; - border-width: 0 0 1px 0; - color: dt('datatable.header.cell.color'); - font-weight: normal; - text-align: start; - transition: - background dt('datatable.transition.duration'), - color dt('datatable.transition.duration'), - border-color dt('datatable.transition.duration'), - outline-color dt('datatable.transition.duration'), - box-shadow dt('datatable.transition.duration'); - } - - .p-datatable-column-title { - font-weight: dt('datatable.column.title.font.weight'); - } - - .p-datatable-tbody > tr { - outline-color: transparent; - background: dt('datatable.row.background'); - color: dt('datatable.row.color'); - transition: - background dt('datatable.transition.duration'), - color dt('datatable.transition.duration'), - border-color dt('datatable.transition.duration'), - outline-color dt('datatable.transition.duration'), - box-shadow dt('datatable.transition.duration'); - } - - .p-datatable-tbody > tr > td { - text-align: start; - border-color: dt('datatable.body.cell.border.color'); - border-style: solid; - border-width: 0 0 1px 0; - padding: dt('datatable.body.cell.padding'); - } - - .p-datatable-hoverable .p-datatable-tbody > tr:not(.p-datatable-row-selected):hover { - background: dt('datatable.row.hover.background'); - color: dt('datatable.row.hover.color'); - } - - .p-datatable-tbody > tr.p-datatable-row-selected { - background: dt('datatable.row.selected.background'); - color: dt('datatable.row.selected.color'); - } - - .p-datatable-tbody > tr:has(+ .p-datatable-row-selected) > td { - border-block-end-color: dt('datatable.body.cell.selected.border.color'); - } - - .p-datatable-tbody > tr.p-datatable-row-selected > td { - border-block-end-color: dt('datatable.body.cell.selected.border.color'); - } - - .p-datatable-tbody > tr:focus-visible, - .p-datatable-tbody > tr.p-datatable-contextmenu-row-selected { - box-shadow: dt('datatable.row.focus.ring.shadow'); - outline: dt('datatable.row.focus.ring.width') dt('datatable.row.focus.ring.style') dt('datatable.row.focus.ring.color'); - outline-offset: dt('datatable.row.focus.ring.offset'); - } - - .p-datatable-tfoot > tr > td { - text-align: start; - padding: dt('datatable.footer.cell.padding'); - border-color: dt('datatable.footer.cell.border.color'); - border-style: solid; - border-width: 0 0 1px 0; - color: dt('datatable.footer.cell.color'); - background: dt('datatable.footer.cell.background'); - } - - .p-datatable-column-footer { - font-weight: dt('datatable.column.footer.font.weight'); - } - - .p-datatable-sortable-column { - cursor: pointer; - user-select: none; - outline-color: transparent; - } - - .p-datatable-column-title, - .p-datatable-sort-icon, - .p-datatable-sort-badge { - vertical-align: middle; - } - - .p-datatable-sort-icon { - color: dt('datatable.sort.icon.color'); - font-size: dt('datatable.sort.icon.size'); - width: dt('datatable.sort.icon.size'); - height: dt('datatable.sort.icon.size'); - transition: color dt('datatable.transition.duration'); - } - - .p-datatable-sortable-column:not(.p-datatable-column-sorted):hover { - background: dt('datatable.header.cell.hover.background'); - color: dt('datatable.header.cell.hover.color'); - } - - .p-datatable-sortable-column:not(.p-datatable-column-sorted):hover .p-datatable-sort-icon { - color: dt('datatable.sort.icon.hover.color'); - } - - .p-datatable-column-sorted { - background: dt('datatable.header.cell.selected.background'); - color: dt('datatable.header.cell.selected.color'); - } - - .p-datatable-column-sorted .p-datatable-sort-icon { - color: dt('datatable.header.cell.selected.color'); - } - - .p-datatable-sortable-column:focus-visible { - box-shadow: dt('datatable.header.cell.focus.ring.shadow'); - outline: dt('datatable.header.cell.focus.ring.width') dt('datatable.header.cell.focus.ring.style') dt('datatable.header.cell.focus.ring.color'); - outline-offset: dt('datatable.header.cell.focus.ring.offset'); - } - - .p-datatable-hoverable .p-datatable-selectable-row { - cursor: pointer; - } - - .p-datatable-tbody > tr.p-datatable-dragpoint-top > td { - box-shadow: inset 0 2px 0 0 dt('datatable.drop.point.color'); - } - - .p-datatable-tbody > tr.p-datatable-dragpoint-bottom > td { - box-shadow: inset 0 -2px 0 0 dt('datatable.drop.point.color'); - } - - .p-datatable-loading-icon { - font-size: dt('datatable.loading.icon.size'); - width: dt('datatable.loading.icon.size'); - height: dt('datatable.loading.icon.size'); - } - - .p-datatable-gridlines .p-datatable-header { - border-width: 1px 1px 0 1px; - } - - .p-datatable-gridlines .p-datatable-footer { - border-width: 0 1px 1px 1px; - } - - .p-datatable-gridlines .p-datatable-paginator-top { - border-width: 1px 1px 0 1px; - } - - .p-datatable-gridlines .p-datatable-paginator-bottom { - border-width: 0 1px 1px 1px; - } - - .p-datatable-gridlines .p-datatable-thead > tr > th { - border-width: 1px 0 1px 1px; - } - - .p-datatable-gridlines .p-datatable-thead > tr > th:last-child { - border-width: 1px; - } - - .p-datatable-gridlines .p-datatable-tbody > tr > td { - border-width: 1px 0 0 1px; - } - - .p-datatable-gridlines .p-datatable-tbody > tr > td:last-child { - border-width: 1px 1px 0 1px; - } - - .p-datatable-gridlines .p-datatable-tbody > tr:last-child > td { - border-width: 1px 0 1px 1px; - } - - .p-datatable-gridlines .p-datatable-tbody > tr:last-child > td:last-child { - border-width: 1px; - } - - .p-datatable-gridlines .p-datatable-tfoot > tr > td { - border-width: 1px 0 1px 1px; - } - - .p-datatable-gridlines .p-datatable-tfoot > tr > td:last-child { - border-width: 1px 1px 1px 1px; - } - - .p-datatable.p-datatable-gridlines .p-datatable-thead + .p-datatable-tfoot > tr > td { - border-width: 0 0 1px 1px; - } - - .p-datatable.p-datatable-gridlines .p-datatable-thead + .p-datatable-tfoot > tr > td:last-child { - border-width: 0 1px 1px 1px; - } - - .p-datatable.p-datatable-gridlines:has(.p-datatable-thead):has(.p-datatable-tbody) .p-datatable-tbody > tr > td { - border-width: 0 0 1px 1px; - } - - .p-datatable.p-datatable-gridlines:has(.p-datatable-thead):has(.p-datatable-tbody) .p-datatable-tbody > tr > td:last-child { - border-width: 0 1px 1px 1px; - } - - .p-datatable.p-datatable-gridlines:has(.p-datatable-tbody):has(.p-datatable-tfoot) .p-datatable-tbody > tr:last-child > td { - border-width: 0 0 0 1px; - } - - .p-datatable.p-datatable-gridlines:has(.p-datatable-tbody):has(.p-datatable-tfoot) .p-datatable-tbody > tr:last-child > td:last-child { - border-width: 0 1px 0 1px; - } - - .p-datatable.p-datatable-striped .p-datatable-tbody > tr.p-row-odd { - background: dt('datatable.row.striped.background'); - } - - .p-datatable.p-datatable-striped .p-datatable-tbody > tr.p-row-odd.p-datatable-row-selected { - background: dt('datatable.row.selected.background'); - color: dt('datatable.row.selected.color'); - } - - .p-datatable-striped.p-datatable-hoverable .p-datatable-tbody > tr:not(.p-datatable-row-selected):hover { - background: dt('datatable.row.hover.background'); - color: dt('datatable.row.hover.color'); - } - - .p-datatable.p-datatable-sm .p-datatable-header { - padding: dt('datatable.header.sm.padding'); - } - - .p-datatable.p-datatable-sm .p-datatable-thead > tr > th { - padding: dt('datatable.header.cell.sm.padding'); - } - - .p-datatable.p-datatable-sm .p-datatable-tbody > tr > td { - padding: dt('datatable.body.cell.sm.padding'); - } - - .p-datatable.p-datatable-sm .p-datatable-tfoot > tr > td { - padding: dt('datatable.footer.cell.sm.padding'); - } - - .p-datatable.p-datatable-sm .p-datatable-footer { - padding: dt('datatable.footer.sm.padding'); - } - - .p-datatable.p-datatable-lg .p-datatable-header { - padding: dt('datatable.header.lg.padding'); - } - - .p-datatable.p-datatable-lg .p-datatable-thead > tr > th { - padding: dt('datatable.header.cell.lg.padding'); - } - - .p-datatable.p-datatable-lg .p-datatable-tbody > tr > td { - padding: dt('datatable.body.cell.lg.padding'); - } - - .p-datatable.p-datatable-lg .p-datatable-tfoot > tr > td { - padding: dt('datatable.footer.cell.lg.padding'); - } - - .p-datatable.p-datatable-lg .p-datatable-footer { - padding: dt('datatable.footer.lg.padding'); - } - - .p-datatable-row-toggle-button { - display: inline-flex; - align-items: center; - justify-content: center; - overflow: hidden; - position: relative; - width: dt('datatable.row.toggle.button.size'); - height: dt('datatable.row.toggle.button.size'); - color: dt('datatable.row.toggle.button.color'); - border: 0 none; - background: transparent; - cursor: pointer; - border-radius: dt('datatable.row.toggle.button.border.radius'); - transition: - background dt('datatable.transition.duration'), - color dt('datatable.transition.duration'), - border-color dt('datatable.transition.duration'), - outline-color dt('datatable.transition.duration'), - box-shadow dt('datatable.transition.duration'); - outline-color: transparent; - user-select: none; - } - - .p-datatable-row-toggle-button:enabled:hover { - color: dt('datatable.row.toggle.button.hover.color'); - background: dt('datatable.row.toggle.button.hover.background'); - } - - .p-datatable-tbody > tr.p-datatable-row-selected .p-datatable-row-toggle-button:hover { - background: dt('datatable.row.toggle.button.selected.hover.background'); - color: dt('datatable.row.toggle.button.selected.hover.color'); - } - - .p-datatable-row-toggle-button:focus-visible { - box-shadow: dt('datatable.row.toggle.button.focus.ring.shadow'); - outline: dt('datatable.row.toggle.button.focus.ring.width') dt('datatable.row.toggle.button.focus.ring.style') dt('datatable.row.toggle.button.focus.ring.color'); - outline-offset: dt('datatable.row.toggle.button.focus.ring.offset'); - } - - .p-datatable-row-toggle-icon:dir(rtl) { - transform: rotate(180deg); - } -`,I2={root:function(t){var n=t.props;return["p-datatable p-component",{"p-datatable-hoverable":n.rowHover||n.selectionMode,"p-datatable-resizable":n.resizableColumns,"p-datatable-resizable-fit":n.resizableColumns&&n.columnResizeMode==="fit","p-datatable-scrollable":n.scrollable,"p-datatable-flex-scrollable":n.scrollable&&n.scrollHeight==="flex","p-datatable-striped":n.stripedRows,"p-datatable-gridlines":n.showGridlines,"p-datatable-sm":n.size==="small","p-datatable-lg":n.size==="large"}]},mask:"p-datatable-mask p-overlay-mask",loadingIcon:"p-datatable-loading-icon",header:"p-datatable-header",pcPaginator:function(t){var n=t.position;return"p-datatable-paginator-"+n},tableContainer:"p-datatable-table-container",table:function(t){var n=t.props;return["p-datatable-table",{"p-datatable-scrollable-table":n.scrollable,"p-datatable-resizable-table":n.resizableColumns,"p-datatable-resizable-table-fit":n.resizableColumns&&n.columnResizeMode==="fit"}]},thead:"p-datatable-thead",headerCell:function(t){var n=t.instance,o=t.props,i=t.column;return i&&!n.columnProp("hidden")&&(o.rowGroupMode!=="subheader"||o.groupRowsBy!==n.columnProp(i,"field"))?["p-datatable-header-cell",{"p-datatable-frozen-column":n.columnProp("frozen")}]:["p-datatable-header-cell",{"p-datatable-sortable-column":n.columnProp("sortable"),"p-datatable-resizable-column":n.resizableColumns,"p-datatable-column-sorted":n.isColumnSorted(),"p-datatable-frozen-column":n.columnProp("frozen"),"p-datatable-reorderable-column":o.reorderableColumns}]},columnResizer:"p-datatable-column-resizer",columnHeaderContent:"p-datatable-column-header-content",columnTitle:"p-datatable-column-title",columnFooter:"p-datatable-column-footer",sortIcon:"p-datatable-sort-icon",pcSortBadge:"p-datatable-sort-badge",filter:function(t){var n=t.props;return["p-datatable-filter",{"p-datatable-inline-filter":n.display==="row","p-datatable-popover-filter":n.display==="menu"}]},filterElementContainer:"p-datatable-filter-element-container",pcColumnFilterButton:"p-datatable-column-filter-button",pcColumnFilterClearButton:"p-datatable-column-filter-clear-button",filterOverlay:function(t){var n=t.props;return["p-datatable-filter-overlay p-component",{"p-datatable-filter-overlay-popover":n.display==="menu"}]},filterConstraintList:"p-datatable-filter-constraint-list",filterConstraint:function(t){var n=t.instance,o=t.matchMode;return["p-datatable-filter-constraint",{"p-datatable-filter-constraint-selected":o&&n.isRowMatchModeSelected(o.value)}]},filterConstraintSeparator:"p-datatable-filter-constraint-separator",filterOperator:"p-datatable-filter-operator",pcFilterOperatorDropdown:"p-datatable-filter-operator-dropdown",filterRuleList:"p-datatable-filter-rule-list",filterRule:"p-datatable-filter-rule",pcFilterConstraintDropdown:"p-datatable-filter-constraint-dropdown",pcFilterRemoveRuleButton:"p-datatable-filter-remove-rule-button",pcFilterAddRuleButton:"p-datatable-filter-add-rule-button",filterButtonbar:"p-datatable-filter-buttonbar",pcFilterClearButton:"p-datatable-filter-clear-button",pcFilterApplyButton:"p-datatable-filter-apply-button",tbody:function(t){var n=t.props;return n.frozenRow?"p-datatable-tbody p-datatable-frozen-tbody":"p-datatable-tbody"},rowGroupHeader:"p-datatable-row-group-header",rowToggleButton:"p-datatable-row-toggle-button",rowToggleIcon:"p-datatable-row-toggle-icon",row:function(t){var n=t.instance,o=t.props,i=t.index,r=t.columnSelectionMode,a=[];return o.selectionMode&&a.push("p-datatable-selectable-row"),o.selection&&a.push({"p-datatable-row-selected":r?n.isSelected&&n.$parentInstance.$parentInstance.highlightOnSelect:n.isSelected}),o.contextMenuSelection&&a.push({"p-datatable-contextmenu-row-selected":n.isSelectedWithContextMenu}),a.push(i%2===0?"p-row-even":"p-row-odd"),a},rowExpansion:"p-datatable-row-expansion",rowGroupFooter:"p-datatable-row-group-footer",emptyMessage:"p-datatable-empty-message",bodyCell:function(t){var n=t.instance;return[{"p-datatable-frozen-column":n.columnProp("frozen")}]},reorderableRowHandle:"p-datatable-reorderable-row-handle",pcRowEditorInit:"p-datatable-row-editor-init",pcRowEditorSave:"p-datatable-row-editor-save",pcRowEditorCancel:"p-datatable-row-editor-cancel",tfoot:"p-datatable-tfoot",footerCell:function(t){var n=t.instance;return[{"p-datatable-frozen-column":n.columnProp("frozen")}]},virtualScrollerSpacer:"p-datatable-virtualscroller-spacer",footer:"p-datatable-footer",columnResizeIndicator:"p-datatable-column-resize-indicator",rowReorderIndicatorUp:"p-datatable-row-reorder-indicator-up",rowReorderIndicatorDown:"p-datatable-row-reorder-indicator-down"},T2={tableContainer:{overflow:"auto"},thead:{position:"sticky"},tfoot:{position:"sticky"}},R2=fe.extend({name:"datatable",style:P2,classes:I2,inlineStyles:T2}),Hp={name:"BarsIcon",extends:Te};function O2(e){return _2(e)||L2(e)||A2(e)||E2()}function E2(){throw new TypeError(`Invalid attempt to spread non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function A2(e,t){if(e){if(typeof e=="string")return Al(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Al(e,t):void 0}}function L2(e){if(typeof Symbol<"u"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function _2(e){if(Array.isArray(e))return Al(e)}function Al(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);n .p-radiobutton-box { - border-color: dt('radiobutton.invalid.border.color'); - } - - .p-radiobutton.p-variant-filled .p-radiobutton-box { - background: dt('radiobutton.filled.background'); - } - - .p-radiobutton.p-variant-filled.p-radiobutton-checked .p-radiobutton-box { - background: dt('radiobutton.checked.background'); - } - - .p-radiobutton.p-variant-filled:not(.p-disabled):has(.p-radiobutton-input:hover).p-radiobutton-checked .p-radiobutton-box { - background: dt('radiobutton.checked.hover.background'); - } - - .p-radiobutton.p-disabled { - opacity: 1; - } - - .p-radiobutton.p-disabled .p-radiobutton-box { - background: dt('radiobutton.disabled.background'); - border-color: dt('radiobutton.checked.disabled.border.color'); - } - - .p-radiobutton-checked.p-disabled .p-radiobutton-box .p-radiobutton-icon { - background: dt('radiobutton.icon.disabled.color'); - } - - .p-radiobutton-sm, - .p-radiobutton-sm .p-radiobutton-box { - width: dt('radiobutton.sm.width'); - height: dt('radiobutton.sm.height'); - } - - .p-radiobutton-sm .p-radiobutton-icon { - font-size: dt('radiobutton.icon.sm.size'); - width: dt('radiobutton.icon.sm.size'); - height: dt('radiobutton.icon.sm.size'); - } - - .p-radiobutton-lg, - .p-radiobutton-lg .p-radiobutton-box { - width: dt('radiobutton.lg.width'); - height: dt('radiobutton.lg.height'); - } - - .p-radiobutton-lg .p-radiobutton-icon { - font-size: dt('radiobutton.icon.lg.size'); - width: dt('radiobutton.icon.lg.size'); - height: dt('radiobutton.icon.lg.size'); - } -`,U2={root:function(t){var n=t.instance,o=t.props;return["p-radiobutton p-component",{"p-radiobutton-checked":n.checked,"p-disabled":o.disabled,"p-invalid":n.$pcRadioButtonGroup?n.$pcRadioButtonGroup.$invalid:n.$invalid,"p-variant-filled":n.$variant==="filled","p-radiobutton-sm p-inputfield-sm":o.size==="small","p-radiobutton-lg p-inputfield-lg":o.size==="large"}]},box:"p-radiobutton-box",input:"p-radiobutton-input",icon:"p-radiobutton-icon"},H2=fe.extend({name:"radiobutton",style:V2,classes:U2}),G2={name:"BaseRadioButton",extends:Jn,props:{value:null,binary:Boolean,readonly:{type:Boolean,default:!1},tabindex:{type:Number,default:null},inputId:{type:String,default:null},inputClass:{type:[String,Object],default:null},inputStyle:{type:Object,default:null},ariaLabelledby:{type:String,default:null},ariaLabel:{type:String,default:null}},style:H2,provide:function(){return{$pcRadioButton:this,$parentInstance:this}}};function _r(e){"@babel/helpers - typeof";return _r=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},_r(e)}function K2(e,t,n){return(t=W2(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function W2(e){var t=q2(e,"string");return _r(t)=="symbol"?t:t+""}function q2(e,t){if(_r(e)!="object"||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var o=n.call(e,t);if(_r(o)!="object")return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return(t==="string"?String:Number)(e)}var Kp={name:"RadioButton",extends:G2,inheritAttrs:!1,emits:["change","focus","blur"],inject:{$pcRadioButtonGroup:{default:void 0}},methods:{getPTOptions:function(t){var n=t==="root"?this.ptmi:this.ptm;return n(t,{context:{checked:this.checked,disabled:this.disabled}})},onChange:function(t){if(!this.disabled&&!this.readonly){var n=this.binary?!this.checked:this.value;this.$pcRadioButtonGroup?this.$pcRadioButtonGroup.writeValue(n,t):this.writeValue(n,t),this.$emit("change",t)}},onFocus:function(t){this.$emit("focus",t)},onBlur:function(t){var n,o;this.$emit("blur",t),(n=(o=this.formField).onBlur)===null||n===void 0||n.call(o,t)}},computed:{groupName:function(){return this.$pcRadioButtonGroup?this.$pcRadioButtonGroup.groupName:this.$formName},checked:function(){var t=this.$pcRadioButtonGroup?this.$pcRadioButtonGroup.d_value:this.d_value;return t!=null&&(this.binary?!!t:Xn(t,this.value))},dataP:function(){return Me(K2({invalid:this.$invalid,checked:this.checked,disabled:this.disabled,filled:this.$variant==="filled"},this.size,this.size))}}},Q2=["data-p-checked","data-p-disabled","data-p"],Z2=["id","value","name","checked","tabindex","disabled","readonly","aria-labelledby","aria-label","aria-invalid"],Y2=["data-p"],X2=["data-p"];function J2(e,t,n,o,i,r){return g(),b("div",m({class:e.cx("root")},r.getPTOptions("root"),{"data-p-checked":r.checked,"data-p-disabled":e.disabled,"data-p":r.dataP}),[h("input",m({id:e.inputId,type:"radio",class:[e.cx("input"),e.inputClass],style:e.inputStyle,value:e.value,name:r.groupName,checked:r.checked,tabindex:e.tabindex,disabled:e.disabled,readonly:e.readonly,"aria-labelledby":e.ariaLabelledby,"aria-label":e.ariaLabel,"aria-invalid":e.invalid||void 0,onFocus:t[0]||(t[0]=function(){return r.onFocus&&r.onFocus.apply(r,arguments)}),onBlur:t[1]||(t[1]=function(){return r.onBlur&&r.onBlur.apply(r,arguments)}),onChange:t[2]||(t[2]=function(){return r.onChange&&r.onChange.apply(r,arguments)})},r.getPTOptions("input")),null,16,Z2),h("div",m({class:e.cx("box")},r.getPTOptions("box"),{"data-p":r.dataP}),[h("div",m({class:e.cx("icon")},r.getPTOptions("icon"),{"data-p":r.dataP}),null,16,X2)],16,Y2)],16,Q2)}Kp.render=J2;var Wp={name:"FilterIcon",extends:Te};function ek(e){return rk(e)||ok(e)||nk(e)||tk()}function tk(){throw new TypeError(`Invalid attempt to spread non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function nk(e,t){if(e){if(typeof e=="string")return _l(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?_l(e,t):void 0}}function ok(e){if(typeof Symbol<"u"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function rk(e){if(Array.isArray(e))return _l(e)}function _l(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);n3?(se=De===ue)&&(q=ne[(z=ne[4])?5:(z=3,3)],ne[4]=ne[5]=e):ne[0]<=ge&&((se=pe<2&&geue||ue>De)&&(ne[4]=pe,ne[5]=ue,j.n=De,z=0))}if(se||pe>1)return a;throw X=!0,ue}return function(pe,ue,se){if(H>1)throw TypeError("Generator is already running");for(X&&ue===1&&le(ue,se),z=ue,q=se;(t=z<2?e:q)||!X;){K||(z?z<3?(z>1&&(j.n=-1),le(z,q)):j.n=q:j.v=q);try{if(H=2,K){if(z||(pe="next"),t=K[pe]){if(!(t=t.call(K,q)))throw TypeError("iterator result is not an object");if(!t.done)return t;q=t.value,z<2&&(z=0)}else z===1&&(t=K.return)&&t.call(K),z<2&&(q=TypeError("The iterator does not provide a '"+pe+"' method"),z=1);K=e}else if((t=(X=j.n<0)?q:L.call(k,j))!==a)break}catch(ne){K=e,z=1,q=ne}finally{H=1}}return{value:t,done:X}}}(p,C,S),!0),P}var a={};function l(){}function s(){}function d(){}t=Object.getPrototypeOf;var u=[][o]?t(t([][o]())):(wt(t={},o,function(){return this}),t),c=d.prototype=l.prototype=Object.create(u);function f(p){return Object.setPrototypeOf?Object.setPrototypeOf(p,d):(p.__proto__=d,wt(p,i,"GeneratorFunction")),p.prototype=Object.create(c),p}return s.prototype=d,wt(c,"constructor",d),wt(d,"constructor",s),s.displayName="GeneratorFunction",wt(d,i,"GeneratorFunction"),wt(c),wt(c,i,"Generator"),wt(c,o,function(){return this}),wt(c,"toString",function(){return"[object Generator]"}),(Vo=function(){return{w:r,m:f}})()}function wt(e,t,n,o){var i=Object.defineProperty;try{i({},"",{})}catch{i=0}wt=function(a,l,s,d){function u(c,f){wt(a,c,function(p){return this._invoke(c,f,p)})}l?i?i(a,l,{value:s,enumerable:!d,configurable:!d,writable:!d}):a[l]=s:(u("next",0),u("throw",1),u("return",2))},wt(e,t,n,o)}function yu(e,t,n,o,i,r,a){try{var l=e[r](a),s=l.value}catch(d){return void n(d)}l.done?t(s):Promise.resolve(s).then(o,i)}function vu(e){return function(){var t=this,n=arguments;return new Promise(function(o,i){var r=e.apply(t,n);function a(s){yu(r,o,i,a,l,"next",s)}function l(s){yu(r,o,i,a,l,"throw",s)}a(void 0)})}}var th={name:"BodyCell",hostName:"DataTable",extends:ye,emits:["cell-edit-init","cell-edit-complete","cell-edit-cancel","row-edit-init","row-edit-save","row-edit-cancel","row-toggle","radio-change","checkbox-change","editing-meta-change"],props:{rowData:{type:Object,default:null},column:{type:Object,default:null},frozenRow:{type:Boolean,default:!1},rowIndex:{type:Number,default:null},index:{type:Number,default:null},isRowExpanded:{type:Boolean,default:!1},selected:{type:Boolean,default:!1},editing:{type:Boolean,default:!1},editingMeta:{type:Object,default:null},editMode:{type:String,default:null},virtualScrollerContentProps:{type:Object,default:null},ariaControls:{type:String,default:null},name:{type:String,default:null},expandedRowIcon:{type:String,default:null},collapsedRowIcon:{type:String,default:null},editButtonProps:{type:Object,default:null}},documentEditListener:null,selfClick:!1,overlayEventListener:null,editCompleteTimeout:null,data:function(){return{d_editing:this.editing,styleObject:{}}},watch:{editing:function(t){this.d_editing=t},"$data.d_editing":function(t){this.$emit("editing-meta-change",{data:this.rowData,field:this.field||"field_".concat(this.index),index:this.rowIndex,editing:t})}},mounted:function(){this.columnProp("frozen")&&this.updateStickyPosition()},updated:function(){var t=this;this.columnProp("frozen")&&this.updateStickyPosition(),this.d_editing&&(this.editMode==="cell"||this.editMode==="row"&&this.columnProp("rowEditor"))&&setTimeout(function(){var n=Nn(t.$el);n&&n.focus()},1)},beforeUnmount:function(){this.overlayEventListener&&(un.off("overlay-click",this.overlayEventListener),this.overlayEventListener=null)},methods:{columnProp:function(t){return An(this.column,t)},getColumnPT:function(t){var n,o,i={props:this.column.props,parent:{instance:this,props:this.$props,state:this.$data},context:{index:this.index,size:(n=this.$parentInstance)===null||n===void 0||(n=n.$parentInstance)===null||n===void 0?void 0:n.size,showGridlines:(o=this.$parentInstance)===null||o===void 0||(o=o.$parentInstance)===null||o===void 0?void 0:o.showGridlines}};return m(this.ptm("column.".concat(t),{column:i}),this.ptm("column.".concat(t),i),this.ptmo(this.getColumnProp(),t,i))},getColumnProp:function(){return this.column.props&&this.column.props.pt?this.column.props.pt:void 0},resolveFieldData:function(){return Ce(this.rowData,this.field)},toggleRow:function(t){this.$emit("row-toggle",{originalEvent:t,data:this.rowData})},toggleRowWithRadio:function(t,n){this.$emit("radio-change",{originalEvent:t.originalEvent,index:n,data:t.data})},toggleRowWithCheckbox:function(t,n){this.$emit("checkbox-change",{originalEvent:t.originalEvent,index:n,data:t.data})},isEditable:function(){return this.column.children&&this.column.children.editor!=null},bindDocumentEditListener:function(){var t=this;this.documentEditListener||(this.documentEditListener=function(n){t.selfClick=t.$el&&t.$el.contains(n.target),t.editCompleteTimeout&&clearTimeout(t.editCompleteTimeout),t.selfClick||(t.editCompleteTimeout=setTimeout(function(){t.completeEdit(n,"outside")},1))},document.addEventListener("mousedown",this.documentEditListener))},unbindDocumentEditListener:function(){this.documentEditListener&&(document.removeEventListener("mousedown",this.documentEditListener),this.documentEditListener=null,this.selfClick=!1,this.editCompleteTimeout&&(clearTimeout(this.editCompleteTimeout),this.editCompleteTimeout=null))},switchCellToViewMode:function(){this.d_editing=!1,this.unbindDocumentEditListener(),un.off("overlay-click",this.overlayEventListener),this.overlayEventListener=null},onClick:function(t){var n=this;this.editMode==="cell"&&this.isEditable()&&(this.d_editing||(this.d_editing=!0,this.bindDocumentEditListener(),this.$emit("cell-edit-init",{originalEvent:t,data:this.rowData,field:this.field,index:this.rowIndex}),this.overlayEventListener=function(o){n.selfClick=n.$el&&n.$el.contains(o.target)},un.on("overlay-click",this.overlayEventListener)))},completeEdit:function(t,n){var o={originalEvent:t,data:this.rowData,newData:this.editingRowData,value:this.rowData[this.field],newValue:this.editingRowData[this.field],field:this.field,index:this.rowIndex,type:n,defaultPrevented:!1,preventDefault:function(){this.defaultPrevented=!0}};this.$emit("cell-edit-complete",o),o.defaultPrevented||this.switchCellToViewMode()},onKeyDown:function(t){if(this.editMode==="cell")switch(t.code){case"Enter":case"NumpadEnter":this.completeEdit(t,"enter");break;case"Escape":this.switchCellToViewMode(),this.$emit("cell-edit-cancel",{originalEvent:t,data:this.rowData,field:this.field,index:this.rowIndex});break;case"Tab":this.completeEdit(t,"tab"),t.shiftKey?this.moveToPreviousCell(t):this.moveToNextCell(t);break}},moveToPreviousCell:function(t){var n=this;return vu(Vo().m(function o(){var i,r;return Vo().w(function(a){for(;;)switch(a.n){case 0:if(i=n.findCell(t.target),r=n.findPreviousEditableColumn(i),!r){a.n=2;break}return a.n=1,n.$nextTick();case 1:Rd(r,"click"),t.preventDefault();case 2:return a.a(2)}},o)}))()},moveToNextCell:function(t){var n=this;return vu(Vo().m(function o(){var i,r;return Vo().w(function(a){for(;;)switch(a.n){case 0:if(i=n.findCell(t.target),r=n.findNextEditableColumn(i),!r){a.n=2;break}return a.n=1,n.$nextTick();case 1:Rd(r,"click"),t.preventDefault();case 2:return a.a(2)}},o)}))()},findCell:function(t){if(t){for(var n=t;n&&!Ke(n,"data-p-cell-editing");)n=n.parentElement;return n}else return null},findPreviousEditableColumn:function(t){var n=t.previousElementSibling;if(!n){var o=t.parentElement.previousElementSibling;o&&(n=o.lastElementChild)}return n?Ke(n,"data-p-editable-column")?n:this.findPreviousEditableColumn(n):null},findNextEditableColumn:function(t){var n=t.nextElementSibling;if(!n){var o=t.parentElement.nextElementSibling;o&&(n=o.firstElementChild)}return n?Ke(n,"data-p-editable-column")?n:this.findNextEditableColumn(n):null},onRowEditInit:function(t){this.$emit("row-edit-init",{originalEvent:t,data:this.rowData,newData:this.editingRowData,field:this.field,index:this.rowIndex})},onRowEditSave:function(t){this.$emit("row-edit-save",{originalEvent:t,data:this.rowData,newData:this.editingRowData,field:this.field,index:this.rowIndex})},onRowEditCancel:function(t){this.$emit("row-edit-cancel",{originalEvent:t,data:this.rowData,newData:this.editingRowData,field:this.field,index:this.rowIndex})},editorInitCallback:function(t){this.$emit("row-edit-init",{originalEvent:t,data:this.rowData,newData:this.editingRowData,field:this.field,index:this.rowIndex})},editorSaveCallback:function(t){this.editMode==="row"?this.$emit("row-edit-save",{originalEvent:t,data:this.rowData,newData:this.editingRowData,field:this.field,index:this.rowIndex}):this.completeEdit(t,"enter")},editorCancelCallback:function(t){this.editMode==="row"?this.$emit("row-edit-cancel",{originalEvent:t,data:this.rowData,newData:this.editingRowData,field:this.field,index:this.rowIndex}):(this.switchCellToViewMode(),this.$emit("cell-edit-cancel",{originalEvent:t,data:this.rowData,field:this.field,index:this.rowIndex}))},updateStickyPosition:function(){if(this.columnProp("frozen")){var t=this.columnProp("alignFrozen");if(t==="right"){var n=0,o=ra(this.$el,'[data-p-frozen-column="true"]');o&&(n=nt(o)+parseFloat(o.style["inset-inline-end"]||0)),this.styleObject.insetInlineEnd=n+"px"}else{var i=0,r=ia(this.$el,'[data-p-frozen-column="true"]');r&&(i=nt(r)+parseFloat(r.style["inset-inline-start"]||0)),this.styleObject.insetInlineStart=i+"px"}}},getVirtualScrollerProp:function(t){return this.virtualScrollerContentProps?this.virtualScrollerContentProps[t]:null}},computed:{editingRowData:function(){return this.editingMeta[this.rowIndex]?this.editingMeta[this.rowIndex].data:this.rowData},field:function(){return this.columnProp("field")},containerClass:function(){return[this.columnProp("bodyClass"),this.columnProp("class"),this.cx("bodyCell")]},containerStyle:function(){var t=this.columnProp("bodyStyle"),n=this.columnProp("style");return this.columnProp("frozen")?[n,t,this.styleObject]:[n,t]},loading:function(){return this.getVirtualScrollerProp("loading")},loadingOptions:function(){var t=this.getVirtualScrollerProp("getLoaderOptions");return t&&t(this.rowIndex,{cellIndex:this.index,cellFirst:this.index===0,cellLast:this.index===this.getVirtualScrollerProp("columns").length-1,cellEven:this.index%2===0,cellOdd:this.index%2!==0,column:this.column,field:this.field})},expandButtonAriaLabel:function(){return this.$primevue.config.locale.aria?this.isRowExpanded?this.$primevue.config.locale.aria.expandRow:this.$primevue.config.locale.aria.collapseRow:void 0},initButtonAriaLabel:function(){return this.$primevue.config.locale.aria?this.$primevue.config.locale.aria.editRow:void 0},saveButtonAriaLabel:function(){return this.$primevue.config.locale.aria?this.$primevue.config.locale.aria.saveEdit:void 0},cancelButtonAriaLabel:function(){return this.$primevue.config.locale.aria?this.$primevue.config.locale.aria.cancelEdit:void 0}},components:{DTRadioButton:eh,DTCheckbox:Jp,Button:xt,ChevronDownIcon:sa,ChevronRightIcon:As,BarsIcon:Hp,PencilIcon:Gp,CheckIcon:Oo,TimesIcon:to},directives:{ripple:en}};function Br(e){"@babel/helpers - typeof";return Br=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Br(e)}function wu(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),n.push.apply(n,o)}return n}function mi(e){for(var t=1;t=e.length?{done:!0}:{done:!1,value:e[o++]}},e:function(d){throw d},f:i}}throw new TypeError(`Invalid attempt to iterate non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var r,a=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var d=n.next();return a=d.done,d},e:function(d){l=!0,r=d},f:function(){try{a||n.return==null||n.return()}finally{if(l)throw r}}}}function d5(e,t){if(e){if(typeof e=="string")return Cu(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Cu(e,t):void 0}}function Cu(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);n-1:this.groupRowsBy===n:!1},findIndexInSelection:function(t){return this.findIndex(t,this.selection)},findIndex:function(t,n){var o=-1;if(n&&n.length){for(var i=0;i-1:!1},isRowGroupExpanded:function(){if(this.expandableRowGroups&&this.expandedRowGroups){var t=Ce(this.rowData,this.groupRowsBy);return this.expandedRowGroups.indexOf(t)>-1}return!1},isSelected:function(){return this.rowData&&this.selection?this.dataKey?this.selectionKeys?this.selectionKeys[Ce(this.rowData,this.dataKey)]!==void 0:!1:this.selection instanceof Array?this.findIndexInSelection(this.rowData)>-1:this.equals(this.rowData,this.selection):!1},isSelectedWithContextMenu:function(){return this.rowData&&this.contextMenuSelection?this.equals(this.rowData,this.contextMenuSelection,this.dataKey):!1},shouldRenderRowGroupHeader:function(){var t=Ce(this.rowData,this.groupRowsBy),n=this.value[this.rowIndex-1];if(n){var o=Ce(n,this.groupRowsBy);return t!==o}else return!0},shouldRenderRowGroupFooter:function(){if(this.expandableRowGroups&&!this.isRowGroupExpanded)return!1;var t=Ce(this.rowData,this.groupRowsBy),n=this.value[this.rowIndex+1];if(n){var o=Ce(n,this.groupRowsBy);return t!==o}else return!0},columnsLength:function(){var t=this;if(this.columns){var n=0;return this.columns.forEach(function(o){t.columnProp(o,"hidden")&&n++}),this.columns.length-n}return 0}},components:{DTBodyCell:th,ChevronDownIcon:sa,ChevronRightIcon:As}};function zr(e){"@babel/helpers - typeof";return zr=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},zr(e)}function xu(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),n.push.apply(n,o)}return n}function vn(e){for(var t=1;t=e.length?{done:!0}:{done:!1,value:e[o++]}},e:function(d){throw d},f:i}}throw new TypeError(`Invalid attempt to iterate non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var r,a=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var d=n.next();return a=d.done,d},e:function(d){l=!0,r=d},f:function(){try{a||n.return==null||n.return()}finally{if(l)throw r}}}}function E5(e,t){if(e){if(typeof e=="string")return Iu(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Iu(e,t):void 0}}function Iu(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);n1},removeRuleButtonLabel:function(){return this.$primevue.config.locale?this.$primevue.config.locale.removeRule:void 0},addRuleButtonLabel:function(){return this.$primevue.config.locale?this.$primevue.config.locale.addRule:void 0},isShowAddConstraint:function(){return this.showAddButton&&this.filters[this.field].operator&&this.fieldConstraints&&this.fieldConstraints.length-1?t:t+1},isMultiSorted:function(){return this.sortMode==="multiple"&&this.columnProp("sortable")&&this.getMultiSortMetaIndex()>-1},isColumnSorted:function(){return this.sortMode==="single"?this.sortField&&(this.sortField===this.columnProp("field")||this.sortField===this.columnProp("sortField")):this.isMultiSorted()},updateStickyPosition:function(){if(this.columnProp("frozen")){var t=this.columnProp("alignFrozen");if(t==="right"){var n=0,o=ra(this.$el,'[data-p-frozen-column="true"]');o&&(n=nt(o)+parseFloat(o.style["inset-inline-end"]||0)),this.styleObject.insetInlineEnd=n+"px"}else{var i=0,r=ia(this.$el,'[data-p-frozen-column="true"]');r&&(i=nt(r)+parseFloat(r.style["inset-inline-start"]||0)),this.styleObject.insetInlineStart=i+"px"}var a=this.$el.parentElement.nextElementSibling;if(a){var l=Ti(this.$el);a.children[l]&&(a.children[l].style["inset-inline-start"]=this.styleObject["inset-inline-start"],a.children[l].style["inset-inline-end"]=this.styleObject["inset-inline-end"])}}},onHeaderCheckboxChange:function(t){this.$emit("checkbox-change",t)}},computed:{containerClass:function(){return[this.cx("headerCell"),this.filterColumn?this.columnProp("filterHeaderClass"):this.columnProp("headerClass"),this.columnProp("class")]},containerStyle:function(){var t=this.filterColumn?this.columnProp("filterHeaderStyle"):this.columnProp("headerStyle"),n=this.columnProp("style");return this.columnProp("frozen")?[n,t,this.styleObject]:[n,t]},sortState:function(){var t=!1,n=null;if(this.sortMode==="single")t=this.sortField&&(this.sortField===this.columnProp("field")||this.sortField===this.columnProp("sortField")),n=t?this.sortOrder:0;else if(this.sortMode==="multiple"){var o=this.getMultiSortMetaIndex();o>-1&&(t=!0,n=this.multiSortMeta[o].order)}return{sorted:t,sortOrder:n}},sortableColumnIcon:function(){var t=this.sortState,n=t.sorted,o=t.sortOrder;if(n){if(n&&o>0)return Ul;if(n&&o<0)return Nl}else return Fl;return null},ariaSort:function(){if(this.columnProp("sortable")){var t=this.sortState,n=t.sorted,o=t.sortOrder;return n&&o<0?"descending":n&&o>0?"ascending":"none"}else return null}},components:{Badge:oi,DTHeaderCheckbox:_s,DTColumnFilter:Ls,SortAltIcon:Fl,SortAmountUpAltIcon:Ul,SortAmountDownIcon:Nl}};function Hr(e){"@babel/helpers - typeof";return Hr=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Hr(e)}function Lu(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),n.push.apply(n,o)}return n}function _u(e){for(var t=1;t=e.length?{done:!0}:{done:!1,value:e[o++]}},e:function(d){throw d},f:i}}throw new TypeError(`Invalid attempt to iterate non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var r,a=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var d=n.next();return a=d.done,d},e:function(d){l=!0,r=d},f:function(){try{a||n.return==null||n.return()}finally{if(l)throw r}}}}function Be(e){return yS(e)||bS(e)||Ds(e)||mS()}function mS(){throw new TypeError(`Invalid attempt to spread non-iterable instance. -In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function Ds(e,t){if(e){if(typeof e=="string")return Gl(e,t);var n={}.toString.call(e).slice(8,-1);return n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set"?Array.from(e):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Gl(e,t):void 0}}function bS(e){if(typeof Symbol<"u"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function yS(e){if(Array.isArray(e))return Gl(e)}function Gl(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);no?this.multisortField(t,n,o+1):0:Bd(i,r,this.d_multiSortMeta[o].order,a,this.d_nullSortOrder)},addMultiSortField:function(t){var n=this.d_multiSortMeta.findIndex(function(o){return o.field===t});n>=0?this.removableSort&&this.d_multiSortMeta[n].order*-1===this.defaultSortOrder?this.d_multiSortMeta.splice(n,1):this.d_multiSortMeta[n]={field:t,order:this.d_multiSortMeta[n].order*-1}:this.d_multiSortMeta.push({field:t,order:this.defaultSortOrder}),this.d_multiSortMeta=Be(this.d_multiSortMeta)},getActiveFilters:function(t){var n=function(a){var l=Mu(a,2),s=l[0],d=l[1];if(d.constraints){var u=d.constraints.filter(function(c){return c.value!==null});if(u.length>0)return[s,vt(vt({},d),{},{constraints:u})]}else if(d.value!==null)return[s,d]},o=function(a){return a!==void 0},i=Object.entries(t).map(n).filter(o);return Object.fromEntries(i)},filter:function(t){var n=this;if(t){this.clearEditingMetaData();var o=this.getActiveFilters(this.filters),i;o.global&&(i=this.globalFilterFields||this.columns.map(function(k){return n.columnProp(k,"filterField")||n.columnProp(k,"field")}));for(var r=[],a=0;a=a.length?a.length-1:o+1;this.onRowClick({originalEvent:t,data:a[l],index:l})}t.preventDefault()},onArrowUpKey:function(t,n,o,i){var r=this.findPrevSelectableRow(n);if(r&&this.focusRowChange(n,r),t.shiftKey){var a=this.dataToRender(i.rows),l=o-1<=0?0:o-1;this.onRowClick({originalEvent:t,data:a[l],index:l})}t.preventDefault()},onHomeKey:function(t,n,o,i){var r=this.findFirstSelectableRow();if(r&&this.focusRowChange(n,r),t.ctrlKey&&t.shiftKey){var a=this.dataToRender(i.rows);this.$emit("update:selection",a.slice(0,o+1))}t.preventDefault()},onEndKey:function(t,n,o,i){var r=this.findLastSelectableRow();if(r&&this.focusRowChange(n,r),t.ctrlKey&&t.shiftKey){var a=this.dataToRender(i.rows);this.$emit("update:selection",a.slice(o,a.length))}t.preventDefault()},onEnterKey:function(t,n,o){this.onRowClick({originalEvent:t,data:n,index:o}),t.preventDefault()},onSpaceKey:function(t,n,o,i){if(this.onEnterKey(t,n,o),t.shiftKey&&this.selection!==null){var r=this.dataToRender(i.rows),a;if(this.selection.length>0){var l,s;l=Ta(this.selection[0],r),s=Ta(this.selection[this.selection.length-1],r),a=o<=l?s:l}else a=Ta(this.selection,r);var d=a!==o?r.slice(Math.min(a,o),Math.max(a,o)+1):n;this.$emit("update:selection",d)}},onTabKey:function(t,n){var o=this.$refs.bodyRef&&this.$refs.bodyRef.$el,i=lo(o,'tr[data-p-selectable-row="true"]');if(t.code==="Tab"&&i&&i.length>0){var r=In(o,'tr[data-p-selected="true"]'),a=In(o,'tr[data-p-selectable-row="true"][tabindex="0"]');r?(r.tabIndex="0",a&&a!==r&&(a.tabIndex="-1")):(i[0].tabIndex="0",a!==i[0]&&i[n]&&(i[n].tabIndex="-1"))}},findNextSelectableRow:function(t){var n=t.nextElementSibling;return n?Ke(n,"data-p-selectable-row")===!0?n:this.findNextSelectableRow(n):null},findPrevSelectableRow:function(t){var n=t.previousElementSibling;return n?Ke(n,"data-p-selectable-row")===!0?n:this.findPrevSelectableRow(n):null},findFirstSelectableRow:function(){var t=In(this.$refs.table,'tr[data-p-selectable-row="true"]');return t},findLastSelectableRow:function(){var t=lo(this.$refs.table,'tr[data-p-selectable-row="true"]');return t?t[t.length-1]:null},focusRowChange:function(t,n){t.tabIndex="-1",n.tabIndex="0",Xe(n)},toggleRowWithRadio:function(t){var n=t.data;this.isSelected(n)?(this.$emit("update:selection",null),this.$emit("row-unselect",{originalEvent:t.originalEvent,data:n,index:t.index,type:"radiobutton"})):(this.$emit("update:selection",n),this.$emit("row-select",{originalEvent:t.originalEvent,data:n,index:t.index,type:"radiobutton"}))},toggleRowWithCheckbox:function(t){var n=t.data;if(this.isSelected(n)){var o=this.findIndexInSelection(n),i=this.selection.filter(function(a,l){return l!=o});this.$emit("update:selection",i),this.$emit("row-unselect",{originalEvent:t.originalEvent,data:n,index:t.index,type:"checkbox"})}else{var r=this.selection?Be(this.selection):[];r=[].concat(Be(r),[n]),this.$emit("update:selection",r),this.$emit("row-select",{originalEvent:t.originalEvent,data:n,index:t.index,type:"checkbox"})}},toggleRowsWithCheckbox:function(t){if(this.selectAll!==null)this.$emit("select-all-change",t);else{var n=t.originalEvent,o=t.checked,i=[];o?(i=this.frozenValue?[].concat(Be(this.frozenValue),Be(this.processedData)):this.processedData,this.$emit("row-select-all",{originalEvent:n,data:i})):this.$emit("row-unselect-all",{originalEvent:n}),this.$emit("update:selection",i)}},isSingleSelectionMode:function(){return this.selectionMode==="single"},isMultipleSelectionMode:function(){return this.selectionMode==="multiple"},isSelected:function(t){return t&&this.selection?this.dataKey?this.d_selectionKeys?this.d_selectionKeys[Ce(t,this.dataKey)]!==void 0:!1:this.selection instanceof Array?this.findIndexInSelection(t)>-1:this.equals(t,this.selection):!1},findIndexInSelection:function(t){return this.findIndex(t,this.selection)},findIndex:function(t,n){var o=-1;if(n&&n.length){for(var i=0;ithis.anchorRowIndex?(n=this.anchorRowIndex,o=this.rangeRowIndex):this.rangeRowIndexparseInt(i,10)){if(this.columnResizeMode==="fit"){var r=this.resizeColumnElement.nextElementSibling,a=r.offsetWidth-t;o>15&&a>15&&this.resizeTableCells(o,a)}else if(this.columnResizeMode==="expand"){var l=this.$refs.table.offsetWidth+t+"px",s=function(f){f&&(f.style.width=f.style.minWidth=l)};if(this.resizeTableCells(o),s(this.$refs.table),!this.virtualScrollerDisabled){var d=this.$refs.bodyRef&&this.$refs.bodyRef.$el,u=this.$refs.frozenBodyRef&&this.$refs.frozenBodyRef.$el;s(d),s(u)}}this.$emit("column-resize-end",{element:this.resizeColumnElement,delta:t})}this.$refs.resizeHelper.style.display="none",this.resizeColumn=null,this.$el.removeAttribute("data-p-unselectable-text"),!this.isUnstyled&&(this.$el.style["user-select"]=""),this.unbindColumnResizeEvents(),this.isStateful()&&this.saveState()},resizeTableCells:function(t,n){var o=Ti(this.resizeColumnElement),i=[],r=lo(this.$refs.table,'thead[data-pc-section="thead"] > tr > th');r.forEach(function(s){return i.push(nt(s))}),this.destroyStyleElement(),this.createStyleElement();var a="",l='[data-pc-name="datatable"]['.concat(this.$attrSelector,'] > [data-pc-section="tablecontainer"] ').concat(this.virtualScrollerDisabled?"":'> [data-pc-name="virtualscroller"]',' > table[data-pc-section="table"]');i.forEach(function(s,d){var u=d===o?t:n&&d===o+1?n:s,c="width: ".concat(u,"px !important; max-width: ").concat(u,"px !important");a+=` - `.concat(l,' > thead[data-pc-section="thead"] > tr > th:nth-child(').concat(d+1,`), - `).concat(l,' > tbody[data-pc-section="tbody"] > tr > td:nth-child(').concat(d+1,`), - `).concat(l,' > tfoot[data-pc-section="tfoot"] > tr > td:nth-child(').concat(d+1,`) { - `).concat(c,` - } - `)}),this.styleElement.innerHTML=a},bindColumnResizeEvents:function(){var t=this;this.documentColumnResizeListener||(this.documentColumnResizeListener=function(n){t.columnResizing&&t.onColumnResize(n)},document.addEventListener("mousemove",this.documentColumnResizeListener)),this.documentColumnResizeEndListener||(this.documentColumnResizeEndListener=function(){t.columnResizing&&(t.columnResizing=!1,t.onColumnResizeEnd())},document.addEventListener("mouseup",this.documentColumnResizeEndListener))},unbindColumnResizeEvents:function(){this.documentColumnResizeListener&&(document.removeEventListener("document",this.documentColumnResizeListener),this.documentColumnResizeListener=null),this.documentColumnResizeEndListener&&(document.removeEventListener("document",this.documentColumnResizeEndListener),this.documentColumnResizeEndListener=null)},onColumnHeaderMouseDown:function(t){var n=t.originalEvent,o=t.column;this.reorderableColumns&&this.columnProp(o,"reorderableColumn")!==!1&&(n.target.nodeName==="INPUT"||n.target.nodeName==="TEXTAREA"||Ke(n.target,'[data-pc-section="columnresizer"]')?n.currentTarget.draggable=!1:n.currentTarget.draggable=!0)},onColumnHeaderDragStart:function(t){var n=t.originalEvent,o=t.column;if(this.columnResizing){n.preventDefault();return}this.colReorderIconWidth=t0(this.$refs.reorderIndicatorUp),this.colReorderIconHeight=e0(this.$refs.reorderIndicatorUp),this.draggedColumn=o,this.draggedColumnElement=this.findParentHeader(n.target),n.dataTransfer.setData("text","b")},onColumnHeaderDragOver:function(t){var n=t.originalEvent,o=t.column,i=this.findParentHeader(n.target);if(this.reorderableColumns&&this.draggedColumnElement&&i&&!this.columnProp(o,"frozen")){n.preventDefault();var r=so(this.$el),a=so(i);if(this.draggedColumnElement!==i){var l=a.left-r.left,s=a.left+i.offsetWidth/2;this.$refs.reorderIndicatorUp.style.top=a.top-r.top-(this.colReorderIconHeight-1)+"px",this.$refs.reorderIndicatorDown.style.top=a.top-r.top+i.offsetHeight+"px",n.pageX>s?(this.$refs.reorderIndicatorUp.style.left=l+i.offsetWidth-Math.ceil(this.colReorderIconWidth/2)+"px",this.$refs.reorderIndicatorDown.style.left=l+i.offsetWidth-Math.ceil(this.colReorderIconWidth/2)+"px",this.dropPosition=1):(this.$refs.reorderIndicatorUp.style.left=l-Math.ceil(this.colReorderIconWidth/2)+"px",this.$refs.reorderIndicatorDown.style.left=l-Math.ceil(this.colReorderIconWidth/2)+"px",this.dropPosition=-1),this.$refs.reorderIndicatorUp.style.display="block",this.$refs.reorderIndicatorDown.style.display="block"}}},onColumnHeaderDragLeave:function(t){var n=t.originalEvent;this.reorderableColumns&&this.draggedColumnElement&&(n.preventDefault(),this.$refs.reorderIndicatorUp.style.display="none",this.$refs.reorderIndicatorDown.style.display="none")},onColumnHeaderDrop:function(t){var n=this,o=t.originalEvent,i=t.column;if(o.preventDefault(),this.draggedColumnElement){var r=Ti(this.draggedColumnElement),a=Ti(this.findParentHeader(o.target)),l=r!==a;if(l&&(a-r===1&&this.dropPosition===-1||a-r===-1&&this.dropPosition===1)&&(l=!1),l){var s=function(x,P){return n.columnProp(x,"columnKey")||n.columnProp(P,"columnKey")?n.columnProp(x,"columnKey")===n.columnProp(P,"columnKey"):n.columnProp(x,"field")===n.columnProp(P,"field")},d=this.columns.findIndex(function(S){return s(S,n.draggedColumn)}),u=this.columns.findIndex(function(S){return s(S,i)}),c=[],f=lo(this.$el,'thead[data-pc-section="thead"] > tr > th');f.forEach(function(S){return c.push(nt(S))});var p=c.find(function(S,x){return x===d}),v=c.filter(function(S,x){return x!==d}),C=[].concat(Be(v.slice(0,u)),[p],Be(v.slice(u)));this.addColumnWidthStyles(C),ud&&this.dropPosition===-1&&u--,Dd(this.columns,d,u),this.updateReorderableColumns(),this.$emit("column-reorder",{originalEvent:o,dragIndex:d,dropIndex:u})}this.$refs.reorderIndicatorUp.style.display="none",this.$refs.reorderIndicatorDown.style.display="none",this.draggedColumnElement.draggable=!1,this.draggedColumnElement=null,this.draggedColumn=null,this.dropPosition=null}},findParentHeader:function(t){if(t.nodeName==="TH")return t;for(var n=t.parentElement;n.nodeName!=="TH"&&(n=n.parentElement,!!n););return n},findColumnByKey:function(t,n){if(t&&t.length)for(var o=0;othis.droppedRowIndex?this.droppedRowIndex:this.droppedRowIndex===0?0:this.droppedRowIndex-1,o=Be(this.processedData);Dd(o,this.draggedRowIndex+this.d_first,n+this.d_first),this.$emit("row-reorder",{originalEvent:t,dragIndex:this.draggedRowIndex,dropIndex:n,value:o})}this.onRowDragLeave(t),this.onRowDragEnd(t),t.preventDefault()},toggleRow:function(t){var n=this,o=t.expanded,i=dS(t,sS),r=t.data,a;if(this.dataKey){var l=Ce(r,this.dataKey);a=this.expandedRows?vt({},this.expandedRows):{},o?a[l]=!0:delete a[l]}else a=this.expandedRows?Be(this.expandedRows):[],o?a.push(r):a=a.filter(function(s){return!n.equals(r,s)});this.$emit("update:expandedRows",a),o?this.$emit("row-expand",i):this.$emit("row-collapse",i)},toggleRowGroup:function(t){var n=t.originalEvent,o=t.data,i=Ce(o,this.groupRowsBy),r=this.expandedRowGroups?Be(this.expandedRowGroups):[];this.isRowGroupExpanded(o)?(r=r.filter(function(a){return a!==i}),this.$emit("update:expandedRowGroups",r),this.$emit("rowgroup-collapse",{originalEvent:n,data:i})):(r.push(i),this.$emit("update:expandedRowGroups",r),this.$emit("rowgroup-expand",{originalEvent:n,data:i}))},isRowGroupExpanded:function(t){if(this.expandableRowGroups&&this.expandedRowGroups){var n=Ce(t,this.groupRowsBy);return this.expandedRowGroups.indexOf(n)>-1}return!1},isStateful:function(){return this.stateKey!=null},getStorage:function(){switch(this.stateStorage){case"local":return window.localStorage;case"session":return window.sessionStorage;default:throw new Error(this.stateStorage+' is not a valid value for the state storage, supported values are "local" and "session".')}},saveState:function(){var t=this.getStorage(),n={};this.paginator&&(n.first=this.d_first,n.rows=this.d_rows),this.d_sortField&&(typeof this.d_sortField!="function"&&(n.sortField=this.d_sortField),n.sortOrder=this.d_sortOrder),this.d_multiSortMeta&&(n.multiSortMeta=this.d_multiSortMeta),this.hasFilters&&(n.filters=this.filters),this.resizableColumns&&this.saveColumnWidths(n),this.reorderableColumns&&(n.columnOrder=this.d_columnOrder),this.expandedRows&&(n.expandedRows=this.expandedRows),this.expandedRowGroups&&(n.expandedRowGroups=this.expandedRowGroups),this.selection&&(n.selection=this.selection,n.selectionKeys=this.d_selectionKeys),Object.keys(n).length&&t.setItem(this.stateKey,JSON.stringify(n)),this.$emit("state-save",n)},restoreState:function(){var t=this.getStorage(),n=t.getItem(this.stateKey),o=/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/,i=function(s,d){return typeof d=="string"&&o.test(d)?new Date(d):d},r;try{r=JSON.parse(n,i)}catch{}if(!r||Yt(r)!=="object"){t.removeItem(this.stateKey);return}var a={};this.paginator&&(typeof r.first=="number"&&(this.d_first=r.first,this.$emit("update:first",this.d_first),a.first=this.d_first),typeof r.rows=="number"&&(this.d_rows=r.rows,this.$emit("update:rows",this.d_rows),a.rows=this.d_rows)),typeof r.sortField=="string"&&(this.d_sortField=r.sortField,this.$emit("update:sortField",this.d_sortField),a.sortField=this.d_sortField),typeof r.sortOrder=="number"&&(this.d_sortOrder=r.sortOrder,this.$emit("update:sortOrder",this.d_sortOrder),a.sortOrder=this.d_sortOrder),Array.isArray(r.multiSortMeta)&&(this.d_multiSortMeta=r.multiSortMeta,this.$emit("update:multiSortMeta",this.d_multiSortMeta),a.multiSortMeta=this.d_multiSortMeta),this.hasFilters&&Yt(r.filters)==="object"&&r.filters!==null&&(this.d_filters=this.cloneFilters(r.filters),this.$emit("update:filters",this.d_filters),a.filters=this.d_filters),this.resizableColumns&&(typeof r.columnWidths=="string"&&(this.columnWidthsState=r.columnWidths,a.columnWidths=this.columnWidthsState),typeof r.tableWidth=="string"&&(this.tableWidthState=r.tableWidth,a.tableWidth=this.tableWidthState)),this.reorderableColumns&&Array.isArray(r.columnOrder)&&(this.d_columnOrder=r.columnOrder,a.columnOrder=this.d_columnOrder),Yt(r.expandedRows)==="object"&&r.expandedRows!==null&&(this.$emit("update:expandedRows",r.expandedRows),a.expandedRows=r.expandedRows),Array.isArray(r.expandedRowGroups)&&(this.$emit("update:expandedRowGroups",r.expandedRowGroups),a.expandedRowGroups=r.expandedRowGroups),Yt(r.selection)==="object"&&r.selection!==null&&(Yt(r.selectionKeys)==="object"&&r.selectionKeys!==null&&(this.d_selectionKeys=r.selectionKeys,a.selectionKeys=this.d_selectionKeys),this.$emit("update:selection",r.selection),a.selection=r.selection),this.$emit("state-restore",a)},saveColumnWidths:function(t){var n=[],o=lo(this.$el,'thead[data-pc-section="thead"] > tr > th');o.forEach(function(i){return n.push(nt(i))}),t.columnWidths=n.join(","),this.columnResizeMode==="expand"&&(t.tableWidth=nt(this.$refs.table)+"px")},addColumnWidthStyles:function(t){this.createStyleElement();var n="",o='[data-pc-name="datatable"]['.concat(this.$attrSelector,'] > [data-pc-section="tablecontainer"] ').concat(this.virtualScrollerDisabled?"":'> [data-pc-name="virtualscroller"]',' > table[data-pc-section="table"]');t.forEach(function(i,r){var a="width: ".concat(i,"px !important; max-width: ").concat(i,"px !important");n+=` - `.concat(o,' > thead[data-pc-section="thead"] > tr > th:nth-child(').concat(r+1,`), - `).concat(o,' > tbody[data-pc-section="tbody"] > tr > td:nth-child(').concat(r+1,`), - `).concat(o,' > tfoot[data-pc-section="tfoot"] > tr > td:nth-child(').concat(r+1,`) { - `).concat(a,` - } - `)}),this.styleElement.innerHTML=n},restoreColumnWidths:function(){if(this.columnWidthsState){var t=this.columnWidthsState.split(",");this.columnResizeMode==="expand"&&this.tableWidthState&&(this.$refs.table.style.width=this.tableWidthState,this.$refs.table.style.minWidth=this.tableWidthState),me(t)&&this.addColumnWidthStyles(t)}},onCellEditInit:function(t){this.$emit("cell-edit-init",t)},onCellEditComplete:function(t){this.$emit("cell-edit-complete",t)},onCellEditCancel:function(t){this.$emit("cell-edit-cancel",t)},onRowEditInit:function(t){var n=this.editingRows?Be(this.editingRows):[];n.push(t.data),this.$emit("update:editingRows",n),this.$emit("row-edit-init",t)},onRowEditSave:function(t){var n=Be(this.editingRows);n.splice(this.findIndex(t.data,n),1),this.$emit("update:editingRows",n),this.$emit("row-edit-save",t)},onRowEditCancel:function(t){var n=Be(this.editingRows);n.splice(this.findIndex(t.data,n),1),this.$emit("update:editingRows",n),this.$emit("row-edit-cancel",t)},onEditingMetaChange:function(t){var n=t.data,o=t.field,i=t.index,r=t.editing,a=vt({},this.d_editingMeta),l=a[i];if(r)!l&&(l=a[i]={data:vt({},n),fields:[]}),l.fields.push(o);else if(l){var s=l.fields.filter(function(d){return d!==o});s.length?l.fields=s:delete a[i]}this.d_editingMeta=a},clearEditingMetaData:function(){this.editMode&&(this.d_editingMeta={})},createLazyLoadEvent:function(t){return{originalEvent:t,first:this.d_first,rows:this.d_rows,sortField:this.d_sortField,sortOrder:this.d_sortOrder,multiSortMeta:this.d_multiSortMeta,filters:this.d_filters}},hasGlobalFilter:function(){return this.filters&&Object.prototype.hasOwnProperty.call(this.filters,"global")},onFilterChange:function(t){this.d_filters=t},onFilterApply:function(){this.d_first=0,this.$emit("update:first",this.d_first),this.$emit("update:filters",this.d_filters),this.lazy&&this.$emit("filter",this.createLazyLoadEvent())},cloneFilters:function(t){var n={};return t&&Object.entries(t).forEach(function(o){var i=Mu(o,2),r=i[0],a=i[1];n[r]=a.operator?{operator:a.operator,constraints:a.constraints.map(function(l){return vt({},l)})}:vt({},a)}),n},updateReorderableColumns:function(){var t=this,n=[];this.columns.forEach(function(o){return n.push(t.columnProp(o,"columnKey")||t.columnProp(o,"field"))}),this.d_columnOrder=n},createStyleElement:function(){var t;this.styleElement=document.createElement("style"),this.styleElement.type="text/css",aa(this.styleElement,"nonce",(t=this.$primevue)===null||t===void 0||(t=t.config)===null||t===void 0||(t=t.csp)===null||t===void 0?void 0:t.nonce),document.head.appendChild(this.styleElement)},destroyStyleElement:function(){this.styleElement&&(document.head.removeChild(this.styleElement),this.styleElement=null)},dataToRender:function(t){var n=t||this.processedData;if(n&&this.paginator){var o=this.lazy?0:this.d_first;return n.slice(o,o+this.d_rows)}return n},getVirtualScrollerRef:function(){return this.$refs.virtualScroller},hasSpacerStyle:function(t){return me(t)}},computed:{columns:function(){var t=this.d_columns.get(this);if(t&&this.reorderableColumns&&this.d_columnOrder){var n=[],o=Mo(this.d_columnOrder),i;try{for(o.s();!(i=o.n()).done;){var r=i.value,a=this.findColumnByKey(t,r);a&&!this.columnProp(a,"hidden")&&n.push(a)}}catch(l){o.e(l)}finally{o.f()}return[].concat(n,Be(t.filter(function(l){return n.indexOf(l)<0})))}return t},columnGroups:function(){return this.d_columnGroups.get(this)},headerColumnGroup:function(){var t,n=this;return(t=this.columnGroups)===null||t===void 0?void 0:t.find(function(o){return n.columnProp(o,"type")==="header"})},footerColumnGroup:function(){var t,n=this;return(t=this.columnGroups)===null||t===void 0?void 0:t.find(function(o){return n.columnProp(o,"type")==="footer"})},hasFilters:function(){return this.filters&&Object.keys(this.filters).length>0&&this.filters.constructor===Object},processedData:function(){var t,n=this.value||[];return!this.lazy&&!((t=this.virtualScrollerOptions)!==null&&t!==void 0&&t.lazy)&&n&&n.length&&(this.hasFilters&&(n=this.filter(n)),this.sorted&&(this.sortMode==="single"?n=this.sortSingle(n):this.sortMode==="multiple"&&(n=this.sortMultiple(n)))),n},totalRecordsLength:function(){if(this.lazy)return this.totalRecords;var t=this.processedData;return t?t.length:0},empty:function(){var t=this.processedData;return!t||t.length===0},paginatorTop:function(){return this.paginator&&(this.paginatorPosition!=="bottom"||this.paginatorPosition==="both")},paginatorBottom:function(){return this.paginator&&(this.paginatorPosition!=="top"||this.paginatorPosition==="both")},sorted:function(){return this.d_sortField||this.d_multiSortMeta&&this.d_multiSortMeta.length>0},allRowsSelected:function(){var t=this;if(this.selectAll!==null)return this.selectAll;var n=this.frozenValue?[].concat(Be(this.frozenValue),Be(this.processedData)):this.processedData;return me(n)&&this.selection&&Array.isArray(this.selection)&&n.every(function(o){return t.selection.some(function(i){return t.equals(i,o)})})},groupRowSortField:function(){return this.sortMode==="single"?this.sortField:this.d_groupRowsSortMeta?this.d_groupRowsSortMeta.field:null},headerFilterButtonProps:function(){return vt(vt({filter:{severity:"secondary",text:!0,rounded:!0}},this.filterButtonProps),{},{inline:vt({clear:{severity:"secondary",text:!0,rounded:!0}},this.filterButtonProps.inline),popover:vt({addRule:{severity:"info",text:!0,size:"small"},removeRule:{severity:"danger",text:!0,size:"small"},apply:{size:"small"},clear:{outlined:!0,size:"small"}},this.filterButtonProps.popover)})},rowEditButtonProps:function(){return vt(vt({},{init:{severity:"secondary",text:!0,rounded:!0},save:{severity:"secondary",text:!0,rounded:!0},cancel:{severity:"secondary",text:!0,rounded:!0}}),this.editButtonProps)},virtualScrollerDisabled:function(){return gt(this.virtualScrollerOptions)||!this.scrollable},dataP:function(){return Me(Ri(Ri(Ri({scrollable:this.scrollable,"flex-scrollable":this.scrollable&&this.scrollHeight==="flex"},this.size,this.size),"loading",this.loading),"empty",this.empty))}},components:{DTPaginator:ii,DTTableHeader:sh,DTTableBody:oh,DTTableFooter:ih,DTVirtualScroller:Os,ArrowDownIcon:Rp,ArrowUpIcon:Op,SpinnerIcon:ni}};function Kr(e){"@babel/helpers - typeof";return Kr=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Kr(e)}function zu(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),n.push.apply(n,o)}return n}function Fu(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,o=Array(t);ne.length)&&(t=e.length);for(var n=0,o=Array(t);n=t.minX&&s+o=t.minY&&d+ir.dialogVisible=u),modal:!0,closable:!((d=e.updateInfo)!=null&&d.forceUpdate),header:"发现新版本",style:{width:"500px"},onHide:r.handleClose},{footer:V(()=>{var u,c;return[!e.isDownloading&&e.updateProgress===0?(g(),T(l,{key:0,label:"立即更新",onClick:r.handleStartDownload},null,8,["onClick"])):I("",!0),!e.isDownloading&&e.updateProgress===100?(g(),T(l,{key:1,label:"立即安装",onClick:r.handleInstallUpdate},null,8,["onClick"])):I("",!0),!((u=e.updateInfo)!=null&&u.forceUpdate)&&!e.isDownloading&&e.updateProgress===0?(g(),T(l,{key:2,label:"稍后提醒",severity:"secondary",onClick:r.handleClose},null,8,["onClick"])):I("",!0),!((c=e.updateInfo)!=null&&c.forceUpdate)&&!e.isDownloading&&e.updateProgress===100?(g(),T(l,{key:3,label:"稍后安装",severity:"secondary",onClick:r.handleClose},null,8,["onClick"])):I("",!0)]}),default:V(()=>{var u,c,f,p;return[h("div",H6,[h("div",G6,[h("p",null,[t[1]||(t[1]=h("strong",null,"新版本号:",-1)),$e(" "+_(((u=e.updateInfo)==null?void 0:u.version)||"未知"),1)]),((c=e.updateInfo)==null?void 0:c.fileSize)>0?(g(),b("p",K6,[t[2]||(t[2]=h("strong",null,"文件大小:",-1)),$e(" "+_(r.formatFileSize(e.updateInfo.fileSize)),1)])):I("",!0),(f=e.updateInfo)!=null&&f.releaseNotes?(g(),b("div",W6,[t[3]||(t[3]=h("p",null,[h("strong",null,"更新内容:")],-1)),h("pre",null,_(e.updateInfo.releaseNotes),1)])):I("",!0)]),e.isDownloading||e.updateProgress>0?(g(),b("div",q6,[D(a,{value:r.progressValue},null,8,["value"]),h("div",Q6,[h("span",null,"下载进度: "+_(r.progressValue)+"%",1),((p=e.downloadState)==null?void 0:p.totalBytes)>0?(g(),b("span",Z6," ("+_(r.formatFileSize(e.downloadState.downloadedBytes||0))+" / "+_(r.formatFileSize(e.downloadState.totalBytes))+") ",1)):I("",!0)])])):I("",!0)])]}),_:1},8,["visible","closable","onHide"])}const X6=dt(U6,[["render",Y6],["__scopeId","data-v-dd11359a"]]),J6={name:"UserInfoDialog",components:{Dialog:Eo,Button:xt},props:{visible:{type:Boolean,default:!1},userInfo:{type:Object,default:()=>({userName:"",phone:"",snCode:"",deviceId:"",remainingDays:null})}},computed:{dialogVisible:{get(){return this.visible},set(e){e||this.handleClose()}},remainingDaysClass(){return this.userInfo.remainingDays===null?"":this.userInfo.remainingDays<=0?"text-error":this.userInfo.remainingDays<=3?"text-warning":""}},methods:{handleClose(){this.$emit("close")}}},e3={class:"info-content"},t3={class:"info-item"},n3={class:"info-item"},o3={class:"info-item"},r3={class:"info-item"},i3={class:"info-item"};function a3(e,t,n,o,i,r){const a=R("Button"),l=R("Dialog");return g(),T(l,{visible:r.dialogVisible,"onUpdate:visible":t[0]||(t[0]=s=>r.dialogVisible=s),modal:"",header:"个人信息",style:{width:"500px"},onHide:r.handleClose},{footer:V(()=>[D(a,{label:"关闭",onClick:r.handleClose},null,8,["onClick"])]),default:V(()=>[h("div",e3,[h("div",t3,[t[1]||(t[1]=h("label",null,"用户名:",-1)),h("span",null,_(n.userInfo.userName||"-"),1)]),h("div",n3,[t[2]||(t[2]=h("label",null,"手机号:",-1)),h("span",null,_(n.userInfo.phone||"-"),1)]),h("div",o3,[t[3]||(t[3]=h("label",null,"设备SN码:",-1)),h("span",null,_(n.userInfo.snCode||"-"),1)]),h("div",r3,[t[4]||(t[4]=h("label",null,"设备ID:",-1)),h("span",null,_(n.userInfo.deviceId||"-"),1)]),h("div",i3,[t[5]||(t[5]=h("label",null,"剩余天数:",-1)),h("span",{class:J(r.remainingDaysClass)},_(n.userInfo.remainingDays!==null?n.userInfo.remainingDays+" 天":"-"),3)])])]),_:1},8,["visible","onHide"])}const l3=dt(J6,[["render",a3],["__scopeId","data-v-2d37d2c9"]]),bn={methods:{addLog(e,t){this.$store&&this.$store.dispatch("log/addLog",{level:e,message:t})},clearLogs(){this.$store&&this.$store.dispatch("log/clearLogs")},exportLogs(){this.$store&&this.$store.dispatch("log/exportLogs")}},computed:{logEntries(){return this.$store?this.$store.getters["log/logEntries"]||[]:[]}}},s3={name:"SettingsDialog",mixins:[bn],components:{Dialog:Eo,Button:xt,InputSwitch:gC},props:{visible:{type:Boolean,default:!1}},computed:{dialogVisible:{get(){return this.visible},set(e){e||this.handleClose()}}},computed:{settings:{get(){return this.$store.state.config.appSettings},set(e){this.$store.dispatch("config/updateAppSettings",e)}}},methods:{handleSettingChange(e,t){const n=typeof t=="boolean"?t:t.value;this.$store.dispatch("config/updateAppSetting",{key:e,value:n})},handleSave(){this.addLog("success","设置已保存"),this.$emit("save",this.settings),this.handleClose()},handleClose(){this.$emit("close")}}},d3={class:"settings-content"},u3={class:"settings-section"},c3={class:"setting-item"},f3={class:"setting-item"},p3={class:"settings-section"},h3={class:"setting-item"},g3={class:"setting-item"};function m3(e,t,n,o,i,r){const a=R("InputSwitch"),l=R("Button"),s=R("Dialog");return g(),T(s,{visible:r.dialogVisible,"onUpdate:visible":t[8]||(t[8]=d=>r.dialogVisible=d),modal:"",header:"系统设置",style:{width:"500px"},onHide:r.handleClose},{footer:V(()=>[D(l,{label:"取消",severity:"secondary",onClick:r.handleClose},null,8,["onClick"]),D(l,{label:"保存",onClick:r.handleSave},null,8,["onClick"])]),default:V(()=>[h("div",d3,[h("div",u3,[t[11]||(t[11]=h("h4",{class:"section-title"},"应用设置",-1)),h("div",c3,[t[9]||(t[9]=h("label",null,"自动启动",-1)),D(a,{modelValue:r.settings.autoStart,"onUpdate:modelValue":t[0]||(t[0]=d=>r.settings.autoStart=d),onChange:t[1]||(t[1]=d=>r.handleSettingChange("autoStart",d))},null,8,["modelValue"])]),h("div",f3,[t[10]||(t[10]=h("label",null,"开机自启",-1)),D(a,{modelValue:r.settings.startOnBoot,"onUpdate:modelValue":t[2]||(t[2]=d=>r.settings.startOnBoot=d),onChange:t[3]||(t[3]=d=>r.handleSettingChange("startOnBoot",d))},null,8,["modelValue"])])]),h("div",p3,[t[14]||(t[14]=h("h4",{class:"section-title"},"通知设置",-1)),h("div",h3,[t[12]||(t[12]=h("label",null,"启用通知",-1)),D(a,{modelValue:r.settings.enableNotifications,"onUpdate:modelValue":t[4]||(t[4]=d=>r.settings.enableNotifications=d),onChange:t[5]||(t[5]=d=>r.handleSettingChange("enableNotifications",d))},null,8,["modelValue"])]),h("div",g3,[t[13]||(t[13]=h("label",null,"声音提醒",-1)),D(a,{modelValue:r.settings.soundAlert,"onUpdate:modelValue":t[6]||(t[6]=d=>r.settings.soundAlert=d),onChange:t[7]||(t[7]=d=>r.handleSettingChange("soundAlert",d))},null,8,["modelValue"])])])])]),_:1},8,["visible","onHide"])}const b3=dt(s3,[["render",m3],["__scopeId","data-v-daae3f81"]]),y3={name:"UserMenu",mixins:[bn],components:{UserInfoDialog:l3,SettingsDialog:b3},data(){return{menuVisible:!1,showUserInfoDialog:!1,showSettingsDialog:!1}},computed:{...Ze("auth",["isLoggedIn","userName","snCode","deviceId","remainingDays","phone"]),...Ze("mqtt",["isConnected"]),userInfo(){return{userName:this.userName||"",phone:this.phone||"",snCode:this.snCode||"",deviceId:this.deviceId||"",remainingDays:this.remainingDays}}},methods:{toggleMenu(){this.menuVisible=!this.menuVisible},showUserInfo(){this.menuVisible=!1,this.showUserInfoDialog=!0},showSettings(){this.menuVisible=!1,this.showSettingsDialog=!0},async handleLogout(){if(this.menuVisible=!1,!!this.isLoggedIn)try{if(this.addLog("info","正在注销登录..."),this.isConnected&&window.electronAPI&&window.electronAPI.mqtt)try{await window.electronAPI.invoke("mqtt:disconnect")}catch(e){console.error("断开MQTT连接失败:",e)}if(window.electronAPI&&window.electronAPI.invoke)try{await window.electronAPI.invoke("auth:logout")}catch(e){console.error("调用退出接口失败:",e)}if(this.$store){this.$store.dispatch("auth/logout"),this.$store.commit("platform/SET_PLATFORM_LOGIN_STATUS",{status:"-",color:"#FF9800",isLoggedIn:!1});const e=this.$store.state.task.taskUpdateTimer;e&&(clearInterval(e),this.$store.dispatch("task/setTaskUpdateTimer",null))}this.$router&&this.$router.push("/login").catch(e=>{e.name!=="NavigationDuplicated"&&console.error("跳转登录页失败:",e)}),this.addLog("success","注销登录成功")}catch(e){console.error("退出登录异常:",e),this.$store&&this.$store.dispatch("auth/logout"),this.$router&&this.$router.push("/login").catch(()=>{}),this.addLog("error",`注销登录异常: ${e.message}`)}},handleSettingsSave(e){console.log("设置已保存:",e)}},mounted(){this.handleClickOutside=e=>{this.$el&&!this.$el.contains(e.target)&&(this.menuVisible=!1)},document.addEventListener("click",this.handleClickOutside)},beforeDestroy(){this.handleClickOutside&&document.removeEventListener("click",this.handleClickOutside)}},v3={class:"user-menu"},w3={class:"user-name"},C3={key:0,class:"user-menu-dropdown"};function k3(e,t,n,o,i,r){const a=R("UserInfoDialog"),l=R("SettingsDialog");return g(),b("div",v3,[h("div",{class:"user-info",onClick:t[0]||(t[0]=(...s)=>r.toggleMenu&&r.toggleMenu(...s))},[h("span",w3,_(e.userName||"未登录"),1),t[6]||(t[6]=h("span",{class:"dropdown-icon"},"▼",-1))]),i.menuVisible?(g(),b("div",C3,[h("div",{class:"menu-item",onClick:t[1]||(t[1]=(...s)=>r.showUserInfo&&r.showUserInfo(...s))},[...t[7]||(t[7]=[h("span",{class:"menu-icon"},"👤",-1),h("span",{class:"menu-text"},"个人信息",-1)])]),h("div",{class:"menu-item",onClick:t[2]||(t[2]=(...s)=>r.showSettings&&r.showSettings(...s))},[...t[8]||(t[8]=[h("span",{class:"menu-icon"},"⚙️",-1),h("span",{class:"menu-text"},"设置",-1)])]),t[10]||(t[10]=h("div",{class:"menu-divider"},null,-1)),h("div",{class:"menu-item",onClick:t[3]||(t[3]=(...s)=>r.handleLogout&&r.handleLogout(...s))},[...t[9]||(t[9]=[h("span",{class:"menu-icon"},"🚪",-1),h("span",{class:"menu-text"},"退出登录",-1)])])])):I("",!0),D(a,{visible:i.showUserInfoDialog,"user-info":r.userInfo,onClose:t[4]||(t[4]=s=>i.showUserInfoDialog=!1)},null,8,["visible","user-info"]),D(l,{visible:i.showSettingsDialog,onClose:t[5]||(t[5]=s=>i.showSettingsDialog=!1),onSave:r.handleSettingsSave},null,8,["visible","onSave"])])}const S3=dt(y3,[["render",k3],["__scopeId","data-v-f94e136c"]]),Aa={};class x3{constructor(){this.token=this.getToken()}getBaseURL(){return(Aa==null?void 0:Aa.VITE_API_URL)||"https://work.light120.com/api"}async requestWithFetch(t,n,o=null){const i=this.getBaseURL(),r=n.startsWith("/")?n:`/${n}`,a=`${i}${r}`,l=this.buildHeaders(),s={method:t.toUpperCase(),headers:l};if(t.toUpperCase()==="GET"&&o){const c=new URLSearchParams(o),f=`${a}?${c}`;console.log("requestWithFetch",t,f);const v=await(await fetch(f,s)).json();return console.log("requestWithFetch result",v),v}t.toUpperCase()==="POST"&&o&&(s.body=JSON.stringify(o)),console.log("requestWithFetch",t,a,o);const u=await(await fetch(a,s)).json();return console.log("requestWithFetch result",u),u}setToken(t){this.token=t,t?localStorage.setItem("api_token",t):localStorage.removeItem("api_token")}getToken(){return this.token||(this.token=localStorage.getItem("api_token")),this.token}buildHeaders(){const t={"Content-Type":"application/json"},n=this.getToken();return n&&(t["applet-token"]=`${n}`),t}async handleError(t){if(t.response){const{status:n,data:o}=t.response;return{code:n,message:(o==null?void 0:o.message)||`请求失败: ${n}`,data:null}}else return t.request?{code:-1,message:"网络错误,请检查网络连接",data:null}:{code:-1,message:t.message||"未知错误",data:null}}showError(t){console.error("[API错误]",t)}async request(t,n,o=null){try{const i=await this.requestWithFetch(t,n,o);if(i&&i.code!==void 0&&i.code!==0){const r=i.message||"请求失败";console.warn("[API警告]",r)}return i}catch(i){const r=i.message||"请求失败";throw this.showError(r),i}}async get(t,n={}){try{return await this.request("GET",t,n)}catch(o){const i=o.message||"请求失败";throw this.showError(i),o}}async post(t,n={}){try{return await this.request("POST",t,n)}catch(o){console.error("[ApiClient] POST 请求失败:",{error:o.message,endpoint:t,data:n});const i=await this.handleError(o);return i&&i.code!==0&&this.showError(i.message||"请求失败"),i}}}const We=new x3;async function $3(e,t,n=null){const o={login_name:e,password:t};n&&(o.device_id=n);const i=await We.post("/user/login",o);return i.code===0&&i.data&&i.data.token&&We.setToken(i.data.token),i}function ph(){return We.getToken()}function P3(){We.setToken(null)}const I3={data(){return{phone:"",password:"",isLoggedIn:!1,loginButtonText:"登录",userName:"",remainingDays:null,snCode:"",deviceId:"-",listenChannel:"-",userMenuInfo:{userName:"",snCode:""}}},methods:{async loadSavedConfig(){try{if(this.$store){const e=this.$store.state.config.phone||this.$store.state.auth.phone;e&&(this.phone=e)}}catch(e){console.error("加载配置失败:",e),this.addLog&&this.addLog("error",`加载配置失败: ${e.message}`)}},async userLogin(e,t=!0){if(!this.phone)return this.addLog&&this.addLog("error","请输入手机号"),{success:!1,error:"请输入手机号"};if(!e)return this.addLog&&this.addLog("error","请输入密码"),{success:!1,error:"请输入密码"};if(!window.electronAPI)return this.addLog&&this.addLog("error","Electron API不可用"),{success:!1,error:"Electron API不可用"};try{this.addLog&&this.addLog("info",`正在使用手机号 ${this.phone} 登录...`);const n=await window.electronAPI.invoke("auth:login",{phone:this.phone,password:e});return n.success&&n.data?(this.$store&&(await this.$store.dispatch("auth/login",{phone:this.phone,password:e,deviceId:n.data.device_id||""}),t&&(this.$store.dispatch("config/setRememberMe",!0),this.$store.dispatch("config/setPhone",this.phone))),this.checkMQTTStatus&&setTimeout(()=>{this.checkMQTTStatus()},1e3),this.startTaskStatusUpdate&&this.startTaskStatusUpdate(),{success:!0,data:n.data}):(this.addLog&&this.addLog("error",`登录失败: ${n.error||"未知错误"}`),{success:!1,error:n.error||"未知错误"})}catch(n){return this.addLog&&this.addLog("error",`登录过程中发生错误: ${n.message}`),{success:!1,error:n.message}}},async tryAutoLogin(){try{if(!this.$store)return!1;const e=this.$store.state.config.phone||this.$store.state.auth.phone;if(this.$store.state.config.userLoggedOut||this.$store.state.auth.userLoggedOut||!e)return!1;const n=ph(),o=this.$store?this.$store.state.auth.snCode:"",i=this.$store?this.$store.state.auth.userName:"";return n&&(o||i)?(this.$store.commit("auth/SET_LOGGED_IN",!0),this.$store.commit("auth/SET_LOGIN_BUTTON_TEXT","注销登录"),this.addLog&&this.addLog("info","自动登录成功"),this.checkMQTTStatus&&setTimeout(()=>{this.checkMQTTStatus()},1e3),!0):!1}catch(e){return console.error("自动登录失败:",e),this.addLog&&this.addLog("error",`自动登录失败: ${e.message}`),!1}},async logoutDevice(){if(!window.electronAPI){this.addLog&&this.addLog("error","Electron API不可用");return}try{this.addLog&&this.addLog("info","正在注销登录..."),await window.electronAPI.invoke("auth:logout"),this.stopTaskStatusUpdate&&this.stopTaskStatusUpdate(),this.$store&&(this.$store.dispatch("auth/logout"),this.$store.dispatch("config/setUserLoggedOut",!0)),this.addLog&&this.addLog("success","注销登录成功"),this.$emit&&this.$emit("logout-success")}catch(e){this.addLog&&this.addLog("error",`注销登录异常: ${e.message}`)}}},watch:{snCode(e){this.userMenuInfo.snCode=e}}},hh={computed:{isConnected(){return this.$store?this.$store.state.mqtt.isConnected:!1},mqttStatus(){return this.$store?this.$store.state.mqtt.mqttStatus:"未连接"}},methods:{async checkMQTTStatus(){try{if(!window.electronAPI)return;const e=await window.electronAPI.invoke("mqtt:status");e&&typeof e.isConnected<"u"&&this.$store&&this.$store.dispatch("mqtt/setConnected",e.isConnected)}catch(e){console.warn("查询MQTT状态失败:",e)}},async disconnectMQTT(){try{if(!window.electronAPI)return;await window.electronAPI.invoke("mqtt:disconnect"),this.addLog&&this.addLog("info","服务断开连接指令已发送")}catch(e){this.addLog&&this.addLog("error",`断开服务连接异常: ${e.message}`)}},onMQTTConnected(e){console.log("[WS] onMQTTConnected 被调用,数据:",e),this.$store&&(this.$store.dispatch("mqtt/setConnected",!0),console.log("[WS] 状态已更新为已连接")),this.addLog&&this.addLog("success","MQTT 服务已连接")},onMQTTDisconnected(e){this.$store&&this.$store.dispatch("mqtt/setConnected",!1),this.addLog&&this.addLog("warn",`服务连接断开: ${e.reason||"未知原因"}`)},onMQTTMessage(e){var n;const t=((n=e.payload)==null?void 0:n.action)||"unknown";this.addLog&&this.addLog("info",`收到远程指令: ${t}`)},onMQTTStatusChange(e){if(console.log("[WS] onMQTTStatusChange 被调用,数据:",e),e&&typeof e.isConnected<"u")this.$store&&(this.$store.dispatch("mqtt/setConnected",e.isConnected),console.log("[WS] 通过 isConnected 更新状态:",e.isConnected));else if(e&&e.status){const t=e.status==="connected"||e.status==="已连接";this.$store&&(this.$store.dispatch("mqtt/setConnected",t),console.log("[WS] 通过 status 更新状态:",t))}}}},gh={computed:{displayText(){return this.$store?this.$store.state.task.displayText:null},nextExecuteTimeText(){return this.$store?this.$store.state.task.nextExecuteTimeText:null},currentActivity(){return this.$store?this.$store.state.task.currentActivity:null},pendingQueue(){return this.$store?this.$store.state.task.pendingQueue:null},deviceStatus(){return this.$store?this.$store.state.task.deviceStatus:null}},methods:{startTaskStatusUpdate(){console.log("[TaskMixin] 设备工作状态更新已启动,使用 MQTT 实时推送")},stopTaskStatusUpdate(){this.$store&&this.$store.dispatch("task/clearDeviceWorkStatus")},onDeviceWorkStatus(e){if(!e||!this.$store){console.warn("[Renderer] 收到设备工作状态但数据无效:",e);return}try{this.$store.dispatch("task/updateDeviceWorkStatus",e),this.$nextTick(()=>{const t=this.$store.state.task})}catch(t){console.error("[Renderer] 更新设备工作状态失败:",t)}}}},mh={computed:{uptime(){return this.$store?this.$store.state.system.uptime:"0分钟"},cpuUsage(){return this.$store?this.$store.state.system.cpuUsage:"0%"},memUsage(){return this.$store?this.$store.state.system.memUsage:"0MB"},deviceId(){return this.$store?this.$store.state.system.deviceId:"-"}},methods:{startSystemInfoUpdate(){const e=()=>{if(this.$store&&this.startTime){const t=Math.floor((Date.now()-this.startTime)/1e3/60);this.$store.dispatch("system/updateUptime",`${t}分钟`)}};e(),setInterval(e,5e3)},updateSystemInfo(e){this.$store&&e&&(e.cpu!==void 0&&this.$store.dispatch("system/updateCpuUsage",e.cpu),e.memory!==void 0&&this.$store.dispatch("system/updateMemUsage",e.memory),e.deviceId!==void 0&&this.$store.dispatch("system/updateDeviceId",e.deviceId))}}},bh={computed:{currentPlatform(){return this.$store?this.$store.state.platform.currentPlatform:"-"},platformLoginStatus(){return this.$store?this.$store.state.platform.platformLoginStatus:"-"},platformLoginStatusColor(){return this.$store?this.$store.state.platform.platformLoginStatusColor:"#FF9800"},isPlatformLoggedIn(){return this.$store?this.$store.state.platform.isPlatformLoggedIn:!1}},methods:{onPlatformLoginStatusUpdated(e){if(this.$store&&e){e.platform!==void 0&&this.$store.dispatch("platform/updatePlatform",e.platform);const t=e.isLoggedIn!==void 0?e.isLoggedIn:!1;this.$store.dispatch("platform/updatePlatformLoginStatus",{status:e.status||(t?"已登录":"未登录"),color:e.color||(t?"#4CAF50":"#FF9800"),isLoggedIn:t})}},async checkPlatformLoginStatus(){if(!window.electronAPI||!window.electronAPI.invoke){console.warn("[PlatformMixin] electronAPI 不可用,无法检查平台登录状态");return}try{const e=await window.electronAPI.invoke("auth:platform-login-status");e&&e.success&&console.log("[PlatformMixin] 平台登录状态检查完成:",{platform:e.platformType,isLoggedIn:e.isLoggedIn})}catch(e){console.error("[PlatformMixin] 检查平台登录状态失败:",e)}}}},yh={data(){return{qrCodeAutoRefreshInterval:null,qrCodeCountdownInterval:null}},computed:{qrCodeUrl(){return this.$store?this.$store.state.qrCode.qrCodeUrl:null},qrCodeCountdown(){return this.$store?this.$store.state.qrCode.qrCodeCountdown:0},qrCodeCountdownActive(){return this.$store?this.$store.state.qrCode.qrCodeCountdownActive:!1},qrCodeExpired(){return this.$store?this.$store.state.qrCode.qrCodeExpired:!1},qrCodeRefreshCount(){return this.$store?this.$store.state.qrCode.qrCodeRefreshCount:0},isPlatformLoggedIn(){return this.$store?this.$store.state.platform.isPlatformLoggedIn:!1}},methods:{async getQrCode(){try{if(!window.electronAPI||!window.electronAPI.invoke){console.error("[二维码] electronAPI 不可用");return}const e=await window.electronAPI.invoke("command:execute",{platform:"boss",action:"get_login_qr_code",data:{type:"app"},source:"renderer"});if(e.success&&e.data){const t=e.data.qrCodeUrl||e.data.qr_code_url||e.data.oos_url||e.data.imageData,n=e.data.qrCodeOosUrl||e.data.oos_url||null;if(t&&this.$store)return this.$store.dispatch("qrCode/setQrCode",{url:t,oosUrl:n}),this.addLog&&this.addLog("success","二维码已获取"),!0}else console.error("[二维码] 获取失败:",e.error||"未知错误"),this.addLog&&this.addLog("error",`获取二维码失败: ${e.error||"未知错误"}`)}catch(e){console.error("[二维码] 获取失败:",e),this.addLog&&this.addLog("error",`获取二维码失败: ${e.message}`)}return!1},startQrCodeAutoRefresh(){if(this.qrCodeAutoRefreshInterval||this.isPlatformLoggedIn)return;const e=25e3,t=3;this.$store&&this.$store.dispatch("qrCode/setQrCodeCountdown",{countdown:25,isActive:!0,refreshCount:0,isExpired:!1}),this.getQrCode(),this.qrCodeAutoRefreshInterval=setInterval(async()=>{if(this.isPlatformLoggedIn){this.stopQrCodeAutoRefresh();return}const n=this.qrCodeRefreshCount;if(n>=t){this.$store&&this.$store.dispatch("qrCode/setQrCodeCountdown",{countdown:0,isActive:!1,refreshCount:n,isExpired:!0}),this.stopQrCodeAutoRefresh();return}await this.getQrCode()&&this.$store&&this.$store.dispatch("qrCode/setQrCodeCountdown",{countdown:25,isActive:!0,refreshCount:n+1,isExpired:!1})},e),this.startQrCodeCountdown()},stopQrCodeAutoRefresh(){this.qrCodeAutoRefreshInterval&&(clearInterval(this.qrCodeAutoRefreshInterval),this.qrCodeAutoRefreshInterval=null),this.stopQrCodeCountdown(),this.$store&&this.$store.dispatch("qrCode/setQrCodeCountdown",{countdown:0,isActive:!1,refreshCount:this.qrCodeRefreshCount,isExpired:this.qrCodeExpired})},startQrCodeCountdown(){this.qrCodeCountdownInterval||(this.qrCodeCountdownInterval=setInterval(()=>{if(this.qrCodeCountdownActive&&this.qrCodeCountdown>0){const e=this.qrCodeCountdown-1;this.$store&&this.$store.dispatch("qrCode/setQrCodeCountdown",{countdown:e,isActive:!0,refreshCount:this.qrCodeRefreshCount,isExpired:!1})}else this.stopQrCodeCountdown()},1e3))},stopQrCodeCountdown(){this.qrCodeCountdownInterval&&(clearInterval(this.qrCodeCountdownInterval),this.qrCodeCountdownInterval=null)}},watch:{isPlatformLoggedIn(e){e&&this.stopQrCodeAutoRefresh()}},beforeUnmount(){this.stopQrCodeAutoRefresh()}},T3={computed:{updateDialogVisible(){return this.$store?this.$store.state.update.updateDialogVisible:!1},updateInfo(){return this.$store?this.$store.state.update.updateInfo:null},updateProgress(){return this.$store?this.$store.state.update.updateProgress:0},isDownloading(){return this.$store?this.$store.state.update.isDownloading:!1},downloadState(){return this.$store?this.$store.state.update.downloadState:{progress:0,downloadedBytes:0,totalBytes:0}}},methods:{onUpdateAvailable(e){if(console.log("[UpdateMixin] onUpdateAvailable 被调用,updateInfo:",e),!e){console.warn("[UpdateMixin] updateInfo 为空");return}this.$store?(console.log("[UpdateMixin] 更新 store,设置更新信息并显示弹窗"),this.$store.dispatch("update/setUpdateInfo",e),this.$store.dispatch("update/showUpdateDialog"),console.log("[UpdateMixin] Store 状态:",{updateDialogVisible:this.$store.state.update.updateDialogVisible,updateInfo:this.$store.state.update.updateInfo})):console.error("[UpdateMixin] $store 不存在"),this.addLog&&this.addLog("info",`发现新版本: ${e.version||"未知"}`)},onUpdateProgress(e){this.$store&&e&&(this.$store.dispatch("update/setDownloadState",{progress:e.progress||0,downloadedBytes:e.downloadedBytes||0,totalBytes:e.totalBytes||0}),this.$store.dispatch("update/setUpdateProgress",e.progress||0),this.$store.dispatch("update/setDownloading",!0))},onUpdateDownloaded(e){this.$store&&(this.$store.dispatch("update/setDownloading",!1),this.$store.dispatch("update/setUpdateProgress",100)),this.addLog&&this.addLog("success","更新包下载完成"),this.showNotification&&this.showNotification("更新下载完成","更新包已下载完成,是否立即安装?")},onUpdateError(e){this.$store&&this.$store.dispatch("update/setDownloading",!1);const t=(e==null?void 0:e.error)||"更新失败";this.addLog&&this.addLog("error",`更新错误: ${t}`),this.showNotification&&this.showNotification("更新失败",t)},closeUpdateDialog(){this.$store&&this.$store.dispatch("update/hideUpdateDialog")},async startDownload(){const e=this.updateInfo;if(!e||!e.downloadUrl){this.addLog&&this.addLog("error","更新信息不存在");return}if(!window.electronAPI){this.addLog&&this.addLog("error","Electron API不可用");return}try{await window.electronAPI.invoke("update:download",e.downloadUrl)}catch(t){this.addLog&&this.addLog("error",`下载更新失败: ${t.message}`)}},async installUpdate(){if(!window.electronAPI){this.addLog&&this.addLog("error","Electron API不可用");return}try{await window.electronAPI.invoke("update:install"),setTimeout(()=>{this.closeUpdateDialog()},1e3)}catch(e){this.addLog&&this.addLog("error",`安装更新失败: ${e.message}`)}}}},vh={mixins:[bh],data(){return{_registeredEventListeners:[]}},methods:{setupEventListeners(){if(console.log("[事件监听] setupEventListeners 开始执行"),!window.electronAPI||!window.electronEvents){console.error("[事件监听] Electron API不可用",{hasElectronAPI:!!window.electronAPI,hasElectronEvents:!!window.electronEvents}),this.addLog&&this.addLog("error","Electron API不可用");return}const e=window.electronEvents;console.log("[事件监听] electronEvents 对象:",e),[{channel:"mqtt:connected",handler:n=>{console.log("[事件监听] 收到 mqtt:connected 事件,数据:",n),this.onMQTTConnected(n)}},{channel:"mqtt:disconnected",handler:n=>{console.log("[事件监听] 收到 mqtt:disconnected 事件,数据:",n),this.onMQTTDisconnected(n)}},{channel:"mqtt:message",handler:n=>{console.log("[事件监听] 收到 mqtt:message 事件"),this.onMQTTMessage(n)}},{channel:"mqtt:status",handler:n=>{console.log("[事件监听] 收到 mqtt:status 事件,数据:",n),this.onMQTTStatusChange(n)}},{channel:"command:result",handler:n=>{this.addLog&&(n.success?this.addLog("success",`指令执行成功 : ${JSON.stringify(n.data).length}字符`):this.addLog("error",`指令执行失败: ${n.error}`))}},{channel:"system:info",handler:n=>this.updateSystemInfo(n)},{channel:"log:message",handler:n=>{console.log("[事件监听] 收到 log:message 事件,数据:",n),this.addLog&&this.addLog(n.level,n.message)}},{channel:"notification",handler:n=>{this.showNotification&&this.showNotification(n.title,n.body)}},{channel:"update:available",handler:n=>{console.log("[事件监听] 收到 update:available 事件,数据:",n),console.log("[事件监听] onUpdateAvailable 方法存在:",!!this.onUpdateAvailable),this.onUpdateAvailable?this.onUpdateAvailable(n):console.warn("[事件监听] onUpdateAvailable 方法不存在,当前组件:",this.$options.name)}},{channel:"update:progress",handler:n=>{this.onUpdateProgress&&this.onUpdateProgress(n)}},{channel:"update:downloaded",handler:n=>{this.onUpdateDownloaded&&this.onUpdateDownloaded(n)}},{channel:"update:error",handler:n=>{this.onUpdateError&&this.onUpdateError(n)}},{channel:"device:work-status",handler:n=>{this.onDeviceWorkStatus(n)}},{channel:"platform:login-status-updated",handler:n=>{this.onPlatformLoginStatusUpdated?this.onPlatformLoginStatusUpdated(n):console.warn("[事件监听] 无法更新平台登录状态:组件未定义 onPlatformLoginStatusUpdated 且 store 不可用")}}].forEach(({channel:n,handler:o})=>{e.on(n,o),this._registeredEventListeners.push({channel:n,handler:o})}),console.log("[事件监听] 所有事件监听器已设置完成,当前组件:",this.$options.name),console.log("[事件监听] 更新相关方法检查:",{onUpdateAvailable:!!this.onUpdateAvailable,onUpdateProgress:!!this.onUpdateProgress,onUpdateDownloaded:!!this.onUpdateDownloaded,onUpdateError:!!this.onUpdateError}),this.$store&&this.$store.dispatch?(this.$store.dispatch("log/addLog",{level:"info",message:"事件监听器设置完成"}),console.log("[事件监听] 已通过 store.dispatch 添加日志")):this.addLog?(this.addLog("info","事件监听器设置完成"),console.log("[事件监听] 已通过 addLog 方法添加日志")):console.log("[事件监听] 日志系统暂不可用,将在组件完全初始化后记录")},cleanupEventListeners(){console.log("[事件监听] 开始清理事件监听器"),!(!window.electronEvents||!this._registeredEventListeners)&&(this._registeredEventListeners.forEach(({channel:e,handler:t})=>{try{window.electronEvents.off(e,t)}catch(n){console.warn(`[事件监听] 移除监听器失败: ${e}`,n)}}),this._registeredEventListeners=[],console.log("[事件监听] 事件监听器清理完成"))},showNotification(e,t){"Notification"in window&&(Notification.permission==="granted"?new Notification(e,{body:t,icon:"/assets/icon.png"}):Notification.permission!=="denied"&&Notification.requestPermission().then(n=>{n==="granted"&&new Notification(e,{body:t,icon:"/assets/icon.png"})})),this.addLog&&this.addLog("info",`[通知] ${e}: ${t}`)}}},R3={name:"App",mixins:[bn,I3,hh,gh,mh,bh,yh,T3,vh],components:{Sidebar:Hb,UpdateDialog:X6,UserMenu:S3},data(){return{startTime:Date.now(),isLoading:!0,browserWindowVisible:!1}},mounted(){this.setupEventListeners(),console.log("[App] mounted: 事件监听器已设置"),console.log("[App] mounted: 更新相关方法检查:",{onUpdateAvailable:!!this.onUpdateAvailable,onUpdateProgress:!!this.onUpdateProgress,onUpdateDownloaded:!!this.onUpdateDownloaded,onUpdateError:!!this.onUpdateError}),this.init()},watch:{isLoggedIn(e,t){!e&&this.$route.name!=="Login"&&this.$router.push("/login"),e&&!t&&this.$nextTick(()=>{setTimeout(()=>{this.checkMQTTStatus&&this.checkMQTTStatus(),this.startTaskStatusUpdate&&this.startTaskStatusUpdate()},500)})}},methods:{async init(){this.hideLoadingScreen();const e=await window.electronAPI.invoke("system:get-version");e&&e.success&&e.version&&this.$store.dispatch("app/setVersion",e.version),await this.loadSavedConfig(),this.$store&&this.$store.dispatch&&await this.$store.dispatch("delivery/loadDeliveryConfig"),this.startSystemInfoUpdate();const t=await this.tryAutoLogin();this.$store.state.auth.isLoggedIn?(this.startTaskStatusUpdate(),this.checkMQTTStatus()):t||this.$router.push("/login"),setTimeout(()=>{this.checkForUpdate()},3e3)},async checkForUpdate(){var e;try{if(!window.electronAPI||!window.electronAPI.invoke){console.warn("[App] electronAPI 不可用,无法检查更新");return}const t=await window.electronAPI.invoke("update:check",{silent:!0});t&&t.success&&t.hasUpdate?console.log("[App] 发现新版本:",(e=t.updateInfo)==null?void 0:e.version):t&&t.success&&!t.hasUpdate?console.log("[App] 当前已是最新版本"):console.warn("[App] 检查更新失败:",t==null?void 0:t.error)}catch(t){console.error("[App] 检查更新异常:",t)}},hideLoadingScreen(){setTimeout(()=>{const e=document.getElementById("loading-screen"),t=document.getElementById("app");e&&(e.classList.add("hidden"),setTimeout(()=>{e.parentNode&&e.remove()},500)),t&&(t.style.display="block"),this.isLoading=!1},500)},async checkMQTTStatus(){var e,t,n;try{if(!window.electronAPI||!window.electronAPI.invoke){console.warn("[App] electronAPI 不可用");return}const o=await window.electronAPI.invoke("mqtt:status");if(console.log("[App] MQTT 状态查询结果:",o),o&&o.isConnected)this.$store&&(this.$store.dispatch("mqtt/setConnected",!0),console.log("[App] MQTT 状态已更新为已连接"));else{const i=(n=(t=(e=this.$store)==null?void 0:e.state)==null?void 0:t.auth)==null?void 0:n.snCode;if(i){console.log("[App] MQTT 未连接,尝试重新连接...");try{await window.electronAPI.invoke("mqtt:connect",i),console.log("[App] MQTT 重新连接成功"),this.$store&&this.$store.dispatch("mqtt/setConnected",!0)}catch(r){console.warn("[App] MQTT 重新连接失败:",r),this.$store&&this.$store.dispatch("mqtt/setConnected",!1)}}else console.warn("[App] 无法重新连接 MQTT: 缺少 snCode")}}catch(o){console.error("[App] 检查 MQTT 状态失败:",o)}}},computed:{...Ze("app",["currentVersion"]),...Ze("mqtt",["isConnected"]),...Ze("auth",["isLoggedIn","userName","snCode","deviceId","remainingDays","phone"]),showSidebar(){return this.$route.meta.showSidebar!==!1},statusDotClass(){return{"status-dot":!0,connected:this.isConnected}}}},O3={class:"container"},E3={class:"header"},A3={class:"header-left"},L3={style:{"font-size":"0.7em",opacity:"0.8"}},_3={class:"status-indicator"},D3={class:"header-right"},B3={class:"main-content"};function M3(e,t,n,o,i,r){const a=R("UserMenu"),l=R("Sidebar"),s=R("router-view"),d=R("UpdateDialog");return g(),b("div",O3,[h("header",E3,[h("div",A3,[h("h1",null,[t[0]||(t[0]=$e("Boss - 远程监听服务 ",-1)),h("span",L3,"v"+_(e.currentVersion),1)]),h("div",_3,[h("span",{class:J(r.statusDotClass)},null,2),h("span",null,_(e.isConnected?"已连接":"未连接"),1)])]),h("div",D3,[r.showSidebar?(g(),T(a,{key:0})):I("",!0)])]),h("div",B3,[r.showSidebar?(g(),T(l,{key:0})):I("",!0),h("div",{class:J(["content-area",{"full-width":!r.showSidebar}])},[D(s)],2)]),D(d)])}const z3=dt(R3,[["render",M3],["__scopeId","data-v-84f95a09"]]);/*! - * vue-router v4.6.4 - * (c) 2025 Eduardo San Martin Morote - * @license MIT - */const co=typeof document<"u";function wh(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function F3(e){return e.__esModule||e[Symbol.toStringTag]==="Module"||e.default&&wh(e.default)}const Pe=Object.assign;function La(e,t){const n={};for(const o in t){const i=t[o];n[o]=Mt(i)?i.map(e):e(i)}return n}const er=()=>{},Mt=Array.isArray;function Wu(e,t){const n={};for(const o in e)n[o]=o in t?t[o]:e[o];return n}const Ch=/#/g,j3=/&/g,N3=/\//g,V3=/=/g,U3=/\?/g,kh=/\+/g,H3=/%5B/g,G3=/%5D/g,Sh=/%5E/g,K3=/%60/g,xh=/%7B/g,W3=/%7C/g,$h=/%7D/g,q3=/%20/g;function Bs(e){return e==null?"":encodeURI(""+e).replace(W3,"|").replace(H3,"[").replace(G3,"]")}function Q3(e){return Bs(e).replace(xh,"{").replace($h,"}").replace(Sh,"^")}function ql(e){return Bs(e).replace(kh,"%2B").replace(q3,"+").replace(Ch,"%23").replace(j3,"%26").replace(K3,"`").replace(xh,"{").replace($h,"}").replace(Sh,"^")}function Z3(e){return ql(e).replace(V3,"%3D")}function Y3(e){return Bs(e).replace(Ch,"%23").replace(U3,"%3F")}function X3(e){return Y3(e).replace(N3,"%2F")}function Yr(e){if(e==null)return null;try{return decodeURIComponent(""+e)}catch{}return""+e}const J3=/\/$/,e4=e=>e.replace(J3,"");function _a(e,t,n="/"){let o,i={},r="",a="";const l=t.indexOf("#");let s=t.indexOf("?");return s=l>=0&&s>l?-1:s,s>=0&&(o=t.slice(0,s),r=t.slice(s,l>0?l:t.length),i=e(r.slice(1))),l>=0&&(o=o||t.slice(0,l),a=t.slice(l,t.length)),o=r4(o??t,n),{fullPath:o+r+a,path:o,query:i,hash:Yr(a)}}function t4(e,t){const n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}function qu(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function n4(e,t,n){const o=t.matched.length-1,i=n.matched.length-1;return o>-1&&o===i&&ko(t.matched[o],n.matched[i])&&Ph(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function ko(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function Ph(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(var n in e)if(!o4(e[n],t[n]))return!1;return!0}function o4(e,t){return Mt(e)?Qu(e,t):Mt(t)?Qu(t,e):(e==null?void 0:e.valueOf())===(t==null?void 0:t.valueOf())}function Qu(e,t){return Mt(t)?e.length===t.length&&e.every((n,o)=>n===t[o]):e.length===1&&e[0]===t}function r4(e,t){if(e.startsWith("/"))return e;if(!e)return t;const n=t.split("/"),o=e.split("/"),i=o[o.length-1];(i===".."||i===".")&&o.push("");let r=n.length-1,a,l;for(a=0;a1&&r--;else break;return n.slice(0,r).join("/")+"/"+o.slice(a).join("/")}const wn={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0};let Ql=function(e){return e.pop="pop",e.push="push",e}({}),Da=function(e){return e.back="back",e.forward="forward",e.unknown="",e}({});function i4(e){if(!e)if(co){const t=document.querySelector("base");e=t&&t.getAttribute("href")||"/",e=e.replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return e[0]!=="/"&&e[0]!=="#"&&(e="/"+e),e4(e)}const a4=/^[^#]+#/;function l4(e,t){return e.replace(a4,"#")+t}function s4(e,t){const n=document.documentElement.getBoundingClientRect(),o=e.getBoundingClientRect();return{behavior:t.behavior,left:o.left-n.left-(t.left||0),top:o.top-n.top-(t.top||0)}}const pa=()=>({left:window.scrollX,top:window.scrollY});function d4(e){let t;if("el"in e){const n=e.el,o=typeof n=="string"&&n.startsWith("#"),i=typeof n=="string"?o?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!i)return;t=s4(i,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(t.left!=null?t.left:window.scrollX,t.top!=null?t.top:window.scrollY)}function Zu(e,t){return(history.state?history.state.position-t:-1)+e}const Zl=new Map;function u4(e,t){Zl.set(e,t)}function c4(e){const t=Zl.get(e);return Zl.delete(e),t}function f4(e){return typeof e=="string"||e&&typeof e=="object"}function Ih(e){return typeof e=="string"||typeof e=="symbol"}let Ne=function(e){return e[e.MATCHER_NOT_FOUND=1]="MATCHER_NOT_FOUND",e[e.NAVIGATION_GUARD_REDIRECT=2]="NAVIGATION_GUARD_REDIRECT",e[e.NAVIGATION_ABORTED=4]="NAVIGATION_ABORTED",e[e.NAVIGATION_CANCELLED=8]="NAVIGATION_CANCELLED",e[e.NAVIGATION_DUPLICATED=16]="NAVIGATION_DUPLICATED",e}({});const Th=Symbol("");Ne.MATCHER_NOT_FOUND+"",Ne.NAVIGATION_GUARD_REDIRECT+"",Ne.NAVIGATION_ABORTED+"",Ne.NAVIGATION_CANCELLED+"",Ne.NAVIGATION_DUPLICATED+"";function So(e,t){return Pe(new Error,{type:e,[Th]:!0},t)}function rn(e,t){return e instanceof Error&&Th in e&&(t==null||!!(e.type&t))}const p4=["params","query","hash"];function h4(e){if(typeof e=="string")return e;if(e.path!=null)return e.path;const t={};for(const n of p4)n in e&&(t[n]=e[n]);return JSON.stringify(t,null,2)}function g4(e){const t={};if(e===""||e==="?")return t;const n=(e[0]==="?"?e.slice(1):e).split("&");for(let o=0;oi&&ql(i)):[o&&ql(o)]).forEach(i=>{i!==void 0&&(t+=(t.length?"&":"")+n,i!=null&&(t+="="+i))})}return t}function m4(e){const t={};for(const n in e){const o=e[n];o!==void 0&&(t[n]=Mt(o)?o.map(i=>i==null?null:""+i):o==null?o:""+o)}return t}const b4=Symbol(""),Xu=Symbol(""),Ms=Symbol(""),Rh=Symbol(""),Yl=Symbol("");function zo(){let e=[];function t(o){return e.push(o),()=>{const i=e.indexOf(o);i>-1&&e.splice(i,1)}}function n(){e=[]}return{add:t,list:()=>e.slice(),reset:n}}function xn(e,t,n,o,i,r=a=>a()){const a=o&&(o.enterCallbacks[i]=o.enterCallbacks[i]||[]);return()=>new Promise((l,s)=>{const d=f=>{f===!1?s(So(Ne.NAVIGATION_ABORTED,{from:n,to:t})):f instanceof Error?s(f):f4(f)?s(So(Ne.NAVIGATION_GUARD_REDIRECT,{from:t,to:f})):(a&&o.enterCallbacks[i]===a&&typeof f=="function"&&a.push(f),l())},u=r(()=>e.call(o&&o.instances[i],t,n,d));let c=Promise.resolve(u);e.length<3&&(c=c.then(d)),c.catch(f=>s(f))})}function Ba(e,t,n,o,i=r=>r()){const r=[];for(const a of e)for(const l in a.components){let s=a.components[l];if(!(t!=="beforeRouteEnter"&&!a.instances[l]))if(wh(s)){const d=(s.__vccOpts||s)[t];d&&r.push(xn(d,n,o,a,l,i))}else{let d=s();r.push(()=>d.then(u=>{if(!u)throw new Error(`Couldn't resolve component "${l}" at "${a.path}"`);const c=F3(u)?u.default:u;a.mods[l]=u,a.components[l]=c;const f=(c.__vccOpts||c)[t];return f&&xn(f,n,o,a,l,i)()}))}}return r}function y4(e,t){const n=[],o=[],i=[],r=Math.max(t.matched.length,e.matched.length);for(let a=0;ako(d,l))?o.push(l):n.push(l));const s=e.matched[a];s&&(t.matched.find(d=>ko(d,s))||i.push(s))}return[n,o,i]}/*! - * vue-router v4.6.4 - * (c) 2025 Eduardo San Martin Morote - * @license MIT - */let v4=()=>location.protocol+"//"+location.host;function Oh(e,t){const{pathname:n,search:o,hash:i}=t,r=e.indexOf("#");if(r>-1){let a=i.includes(e.slice(r))?e.slice(r).length:1,l=i.slice(a);return l[0]!=="/"&&(l="/"+l),qu(l,"")}return qu(n,e)+o+i}function w4(e,t,n,o){let i=[],r=[],a=null;const l=({state:f})=>{const p=Oh(e,location),v=n.value,C=t.value;let S=0;if(f){if(n.value=p,t.value=f,a&&a===v){a=null;return}S=C?f.position-C.position:0}else o(p);i.forEach(x=>{x(n.value,v,{delta:S,type:Ql.pop,direction:S?S>0?Da.forward:Da.back:Da.unknown})})};function s(){a=n.value}function d(f){i.push(f);const p=()=>{const v=i.indexOf(f);v>-1&&i.splice(v,1)};return r.push(p),p}function u(){if(document.visibilityState==="hidden"){const{history:f}=window;if(!f.state)return;f.replaceState(Pe({},f.state,{scroll:pa()}),"")}}function c(){for(const f of r)f();r=[],window.removeEventListener("popstate",l),window.removeEventListener("pagehide",u),document.removeEventListener("visibilitychange",u)}return window.addEventListener("popstate",l),window.addEventListener("pagehide",u),document.addEventListener("visibilitychange",u),{pauseListeners:s,listen:d,destroy:c}}function Ju(e,t,n,o=!1,i=!1){return{back:e,current:t,forward:n,replaced:o,position:window.history.length,scroll:i?pa():null}}function C4(e){const{history:t,location:n}=window,o={value:Oh(e,n)},i={value:t.state};i.value||r(o.value,{back:null,current:o.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function r(s,d,u){const c=e.indexOf("#"),f=c>-1?(n.host&&document.querySelector("base")?e:e.slice(c))+s:v4()+e+s;try{t[u?"replaceState":"pushState"](d,"",f),i.value=d}catch(p){console.error(p),n[u?"replace":"assign"](f)}}function a(s,d){r(s,Pe({},t.state,Ju(i.value.back,s,i.value.forward,!0),d,{position:i.value.position}),!0),o.value=s}function l(s,d){const u=Pe({},i.value,t.state,{forward:s,scroll:pa()});r(u.current,u,!0),r(s,Pe({},Ju(o.value,s,null),{position:u.position+1},d),!1),o.value=s}return{location:o,state:i,push:l,replace:a}}function k4(e){e=i4(e);const t=C4(e),n=w4(e,t.state,t.location,t.replace);function o(r,a=!0){a||n.pauseListeners(),history.go(r)}const i=Pe({location:"",base:e,go:o,createHref:l4.bind(null,e)},t,n);return Object.defineProperty(i,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(i,"state",{enumerable:!0,get:()=>t.state.value}),i}function S4(e){return e=location.host?e||location.pathname+location.search:"",e.includes("#")||(e+="#"),k4(e)}let Hn=function(e){return e[e.Static=0]="Static",e[e.Param=1]="Param",e[e.Group=2]="Group",e}({});var He=function(e){return e[e.Static=0]="Static",e[e.Param=1]="Param",e[e.ParamRegExp=2]="ParamRegExp",e[e.ParamRegExpEnd=3]="ParamRegExpEnd",e[e.EscapeNext=4]="EscapeNext",e}(He||{});const x4={type:Hn.Static,value:""},$4=/[a-zA-Z0-9_]/;function P4(e){if(!e)return[[]];if(e==="/")return[[x4]];if(!e.startsWith("/"))throw new Error(`Invalid path "${e}"`);function t(p){throw new Error(`ERR (${n})/"${d}": ${p}`)}let n=He.Static,o=n;const i=[];let r;function a(){r&&i.push(r),r=[]}let l=0,s,d="",u="";function c(){d&&(n===He.Static?r.push({type:Hn.Static,value:d}):n===He.Param||n===He.ParamRegExp||n===He.ParamRegExpEnd?(r.length>1&&(s==="*"||s==="+")&&t(`A repeatable param (${d}) must be alone in its segment. eg: '/:ids+.`),r.push({type:Hn.Param,value:d,regexp:u,repeatable:s==="*"||s==="+",optional:s==="*"||s==="?"})):t("Invalid state to consume buffer"),d="")}function f(){d+=s}for(;lt.length?t.length===1&&t[0]===lt.Static+lt.Segment?1:-1:0}function Eh(e,t){let n=0;const o=e.score,i=t.score;for(;n0&&t[t.length-1]<0}const E4={strict:!1,end:!0,sensitive:!1};function A4(e,t,n){const o=R4(P4(e.path),n),i=Pe(o,{record:e,parent:t,children:[],alias:[]});return t&&!i.record.aliasOf==!t.record.aliasOf&&t.children.push(i),i}function L4(e,t){const n=[],o=new Map;t=Wu(E4,t);function i(c){return o.get(c)}function r(c,f,p){const v=!p,C=oc(c);C.aliasOf=p&&p.record;const S=Wu(t,c),x=[C];if("alias"in c){const k=typeof c.alias=="string"?[c.alias]:c.alias;for(const F of k)x.push(oc(Pe({},C,{components:p?p.record.components:C.components,path:F,aliasOf:p?p.record:C})))}let P,L;for(const k of x){const{path:F}=k;if(f&&F[0]!=="/"){const K=f.record.path,z=K[K.length-1]==="/"?"":"/";k.path=f.record.path+(F&&z+F)}if(P=A4(k,f,S),p?p.alias.push(P):(L=L||P,L!==P&&L.alias.push(P),v&&c.name&&!rc(P)&&a(c.name)),Ah(P)&&s(P),C.children){const K=C.children;for(let z=0;z{a(L)}:er}function a(c){if(Ih(c)){const f=o.get(c);f&&(o.delete(c),n.splice(n.indexOf(f),1),f.children.forEach(a),f.alias.forEach(a))}else{const f=n.indexOf(c);f>-1&&(n.splice(f,1),c.record.name&&o.delete(c.record.name),c.children.forEach(a),c.alias.forEach(a))}}function l(){return n}function s(c){const f=B4(c,n);n.splice(f,0,c),c.record.name&&!rc(c)&&o.set(c.record.name,c)}function d(c,f){let p,v={},C,S;if("name"in c&&c.name){if(p=o.get(c.name),!p)throw So(Ne.MATCHER_NOT_FOUND,{location:c});S=p.record.name,v=Pe(nc(f.params,p.keys.filter(L=>!L.optional).concat(p.parent?p.parent.keys.filter(L=>L.optional):[]).map(L=>L.name)),c.params&&nc(c.params,p.keys.map(L=>L.name))),C=p.stringify(v)}else if(c.path!=null)C=c.path,p=n.find(L=>L.re.test(C)),p&&(v=p.parse(C),S=p.record.name);else{if(p=f.name?o.get(f.name):n.find(L=>L.re.test(f.path)),!p)throw So(Ne.MATCHER_NOT_FOUND,{location:c,currentLocation:f});S=p.record.name,v=Pe({},f.params,c.params),C=p.stringify(v)}const x=[];let P=p;for(;P;)x.unshift(P.record),P=P.parent;return{name:S,path:C,params:v,matched:x,meta:D4(x)}}e.forEach(c=>r(c));function u(){n.length=0,o.clear()}return{addRoute:r,resolve:d,removeRoute:a,clearRoutes:u,getRoutes:l,getRecordMatcher:i}}function nc(e,t){const n={};for(const o of t)o in e&&(n[o]=e[o]);return n}function oc(e){const t={path:e.path,redirect:e.redirect,name:e.name,meta:e.meta||{},aliasOf:e.aliasOf,beforeEnter:e.beforeEnter,props:_4(e),children:e.children||[],instances:{},leaveGuards:new Set,updateGuards:new Set,enterCallbacks:{},components:"components"in e?e.components||null:e.component&&{default:e.component}};return Object.defineProperty(t,"mods",{value:{}}),t}function _4(e){const t={},n=e.props||!1;if("component"in e)t.default=n;else for(const o in e.components)t[o]=typeof n=="object"?n[o]:n;return t}function rc(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function D4(e){return e.reduce((t,n)=>Pe(t,n.meta),{})}function B4(e,t){let n=0,o=t.length;for(;n!==o;){const r=n+o>>1;Eh(e,t[r])<0?o=r:n=r+1}const i=M4(e);return i&&(o=t.lastIndexOf(i,o-1)),o}function M4(e){let t=e;for(;t=t.parent;)if(Ah(t)&&Eh(e,t)===0)return t}function Ah({record:e}){return!!(e.name||e.components&&Object.keys(e.components).length||e.redirect)}function ic(e){const t=cn(Ms),n=cn(Rh),o=Ct(()=>{const s=go(e.to);return t.resolve(s)}),i=Ct(()=>{const{matched:s}=o.value,{length:d}=s,u=s[d-1],c=n.matched;if(!u||!c.length)return-1;const f=c.findIndex(ko.bind(null,u));if(f>-1)return f;const p=ac(s[d-2]);return d>1&&ac(u)===p&&c[c.length-1].path!==p?c.findIndex(ko.bind(null,s[d-2])):f}),r=Ct(()=>i.value>-1&&V4(n.params,o.value.params)),a=Ct(()=>i.value>-1&&i.value===n.matched.length-1&&Ph(n.params,o.value.params));function l(s={}){if(N4(s)){const d=t[go(e.replace)?"replace":"push"](go(e.to)).catch(er);return e.viewTransition&&typeof document<"u"&&"startViewTransition"in document&&document.startViewTransition(()=>d),d}return Promise.resolve()}return{route:o,href:Ct(()=>o.value.href),isActive:r,isExactActive:a,navigate:l}}function z4(e){return e.length===1?e[0]:e}const F4=of({name:"RouterLink",compatConfig:{MODE:3},props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"},viewTransition:Boolean},useLink:ic,setup(e,{slots:t}){const n=Po(ic(e)),{options:o}=cn(Ms),i=Ct(()=>({[lc(e.activeClass,o.linkActiveClass,"router-link-active")]:n.isActive,[lc(e.exactActiveClass,o.linkExactActiveClass,"router-link-exact-active")]:n.isExactActive}));return()=>{const r=t.default&&z4(t.default(n));return e.custom?r:ys("a",{"aria-current":n.isExactActive?e.ariaCurrentValue:null,href:n.href,onClick:n.navigate,class:i.value},r)}}}),j4=F4;function N4(e){if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)&&!e.defaultPrevented&&!(e.button!==void 0&&e.button!==0)){if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}return e.preventDefault&&e.preventDefault(),!0}}function V4(e,t){for(const n in t){const o=t[n],i=e[n];if(typeof o=="string"){if(o!==i)return!1}else if(!Mt(i)||i.length!==o.length||o.some((r,a)=>r.valueOf()!==i[a].valueOf()))return!1}return!0}function ac(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const lc=(e,t,n)=>e??t??n,U4=of({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},compatConfig:{MODE:3},setup(e,{attrs:t,slots:n}){const o=cn(Yl),i=Ct(()=>e.route||o.value),r=cn(Xu,0),a=Ct(()=>{let d=go(r);const{matched:u}=i.value;let c;for(;(c=u[d])&&!c.components;)d++;return d}),l=Ct(()=>i.value.matched[a.value]);xi(Xu,Ct(()=>a.value+1)),xi(b4,l),xi(Yl,i);const s=Wo();return Lt(()=>[s.value,l.value,e.name],([d,u,c],[f,p,v])=>{u&&(u.instances[c]=d,p&&p!==u&&d&&d===f&&(u.leaveGuards.size||(u.leaveGuards=p.leaveGuards),u.updateGuards.size||(u.updateGuards=p.updateGuards))),d&&u&&(!p||!ko(u,p)||!f)&&(u.enterCallbacks[c]||[]).forEach(C=>C(d))},{flush:"post"}),()=>{const d=i.value,u=e.name,c=l.value,f=c&&c.components[u];if(!f)return sc(n.default,{Component:f,route:d});const p=c.props[u],v=p?p===!0?d.params:typeof p=="function"?p(d):p:null,S=ys(f,Pe({},v,t,{onVnodeUnmounted:x=>{x.component.isUnmounted&&(c.instances[u]=null)},ref:s}));return sc(n.default,{Component:S,route:d})||S}}});function sc(e,t){if(!e)return null;const n=e(t);return n.length===1?n[0]:n}const H4=U4;function G4(e){const t=L4(e.routes,e),n=e.parseQuery||g4,o=e.stringifyQuery||Yu,i=e.history,r=zo(),a=zo(),l=zo(),s=pg(wn);let d=wn;co&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const u=La.bind(null,A=>""+A),c=La.bind(null,X3),f=La.bind(null,Yr);function p(A,Y){let Q,oe;return Ih(A)?(Q=t.getRecordMatcher(A),oe=Y):oe=A,t.addRoute(oe,Q)}function v(A){const Y=t.getRecordMatcher(A);Y&&t.removeRoute(Y)}function C(){return t.getRoutes().map(A=>A.record)}function S(A){return!!t.getRecordMatcher(A)}function x(A,Y){if(Y=Pe({},Y||s.value),typeof A=="string"){const $=_a(n,A,Y.path),E=t.resolve({path:$.path},Y),B=i.createHref($.fullPath);return Pe($,E,{params:f(E.params),hash:Yr($.hash),redirectedFrom:void 0,href:B})}let Q;if(A.path!=null)Q=Pe({},A,{path:_a(n,A.path,Y.path).path});else{const $=Pe({},A.params);for(const E in $)$[E]==null&&delete $[E];Q=Pe({},A,{params:c($)}),Y.params=c(Y.params)}const oe=t.resolve(Q,Y),ve=A.hash||"";oe.params=u(f(oe.params));const y=t4(o,Pe({},A,{hash:Q3(ve),path:oe.path})),w=i.createHref(y);return Pe({fullPath:y,hash:ve,query:o===Yu?m4(A.query):A.query||{}},oe,{redirectedFrom:void 0,href:w})}function P(A){return typeof A=="string"?_a(n,A,s.value.path):Pe({},A)}function L(A,Y){if(d!==A)return So(Ne.NAVIGATION_CANCELLED,{from:Y,to:A})}function k(A){return z(A)}function F(A){return k(Pe(P(A),{replace:!0}))}function K(A,Y){const Q=A.matched[A.matched.length-1];if(Q&&Q.redirect){const{redirect:oe}=Q;let ve=typeof oe=="function"?oe(A,Y):oe;return typeof ve=="string"&&(ve=ve.includes("?")||ve.includes("#")?ve=P(ve):{path:ve},ve.params={}),Pe({query:A.query,hash:A.hash,params:ve.path!=null?{}:A.params},ve)}}function z(A,Y){const Q=d=x(A),oe=s.value,ve=A.state,y=A.force,w=A.replace===!0,$=K(Q,oe);if($)return z(Pe(P($),{state:typeof $=="object"?Pe({},ve,$.state):ve,force:y,replace:w}),Y||Q);const E=Q;E.redirectedFrom=Y;let B;return!y&&n4(o,oe,Q)&&(B=So(Ne.NAVIGATION_DUPLICATED,{to:E,from:oe}),Ue(oe,oe,!0,!1)),(B?Promise.resolve(B):ee(E,oe)).catch(O=>rn(O)?rn(O,Ne.NAVIGATION_GUARD_REDIRECT)?O:Ve(O):ge(O,E,oe)).then(O=>{if(O){if(rn(O,Ne.NAVIGATION_GUARD_REDIRECT))return z(Pe({replace:w},P(O.to),{state:typeof O.to=="object"?Pe({},ve,O.to.state):ve,force:y}),Y||E)}else O=j(E,oe,!0,w,ve);return X(E,oe,O),O})}function q(A,Y){const Q=L(A,Y);return Q?Promise.reject(Q):Promise.resolve()}function H(A){const Y=bt.values().next().value;return Y&&typeof Y.runWithContext=="function"?Y.runWithContext(A):A()}function ee(A,Y){let Q;const[oe,ve,y]=y4(A,Y);Q=Ba(oe.reverse(),"beforeRouteLeave",A,Y);for(const $ of oe)$.leaveGuards.forEach(E=>{Q.push(xn(E,A,Y))});const w=q.bind(null,A,Y);return Q.push(w),rt(Q).then(()=>{Q=[];for(const $ of r.list())Q.push(xn($,A,Y));return Q.push(w),rt(Q)}).then(()=>{Q=Ba(ve,"beforeRouteUpdate",A,Y);for(const $ of ve)$.updateGuards.forEach(E=>{Q.push(xn(E,A,Y))});return Q.push(w),rt(Q)}).then(()=>{Q=[];for(const $ of y)if($.beforeEnter)if(Mt($.beforeEnter))for(const E of $.beforeEnter)Q.push(xn(E,A,Y));else Q.push(xn($.beforeEnter,A,Y));return Q.push(w),rt(Q)}).then(()=>(A.matched.forEach($=>$.enterCallbacks={}),Q=Ba(y,"beforeRouteEnter",A,Y,H),Q.push(w),rt(Q))).then(()=>{Q=[];for(const $ of a.list())Q.push(xn($,A,Y));return Q.push(w),rt(Q)}).catch($=>rn($,Ne.NAVIGATION_CANCELLED)?$:Promise.reject($))}function X(A,Y,Q){l.list().forEach(oe=>H(()=>oe(A,Y,Q)))}function j(A,Y,Q,oe,ve){const y=L(A,Y);if(y)return y;const w=Y===wn,$=co?history.state:{};Q&&(oe||w?i.replace(A.fullPath,Pe({scroll:w&&$&&$.scroll},ve)):i.push(A.fullPath,ve)),s.value=A,Ue(A,Y,Q,w),Ve()}let le;function pe(){le||(le=i.listen((A,Y,Q)=>{if(!Nt.listening)return;const oe=x(A),ve=K(oe,Nt.currentRoute.value);if(ve){z(Pe(ve,{replace:!0,force:!0}),oe).catch(er);return}d=oe;const y=s.value;co&&u4(Zu(y.fullPath,Q.delta),pa()),ee(oe,y).catch(w=>rn(w,Ne.NAVIGATION_ABORTED|Ne.NAVIGATION_CANCELLED)?w:rn(w,Ne.NAVIGATION_GUARD_REDIRECT)?(z(Pe(P(w.to),{force:!0}),oe).then($=>{rn($,Ne.NAVIGATION_ABORTED|Ne.NAVIGATION_DUPLICATED)&&!Q.delta&&Q.type===Ql.pop&&i.go(-1,!1)}).catch(er),Promise.reject()):(Q.delta&&i.go(-Q.delta,!1),ge(w,oe,y))).then(w=>{w=w||j(oe,y,!1),w&&(Q.delta&&!rn(w,Ne.NAVIGATION_CANCELLED)?i.go(-Q.delta,!1):Q.type===Ql.pop&&rn(w,Ne.NAVIGATION_ABORTED|Ne.NAVIGATION_DUPLICATED)&&i.go(-1,!1)),X(oe,y,w)}).catch(er)}))}let ue=zo(),se=zo(),ne;function ge(A,Y,Q){Ve(A);const oe=se.list();return oe.length?oe.forEach(ve=>ve(A,Y,Q)):console.error(A),Promise.reject(A)}function De(){return ne&&s.value!==wn?Promise.resolve():new Promise((A,Y)=>{ue.add([A,Y])})}function Ve(A){return ne||(ne=!A,pe(),ue.list().forEach(([Y,Q])=>A?Q(A):Y()),ue.reset()),A}function Ue(A,Y,Q,oe){const{scrollBehavior:ve}=e;if(!co||!ve)return Promise.resolve();const y=!Q&&c4(Zu(A.fullPath,0))||(oe||!Q)&&history.state&&history.state.scroll||null;return ds().then(()=>ve(A,Y,y)).then(w=>w&&d4(w)).catch(w=>ge(w,A,Y))}const je=A=>i.go(A);let Ot;const bt=new Set,Nt={currentRoute:s,listening:!0,addRoute:p,removeRoute:v,clearRoutes:t.clearRoutes,hasRoute:S,getRoutes:C,resolve:x,options:e,push:k,replace:F,go:je,back:()=>je(-1),forward:()=>je(1),beforeEach:r.add,beforeResolve:a.add,afterEach:l.add,onError:se.add,isReady:De,install(A){A.component("RouterLink",j4),A.component("RouterView",H4),A.config.globalProperties.$router=Nt,Object.defineProperty(A.config.globalProperties,"$route",{enumerable:!0,get:()=>go(s)}),co&&!Ot&&s.value===wn&&(Ot=!0,k(i.location).catch(oe=>{}));const Y={};for(const oe in wn)Object.defineProperty(Y,oe,{get:()=>s.value[oe],enumerable:!0});A.provide(Ms,Nt),A.provide(Rh,jc(Y)),A.provide(Yl,s);const Q=A.unmount;bt.add(A),A.unmount=function(){bt.delete(A),bt.size<1&&(d=wn,le&&le(),le=null,s.value=wn,Ot=!1,ne=!1),Q()}}};function rt(A){return A.reduce((Y,Q)=>Y.then(()=>H(Q)),Promise.resolve())}return Nt}const K4={name:"LoginPage",components:{InputText:eo,Password:yp,Button:xt,Checkbox:da,Message:ca},data(){return{email:"",password:"",rememberMe:!0,isLoading:!1,errorMessage:""}},mounted(){if(this.$store){const e=this.$store.state.config.email||this.$store.state.auth.email;e&&(this.email=e);const t=this.$store.state.config.rememberMe;t!==void 0&&(this.rememberMe=t)}},methods:{generateDeviceId(){if(this.$store){let e=this.$store.state.config.deviceId||this.$store.state.auth.deviceId;if(e)return e}try{const e=[navigator.userAgent,navigator.language,navigator.platform,screen.width,screen.height,screen.colorDepth,new Date().getTimezoneOffset()].join("|");let t=0;for(let o=0;o[$e(_(i.errorMessage),1)]),_:1})):I("",!0),h("div",Z4,[t[3]||(t[3]=h("label",{class:"form-label"},"邮箱",-1)),D(l,{modelValue:i.email,"onUpdate:modelValue":t[0]||(t[0]=u=>i.email=u),type:"email",placeholder:"请输入邮箱地址",autocomplete:"email",class:"form-input",onKeyup:Xo(r.handleLogin,["enter"])},null,8,["modelValue","onKeyup"])]),h("div",Y4,[t[4]||(t[4]=h("label",{class:"form-label"},"密码",-1)),D(l,{modelValue:i.password,"onUpdate:modelValue":t[1]||(t[1]=u=>i.password=u),type:"password",placeholder:"请输入密码",autocomplete:"current-password",class:"form-input",onKeyup:Xo(r.handleLogin,["enter"])},null,8,["modelValue","onKeyup"])]),h("div",X4,[h("div",J4,[D(s,{modelValue:i.rememberMe,"onUpdate:modelValue":t[2]||(t[2]=u=>i.rememberMe=u),inputId:"remember",binary:""},null,8,["modelValue"]),t[5]||(t[5]=h("label",{for:"remember",class:"remember-label"},"记住登录信息",-1))])]),h("div",e7,[D(d,{label:"登录",onClick:r.handleLogin,disabled:i.isLoading||!i.email||!i.password,loading:i.isLoading,class:"btn-block"},null,8,["onClick","disabled","loading"])])])])])}const n7=dt(K4,[["render",t7],["__scopeId","data-v-b5ae25b5"]]),o7={name:"DeliverySettings",mixins:[bn],components:{ToggleSwitch:Es,InputText:eo,Select:no},props:{config:{type:Object,required:!0}},data(){return{workdaysOptions:[{label:"全部日期",value:!1},{label:"仅工作日",value:!0}]}},methods:{...oa("delivery",["updateDeliveryConfig","saveDeliveryConfig"]),updateConfig(e,t){this.updateDeliveryConfig({key:e,value:t})},async handleSave(){const e=await this.saveDeliveryConfig();e&&e.success?this.addLog("success","投递配置已保存"):this.addLog("error",(e==null?void 0:e.error)||"保存配置失败")}}},r7={class:"settings-section"},i7={class:"settings-form-horizontal"},a7={class:"form-row"},l7={class:"form-item"},s7={class:"switch-label"},d7={class:"form-item"},u7={class:"form-item"},c7={class:"form-item"};function f7(e,t,n,o,i,r){const a=R("ToggleSwitch"),l=R("InputText"),s=R("Select");return g(),b("div",r7,[h("div",i7,[h("div",a7,[h("div",l7,[t[4]||(t[4]=h("label",{class:"form-label"},"自动投递:",-1)),D(a,{modelValue:n.config.autoDelivery,"onUpdate:modelValue":t[0]||(t[0]=d=>r.updateConfig("autoDelivery",d))},null,8,["modelValue"]),h("span",s7,_(n.config.autoDelivery?"开启":"关闭"),1)]),h("div",d7,[t[5]||(t[5]=h("label",{class:"form-label"},"投递开始时间:",-1)),D(l,{type:"time",value:n.config.startTime,onInput:t[1]||(t[1]=d=>r.updateConfig("startTime",d.target.value)),class:"form-input"},null,8,["value"])]),h("div",u7,[t[6]||(t[6]=h("label",{class:"form-label"},"投递结束时间:",-1)),D(l,{type:"time",value:n.config.endTime,onInput:t[2]||(t[2]=d=>r.updateConfig("endTime",d.target.value)),class:"form-input"},null,8,["value"])]),h("div",c7,[t[7]||(t[7]=h("label",{class:"form-label"},"是否仅工作日:",-1)),D(s,{modelValue:n.config.workdaysOnly,options:i.workdaysOptions,optionLabel:"label",optionValue:"value","onUpdate:modelValue":t[3]||(t[3]=d=>r.updateConfig("workdaysOnly",d)),class:"form-input"},null,8,["modelValue","options"])])])])])}const p7=dt(o7,[["render",f7],["__scopeId","data-v-7fa19e94"]]),h7={name:"DeliveryTrendChart",props:{data:{type:Array,default:()=>[]}},data(){return{chartWidth:600,chartHeight:200,padding:{top:20,right:20,bottom:30,left:40}}},computed:{chartData(){if(!this.data||this.data.length===0){const e=new Date;return Array.from({length:7},(t,n)=>{const o=new Date(e);return o.setDate(o.getDate()-(6-n)),{date:this.formatDate(o),value:0}})}return this.data},maxValue(){const e=this.chartData.map(n=>n.value),t=Math.max(...e,1);return Math.ceil(t*1.2)}},mounted(){this.drawChart()},watch:{chartData:{handler(){this.$nextTick(()=>{this.drawChart()})},deep:!0}},methods:{formatDate(e){const t=e.getMonth()+1,n=e.getDate();return`${t}/${n}`},drawChart(){const e=this.$refs.chartCanvas;if(!e)return;const t=e.getContext("2d"),{width:n,height:o}=e,{padding:i}=this;t.clearRect(0,0,n,o);const r=n-i.left-i.right,a=o-i.top-i.bottom;t.fillStyle="#f9f9f9",t.fillRect(i.left,i.top,r,a),t.strokeStyle="#e0e0e0",t.lineWidth=1;for(let l=0;l<=5;l++){const s=i.top+a/5*l;t.beginPath(),t.moveTo(i.left,s),t.lineTo(i.left+r,s),t.stroke()}for(let l=0;l<=7;l++){const s=i.left+r/7*l;t.beginPath(),t.moveTo(s,i.top),t.lineTo(s,i.top+a),t.stroke()}if(this.chartData.length>0){const l=this.chartData.map((d,u)=>{const c=i.left+r/(this.chartData.length-1)*u,f=i.top+a-d.value/this.maxValue*a;return{x:c,y:f,value:d.value}});t.strokeStyle="#4CAF50",t.lineWidth=2,t.beginPath(),l.forEach((d,u)=>{u===0?t.moveTo(d.x,d.y):t.lineTo(d.x,d.y)}),t.stroke(),t.fillStyle="#4CAF50",l.forEach(d=>{t.beginPath(),t.arc(d.x,d.y,4,0,Math.PI*2),t.fill(),t.fillStyle="#666",t.font="12px Arial",t.textAlign="center",t.fillText(d.value.toString(),d.x,d.y-10),t.fillStyle="#4CAF50"});const s=t.createLinearGradient(i.left,i.top,i.left,i.top+a);s.addColorStop(0,"rgba(76, 175, 80, 0.2)"),s.addColorStop(1,"rgba(76, 175, 80, 0.05)"),t.fillStyle=s,t.beginPath(),t.moveTo(i.left,i.top+a),l.forEach(d=>{t.lineTo(d.x,d.y)}),t.lineTo(i.left+r,i.top+a),t.closePath(),t.fill()}t.fillStyle="#666",t.font="11px Arial",t.textAlign="right";for(let l=0;l<=5;l++){const s=Math.round(this.maxValue/5*(5-l)),d=i.top+a/5*l;t.fillText(s.toString(),i.left-10,d+4)}}}},g7={class:"delivery-trend-chart"},m7={class:"chart-container"},b7=["width","height"],y7={class:"chart-legend"},v7={class:"legend-date"},w7={class:"legend-value"};function C7(e,t,n,o,i,r){return g(),b("div",g7,[h("div",m7,[h("canvas",{ref:"chartCanvas",width:i.chartWidth,height:i.chartHeight},null,8,b7)]),h("div",y7,[(g(!0),b(te,null,Fe(r.chartData,(a,l)=>(g(),b("div",{key:l,class:"legend-item"},[h("span",v7,_(a.date),1),h("span",w7,_(a.value),1)]))),128))])])}const k7=dt(h7,[["render",C7],["__scopeId","data-v-26c78ab7"]]);class S7{async getList(t={}){try{return await We.post("/apply/list",t)}catch(n){throw console.error("获取投递记录列表失败:",n),n}}async getStatistics(t=null,n=null){try{const o=t?{sn_code:t}:{};return n&&(n.startTime!==null&&n.startTime!==void 0&&(o.startTime=n.startTime),n.endTime!==null&&n.endTime!==void 0&&(o.endTime=n.endTime)),await We.post("/apply/statistics",o)}catch(o){throw console.error("获取投递统计失败:",o),o}}async getTrendData(t=null){try{const n=t?{sn_code:t}:{};return await We.get("/apply/trend",n)}catch(n){throw console.error("获取投递趋势数据失败:",n),n}}async getDetail(t){try{return await We.get("/apply/detail",{id:t})}catch(n){throw console.error("获取投递记录详情失败:",n),n}}}const tr=new S7,x7=Object.freeze(Object.defineProperty({__proto__:null,default:tr},Symbol.toStringTag,{value:"Module"}));let Fo=null;const $7={name:"ConsolePage",mixins:[gh,vh,mh,yh,hh,bn],components:{DeliverySettings:p7,DeliveryTrendChart:k7},data(){return{showSettings:!1,trendData:[],trendDataRetryCount:0,maxTrendDataRetries:5}},computed:{...Ze("auth",["isLoggedIn","userName","remainingDays","snCode","platformType"]),...Ze("task",["displayText","nextExecuteTimeText","currentActivity","pendingQueue","deviceStatus","taskStats"]),...Ze("delivery",["deliveryStats","deliveryConfig"]),...Ze("platform",["isPlatformLoggedIn"]),...Ze("qrCode",["qrCodeUrl","qrCodeCountdownActive","qrCodeCountdown","qrCodeExpired"]),...Ze("system",["deviceId","uptime","cpuUsage","memUsage"]),todayJobSearchCount(){return this.taskStats?this.taskStats.todayCount:0},todayChatCount(){return 0},displayPlatform(){return this.platformType?{boss:"BOSS直聘",liepin:"猎聘",zhilian:"智联招聘",1:"BOSS直聘"}[this.platformType]||this.platformType:"-"}},watch:{},mounted(){this.init()},beforeUnmount(){this.stopQrCodeAutoRefresh&&this.stopQrCodeAutoRefresh()},methods:{...oa("delivery",["updateDeliveryConfig","saveDeliveryConfig"]),formatTaskTime(e){if(!e)return"-";try{const t=new Date(e),n=new Date,o=t.getTime()-n.getTime();if(o<0)return"已过期";const i=Math.floor(o/(1e3*60)),r=Math.floor(i/60),a=Math.floor(r/24);return a>0?`${a}天后 (${t.toLocaleString("zh-CN",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"})})`:r>0?`${r}小时后 (${t.toLocaleString("zh-CN",{hour:"2-digit",minute:"2-digit"})})`:i>0?`${i}分钟后 (${t.toLocaleString("zh-CN",{hour:"2-digit",minute:"2-digit"})})`:"即将执行"}catch{return e}},toggleSettings(){this.showSettings=!this.showSettings},async init(){await new Promise(e=>setTimeout(e,3e3)),await this.loadTrendData(),await this.loadDeliveryConfig(),await this.loadDeliveryStats(),await this.autoLoadTaskStats(),this.$nextTick(async()=>{this.checkMQTTStatus&&(await this.checkMQTTStatus(),console.log("[ConsolePage] MQTT状态已查询"))}),this.qrCodeUrl&&!this.isPlatformLoggedIn&&this.startQrCodeAutoRefresh(),this.$nextTick(()=>{console.log("[ConsolePage] 页面已挂载,设备工作状态:",{displayText:this.displayText,nextExecuteTimeText:this.nextExecuteTimeText,currentActivity:this.currentActivity,pendingQueue:this.pendingQueue,deviceStatus:this.deviceStatus,isLoggedIn:this.isLoggedIn,snCode:this.snCode,storeState:this.$store?this.$store.state.task:null})})},async loadTrendData(){var e,t,n;try{this.trendDataRetryCount=0;const o=(n=(t=(e=this.$store)==null?void 0:e.state)==null?void 0:t.auth)==null?void 0:n.snCode,i=await tr.getTrendData(o);i&&i.code===0&&i.data?Array.isArray(i.data)?this.trendData=i.data:i.data.trendData?this.trendData=i.data.trendData:this.generateEmptyTrendData():this.generateEmptyTrendData()}catch(o){console.error("加载趋势数据失败:",o),this.generateEmptyTrendData()}},generateEmptyTrendData(){const e=new Date;this.trendData=Array.from({length:7},(t,n)=>{const o=new Date(e);return o.setDate(o.getDate()-(6-n)),{date:this.formatDate(o),value:0}})},formatDate(e){const t=e.getMonth()+1,n=e.getDate();return`${t}/${n}`},handleUpdateConfig({key:e,value:t}){this.updateDeliveryConfig({key:e,value:t})},async handleRefreshPlatformLoginStatus(){await this.checkPlatformLoginStatus()},async handleSaveConfig(){try{const e=await this.saveDeliveryConfig();e&&e.success?(this.showSettings=!1,this.addLog("success","投递配置已保存")):this.addLog("error",(e==null?void 0:e.error)||"保存配置失败")}catch(e){console.error("保存配置失败:",e),this.addLog("error",`保存配置失败: ${e.message}`)}},async loadDeliveryConfig(){try{await this.$store.dispatch("delivery/loadDeliveryConfig")}catch(e){console.error("加载投递配置失败:",e)}},async loadDeliveryStats(){try{await this.$store.dispatch("delivery/loadDeliveryStats")}catch(e){console.error("加载投递统计失败:",e)}},async loadTaskStats(){try{await this.$store.dispatch("task/loadTaskStats")}catch(e){console.error("加载任务统计失败:",e)}},async autoLoadTaskStats(){this.loadTaskStats(),Fo||(Fo=setInterval(()=>{this.loadTaskStats()},60*1e3))},async handleGetQrCode(){await this.getQrCode()&&this.startQrCodeAutoRefresh()},handleReloadBrowser(){this.addLog("info","正在重新加载页面..."),window.location.reload()},async handleShowBrowser(){try{if(!window.electronAPI||!window.electronAPI.invoke){this.addLog("error","electronAPI 不可用,无法显示浏览器"),console.error("electronAPI 不可用");return}const e=await window.electronAPI.invoke("browser-window:show");e&&e.success?this.addLog("success","浏览器窗口已显示"):this.addLog("error",(e==null?void 0:e.error)||"显示浏览器失败")}catch(e){console.error("显示浏览器失败:",e),this.addLog("error",`显示浏览器失败: ${e.message}`)}}},beforeDestroy(){Fo&&(clearInterval(Fo),Fo=null)}},P7={class:"page-console"},I7={class:"console-header"},T7={class:"header-left"},R7={class:"header-title-section"},O7={class:"delivery-settings-summary"},E7={class:"summary-item"},A7={class:"summary-item"},L7={class:"summary-value"},_7={class:"summary-item"},D7={class:"summary-value"},B7={class:"header-right"},M7={class:"quick-stats"},z7={class:"quick-stat-item"},F7={class:"stat-value"},j7={class:"quick-stat-item"},N7={class:"stat-value"},V7={class:"quick-stat-item"},U7={class:"stat-value"},H7={class:"quick-stat-item highlight"},G7={class:"stat-value"},K7={class:"settings-modal-content"},W7={class:"modal-header"},q7={class:"modal-body"},Q7={class:"modal-footer"},Z7={class:"console-content"},Y7={class:"content-left"},X7={class:"status-card"},J7={class:"status-grid"},e8={class:"status-item"},t8={class:"status-value"},n8={key:0,class:"status-detail"},o8={key:1,class:"status-detail"},r8={class:"status-actions"},i8={class:"status-item"},a8={class:"status-detail"},l8={class:"status-detail"},s8={class:"status-item"},d8={class:"status-detail"},u8={class:"status-item"},c8={class:"status-detail"},f8={class:"status-detail"},p8={class:"status-detail"},h8={class:"task-card"},g8={key:0,class:"device-work-status"},m8={class:"status-content"},b8={class:"status-text"},y8={key:1,class:"current-activity"},v8={class:"task-header"},w8={class:J(["status-badge","status-info"])},C8={class:"task-content"},k8={class:"task-name"},S8={key:0,class:"task-progress"},x8={class:"progress-bar"},$8={class:"progress-text"},P8={key:1,class:"task-step"},I8={key:2,class:"no-task"},T8={key:3,class:"pending-queue"},R8={class:"task-header"},O8={class:"task-count"},E8={class:"queue-content"},A8={class:"queue-count"},L8={key:4,class:"next-task-time"},_8={class:"time-content"},D8={class:"content-right"},B8={class:"qr-card"},M8={class:"card-header"},z8={class:"qr-content"},F8={key:0,class:"qr-placeholder"},j8={key:1,class:"qr-display"},N8=["src"],V8={class:"qr-info"},U8={key:0,class:"qr-countdown"},H8={key:1,class:"qr-expired"},G8={class:"trend-chart-card"},K8={class:"chart-content"};function W8(e,t,n,o,i,r){const a=R("DeliverySettings"),l=R("DeliveryTrendChart");return g(),b("div",P7,[h("div",I7,[h("div",T7,[h("div",R7,[t[12]||(t[12]=h("h2",{class:"page-title"},"控制台",-1)),h("div",O7,[h("div",E7,[t[9]||(t[9]=h("span",{class:"summary-label"},"自动投递:",-1)),h("span",{class:J(["summary-value",e.deliveryConfig.autoDelivery?"enabled":"disabled"])},_(e.deliveryConfig.autoDelivery?"已开启":"已关闭"),3)]),h("div",A7,[t[10]||(t[10]=h("span",{class:"summary-label"},"投递时间:",-1)),h("span",L7,_(e.deliveryConfig.startTime||"09:00")+" - "+_(e.deliveryConfig.endTime||"18:00"),1)]),h("div",_7,[t[11]||(t[11]=h("span",{class:"summary-label"},"仅工作日:",-1)),h("span",D7,_(e.deliveryConfig.workdaysOnly?"是":"否"),1)])])])]),h("div",B7,[h("div",M7,[h("div",z7,[t[13]||(t[13]=h("span",{class:"stat-label"},"今日投递",-1)),h("span",F7,_(e.deliveryStats.todayCount||0),1)]),h("div",j7,[t[14]||(t[14]=h("span",{class:"stat-label"},"今日找工作",-1)),h("span",N7,_(r.todayJobSearchCount||0),1)]),h("div",V7,[t[15]||(t[15]=h("span",{class:"stat-label"},"今日沟通",-1)),h("span",U7,_(r.todayChatCount||0),1)]),h("div",H7,[t[16]||(t[16]=h("span",{class:"stat-label"},"执行中任务",-1)),h("span",G7,_(e.currentActivity?1:0),1)])]),h("button",{class:"btn-settings",onClick:t[0]||(t[0]=(...s)=>r.toggleSettings&&r.toggleSettings(...s))},[...t[17]||(t[17]=[h("span",{class:"settings-icon"},"⚙️",-1),h("span",{class:"settings-text"},"设置",-1)])])])]),i.showSettings?(g(),b("div",{key:0,class:"settings-modal",onClick:t[4]||(t[4]=To((...s)=>r.toggleSettings&&r.toggleSettings(...s),["self"]))},[h("div",K7,[h("div",W7,[t[18]||(t[18]=h("h3",{class:"modal-title"},"自动投递设置",-1)),h("button",{class:"btn-close",onClick:t[1]||(t[1]=(...s)=>r.toggleSettings&&r.toggleSettings(...s))},"×")]),h("div",q7,[D(a,{config:e.deliveryConfig,onUpdateConfig:r.handleUpdateConfig},null,8,["config","onUpdateConfig"])]),h("div",Q7,[h("button",{class:"btn btn-secondary",onClick:t[2]||(t[2]=(...s)=>r.toggleSettings&&r.toggleSettings(...s))},"取消"),h("button",{class:"btn btn-primary",onClick:t[3]||(t[3]=(...s)=>r.handleSaveConfig&&r.handleSaveConfig(...s))},"保存")])])])):I("",!0),h("div",Z7,[h("div",Y7,[h("div",X7,[t[24]||(t[24]=h("div",{class:"card-header"},[h("h3",{class:"card-title"},"系统状态")],-1)),h("div",J7,[h("div",e8,[t[20]||(t[20]=h("div",{class:"status-label"},"用户登录",-1)),h("div",t8,[h("span",{class:J(["status-badge",e.isLoggedIn?"status-success":"status-error"])},_(e.isLoggedIn?"已登录":"未登录"),3)]),e.isLoggedIn&&e.userName?(g(),b("div",n8,_(e.userName),1)):I("",!0),e.isLoggedIn&&e.remainingDays!==null?(g(),b("div",o8,[t[19]||(t[19]=$e(" 剩余: ",-1)),h("span",{class:J(e.remainingDays<=3?"text-warning":"")},_(e.remainingDays)+"天",3)])):I("",!0),h("div",r8,[h("button",{class:"btn-action",onClick:t[5]||(t[5]=(...s)=>r.handleReloadBrowser&&r.handleReloadBrowser(...s)),title:"重新加载浏览器页面"}," 🔄 重新加载 "),h("button",{class:"btn-action",onClick:t[6]||(t[6]=(...s)=>r.handleShowBrowser&&r.handleShowBrowser(...s)),title:"显示浏览器窗口"}," 🖥️ 显示浏览器 ")])]),h("div",i8,[t[21]||(t[21]=h("div",{class:"status-label"},"平台登录",-1)),h("div",a8,_(r.displayPlatform),1),h("div",l8,[h("span",{class:J(["status-badge",e.isPlatformLoggedIn?"status-success":"status-warning"])},_(e.isPlatformLoggedIn?"已登录":"未登录"),3),h("button",{class:"btn-action",severity:"info",variant:"text",onClick:t[7]||(t[7]=(...s)=>r.handleRefreshPlatformLoginStatus&&r.handleRefreshPlatformLoginStatus(...s)),title:"刷新平台登录状态"}," 🔄 刷新 ")])]),h("div",s8,[t[22]||(t[22]=h("div",{class:"status-label"},"设备信息",-1)),h("div",d8,"SN: "+_(e.snCode||"-"),1)]),h("div",u8,[t[23]||(t[23]=h("div",{class:"status-label"},"系统资源",-1)),h("div",c8,"运行: "+_(e.uptime),1),h("div",f8,"CPU: "+_(e.cpuUsage),1),h("div",p8,"内存: "+_(e.memUsage),1)])])]),h("div",h8,[t[29]||(t[29]=h("div",{class:"card-header"},[h("h3",{class:"card-title"},"任务信息")],-1)),e.displayText?(g(),b("div",g8,[t[25]||(t[25]=h("div",{class:"status-header"},[h("span",{class:"status-label"},"设备工作状态")],-1)),h("div",m8,[h("div",b8,_(e.displayText),1)])])):I("",!0),e.currentActivity?(g(),b("div",y8,[h("div",v8,[t[26]||(t[26]=h("span",{class:"task-label"},"当前活动",-1)),h("span",w8,_(e.currentActivity.status==="running"?"执行中":e.currentActivity.status==="completed"?"已完成":"未知"),1)]),h("div",C8,[h("div",k8,_(e.currentActivity.description||e.currentActivity.name||"-"),1),e.currentActivity.progress!==null&&e.currentActivity.progress!==void 0?(g(),b("div",S8,[h("div",x8,[h("div",{class:"progress-fill",style:$o({width:e.currentActivity.progress+"%"})},null,4)]),h("span",$8,_(e.currentActivity.progress)+"%",1)])):I("",!0),e.currentActivity.currentStep?(g(),b("div",P8,_(e.currentActivity.currentStep),1)):I("",!0)])])):e.displayText?I("",!0):(g(),b("div",I8,"暂无执行中的活动")),e.pendingQueue?(g(),b("div",T8,[h("div",R8,[t[27]||(t[27]=h("span",{class:"task-label"},"待执行队列",-1)),h("span",O8,_(e.pendingQueue.totalCount||0)+"个",1)]),h("div",E8,[h("div",A8,"待执行: "+_(e.pendingQueue.totalCount||0)+"个任务",1)])])):I("",!0),e.nextExecuteTimeText?(g(),b("div",L8,[t[28]||(t[28]=h("div",{class:"task-header"},[h("span",{class:"task-label"},"下次执行时间")],-1)),h("div",_8,_(e.nextExecuteTimeText),1)])):I("",!0)])]),h("div",D8,[h("div",B8,[h("div",M8,[t[30]||(t[30]=h("h3",{class:"card-title"},"登录二维码",-1)),e.isPlatformLoggedIn?I("",!0):(g(),b("button",{key:0,class:"btn-qr-refresh",onClick:t[8]||(t[8]=(...s)=>r.handleGetQrCode&&r.handleGetQrCode(...s))}," 获取二维码 "))]),h("div",z8,[e.qrCodeUrl?(g(),b("div",j8,[h("img",{src:e.qrCodeUrl,alt:"登录二维码",class:"qr-image"},null,8,N8),h("div",V8,[t[32]||(t[32]=h("p",null,"请使用微信扫描二维码登录",-1)),e.qrCodeCountdownActive&&e.qrCodeCountdown>0?(g(),b("p",U8,_(e.qrCodeCountdown)+"秒后自动刷新 ",1)):I("",!0),e.qrCodeExpired?(g(),b("p",H8," 二维码已过期,请重新获取 ")):I("",!0)])])):(g(),b("div",F8,[...t[31]||(t[31]=[h("p",null,'点击"获取二维码"按钮获取二维码',-1)])]))])]),h("div",G8,[t[33]||(t[33]=h("div",{class:"card-header"},[h("h3",{class:"card-title"},"近7天投递趋势")],-1)),h("div",K8,[D(l,{data:i.trendData},null,8,["data"])])])])])])}const q8=dt($7,[["render",W8],["__scopeId","data-v-100c009e"]]),Q8={name:"DeliveryPage",mixins:[bn],components:{Card:ai,Select:no,DataTable:dh,Column:IS,Tag:ua,Button:xt,Dialog:Eo,Paginator:ii,ProgressSpinner:fa},data(){return{loading:!1,records:[],statistics:null,searchOption:{key:"jobTitle",value:"",platform:"",applyStatus:"",feedbackStatus:"",timeRange:"today"},timeRangeOptions:[{label:"全部时间",value:null},{label:"今日",value:"today"},{label:"近7天",value:"7days"},{label:"近30天",value:"30days"},{label:"历史",value:"history"}],platformOptions:[{label:"全部平台",value:""},{label:"Boss直聘",value:"boss"},{label:"猎聘",value:"liepin"}],applyStatusOptions:[{label:"全部状态",value:""},{label:"待投递",value:"pending"},{label:"投递中",value:"applying"},{label:"投递成功",value:"success"},{label:"投递失败",value:"failed"}],feedbackStatusOptions:[{label:"全部反馈",value:""},{label:"无反馈",value:"none"},{label:"已查看",value:"viewed"},{label:"感兴趣",value:"interested"},{label:"面试邀约",value:"interview"}],pageOption:{page:1,pageSize:10},total:0,currentPage:1,showDetail:!1,currentRecord:null}},computed:{...Ze("auth",["snCode"]),totalPages(){return Math.ceil(this.total/this.pageOption.pageSize)}},mounted(){this.loadStatistics(),this.loadRecords()},methods:{async loadStatistics(){var e,t,n;try{const o=(n=(t=(e=this.$store)==null?void 0:e.state)==null?void 0:t.auth)==null?void 0:n.snCode;if(!o){console.warn("未获取到设备SN码,无法加载统计数据");return}const i=this.getTimeRange(),r=await tr.getStatistics(o,i);r&&r.code===0&&(this.statistics=r.data)}catch(o){console.error("加载统计数据失败:",o)}},async loadRecords(){this.loading=!0;try{const e=this.getTimeRange(),t={...this.searchOption,...e},n={sn_code:this.snCode,seachOption:t,pageOption:this.pageOption},o=await tr.getList(n);o&&o.code===0?(this.records=o.data.rows||o.data.list||[],this.total=o.data.count||o.data.total||0,this.currentPage=this.pageOption.page,console.log("[投递管理] 加载记录成功:",{recordsCount:this.records.length,total:this.total,currentPage:this.currentPage})):console.warn("[投递管理] 响应格式异常:",o)}catch(e){console.error("加载投递记录失败:",e),this.addLog&&this.addLog("error","加载投递记录失败: "+(e.message||"未知错误"))}finally{this.loading=!1}},getTimeRange(){const{timeRange:e}=this.searchOption;if(console.log("[getTimeRange] timeRange 值:",e,"类型:",typeof e,"searchOption:",this.searchOption),e==null||e==="")return console.log("[getTimeRange] 返回空对象(未选择时间范围)"),{};const t=new Date,n=new Date(t.getFullYear(),t.getMonth(),t.getDate());let o=null,i=null;switch(e){case"today":o=n.getTime(),i=t.getTime();break;case"7days":o=new Date(n.getTime()-6*24*60*60*1e3).getTime(),i=t.getTime();break;case"30days":o=new Date(n.getTime()-29*24*60*60*1e3).getTime(),i=t.getTime();break;case"history":o=null,i=new Date(n.getTime()-30*24*60*60*1e3).getTime();break;default:return console.warn("[getTimeRange] 未知的时间范围值:",e),{}}const r={};return o!==null&&(r.startTime=o),i!==null&&(r.endTime=i),console.log("[getTimeRange] 计算结果:",r),r},handleSearch(){this.pageOption.page=1,this.loadStatistics(),this.loadRecords()},handlePageChange(e){this.pageOption.page=e,this.currentPage=e,this.loadRecords()},onPageChange(e){this.currentPage=Math.floor(e.first/this.pageOption.pageSize)+1,this.pageOption.page=this.currentPage,this.loadRecords()},getApplyStatusSeverity(e){return{pending:"warning",applying:"info",success:"success",failed:"danger",duplicate:"secondary"}[e]||"secondary"},getFeedbackStatusSeverity(e){return{none:"secondary",viewed:"info",interested:"success",not_suitable:"danger",interview:"success"}[e]||"secondary"},async handleViewDetail(e){try{const t=await tr.getDetail(e.id||e.applyId);t&&t.code===0&&(this.currentRecord=t.data||e,this.showDetail=!0)}catch(t){console.error("获取详情失败:",t),this.currentRecord=e,this.showDetail=!0,this.addLog&&this.addLog("error","获取详情失败: "+(t.message||"未知错误"))}},closeDetail(){this.showDetail=!1,this.currentRecord=null},getApplyStatusText(e){return{pending:"待投递",applying:"投递中",success:"投递成功",failed:"投递失败",duplicate:"重复投递"}[e]||e||"-"},getFeedbackStatusText(e){return{none:"无反馈",viewed:"已查看",interested:"感兴趣",not_suitable:"不合适",interview:"面试邀约"}[e]||e||"-"},formatTime(e){return e?new Date(e).toLocaleString("zh-CN"):"-"}}},Z8={class:"page-delivery"},Y8={class:"filter-section"},X8={class:"filter-box"},J8={key:0,class:"stats-section"},e9={class:"stat-value"},t9={class:"stat-value"},n9={class:"stat-value"},o9={class:"stat-value"},r9={class:"table-section"},i9={key:0,class:"loading-wrapper"},a9={key:1,class:"empty"},l9={key:0,class:"detail-content"},s9={class:"detail-item"},d9={class:"detail-item"},u9={class:"detail-item"},c9={class:"detail-item"},f9={class:"detail-item"},p9={class:"detail-item"},h9={class:"detail-item"},g9={key:0,class:"detail-item"};function m9(e,t,n,o,i,r){const a=R("Select"),l=R("Card"),s=R("ProgressSpinner"),d=R("Column"),u=R("Tag"),c=R("Button"),f=R("DataTable"),p=R("Paginator"),v=R("Dialog");return g(),b("div",Z8,[t[17]||(t[17]=h("h2",{class:"page-title"},"投递管理",-1)),h("div",Y8,[h("div",X8,[D(a,{modelValue:i.searchOption.timeRange,"onUpdate:modelValue":[t[0]||(t[0]=C=>i.searchOption.timeRange=C),r.handleSearch],options:i.timeRangeOptions,optionLabel:"label",optionValue:"value",placeholder:"时间范围",class:"filter-select"},null,8,["modelValue","options","onUpdate:modelValue"]),D(a,{modelValue:i.searchOption.platform,"onUpdate:modelValue":[t[1]||(t[1]=C=>i.searchOption.platform=C),r.handleSearch],options:i.platformOptions,optionLabel:"label",optionValue:"value",placeholder:"全部平台",class:"filter-select"},null,8,["modelValue","options","onUpdate:modelValue"]),D(a,{modelValue:i.searchOption.applyStatus,"onUpdate:modelValue":[t[2]||(t[2]=C=>i.searchOption.applyStatus=C),r.handleSearch],options:i.applyStatusOptions,optionLabel:"label",optionValue:"value",placeholder:"全部状态",class:"filter-select"},null,8,["modelValue","options","onUpdate:modelValue"]),D(a,{modelValue:i.searchOption.feedbackStatus,"onUpdate:modelValue":[t[3]||(t[3]=C=>i.searchOption.feedbackStatus=C),r.handleSearch],options:i.feedbackStatusOptions,optionLabel:"label",optionValue:"value",placeholder:"全部反馈",class:"filter-select"},null,8,["modelValue","options","onUpdate:modelValue"])])]),i.statistics?(g(),b("div",J8,[D(l,{class:"stat-card"},{content:V(()=>[h("div",e9,_(i.statistics.totalCount||0),1),t[5]||(t[5]=h("div",{class:"stat-label"},"总投递数",-1))]),_:1}),D(l,{class:"stat-card"},{content:V(()=>[h("div",t9,_(i.statistics.successCount||0),1),t[6]||(t[6]=h("div",{class:"stat-label"},"成功数",-1))]),_:1}),D(l,{class:"stat-card"},{content:V(()=>[h("div",n9,_(i.statistics.totalJobCount||0),1),t[7]||(t[7]=h("div",{class:"stat-label"},"今日找工作数",-1))]),_:1}),D(l,{class:"stat-card"},{content:V(()=>[h("div",o9,_(i.statistics.successRate||0)+"%",1),t[8]||(t[8]=h("div",{class:"stat-label"},"成功率",-1))]),_:1})])):I("",!0),h("div",r9,[i.loading?(g(),b("div",i9,[D(s)])):i.records.length===0?(g(),b("div",a9,"暂无投递记录")):(g(),T(f,{key:2,value:i.records,style:{"min-width":"50rem"}},{default:V(()=>[D(d,{field:"jobTitle",header:"岗位名称"},{body:V(({data:C})=>[$e(_(C.jobTitle||"-"),1)]),_:1}),D(d,{field:"companyName",header:"公司名称"},{body:V(({data:C})=>[$e(_(C.companyName||"-"),1)]),_:1}),D(d,{field:"platform",header:"平台"},{body:V(({data:C})=>[D(u,{value:C.platform==="boss"?"Boss直聘":C.platform==="liepin"?"猎聘":C.platform,severity:"info"},null,8,["value"])]),_:1}),D(d,{field:"applyStatus",header:"投递状态"},{body:V(({data:C})=>[D(u,{value:r.getApplyStatusText(C.applyStatus),severity:r.getApplyStatusSeverity(C.applyStatus)},null,8,["value","severity"])]),_:1}),D(d,{field:"feedbackStatus",header:"反馈状态"},{body:V(({data:C})=>[D(u,{value:r.getFeedbackStatusText(C.feedbackStatus),severity:r.getFeedbackStatusSeverity(C.feedbackStatus)},null,8,["value","severity"])]),_:1}),D(d,{field:"applyTime",header:"投递时间"},{body:V(({data:C})=>[$e(_(r.formatTime(C.applyTime)),1)]),_:1}),D(d,{header:"操作"},{body:V(({data:C})=>[D(c,{label:"查看详情",size:"small",onClick:S=>r.handleViewDetail(C)},null,8,["onClick"])]),_:1})]),_:1},8,["value"]))]),i.total>0?(g(),T(p,{key:1,rows:i.pageOption.pageSize,totalRecords:i.total,first:(i.currentPage-1)*i.pageOption.pageSize,onPage:r.onPageChange},null,8,["rows","totalRecords","first","onPage"])):I("",!0),D(v,{visible:i.showDetail,"onUpdate:visible":t[4]||(t[4]=C=>i.showDetail=C),modal:"",header:"投递详情",style:{width:"600px"},onHide:r.closeDetail},{default:V(()=>[i.currentRecord?(g(),b("div",l9,[h("div",s9,[t[9]||(t[9]=h("label",null,"岗位名称:",-1)),h("span",null,_(i.currentRecord.jobTitle||"-"),1)]),h("div",d9,[t[10]||(t[10]=h("label",null,"公司名称:",-1)),h("span",null,_(i.currentRecord.companyName||"-"),1)]),h("div",u9,[t[11]||(t[11]=h("label",null,"薪资范围:",-1)),h("span",null,_(i.currentRecord.salary||"-"),1)]),h("div",c9,[t[12]||(t[12]=h("label",null,"工作地点:",-1)),h("span",null,_(i.currentRecord.location||"-"),1)]),h("div",f9,[t[13]||(t[13]=h("label",null,"投递状态:",-1)),h("span",null,_(r.getApplyStatusText(i.currentRecord.applyStatus)),1)]),h("div",p9,[t[14]||(t[14]=h("label",null,"反馈状态:",-1)),h("span",null,_(r.getFeedbackStatusText(i.currentRecord.feedbackStatus)),1)]),h("div",h9,[t[15]||(t[15]=h("label",null,"投递时间:",-1)),h("span",null,_(r.formatTime(i.currentRecord.applyTime)),1)]),i.currentRecord.feedbackContent?(g(),b("div",g9,[t[16]||(t[16]=h("label",null,"反馈内容:",-1)),h("span",null,_(i.currentRecord.feedbackContent),1)])):I("",!0)])):I("",!0)]),_:1},8,["visible","onHide"])])}const b9=dt(Q8,[["render",m9],["__scopeId","data-v-260a7ccd"]]);class y9{async getInviteInfo(t){try{return await We.post("/invite/info",{sn_code:t})}catch(n){throw console.error("获取邀请信息失败:",n),n}}async getStatistics(t){try{return await We.post("/invite/statistics",{sn_code:t})}catch(n){throw console.error("获取邀请统计失败:",n),n}}async generateInviteCode(t){try{return await We.post("/invite/generate",{sn_code:t})}catch(n){throw console.error("生成邀请码失败:",n),n}}async getRecords(t,n={}){try{return await We.post("/invite/records",{sn_code:t,page:n.page||1,pageSize:n.pageSize||20})}catch(o){throw console.error("获取邀请记录列表失败:",o),o}}}const wi=new y9,v9={name:"InvitePage",mixins:[bn],components:{Card:ai,Button:xt,Badge:oi,Tag:ua,Paginator:ii,Message:ca,ProgressSpinner:fa},data(){return{inviteInfo:{},statistics:{},showSuccess:!1,successMessage:"",recordsList:[],recordsLoading:!1,recordsTotal:0,currentPage:1,pageSize:20}},computed:{...Ze("auth",["snCode","isLoggedIn"]),totalPages(){return Math.ceil(this.recordsTotal/this.pageSize)}},watch:{isLoggedIn(e){e&&this.snCode&&(this.loadInviteInfo(),this.loadStatistics(),this.loadRecords())},snCode(e){e&&this.isLoggedIn&&(this.loadInviteInfo(),this.loadStatistics(),this.loadRecords())}},mounted(){this.$nextTick(()=>{this.isLoggedIn&&this.snCode&&(this.loadInviteInfo(),this.loadStatistics(),this.loadRecords())})},activated(){this.$nextTick(()=>{this.isLoggedIn&&this.snCode&&(this.loadInviteInfo(),this.loadStatistics(),this.loadRecords())})},methods:{async loadInviteInfo(){try{if(!this.snCode){console.warn("SN码不存在,无法加载邀请信息");return}const e=await wi.getInviteInfo(this.snCode);e&&(e.code===0||e.success)&&(this.inviteInfo=e.data||{},this.inviteInfo.invite_link||await this.handleGenerateCode())}catch(e){console.error("加载邀请信息失败:",e),this.addLog&&this.addLog("error","加载邀请信息失败: "+(e.message||"未知错误"))}},async loadStatistics(){try{if(!this.snCode)return;const e=await wi.getStatistics(this.snCode);e&&(e.code===0||e.success)&&(this.statistics=e.data)}catch(e){console.error("加载统计数据失败:",e)}},async handleGenerateCode(){try{if(!this.snCode){console.warn("SN码不存在,无法生成邀请码");return}const e=await wi.generateInviteCode(this.snCode);e&&(e.code===0||e.success)&&(this.inviteInfo=e.data||{},this.showSuccess||this.showSuccessMessage("邀请链接已生成!"))}catch(e){console.error("生成邀请码失败:",e),this.addLog&&this.addLog("error","生成邀请码失败: "+(e.message||"未知错误"))}},async handleCopyCode(){if(this.inviteInfo.invite_code)try{window.electronAPI&&window.electronAPI.clipboard?(await window.electronAPI.clipboard.writeText(this.inviteInfo.invite_code),this.showSuccessMessage("邀请码已复制到剪贴板")):(await navigator.clipboard.writeText(this.inviteInfo.invite_code),this.showSuccessMessage("邀请码已复制到剪贴板"))}catch(e){console.error("复制失败:",e),this.addLog&&this.addLog("error","复制失败: "+(e.message||"未知错误"))}},async handleCopyLink(){if(this.inviteInfo.invite_link)try{window.electronAPI&&window.electronAPI.clipboard?(await window.electronAPI.clipboard.writeText(this.inviteInfo.invite_link),this.showSuccessMessage("邀请链接已复制到剪贴板")):(await navigator.clipboard.writeText(this.inviteInfo.invite_link),this.showSuccessMessage("邀请链接已复制到剪贴板"))}catch(e){console.error("复制失败:",e),this.addLog&&this.addLog("error","复制失败: "+(e.message||"未知错误"))}},showSuccessMessage(e){this.successMessage=e,this.showSuccess=!0,setTimeout(()=>{this.showSuccess=!1},3e3)},async loadRecords(){var e,t;try{if(!this.snCode)return;this.recordsLoading=!0;const n=await wi.getRecords(this.snCode,{page:this.currentPage,pageSize:this.pageSize});n&&(n.code===0||n.success)&&(this.recordsList=((e=n.data)==null?void 0:e.list)||[],this.recordsTotal=((t=n.data)==null?void 0:t.total)||0)}catch(n){console.error("加载邀请记录列表失败:",n),this.addLog&&this.addLog("error","加载邀请记录列表失败: "+(n.message||"未知错误"))}finally{this.recordsLoading=!1}},changePage(e){e>=1&&e<=this.totalPages&&(this.currentPage=e,this.loadRecords())},onPageChange(e){this.currentPage=Math.floor(e.first/this.pageSize)+1,this.loadRecords()},formatTime(e){return e?new Date(e).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}):"-"}}},w9={class:"page-invite"},C9={class:"invite-code-section"},k9={class:"link-display"},S9={class:"link-value"},x9={key:0,class:"code-display"},$9={class:"code-value"},P9={class:"records-section"},I9={class:"section-header"},T9={key:1,class:"records-list"},R9={class:"record-info"},O9={class:"record-phone"},E9={class:"record-time"},A9={class:"record-status"},L9={key:0,class:"reward-info"},_9={key:2,class:"empty-tip"};function D9(e,t,n,o,i,r){const a=R("Button"),l=R("Card"),s=R("Badge"),d=R("ProgressSpinner"),u=R("Tag"),c=R("Paginator"),f=R("Message");return g(),b("div",w9,[t[6]||(t[6]=h("h2",{class:"page-title"},"推广邀请",-1)),D(l,{class:"invite-card"},{title:V(()=>[...t[1]||(t[1]=[$e("我的邀请链接",-1)])]),content:V(()=>[h("div",C9,[h("div",k9,[t[2]||(t[2]=h("span",{class:"link-label"},"邀请链接:",-1)),h("span",S9,_(i.inviteInfo.invite_link||"加载中..."),1),i.inviteInfo.invite_link?(g(),T(a,{key:0,label:"复制链接",size:"small",onClick:r.handleCopyLink},null,8,["onClick"])):I("",!0)]),i.inviteInfo.invite_code?(g(),b("div",x9,[t[3]||(t[3]=h("span",{class:"code-label"},"邀请码:",-1)),h("span",$9,_(i.inviteInfo.invite_code),1),D(a,{label:"复制",size:"small",onClick:r.handleCopyCode},null,8,["onClick"])])):I("",!0)]),t[4]||(t[4]=h("div",{class:"invite-tip"},[h("p",null,[$e("💡 分享邀请链接给好友,好友通过链接注册后,您将获得 "),h("strong",null,"3天试用期"),$e(" 奖励")])],-1))]),_:1}),h("div",P9,[h("div",I9,[h("h3",null,[t[5]||(t[5]=$e("邀请记录 ",-1)),D(s,{value:i.statistics&&i.statistics.totalInvites||0,severity:"success",class:"stat-value"},null,8,["value"])]),D(a,{label:"刷新",onClick:r.loadRecords,loading:i.recordsLoading,disabled:i.recordsLoading},null,8,["onClick","loading","disabled"])]),i.recordsLoading?(g(),T(d,{key:0})):i.recordsList&&i.recordsList.length>0?(g(),b("div",T9,[(g(!0),b(te,null,Fe(i.recordsList,p=>(g(),T(l,{key:p.id,class:"record-item"},{content:V(()=>[h("div",R9,[h("div",O9,_(p.invitee_phone||"未知"),1),h("div",E9,_(r.formatTime(p.register_time)),1)]),h("div",A9,[D(u,{value:p.reward_status===1?"已奖励":"待奖励",severity:p.reward_status===1?"success":"warning"},null,8,["value","severity"]),p.reward_status===1?(g(),b("span",L9," +"+_(p.reward_value||3)+"天 ",1)):I("",!0)])]),_:2},1024))),128))])):(g(),b("div",_9,"暂无邀请记录")),i.recordsTotal>0?(g(),T(c,{key:3,rows:i.pageSize,totalRecords:i.recordsTotal,first:(i.currentPage-1)*i.pageSize,onPage:r.onPageChange},null,8,["rows","totalRecords","first","onPage"])):I("",!0)]),t[7]||(t[7]=h("div",{class:"info-section"},[h("h3",null,"邀请说明"),h("ul",{class:"info-list"},[h("li",null,"分享您的邀请链接给好友"),h("li",null,[$e("好友通过您的邀请链接注册后,您将自动获得 "),h("strong",null,"3天试用期"),$e(" 奖励")]),h("li",null,"每成功邀请一位用户注册,您将获得3天试用期"),h("li",null,"试用期将自动累加到您的账户剩余天数中")])],-1)),i.showSuccess?(g(),T(f,{key:0,severity:"success",closable:!0,onClose:t[0]||(t[0]=p=>i.showSuccess=!1),class:"success-message"},{default:V(()=>[$e(_(i.successMessage),1)]),_:1})):I("",!0)])}const B9=dt(v9,[["render",D9],["__scopeId","data-v-098fa8fa"]]);class M9{async submit(t){try{return await We.post("/feedback/submit",t)}catch(n){throw console.error("提交反馈失败:",n),n}}async getList(t={}){try{return await We.post("/feedback/list",t)}catch(n){throw console.error("获取反馈列表失败:",n),n}}async getDetail(t){try{return await We.get("/feedback/detail",{id:t})}catch(n){throw console.error("获取反馈详情失败:",n),n}}}const Ma=new M9,z9={name:"FeedbackPage",mixins:[bn],components:{Dropdown:Bw,Textarea:vp,InputText:eo,Button:xt,Card:ai,Tag:ua,Dialog:Eo,Paginator:ii,ProgressSpinner:fa},data(){return{formData:{type:"",content:"",contact:""},typeOptions:[{label:"Bug反馈",value:"bug"},{label:"功能建议",value:"suggestion"},{label:"使用问题",value:"question"},{label:"其他",value:"other"}],submitting:!1,feedbacks:[],loading:!1,showSuccess:!1,successMessage:"",currentPage:1,pageSize:10,total:0,showDetail:!1,currentFeedback:null}},computed:{...Ze("auth",["snCode"]),totalPages(){return Math.ceil(this.total/this.pageSize)}},mounted(){this.loadFeedbacks()},methods:{async handleSubmit(){if(!this.formData.type||!this.formData.content){this.addLog&&this.addLog("warn","请填写完整的反馈信息");return}if(!this.snCode){this.addLog&&this.addLog("error","请先登录");return}this.submitting=!0;try{const e=await Ma.submit({...this.formData,sn_code:this.snCode});e&&e.code===0?(this.showSuccessMessage("反馈提交成功,感谢您的反馈!"),this.handleReset(),this.loadFeedbacks()):this.addLog&&this.addLog("error",e.message||"提交失败")}catch(e){console.error("提交反馈失败:",e),this.addLog&&this.addLog("error","提交反馈失败: "+(e.message||"未知错误"))}finally{this.submitting=!1}},handleReset(){this.formData={type:"",content:"",contact:""}},async loadFeedbacks(){if(this.snCode){this.loading=!0;try{const e=await Ma.getList({sn_code:this.snCode,page:this.currentPage,pageSize:this.pageSize});e&&e.code===0?(this.feedbacks=e.data.rows||e.data.list||[],this.total=e.data.total||e.data.count||0):console.warn("[反馈管理] 响应格式异常:",e)}catch(e){console.error("加载反馈列表失败:",e),this.addLog&&this.addLog("error","加载反馈列表失败: "+(e.message||"未知错误"))}finally{this.loading=!1}}},async handleViewDetail(e){try{const t=await Ma.getDetail(e.id);t&&t.code===0?(this.currentFeedback=t.data||e,this.showDetail=!0):(this.currentFeedback=e,this.showDetail=!0)}catch(t){console.error("获取详情失败:",t),this.currentFeedback=e,this.showDetail=!0,this.addLog&&this.addLog("error","获取详情失败: "+(t.message||"未知错误"))}},closeDetail(){this.showDetail=!1,this.currentFeedback=null},handlePageChange(e){this.currentPage=e,this.loadFeedbacks()},onPageChange(e){this.currentPage=Math.floor(e.first/this.pageSize)+1,this.loadFeedbacks()},getStatusSeverity(e){return{pending:"warning",processing:"info",completed:"success",rejected:"danger"}[e]||"secondary"},getTypeText(e){return{bug:"Bug反馈",suggestion:"功能建议",question:"使用问题",other:"其他"}[e]||e||"-"},getStatusText(e){return{pending:"待处理",processing:"处理中",completed:"已完成",rejected:"已拒绝"}[e]||e||"-"},formatTime(e){return e?new Date(e).toLocaleString("zh-CN"):"-"},showSuccessMessage(e){this.successMessage=e,this.showSuccess=!0,setTimeout(()=>{this.showSuccess=!1},3e3)}}},F9={class:"page-feedback"},j9={class:"feedback-form-section"},N9={class:"form-group"},V9={class:"form-group"},U9={class:"form-group"},H9={class:"form-actions"},G9={class:"feedback-history-section"},K9={key:1,class:"empty"},W9={key:2,class:"feedback-table-wrapper"},q9={class:"feedback-table"},Q9={class:"content-cell"},Z9={class:"content-text"},Y9={class:"time-cell"},X9={key:0,class:"detail-content"},J9={class:"detail-item"},ex={class:"detail-item"},tx={class:"detail-content"},nx={key:0,class:"detail-item"},ox={class:"detail-item"},rx={class:"detail-item"},ix={key:1,class:"detail-item"},ax={class:"detail-content"},lx={key:2,class:"detail-item"},sx={key:0,class:"success-message"};function dx(e,t,n,o,i,r){const a=R("Dropdown"),l=R("Textarea"),s=R("InputText"),d=R("Button"),u=R("ProgressSpinner"),c=R("Tag"),f=R("Paginator"),p=R("Dialog");return g(),b("div",F9,[t[18]||(t[18]=h("h2",{class:"page-title"},"意见反馈",-1)),h("div",j9,[t[8]||(t[8]=h("h3",null,"提交反馈",-1)),h("form",{onSubmit:t[3]||(t[3]=To((...v)=>r.handleSubmit&&r.handleSubmit(...v),["prevent"]))},[h("div",N9,[t[5]||(t[5]=h("label",null,[$e("反馈类型 "),h("span",{class:"required"},"*")],-1)),D(a,{modelValue:i.formData.type,"onUpdate:modelValue":t[0]||(t[0]=v=>i.formData.type=v),options:i.typeOptions,optionLabel:"label",optionValue:"value",placeholder:"请选择反馈类型",class:"form-control",required:""},null,8,["modelValue","options"])]),h("div",V9,[t[6]||(t[6]=h("label",null,[$e("反馈内容 "),h("span",{class:"required"},"*")],-1)),D(l,{modelValue:i.formData.content,"onUpdate:modelValue":t[1]||(t[1]=v=>i.formData.content=v),rows:"6",placeholder:"请详细描述您的问题或建议...",class:"form-control",required:""},null,8,["modelValue"])]),h("div",U9,[t[7]||(t[7]=h("label",null,"联系方式(可选)",-1)),D(s,{modelValue:i.formData.contact,"onUpdate:modelValue":t[2]||(t[2]=v=>i.formData.contact=v),placeholder:"请输入您的联系方式(手机号、邮箱等)",class:"form-control"},null,8,["modelValue"])]),h("div",H9,[D(d,{type:"submit",label:"提交反馈",disabled:i.submitting,loading:i.submitting},null,8,["disabled","loading"]),D(d,{label:"重置",severity:"secondary",onClick:r.handleReset},null,8,["onClick"])])],32)]),h("div",G9,[t[10]||(t[10]=h("h3",null,"反馈历史",-1)),i.loading?(g(),T(u,{key:0})):i.feedbacks.length===0?(g(),b("div",K9,"暂无反馈记录")):(g(),b("div",W9,[h("table",q9,[t[9]||(t[9]=h("thead",null,[h("tr",null,[h("th",null,"反馈类型"),h("th",null,"反馈内容"),h("th",null,"状态"),h("th",null,"提交时间"),h("th",null,"操作")])],-1)),h("tbody",null,[(g(!0),b(te,null,Fe(i.feedbacks,v=>(g(),b("tr",{key:v.id},[h("td",null,[D(c,{value:r.getTypeText(v.type),severity:"info"},null,8,["value"])]),h("td",Q9,[h("div",Z9,_(v.content),1)]),h("td",null,[v.status?(g(),T(c,{key:0,value:r.getStatusText(v.status),severity:r.getStatusSeverity(v.status)},null,8,["value","severity"])):I("",!0)]),h("td",Y9,_(r.formatTime(v.createTime)),1),h("td",null,[D(d,{label:"查看详情",size:"small",onClick:C=>r.handleViewDetail(v)},null,8,["onClick"])])]))),128))])])])),i.total>0?(g(),T(f,{key:3,rows:i.pageSize,totalRecords:i.total,first:(i.currentPage-1)*i.pageSize,onPage:r.onPageChange},null,8,["rows","totalRecords","first","onPage"])):I("",!0)]),D(p,{visible:i.showDetail,"onUpdate:visible":t[4]||(t[4]=v=>i.showDetail=v),modal:"",header:"反馈详情",style:{width:"600px"},onHide:r.closeDetail},{default:V(()=>[i.currentFeedback?(g(),b("div",X9,[h("div",J9,[t[11]||(t[11]=h("label",null,"反馈类型:",-1)),h("span",null,_(r.getTypeText(i.currentFeedback.type)),1)]),h("div",ex,[t[12]||(t[12]=h("label",null,"反馈内容:",-1)),h("div",tx,_(i.currentFeedback.content),1)]),i.currentFeedback.contact?(g(),b("div",nx,[t[13]||(t[13]=h("label",null,"联系方式:",-1)),h("span",null,_(i.currentFeedback.contact),1)])):I("",!0),h("div",ox,[t[14]||(t[14]=h("label",null,"处理状态:",-1)),D(c,{value:r.getStatusText(i.currentFeedback.status),severity:r.getStatusSeverity(i.currentFeedback.status)},null,8,["value","severity"])]),h("div",rx,[t[15]||(t[15]=h("label",null,"提交时间:",-1)),h("span",null,_(r.formatTime(i.currentFeedback.createTime)),1)]),i.currentFeedback.reply_content?(g(),b("div",ix,[t[16]||(t[16]=h("label",null,"回复内容:",-1)),h("div",ax,_(i.currentFeedback.reply_content),1)])):I("",!0),i.currentFeedback.reply_time?(g(),b("div",lx,[t[17]||(t[17]=h("label",null,"回复时间:",-1)),h("span",null,_(r.formatTime(i.currentFeedback.reply_time)),1)])):I("",!0)])):I("",!0)]),_:1},8,["visible","onHide"]),i.showSuccess?(g(),b("div",sx,_(i.successMessage),1)):I("",!0)])}const ux=dt(z9,[["render",dx],["__scopeId","data-v-8ac3a0fd"]]),cx=()=>"http://localhost:9097/api".replace(/\/api$/,"");class fx{async getConfig(t){try{let n={};if(Array.isArray(t))n.configKeys=t.join(",");else if(typeof t=="string")n.configKey=t;else throw new Error("配置键格式错误");return await We.get("/config/get",n)}catch(n){throw console.error("获取配置失败:",n),n}}async getWechatConfig(){try{const t=await this.getConfig(["wx_num","wx_img"]);if(t&&t.code===0){let n=t.data.wx_img||"";if(n&&!n.startsWith("http://")&&!n.startsWith("https://")&&!n.startsWith("data:")){const o=cx();n.startsWith("/")?n=o+n:n=o+"/"+n}return{wechatNumber:t.data.wx_num||"",wechatQRCode:n}}return{wechatNumber:"",wechatQRCode:""}}catch(t){return console.error("获取微信配置失败:",t),{wechatNumber:"",wechatQRCode:""}}}async getPricingPlans(){try{const t=await We.get("/config/pricing-plans");return t&&t.code===0?t.data||[]:[]}catch(t){return console.error("获取价格套餐失败:",t),[]}}}const dc=new fx,px={name:"PurchasePage",mixins:[bn],components:{Card:ai,Button:xt,Badge:oi,Message:ca},data(){return{wechatNumber:"",wechatQRCode:"",showSuccess:!1,successMessage:"",loading:!1,pricingPlans:[]}},mounted(){this.loadWechatConfig(),this.loadPricingPlans()},methods:{async loadWechatConfig(){this.loading=!0;try{const e=await dc.getWechatConfig();e.wechatNumber&&(this.wechatNumber=e.wechatNumber),e.wechatQRCode&&(this.wechatQRCode=e.wechatQRCode)}catch(e){console.error("加载微信配置失败:",e),this.addLog&&this.addLog("error","加载微信配置失败: "+(e.message||"未知错误"))}finally{this.loading=!1}},async loadPricingPlans(){try{const e=await dc.getPricingPlans();e&&e.length>0&&(this.pricingPlans=e)}catch(e){console.error("加载价格套餐失败:",e),this.addLog&&this.addLog("error","加载价格套餐失败: "+(e.message||"未知错误"))}},async handleCopyWechat(){try{if(window.electronAPI&&window.electronAPI.clipboard)await window.electronAPI.clipboard.writeText(this.wechatNumber),this.showSuccessMessage("微信号已复制到剪贴板");else throw new Error("electronAPI 不可用,无法复制")}catch(e){console.error("复制失败:",e),this.addLog&&this.addLog("error","复制失败: "+(e.message||"未知错误"))}},handleContact(e){const t=`我想购买【${e.name}】(${e.duration}),价格:¥${e.price}${e.unit}`;this.showSuccessMessage(`请添加微信号 ${this.wechatNumber} 并发送:"${t}"`)},showSuccessMessage(e){this.successMessage=e,this.showSuccess=!0,setTimeout(()=>{this.showSuccess=!1},3e3)}}},hx={class:"page-purchase"},gx={class:"contact-section"},mx={class:"contact-content"},bx={class:"qr-code-wrapper"},yx={class:"qr-code-placeholder"},vx=["src"],wx={key:1,class:"qr-code-placeholder-text"},Cx={class:"contact-info"},kx={class:"info-item"},Sx={class:"info-value"},xx={class:"pricing-section"},$x={class:"pricing-grid"},Px={class:"plan-header"},Ix={class:"plan-name"},Tx={class:"plan-duration"},Rx={class:"plan-price"},Ox={key:0,class:"original-price"},Ex={class:"original-price-text"},Ax={class:"current-price"},Lx={class:"price-amount"},_x={key:0,class:"price-unit"},Dx={class:"plan-features"},Bx={class:"plan-action"},Mx={class:"notice-section"};function zx(e,t,n,o,i,r){const a=R("Button"),l=R("Card"),s=R("Badge"),d=R("Message");return g(),b("div",hx,[t[10]||(t[10]=h("h2",{class:"page-title"},"如何购买",-1)),h("div",gx,[D(l,{class:"contact-card"},{title:V(()=>[...t[1]||(t[1]=[$e("联系购买",-1)])]),content:V(()=>[t[4]||(t[4]=h("p",{class:"contact-desc"},"扫描下方二维码或添加微信号联系我们",-1)),h("div",mx,[h("div",bx,[h("div",yx,[i.wechatQRCode?(g(),b("img",{key:0,src:i.wechatQRCode,alt:"微信二维码",class:"qr-code-image"},null,8,vx)):(g(),b("div",wx,[...t[2]||(t[2]=[h("span",null,"微信二维码",-1),h("small",null,"请上传二维码图片",-1)])]))])]),h("div",Cx,[h("div",kx,[t[3]||(t[3]=h("span",{class:"info-label"},"微信号:",-1)),h("span",Sx,_(i.wechatNumber),1),D(a,{label:"复制",size:"small",onClick:r.handleCopyWechat},null,8,["onClick"])])])])]),_:1})]),h("div",xx,[t[7]||(t[7]=h("h3",{class:"section-title"},"价格套餐",-1)),h("div",$x,[(g(!0),b(te,null,Fe(i.pricingPlans,u=>(g(),T(l,{key:u.id,class:J(["pricing-card",{featured:u.featured}])},{header:V(()=>[u.featured?(g(),T(s,{key:0,value:"推荐",severity:"success"})):I("",!0)]),content:V(()=>[h("div",Px,[h("h4",Ix,_(u.name),1),h("div",Tx,_(u.duration),1)]),h("div",Rx,[u.originalPrice&&u.originalPrice>u.price?(g(),b("div",Ox,[h("span",Ex,"原价 ¥"+_(u.originalPrice),1)])):I("",!0),h("div",Ax,[t[5]||(t[5]=h("span",{class:"price-symbol"},"¥",-1)),h("span",Lx,_(u.price),1),u.unit?(g(),b("span",_x,_(u.unit),1)):I("",!0)]),u.discount?(g(),T(s,{key:1,value:u.discount,severity:"danger",class:"discount-badge"},null,8,["value"])):I("",!0)]),h("div",Dx,[(g(!0),b(te,null,Fe(u.features,c=>(g(),b("div",{class:"feature-item",key:c},[t[6]||(t[6]=h("span",{class:"feature-icon"},"✓",-1)),h("span",null,_(c),1)]))),128))]),h("div",Bx,[D(a,{label:"立即购买",onClick:c=>r.handleContact(u),class:"btn-full-width"},null,8,["onClick"])])]),_:2},1032,["class"]))),128))])]),h("div",Mx,[D(l,{class:"notice-card"},{title:V(()=>[...t[8]||(t[8]=[$e("购买说明",-1)])]),content:V(()=>[...t[9]||(t[9]=[h("ul",{class:"notice-list"},[h("li",null,"购买后请联系客服激活账号"),h("li",null,"终生套餐享受永久使用权限"),h("li",null,"如有疑问,请添加微信号咨询")],-1)])]),_:1})]),i.showSuccess?(g(),T(d,{key:0,severity:"success",closable:!0,onClose:t[0]||(t[0]=u=>i.showSuccess=!1),class:"success-message"},{default:V(()=>[$e(_(i.successMessage),1)]),_:1})):I("",!0)])}const Fx=dt(px,[["render",zx],["__scopeId","data-v-1c98de88"]]),jx={name:"LogPage",components:{Button:xt},computed:{...Ze("log",["logs"]),logEntries(){return this.logs}},mounted(){this.scrollToBottom()},updated(){this.scrollToBottom()},methods:{...oa("log",["clearLogs","exportLogs"]),handleClearLogs(){this.clearLogs()},handleExportLogs(){this.exportLogs()},scrollToBottom(){this.$nextTick(()=>{const e=document.getElementById("log-container");e&&(e.scrollTop=e.scrollHeight)})}},watch:{logEntries(){this.scrollToBottom()}}},Nx={class:"page-log"},Vx={class:"log-controls-section"},Ux={class:"log-controls"},Hx={class:"log-content-section"},Gx={class:"log-container",id:"log-container"},Kx={class:"log-time"},Wx={class:"log-message"},qx={key:0,class:"log-empty"};function Qx(e,t,n,o,i,r){const a=R("Button");return g(),b("div",Nx,[t[3]||(t[3]=h("h2",{class:"page-title"},"运行日志",-1)),h("div",Vx,[h("div",Ux,[D(a,{class:"btn",onClick:r.handleClearLogs},{default:V(()=>[...t[0]||(t[0]=[$e("清空日志",-1)])]),_:1},8,["onClick"]),D(a,{class:"btn",onClick:r.handleExportLogs},{default:V(()=>[...t[1]||(t[1]=[$e("导出日志",-1)])]),_:1},8,["onClick"])])]),h("div",Hx,[h("div",Gx,[(g(!0),b(te,null,Fe(r.logEntries,(l,s)=>(g(),b("div",{key:s,class:"log-entry"},[h("span",Kx,"["+_(l.time)+"]",1),h("span",{class:J(["log-level",l.level.toLowerCase()])},"["+_(l.level)+"]",3),h("span",Wx,_(l.message),1)]))),128)),r.logEntries.length===0?(g(),b("div",qx,[...t[2]||(t[2]=[h("p",null,"暂无日志记录",-1)])])):I("",!0)])])])}const Zx=dt(jx,[["render",Qx],["__scopeId","data-v-c5fdcf0e"]]),Yx={namespaced:!0,state:{currentVersion:"1.0.0",isLoading:!0,startTime:Date.now()},mutations:{SET_VERSION(e,t){e.currentVersion=t},SET_LOADING(e,t){e.isLoading=t}},actions:{setVersion({commit:e},t){e("SET_VERSION",t)},setLoading({commit:e},t){e("SET_LOADING",t)}}},Xx={namespaced:!0,state:{email:"",password:"",isLoggedIn:!1,loginButtonText:"登录",userName:"",remainingDays:null,snCode:"",deviceId:null,platformType:null,userId:null,listenChannel:"-",userLoggedOut:!1,rememberMe:!1,userMenuInfo:{userName:"",snCode:""}},mutations:{SET_EMAIL(e,t){e.email=t},SET_PASSWORD(e,t){e.password=t},SET_LOGGED_IN(e,t){e.isLoggedIn=t},SET_LOGIN_BUTTON_TEXT(e,t){e.loginButtonText=t},SET_USER_NAME(e,t){e.userName=t,e.userMenuInfo.userName=t},SET_REMAINING_DAYS(e,t){e.remainingDays=t},SET_SN_CODE(e,t){e.snCode=t,e.userMenuInfo.snCode=t,e.listenChannel=t?`request_${t}`:"-"},SET_DEVICE_ID(e,t){e.deviceId=t},SET_PLATFORM_TYPE(e,t){e.platformType=t},SET_USER_ID(e,t){e.userId=t},SET_USER_LOGGED_OUT(e,t){e.userLoggedOut=t},SET_REMEMBER_ME(e,t){e.rememberMe=t},SET_USER_MENU_INFO(e,t){e.userMenuInfo={...e.userMenuInfo,...t}},CLEAR_AUTH(e){e.isLoggedIn=!1,e.loginButtonText="登录",e.listenChannel="-",e.snCode="",e.deviceId=null,e.platformType=null,e.userId=null,e.userName="",e.remainingDays=null,e.userMenuInfo={userName:"",snCode:""},e.password="",e.userLoggedOut=!0}},actions:{async restoreLoginStatus({commit:e,state:t}){try{const n=ph();if(console.log("[Auth Store] 尝试恢复登录状态:",{hasToken:!!n,userLoggedOut:t.userLoggedOut,snCode:t.snCode,userName:t.userName,isLoggedIn:t.isLoggedIn,persistedState:{email:t.email,platformType:t.platformType,userId:t.userId,deviceId:t.deviceId}}),n&&!t.userLoggedOut&&(t.snCode||t.userName)){if(console.log("[Auth Store] 满足恢复登录条件,开始恢复..."),e("SET_LOGGED_IN",!0),e("SET_LOGIN_BUTTON_TEXT","注销登录"),window.electronAPI&&window.electronAPI.invoke)try{if(await window.electronAPI.invoke("auth:sync-user-info",{platform_type:t.platformType||null,sn_code:t.snCode||"",user_id:t.userId||null,user_name:t.userName||"",device_id:t.deviceId||null}),console.log("[Auth Store] 用户信息已同步到主进程"),t.snCode)try{const o=await window.electronAPI.invoke("mqtt:connect",t.snCode);console.log("[Auth Store] 恢复登录后 MQTT 连接结果:",o),o&&o.success&&o.isConnected&&(e("mqtt/SET_CONNECTED",!0,{root:!0}),e("mqtt/SET_STATUS","已连接",{root:!0}),console.log("[Auth Store] 恢复登录后 MQTT 状态已更新到 store"))}catch(o){console.warn("[Auth Store] 恢复登录后 MQTT 连接失败:",o)}}catch(o){console.warn("[Auth Store] 恢复登录状态时同步用户信息到主进程失败:",o)}else console.warn("[Auth Store] electronAPI 不可用,无法同步用户信息到主进程");console.log("[Auth Store] 登录状态恢复完成")}else console.log("[Auth Store] 不满足恢复登录条件,跳过恢复")}catch(n){console.error("[Auth Store] 恢复登录状态失败:",n)}},async login({commit:e},{email:t,password:n,deviceId:o=null}){try{const i=await $3(t,n,o);if(i.code===0&&i.data){const{token:r,user:a,device_id:l}=i.data;if(e("SET_EMAIL",t),e("SET_PASSWORD",n),e("SET_LOGGED_IN",!0),e("SET_LOGIN_BUTTON_TEXT","注销登录"),e("SET_USER_NAME",(a==null?void 0:a.name)||t),e("SET_REMAINING_DAYS",(a==null?void 0:a.remaining_days)||null),e("SET_SN_CODE",(a==null?void 0:a.sn_code)||""),e("SET_DEVICE_ID",l||o),e("SET_PLATFORM_TYPE",(a==null?void 0:a.platform_type)||null),e("SET_USER_ID",(a==null?void 0:a.id)||null),e("SET_USER_LOGGED_OUT",!1),a!=null&&a.platform_type){const d={boss:"BOSS直聘",liepin:"猎聘",zhilian:"智联招聘",1:"BOSS直聘"}[a.platform_type]||a.platform_type;e("platform/SET_CURRENT_PLATFORM",d,{root:!0}),e("platform/SET_PLATFORM_LOGIN_STATUS",{status:"未登录",color:"#FF9800",isLoggedIn:!1},{root:!0}),console.log("[Auth Store] 平台信息已初始化")}if(window.electronAPI&&window.electronAPI.invoke)try{if(await window.electronAPI.invoke("auth:sync-user-info",{token:r,platform_type:(a==null?void 0:a.platform_type)||null,sn_code:(a==null?void 0:a.sn_code)||"",user_id:(a==null?void 0:a.id)||null,user_name:(a==null?void 0:a.name)||t,device_id:l||o}),a!=null&&a.sn_code)try{const s=await window.electronAPI.invoke("mqtt:connect",a.sn_code);console.log("[Auth Store] MQTT 连接结果:",s),s&&s.success&&s.isConnected&&(e("mqtt/SET_CONNECTED",!0,{root:!0}),e("mqtt/SET_STATUS","已连接",{root:!0}),console.log("[Auth Store] MQTT 状态已更新到 store"))}catch(s){console.warn("[Auth Store] MQTT 连接失败:",s)}}catch(s){console.warn("[Auth Store] 同步用户信息到主进程失败:",s)}return{success:!0,data:i.data}}else return{success:!1,error:i.message||"登录失败"}}catch(i){return console.error("[Auth Store] 登录失败:",i),{success:!1,error:i.message||"登录过程中发生错误"}}},logout({commit:e}){e("CLEAR_AUTH"),P3()},updateUserInfo({commit:e},t){t.name&&e("SET_USER_NAME",t.name),t.sn_code&&e("SET_SN_CODE",t.sn_code),t.device_id&&e("SET_DEVICE_ID",t.device_id),t.remaining_days!==void 0&&e("SET_REMAINING_DAYS",t.remaining_days)}},getters:{isLoggedIn:e=>e.isLoggedIn,userInfo:e=>({email:e.email,userName:e.userName,snCode:e.snCode,deviceId:e.deviceId,remainingDays:e.remainingDays})}},Jx={namespaced:!0,state:{isConnected:!1,mqttStatus:"未连接"},mutations:{SET_CONNECTED(e,t){e.isConnected=t},SET_STATUS(e,t){e.mqttStatus=t}},actions:{setConnected({commit:e},t){e("SET_CONNECTED",t),e("SET_STATUS",t?"已连接":"未连接")}}},e$={namespaced:!0,state:{displayText:null,nextExecuteTimeText:null,currentActivity:null,pendingQueue:null,deviceStatus:null,taskStats:{todayCount:0,weekCount:0,monthCount:0,totalCount:0,completedCount:0,runningCount:0,pendingCount:0,failedCount:0,completionRate:0}},mutations:{SET_DEVICE_WORK_STATUS(e,t){var n;e.displayText=t.displayText||null,e.nextExecuteTimeText=((n=t.pendingQueue)==null?void 0:n.nextExecuteTimeText)||null,e.currentActivity=t.currentActivity||null,e.pendingQueue=t.pendingQueue||null,e.deviceStatus=t.deviceStatus||null},CLEAR_DEVICE_WORK_STATUS(e){e.displayText=null,e.nextExecuteTimeText=null,e.currentActivity=null,e.pendingQueue=null,e.deviceStatus=null},SET_TASK_STATS(e,t){e.taskStats={...e.taskStats,...t}}},actions:{updateDeviceWorkStatus({commit:e},t){e("SET_DEVICE_WORK_STATUS",t)},clearDeviceWorkStatus({commit:e}){e("CLEAR_DEVICE_WORK_STATUS")},async loadTaskStats({commit:e,rootState:t}){try{const n=t.auth.snCode;if(!n)return console.warn("[Task Store] 没有 snCode,无法加载任务统计"),{success:!1,error:"请先登录"};const o=await We.get("/task/statistics",{sn_code:n});if(o&&o.code===0&&o.data)return e("SET_TASK_STATS",o.data),{success:!0};{const i=(o==null?void 0:o.message)||"加载任务统计失败";return console.error("[Task Store] 加载任务统计失败:",o),{success:!1,error:i}}}catch(n){return console.error("[Task Store] 加载任务统计失败:",n),{success:!1,error:n.message||"加载任务统计失败"}}}}},t$={namespaced:!0,state:{uptime:"0分钟",cpuUsage:"0%",memUsage:"0MB",deviceId:"-"},mutations:{SET_UPTIME(e,t){e.uptime=t},SET_CPU_USAGE(e,t){e.cpuUsage=t},SET_MEM_USAGE(e,t){e.memUsage=t},SET_DEVICE_ID(e,t){e.deviceId=t||"-"}},actions:{updateUptime({commit:e},t){e("SET_UPTIME",t)},updateCpuUsage({commit:e},t){e("SET_CPU_USAGE",`${t.toFixed(1)}%`)},updateMemUsage({commit:e},t){e("SET_MEM_USAGE",`${t}MB`)},updateDeviceId({commit:e},t){e("SET_DEVICE_ID",t)}}},n$={namespaced:!0,state:{currentPlatform:"-",platformLoginStatus:"-",platformLoginStatusColor:"#FF9800",isPlatformLoggedIn:!1},mutations:{SET_CURRENT_PLATFORM(e,t){e.currentPlatform=t},SET_PLATFORM_LOGIN_STATUS(e,{status:t,color:n,isLoggedIn:o}){e.platformLoginStatus=t,e.platformLoginStatusColor=n||"#FF9800",e.isPlatformLoggedIn=o||!1}},actions:{updatePlatform({commit:e},t){e("SET_CURRENT_PLATFORM",t)},updatePlatformLoginStatus({commit:e},{status:t,color:n,isLoggedIn:o}){e("SET_PLATFORM_LOGIN_STATUS",{status:t,color:n,isLoggedIn:o})}}},o$={namespaced:!0,state:{qrCodeUrl:null,qrCodeOosUrl:null,qrCodeCountdown:0,qrCodeCountdownActive:!1,qrCodeRefreshCount:0,qrCodeExpired:!1},mutations:{SET_QR_CODE_URL(e,{url:t,oosUrl:n}){e.qrCodeUrl=t,e.qrCodeOosUrl=n||null},SET_QR_CODE_COUNTDOWN(e,{countdown:t,isActive:n,refreshCount:o,isExpired:i}){e.qrCodeCountdown=t||0,e.qrCodeCountdownActive=n||!1,e.qrCodeRefreshCount=o||0,e.qrCodeExpired=i||!1},CLEAR_QR_CODE(e){e.qrCodeUrl=null,e.qrCodeOosUrl=null}},actions:{setQrCode({commit:e},{url:t,oosUrl:n}){e("SET_QR_CODE_URL",{url:t,oosUrl:n})},setQrCodeCountdown({commit:e},t){e("SET_QR_CODE_COUNTDOWN",t)},clearQrCode({commit:e}){e("CLEAR_QR_CODE")}}},r$={namespaced:!0,state:{updateDialogVisible:!1,updateInfo:null,updateProgress:0,isDownloading:!1,downloadState:{progress:0,downloadedBytes:0,totalBytes:0}},mutations:{SET_UPDATE_DIALOG_VISIBLE(e,t){e.updateDialogVisible=t},SET_UPDATE_INFO(e,t){e.updateInfo=t},SET_UPDATE_PROGRESS(e,t){e.updateProgress=t},SET_DOWNLOADING(e,t){e.isDownloading=t},SET_DOWNLOAD_STATE(e,t){e.downloadState={...e.downloadState,...t}}},actions:{showUpdateDialog({commit:e}){e("SET_UPDATE_DIALOG_VISIBLE",!0)},hideUpdateDialog({commit:e}){e("SET_UPDATE_DIALOG_VISIBLE",!1)},setUpdateInfo({commit:e},t){e("SET_UPDATE_INFO",t)},setUpdateProgress({commit:e},t){e("SET_UPDATE_PROGRESS",t)},setDownloading({commit:e},t){e("SET_DOWNLOADING",t)},setDownloadState({commit:e},t){e("SET_DOWNLOAD_STATE",t)}}},i$=function(){const t=typeof document<"u"&&document.createElement("link").relList;return t&&t.supports&&t.supports("modulepreload")?"modulepreload":"preload"}(),a$=function(e){return"/app/"+e},uc={},za=function(t,n,o){let i=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const a=document.querySelector("meta[property=csp-nonce]"),l=(a==null?void 0:a.nonce)||(a==null?void 0:a.getAttribute("nonce"));i=Promise.allSettled(n.map(s=>{if(s=a$(s),s in uc)return;uc[s]=!0;const d=s.endsWith(".css"),u=d?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${s}"]${u}`))return;const c=document.createElement("link");if(c.rel=d?"stylesheet":i$,d||(c.as="script"),c.crossOrigin="",c.href=s,l&&c.setAttribute("nonce",l),document.head.appendChild(c),d)return new Promise((f,p)=>{c.addEventListener("load",f),c.addEventListener("error",()=>p(new Error(`Unable to preload CSS for ${s}`)))})}))}function r(a){const l=new Event("vite:preloadError",{cancelable:!0});if(l.payload=a,window.dispatchEvent(l),!l.defaultPrevented)throw a}return i.then(a=>{for(const l of a||[])l.status==="rejected"&&r(l.reason);return t().catch(r)})},l$={namespaced:!0,state:{deliveryStats:{todayCount:0,weekCount:0,monthCount:0,totalCount:0,successCount:0,failedCount:0,pendingCount:0,interviewCount:0,successRate:0,interviewRate:0},deliveryConfig:{autoDelivery:!1,interval:30,minSalary:15e3,maxSalary:3e4,scrollPages:3,maxPerBatch:10,filterKeywords:"",excludeKeywords:"",startTime:"09:00",endTime:"18:00",workdaysOnly:!0}},mutations:{SET_DELIVERY_STATS(e,t){e.deliveryStats={...e.deliveryStats,...t}},SET_DELIVERY_CONFIG(e,t){e.deliveryConfig={...e.deliveryConfig,...t}},UPDATE_DELIVERY_CONFIG(e,{key:t,value:n}){e.deliveryConfig[t]=n}},actions:{updateDeliveryStats({commit:e},t){e("SET_DELIVERY_STATS",t)},async loadDeliveryStats({commit:e,rootState:t}){try{const n=t.auth.snCode;if(!n)return console.warn("[Delivery Store] 没有 snCode,无法加载统计数据"),{success:!1,error:"请先登录"};const i=await(await za(async()=>{const{default:r}=await Promise.resolve().then(()=>x7);return{default:r}},void 0)).default.getStatistics(n);if(i&&i.code===0&&i.data)return e("SET_DELIVERY_STATS",i.data),{success:!0};{const r=(i==null?void 0:i.message)||"加载统计失败";return console.error("[Delivery Store] 加载统计失败:",i),{success:!1,error:r}}}catch(n){return console.error("[Delivery Store] 加载统计失败:",n),{success:!1,error:n.message||"加载统计失败"}}},updateDeliveryConfig({commit:e},{key:t,value:n}){e("UPDATE_DELIVERY_CONFIG",{key:t,value:n})},setDeliveryConfig({commit:e},t){e("SET_DELIVERY_CONFIG",t)},async saveDeliveryConfig({state:e,rootState:t}){try{const n=t.auth.snCode;if(!n)return{success:!1,error:"请先登录"};const o={auto_deliver:e.deliveryConfig.autoDelivery,time_range:{start_time:e.deliveryConfig.startTime,end_time:e.deliveryConfig.endTime,workdays_only:e.deliveryConfig.workdaysOnly?1:0}},r=await(await za(async()=>{const{default:a}=await import("./delivery_config-BjklYJQ0.js");return{default:a}},[])).default.saveConfig(n,o);if(r&&(r.code===0||r.success===!0))return{success:!0};{const a=(r==null?void 0:r.message)||(r==null?void 0:r.error)||"保存失败";return console.error("[Delivery Store] 保存配置失败:",r),{success:!1,error:a}}}catch(n){return console.error("[Delivery Store] 保存配置失败:",n),{success:!1,error:n.message||"保存配置失败"}}},async loadDeliveryConfig({commit:e,rootState:t}){try{const n=t.auth.snCode;if(!n)return{success:!0};const i=await(await za(async()=>{const{default:r}=await import("./delivery_config-BjklYJQ0.js");return{default:r}},[])).default.getConfig(n);if(i&&i.data&&i.data.deliver_config){const r=i.data.deliver_config;console.log("deliverConfig",r);const a={};if(r.auto_deliver!=null&&(a.autoDelivery=r.auto_deliver),r.time_range){const l=r.time_range;l.start_time!=null&&(a.startTime=l.start_time),l.end_time!=null&&(a.endTime=l.end_time),l.workdays_only!=null&&(a.workdaysOnly=l.workdays_only===1)}return console.log("frontendConfig",a),e("SET_DELIVERY_CONFIG",a),{success:!0}}else return{success:!0}}catch(n){return console.error("[Delivery Store] 加载配置失败:",n),{success:!0}}}}},s$={namespaced:!0,state:{logs:[],maxLogs:1e3},mutations:{ADD_LOG(e,t){e.logs.push(t),e.logs.length>e.maxLogs&&e.logs.shift()},CLEAR_LOGS(e){e.logs=[]}},actions:{addLog({commit:e},{level:t,message:n}){const i={time:new Date().toLocaleString(),level:t.toUpperCase(),message:n};e("ADD_LOG",i)},clearLogs({commit:e}){e("CLEAR_LOGS"),e("ADD_LOG",{time:new Date().toLocaleString(),level:"INFO",message:"日志已清空"})},exportLogs({state:e,commit:t}){const n=e.logs.map(a=>`[${a.time}] [${a.level}] ${a.message}`).join(` -`),o=new Blob([n],{type:"text/plain"}),i=URL.createObjectURL(o),r=document.createElement("a");r.href=i,r.download=`logs_${new Date().toISOString().replace(/[:.]/g,"-")}.txt`,r.click(),URL.revokeObjectURL(i),t("ADD_LOG",{time:new Date().toLocaleString(),level:"INFO",message:"日志已导出"})}},getters:{logEntries:e=>e.logs}},d$={namespaced:!0,state:{email:"",userLoggedOut:!1,rememberMe:!1,appSettings:{autoStart:!1,startOnBoot:!1,enableNotifications:!0,soundAlert:!0},deviceId:null},mutations:{SET_EMAIL(e,t){e.email=t},SET_USER_LOGGED_OUT(e,t){e.userLoggedOut=t},SET_REMEMBER_ME(e,t){e.rememberMe=t},SET_APP_SETTINGS(e,t){e.appSettings={...e.appSettings,...t}},UPDATE_APP_SETTING(e,{key:t,value:n}){e.appSettings[t]=n},SET_DEVICE_ID(e,t){e.deviceId=t}},actions:{setEmail({commit:e},t){e("SET_EMAIL",t)},setUserLoggedOut({commit:e},t){e("SET_USER_LOGGED_OUT",t)},setRememberMe({commit:e},t){e("SET_REMEMBER_ME",t)},updateAppSettings({commit:e},t){e("SET_APP_SETTINGS",t)},updateAppSetting({commit:e},{key:t,value:n}){e("UPDATE_APP_SETTING",{key:t,value:n})},setDeviceId({commit:e},t){e("SET_DEVICE_ID",t)}},getters:{email:e=>e.email,userLoggedOut:e=>e.userLoggedOut,rememberMe:e=>e.rememberMe,appSettings:e=>e.appSettings,deviceId:e=>e.deviceId}};var u$=function(e){return function(t){return!!t&&typeof t=="object"}(e)&&!function(t){var n=Object.prototype.toString.call(t);return n==="[object RegExp]"||n==="[object Date]"||function(o){return o.$$typeof===c$}(t)}(e)},c$=typeof Symbol=="function"&&Symbol.for?Symbol.for("react.element"):60103;function Uo(e,t){return t.clone!==!1&&t.isMergeableObject(e)?xo(Array.isArray(e)?[]:{},e,t):e}function f$(e,t,n){return e.concat(t).map(function(o){return Uo(o,n)})}function cc(e){return Object.keys(e).concat(function(t){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(t).filter(function(n){return t.propertyIsEnumerable(n)}):[]}(e))}function fc(e,t){try{return t in e}catch{return!1}}function xo(e,t,n){(n=n||{}).arrayMerge=n.arrayMerge||f$,n.isMergeableObject=n.isMergeableObject||u$,n.cloneUnlessOtherwiseSpecified=Uo;var o=Array.isArray(t);return o===Array.isArray(e)?o?n.arrayMerge(e,t,n):function(i,r,a){var l={};return a.isMergeableObject(i)&&cc(i).forEach(function(s){l[s]=Uo(i[s],a)}),cc(r).forEach(function(s){(function(d,u){return fc(d,u)&&!(Object.hasOwnProperty.call(d,u)&&Object.propertyIsEnumerable.call(d,u))})(i,s)||(l[s]=fc(i,s)&&a.isMergeableObject(r[s])?function(d,u){if(!u.customMerge)return xo;var c=u.customMerge(d);return typeof c=="function"?c:xo}(s,a)(i[s],r[s],a):Uo(r[s],a))}),l}(e,t,n):Uo(t,n)}xo.all=function(e,t){if(!Array.isArray(e))throw new Error("first argument should be an array");return e.reduce(function(n,o){return xo(n,o,t)},{})};var p$=xo;function h$(e){var t=(e=e||{}).storage||window&&window.localStorage,n=e.key||"vuex";function o(u,c){var f=c.getItem(u);try{return typeof f=="string"?JSON.parse(f):typeof f=="object"?f:void 0}catch{}}function i(){return!0}function r(u,c,f){return f.setItem(u,JSON.stringify(c))}function a(u,c){return Array.isArray(c)?c.reduce(function(f,p){return function(S,x,P,L){return!/^(__proto__|constructor|prototype)$/.test(x)&&((x=x.split?x.split("."):x.slice(0)).slice(0,-1).reduce(function(k,F){return k[F]=k[F]||{}},S)[x.pop()]=P),S}(f,p,(v=u,(v=((C=p).split?C.split("."):C).reduce(function(S,x){return S&&S[x]},v))===void 0?void 0:v));var v,C},{}):u}function l(u){return function(c){return u.subscribe(c)}}(e.assertStorage||function(){t.setItem("@@",1),t.removeItem("@@")})(t);var s,d=function(){return(e.getState||o)(n,t)};return e.fetchBeforeUse&&(s=d()),function(u){e.fetchBeforeUse||(s=d()),typeof s=="object"&&s!==null&&(u.replaceState(e.overwrite?s:p$(u.state,s,{arrayMerge:e.arrayMerger||function(c,f){return f},clone:!1})),(e.rehydrated||function(){})(u)),(e.subscriber||l)(u)(function(c,f){(e.filter||i)(c)&&(e.setState||r)(n,(e.reducer||a)(f,e.paths),t)})}}const zs=Eb({modules:{app:Yx,auth:Xx,mqtt:Jx,task:e$,system:t$,platform:n$,qrCode:o$,update:r$,delivery:l$,log:s$,config:d$},plugins:[h$({key:"boss-auto-app",storage:window.localStorage,paths:["auth","config"]})]});console.log("[Store] localStorage中保存的数据:",{"boss-auto-app":localStorage.getItem("boss-auto-app"),api_token:localStorage.getItem("api_token")});zs.dispatch("auth/restoreLoginStatus");const g$=[{path:"/",redirect:"/console"},{path:"/login",name:"Login",component:n7,meta:{requiresAuth:!1,showSidebar:!1}},{path:"/console",name:"Console",component:q8,meta:{requiresAuth:!0}},{path:"/delivery",name:"Delivery",component:b9,meta:{requiresAuth:!0}},{path:"/invite",name:"Invite",component:B9,meta:{requiresAuth:!0}},{path:"/feedback",name:"Feedback",component:ux,meta:{requiresAuth:!0}},{path:"/log",name:"Log",component:Zx,meta:{requiresAuth:!0}},{path:"/purchase",name:"Purchase",component:Fx,meta:{requiresAuth:!0}}],Lh=G4({history:S4(),routes:g$});Lh.beforeEach((e,t,n)=>{const o=zs.state.auth.isLoggedIn;e.meta.requiresAuth&&!o?n("/login"):e.path==="/login"&&o?n("/console"):n()});function Xr(e){"@babel/helpers - typeof";return Xr=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Xr(e)}function pc(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter(function(i){return Object.getOwnPropertyDescriptor(e,i).enumerable})),n.push.apply(n,o)}return n}function Ci(e){for(var t=1;t{Gn.mount("#app"),window.app=Gn,console.log("Vue 应用已挂载")}):(Gn.mount("#app"),window.app=Gn,console.log("Vue 应用已挂载"));export{We as a}; diff --git a/app/assets/primeicons-C6QP2o4f.woff2 b/app/assets/primeicons-C6QP2o4f.woff2 deleted file mode 100644 index 26fb219..0000000 Binary files a/app/assets/primeicons-C6QP2o4f.woff2 and /dev/null differ diff --git a/app/assets/primeicons-DMOk5skT.eot b/app/assets/primeicons-DMOk5skT.eot deleted file mode 100644 index 6e7e08a..0000000 Binary files a/app/assets/primeicons-DMOk5skT.eot and /dev/null differ diff --git a/app/assets/primeicons-Dr5RGzOO.svg b/app/assets/primeicons-Dr5RGzOO.svg deleted file mode 100644 index fde255e..0000000 --- a/app/assets/primeicons-Dr5RGzOO.svg +++ /dev/null @@ -1,345 +0,0 @@ - - - - - - -{ - "fontFamily": "primeicons", - "majorVersion": 1, - "minorVersion": 0, - "copyright": "PrimeTek Informatics", - "designer": "", - "description": "Icon Library for Prime UI Libraries\nFont generated by IcoMoon.", - "fontURL": "https://github.com/primefaces/primeicons", - "license": "MIT", - "licenseURL": "https://opensource.org/licenses/MIT", - "version": "Version 1.0", - "fontId": "primeicons", - "psName": "primeicons", - "subFamily": "Regular", - "fullName": "primeicons" -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/assets/primeicons-MpK4pl85.ttf b/app/assets/primeicons-MpK4pl85.ttf deleted file mode 100644 index 06fa9b1..0000000 Binary files a/app/assets/primeicons-MpK4pl85.ttf and /dev/null differ diff --git a/app/assets/primeicons-WjwUDZjB.woff b/app/assets/primeicons-WjwUDZjB.woff deleted file mode 100644 index 62c47a2..0000000 Binary files a/app/assets/primeicons-WjwUDZjB.woff and /dev/null differ diff --git a/app/index.html b/app/index.html deleted file mode 100644 index e8aa269..0000000 --- a/app/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - boss - 远程监听服务 - - - - - - -
-
- -
正在启动...
-
-
-
-
-
- - -
- - - - - diff --git a/config/config.js b/config/config.js index dda0422..8a6d78c 100644 --- a/config/config.js +++ b/config/config.js @@ -68,7 +68,7 @@ module.exports = { ai: { "apiKey": "sk-c83cdb06a6584f99bb2cd6e8a5ae3bbc", "baseUrl": "https://dashscope.aliyuncs.com/api/v1", - "model": "qwen-turbo" + "model": "qwen-plus" }, // MQTT配置 diff --git a/config/framework.config.js b/config/framework.config.js index 8f50123..3d85bb8 100644 --- a/config/framework.config.js +++ b/config/framework.config.js @@ -25,7 +25,7 @@ module.exports = { acquire: 30000, idle: 10000 }, - logging: true + logging: false }, // API 路径配置(必需) diff --git a/scripts/migrate_add_auto_search_active.sql b/scripts/migrate_add_auto_search_active.sql new file mode 100644 index 0000000..500c4f1 --- /dev/null +++ b/scripts/migrate_add_auto_search_active.sql @@ -0,0 +1,59 @@ +-- 任务调度系统重构 - 数据库迁移脚本 +-- 为 pla_account 表添加自动搜索和自动活跃相关字段 + +USE autoAiWorkSys; + +-- 1. 添加自动搜索开关字段 +ALTER TABLE pla_account +ADD COLUMN auto_search TINYINT(1) DEFAULT 0 COMMENT '是否开启自动搜索: 0-关闭, 1-开启'; + +-- 2. 添加搜索配置字段 +ALTER TABLE pla_account +ADD COLUMN search_config TEXT COMMENT '搜索配置(JSON): {search_interval, page_count, city, salary_range, time_range等}'; + +-- 3. 添加自动活跃开关字段 +ALTER TABLE pla_account +ADD COLUMN auto_active TINYINT(1) DEFAULT 0 COMMENT '是否开启自动活跃: 0-关闭, 1-开启'; + +-- 4. 添加活跃策略配置字段 +ALTER TABLE pla_account +ADD COLUMN active_strategy TEXT COMMENT '活跃策略配置(JSON): {active_interval, actions, time_range等}'; + +-- 5. 查看表结构验证 +DESC pla_account; + +-- 示例: 为已有账号设置默认配置 +-- UPDATE pla_account +-- SET +-- auto_search = 0, +-- search_config = JSON_OBJECT( +-- 'search_interval', 60, +-- 'page_count', 3, +-- 'city', '', +-- 'time_range', JSON_OBJECT( +-- 'start_time', '09:00', +-- 'end_time', '18:00', +-- 'workdays_only', 1 +-- ) +-- ), +-- auto_active = 0, +-- active_strategy = JSON_OBJECT( +-- 'active_interval', 120, +-- 'actions', JSON_ARRAY('browse_jobs', 'refresh_resume', 'check_notifications'), +-- 'time_range', JSON_OBJECT( +-- 'start_time', '08:00', +-- 'end_time', '23:00', +-- 'workdays_only', 0 +-- ) +-- ) +-- WHERE is_delete = 0; + +-- 注意: +-- 1. 执行前请先备份数据库 +-- 2. 建议在测试环境先测试 +-- 3. search_config 和 active_strategy 字段存储JSON格式的配置 +-- 4. 如果字段已存在会报错,可以先删除字段后再添加: +-- ALTER TABLE pla_account DROP COLUMN auto_search; +-- ALTER TABLE pla_account DROP COLUMN search_config; +-- ALTER TABLE pla_account DROP COLUMN auto_active; +-- ALTER TABLE pla_account DROP COLUMN active_strategy;