diff --git a/README.md b/README.md index e215bc4..b89fc2c 100644 Binary files a/README.md and b/README.md differ diff --git a/app/page.tsx b/app/page.tsx index 9007252..2bf058e 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,101 +1,9 @@ -import Image from "next/image"; +import Calculator from '@/components/calculator'; export default function Home() { return ( -
-
- Next.js logo -
    -
  1. - Get started by editing{" "} - - app/page.tsx - - . -
  2. -
  3. Save and see your changes instantly.
  4. -
- -
- - Vercel logomark - Deploy now - - - Read our docs - -
-
- -
+
+ +
); -} +} \ No newline at end of file diff --git a/components/calculator.tsx b/components/calculator.tsx new file mode 100644 index 0000000..ce69634 --- /dev/null +++ b/components/calculator.tsx @@ -0,0 +1,268 @@ +"use client"; + +import React, { useState, useCallback } from 'react'; +import { Wallet, Clock, Calendar } from 'lucide-react'; + +const SalaryCalculator = () => { + const [formData, setFormData] = useState({ + annualSalary: '', // 年薪 + workDaysPerWeek: 5, // 每周工作天数 + annualLeave: 5, // 年假天数 + publicHolidays: 11, // 法定节假日 + workHours: 8, // 工作时长 + commuteHours: 1, // 通勤时长 + breakHours: 1, // 预备时长 + workEnvironment: '1.0', // 工作环境系数 + heterogeneity: '1.0', // 异性环境系数 + teamwork: '1.0', // 同事环境系数 + education: '1.0' // 学历系数 + }); + + const calculateWorkingDays = useCallback(() => { + const weeksPerYear = 52; + const totalWorkDays = weeksPerYear * formData.workDaysPerWeek; + const totalLeaves = Number(formData.annualLeave) + Number(formData.publicHolidays); + return totalWorkDays - totalLeaves; + }, [formData.workDaysPerWeek, formData.annualLeave, formData.publicHolidays]); + + const calculateDailySalary = useCallback(() => { + if (!formData.annualSalary) return 0; + const workingDays = calculateWorkingDays(); + return Number(formData.annualSalary) / workingDays; + }, [formData.annualSalary, calculateWorkingDays]); + + const handleInputChange = (name: string, value: string) => { + setFormData(prev => ({ + ...prev, + [name]: value + })); + }; + + const calculateValue = () => { + if (!formData.annualSalary) return 0; + + const dailySalary = calculateDailySalary(); + const workHours = Number(formData.workHours); + const commuteHours = Number(formData.commuteHours); + const breakHours = Number(formData.breakHours); + + const environmentFactor = Number(formData.workEnvironment) * + Number(formData.heterogeneity) * + Number(formData.teamwork); + + return (dailySalary * environmentFactor) / + (35 * (workHours + commuteHours - 0.5 * breakHours) * Number(formData.education)); + }; + + const value = calculateValue(); + + const getValueAssessment = () => { + if (!formData.annualSalary) return { text: "请输入年薪", color: "text-gray-500" }; + if (value < 0.8) return { text: "很惨", color: "text-red-500" }; + if (value <= 1.5) return { text: "一般", color: "text-yellow-500" }; + if (value <= 2.0) return { text: "很爽", color: "text-green-500" }; + return { text: "爽到爆炸", color: "text-purple-500" }; + }; + + const RadioGroup = ({ label, name, value, onChange, options }: { + label: string; + name: string; + value: string; + onChange: (name: string, value: string) => void; + options: Array<{ label: string; value: string; }>; + }) => ( +
+ +
+ {options.map((option) => ( + + ))} +
+
+ ); + + return ( +
+
+

+ 这b班上得值不值·测算版 +

+
+ 拿走工资前,请先算算这班值不值得上 +
+
+ +
+
+ {/* 薪资与工作时间 */} +
+
+ +
+ + handleInputChange('annualSalary', e.target.value)} + placeholder="税前年薪" + className="block w-full rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + /> +
+
+ +
+
+ + handleInputChange('workDaysPerWeek', e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + /> +
+
+ + handleInputChange('annualLeave', e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + /> +
+
+ + handleInputChange('publicHolidays', e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + /> +
+
+ + handleInputChange('workHours', e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + /> +
+
+ +
+
+ + handleInputChange('commuteHours', e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + /> +
+
+ + handleInputChange('breakHours', e.target.value)} + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + /> +
+
+
+ +
+ + {/* 环境系数 */} +
+ + + + + + + +
+
+
+ +
+
+
+
年工作天数
+
{calculateWorkingDays()}天
+
+
+
平均日薪
+
¥{calculateDailySalary().toFixed(2)}
+
+
+
工作性价比
+
+ {value.toFixed(2)} ({getValueAssessment().text}) +
+
+
+
+
+ ); +}; + +export default SalaryCalculator; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3e601d9..1f7871a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "worth-calculator", "version": "0.1.0", "dependencies": { + "lucide-react": "^0.454.0", "next": "15.0.2", "react": "19.0.0-rc-02c0e824-20241028", "react-dom": "19.0.0-rc-02c0e824-20241028" @@ -3733,6 +3734,15 @@ "dev": true, "license": "ISC" }, + "node_modules/lucide-react": { + "version": "0.454.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.454.0.tgz", + "integrity": "sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", diff --git a/package.json b/package.json index 659c52b..48401ac 100644 --- a/package.json +++ b/package.json @@ -9,18 +9,19 @@ "lint": "next lint" }, "dependencies": { + "lucide-react": "^0.454.0", + "next": "15.0.2", "react": "19.0.0-rc-02c0e824-20241028", - "react-dom": "19.0.0-rc-02c0e824-20241028", - "next": "15.0.2" + "react-dom": "19.0.0-rc-02c0e824-20241028" }, "devDependencies": { - "typescript": "^5", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "eslint": "^8", + "eslint-config-next": "15.0.2", "postcss": "^8", "tailwindcss": "^3.4.1", - "eslint": "^8", - "eslint-config-next": "15.0.2" + "typescript": "^5" } }