/** * 运势计算工具类 * 基于用户资料(生日、星座、生肖)计算婚恋运势、脱单指数、幸运推荐 */ import { getZodiacByBirthday, getZodiacInfo } from './zodiac.js' // 星座数据 const CONSTELLATIONS = { '白羊座': { element: '火', startDate: '03-21', endDate: '04-19', luckyColors: ['红色', '橙色'], luckyNumbers: [1, 9], personality: '热情冲动' }, '金牛座': { element: '土', startDate: '04-20', endDate: '05-20', luckyColors: ['绿色', '粉色'], luckyNumbers: [2, 6], personality: '稳重踏实' }, '双子座': { element: '风', startDate: '05-21', endDate: '06-21', luckyColors: ['黄色', '蓝色'], luckyNumbers: [3, 5], personality: '机智多变' }, '巨蟹座': { element: '水', startDate: '06-22', endDate: '07-22', luckyColors: ['白色', '银色'], luckyNumbers: [2, 7], personality: '温柔体贴' }, '狮子座': { element: '火', startDate: '07-23', endDate: '08-22', luckyColors: ['金色', '橙色'], luckyNumbers: [1, 5], personality: '自信大方' }, '处女座': { element: '土', startDate: '08-23', endDate: '09-22', luckyColors: ['灰色', '米色'], luckyNumbers: [4, 8], personality: '细心完美' }, '天秤座': { element: '风', startDate: '09-23', endDate: '10-23', luckyColors: ['粉色', '蓝色'], luckyNumbers: [6, 9], personality: '优雅和谐' }, '天蝎座': { element: '水', startDate: '10-24', endDate: '11-22', luckyColors: ['深红', '黑色'], luckyNumbers: [3, 9], personality: '神秘深情' }, '射手座': { element: '火', startDate: '11-23', endDate: '12-21', luckyColors: ['紫色', '蓝色'], luckyNumbers: [3, 7], personality: '乐观自由' }, '摩羯座': { element: '土', startDate: '12-22', endDate: '01-19', luckyColors: ['黑色', '深蓝'], luckyNumbers: [4, 8], personality: '务实稳重' }, '水瓶座': { element: '风', startDate: '01-20', endDate: '02-18', luckyColors: ['蓝色', '银色'], luckyNumbers: [4, 7], personality: '独立创新' }, '双鱼座': { element: '水', startDate: '02-19', endDate: '03-20', luckyColors: ['海蓝', '紫色'], luckyNumbers: [3, 9], personality: '浪漫敏感' } } // 约会建议库 const DATE_SUGGESTIONS = [ '浪漫晚餐', '咖啡约会', '电影之夜', '公园散步', '逛街购物', '看展览', '户外野餐', '游乐园', '密室逃脱', '烘焙体验', '书店约会', '音乐会', '运动健身', '美食探店', '手工DIY' ] // 穿搭风格库 const STYLE_SUGGESTIONS = [ '清新甜美', '优雅知性', '休闲运动', '简约大方', '时尚潮流', '温柔淑女', '帅气中性', '复古文艺', '可爱减龄', '成熟稳重' ] // 幸运色库 const LUCKY_COLORS = [ '粉红色', '天蓝色', '薄荷绿', '珊瑚橙', '薰衣草紫', '米白色', '浅黄色', '玫瑰红', '湖蓝色', '杏色' ] /** * 根据生日获取星座 * @param {String} birthday - 生日,格式:YYYY-MM-DD * @returns {String} 星座名称 */ export function getConstellationByBirthday(birthday) { if (!birthday) return null const parts = birthday.split('-') const month = parseInt(parts[1]) const day = parseInt(parts[2]) const mmdd = `${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}` for (const [name, info] of Object.entries(CONSTELLATIONS)) { const start = info.startDate const end = info.endDate // 处理跨年的星座(摩羯座) if (start > end) { if (mmdd >= start || mmdd <= end) return name } else { if (mmdd >= start && mmdd <= end) return name } } return '未知' } /** * 获取基于日期的种子值(确保同一天结果一致) * @param {Date} date - 日期 * @param {String} salt - 盐值(用于区分不同计算) * @returns {Number} 种子值 */ function getDaySeed(date, salt = '') { const dateStr = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}-${salt}` let hash = 0 for (let i = 0; i < dateStr.length; i++) { const char = dateStr.charCodeAt(i) hash = ((hash << 5) - hash) + char hash = hash & hash } return Math.abs(hash) } /** * 基于种子的伪随机数生成器 * @param {Number} seed - 种子值 * @param {Number} min - 最小值 * @param {Number} max - 最大值 * @returns {Number} 随机数 */ function seededRandom(seed, min = 0, max = 100) { const x = Math.sin(seed) * 10000 const random = x - Math.floor(x) return Math.floor(random * (max - min + 1)) + min } /** * 计算用户的婚恋运势 * @param {Object} userInfo - 用户信息 { birthDate, star, animal, gender } * @returns {Array} 运势数组 */ export function calculateLoveFortune(userInfo) { const today = new Date() const birthDate = userInfo.birthDate || userInfo.birth_date // 获取星座和生肖 const constellation = userInfo.star || (birthDate ? getConstellationByBirthday(birthDate) : null) const zodiac = userInfo.animal || (birthDate ? getZodiacByBirthday(birthDate) : null) // 基础分数 let baseScore = 70 // 根据星座元素调整基础分 if (constellation && CONSTELLATIONS[constellation]) { const element = CONSTELLATIONS[constellation].element const dayOfWeek = today.getDay() // 不同元素在不同日子有不同运势 if (element === '火' && (dayOfWeek === 2 || dayOfWeek === 4)) baseScore += 5 if (element === '土' && (dayOfWeek === 0 || dayOfWeek === 6)) baseScore += 5 if (element === '风' && (dayOfWeek === 1 || dayOfWeek === 3)) baseScore += 5 if (element === '水' && (dayOfWeek === 5)) baseScore += 5 } // 使用日期种子确保同一天结果一致 const seed1 = getDaySeed(today, `${constellation}-peach`) const seed2 = getDaySeed(today, `${zodiac}-love`) const seed3 = getDaySeed(today, `${constellation}-charm`) // 计算三项运势分数 const peachScore = Math.min(95, Math.max(60, baseScore + seededRandom(seed1, -10, 20))) const loveScore = Math.min(95, Math.max(55, baseScore + seededRandom(seed2, -15, 18))) const charmScore = Math.min(98, Math.max(65, baseScore + seededRandom(seed3, -5, 25))) return [ { label: '桃花运', icon: '🌸', score: peachScore, color: 'linear-gradient(135deg, #FF6B9D 0%, #FFA5C6 100%)' }, { label: '爱情指数', icon: '💕', score: loveScore, color: 'linear-gradient(135deg, #E91E63 0%, #FF6B9D 100%)' }, { label: '魅力值', icon: '✨', score: charmScore, color: 'linear-gradient(135deg, #9C27B0 0%, #BA68C8 100%)' } ] } /** * 计算本周脱单指数 * @param {Object} userInfo - 用户信息 * @returns {Object} 脱单指数数据 */ export function calculateSingleIndex(userInfo) { const today = new Date() const birthDate = userInfo.birthDate || userInfo.birth_date // 获取星座和生肖 const constellation = userInfo.star || (birthDate ? getConstellationByBirthday(birthDate) : null) const zodiac = userInfo.animal || (birthDate ? getZodiacByBirthday(birthDate) : null) // 获取本周的周一作为种子基准 const weekStart = new Date(today) weekStart.setDate(today.getDate() - today.getDay() + 1) const seed = getDaySeed(weekStart, `${constellation}-${zodiac}-single`) // 计算基础分数 let score = seededRandom(seed, 65, 95) // 根据生肖特性微调 if (zodiac) { const zodiacInfo = getZodiacInfo(zodiac) if (zodiacInfo) { // 社交型生肖加分 if (['鼠', '马', '猴', '猪'].includes(zodiac)) score += 3 // 内敛型生肖略减 if (['牛', '蛇', '羊'].includes(zodiac)) score -= 2 } } score = Math.min(98, Math.max(50, score)) // 确定等级 let level, levelColor if (score >= 90) { level = '极佳' levelColor = 'linear-gradient(135deg, #FF6B6B 0%, #FF8E53 100%)' } else if (score >= 80) { level = '很好' levelColor = 'linear-gradient(135deg, #4CAF50 0%, #8BC34A 100%)' } else if (score >= 70) { level = '良好' levelColor = 'linear-gradient(135deg, #2196F3 0%, #03A9F4 100%)' } else if (score >= 60) { level = '一般' levelColor = 'linear-gradient(135deg, #FF9800 0%, #FFC107 100%)' } else { level = '需努力' levelColor = 'linear-gradient(135deg, #9E9E9E 0%, #BDBDBD 100%)' } // 计算最佳约会日 const bestDaySeed = getDaySeed(weekStart, `${constellation}-bestday`) const bestDayIndex = seededRandom(bestDaySeed, 0, 6) const weekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'] const bestDay = weekDays[bestDayIndex] // 计算最佳时间段 const timeSeed = getDaySeed(weekStart, `${zodiac}-time`) const timeSlots = ['上午10-12点', '下午2-5点', '傍晚5-7点', '晚上7-9点'] const bestTime = timeSlots[seededRandom(timeSeed, 0, 3)] // 推荐地点 const placeSeed = getDaySeed(weekStart, `${constellation}-place`) const places = [ '咖啡厅、书店', '公园、广场', '商场、电影院', '餐厅、美食街', '展览馆、博物馆', '游乐园、景区' ] const bestPlace = places[seededRandom(placeSeed, 0, 5)] return { score, level, levelColor, tips: [ { icon: '📅', text: `最佳约会日:${bestDay}` }, { icon: '⏰', text: `最佳时间:${bestTime}` }, { icon: '📍', text: `推荐地点:${bestPlace}` } ] } } /** * 计算今日幸运推荐 * @param {Object} userInfo - 用户信息 * @returns {Array} 幸运推荐数组 */ export function calculateLuckyRecommend(userInfo) { const today = new Date() const birthDate = userInfo.birthDate || userInfo.birth_date // 获取星座 const constellation = userInfo.star || (birthDate ? getConstellationByBirthday(birthDate) : null) const zodiac = userInfo.animal || (birthDate ? getZodiacByBirthday(birthDate) : null) // 幸运色 let luckyColor = '粉红色' if (constellation && CONSTELLATIONS[constellation]) { const constellationColors = CONSTELLATIONS[constellation].luckyColors const colorSeed = getDaySeed(today, `${constellation}-color`) luckyColor = constellationColors[seededRandom(colorSeed, 0, constellationColors.length - 1)] } else { const colorSeed = getDaySeed(today, 'default-color') luckyColor = LUCKY_COLORS[seededRandom(colorSeed, 0, LUCKY_COLORS.length - 1)] } // 幸运数字 let luckyNumber = '7' if (constellation && CONSTELLATIONS[constellation]) { const constellationNumbers = CONSTELLATIONS[constellation].luckyNumbers const numberSeed = getDaySeed(today, `${constellation}-number`) luckyNumber = constellationNumbers[seededRandom(numberSeed, 0, constellationNumbers.length - 1)].toString() } else { const numberSeed = getDaySeed(today, 'default-number') luckyNumber = seededRandom(numberSeed, 1, 9).toString() } // 约会建议 const dateSeed = getDaySeed(today, `${zodiac}-date`) const dateSuggestion = DATE_SUGGESTIONS[seededRandom(dateSeed, 0, DATE_SUGGESTIONS.length - 1)] // 穿搭风格 const styleSeed = getDaySeed(today, `${constellation}-style`) const styleSuggestion = STYLE_SUGGESTIONS[seededRandom(styleSeed, 0, STYLE_SUGGESTIONS.length - 1)] return [ { label: '幸运色', icon: '🎨', value: luckyColor, bgColor: 'linear-gradient(135deg, #FFB6C1 0%, #FFE4E1 100%)' }, { label: '幸运数字', icon: '🔢', value: luckyNumber, bgColor: 'linear-gradient(135deg, #9C27B0 0%, #CE93D8 100%)' }, { label: '约会建议', icon: '💡', value: dateSuggestion, bgColor: 'linear-gradient(135deg, #FF9800 0%, #FFB74D 100%)' }, { label: '穿搭风格', icon: '👗', value: styleSuggestion, bgColor: 'linear-gradient(135deg, #4CAF50 0%, #81C784 100%)' } ] } /** * 获取用户完整的运势数据 * @param {Object} userInfo - 用户信息 * @returns {Object} 完整运势数据 */ export function getFullFortuneData(userInfo) { // 检查用户是否有足够的资料 const birthDate = userInfo.birthDate || userInfo.birth_date const hasProfile = birthDate || userInfo.star || userInfo.animal if (!hasProfile) { // 返回默认数据并提示完善资料 return { hasProfile: false, message: '完善个人资料后可查看专属运势', loveFortune: [ { label: '桃花运', icon: '🌸', score: 75, color: 'linear-gradient(135deg, #FF6B9D 0%, #FFA5C6 100%)' }, { label: '爱情指数', icon: '💕', score: 70, color: 'linear-gradient(135deg, #E91E63 0%, #FF6B9D 100%)' }, { label: '魅力值', icon: '✨', score: 80, color: 'linear-gradient(135deg, #9C27B0 0%, #BA68C8 100%)' } ], singleIndex: { score: 75, level: '良好', levelColor: 'linear-gradient(135deg, #2196F3 0%, #03A9F4 100%)', tips: [ { icon: '📅', text: '最佳约会日:周六' }, { icon: '⏰', text: '最佳时间:下午2-5点' }, { icon: '📍', text: '推荐地点:咖啡厅、公园' } ] }, luckyRecommend: [ { label: '幸运色', icon: '🎨', value: '粉红色', bgColor: 'linear-gradient(135deg, #FFB6C1 0%, #FFE4E1 100%)' }, { label: '幸运数字', icon: '🔢', value: '7', bgColor: 'linear-gradient(135deg, #9C27B0 0%, #CE93D8 100%)' }, { label: '约会建议', icon: '💡', value: '浪漫晚餐', bgColor: 'linear-gradient(135deg, #FF9800 0%, #FFB74D 100%)' }, { label: '穿搭风格', icon: '👗', value: '清新甜美', bgColor: 'linear-gradient(135deg, #4CAF50 0%, #81C784 100%)' } ] } } return { hasProfile: true, constellation: userInfo.star || (birthDate ? getConstellationByBirthday(birthDate) : null), zodiac: userInfo.animal || (birthDate ? getZodiacByBirthday(birthDate) : null), loveFortune: calculateLoveFortune(userInfo), singleIndex: calculateSingleIndex(userInfo), luckyRecommend: calculateLuckyRecommend(userInfo) } } export default { getConstellationByBirthday, calculateLoveFortune, calculateSingleIndex, calculateLuckyRecommend, getFullFortuneData, CONSTELLATIONS }