| | |
| | | <template> |
| | | <div> |
| | | <FormDialog |
| | | v-model="dialogFormVisible" |
| | | <FormDialog v-model="dialogFormVisible" |
| | | :operation-type="operationType" |
| | | :title="dialogTitle" |
| | | width="80%" |
| | | @close="closeDia" |
| | | @confirm="submitForm" |
| | | @cancel="closeDia" |
| | | > |
| | | <el-form ref="formRef" :model="form" :rules="rules" label-position="top"> |
| | | @cancel="closeDia"> |
| | | <el-form ref="formRef" |
| | | :model="form" |
| | | :rules="rules" |
| | | label-position="top"> |
| | | <el-row :gutter="24"> |
| | | <!-- 左侧:适用人员 --> |
| | | <el-col :span="8"> |
| | | <el-form-item label="适用人员:" prop="deptIds"> |
| | | <el-form-item label="适用人员:" |
| | | prop="deptIds"> |
| | | <div class="dept-checkbox-wrap"> |
| | | <el-checkbox-group |
| | | v-model="form.deptIds" |
| | | :disabled="isDetail" |
| | | > |
| | | <div |
| | | v-for="dept in deptList" |
| | | <el-checkbox-group v-model="form.deptIds" |
| | | :disabled="isDetail"> |
| | | <div v-for="dept in deptList" |
| | | :key="dept.deptId" |
| | | class="dept-checkbox-item" |
| | | > |
| | | class="dept-checkbox-item"> |
| | | <el-checkbox :value="dept.deptId"> |
| | | {{ dept.deptName }} |
| | | <span v-if="dept.personCount != null" class="dept-count" |
| | | >{{ dept.personCount }}人</span |
| | | > |
| | | <span v-if="dept.personCount != null" |
| | | class="dept-count">{{ dept.personCount }}人</span> |
| | | </el-checkbox> |
| | | </div> |
| | | </el-checkbox-group> |
| | |
| | | <!-- 右侧:基础信息 + 保险类型 --> |
| | | <el-col :span="16"> |
| | | <!-- 基础信息 --> |
| | | <el-card class="form-card" shadow="never"> |
| | | <el-card class="form-card" |
| | | shadow="never"> |
| | | <template #header> |
| | | <span class="card-title"><span class="card-title-line">|</span> 基础信息</span> |
| | | <el-icon class="card-collapse"><ArrowUp /></el-icon> |
| | | <el-icon class="card-collapse"> |
| | | <ArrowUp /> |
| | | </el-icon> |
| | | </template> |
| | | <el-form-item label="方案标题:" prop="title"> |
| | | <el-input |
| | | v-model="form.title" |
| | | <el-form-item label="方案标题:" |
| | | prop="title"> |
| | | <el-input v-model="form.title" |
| | | placeholder="请输入" |
| | | clearable |
| | | :disabled="isDetail" |
| | | /> |
| | | :disabled="isDetail" /> |
| | | </el-form-item> |
| | | <el-form-item label="备注:" prop="remark"> |
| | | <el-input |
| | | v-model="form.remark" |
| | | <el-form-item label="备注:" |
| | | prop="remark"> |
| | | <el-input v-model="form.remark" |
| | | type="textarea" |
| | | :rows="2" |
| | | placeholder="请输入" |
| | | clearable |
| | | :disabled="isDetail" |
| | | /> |
| | | :disabled="isDetail" /> |
| | | </el-form-item> |
| | | </el-card> |
| | | |
| | | <!-- 保险类型 --> |
| | | <el-card class="form-card" shadow="never"> |
| | | <el-card class="form-card" |
| | | shadow="never"> |
| | | <template #header> |
| | | <span class="card-title"><span class="card-title-line">|</span> 保险类型</span> |
| | | <el-button |
| | | v-if="!isDetail" |
| | | <el-button v-if="!isDetail" |
| | | type="primary" |
| | | size="small" |
| | | @click="addInsuranceBenefit" |
| | | > |
| | | @click="addInsuranceBenefit"> |
| | | 添加保险福利 |
| | | </el-button> |
| | | </template> |
| | | <el-row :gutter="16"> |
| | | <el-col |
| | | v-for="(item, index) in form.insuranceBenefits" |
| | | <el-col v-for="(item, index) in form.insuranceBenefits" |
| | | :key="item._key" |
| | | :span="12" |
| | | > |
| | | :span="12"> |
| | | <div class="insurance-benefit-card"> |
| | | <div class="insurance-benefit-title"> |
| | | 保险福利{{ index + 1 }} |
| | | <el-button |
| | | v-if="!isDetail && form.insuranceBenefits.length > 1" |
| | | <el-button v-if="!isDetail && form.insuranceBenefits.length > 1" |
| | | type="danger" |
| | | link |
| | | size="small" |
| | | class="card-delete-btn" |
| | | @click="removeInsuranceBenefit(index)" |
| | | > |
| | | @click="removeInsuranceBenefit(index)"> |
| | | 删除 |
| | | </el-button> |
| | | </div> |
| | | <el-form-item |
| | | :prop="'insuranceBenefits.' + index + '.insuranceType'" |
| | | <el-form-item :prop="'insuranceBenefits.' + index + '.insuranceType'" |
| | | label="保险类型:" |
| | | label-width="100px" |
| | | > |
| | | <el-select |
| | | v-model="item.insuranceType" |
| | | label-width="100px"> |
| | | <el-select v-model="item.insuranceType" |
| | | placeholder="请选择" |
| | | clearable |
| | | style="width: 100%" |
| | | :disabled="isDetail" |
| | | > |
| | | <el-option |
| | | v-for="opt in insuranceTypeOptions" |
| | | :disabled="isDetail"> |
| | | <el-option v-for="opt in insuranceTypeOptions" |
| | | :key="opt.value" |
| | | :label="opt.label" |
| | | :value="opt.value" |
| | | /> |
| | | :value="opt.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="缴费基数:" label-width="100px"> |
| | | <el-form-item label="缴费基数:" |
| | | label-width="100px"> |
| | | <div class="base-salary-wrap"> |
| | | <el-input |
| | | v-model="item.paymentBase" |
| | | <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" |
| | | @input="handlePaymentBaseInput(item)" /> |
| | | <el-checkbox v-model="item.useBasicSalary" |
| | | @change="handleUseBasicSalaryChange(item)" |
| | | :disabled="isDetail" |
| | | > |
| | | :disabled="isDetail"> |
| | | 调用基本工资 |
| | | </el-checkbox> |
| | | </div> |
| | | </el-form-item> |
| | | <el-form-item label="个人缴费比例:" label-width="100px"> |
| | | <el-form-item label="个人缴费比例:" |
| | | label-width="100px"> |
| | | <div class="personal-ratio-wrap"> |
| | | <el-input |
| | | v-model="item.personalRatio" |
| | | <el-input v-model="item.personalRatio" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 100px" |
| | | type="number" |
| | | :disabled="isDetail" |
| | | /> |
| | | :min="0" |
| | | @input="handlePersonalRatioInput(item)" /> |
| | | <span class="ratio-unit">(%)</span> |
| | | <span class="ratio-plus">+</span> |
| | | <el-input |
| | | v-model="item.personalFixed" |
| | | <el-input v-model="item.personalFixed" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 100px" |
| | | type="number" |
| | | :disabled="isDetail" |
| | | /> |
| | | :min="0" |
| | | @input="handlePersonalFixedInput(item)" /> |
| | | </div> |
| | | </el-form-item> |
| | | </div> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, toRefs, getCurrentInstance, nextTick, computed } 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 { socialSecurityAdd, socialSecurityUpdate } from "@/api/personnelManagement/socialSecuritySet.js"; |
| | | import { |
| | | socialSecurityAdd, |
| | | socialSecurityUpdate, |
| | | } from "@/api/personnelManagement/socialSecuritySet.js"; |
| | | |
| | | const emit = defineEmits(["close"]); |
| | | const { proxy } = getCurrentInstance(); |
| | |
| | | |
| | | function flattenDept(tree, list = []) { |
| | | if (!tree || !tree.length) return list; |
| | | tree.forEach((node) => { |
| | | tree.forEach(node => { |
| | | list.push({ |
| | | deptId: node.deptId, |
| | | deptName: node.deptName, |
| | |
| | | } |
| | | |
| | | const loadDeptList = () => { |
| | | listDept().then((res) => { |
| | | listDept().then(res => { |
| | | const tree = res.data ?? []; |
| | | deptList.value = flattenDept(tree); |
| | | }); |
| | |
| | | form.value.insuranceBenefits.push(defaultBenefit()); |
| | | }; |
| | | |
| | | const removeInsuranceBenefit = (index) => { |
| | | const removeInsuranceBenefit = index => { |
| | | form.value.insuranceBenefits.splice(index, 1); |
| | | }; |
| | | |
| | | const handleUseBasicSalaryChange = (item) => { |
| | | const handleUseBasicSalaryChange = item => { |
| | | if (item.useBasicSalary) { |
| | | item.paymentBase = ""; |
| | | } |
| | | }; |
| | | |
| | | const handlePaymentBaseInput = (item) => { |
| | | const handlePaymentBaseInput = item => { |
| | | if (item.paymentBase !== "" && item.paymentBase != null) { |
| | | item.useBasicSalary = false; |
| | | } |
| | | }; |
| | | |
| | | const handlePersonalRatioInput = item => { |
| | | if (item.personalRatio !== "" && item.personalRatio != null) { |
| | | const value = Number(item.personalRatio); |
| | | if (value < 0) { |
| | | item.personalRatio = ""; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const handlePersonalFixedInput = item => { |
| | | if (item.personalFixed !== "" && item.personalFixed != null) { |
| | | const value = Number(item.personalFixed); |
| | | if (value < 0) { |
| | | item.personalFixed = ""; |
| | | } |
| | | } |
| | | }; |
| | | |
| | |
| | | if (d.deptIds) { |
| | | form.value.deptIds = String(d.deptIds) |
| | | .split(",") |
| | | .filter((v) => v !== "") |
| | | .map((v) => { |
| | | .filter(v => v !== "") |
| | | .map(v => { |
| | | const num = Number(v); |
| | | return Number.isNaN(num) ? v : num; |
| | | }); |
| | |
| | | const detailList = d.schemeInsuranceDetailList || []; |
| | | form.value.insuranceBenefits = |
| | | detailList.length > 0 |
| | | ? detailList.map((b) => ({ |
| | | ? detailList.map(b => ({ |
| | | _key: Math.random().toString(36).slice(2), |
| | | insuranceType: b.insuranceType || "", |
| | | paymentBase: b.paymentBase ?? "", |
| | |
| | | closeDia(); |
| | | return; |
| | | } |
| | | formRef.value?.validate((valid) => { |
| | | formRef.value?.validate(valid => { |
| | | if (!valid) return; |
| | | const deptIds = |
| | | Array.isArray(form.value.deptIds) && form.value.deptIds.length |
| | |
| | | }) |
| | | ); |
| | | const insuranceTypes = schemeInsuranceDetailList |
| | | .map((item) => item.insuranceType) |
| | | .filter((v) => v) |
| | | .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) |
| | | .filter(d => |
| | | (form.value.deptIds || []).some(id => String(id) === String(d.deptId)) |
| | | ) |
| | | ) |
| | | .map((d) => d.deptName) |
| | | .map(d => d.deptName) |
| | | .join(","); |
| | | const submitData = { |
| | | id: form.value.id, |