不讲废话,先给效果图

在这里插入图片描述
进入的页面看到的很清爽,没有多余的内容,用户需要做的就是选择自己的省份,填写个人月缴费额就可以了,平均缴费指数用户可以自己调整。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

下面给出完整的代码

页面结构(WXML)

<template>
  <view class="welfare-calc-page">
    <!-- 顶部导航 -->
    <view class="nav-bar">

    </view>

    <!-- 功能模块切换 -->
    <view class="module-tabs">
      <view class="tab-item" :class="{ active: activeTab === 1 }" @click="switchTab(1)">
        养老金估算
      </view>
      <view class="tab-item" :class="{ active: activeTab === 0 }" @click="switchTab(0)">
        个税计算
      </view>
      <view class="tab-item" :class="{ active: activeTab === 2 }" @click="switchTab(2)">
        劳动赔偿
      </view>
    </view>

    <!-- 个税计算模块 -->
    <view class="calc-form" v-show="activeTab === 0">
      <view class="form-row">
        <text class="form-label">计算模式</text>
        <view class="mode-selector">
          <text class="mode-btn" :class="{ active: taxMode === 'month' }" @click="taxMode = 'month'">月薪</text>
          <text class="mode-btn" :class="{ active: taxMode === 'year' }" @click="taxMode = 'year'">年薪</text>
        </view>
      </view>
      <view class="form-row">
        <text class="form-label">{{ taxMode === 'month' ? '税前月薪' : '税前年薪' }}</text>
        <input class="form-input" type="digit" v-model.number="taxForm.salary" placeholder="请输入金额" />
      </view>
      <view class="form-row">
        <text class="form-label">五险一金(元/月)</text>
        <input class="form-input" type="digit" v-model.number="taxForm.insurance" placeholder="如:1000" />
      </view>
      <view class="form-row">
        <text class="form-label">专项附加扣除(元/月)</text>
        <input class="form-input" type="digit" v-model.number="taxForm.deduction" placeholder="如:2000" />
      </view>
    </view>

    <!-- 省份选择弹窗 -->
    <view class="modal-overlay" v-if="showProvincePicker" @click="showProvincePicker = false">
      <view class="modal-content province-modal" @click.stop>
        <view class="modal-title">选择参保省份</view>
        <scroll-view class="province-scroll" scroll-y="true">
          <view class="province-grid">
            <view 
              class="province-item" 
              v-for="(item, index) in provinceList" 
              :key="index"
              :class="{ selected: selectedProvince.key === item.key }"
              @click="selectProvince(item)"
            >
              {{ item.name }}
            </view>
          </view>
        </scroll-view>
      </view>
    </view>

    <!-- 养老金估算模块 -->
    <view class="calc-form" v-show="activeTab === 1">
      <view class="form-row" @click="showProvincePicker = true">
        <text class="form-label">参保省份</text>
        <text class="form-value" >{{ selectedProvince.name }}</text>
      </view>
      <view class="form-row">
        <text class="form-label">退休时全省上年度月平均工资</text>
        <input class="form-input" type="digit" v-model.number="pensionForm.socialWage" placeholder="如:20" />
      </view>
      <view class="form-row">
        <text class="form-label">本人平均缴费指数</text>
        <input  class="form-input"  type="text"  v-model="pensionForm.payIndex"  @input="handlePayIndexInput" @blur="validatePayIndexRange"
          placeholder="默认1.0"  />
      </view>
      <view class="form-row">
        <text class="form-label">缴费年限</text>
        <input  class="form-input"  type="text"  v-model="pensionForm.payYears"  @input="handlePayYearsInput" @blur="validatePayYearsRange" placeholder="如:20" />
      </view>
      <view class="form-row">
        <text class="form-label">个人月缴养老金(8%部分)</text>
        <input  class="form-input"   type="text"  v-model="pensionForm.personalMonthly"  @input="handlePersonalMonthlyInput" @blur="validatePersonalMonthlyRange" placeholder="如:200" />
      </view>
      <view class="form-row" @click="showMonthPicker = true">
        <text class="form-label">计发月数</text>
        <text class="form-value">{{ pensionForm.months }}</text>
      </view>
    </view>

    <!-- 劳动赔偿模块 -->
    <view class="calc-form" v-show="activeTab === 2">
      <view class="form-row">
        <text class="form-label">近12月平均工资</text>
        <input class="form-input" type="digit" v-model.number="compForm.wage" placeholder="如:8000" />
      </view>
      <view class="form-row">
        <text class="form-label">工作年限</text>
        <input class="form-input" type="digit" v-model.number="compForm.years" placeholder="如:3" />
      </view>
      <view class="form-row">
        <text class="form-label">赔偿类型</text>
        <picker mode="selector" :range="compTypeList" @change="handleCompTypeChange">
          <view class="form-value">{{ compTypeList[compTypeIndex] }}</view>
        </picker>
      </view>
    </view>

    <!-- 统一计算按钮 -->
    <button class="calc-btn" @click="handleCalculate" :loading="calculating">
      计算结果
    </button>

    <!-- 计发月数选择弹窗(仅50~63岁,点击直接选中) -->
    <view class="modal-overlay" v-if="showMonthPicker" @click="showMonthPicker = false">
      <view class="modal-content" @click.stop>
        <view class="modal-title">计发月数</view>
        <!-- 新增:身份说明行 -->
        <view class="identity-tip">
          <text>退休年龄说明:</text>
        </view>
        <view class="identity-tip">
          <text class="tip-highlight">50~55岁为女工人</text>
          <text class="tip-highlight">55~58岁为女干部</text>
          <text class="tip-highlight">60~63岁为男同志</text>
        </view>
        <view class="month-table">
          <view class="table-header">
            <text class="col">退休年龄</text>
            <text class="col">计发月数</text>
            <text class="col">退休年龄</text>
            <text class="col">计发月数</text>
          </view>
          <!-- 左列:50~56岁,右列:57~63岁 -->
          <view class="table-row" v-for="(item, index) in monthList.slice(0, 7)" :key="index">
            <text class="col clickable" @click="selectMonthDirect(item.age)"
              :class="{ selected: selectedMonthAge === item.age }">
              {{ item.age }}
            </text>
            <text class="col clickable" @click="selectMonthDirect(item.age)"
              :class="{ selected: selectedMonthAge === item.age }">
              {{ item.months }}
            </text>
            <text class="col clickable" @click="selectMonthDirect(monthList[index + 7]?.age)"
              :class="{ selected: selectedMonthAge === monthList[index + 7]?.age }" v-if="monthList[index + 7]">
              {{ monthList[index + 7]?.age }}
            </text>
            <text class="col clickable" @click="selectMonthDirect(monthList[index + 7]?.age)"
              :class="{ selected: selectedMonthAge === monthList[index + 7]?.age }" v-if="monthList[index + 7]">
              {{ monthList[index + 7]?.months }}
            </text>
          </view>
        </view>
      </view>
    </view>

  </view>
