index.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <template>
  2. <view class="wxyj-container">
  3. <!-- 基础信息 -->
  4. <view class="card">
  5. <view class="form-row">
  6. <text class="label">所在地区</text>
  7. <picker @change="bindPickerChange" :value="index" :range="array">
  8. <view class="picker">{{ array[index] }}</view>
  9. </picker>
  10. </view>
  11. <view class="form-row">
  12. <text class="label">税前月收入</text>
  13. <!-- 使用 v-model 改善输入体验 -->
  14. <input class="number-input" type="number" :value="inputValue" @blur="bindKeyInput" :focus="focus" placeholder="请输入税前月收入" />
  15. </view>
  16. <view class="tips">基数范围:{{ baseMin }} - {{ baseMax }}</view>
  17. <view class="actions">
  18. <button class="btn primary" size="mini" :plain="false" @tap="startCount">开始计算</button>
  19. <button class="btn" size="mini" :plain="false" @tap="resetData">重新计算</button>
  20. </view>
  21. </view>
  22. <!-- 明细表 -->
  23. <view class="card">
  24. <view class="table header">
  25. <text class="col name">缴费项目</text>
  26. <text class="col rate">个人比例(%)</text>
  27. <text class="col rate">单位比例(%)</text>
  28. <text class="col amt">个人金额</text>
  29. <text class="col amt">单位金额</text>
  30. </view>
  31. <view v-for="(item, idx) in insurance" :key="idx" class="table row">
  32. <text class="col name">{{ item.category }}</text>
  33. <input class="col rate rate-input" type="number" :value="item.private_percentage" @input="onRateChange(idx, 'private_percentage', $event)" />
  34. <input class="col rate rate-input" type="number" :value="item.company_percentage" @input="onRateChange(idx, 'company_percentage', $event)" />
  35. <text class="col amt">{{ formatAmount(salary * toNumber(item.private_percentage) / 100) }}</text>
  36. <text class="col amt">{{ formatAmount(salary * toNumber(item.company_percentage) / 100) }}</text>
  37. </view>
  38. <view class="table total">
  39. <text class="col name">合计</text>
  40. <text class="col rate">{{ private_total }}%</text>
  41. <text class="col rate">{{ company_total }}%</text>
  42. <text class="col amt highlight">{{ formatAmount(salary * private_total / 100) }}</text>
  43. <text class="col amt highlight">{{ formatAmount(salary * company_total / 100) }}</text>
  44. </view>
  45. </view>
  46. </view>
  47. </template>
  48. <script>
  49. //index.js
  50. //获取应用实例
  51. var app = getApp();
  52. export default {
  53. data() {
  54. return {
  55. motto: 'Hello World',
  56. inputValue: '',
  57. userInfo: {},
  58. focus: false,
  59. index: 1,
  60. salary: 0,
  61. array: ['上海', '北京', '广州', '深圳'],
  62. // 城市基数范围(可根据最新政策调整)
  63. cityBaseRange: {
  64. 上海: { min: 2014, max: 17814 },
  65. 北京: { min: 2320, max: 21258 },
  66. 广州: { min: 2300, max: 19707 },
  67. 深圳: { min: 2480, max: 22986 }
  68. },
  69. // 当前展示的基数范围
  70. baseMin: 0,
  71. baseMax: 0,
  72. insurance: [
  73. {
  74. category: '养老',
  75. private_percentage: '8',
  76. company_percentage: '22'
  77. },
  78. {
  79. category: '医疗',
  80. private_percentage: '2',
  81. company_percentage: '12'
  82. },
  83. {
  84. category: '失业',
  85. private_percentage: '1',
  86. company_percentage: '1.7'
  87. },
  88. {
  89. category: '工伤',
  90. private_percentage: '0',
  91. company_percentage: '0.5'
  92. },
  93. {
  94. category: '生育',
  95. private_percentage: '0',
  96. company_percentage: '0.8'
  97. },
  98. {
  99. category: '公积金',
  100. private_percentage: '7',
  101. company_percentage: '7'
  102. }
  103. ],
  104. private_total: 0,
  105. company_total: 0
  106. };
  107. },
  108. onLoad: function () {
  109. console.log('onLoad', this);
  110. var that = this;
  111. this.total();
  112. this.updateBaseRange();
  113. //调用应用实例的方法获取全局数据
  114. // app.getUserInfo(function(userInfo){
  115. // //更新数据
  116. // that.setData({
  117. // userInfo:userInfo
  118. // })
  119. //
  120. },
  121. methods: {
  122. //事件处理函数
  123. bindViewTap: function () {
  124. uni.navigateTo({
  125. url: '../logs/logs'
  126. });
  127. },
  128. bindPickerChange: function (e) {
  129. console.log('picker发送选择改变,携带值为', e.detail.value);
  130. this.setData({ index: e.detail.value });
  131. // 切换城市时提示基数范围
  132. const city = this.array[e.detail.value];
  133. const range = this.cityBaseRange[city] || { min: 0, max: 0 };
  134. this.modalView(`当前城市基数范围:${range.min} - ${range.max}`);
  135. this.updateBaseRange();
  136. },
  137. updateBaseRange: function () {
  138. const city = this.array[this.index];
  139. const range = this.cityBaseRange[city] || { min: 0, max: 0 };
  140. this.setData({ baseMin: range.min, baseMax: range.max });
  141. },
  142. total: function () {
  143. const insurance = this.insurance;
  144. console.log(insurance);
  145. let private_total = 0;
  146. let company_total = 0;
  147. if (insurance) {
  148. insurance.forEach((t, i) => {
  149. private_total += this.toNumber(t.private_percentage);
  150. company_total += this.toNumber(t.company_percentage);
  151. });
  152. }
  153. this.setData({
  154. private_total,
  155. company_total
  156. });
  157. },
  158. bindKeyInput: function (e) {
  159. console.log(e);
  160. this.setData({ inputValue: e.detail.value });
  161. },
  162. onRateChange: function (idx, key, e) {
  163. const val = e.detail.value;
  164. const list = this.insurance.slice();
  165. list[idx][key] = val;
  166. this.setData({ insurance: list });
  167. this.total();
  168. },
  169. toNumber: function (v) {
  170. const n = parseFloat(v);
  171. return isNaN(n) ? 0 : n;
  172. },
  173. formatAmount: function (v) {
  174. const n = parseFloat(v);
  175. if (!isNaN(n)) {
  176. return n.toFixed(2);
  177. }
  178. return '0.00';
  179. },
  180. modalView: function (text) {
  181. uni.showModal({
  182. title: 'Warning',
  183. content: text,
  184. showCancel: false,
  185. success: function (res) {
  186. if (res.confirm) {
  187. console.log('用户点击确定');
  188. }
  189. }
  190. });
  191. },
  192. startCount: function () {
  193. let inputValue = this.inputValue;
  194. if (!!inputValue) {
  195. if (!!(inputValue / 1)) {
  196. if (inputValue > 0) {
  197. // 根据城市范围校验并钳制
  198. const city = this.array[this.index];
  199. const range = this.cityBaseRange[city] || { min: 0, max: Number.MAX_SAFE_INTEGER };
  200. const iv = parseFloat(inputValue);
  201. inputValue = Math.min(Math.max(iv, range.min), range.max);
  202. this.setData({
  203. salary: inputValue,
  204. focus: false
  205. });
  206. } else {
  207. this.modalView('别开玩笑了,你还欠老板钱?');
  208. }
  209. } else {
  210. this.modalView('请输入数字,OK?');
  211. }
  212. } else {
  213. this.modalView('输入不能为空,请重新输入!');
  214. }
  215. },
  216. resetData: function () {
  217. this.setData({
  218. salary: 0,
  219. focus: true,
  220. inputValue: ''
  221. });
  222. }
  223. }
  224. };
  225. </script>
  226. <style>
  227. @import './index.css';
  228. </style>