/** * 项目相关模拟数据 */ import type { ProjectInfo, ProjectTag, ProjectPublisher, ProjectQueryParams, ProjectListResult, WorkType } from '@/types' // 模拟项目标签 const mockProjectTags: ProjectTag[] = [ { id: 1, name: 'Vue', color: '#42b883' }, { id: 2, name: 'React', color: '#61dafb' }, { id: 3, name: 'Node.js', color: '#339933' }, { id: 4, name: 'Python', color: '#3776ab' }, { id: 5, name: 'Java', color: '#007396' }, { id: 6, name: 'Go', color: '#00add8' }, { id: 7, name: '小程序', color: '#07c160' }, { id: 8, name: 'APP开发', color: '#ff6b6b' }, { id: 9, name: '数据分析', color: '#845ef7' }, { id: 10, name: 'AI/ML', color: '#ff922b' } ] // 模拟发布人 const mockPublishers: ProjectPublisher[] = [ { id: 1, username: 'techcorp', nickname: '科技有限公司', avatar: 'https://api.dicebear.com/7.x/identicon/svg?seed=techcorp', company: '科技有限公司' }, { id: 2, username: 'startup', nickname: '创业团队', avatar: 'https://api.dicebear.com/7.x/identicon/svg?seed=startup', company: '创新科技' }, { id: 3, username: 'bigcompany', nickname: '大厂HR', avatar: 'https://api.dicebear.com/7.x/identicon/svg?seed=bigcompany', company: '某大厂' }, { id: 4, username: 'freelancer', nickname: '独立开发者', avatar: 'https://api.dicebear.com/7.x/identicon/svg?seed=freelancer' }, { id: 5, username: 'agency', nickname: '外包公司', avatar: 'https://api.dicebear.com/7.x/identicon/svg?seed=agency', company: '软件外包' } ] const projectNames = [ '企业官网开发项目', '电商小程序开发', '数据可视化平台', 'CRM系统定制开发', 'APP后端接口开发', '在线教育平台开发', '社交应用开发', '物流管理系统', 'AI智能客服系统', '区块链应用开发', '医疗健康APP', '金融风控系统' ] const locations = ['北京', '上海', '深圳', '杭州', '广州', '成都', '武汉', '南京', '不限'] const workTypes: WorkType[] = ['fulltime', 'parttime', 'remote', 'internship'] const descriptions = [ '我们正在寻找有经验的开发者加入我们的项目,参与核心功能的开发和优化。项目采用最新的技术栈,有良好的代码规范和开发流程。', '这是一个具有挑战性的项目,需要您具备扎实的编程基础和良好的学习能力。我们提供灵活的工作时间和有竞争力的薪资待遇。', '加入我们的团队,您将有机会参与大型项目的架构设计和技术选型,与优秀的工程师一起工作,不断提升自己的技术能力。' ] const requirements = [ '1. 3年以上相关开发经验\n2. 熟悉主流开发框架\n3. 良好的代码规范意识\n4. 具备团队协作精神\n5. 有大型项目经验优先', '1. 本科及以上学历\n2. 熟练掌握至少一门编程语言\n3. 了解常用设计模式\n4. 具备独立解决问题的能力\n5. 有开源项目经验优先', '1. 2年以上工作经验\n2. 熟悉敏捷开发流程\n3. 具备良好的沟通能力\n4. 能够承受一定的工作压力\n5. 对技术有热情' ] const benefits = [ '五险一金、带薪年假、弹性工作、免费午餐、定期团建、技术分享会', '远程办公、股权激励、年终奖金、技术培训、健身房、零食饮料', '双休、节日福利、项目奖金、晋升通道清晰、技术氛围好' ] // 生成模拟项目数据 function generateMockProjects(): ProjectInfo[] { const projects: ProjectInfo[] = [] for (let i = 1; i <= 40; i++) { const salaryMin = Math.floor(Math.random() * 20 + 5) * 1000 const salaryMax = salaryMin + Math.floor(Math.random() * 15 + 5) * 1000 const deadlineDate = new Date(Date.now() + Math.floor(Math.random() * 60 + 10) * 24 * 60 * 60 * 1000) const isExpired = Math.random() > 0.9 const tag1 = mockProjectTags[i % mockProjectTags.length]! const tag2 = mockProjectTags[(i + 3) % mockProjectTags.length]! const isPinned = Math.random() > 0.8 const pinnedDays = [3, 7, 14, 30][Math.floor(Math.random() * 4)] projects.push({ id: i, name: projectNames[i % projectNames.length]!, salaryMin, salaryMax, salaryUnit: Math.random() > 0.7 ? '项目' : '月', publisher: mockPublishers[i % mockPublishers.length]!, location: locations[i % locations.length]!, workType: workTypes[i % workTypes.length]!, description: descriptions[i % descriptions.length]!, requirements: requirements[i % requirements.length]!, benefits: benefits[i % benefits.length]!, tags: tag1.id === tag2.id ? [tag1] : [tag1, tag2], contactEmail: `hr${i}@example.com`, deadline: deadlineDate.toISOString(), status: isExpired ? 'expired' : (Math.random() > 0.2 ? 'active' : 'closed'), createdAt: new Date(Date.now() - Math.floor(Math.random() * 30 * 24 * 60 * 60 * 1000)).toISOString(), updatedAt: new Date(Date.now() - Math.floor(Math.random() * 7 * 24 * 60 * 60 * 1000)).toISOString(), isPinned, pinnedUntil: isPinned ? new Date(Date.now() + pinnedDays! * 24 * 60 * 60 * 1000).toISOString() : undefined, exposureCount: Math.floor(Math.random() * 500), lastExposureAt: Math.random() > 0.5 ? new Date(Date.now() - Math.floor(Math.random() * 3 * 24 * 60 * 60 * 1000)).toISOString() : undefined }) } return projects.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()) } let mockProjects = generateMockProjects() // 模拟延迟 function delay(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)) } // 获取项目列表 export async function mockGetProjectList(params: ProjectQueryParams = {}): Promise { await delay(300) const { page = 1, pageSize = 10, keyword, workType, tagId, status, location } = params let filtered = [...mockProjects] if (keyword) { filtered = filtered.filter(p => p.name.includes(keyword) || p.publisher.nickname.includes(keyword)) } if (workType) { filtered = filtered.filter(p => p.workType === workType) } if (tagId) { filtered = filtered.filter(p => p.tags.some(t => t.id === tagId)) } if (status) { filtered = filtered.filter(p => p.status === status) } if (location) { filtered = filtered.filter(p => p.location === location || p.location === '不限') } const start = (page - 1) * pageSize const list = filtered.slice(start, start + pageSize) return { list, total: filtered.length, page, pageSize } } // 删除项目 export async function mockDeleteProject(id: number): Promise { await delay(200) mockProjects = mockProjects.filter(p => p.id !== id) } // 批量删除项目 export async function mockBatchDeleteProjects(ids: number[]): Promise { await delay(300) mockProjects = mockProjects.filter(p => !ids.includes(p.id)) } // 获取项目标签列表 export async function mockGetProjectTags(): Promise { await delay(100) return mockProjectTags } // 获取工作地点列表 export async function mockGetLocations(): Promise { await delay(100) return locations } // 设置项目置顶 export async function mockSetProjectPin(id: number, isPinned: boolean, days?: number): Promise { await delay(200) const project = mockProjects.find(p => p.id === id) if (project) { project.isPinned = isPinned project.pinnedUntil = isPinned && days ? new Date(Date.now() + days * 24 * 60 * 60 * 1000).toISOString() : undefined project.updatedAt = new Date().toISOString() return project } return null } // 手动曝光项目 export async function mockExposeProject(id: number): Promise { await delay(200) const project = mockProjects.find(p => p.id === id) if (project) { project.exposureCount += 1 project.lastExposureAt = new Date().toISOString() project.updatedAt = new Date().toISOString() return project } return null }