</template>

样式设计(WXSS)

<style scoped>
.welfare-calc-page {
  min-height: 100vh;
  background-color: #f0f4fc;
  padding: 20rpx;
}

/* 顶部导航 */
.nav-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20rpx 0;
  margin-bottom: 30rpx;
}

.back-btn {
  font-size: 40rpx;
  color: #0052d9;
}

.page-title {
  font-size: 36rpx;
  font-weight: 500;
  color: #000;
}

.nav-placeholder {
  width: 60rpx;
}

/* 模块切换 */
.module-tabs {
  display: flex;
  border-radius: 16rpx;
  background-color: #e8edf7;
  margin-bottom: 30rpx;
}

.tab-item {
  flex: 1;
  padding: 24rpx 0;
  text-align: center;
  font-size: 32rpx;
  color: #666;
  border-radius: 16rpx;
}

.tab-item.active {
  background-color: #0052d9;
  color: #fff;
}

/* 表单区域 */
.calc-form {
  background-color: #fff;
  border-radius: 20rpx;
  padding: 30rpx;
  margin-bottom: 40rpx;
}

.form-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 24rpx 0;
  border-bottom: 1rpx solid #f0f4fc;
}

.form-row:last-child {
  border-bottom: none;
}

.form-label {
  font-size: 30rpx;
  color: #333;
}

.form-value {
  font-size: 30rpx;
  color: #666;
  text-align: right;
  flex: 1;
}

/* 可点击的 picker 行 */
.picker-row {
  position: relative;
  cursor: pointer;
}

/* 添加 hover 类用于点击反馈 */
.picker-row-hover {
  background-color: #f5f5f5;
}

.form-input {
  border: none;
  outline: none;
  background: transparent;
  text-align: right;
  font-size: 30rpx;
  color: #666;
  width: 35%;
}

/* 省份选择弹窗 */
.province-modal {
  max-height: 80vh;
  padding: 0;
  overflow: hidden;
}

.province-scroll {
  max-height: 60vh;
}

.province-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20rpx;
  padding: 30rpx;
}

.province-item {
  padding: 20rpx 10rpx;
  text-align: center;
  font-size: 28rpx;
  color: #333;
  border: 1rpx solid #e0e0e0;
  border-radius: 8rpx;
  background-color: #fff;
}

.province-item.selected {
  background-color: #0052d9;
  color: #fff;
  border-color: #0052d9;
}

/* 确保省份名称可点击 */
.form-value {
  font-size: 30rpx;
  color: #666;
  text-align: right;
  flex: 1;
  cursor: pointer;
}

.modal-confirm {
  margin-top: 0;
  padding: 30rpx;
  text-align: center;
  font-size: 32rpx;
  color: #0052d9;
  border-top: 1rpx solid #eee;
}

.mode-selector {
  display: flex;
  gap: 20rpx;
}

.mode-btn {
  padding: 12rpx 24rpx;
  border-radius: 12rpx;
  font-size: 28rpx;
  color: #666;
  background-color: #e8edf7;
}

.mode-btn.active {
  background-color: #0052d9;
  color: #fff;
}

/* 计算按钮 */
.calc-btn {
  width: 100%;
  height: 96rpx;
  line-height: 96rpx;
  background-color: #0052d9;
  color: #fff;
  border-radius: 20rpx;
  font-size: 34rpx;
  border: none;
  margin-bottom: 40rpx;
}

.calc-btn[loading] {
  background-color: #6699e6;
}

/* 计发月数弹窗 */
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
}

.modal-content {
  width: 90%;
  background-color: #fff;
  border-radius: 20rpx;
  padding: 40rpx;
}

.modal-title {
  font-size: 34rpx;
  font-weight: 500;
  color: #333;
  text-align: center;
  margin-bottom: 30rpx;
}

.month-table {
  font-size: 28rpx;
  color: #333;
}

.table-header {
  display: flex;
  justify-content: space-between;
  padding: 16rpx 0;
  border-bottom: 1rpx solid #eee;
  font-weight: 500;
}

.table-row {
  display: flex;
  justify-content: space-between;
  padding: 16rpx 0;
  border-bottom: 1rpx solid #f5f5f5;
}

.modal-confirm {
  margin-top: 40rpx;
  text-align: center;
  font-size: 32rpx;
  color: #0052d9;
}

/* 计发月数弹窗样式 */
.month-table {
  font-size: 28rpx;
  color: #333;
}

.table-header {
  display: flex;
  padding: 16rpx 0;
  border-bottom: 1rpx solid #eee;
  font-weight: 500;
}

.table-row {
  display: flex;
  padding: 16rpx 0;
  border-bottom: 1rpx solid #f5f5f5;
  cursor: pointer;
}

.table-row:active {
  background-color: #f0f4fc;
}

.table-row.selected {
  background-color: #e8edf7;
  color: #0052d9;
}

.col {
  flex: 1;
  text-align: center;
}

/* 身份说明样式 */
.identity-tip {
  font-size: 26rpx;
  color: #666;
  margin-bottom: 20rpx;
  line-height: 1.6;
  text-align: center;
}

