From 8701469522f071a0c7fb799fe5e53da5cfcbc0c4 Mon Sep 17 00:00:00 2001 From: Zylan Date: Mon, 17 Mar 2025 19:37:05 +0800 Subject: [PATCH] add features --- components/calculator.tsx | 186 +++++++++++++++++++++++++++++--------- 1 file changed, 144 insertions(+), 42 deletions(-) diff --git a/components/calculator.tsx b/components/calculator.tsx index b745b40..f70ebe6 100644 --- a/components/calculator.tsx +++ b/components/calculator.tsx @@ -6,32 +6,43 @@ import { Wallet, Github} from 'lucide-react'; // 保留需要的组件 const SalaryCalculator = () => { const [formData, setFormData] = useState({ annualSalary: '', // 年薪 + pppFactor: '4.19', // 购买力平价转换因子,默认为中国大陆 + country: 'china', // 国家/地区,默认为中国 workDaysPerWeek: '5', // 每周工作天数 + wfhDaysPerWeek: '0', // 每周居家办公天数 annualLeave: '5', // 年假天数 - publicHolidays: '11', // 法定节假日 + paidSickLeave: '3', // 带薪病假天数 + publicHolidays: '13', // 法定节假日 workHours: '10', // 工作时长 commuteHours: '2', // 通勤时长 - breakHours: '2', // 午休时长 - fishTime: '0', // 摸鱼时长 + restTime: '2', // 休息时间(午休+摸鱼) workEnvironment: '1.0', // 工作环境系数 - heterogeneity: '1.0', // 异性环境系数 + leadership: '1.0', // 领导/老板系数 teamwork: '1.0', // 同事环境系数 education: '1.6', // 学历系数 - cityFactor: '1.0' // 城市系数,默认为三线城市 + cityFactor: '1.0', // 城市系数,默认为三线城市 + shuttle: '1.0', // 班车系数 + canteen: '1.0' // 食堂系数 }); const calculateWorkingDays = useCallback(() => { const weeksPerYear = 52; const totalWorkDays = weeksPerYear * Number(formData.workDaysPerWeek); // 确保转换为数字 - const totalLeaves = Number(formData.annualLeave) + Number(formData.publicHolidays); + const totalLeaves = Number(formData.annualLeave) + Number(formData.publicHolidays) + Number(formData.paidSickLeave); return Math.max(totalWorkDays - totalLeaves, 0); - }, [formData.workDaysPerWeek, formData.annualLeave, formData.publicHolidays]); + }, [formData.workDaysPerWeek, formData.annualLeave, formData.publicHolidays, formData.paidSickLeave]); const calculateDailySalary = useCallback(() => { if (!formData.annualSalary) return 0; const workingDays = calculateWorkingDays(); - return Number(formData.annualSalary) / workingDays; // 除 0 不管, Infinity(爽到爆炸)! - }, [formData.annualSalary, calculateWorkingDays]); + + // 应用PPP转换因子标准化薪资 + // 中国地区直接使用默认值4.19,其他地区使用用户输入的PPP + const pppFactor = formData.country === 'china' ? 4.19 : (Number(formData.pppFactor) || 4.19); + const standardizedSalary = Number(formData.annualSalary) * (4.19 / pppFactor); + + return standardizedSalary / workingDays; // 除 0 不管, Infinity(爽到爆炸)! + }, [formData.annualSalary, formData.pppFactor, formData.country, calculateWorkingDays]); const handleInputChange = (name: string, value: string) => { // 直接设置值,不进行任何验证 @@ -47,16 +58,26 @@ const SalaryCalculator = () => { const dailySalary = calculateDailySalary(); const workHours = Number(formData.workHours); const commuteHours = Number(formData.commuteHours); - const breakHours = Number(formData.breakHours); - const fishTime = Number(formData.fishTime); + const restTime = Number(formData.restTime); + const workDaysPerWeek = Number(formData.workDaysPerWeek); + const wfhDaysPerWeek = Math.min(Number(formData.wfhDaysPerWeek), workDaysPerWeek); + const officeDaysRatio = (workDaysPerWeek - wfhDaysPerWeek) / workDaysPerWeek; + + // 通勤时间按办公室工作比例计算,并考虑班车因素 + const shuttleFactor = Number(formData.shuttle); + const effectiveCommuteHours = commuteHours * officeDaysRatio * shuttleFactor; + + // 工作环境因素,包含食堂 + const canteenFactor = Number(formData.canteen); const environmentFactor = Number(formData.workEnvironment) * - Number(formData.heterogeneity) * + Number(formData.leadership) * Number(formData.teamwork) * - Number(formData.cityFactor); + Number(formData.cityFactor) * + canteenFactor; return (dailySalary * environmentFactor) / - (35 * (workHours + commuteHours - 0.5 * breakHours - 0.5 * fishTime) * Number(formData.education)); + (35 * (workHours + effectiveCommuteHours - 0.5 * restTime) * Number(formData.education)); }; const value = calculateValue(); @@ -185,11 +206,56 @@ const SalaryCalculator = () => { className="block w-full rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 dark:text-white" /> +
+ handleInputChange('country', e.target.checked ? 'other' : 'china')} + className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" + /> + +
-
+ {formData.country === 'other' && ( +
+ + handleInputChange('pppFactor', e.target.value)} + placeholder="请输入购买力平价转换因子" + className="mt-1 block w-full rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 dark:text-white" + /> +

+ 常见地区:中国大陆:4.19, 日本:102.59, 美国:1.00, 新加坡:0.84 + + 查看更多 + +

+
+ )} + +
- + { />
- + + handleInputChange('wfhDaysPerWeek', e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 dark:text-white" + /> +
+
+ +
+
+ { />
- + { className="mt-1 block w-full rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 dark:text-white" />
+
+ + handleInputChange('paidSickLeave', e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 dark:text-white" + /> +
+
+ +
{ className="mt-1 block w-full rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 dark:text-white" />
-
- -
{ />
- + handleInputChange('breakHours', e.target.value)} - className="mt-1 block w-full rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 dark:text-white" - /> -
-
- -
-
- - handleInputChange('fishTime', e.target.value)} + value={formData.restTime} + onChange={(e) => handleInputChange('restTime', e.target.value)} className="mt-1 block w-full rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 dark:text-white" />
@@ -294,14 +369,15 @@ const SalaryCalculator = () => { /> @@ -317,6 +393,32 @@ const SalaryCalculator = () => { ]} /> + + + +