From 2763efef00d553bc65e08bd21384cdd6dd2a5a2f Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 05 三月 2026 11:52:05 +0800
Subject: [PATCH] 进销存升级 1.添加社会保险设置页面,开发与联调 2.丰富新增入职所填字段字段并于用户管理关联 3.修改人员薪资页面样式和逻辑

---
 src/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue |  540 ++++++++++++++++++++++++++++-------------------------------
 1 files changed, 259 insertions(+), 281 deletions(-)

diff --git a/src/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue b/src/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue
index 06eee04..e44bdb8 100644
--- a/src/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue
+++ b/src/views/personnelManagement/employeeRecord/components/NewOrEditFormDia.vue
@@ -1,321 +1,299 @@
 <template>
-  <div>
-    <el-dialog
-        v-model="dialogFormVisible"
-        :title="operationType === 'add' ? '鏂板鍏ヨ亴' : '缂栬緫浜哄憳'"
-        width="70%"
-        @close="closeDia"
-    >
-      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
-        <el-row :gutter="30">
-          <el-col :span="12">
-            <el-form-item label="鍛樺伐缂栧彿锛�" prop="staffNo">
-              <el-input v-model="form.staffNo" placeholder="璇疯緭鍏�" clearable :disabled="operationType !== 'add'"/>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="濮撳悕锛�" prop="staffName">
-              <el-input v-model="form.staffName" placeholder="璇疯緭鍏�" clearable/>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="30">
-          <el-col :span="12">
-            <el-form-item label="鎬у埆锛�" prop="sex">
-              <el-select v-model="form.sex">
-                <el-option label="鐢�" value="鐢�" />
-                <el-option label="濂�" value="濂�" />
-              </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="鎴风睄浣忓潃锛�" prop="nativePlace">
-              <el-input v-model="form.nativePlace" placeholder="璇疯緭鍏�" clearable/>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="30">
-          <el-col :span="12">
-            <el-form-item label="宀椾綅锛�" prop="sysPostId">
-              <el-select v-model="form.sysPostId" placeholder="璇烽�夋嫨宀椾綅" clearable>
-                <el-option
-                    v-for="item in postOptions"
-                    :key="item.postId"
-                    :label="item.postName"
-                    :value="item.postId"
-                    :disabled="item.status === '1'"
-                />
-              </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="鐜颁綇鍧�锛�" prop="adress">
-              <el-input v-model="form.adress" placeholder="璇疯緭鍏�" clearable/>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="30">
-          <el-col :span="12">
-            <el-form-item label="閮ㄩ棬锛�" prop="sysDeptId">
-              <el-tree-select
-                  v-model="form.sysDeptId"
-                  :data="deptOptions"
-                  :props="{ value: 'id', label: 'label', children: 'children' }"
-                  value-key="id"
-                  placeholder="璇烽�夋嫨閮ㄩ棬"
-                  check-strictly
-              />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="骞撮緞锛�" prop="age">
-              <el-input-number v-model="form.age" :precision="0" :step="1" style="width: 100%"/>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="30">
-          <el-col :span="12">
-            <el-form-item label="绗竴瀛﹀巻锛�" prop="firstStudy">
-              <el-input v-model="form.firstStudy" placeholder="璇疯緭鍏�" clearable/>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="涓撲笟锛�" prop="profession">
-              <el-input v-model="form.profession" placeholder="璇疯緭鍏�" clearable/>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="30">
-          <el-col :span="12">
-            <el-form-item label="鑱旂郴鐢佃瘽锛�" prop="phone">
-              <el-input v-model="form.phone" placeholder="璇疯緭鍏�" clearable/>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="绱ф�ヨ仈绯讳汉锛�" prop="emergencyContact">
-              <el-input v-model="form.emergencyContact" placeholder="璇疯緭鍏�" clearable/>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="30">
-          <el-col :span="12">
-            <el-form-item label="绱ф�ヨ仈绯讳汉鑱旂郴鐢佃瘽锛�" prop="emergencyContactPhone">
-              <el-input v-model="form.emergencyContactPhone" placeholder="璇疯緭鍏�" clearable/>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="鍚堝悓骞撮檺锛�" prop="contractTerm">
-              <el-input-number v-model="form.contractTerm" :precision="0" :step="1" style="width: 100%" :disabled="true"/>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="30">
-          <el-col :span="12">
-            <el-form-item label="鍚堝悓寮�濮嬫棩鏈燂細" prop="contractStartTime">
-              <el-date-picker
-                  v-model="form.contractStartTime"
-                  type="date"
-                  placeholder="璇烽�夋嫨鏃ユ湡"
-                  value-format="YYYY-MM-DD"
-                  format="YYYY-MM-DD"
-                  clearable
-                  style="width: 100%"
-									@change="calculateContractTerm"
-              />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="鍚堝悓缁撴潫鏃ユ湡锛�" prop="contractEndTime">
-              <el-date-picker
-                  v-model="form.contractEndTime"
-                  type="date"
-                  placeholder="璇烽�夋嫨鏃ユ湡"
-                  value-format="YYYY-MM-DD"
-                  format="YYYY-MM-DD"
-                  clearable
-                  style="width: 100%"
-									@change="calculateContractTerm"
-              />
-            </el-form-item>
-          </el-col>
-        </el-row>
+  <FormDialog
+    v-model="dialogFormVisible"
+    :operation-type="operationType"
+    :title="dialogTitle"
+    width="90%"
+    @close="closeDia"
+    @confirm="submitForm"
+    @cancel="closeDia"
+  >
+    <div class="form-dia-body">
+      <el-form
+        ref="formRef"
+        :model="form"
+        :rules="rules"
+        label-position="top"
+      >
+        <BasicInfoSection :form="form" :operation-type="operationType" />
+        <JobInfoSection
+          :form="form"
+          :post-options="postOptions"
+          :dept-options="deptOptions"
+        />
+        <EducationWorkSection :form="form" />
+        <EmergencyAndAttachmentSection :form="form" />
       </el-form>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">纭</el-button>