.tip-highlight {
  color: #0052d9;
  font-weight: 500;
  margin: 0 8rpx;
}

/* 保留原有样式 */
.clickable {
  cursor: pointer;
  padding: 8rpx 16rpx;
  border-radius: 8rpx;
}

.clickable:active {
  background-color: #f0f4fc;
}

.clickable.selected {
  color: #0052d9;
  font-weight: 500;
}

.table-row {
  display: flex;
  padding: 16rpx 0;
  border-bottom: 1rpx solid #f5f5f5;
}

/* 结果区域 */
.result-box {
  background-color: #fff;
  border-radius: 20rpx;
  padding: 30rpx;
}

.result-title {
  font-size: 32rpx;
  font-weight: 500;
  color: #333;
  margin-bottom: 30rpx;
  text-align: center;
}

.result-item {
  display: flex;
  justify-content: space-between;
  padding: 16rpx 0;
  font-size: 30rpx;
}

.result-total {
  display: flex;
  justify-content: space-between;
  padding: 24rpx 0;
  margin-top: 20rpx;
  border-top: 2rpx solid #0052d9;
  font-size: 32rpx;
  font-weight: 500;
}

.label {
  color: #666;
}

.value {
  color: #0052d9;
  font-weight: 500;
}

.result-note {
  margin-top: 30rpx;
  font-size: 26rpx;
  color: #999;
  line-height: 1.6;
}
</style>

逻辑处理(JS)

JavaScript部分处理用户输入和计算逻辑:

<script>
import { calculateTax, calculatePension, calculateCompensation, socialWage2025, provinceList as calcProvinceList } from '@/utils/calculator.js';

