From a4d0446d7c1c1e56641fd4e887ad4d0ecd0534ca Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期四, 05 三月 2026 17:43:55 +0800
Subject: [PATCH] 排班管理页面完成70%
---
src/views/personnelManagement/socialSecuritySet/components/formDia.vue | 369 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 369 insertions(+), 0 deletions(-)
diff --git a/src/views/personnelManagement/socialSecuritySet/components/formDia.vue b/src/views/personnelManagement/socialSecuritySet/components/formDia.vue
new file mode 100644
index 0000000..3feab2d
--- /dev/null
+++ b/src/views/personnelManagement/socialSecuritySet/components/formDia.vue
@@ -0,0 +1,369 @@
+<template>
+ <div>
+ <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">
+ <el-row :gutter="24">
+ <!-- 宸︿晶锛氶�傜敤浜哄憳 -->
+ <el-col :span="8">
+ <el-form-item label="閫傜敤浜哄憳锛�" prop="deptIds">
+ <div class="dept-checkbox-wrap">
+ <el-checkbox-group v-model="form.deptIds">
+ <div
+ v-for="dept in deptList"
+ :key="dept.deptId"
+ class="dept-checkbox-item"
+ >
+ <el-checkbox :value="dept.deptId">
+ {{ dept.deptName }}
+ <span v-if="dept.personCount != null" class="dept-count"
+ >{{ dept.personCount }}浜�</span
+ >
+ </el-checkbox>
+ </div>
+ </el-checkbox-group>
+ </div>
+ </el-form-item>
+ </el-col>
+ <!-- 鍙充晶锛氬熀纭�淇℃伅 + 淇濋櫓绫诲瀷 -->
+ <el-col :span="16">
+ <!-- 鍩虹淇℃伅 -->
+ <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>
+ </template>
+ <el-form-item label="鏂规鏍囬锛�" prop="title">
+ <el-input v-model="form.title" placeholder="璇疯緭鍏�" clearable />
+ </el-form-item>
+ <el-form-item label="澶囨敞锛�" prop="remark">
+ <el-input
+ v-model="form.remark"
+ type="textarea"
+ :rows="2"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </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>
+ </template>
+ <el-row :gutter="16">
+ <el-col
+ v-for="(item, index) in form.insuranceBenefits"
+ :key="item._key"
+ :span="12"
+ >
+ <div class="insurance-benefit-card">
+ <div class="insurance-benefit-title">
+ 淇濋櫓绂忓埄{{ index + 1 }}
+ <el-button
+ v-if="form.insuranceBenefits.length > 1"
+ type="danger"
+ link
+ size="small"
+ class="card-delete-btn"
+ @click="removeInsuranceBenefit(index)"
+ >
+ 鍒犻櫎
+ </el-button>
+ </div>
+ <el-form-item
+ :prop="'insuranceBenefits.' + index + '.insuranceType'"
+ label="淇濋櫓绫诲瀷锛�"
+ label-width="100px"
+ >
+ <el-select
+ v-model="item.insuranceType"
+ placeholder="璇烽�夋嫨"
+ clearable
+ style="width: 100%"
+ >
+ <el-option
+ v-for="opt in insuranceTypeOptions"
+ :key="opt.value"
+ :label="opt.label"
+ :value="opt.value"
+ />
+ </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>
+ </el-form-item>
+ <el-form-item label="涓汉缂磋垂姣斾緥锛�" label-width="100px">
+ <div class="personal-ratio-wrap">
+ <el-input
+ v-model="item.personalRatio"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 100px"
+ type="number"
+ />
+ <span class="ratio-unit">(%)</span>
+ <span class="ratio-plus">+</span>
+ <el-input
+ v-model="item.personalFixed"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 100px"
+ type="number"
+ />
+ </div>
+ </el-form-item>
+ </div>
+ </el-col>
+ </el-row>
+ </el-card>
+ </el-col>
+ </el-row>
+ </el-form>
+ </FormDialog>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, toRefs, getCurrentInstance, nextTick } 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";
+
+const emit = defineEmits(["close"]);
+const { proxy } = getCurrentInstance();
+
+const dialogFormVisible = ref(false);
+const operationType = ref("add");
+const formRef = ref(null);
+const deptList = ref([]);
+
+const dialogTitle = () =>
+ operationType.value === "add" ? "鏂板鏂规" : "缂栬緫鏂规";
+
+// 淇濋櫓绫诲瀷閫夐」锛堝彲鎸夊瓧鍏告浛鎹級
+const insuranceTypeOptions = [
+ { label: "鍏昏�佷繚闄�", value: "pension" },
+ { label: "鍖荤枟淇濋櫓", value: "medical" },
+ { label: "澶变笟淇濋櫓", value: "unemployment" },
+ { label: "宸ヤ激淇濋櫓", value: "work_injury" },
+ { label: "鐢熻偛淇濋櫓", value: "maternity" },
+];
+
+const defaultBenefit = () => ({
+ _key: Math.random().toString(36).slice(2),
+ insuranceType: "",
+ baseOnSalary: false,
+ useBasicSalary: false,
+ personalRatio: "",
+ personalFixed: "",
+});
+
+const data = reactive({
+ form: {
+ id: undefined,
+ title: "",
+ remark: "",
+ deptIds: [],
+ insuranceBenefits: [defaultBenefit()],
+ },
+ rules: {
+ title: [{ required: true, message: "璇疯緭鍏ユ柟妗堟爣棰�", trigger: "blur" }],
+ deptIds: [
+ {
+ required: true,
+ type: "array",
+ min: 1,
+ message: "璇疯嚦灏戦�夋嫨涓�涓�傜敤閮ㄩ棬",
+ trigger: "change",
+ },
+ ],
+ },
+});
+const { form, rules } = toRefs(data);
+
+function flattenDept(tree, list = []) {
+ if (!tree || !tree.length) return list;
+ tree.forEach((node) => {
+ list.push({
+ deptId: node.deptId,
+ deptName: node.deptName,
+ personCount: node.personCount ?? null,
+ });
+ if (node.children && node.children.length) {
+ flattenDept(node.children, list);
+ }
+ });
+ return list;
+}
+
+const loadDeptList = () => {
+ listDept().then((res) => {
+ const tree = res.data ?? [];
+ deptList.value = flattenDept(tree);
+ });
+};
+
+const addInsuranceBenefit = () => {
+ form.value.insuranceBenefits.push(defaultBenefit());
+};
+
+const removeInsuranceBenefit = (index) => {
+ form.value.insuranceBenefits.splice(index, 1);
+};
+
+const resetForm = () => {
+ form.value = {
+ id: undefined,
+ title: "",
+ remark: "",
+ deptIds: [],
+ insuranceBenefits: [defaultBenefit()],
+ };
+};
+
+const openDialog = (type, row) => {
+ operationType.value = type;
+ 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()];
+ });
+ }
+};
+
+const submitForm = () => {
+ formRef.value?.validate((valid) => {
+ if (!valid) return;
+ const submitData = {
+ ...form.value,
+ insuranceBenefits: form.value.insuranceBenefits.map(
+ ({ _key, ...rest }) => rest
+ ),
+ };
+ if (operationType.value === "add") {
+ socialSecurityAdd(submitData).then(() => {
+ proxy.$modal.msgSuccess("鏂板鎴愬姛");
+ closeDia();
+ });
+ } else {
+ socialSecurityUpdate(submitData).then(() => {
+ proxy.$modal.msgSuccess("淇敼鎴愬姛");
+ closeDia();
+ });
+ }
+ });
+};
+
+const closeDia = () => {
+ proxy.resetForm?.("formRef");
+ dialogFormVisible.value = false;
+ emit("close");
+};
+
+defineExpose({ openDialog });
+</script>
+
+<style scoped>
+.card-title-line {
+ color: #f56c6c;
+ margin-right: 4px;
+}
+.form-card {
+ margin-bottom: 16px;
+}
+.form-card :deep(.el-card__header) {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 12px 16px;
+}
+.card-title {
+ font-weight: 500;
+}
+.card-collapse {
+ color: #999;
+ cursor: pointer;
+}
+.dept-checkbox-wrap {
+ max-height: 320px;
+ overflow-y: auto;
+ padding: 8px 0;
+ border: 1px solid var(--el-border-color);
+ border-radius: 4px;
+ background: #fff;
+}
+.dept-checkbox-item {
+ padding: 6px 12px;
+}
+.dept-count {
+ color: #909399;
+ font-size: 12px;
+ margin-left: 4px;
+}
+.insurance-benefit-card {
+ border: 1px solid var(--el-border-color-lighter);
+ border-radius: 4px;
+ padding: 12px 16px;
+ margin-bottom: 12px;
+ background: #fafafa;
+}
+.insurance-benefit-title {
+ font-size: 14px;
+ margin-bottom: 12px;
+ font-weight: 500;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+.card-delete-btn {
+ margin-left: auto;
+}
+.checkbox-group-inline {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16px;
+}
+.personal-ratio-wrap {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+.ratio-unit,
+.ratio-plus {
+ color: #606266;
+ font-size: 14px;
+}
+</style>
--
Gitblit v1.9.3