-          <el-button @click="closeDia">鍙栨秷</el-button>
-        </div>
-      </template>
-    </el-dialog>
-  </div>
+    </div>
+  </FormDialog>
 </template>
 
 <script setup>
-import {ref, onMounted} from "vue";
-import {findPostOptions} from "@/api/system/post.js";
-import {listDept} from "@/api/system/dept.js";
-import {staffOnJobInfo, createStaffOnJob, updateStaffOnJob} from "@/api/personnelManagement/staffOnJob.js";
-import {deptTreeSelect} from "@/api/system/user.js";
-const { proxy } = getCurrentInstance()
-const emit = defineEmits(['close'])
+import {
+  ref,
+  reactive,
+  toRefs,
+  onMounted,
+  getCurrentInstance,
+  nextTick,
+} from "vue";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { findPostOptions } from "@/api/system/post.js";
+import { deptTreeSelect } from "@/api/system/user.js";
+import {
+  staffOnJobInfo,
+  createStaffOnJob,
+  updateStaffOnJob,
+} from "@/api/personnelManagement/staffOnJob.js";
+
+import BasicInfoSection from "./BasicInfoSection.vue";
+import JobInfoSection from "./JobInfoSection.vue";
+import EducationWorkSection from "./EducationWorkSection.vue";
+import EmergencyAndAttachmentSection from "./EmergencyAndAttachmentSection.vue";
+
+const { proxy } = getCurrentInstance();
+const emit = defineEmits(["close"]);
 
 const dialogFormVisible = ref(false);
-const operationType = ref('')
-const id = ref(0)
-const data = reactive({
-  form: {
-    staffNo: "",
-    staffName: "",
-    sex: "",
-    nativePlace: "",
-    postJob: "",
-    adress: "",
-    firstStudy: "",
-    profession: "",
-    age: 0,
-    phone: "",
-    emergencyContact: "",
-    emergencyContactPhone: "",
-    contractTerm: 0,
-    contractStartTime: "",
-    contractEndTime: "",
-    staffState: "",
-    sysPostId: undefined,
-    sysDeptId: undefined,
-  },
-  rules: {
-    staffNo: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" },],
-    staffName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    sex: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    nativePlace: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    postJob: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    adress: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    firstStudy: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    profession: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    age: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    phone: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    emergencyContact: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    emergencyContactPhone: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    contractTerm: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    contractStartTime: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    contractEndTime: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-  },
-  postOptions: [], // 宀椾綅閫夐」
-  deptOptions: [], // 閮ㄩ棬閫夐」
-});
-const { form, rules, postOptions, deptOptions } = toRefs(data);
+const operationType = ref("add");
+const id = ref(0);
+const formRef = ref(null);
 
-// 鎵撳紑寮规
+const dialogTitle = () =>
+  operationType.value === "add" ? "鏂板鍏ヨ亴" : "缂栬緫浜哄憳";
+
+const createEmptyEducation = () => ({
+  degree: "",
+  school: "",
+  admissionDate: "",
+  graduationDate: "",
+  major: "",
+  academicDegree: "",
+});
+
+const createEmptyWork = () => ({
+  company: "",
+  department: "",
+  position: "",
+  startDate: "",
+  endDate: "",
+  description: "",
+});
+
+const createEmptyEmergency = () => ({
+  name: "",
+  relation: "",
+  phone: "",
+  address: "",
+});
+
+const createDefaultForm = () => ({
+  id: undefined,
+  // 鍩烘湰淇℃伅
+  staffNo: "",
+  staffName: "",
+  aliasName: "",
+  phone: "",
+  sex: "",
+  birthDate: "",
+  age: undefined,
+  nativePlace: "",
+  nation: "",
+  maritalStatus: "",
+  politicalStatus: "",
+  firstWorkDate: "",
+  workingYears: undefined,
+  idCardNo: "",
+  hukouType: "",
+  email: "",
+  currentAddress: "",
+  // 鍦ㄨ亴淇℃伅
+  jobNo: "",
+  staffType: "",
+  entryDate: "",
+  probationPeriod: undefined,
+  regularDate: "",
+  sysDeptId: undefined,
+  directLeader: "",
+  sysPostId: undefined,
+  jobLevel: "",
+  basicSalary: undefined,
+  // 閾惰鍗′俊鎭�
+  bankName: "",
+  bankCardNo: "",
+  // 鏁欒偛缁忓巻
+  educationList: [createEmptyEducation()],
+  // 宸ヤ綔缁忓巻
+  workExperienceList: [createEmptyWork()],
+  // 绱ф�ヨ仈绯讳汉
+  emergencyContacts: [createEmptyEmergency()],
+  emergencyContact: "",
+  emergencyContactPhone: "",
+  // 鏉愭枡闄勪欢锛堜粎鍓嶇灞曠ず锛�
+  attachments: [],
+});
+
+const state = reactive({
+  form: createDefaultForm(),
+  rules: {
+    staffNo: [{ required: true, message: "璇疯緭鍏ュ憳宸ョ紪鍙�", trigger: "blur" }],
+    staffName: [{ required: true, message: "璇疯緭鍏ュ鍚�", trigger: "blur" }],
+    phone: [{ required: true, message: "璇疯緭鍏ユ墜鏈�", trigger: "blur" }],
+    sex: [{ required: true, message: "璇烽�夋嫨鎬у埆", trigger: "change" }],
+    birthDate: [
+      { required: true, message: "璇烽�夋嫨鍑虹敓鏃ユ湡", trigger: "change" },
+    ],
+    jobNo: [{ required: true, message: "璇疯緭鍏ュ伐鍙�", trigger: "blur" }],
+    staffType: [
+      { required: true, message: "璇烽�夋嫨鍛樺伐绫诲瀷", trigger: "change" },
+    ],
+    entryDate: [
+      { required: true, message: "璇烽�夋嫨鍏ヨ亴鏃ユ湡", trigger: "change" },
+    ],
+    sysDeptId: [
+      { required: true, message: "璇烽�夋嫨閮ㄩ棬", trigger: "change" },
+    ],
+  },
+  postOptions: [],
+  deptOptions: [],
+});
+
+const { form, rules, postOptions, deptOptions } = toRefs(state);
+
+const resetForm = () => {
+  Object.assign(form.value, createDefaultForm());
+  nextTick(() => {
+    formRef.value?.clearValidate();
+  });
+};
+
+const fetchPostOptions = () => {
+  findPostOptions().then((res) => {
+    postOptions.value = res.data || [];
+  });
+};
+
+const fetchDeptOptions = () => {
+  deptTreeSelect().then((response) => {
+    deptOptions.value = filterDisabledDept(
+      JSON.parse(JSON.stringify(response.data || []))
+    );
+  });
+};
+
+function filterDisabledDept(deptList) {
+  return deptList.filter((dept) => {
+    if (dept.disabled) {
+      return false;
+    }
+    if (dept.children && dept.children.length) {
+      dept.children = filterDisabledDept(dept.children);
+    }
+    return true;
+  });
+}
+
+const syncEmergencyToLegacyField = () => {
+  const first = form.value.emergencyContacts?.[0];
+  form.value.emergencyContact = first?.name || "";
+  form.value.emergencyContactPhone = first?.phone || "";
+};
+
 const openDialog = (type, row) => {
   operationType.value = type;
   dialogFormVisible.value = true;
-  if (operationType.value === 'edit') {
-    id.value = row.id
-    staffOnJobInfo(id.value, {}).then(res => {
-      form.value = {...res.data}
-      if (form.value.sysPostId === 0) {
-        form.value.sysPostId = undefined
+  fetchPostOptions();
+  fetchDeptOptions();
+  resetForm();
+  if (type === "edit" && row?.id) {
+    id.value = row.id;
+    staffOnJobInfo(id.value, {}).then((res) => {
+      const d = res.data || {};
+      Object.assign(form.value, {
+        ...form.value,
+        ...d,
+      });
+      if (!Array.isArray(form.value.educationList) || !form.value.educationList.length) {
+        form.value.educationList = [createEmptyEducation()];
       }
-      // 缂栬緫鏃朵篃璁$畻涓�娆″悎鍚屽勾闄�
-      calculateContractTerm();
-    })
-  } else {
-		form.value.id = ''
-	}
+      if (
+        !Array.isArray(form.value.workExperienceList) ||
+        !form.value.workExperienceList.length
+      ) {
+        form.value.workExperienceList = [createEmptyWork()];
+      }
+      if (
+        !Array.isArray(form.value.emergencyContacts) ||
+        !form.value.emergencyContacts.length
+      ) {
+        form.value.emergencyContacts = [createEmptyEmergency()];
+      }
+      if (form.value.sysPostId === 0) {
+        form.value.sysPostId = undefined;
+      }
+      if (form.value.sysDeptId === 0) {
+        form.value.sysDeptId = undefined;
+      }
+    });
+  }
+};
 
-}
 onMounted(() => {
-  fetchPostOptions()
-  fetchDeptOptions()
-})
+  fetchPostOptions();
+  fetchDeptOptions();
+});
 