export default {
  data() {
    return {
      activeTab: 1,
      calculating: false,
      showMonthPicker: false,
      selectedMonthAge: 60,
      // 个税表单
      taxMode: 'month',
      taxForm: {
        salary: 8000,
        insurance: 1000,
        deduction: 2000
      },
      taxResult: {
        show: false,
        taxable: 0,
        tax: 0,
        realIncome: 0
      },
      // 养老金表单
      pensionForm: {
        socialWage: 7999,
        payIndex: 1.0,
        payYears: 20,
        personalMonthly: 0,
        months: 139
      },
      pensionResult: {
        show: false,
        basePension: 0,
        personalPension: 0,
        totalPension: 0
      },
      // 劳动赔偿表单
      compForm: {
        wage: 8000,
        years: 3
      },
      compTypeList: ['N+1(协商解除)', '2N(违法辞退)', 'N(到期不续签)'],
      compTypeIndex: 0,
      compResult: {
        show: false,
        amount: 0
      },
      // 省份数据
      provinceList: calcProvinceList,
      selectedProvince: calcProvinceList.find(item => item.key === '安徽') || calcProvinceList[0],
      showProvincePicker: false,
      provinceIndex: 0,
      // 计发月数表
      monthList: [
        { age: 50, months: 195 }, { age: 51, months: 190 }, { age: 52, months: 185 },
        { age: 53, months: 180 }, { age: 54, months: 175 }, { age: 55, months: 170 },
        { age: 56, months: 164 }, { age: 57, months: 158 }, { age: 58, months: 152 },
        { age: 59, months: 145 }, { age: 60, months: 139 }, { age: 61, months: 132 },
        { age: 62, months: 125 }, { age: 63, months: 117 }
      ]
    };
  },
  computed: {
    result() {
      if (this.activeTab === 0) return this.taxResult;
      if (this.activeTab === 1) return this.pensionResult;
      if (this.activeTab === 2) return this.compResult;
      return { show: false };
    }
  },
  watch: {
    activeTab(newVal) {
      // 切换模块时隐藏结果
      if (newVal === 0) this.taxResult.show = false;
      if (newVal === 1) this.pensionResult.show = false;
      if (newVal === 2) this.compResult.show = false;
    }
  },
  onLoad() {
    // 初始化省份社平工资
    this.pensionForm.socialWage = socialWage2025[this.selectedProvince.key] || 7999;
  },
  // 新增:分享给朋友
  onShareAppMessage(res) {
    if (res.from === 'button') {
      // 来自页面内分享按钮
      console.log(res.target);
    }

    // 根据当前选中的计算类型定制分享内容
    const shareData = {
      title: '',
      path: '/pages/calculate/calculate',
      desc: '',
      success: function (res) {
        console.log('分享成功');
      },
      fail: function (res) {
        console.log('分享失败');
      }
    };

    // 根据 activeTab 设置不同的分享标题和描述
    if (this.activeTab === 0) {
      shareData.title = '💰 个税计算器 - 快速计算个人所得税';
      shareData.desc = `税前${this.taxMode === 'month' ? '月薪' : '年薪'}${this.taxForm.salary}元,一键算出到手收入`;
    } else if (this.activeTab === 1) {
      shareData.title = '📊 养老金估算 - 精准测算退休收入';
      shareData.desc = `${this.selectedProvince.name} | 缴费${this.pensionForm.payYears}年 | 预估每月养老金`;
    } else if (this.activeTab === 2) {
      shareData.title = '⚖️ 劳动赔偿计算器 - 合法维护权益';
      shareData.desc = `工作年限${this.compForm.years}年 | ${this.compTypeList[this.compTypeIndex]} 赔偿估算`;
    }

    return shareData;
  },

  // 新增:分享到朋友圈(微信小程序)
  onShareTimeline() {
    // 根据当前选中的计算类型定制分享内容
    let title = '福利计算器 - 个税/养老金/劳动赔偿';

    if (this.activeTab === 0) {
      title = '💰 个税计算器 - 快速计算个人所得税';
    } else if (this.activeTab === 1) {
      title = '📊 养老金估算 - 精准测算退休收入';
    } else if (this.activeTab === 2) {
      title = '⚖️ 劳动赔偿计算器 - 合法维护权益';
    }

    return {
      title: title,
      query: '',
      success: function (res) {
        console.log('分享到朋友圈成功');
      },
      fail: function (res) {
        console.log('分享到朋友圈失败');
      }
    };
  },
  methods: {
    navBack() {
      uni.navigateBack();
    },
    switchTab(index) {
      this.activeTab = index;
    },
    handleProvinceChange(e) {
      const index = e.detail.value;
      const selected = this.provinceList[index];
      this.selectedProvince = selected;
      this.pensionForm.socialWage = socialWage2025[selected.key] || 7999;
    },
    handlePayIndexInput(e) {
      let value = e.detail.value;
      
      // 只保留数字和一个小数点
      value = value.replace(/[^\d.]/g, '');
      
      // 确保只有一个小数点
      const firstDot = value.indexOf('.');
      if (firstDot !== -1) {
        const beforeDot = value.slice(0, firstDot);
        const afterDot = value.slice(firstDot + 1).replace(/\./g, '');
        value = beforeDot + '.' + afterDot;
      }
      
      // 限制最多 2 位小数
      const parts = value.split('.');
      if (parts[1] && parts[1].length > 2) {
        value = parts[0] + '.' + parts[1].slice(0, 2);
      }
      
      // 更新值,不立即校验范围
      this.pensionForm.payIndex = value;
    },

    validatePayIndexRange() {
      let value = this.pensionForm.payIndex;
      
      if (value !== '' && value !== '.') {
        const numValue = parseFloat(value);
        
        if (!isNaN(numValue)) {
          if (numValue < 0.2) {
            this.pensionForm.payIndex = '0.2';
          } else if (numValue > 4) {
            this.pensionForm.payIndex = '4';
          }
        }
      }
    },
    handlePayYearsInput(e) {
      let value = e.detail.value;
      
      // 只保留数字和一个小数点
      value = value.replace(/[^\d.]/g, '');
      
      // 确保只有一个小数点
      const firstDot = value.indexOf('.');
      if (firstDot !== -1) {
        const beforeDot = value.slice(0, firstDot);
        const afterDot = value.slice(firstDot + 1).replace(/\./g, '');
        value = beforeDot + '.' + afterDot;
      }
      
      // 限制最多 1 位小数
      const parts = value.split('.');
      if (parts[1] && parts[1].length > 1) {
        value = parts[0] + '.' + parts[1].slice(0, 1);
      }
      
      // 更新值,不立即校验范围
      this.pensionForm.payYears = value;
    },

    validatePayYearsRange() {
      let value = this.pensionForm.payYears;
      
      if (value !== '' && value !== '.') {
        const numValue = parseFloat(value);
        
        if (!isNaN(numValue)) {
          if (numValue < 15) {
            this.pensionForm.payYears = '15';
          } else if (numValue > 60) {
            this.pensionForm.payYears = '60';
          }
        }
      }
    },
    handlePersonalMonthlyInput(e) {
      let value = e.detail.value;
      
      // 只保留数字(不允许小数)
      value = value.replace(/[^\d]/g, '');
      
      // 更新值,不立即校验范围
      this.pensionForm.personalMonthly = value;
    },

    validatePersonalMonthlyRange() {
      let value = this.pensionForm.personalMonthly;
      
      if (value !== '') {
        const numValue = parseInt(value);
        
        if (!isNaN(numValue)) {
          if (numValue < 100) {
            this.pensionForm.personalMonthly = '100';
          } else if (numValue > 5000) {
            this.pensionForm.personalMonthly = '5000';
          }
        }
      }
    },
    selectMonth() {
      const item = this.monthList.find(i => i.age === this.selectedMonthAge);
      this.pensionForm.months = item.months;
      this.showMonthPicker = false;
    },
    // 直接点击选中计发月数
    selectMonthDirect(age) {
      const item = this.monthList.find(i => i.age === age);
      if (item) {
        this.pensionForm.months = item.months;
        this.selectedMonthAge = age;
        this.showMonthPicker = false;
      }
    },
    handleCompTypeChange(e) {
      this.compTypeIndex = e.detail.value;
    },
    selectProvince(province) {
      this.selectedProvince = province;
      this.pensionForm.socialWage = socialWage2025[province.key] || 7999;
      this.showProvincePicker = false;
    },
    handleCalculate() {
      this.calculating = true;
      let result;
      if (this.activeTab === 0) {
        // 个税计算
        const params = {
          salary: this.taxMode === 'month' ? this.taxForm.salary : this.taxForm.salary * 12,
          insurance: this.taxForm.insurance,
          deduction: this.taxForm.deduction,
          mode: this.taxMode
        };
        result = calculateTax(params);
        setTimeout(() => {
          this.calculating = false;
          if (result.code === 0) {
            // 跳转到结果页面
            uni.navigateTo({
              url: `/pages/calculate/result?type=0&result=${JSON.stringify(result)}`
            });
          } else {
            uni.showToast({ title: result.msg, icon: 'none' });
          }
        }, 500);
      } else if (this.activeTab === 1) {
        // 养老金计算
        const params = {
          socialWage: this.pensionForm.socialWage,
          payIndex: parseFloat(this.pensionForm.payIndex),
          payYears: parseFloat(this.pensionForm.payYears),
          personalMonthly: parseFloat(this.pensionForm.personalMonthly),
          retireAge: this.getMonthByMonths(this.pensionForm.months) // 根据计发月数反推退休年龄
        };
        result = calculatePension(params);
        setTimeout(() => {
          this.calculating = false;
          if (result.code === 0) {
            // 跳转到结果页面
            uni.navigateTo({
              url: `/pages/calculate/result?type=1&result=${JSON.stringify(result)}`
            });
          } else {
            uni.showToast({ title: result.msg, icon: 'none' });
          }
        }, 500);
      } else if (this.activeTab === 2) {
        // 劳动赔偿计算
        result = calculateCompensation(this.compForm.wage, this.compForm.years, this.compTypeIndex);
        setTimeout(() => {
          this.calculating = false;
          if (result.code === 0) {
            // 跳转到结果页面
            uni.navigateTo({
              url: `/pages/calculate/result?type=2&result=${JSON.stringify(result)}`
            });
          } else {
            uni.showToast({ title: result.msg, icon: 'none' });
          }
        }, 500);
      }
    },
    // 添加辅助方法
    getMonthByMonths(months) {
      const monthMap = {
        195: 50, 190: 51, 185: 52, 180: 53, 175: 54,
        170: 55, 164: 56, 158: 57, 152: 58, 145: 59,
        139: 60, 132: 61, 125: 62, 117: 63
      };
      return monthMap[months] || 60;
    }

  }
};
</script>

优化逻辑

各种基础数据以及函数做成js:

// 个税计算
export const calculateTax = (params) => {
  try {
    const { salary = 0, insurance = 0, deduction = 0, mode = 'month' } = params;
    // 校验核心参数
    if (salary < 0 || insurance < 0 || deduction < 0) {
      return { code: -1, msg: '金额不能为负数' };
    }
    const monthlySalary = mode === 'month' ? salary : salary / 12;
    const taxable = Math.max(0, monthlySalary - 5000 - insurance - deduction);
    const annualTaxable = taxable * 12;

    let annualTax = 0;
    if (annualTaxable <= 36000) {
      annualTax = annualTaxable * 0.03;
    } else if (annualTaxable <= 144000) {
      annualTax = annualTaxable * 0.1 - 2520;
    } else if (annualTaxable <= 300000) {
      annualTax = annualTaxable * 0.2 - 16920;
    } else if (annualTaxable <= 420000) {
      annualTax = annualTaxable * 0.25 - 31920;
    } else if (annualTaxable <= 660000) {
      annualTax = annualTaxable * 0.3 - 52920;
    } else if (annualTaxable <= 960000) {
      annualTax = annualTaxable * 0.35 - 85920;
    } else {
      annualTax = annualTaxable * 0.45 - 181920;
    }

    const tax = Number((annualTax / 12).toFixed(2));
    const realIncome = Number((monthlySalary - insurance - tax).toFixed(2));

    return {
      code: 0,
      taxable: Number(taxable.toFixed(2)),
      tax,
      realIncome
    };
  } catch (e) {
    console.error('个税计算异常:', e);
    return { code: -1, msg: '个税计算出错,请检查输入' };
  }
};

// 养老金计算(官方公式,精准匹配整岁计发月数)
export const calculatePension = (params) => {
  try {
    const {
      personalMonthly = 0,
      payYears = 0,
      socialWage = 0,
      payIndex = 1.0,
      retireAge = 60 // 默认60岁
    } = params;

    // 入参校验
    if (personalMonthly <= 0) return { code: -1, msg: '个人月缴养老金需大于0' };
    if (payYears <= 0) return { code: -1, msg: '累计缴费年限需大于0' };
    if (socialWage <= 0) return { code: -1, msg: '社平工资需大于0' };
    if (payIndex <= 0) return { code: -1, msg: '平均缴费指数需大于0' };
    if (retireAge < 50 || retireAge > 63) return { code: -1, msg: '退休年龄需在50~63岁之间' };

    // 核心:精准匹配你提供的整岁计发月数标准值
    const retireMonthMap = {
      50: 195, 51: 190, 52: 185, 53: 180, 54: 175,
      55: 170, 56: 164, 57: 158, 58: 152, 59: 145,
      60: 139, 61: 132, 62: 125, 63: 117
    };
    // 获取当前退休年龄对应的计发月数(确保是整数)
    const months = retireMonthMap[retireAge];

    // 个人账户总额(含利息估算 6%)
    const personalTotal = personalMonthly * 12 * payYears;
    const personalTotalWithInterest = Number((personalTotal * Math.pow(1.06, payYears / 2)).toFixed(2));

    // 个人账户养老金(总额 / 计发月数)
    const personalPension = Number((personalTotalWithInterest / months).toFixed(2));

    // 基础养老金(官方公式:社平工资×(1+缴费指数)/2 × 缴费年限 × 1%)
    const basePension = Number((socialWage * (1 + payIndex) / 2 * payYears * 0.01).toFixed(2));

    // 每月合计养老金
    const totalPension = Number((basePension + personalPension).toFixed(2));

    return {
      code: 0,
      personalTotal: personalTotalWithInterest, // 个人账户总额(含利息)
      basePension, // 基础养老金
      personalPension, // 个人账户养老金
      totalPension // 每月合计养老金
    };
  } catch (e) {
    console.error('养老金计算异常:', e);
    return { code: -1, msg: '养老金测算出错,请检查输入' };
  }
};

