| | |
| | | maternityRatio?: number; |
| | | housingFundCompanyRatio?: number; |
| | | housingFundPersonalRatio?: number; |
| | | /** é»è®¤ç¤¾ä¿ç¼´è´¹åºæ°ï¼ä¸å¡«åç¨åå·¥åºæ¬å·¥èµï¼ */ |
| | | defaultSocialSecurityBase?: number; |
| | | /** é»è®¤å
¬ç§¯éç¼´è´¹åºæ°ï¼ä¸å¡«æ 0 åç¨ç¤¾ä¿åºæ°ï¼ */ |
| | | defaultHousingFundBase?: number; |
| | | /** éç¨é¨é¨IDå表ï¼ä¸ºç©ºè¡¨ç¤ºå
¨å±é»è®¤æ¹æ¡ï¼ */ |
| | | deptIds?: number[]; |
| | | /** éç¨é¨é¨åç§°ï¼å¤ä¸ªç¨ãåéï¼ä¸ºç©ºè¡¨ç¤ºå
¨å±é»è®¤ï¼ */ |
| | | deptNames?: string; |
| | | status?: number; |
| | | remark?: string; |
| | | createTime?: string; |
| | |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { HrmSalaryCalculationApi } from '#/api/hrm/salary/calculation'; |
| | | |
| | | import { ref } from 'vue'; |
| | | import { ref, watch } from 'vue'; |
| | | |
| | | import { Page } from '#/packages/effects/common-ui/src'; |
| | | import { downloadFileFromBlobPart } from '#/packages/utils/src'; |
| | |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | calculateSalary, |
| | | confirmSalary, |
| | | deleteSalaryCalculation, |
| | | exportSalaryCalculation, |
| | |
| | | const previewLoading = ref(false); |
| | | const previewData = ref<HrmSalaryCalculationApi.SalaryCalculation[]>([]); |
| | | const submitLoading = ref(false); |
| | | const calculateLoading = ref(false); |
| | | |
| | | // æå¼æ ¸ç®å¼¹çª |
| | | async function openCalculateModal() { |
| | |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** æ§è¡èªé
¬æ ¸ç®ï¼èªå¨è®¡ç®å¹¶ä¿åï¼ */ |
| | | async function handleCalculate() { |
| | | if (!calculatePeriod.value) { |
| | | message.warning('è¯·éæ©æ ¸ç®å¨æ'); |
| | | return; |
| | | // æ ¸ç®ææåªå
许å¨ãé¢è§ â ä¿åãä¹é´æµè½¬ï¼æ¹äºå¨æ/é¨é¨å°±å¿
须鿰é¢è§ï¼ |
| | | // å¦å伿ä¸ä¸è½®çé¢è§ç»æææ°ç卿åä¸å» |
| | | watch([calculatePeriod, calculateDeptId], () => { |
| | | if (previewData.value.length > 0) { |
| | | previewData.value = []; |
| | | message.info('æ ¸ç®å¨ææé¨é¨å·²åæ´ï¼è¯·éæ°é¢è§æ°æ®'); |
| | | } |
| | | calculateLoading.value = true; |
| | | try { |
| | | await calculateSalary({ |
| | | period: calculatePeriod.value, |
| | | deptId: calculateDeptId.value, |
| | | }); |
| | | message.success('èªé
¬æ ¸ç®æ§è¡æå'); |
| | | calculateVisible.value = false; |
| | | handleRefresh(); |
| | | } finally { |
| | | calculateLoading.value = false; |
| | | } |
| | | } |
| | | }); |
| | | |
| | | /** é¢è§æ ¸ç®æ°æ® */ |
| | | async function handlePreview() { |
| | |
| | | :maskClosable="false" |
| | | > |
| | | <Alert |
| | | message="ä¸¤ç§æ ¸ç®æ¹å¼ï¼1. æ§è¡æ ¸ç® - èªå¨è®¡ç®å¹¶ä¿åï¼2. é¢è§æ°æ® - æå¨è°æ´åä¿å" |
| | | message="æ ¸ç®æµç¨ï¼éå¥½æ ¸ç®å¨æä¸é¨é¨åç¹ãé¢è§æ°æ®ãâ æ ¸å¯¹/è°æ´å项éé¢ â ç¹ãä¿åæ ¸ç®ãè½åº" |
| | | type="info" |
| | | show-icon |
| | | style="margin-bottom: 16px" |
| | |
| | | /> |
| | | </FormItem> |
| | | <FormItem> |
| | | <a-button type="primary" :loading="calculateLoading" @click="handleCalculate"> |
| | | æ§è¡æ ¸ç® |
| | | </a-button> |
| | | </FormItem> |
| | | <FormItem> |
| | | <a-button :loading="previewLoading" @click="handlePreview"> |
| | | <a-button type="primary" :loading="previewLoading" @click="handlePreview"> |
| | | é¢è§æ°æ® |
| | | </a-button> |
| | | </FormItem> |
| | |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { HrmSocialSecuritySchemeApi } from '#/api/hrm/salary/social-security-scheme'; |
| | | |
| | | import { getDeptList } from '#/api/system/dept'; |
| | | import { handleTree } from '#/packages/utils/src'; |
| | | |
| | | /** 表åç±»å */ |
| | | export type FormType = 'create' | 'update'; |
| | | |
| | | /** æ ¼å¼åæ¯ä¾è¾å
¥ */ |
| | | function createRatioFormatter(step: number = 0.01) { |
| | | /** |
| | | * æ ¼å¼åæ¯ä¾è¾å
¥ï¼æ¾ç¤ºå¼ï¼8.5%ï¼ä¸åå¨å¼ï¼0.085ï¼äºè½¬ |
| | | * |
| | | * ä¿ç 2 ä½ç¾åæ¯å°æ°ï¼æ£å¥½å¯¹åºæ°æ®åº decimal(5,4) ç 4 ä½å°æ°ç²¾åº¦ï¼ |
| | | * é¿å
8.5% 被åèäºå
¥æ 9% ååå 0.09ã |
| | | */ |
| | | function createRatioFormatter() { |
| | | return { |
| | | formatter: (value: number) => value !== undefined && value !== null ? `${(value * 100).toFixed(step === 0.001 ? 1 : 0)}%` : '', |
| | | formatter: (value: number) => |
| | | value !== undefined && value !== null |
| | | ? `${Number((value * 100).toFixed(2))}%` |
| | | : '', |
| | | parser: (value: string) => { |
| | | const num = parseFloat(value.replace('%', '')); |
| | | const num = parseFloat(String(value).replace('%', '')); |
| | | return isNaN(num) ? 0 : num / 100; |
| | | }, |
| | | }; |
| | |
| | | ], |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'deptIds', |
| | | label: 'éç¨é¨é¨', |
| | | component: 'ApiTreeSelect', |
| | | componentProps: { |
| | | api: async () => { |
| | | const data = await getDeptList(); |
| | | return handleTree(data); |
| | | }, |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | | childrenField: 'children', |
| | | multiple: true, |
| | | treeCheckable: true, |
| | | showCheckedStrategy: 'SHOW_ALL', |
| | | allowClear: true, |
| | | treeDefaultExpandAll: true, |
| | | placeholder: 'ä¸é表示å
¨å±é»è®¤æ¹æ¡ï¼åªå¯¹æéé¨é¨æ¬çº§çåå·¥çæ', |
| | | }, |
| | | formItemClass: 'col-span-2', |
| | | }, |
| | | // å
»èä¿é© |
| | | { |
| | |
| | | step: 0.001, |
| | | precision: 4, |
| | | style: { width: '100%' }, |
| | | ...createRatioFormatter(0.001), |
| | | ...createRatioFormatter(), |
| | | }, |
| | | }, |
| | | { |
| | |
| | | step: 0.001, |
| | | precision: 4, |
| | | style: { width: '100%' }, |
| | | ...createRatioFormatter(0.001), |
| | | ...createRatioFormatter(), |
| | | }, |
| | | }, |
| | | // 工伤/çè²ä¿é© |
| | |
| | | step: 0.001, |
| | | precision: 4, |
| | | style: { width: '100%' }, |
| | | ...createRatioFormatter(0.001), |
| | | ...createRatioFormatter(), |
| | | }, |
| | | }, |
| | | { |
| | |
| | | step: 0.001, |
| | | precision: 4, |
| | | style: { width: '100%' }, |
| | | ...createRatioFormatter(0.001), |
| | | ...createRatioFormatter(), |
| | | }, |
| | | }, |
| | | // å
¬ç§¯é |
| | |
| | | precision: 4, |
| | | style: { width: '100%' }, |
| | | ...createRatioFormatter(), |
| | | }, |
| | | }, |
| | | // ç¼´è´¹åºæ° |
| | | { |
| | | fieldName: 'divider_base', |
| | | label: 'ç¼´è´¹åºæ°ï¼æªåç¬ç»´æ¤åå·¥ç¤¾ä¿æ¡£æ¡çåå·¥ææ¤è®¡ç®ï¼', |
| | | component: 'Divider', |
| | | formItemClass: 'col-span-2', |
| | | }, |
| | | { |
| | | fieldName: 'defaultSocialSecurityBase', |
| | | label: 'é»è®¤ç¤¾ä¿åºæ°', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | placeholder: 'ç空åç¨åå·¥åºæ¬å·¥èµ', |
| | | min: 0, |
| | | precision: 2, |
| | | style: { width: '100%' }, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'defaultHousingFundBase', |
| | | label: 'é»è®¤å
¬ç§¯éåºæ°', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | placeholder: 'ç空æ 0 åç¨ç¤¾ä¿åºæ°', |
| | | min: 0, |
| | | precision: 2, |
| | | style: { width: '100%' }, |
| | | }, |
| | | }, |
| | | // 夿³¨ |
| | |
| | | export function useGridColumns(): VxeTableGridOptions<HrmSocialSecuritySchemeApi.SocialSecurityScheme>['columns'] { |
| | | return [ |
| | | { field: 'name', title: 'æ¹æ¡åç§°', minWidth: 180 }, |
| | | { |
| | | field: 'deptNames', |
| | | title: 'éç¨é¨é¨', |
| | | minWidth: 160, |
| | | slots: { default: 'deptNames' }, |
| | | }, |
| | | { field: 'effectiveDate', title: 'çææ¥æ', width: 110 }, |
| | | { |
| | | field: 'pensionCompanyRatio', |
| | |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #deptNames="{ row }"> |
| | | <span v-if="row.deptNames">{{ row.deptNames }}</span> |
| | | <Tag v-else color="blue">å
¨å±é»è®¤</Tag> |
| | | </template> |
| | | <template #pensionCompanyRatio="{ row }"> |
| | | {{ formatRatio(row.pensionCompanyRatio) }} |
| | | </template> |
| | |
| | | maternityRatio: 0.005, |
| | | housingFundCompanyRatio: 0.12, |
| | | housingFundPersonalRatio: 0.12, |
| | | deptIds: [], |
| | | status: 0, |
| | | }); |
| | | return; |
| | |
| | | max: 1, |
| | | step: 0.01, |
| | | precision: 4, |
| | | formatter: (value: number) => `${(value * 100).toFixed(0)}%`, |
| | | parser: (value: string) => parseFloat(value.replace('%', '')) / 100, |
| | | // ä¿ç 2 ä½ç¾åæ¯å°æ°ï¼å¯¹åº decimal(5,4) ç 4 ä½å°æ°ï¼ï¼é¿å
3.5% 被åèäºå
¥æ 4% |
| | | formatter: (value: number) => |
| | | value === undefined || value === null |
| | | ? '' |
| | | : `${Number((value * 100).toFixed(2))}%`, |
| | | parser: (value: string) => { |
| | | const num = parseFloat(String(value).replace('%', '')); |
| | | return isNaN(num) ? 0 : num / 100; |
| | | }, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | |
| | | {{ row.minAmount }} ~ {{ row.maxAmount === 0 ? 'â' : row.maxAmount }} |
| | | </template> |
| | | <template #taxRate="{ row }"> |
| | | {{ (row.taxRate * 100).toFixed(0) }}% |
| | | {{ |
| | | row.taxRate === undefined || row.taxRate === null |
| | | ? '-' |
| | | : `${Number((row.taxRate * 100).toFixed(2))}%` |
| | | }} |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |