| | |
| | | <el-col :span="8"> |
| | | <el-form-item label="适用人员:" prop="deptIds"> |
| | | <div class="dept-checkbox-wrap"> |
| | | <el-checkbox-group v-model="form.deptIds"> |
| | | <el-checkbox-group |
| | | v-model="form.deptIds" |
| | | :disabled="isDetail" |
| | | > |
| | | <div |
| | | v-for="dept in deptList" |
| | | :key="dept.deptId" |
| | |
| | | <el-icon class="card-collapse"><ArrowUp /></el-icon> |
| | | </template> |
| | | <el-form-item label="方案标题:" prop="title"> |
| | | <el-input v-model="form.title" placeholder="请输入" clearable /> |
| | | <el-input |
| | | v-model="form.title" |
| | | placeholder="请输入" |
| | | clearable |
| | | :disabled="isDetail" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="备注:" prop="remark"> |
| | | <el-input |
| | |
| | | :rows="2" |
| | | placeholder="请输入" |
| | | clearable |
| | | :disabled="isDetail" |
| | | /> |
| | | </el-form-item> |
| | | </el-card> |
| | |
| | | <el-card class="form-card" shadow="never"> |
| | | <template #header> |
| | | <span class="card-title"><span class="card-title-line">|</span> 保险类型</span> |
| | | <el-button type="primary" size="small" @click="addInsuranceBenefit"> |
| | | <el-button |
| | | v-if="!isDetail" |
| | | type="primary" |
| | | size="small" |
| | | @click="addInsuranceBenefit" |
| | | > |
| | | 添加保险福利 |
| | | </el-button> |
| | | </template> |
| | |
| | | <div class="insurance-benefit-title"> |
| | | 保险福利{{ index + 1 }} |
| | | <el-button |
| | | v-if="form.insuranceBenefits.length > 1" |
| | | v-if="!isDetail && form.insuranceBenefits.length > 1" |
| | | type="danger" |
| | | link |
| | | size="small" |
| | |
| | | placeholder="请选择" |
| | | clearable |
| | | style="width: 100%" |
| | | :disabled="isDetail" |
| | | > |
| | | <el-option |
| | | v-for="opt in insuranceTypeOptions" |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="缴费基数:" label-width="100px"> |
| | | <div class="checkbox-group-inline"> |
| | | <el-checkbox v-model="item.baseOnSalary">根据基本工资缴纳</el-checkbox> |
| | | <el-checkbox v-model="item.useBasicSalary">调用基本工资</el-checkbox> |
| | | <div class="base-salary-wrap"> |
| | | <el-input |
| | | v-model="item.paymentBase" |
| | | placeholder="根据基本工资缴纳" |
| | | clearable |
| | | style="width: 120px" |
| | | type="number" |
| | | :disabled="isDetail || item.useBasicSalary" |
| | | @input="handlePaymentBaseInput(item)" |
| | | /> |
| | | <el-checkbox |
| | | v-model="item.useBasicSalary" |
| | | @change="handleUseBasicSalaryChange(item)" |
| | | :disabled="isDetail" |
| | | > |
| | | 调用基本工资 |
| | | </el-checkbox> |
| | | </div> |
| | | </el-form-item> |
| | | <el-form-item label="个人缴费比例:" label-width="100px"> |
| | |
| | | clearable |
| | | style="width: 100px" |
| | | type="number" |
| | | :disabled="isDetail" |
| | | /> |
| | | <span class="ratio-unit">(%)</span> |
| | | <span class="ratio-plus">+</span> |
| | |
| | | clearable |
| | | style="width: 100px" |
| | | type="number" |
| | | :disabled="isDetail" |
| | | /> |
| | | </div> |
| | | </el-form-item> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, toRefs, getCurrentInstance, nextTick } from "vue"; |
| | | import { ref, reactive, toRefs, getCurrentInstance, nextTick, computed } from "vue"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { ArrowUp } from "@element-plus/icons-vue"; |
| | | import { listDept } from "@/api/system/dept.js"; |
| | | import { |
| | | socialSecurityInfo, |
| | | socialSecurityAdd, |
| | | socialSecurityUpdate, |
| | | } from "@/api/personnelManagement/socialSecuritySet.js"; |
| | | import { socialSecurityAdd, socialSecurityUpdate } from "@/api/personnelManagement/socialSecuritySet.js"; |
| | | |
| | | const emit = defineEmits(["close"]); |
| | | const { proxy } = getCurrentInstance(); |
| | |
| | | const formRef = ref(null); |
| | | const deptList = ref([]); |
| | | |
| | | const isDetail = computed(() => operationType.value === "detail"); |
| | | |
| | | const dialogTitle = () => |
| | | operationType.value === "add" ? "新增方案" : "编辑方案"; |
| | | operationType.value === "add" |
| | | ? "新增方案" |
| | | : operationType.value === "edit" |
| | | ? "编辑方案" |
| | | : "方案详情"; |
| | | |
| | | // 保险类型选项(可按字典替换) |
| | | const insuranceTypeOptions = [ |
| | | { label: "养老保险", value: "pension" }, |
| | | { label: "医疗保险", value: "medical" }, |
| | | { label: "失业保险", value: "unemployment" }, |
| | | { label: "工伤保险", value: "work_injury" }, |
| | | { label: "生育保险", value: "maternity" }, |
| | | { label: "养老保险", value: "养老保险" }, |
| | | { label: "医疗保险", value: "医疗保险" }, |
| | | { label: "失业保险", value: "失业保险" }, |
| | | { label: "工伤保险", value: "工伤保险" }, |
| | | { label: "生育保险", value: "生育保险" }, |
| | | ]; |
| | | |
| | | const defaultBenefit = () => ({ |
| | | _key: Math.random().toString(36).slice(2), |
| | | insuranceType: "", |
| | | baseOnSalary: false, |
| | | paymentBase: "", |
| | | useBasicSalary: false, |
| | | personalRatio: "", |
| | | personalFixed: "", |
| | |
| | | form.value.insuranceBenefits.splice(index, 1); |
| | | }; |
| | | |
| | | const handleUseBasicSalaryChange = (item) => { |
| | | if (item.useBasicSalary) { |
| | | item.paymentBase = ""; |
| | | } |
| | | }; |
| | | |
| | | const handlePaymentBaseInput = (item) => { |
| | | if (item.paymentBase !== "" && item.paymentBase != null) { |
| | | item.useBasicSalary = false; |
| | | } |
| | | }; |
| | | |
| | | const resetForm = () => { |
| | | form.value = { |
| | | id: undefined, |
| | |
| | | dialogFormVisible.value = true; |
| | | loadDeptList(); |
| | | resetForm(); |
| | | if (type === "edit" && row?.id) { |
| | | socialSecurityInfo(row.id).then((res) => { |
| | | const d = res.data || {}; |
| | | form.value.id = d.id; |
| | | form.value.title = d.title; |
| | | form.value.remark = d.remark ?? ""; |
| | | form.value.deptIds = d.deptIds ?? []; |
| | | form.value.insuranceBenefits = |
| | | (d.insuranceBenefits && d.insuranceBenefits.length) |
| | | ? d.insuranceBenefits.map((b) => ({ |
| | | ...b, |
| | | _key: b._key || Math.random().toString(36).slice(2), |
| | | })) |
| | | : [defaultBenefit()]; |
| | | }); |
| | | if ((type === "edit" || type === "detail") && row) { |
| | | const d = row || {}; |
| | | form.value.id = d.id; |
| | | form.value.title = d.title; |
| | | form.value.remark = d.remark ?? ""; |
| | | // deptIds 后端可能是逗号分隔字符串或数组,这里统一转为数组并尽量还原数值类型 |
| | | if (d.deptIds) { |
| | | form.value.deptIds = String(d.deptIds) |
| | | .split(",") |
| | | .filter((v) => v !== "") |
| | | .map((v) => { |
| | | const num = Number(v); |
| | | return Number.isNaN(num) ? v : num; |
| | | }); |
| | | } else { |
| | | form.value.deptIds = []; |
| | | } |
| | | const detailList = d.schemeInsuranceDetailList || []; |
| | | form.value.insuranceBenefits = |
| | | detailList.length > 0 |
| | | ? detailList.map((b) => ({ |
| | | _key: Math.random().toString(36).slice(2), |
| | | insuranceType: b.insuranceType || "", |
| | | paymentBase: b.paymentBase ?? "", |
| | | useBasicSalary: b.useBasicSalary === 2, |
| | | personalRatio: b.personalRatio ?? "", |
| | | personalFixed: b.personalFixed ?? "", |
| | | })) |
| | | : [defaultBenefit()]; |
| | | } |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | // 详情模式下不提交,只关闭弹窗 |
| | | if (operationType.value === "detail") { |
| | | closeDia(); |
| | | return; |
| | | } |
| | | formRef.value?.validate((valid) => { |
| | | if (!valid) return; |
| | | const deptIds = |
| | | Array.isArray(form.value.deptIds) && form.value.deptIds.length |
| | | ? form.value.deptIds.join(",") |
| | | : ""; |
| | | const schemeInsuranceDetailList = (form.value.insuranceBenefits || []).map( |
| | | ({ _key, ...rest }) => ({ |
| | | ...rest, |
| | | useBasicSalary: rest.useBasicSalary ? 2 : 1, |
| | | }) |
| | | ); |
| | | const insuranceTypes = schemeInsuranceDetailList |
| | | .map((item) => item.insuranceType) |
| | | .filter((v) => v) |
| | | .join(","); |
| | | // 部门名称,多个使用逗号隔开(根据选中的 deptIds 与 deptList 计算) |
| | | const deptNames = (deptList.value || []) |
| | | .filter((d) => |
| | | (form.value.deptIds || []).some( |
| | | (id) => String(id) === String(d.deptId) |
| | | ) |
| | | ) |
| | | .map((d) => d.deptName) |
| | | .join(","); |
| | | const submitData = { |
| | | ...form.value, |
| | | insuranceBenefits: form.value.insuranceBenefits.map( |
| | | ({ _key, ...rest }) => rest |
| | | ), |
| | | id: form.value.id, |
| | | title: form.value.title, |
| | | remark: form.value.remark ?? "", |
| | | deptIds, |
| | | insuranceTypes, |
| | | deptNames, |
| | | schemeInsuranceDetailList, |
| | | }; |
| | | if (operationType.value === "add") { |
| | | socialSecurityAdd(submitData).then(() => { |
| | |
| | | flex-wrap: wrap; |
| | | gap: 16px; |
| | | } |
| | | .base-salary-wrap { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | .base-salary-text { |
| | | color: #606266; |
| | | font-size: 14px; |
| | | } |
| | | .personal-ratio-wrap { |
| | | display: flex; |
| | | align-items: center; |