// 劳动赔偿
export const calculateCompensation = (wage, years, typeIndex) => {
  try {
    // 入参校验
    if (!wage || wage <= 0) return { code: -1, msg: '平均工资需大于0' };
    if (years === undefined || years < 0) return { code: -1, msg: '工作年限需大于等于0' };
    if (typeIndex === undefined || typeIndex > 2) return { code: -1, msg: '请选择正确的赔偿类型' };

    let n = Math.floor(years);
    const decimal = years - n;
    if (decimal >= 0.5) n += 1;
    let amount = 0;
    // 赔偿类型:0=N+1 1=2N 2=N
    switch (typeIndex) {
      case 0: amount = wage * (n + 1); break;
      case 1: amount = wage * n * 2; break;
      case 2: amount = wage * n; break;
    }
    return { code: 0, amount: Math.round(amount) };
  } catch (e) {
    console.error('赔偿计算异常:', e);
    return { code: -1, msg: '赔偿金计算出错,请检查输入' };
  }
};

// 2025年各省社平工资(完整数据)
export const socialWage2025 = {
  "上海": 12742, "北京": 12518, "西藏": 11980, "广东": 9493,
  "青海": 9056, "天津": 9417, "新疆": 8448, "浙江": 8433,
  "宁夏": 8366, "江苏": 8917, "海南": 8188, "内蒙古": 8179,
  "四川": 8462, "山东": 7831, "湖北": 7720, "重庆": 7580,
  "贵州": 7520, "吉林": 7480, "辽宁": 7420, "云南": 8265,
  "甘肃": 7350, "安徽": 7999, "山西": 7253, "广西": 6983,
  "湖南": 7694, "河北": 7410, "江西": 7054, "河南": 6738,
  "黑龙江": 7570, "福建": 7932
};

// 省份列表(包含key和name,便于picker渲染和关联社平工资)
export const provinceList = [
  { name: '安徽省', key: '安徽' },
  { name: '上海市', key: '上海' },
  { name: '北京市', key: '北京' },
  { name: '西藏', key: '西藏' },
  { name: '广东省', key: '广东' },
  { name: '青海省', key: '青海' },
  { name: '天津市', key: '天津' },
  { name: '新疆', key: '新疆' },
  { name: '浙江省', key: '浙江' },
  { name: '宁夏', key: '宁夏' },
  { name: '江苏省', key: '江苏' },
  { name: '海南省', key: '海南' },
  { name: '内蒙古', key: '内蒙古' },
  { name: '四川省', key: '四川' },
  { name: '山东省', key: '山东' },
  { name: '湖北省', key: '湖北' },
  { name: '重庆市', key: '重庆' },
  { name: '贵州省', key: '贵州' },
  { name: '吉林省', key: '吉林' },
  { name: '辽宁省', key: '辽宁' },
  { name: '云南省', key: '云南' },
  { name: '甘肃省', key: '甘肃' },
  { name: '山西省', key: '山西' },
  { name: '广西', key: '广西' },
  { name: '湖南省', key: '湖南' },
  { name: '河北省', key: '河北' },
  { name: '江西省', key: '江西' },
  { name: '河南省', key: '河南' },
  { name: '黑龙江省', key: '黑龙江' },
  { name: '福建省', key: '福建' },
];

引入更精确的计算公式能提升专业性。典型养老金计算公式:

养老金 = 基础养老金 + 个人账户养老金
基础养老金 = (当地上年度在岗职工月平均工资 + 本人指数化月平均缴费工资) ÷ 2 × 缴费年限 × 1%
个人账户养老金 = 个人账户储存额 ÷ 计发月数
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