-const fetchPostOptions = () => {
-  findPostOptions().then(res => {
-    postOptions.value = res.data
-  })
-}
-
-// 鏌ヨ閮ㄩ棬鍒楄〃
-const fetchDeptOptions = () => {
-  deptTreeSelect().then(response => {
-    deptOptions.value = filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
-  })
-}
-
-/** 杩囨护绂佺敤鐨勯儴闂� */
-function filterDisabledDept(deptList) {
-  return deptList.filter(dept => {
-    if (dept.disabled) {
-      return false
-    }
-    if (dept.children && dept.children.length) {
-      dept.children = filterDisabledDept(dept.children)
-    }
-    return true
-  })
-}
-
-// 鎻愪氦浜у搧琛ㄥ崟
 const submitForm = () => {
   if (!form.value.sysPostId) {
-    form.value.sysPostId = 0;
+    form.value.sysPostId = undefined;
   }
-  proxy.$refs.formRef.validate(valid => {
+  if (!form.value.sysDeptId) {
+    form.value.sysDeptId = undefined;
+  }
+  syncEmergencyToLegacyField();
+  formRef.value?.validate((valid) => {
     if (valid) {
-      form.value.staffState = 1
       if (operationType.value === "add") {
-        createStaffOnJob(form.value).then(res => {
+        createStaffOnJob(form.value).then(() => {
           proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
           closeDia();
-        })
+        });
       } else {
-        updateStaffOnJob(id.value, form.value).then(res => {
+        updateStaffOnJob(id.value, form.value).then(() => {
           proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
           closeDia();
-        })
+        });
       }
     }
-  })
-}
-// 璁$畻鍚堝悓骞撮檺
-const calculateContractTerm = () => {
-  if (form.value.contractStartTime && form.value.contractEndTime) {
-    const startDate = new Date(form.value.contractStartTime);
-    const endDate = new Date(form.value.contractEndTime);
-    
-    if (endDate > startDate) {
-      // 璁$畻骞翠唤宸�
-      const yearDiff = endDate.getFullYear() - startDate.getFullYear();
-      const monthDiff = endDate.getMonth() - startDate.getMonth();
-      const dayDiff = endDate.getDate() - startDate.getDate();
-      
-      let years = yearDiff;
-      
-      // 濡傛灉缁撴潫鏃ユ湡鐨勬湀鏃ュ皬浜庡紑濮嬫棩鏈熺殑鏈堟棩锛屽垯鍑忓幓1骞�
-      if (monthDiff < 0 || (monthDiff === 0 && dayDiff < 0)) {
-        years = yearDiff - 1;
-      }
-      
-      form.value.contractTerm = Math.max(0, years);
-    } else {
-      form.value.contractTerm = 0;
-    }
-  } else {
-    form.value.contractTerm = 0;
-  }
+  });
 };
 
-// 鍏抽棴寮规
 const closeDia = () => {
-  proxy.resetForm("formRef");
+  formRef.value?.resetFields();
   dialogFormVisible.value = false;
-  emit('close')
+  emit("close");
 };
+
 defineExpose({
   openDialog,
 });
 </script>
 
 <style scoped>
+.form-dia-body {
+  padding: 0;
+}
 
+.card-title-line {
+  color: #f56c6c;
+  margin-right: 4px;
+}
+
+.form-card {
+  margin-bottom: 16px;
+}
+
+.dialog-footer {
+  text-align: right;
+}
 </style>
\ No newline at end of file

--
Gitblit v1.9.3