From f8b148c77b41b6dca8f469d4c37df2d6410360ee Mon Sep 17 00:00:00 2001
From: tuqin <tuqin@tuqin.cn>
Date: 星期四, 08 十月 2026 16:58:31 +0800
Subject: [PATCH] feat(芯导): 仓储物流出库管理 / 人力资源(离职/在职台账/合同/薪资) 前端

---
 src/views/personnelManagement/dimission/components/formDia.vue               |   23 +
 src/api/personnelManagement/staffOnJob.js                                    |    8 
 src/views/personnelManagement/employeeRecord/index.vue                       |  291 ++++++++--------
 src/api/personnelManagement/contract.js                                      |   30 +
 src/views/inventoryManagement/receiptManagement/index.vue                    |    1 
 src/views/inventoryManagement/issueManagement/index.vue                      |  232 +++++-------
 src/views/inventoryManagement/receiptManagement/components/formDiaManual.vue |    7 
 src/views/personnelManagement/contractManagement/index.vue                   |  438 +++++++++--------------
 8 files changed, 485 insertions(+), 545 deletions(-)

diff --git a/src/api/personnelManagement/contract.js b/src/api/personnelManagement/contract.js
new file mode 100644
index 0000000..9c70e0e
--- /dev/null
+++ b/src/api/personnelManagement/contract.js
@@ -0,0 +1,30 @@
+import request from '@/utils/request'
+
+// 鍚堝悓鍙拌处鍒嗛〉
+export function contractListPage(query) {
+  return request({ url: '/staff/contract/listPage', method: 'get', params: query })
+}
+// 鍚堝悓璇︽儏
+export function contractInfo(id) {
+  return request({ url: '/staff/contract/' + id, method: 'get' })
+}
+// 鏂板鍚堝悓
+export function contractAdd(data) {
+  return request({ url: '/staff/contract/add', method: 'post', data })
+}
+// 淇敼鍚堝悓
+export function contractUpdate(data) {
+  return request({ url: '/staff/contract/update', method: 'post', data })
+}
+// 鍒犻櫎鍚堝悓
+export function contractDel(ids) {
+  return request({ url: '/staff/contract/del', method: 'delete', data: ids })
+}
+// 缁鍚堝悓
+export function contractRenew(id, data) {
+  return request({ url: '/staff/contract/renew/' + id, method: 'post', data })
+}
+// 瑙i櫎鍚堝悓
+export function contractTerminate(id, data) {
+  return request({ url: '/staff/contract/terminate/' + id, method: 'post', data })
+}
diff --git a/src/api/personnelManagement/staffOnJob.js b/src/api/personnelManagement/staffOnJob.js
index 7da5469..3e556db 100644
--- a/src/api/personnelManagement/staffOnJob.js
+++ b/src/api/personnelManagement/staffOnJob.js
@@ -52,3 +52,11 @@
         data: params,
     });
 }
+
+// 鍦ㄨ亴鍙拌处缁熻锛堝湪鑱屼汉鏁� / 钖祫鍚堣锛�
+export function staffOnJobStatistics() {
+    return request({
+        url: "/staff/staffOnJob/statistics",
+        method: "get",
+    });
+}
diff --git a/src/views/inventoryManagement/issueManagement/index.vue b/src/views/inventoryManagement/issueManagement/index.vue
index 92d6073..c5a1236 100644
--- a/src/views/inventoryManagement/issueManagement/index.vue
+++ b/src/views/inventoryManagement/issueManagement/index.vue
@@ -1,5 +1,10 @@
 <template>
   <div class="app-container">
+    <el-tabs v-model="activeTab" @tab-change="handleTabChange" class="out-tabs">
+      <el-tab-pane label="鍙戞枡" name="issue" />
+      <el-tab-pane label="閿�鍞嚭搴�" name="sales" />
+      <el-tab-pane label="閫�璐у嚭搴�" name="purchaseReturn" />
+    </el-tabs>
     <div class="search_form">
       <div>
         <span class="search_title ml10">浜у搧澶х被锛�</span>
@@ -8,6 +13,7 @@
           style="width: 240px"
           placeholder="璇疯緭鍏�"
           clearable
+          @keyup.enter="handleQuery"
         />
         <el-button type="primary" @click="handleQuery" style="margin-left: 10px">鎼滅储</el-button>
       </div>
@@ -21,24 +27,27 @@
         border
         v-loading="tableLoading"
         @selection-change="handleSelectionChange"
-        :expand-row-keys="expandedRowKeys"
         :row-key="row => row.id"
         show-summary
         style="width: 100%"
         :summary-method="summarizeMainTable"
-        height="calc(100vh - 18.5em)"
+        height="calc(100vh - 21em)"
       >
         <el-table-column align="center" type="selection" width="55" />
         <el-table-column align="center" label="搴忓彿" type="index" width="60" />
-        <el-table-column label="鎵规鍙�" prop="code" width="130" show-overflow-tooltip />
+        <el-table-column label="鎵规鍙�" width="150" show-overflow-tooltip>
+          <template #default="scope">{{ scope.row.code || scope.row.inboundBatches }}</template>
+        </el-table-column>
         <el-table-column label="浜у搧澶х被" prop="productCategory" show-overflow-tooltip />
         <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" show-overflow-tooltip />
         <el-table-column label="鍗曚綅" prop="unit" width="70" show-overflow-tooltip />
-        <el-table-column label="鐗╁搧绫诲瀷" prop="itemType" show-overflow-tooltip />
-        <el-table-column label="鍓╀綑搴撳瓨" prop="inboundNum0" width="90" show-overflow-tooltip />
-        <el-table-column fixed="right" label="鎿嶄綔" width="100" align="center">
+        <el-table-column v-if="activeTab === 'issue'" label="鐗╁搧绫诲瀷" prop="itemType" show-overflow-tooltip />
+        <el-table-column v-if="activeTab === 'sales'" label="瀹㈡埛鍚嶇О" prop="customerName" show-overflow-tooltip />
+        <el-table-column v-if="activeTab === 'purchaseReturn'" label="渚涘簲鍟�" prop="supplierName" show-overflow-tooltip />
+        <el-table-column :label="cfg.availLabel" prop="inboundNum0" width="110" show-overflow-tooltip />
+        <el-table-column fixed="right" label="鎿嶄綔" width="110" align="center">
           <template #default="scope">
-            <el-button link type="primary" size="small" @click="openForm(scope.row);">鍙戞枡</el-button>
+            <el-button link type="primary" size="small" @click="openForm(scope.row)">{{ cfg.outLabel }}</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -51,17 +60,20 @@
         @pagination="paginationChange"
       />
     </div>
-    <el-dialog v-model="dialogFormVisible" :title="getDialogTitle()" width="40%" @close="closeDia" draggable>
+    <el-dialog v-model="dialogFormVisible" :title="cfg.dialogTitle" width="40%" @close="closeDia" draggable>
       <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
-			<div>{{getAvailableQuantityText()}}:{{currentRowNum}}</div>
-        <el-form-item :label="getQuantityLabel()" prop="inboundQuantity">
+        <div v-if="activeTab === 'purchaseReturn'" style="margin-bottom: 12px">
+          渚涘簲鍟嗭細{{ currentRow.supplierName || '-' }}
+        </div>
+        <div>{{ cfg.availLabel }}锛歿{ currentRowNum }}</div>
+        <el-form-item :label="cfg.qtyLabel" prop="inboundQuantity">
           <el-input-number :step="0.01" :min="0" :max="currentRowNum" style="width: 100%" v-model="form.inboundQuantity" placeholder="璇疯緭鍏�" clearable />
         </el-form-item>
-        <el-form-item :label="getDateLabel()" prop="inboundTime">
+        <el-form-item :label="cfg.dateLabel" prop="inboundTime">
           <el-date-picker style="width: 100%" v-model="form.inboundTime" value-format="YYYY-MM-DD" format="YYYY-MM-DD"
             type="date" placeholder="璇烽�夋嫨" clearable />
         </el-form-item>
-        <el-form-item :label="getPersonLabel()" prop="nickName">
+        <el-form-item :label="cfg.personLabel" prop="nickName">
           <el-select v-model="form.nickName"
 										 filterable
                      default-first-option
@@ -82,42 +94,76 @@
 
 <script setup>
 import pagination from '@/components/PIMTable/Pagination.vue'
-import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue'
+import { ref, reactive, toRefs, onMounted, computed, getCurrentInstance } from 'vue'
 import { ElMessageBox } from "element-plus";
-import useUserStore from '@/store/modules/user'
 import { userListNoPageByTenantId } from "@/api/system/user.js";
 import {
-	getInPageByCustom
+  getInPageByCustom,
+  getStockInPage,
+  getStockInPageByProduction,
 } from "@/api/inventoryManagement/stockIn.js";
 import {
-    delStockManage,
-    stockOut,
+  stockOut,
 } from "@/api/inventoryManagement/stockManage.js";
 import { getCurrentDate } from "@/utils/index.js";
 
-const userStore = useUserStore()
 const { proxy } = getCurrentInstance()
 const tableData = ref([])
 const selectedRows = ref([])
 const userList = ref([])
 const tableLoading = ref(false)
+const activeTab = ref('issue')
 const page = reactive({
   current: 1,
   size: 100,
 })
 const total = ref(0)
-const fileList = ref([])
+
+// 涓夌鍑哄簱绫诲瀷閰嶇疆锛氬彂鏂�(type=3 鑷畾涔夊嚭搴�)銆侀攢鍞嚭搴�(type=2)銆侀��璐у嚭搴�(type=5 閲囪喘閫�璐у嚭搴�)
+const tabConfig = {
+  issue: {
+    type: 3,
+    outLabel: '鍙戞枡',
+    dialogTitle: '鏂板鍙戞枡',
+    availLabel: '鍙彂鏂欐暟閲�',
+    qtyLabel: '鍙戞枡鏁伴噺锛�',
+    dateLabel: '鍙戞枡鏃ユ湡锛�',
+    personLabel: '鍙戞枡浜猴細',
+    exportUrl: '/stockmanagement/exportTwo',
+    exportName: '鍙戞枡鍙拌处.xlsx',
+  },
+  sales: {
+    type: 2,
+    outLabel: '閿�鍞嚭搴�',
+    dialogTitle: '鏂板閿�鍞嚭搴�',
+    availLabel: '鍙嚭搴撴暟閲�',
+    qtyLabel: '鍑哄簱鏁伴噺锛�',
+    dateLabel: '鍑哄簱鏃ユ湡锛�',
+    personLabel: '缁忔墜浜猴細',
+    exportUrl: '/stockmanagement/exportOne',
+    exportName: '閿�鍞嚭搴撳彴璐�.xlsx',
+  },
+  purchaseReturn: {
+    type: 5,
+    outLabel: '閫�璐у嚭搴�',
+    dialogTitle: '鏂板閫�璐у嚭搴�',
+    availLabel: '鍙��璐ф暟閲�',
+    qtyLabel: '閫�璐ф暟閲忥細',
+    dateLabel: '閫�璐ф棩鏈燂細',
+    personLabel: '缁忔墜浜猴細',
+    exportUrl: '/stockmanagement/exportPurchaseReturn',
+    exportName: '閫�璐у嚭搴撳彴璐�.xlsx',
+  },
+}
+const cfg = computed(() => tabConfig[activeTab.value] || tabConfig.issue)
 
 // 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
 const dialogFormVisible = ref(false)
+const currentRow = ref({})
+const currentRowNum = ref(0)
 const data = reactive({
   searchForm: {
-    inboundQuantity:'',
-    inboundTime:'',
-    nickName: '',
-    userId: '',
-    productCategory:'',
-    // timeStr: getCurrentDate(),
+    productCategory: '',
   },
   form: {
     productrecordId: '',
@@ -130,7 +176,10 @@
 })
 const { searchForm, form, rules } = toRefs(data)
 
-// 鏌ヨ鍒楄〃
+const handleTabChange = () => {
+  page.current = 1
+  getList()
+}
 /** 鎼滅储鎸夐挳鎿嶄綔 */
 const handleQuery = () => {
   page.current = 1
@@ -141,81 +190,57 @@
   page.size = obj.limit;
   getList()
 }
+// 鎸� tab 閫夋嫨"鍙嚭搴撳簱瀛�"鏉ユ簮锛氬彂鏂�=鑷畾涔夊叆搴擄紱閿�鍞嚭搴�=鐢熶骇鍏ュ簱锛涢��璐у嚭搴�=閲囪喘鍏ュ簱
+const fetchSource = (params) => {
+  if (activeTab.value === 'sales') return getStockInPageByProduction(params)
+  if (activeTab.value === 'purchaseReturn') return getStockInPage(params)
+  return getInPageByCustom(params)
+}
 const getList = () => {
   tableLoading.value = true
   const params = { ...page }
   params.productCategory = searchForm.value.productCategory
   params.flag = true
-  const apiCall = getInPageByCustom(params)
-  apiCall.then(res => {
+  fetchSource(params).then(res => {
     tableLoading.value = false
-    tableData.value = res.data.records
+    tableData.value = res.data.records || []
     total.value = res.data.total
   }).catch(() => {
     tableLoading.value = false
   })
 }
 
-const findNodeById = (nodes, productId) => {
-  for (let i = 0; i < nodes.length; i++) {
-    if (nodes[i].value === productId) {
-      return nodes[i].label; // 鎵惧埌鑺傜偣锛岃繑鍥炶鑺傜偣
-    }
-    if (nodes[i].children && nodes[i].children.length > 0) {
-      const foundNode = findNodeById(nodes[i].children, productId);
-      if (foundNode) {
-        return foundNode.label; // 鍦ㄥ瓙鑺傜偣涓壘鍒帮紝杩斿洖璇ヨ妭鐐�
-      }
-    }
-  }
-  return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull
-};
 // 琛ㄦ牸閫夋嫨鏁版嵁
 const handleSelectionChange = (selection) => {
-  // 杩囨护鎺夊瓙鏁版嵁
   selectedRows.value = selection.filter(item => item.id);
-  console.log('selection', selectedRows.value)
 }
-const expandedRowKeys = ref([])
 
 // 涓昏〃鍚堣鏂规硶
 const summarizeMainTable = (param) => {
-  return proxy.summarizeTable(param, ['contractAmount', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice']);
-};
-const currentRowId = ref(null) // 鏂板锛氬瓨鍌ㄥ綋鍓嶆搷浣滅殑琛孖D
-
-const currentRowNum = ref(0)
-const salesLedgerProductId = ref(null);
+  return proxy.summarizeTable(param, ['taxInclusiveTotalPrice', 'taxExclusiveTotalPrice']);
+}
 
 // 鎵撳紑寮规
 const openForm = async (row) => {
   dialogFormVisible.value = true
-  currentRowId.value = row.id
-  currentRowNum.value = row.inboundNum0
-  salesLedgerProductId.value = row.salesLedgerProductId
+  currentRow.value = row || {}
+  currentRowNum.value = row ? row.inboundNum0 : 0
   form.value = {}
-  
   // 鍔犺浇鐢ㄦ埛鍒楄〃
   try {
     const userLists = await userListNoPageByTenantId()
     userList.value = userLists.data
-    
     // 鏉愭枡鍑哄簱榛樿鍙戞枡浜�
     const defaultPersonName = '鍚寸帀姊�'
     const defaultPerson = userList.value.find(user => user.nickName === defaultPersonName)
     const defaultUserId = defaultPerson ? defaultPerson.userId : ''
-    
-    // 鍒濆鍖栬〃鍗曟暟鎹�
     form.value = {
       productrecordId: '',
-      inboundQuantity: currentRowNum.value, // 浣跨敤currentRowNum浣滀负榛樿鍊�
-      inboundTime: getCurrentDate(), // 榛樿褰撳墠鏃ユ湡
-      nickName: defaultUserId, // 鏍规嵁tab绫诲瀷璁剧疆榛樿鍙戣揣浜�
+      inboundQuantity: currentRowNum.value,
+      inboundTime: getCurrentDate(),
+      nickName: defaultUserId,
     }
-    console.log('form',form.value)
   } catch (error) {
-    console.error('鍔犺浇鐢ㄦ埛鍒楄〃澶辫触:', error)
-    // 濡傛灉鍔犺浇澶辫触锛屼娇鐢ㄧ┖鍊煎垵濮嬪寲
     form.value = {
       productrecordId: '',
       inboundQuantity: currentRowNum.value,
@@ -228,21 +253,20 @@
 // 鎻愪氦琛ㄥ崟
 const submitForm = () => {
   let num = Number(form.value.inboundQuantity)
-  if(num <= 0 || num > currentRowNum.value){
+  if (num <= 0 || num > currentRowNum.value) {
     return proxy.$modal.msgWarning("璇峰~鍏ユ湁鏁堟暟瀛�")
   }
   proxy.$refs["formRef"].validate(valid => {
-    if (valid && currentRowId.value) {
+    if (valid && currentRow.value && currentRow.value.id) {
       const outData = {
-        id: currentRowId.value, // 鍘熷璁板綍ID
-        salesLedgerProductId: 0,
+        id: currentRow.value.id, // 鏉ユ簮鍏ュ簱璁板綍ID
+        salesLedgerProductId: currentRow.value.salesLedgerProductId || 0,
         quantity: form.value.inboundQuantity, // 鍑哄簱鏁伴噺
         time: form.value.inboundTime, // 鍑哄簱鏃堕棿
-        userId: form.value.nickName, // 鎿嶄綔浜�
-        type: 3 // 鍑哄簱绫诲瀷锛氳嚜瀹氫箟/鏉愭枡
+        userId: form.value.nickName, // 缁忔墜浜�
+        type: cfg.value.type, // 鍑哄簱绫诲瀷锛�3鍙戞枡 / 2閿�鍞嚭搴� / 5閫�璐у嚭搴�
+        supplierName: currentRow.value.supplierName || '', // 閫�璐у嚭搴�-閫�鍥炰緵搴斿晢
       }
-      console.log(outData)
-
       stockOut(outData).then(res => {
         proxy.$modal.msgSuccess("鎻愪氦鎴愬姛")
         closeDia()
@@ -269,69 +293,19 @@
     type: 'warning',
   }
   ).then(() => {
-    const exportUrl = "/stockin/exportTwo"
-    proxy.download(exportUrl, {}, '鍑哄簱鍙拌处.xlsx')
+    proxy.download(cfg.value.exportUrl, {}, cfg.value.exportName)
   }).catch(() => {
     proxy.$modal.msg("宸插彇娑�")
   })
 }
-// 鍒犻櫎
-const handleDelete = () => {
-  let ids = []
-  if (selectedRows.value.length > 0) {
-    ids = selectedRows.value.map(item => item.id);
-  } else {
-    proxy.$modal.msgWarning('璇烽�夋嫨鏁版嵁')
-    return
-  }
-  ElMessageBox.confirm(
-    '閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�',
-    '瀵煎嚭', {
-    confirmButtonText: '纭',
-    cancelButtonText: '鍙栨秷',
-    type: 'warning',
-  }
-  ).then(() => {
-    delStockManage(ids).then(res => {
-      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛")
-      getList()
-    })
-  }).catch(() => {
-    proxy.$modal.msg("宸插彇娑�")
-  })
-}
-
-// 鏍规嵁tab绫诲瀷鑾峰彇寮规鏍囬
-const getDialogTitle = () => {
-  return '鏂板鍙戞枡';
-};
-
-// 鏍规嵁tab绫诲瀷鑾峰彇鍙嚭搴撴暟閲忔枃鏈�
-const getAvailableQuantityText = () => {
-  return '鍙彂鏂欐暟閲�';
-};
-
-// 鏍规嵁tab绫诲瀷鑾峰彇鏁伴噺瀛楁鏍囩
-const getQuantityLabel = () => {
-  return '鍙戞枡鏁伴噺锛�';
-};
-
-// 鏍规嵁tab绫诲瀷鑾峰彇鏃ユ湡瀛楁鏍囩
-const getDateLabel = () => {
-  return '鍙戞枡鏃ユ湡锛�';
-};
-
-// 鏍规嵁tab绫诲瀷鑾峰彇浜哄憳瀛楁鏍囩
-const getPersonLabel = () => {
-  return '鍙戞枡浜猴細';
-};
 
 onMounted(() => {
   getList()
 })
 </script>
 
-<style scoped lang="scss"></style>
-
-
-
+<style scoped lang="scss">
+.out-tabs {
+  margin-bottom: 6px;
+}
+</style>
diff --git a/src/views/inventoryManagement/receiptManagement/components/formDiaManual.vue b/src/views/inventoryManagement/receiptManagement/components/formDiaManual.vue
index f0f9d75..7561257 100644
--- a/src/views/inventoryManagement/receiptManagement/components/formDiaManual.vue
+++ b/src/views/inventoryManagement/receiptManagement/components/formDiaManual.vue
@@ -63,6 +63,13 @@
             <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="scope.row.taxInclusiveUnitPrice" @change="() => calculateTotalPrice(scope.row)" />
           </template>
         </el-table-column>
+        <el-table-column label="绋庣巼(%)" prop="taxRate" width="130">
+          <template #default="scope">
+            <el-select v-model="scope.row.taxRate" placeholder="璇烽�夋嫨绋庣巼" @change="() => calculateExclusivePrice(scope.row)">
+              <el-option v-for="item in taxRateOptions" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+          </template>
+        </el-table-column>
         <el-table-column
            label="鎬讳环(鍏�)"
            prop="taxInclusiveTotalPrice"
diff --git a/src/views/inventoryManagement/receiptManagement/index.vue b/src/views/inventoryManagement/receiptManagement/index.vue
index 7f1f83c..f0e01c3 100644
--- a/src/views/inventoryManagement/receiptManagement/index.vue
+++ b/src/views/inventoryManagement/receiptManagement/index.vue
@@ -50,6 +50,7 @@
         <el-table-column label="鐗╁搧绫诲瀷" prop="itemType" show-overflow-tooltip />
         <el-table-column label="鍏ュ簱鏁伴噺" prop="inboundNum" width="100" show-overflow-tooltip />
         <el-table-column label="鍓╀綑搴撳瓨" prop="inboundNum0" show-overflow-tooltip />
+        <el-table-column label="绋庣巼(%)" prop="taxRate" width="100" />
         <el-table-column label="鍗曚环(鍏�)" prop="taxInclusiveUnitPrice" width="150" />
         <el-table-column label="鎬讳环(鍏�)" prop="taxInclusiveTotalPrice" width="150" />
         <el-table-column label="鍏ュ簱浜�" prop="createBy" width="80" show-overflow-tooltip />
diff --git a/src/views/personnelManagement/contractManagement/index.vue b/src/views/personnelManagement/contractManagement/index.vue
index 98f0272..5298a4f 100644
--- a/src/views/personnelManagement/contractManagement/index.vue
+++ b/src/views/personnelManagement/contractManagement/index.vue
@@ -3,18 +3,19 @@
     <div class="search_form">
       <div>
         <span class="search_title">濮撳悕锛�</span>
-        <el-input v-model="searchForm.staffName" style="width: 240px" placeholder="璇疯緭鍏ュ鍚嶆悳绱�" @change="handleQuery"
-          clearable :prefix-icon="Search" />
-        <span style="margin-left: 10px" class="search_title">鍚堝悓缁撴潫鏃ユ湡锛�</span>
-        <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
-          placeholder="璇烽�夋嫨" clearable @change="changeDaterange" />
+        <el-input v-model="searchForm.staffName" style="width: 200px" placeholder="璇疯緭鍏ュ鍚嶆悳绱�" @change="handleQuery" clearable :prefix-icon="Search" />
+        <span style="margin-left: 10px" class="search_title">鐘舵�侊細</span>
+        <el-select v-model="searchForm.status" placeholder="鍏ㄩ儴" clearable style="width: 140px" @change="handleQuery">
+          <el-option label="鏈夋晥" :value="0" />
+          <el-option label="宸茬画绛�" :value="1" />
+          <el-option label="宸茶В闄�" :value="2" />
+        </el-select>
         <el-button type="primary" @click="handleQuery" style="margin-left: 10px">鎼滅储</el-button>
       </div>
       <div>
-        <!--        <el-button type="primary" @click="openForm('add')">鏂板鍏ヨ亴</el-button>-->
-<!--        <el-button type="info" @click="handleImport">瀵煎叆</el-button>-->
+        <el-button type="primary" @click="openForm('add')">鏂板鍚堝悓</el-button>
         <el-button @click="handleOut">瀵煎嚭</el-button>
-        <!--        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>-->
+        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
       </div>
     </div>
     <div class="table_list">
@@ -22,308 +23,207 @@
         @selection-change="handleSelectionChange" :tableLoading="tableLoading" @pagination="pagination"
         :total="page.total"></PIMTable>
     </div>
-    <form-dia ref="formDia" @close="handleQuery"></form-dia>
 
-    <!-- 鍚堝悓瀵煎叆瀵硅瘽妗� -->
-    <el-dialog
-      :title="upload.title"
-      v-model="upload.open"
-      width="400px"
-      append-to-body
-    >
-      <el-upload
-        ref="uploadRef"
-        :limit="1"
-        accept=".xlsx, .xls"
-        :headers="upload.headers"
-        :action="upload.url + '?updateSupport=' + upload.updateSupport"
-        :disabled="upload.isUploading"
-        :on-progress="handleFileUploadProgress"
-        :on-success="handleFileSuccess"
-        :auto-upload="false"
-        drag
-      >
-        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
-        <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
-        <template #tip>
-          <div class="el-upload__tip text-center">
-            <span>浠呭厑璁稿鍏ls銆亁lsx鏍煎紡鏂囦欢銆�</span>
-            <!-- <el-link
-              type="primary"
-              :underline="false"
-              style="font-size: 12px; vertical-align: baseline"
-              @click="importTemplate"
-              >涓嬭浇妯℃澘</el-link
-            > -->
-          </div>
-        </template>
-      </el-upload>
+    <!-- 鏂板/缂栬緫鍚堝悓 -->
+    <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '鏂板鍚堝悓' : '缂栬緫鍚堝悓'" width="60%" @close="closeDia">
+      <el-form :model="form" label-width="120px" label-position="top" :rules="rules" ref="formRef">
+        <el-row :gutter="30">
+          <el-col :span="12"><el-form-item label="鍛樺伐濮撳悕锛�" prop="staffName"><el-input v-model="form.staffName" placeholder="璇疯緭鍏�" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="鍛樺伐缂栧彿锛�" prop="staffNo"><el-input v-model="form.staffNo" placeholder="璇疯緭鍏�" /></el-form-item></el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12"><el-form-item label="宀椾綅锛�" prop="postJob"><el-input v-model="form.postJob" placeholder="璇疯緭鍏�" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="鍚堝悓骞撮檺锛�" prop="contractTerm"><el-input-number v-model="form.contractTerm" :min="0" :step="1" :precision="0" style="width:100%" /></el-form-item></el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12"><el-form-item label="绛捐鏃ユ湡锛�" prop="signDate"><el-date-picker v-model="form.signDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" placeholder="璇烽�夋嫨" style="width:100%" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="鍚堝悓寮�濮嬫棩鏈燂細" prop="startDate"><el-date-picker v-model="form.startDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" placeholder="璇烽�夋嫨" style="width:100%" /></el-form-item></el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12"><el-form-item label="鍚堝悓缁撴潫鏃ユ湡锛�" prop="endDate"><el-date-picker v-model="form.endDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" placeholder="璇烽�夋嫨" style="width:100%" /></el-form-item></el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24"><el-form-item label="鍚堝悓鍐呭锛�" prop="contractContent"><el-input v-model="form.contractContent" type="textarea" :rows="4" placeholder="璇疯緭鍏ュ悎鍚屽唴瀹�" /></el-form-item></el-col>
+        </el-row>
+      </el-form>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitFileForm">纭� 瀹�</el-button>
-          <el-button @click="upload.open = false">鍙� 娑�</el-button>
+          <el-button type="primary" @click="submitForm">纭</el-button>
+          <el-button @click="closeDia">鍙栨秷</el-button>
         </div>
       </template>
     </el-dialog>
-    <files-dia ref="filesDia"></files-dia>
+
+    <!-- 缁 -->
+    <el-dialog v-model="renewVisible" title="缁鍚堝悓" width="40%">
+      <el-form :model="renewForm" label-width="140px" label-position="top">
+        <el-form-item label="缁鏃ユ湡锛�"><el-date-picker v-model="renewForm.renewDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" placeholder="璇烽�夋嫨" style="width:100%" /></el-form-item>
+        <el-form-item label="缁鍚庡埌鏈熸棩鏈燂細"><el-date-picker v-model="renewForm.renewEndDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" placeholder="璇烽�夋嫨" style="width:100%" /></el-form-item>
+        <el-form-item label="鍚堝悓骞撮檺锛�"><el-input-number v-model="renewForm.contractTerm" :min="0" :step="1" :precision="0" style="width:100%" /></el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button type="primary" @click="submitRenew">纭缁</el-button>
+        <el-button @click="renewVisible = false">鍙栨秷</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 瑙i櫎 -->
+    <el-dialog v-model="terminateVisible" title="瑙i櫎鍚堝悓" width="40%">
+      <el-form :model="terminateForm" label-width="140px" label-position="top">
+        <el-form-item label="瑙i櫎鏃ユ湡锛�"><el-date-picker v-model="terminateForm.terminateDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" placeholder="璇烽�夋嫨" style="width:100%" /></el-form-item>
+        <el-form-item label="瑙i櫎鍘熷洜锛�"><el-input v-model="terminateForm.terminateReason" type="textarea" :rows="3" placeholder="璇疯緭鍏ヨВ闄ゅ師鍥�" /></el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button type="primary" @click="submitTerminate">纭瑙i櫎</el-button>
+        <el-button @click="terminateVisible = false">鍙栨秷</el-button>
+      </template>
+    </el-dialog>
+
+    <form-dia ref="formDia" @close="handleQuery"></form-dia>
   </div>
 </template>
 
 <script setup>
 import { Search } from "@element-plus/icons-vue";
-import { onMounted, ref } from "vue";
-import FormDia from "@/views/personnelManagement/contractManagement/components/formDia.vue";
+import { onMounted, ref, reactive, toRefs, getCurrentInstance, nextTick } from "vue";
 import { ElMessageBox } from "element-plus";
-import { staffOnJobListPage } from "@/api/personnelManagement/employeeRecord.js";
+import FormDia from "@/views/personnelManagement/contractManagement/components/formDia.vue";
+import {
+  contractListPage, contractAdd, contractUpdate, contractDel, contractRenew, contractTerminate,
+} from "@/api/personnelManagement/contract.js";
 import dayjs from "dayjs";
-import { getToken } from "@/utils/auth.js";
-import FilesDia from "./filesDia.vue";
-const data = reactive({
-  searchForm: {
-    staffName: "",
-    entryDate: [
-      dayjs().format("YYYY-MM-DD"),
-      dayjs().add(1, "day").format("YYYY-MM-DD"),
-    ], // 褰曞叆鏃ユ湡
-    entryDateStart: dayjs().format("YYYY-MM-DD"),
-    entryDateEnd: dayjs().add(1, "day").format("YYYY-MM-DD"),
-  },
-});
+
+const { proxy } = getCurrentInstance();
+const data = reactive({ searchForm: { staffName: "", status: undefined } });
 const { searchForm } = toRefs(data);
+
+const statusText = (s) => (s == 0 ? "鏈夋晥" : s == 1 ? "宸茬画绛�" : s == 2 ? "宸茶В闄�" : "");
+const statusType = (s) => (s == 0 ? "primary" : s == 1 ? "warning" : s == 2 ? "danger" : "");
+
 const tableColumn = ref([
+  { label: "鍛樺伐缂栧彿", prop: "staffNo" },
+  { label: "鍛樺伐濮撳悕", prop: "staffName" },
+  { label: "宀椾綅", prop: "postJob" },
+  { label: "绛捐鏃ユ湡", prop: "signDate", width: 120 },
+  { label: "鍚堝悓寮�濮嬫棩鏈�", prop: "startDate", width: 120 },
+  { label: "鍚堝悓缁撴潫鏃ユ湡", prop: "endDate", width: 120 },
+  { label: "鍚堝悓骞撮檺", prop: "contractTerm", width: 90 },
+  { label: "鍚堝悓鍐呭", prop: "contractContent", showOverflowTooltip: true },
   {
-    label: "鐘舵��",
-    prop: "staffState",
-    dataType: "tag",
-    formatData: (params) => {
-      if (params == 0) {
-        return "绂昏亴";
-      } else if (params == 1) {
-        return "鍦ㄨ亴";
-      } else {
-        return null;
-      }
-    },
-    formatType: (params) => {
-      if (params == 0) {
-        return "danger";
-      } else if (params == 1) {
-        return "primary";
-      } else {
-        return null;
-      }
-    },
+    label: "鐘舵��", prop: "status", dataType: "tag",
+    formatData: (p) => statusText(p), formatType: (p) => statusType(p),
   },
+  { label: "缁鏃ユ湡", prop: "renewDate", width: 120 },
+  { label: "瑙i櫎鏃ユ湡", prop: "terminateDate", width: 120 },
   {
-    label: "鍛樺伐缂栧彿",
-    prop: "staffNo",
-  },
-  {
-    label: "濮撳悕",
-    prop: "staffName",
-  },
-  {
-    label: "鎬у埆",
-    prop: "sex",
-  },
-  {
-    label: "绫嶈疮",
-    prop: "nativePlace",
-  },
-  {
-    label: "宀椾綅",
-    prop: "postJob",
-  },
-  {
-    label: "瀹跺涵浣忓潃",
-    prop: "adress",
-    width: 200
-  },
-  {
-    label: "绗竴瀛﹀巻",
-    prop: "firstStudy",
-  },
-  {
-    label: "涓撲笟",
-    prop: "profession",
-    width: 100
-  },
-  {
-    label: "韬唤璇佸彿",
-    prop: "identityCard",
-    width: 200
-  },
-  {
-    label: "骞撮緞",
-    prop: "age",
-  },
-  {
-    label: "鑱旂郴鐢佃瘽",
-    prop: "phone",
-    width: 150
-  },
-  {
-    label: "绱ф�ヨ仈绯讳汉",
-    prop: "emergencyContact",
-    width: 120
-  },
-  {
-    label: "绱ф�ヨ仈绯讳汉鐢佃瘽",
-    prop: "emergencyContactPhone",
-    width: 150
-  },
-  {
-    label: "鍚堝悓骞撮檺",
-    prop: "contractTerm",
-  },
-  // {
-  //   label: "鍚堝悓寮�濮嬫棩鏈�",
-  //   prop: "contractStartTime",
-  //   width: 120
-  // },
-  {
-    label: "鍚堝悓缁撴潫鏃ユ湡",
-    prop: "contractExpireTime",
-    width: 120
-  },
-  {
-    dataType: "action",
-    label: "鎿嶄綔",
-    align: "center",
-    fixed: 'right',
-    width: 120,
+    dataType: "action", label: "鎿嶄綔", align: "center", fixed: "right", width: 200,
     operation: [
-      {
-        name: "璇︽儏",
-        type: "text",
-        clickFun: (row) => {
-          openForm("edit", row);
-        },
-      },
-      {
-        name: "闄勪欢",
-        type: "text",
-        clickFun: (row) => {
-          openFilesFormDia(row);
-        },
-      },
+      { name: "缂栬緫", type: "text", clickFun: (row) => openForm("edit", row) },
+      { name: "缁", type: "text", clickFun: (row) => openRenew(row) },
+      { name: "瑙i櫎", type: "text", clickFun: (row) => openTerminate(row) },
     ],
   },
 ]);
-const filesDia = ref()
+
 const tableData = ref([]);
 const selectedRows = ref([]);
 const tableLoading = ref(false);
-const page = reactive({
-  current: 1,
-  size: 100,
-  total: 0,
-});
-const formDia = ref()
-const { proxy } = getCurrentInstance()
+const page = reactive({ current: 1, size: 100, total: 0 });
+const formDia = ref();
 
-const changeDaterange = (value) => {
-  searchForm.value.entryDateStart = undefined;
-  searchForm.value.entryDateEnd = undefined;
-  if (value) {
-    searchForm.value.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
-    searchForm.value.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
+const dialogFormVisible = ref(false);
+const operationType = ref("");
+const formRef = ref();
+const form = ref({});
+const rules = {
+  staffName: [{ required: true, message: "璇疯緭鍏ュ憳宸ュ鍚�", trigger: "blur" }],
+  signDate: [{ required: true, message: "璇烽�夋嫨绛捐鏃ユ湡", trigger: "change" }],
+};
+
+const openForm = (type, row) => {
+  operationType.value = type;
+  if (type === "add") {
+    form.value = { status: 0, contractTerm: 1 };
+  } else {
+    form.value = { ...row };
   }
-  getList();
+  dialogFormVisible.value = true;
 };
-// 鎵撳紑闄勪欢寮规
-const openFilesFormDia = (row) => {
-  console.log(row)
-  nextTick(() => {
-    filesDia.value?.openDialog( row,'鍚堝悓')
-  })
+const closeDia = () => { proxy.resetForm("formRef"); dialogFormVisible.value = false; };
+const submitForm = () => {
+  formRef.value.validate((valid) => {
+    if (!valid) return;
+    const payload = { ...form.value };
+    const p = operationType.value === "add" ? contractAdd(payload) : contractUpdate(payload);
+    p.then(() => {
+      proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+      closeDia();
+      getList();
+    });
+  });
 };
-// 鏌ヨ鍒楄〃
-/** 鎼滅储鎸夐挳鎿嶄綔 */
-const handleQuery = () => {
-  page.current = 1;
-  getList();
+
+const renewVisible = ref(false);
+const renewForm = ref({});
+const currentId = ref(null);
+const openRenew = (row) => {
+  currentId.value = row.id;
+  renewForm.value = { renewDate: dayjs().format("YYYY-MM-DD"), renewEndDate: row.endDate, contractTerm: row.contractTerm };
+  renewVisible.value = true;
 };
-const pagination = (obj) => {
-  page.current = obj.page;
-  page.size = obj.limit;
-  getList();
+const submitRenew = () => {
+  contractRenew(currentId.value, renewForm.value).then(() => {
+    proxy.$modal.msgSuccess("缁鎴愬姛");
+    renewVisible.value = false;
+    getList();
+  });
 };
+
+const terminateVisible = ref(false);
+const terminateForm = ref({});
+const openTerminate = (row) => {
+  currentId.value = row.id;
+  terminateForm.value = { terminateDate: dayjs().format("YYYY-MM-DD"), terminateReason: "" };
+  terminateVisible.value = true;
+};
+const submitTerminate = () => {
+  contractTerminate(currentId.value, terminateForm.value).then(() => {
+    proxy.$modal.msgSuccess("瑙i櫎鎴愬姛");
+    terminateVisible.value = false;
+    getList();
+  });
+};
+
+const handleQuery = () => { page.current = 1; getList(); };
+const pagination = (obj) => { page.current = obj.page; page.size = obj.limit; getList(); };
 const getList = () => {
   tableLoading.value = true;
-  const params = { ...searchForm.value, ...page };
-  params.entryDate = undefined
-  staffOnJobListPage(params).then(res => {
+  contractListPage({ ...searchForm.value, ...page }).then((res) => {
     tableLoading.value = false;
-    tableData.value = res.data.records
+    tableData.value = res.data.records;
     page.total = res.data.total;
-  }).catch(err => {
-    tableLoading.value = false;
-  })
+  }).catch(() => { tableLoading.value = false; });
 };
-// 琛ㄦ牸閫夋嫨鏁版嵁
-const handleSelectionChange = (selection) => {
-  selectedRows.value = selection;
-};
+const handleSelectionChange = (selection) => { selectedRows.value = selection; };
 
-// 鎵撳紑寮规
-const openForm = (type, row) => {
-  nextTick(() => {
-    formDia.value?.openDialog(type, row)
-  })
+const handleDelete = () => {
+  if (!selectedRows.value.length) { proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁"); return; }
+  const ids = selectedRows.value.map((i) => i.id);
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎", {
+    confirmButtonText: "纭", cancelButtonText: "鍙栨秷", type: "warning",
+  }).then(() => {
+    contractDel(ids).then(() => { proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛"); getList(); });
+  }).catch(() => { proxy.$modal.msg("宸插彇娑�"); });
 };
-// 瀵煎嚭
 const handleOut = () => {
   ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
-    confirmButtonText: "纭",
-    cancelButtonText: "鍙栨秷",
-    type: "warning",
-  })
-    .then(() => {
-      proxy.download("/staff/staffOnJob/export", {}, "鍚堝悓绠$悊.xlsx");
-    })
-    .catch(() => {
-      proxy.$modal.msg("宸插彇娑�");
-    });
+    confirmButtonText: "纭", cancelButtonText: "鍙栨秷", type: "warning",
+  }).then(() => {
+    proxy.download("/staff/contract/export", { ...searchForm.value }, "鍚堝悓绠$悊.xlsx");
+  }).catch(() => { proxy.$modal.msg("宸插彇娑�"); });
 };
-const upload = reactive({
-  // 鏄惁鏄剧ず寮瑰嚭灞傦紙鍚堝悓瀵煎叆锛�
-  open: false,
-  // 寮瑰嚭灞傛爣棰橈紙鍚堝悓瀵煎叆锛�
-  title: "",
-  // 鏄惁绂佺敤涓婁紶
-  isUploading: false,
-  // 鏄惁鏇存柊宸茬粡瀛樺湪鐨勭敤鎴锋暟鎹�
-  updateSupport: 1,
-  // 璁剧疆涓婁紶鐨勮姹傚ご閮�
-  headers: { Authorization: "Bearer " + getToken() },
-  // 涓婁紶鐨勫湴鍧�
-  url: import.meta.env.VITE_APP_BASE_API + "/staff/staffOnJob/import",
-});
-/** 瀵煎叆鎸夐挳鎿嶄綔 */
-function handleImport() {
-  upload.title = "鍚堝悓瀵煎叆";
-  upload.open = true;
-}
-/** 鎻愪氦涓婁紶鏂囦欢 */
-function submitFileForm() {
-  console.log(upload.url + '?updateSupport=' + upload.updateSupport)
-  proxy.$refs["uploadRef"].submit();
-}
-/**鏂囦欢涓婁紶涓鐞� */
-const handleFileUploadProgress = (event, file, fileList) => {
-  upload.isUploading = true;
-};
-/** 鏂囦欢涓婁紶鎴愬姛澶勭悊 */
-const handleFileSuccess = (response, file, fileList) => {
-  upload.open = false;
-  upload.isUploading = false;
-  proxy.$refs["uploadRef"].handleRemove(file);
-  getList();
-};
-onMounted(() => {
-  getList();
-});
+
+onMounted(() => { getList(); });
 </script>
 
 <style scoped></style>
diff --git a/src/views/personnelManagement/dimission/components/formDia.vue b/src/views/personnelManagement/dimission/components/formDia.vue
index f63b011..ff7863d 100644
--- a/src/views/personnelManagement/dimission/components/formDia.vue
+++ b/src/views/personnelManagement/dimission/components/formDia.vue
@@ -132,6 +132,25 @@
             </el-form-item>
           </el-col>
         </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="绂昏亴鏃ユ湡锛�" prop="leaveDate">
+              <el-date-picker v-model="form.leaveDate" type="date" placeholder="璇烽�夋嫨绂昏亴鏃ユ湡" value-format="YYYY-MM-DD" format="YYYY-MM-DD" clearable style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="绂昏亴鍘熷洜锛�" prop="leaveReason">
+              <el-input v-model="form.leaveReason" placeholder="璇疯緭鍏ョ鑱屽師鍥�" clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="宸ヤ綔浜ゆ帴鎯呭喌锛�" prop="handoverInfo">
+              <el-input v-model="form.handoverInfo" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ伐浣滀氦鎺ユ儏鍐�" />
+            </el-form-item>
+          </el-col>
+        </el-row>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
@@ -170,6 +189,9 @@
     contractStartTime: "",
     contractEndTime: "",
     staffState: "",
+    leaveDate: "",
+    leaveReason: "",
+    handoverInfo: "",
   },
   rules: {
     staffNo: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" },],
@@ -188,6 +210,7 @@
     contractTerm: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
     contractStartTime: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
     contractEndTime: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    leaveDate: [{ required: true, message: "璇烽�夋嫨绂昏亴鏃ユ湡", trigger: "change" }],
   },
 });
 const { form, rules } = toRefs(data);
diff --git a/src/views/personnelManagement/employeeRecord/index.vue b/src/views/personnelManagement/employeeRecord/index.vue
index 6965e96..46be361 100644
--- a/src/views/personnelManagement/employeeRecord/index.vue
+++ b/src/views/personnelManagement/employeeRecord/index.vue
@@ -19,10 +19,13 @@
         >
       </div>
       <div>
-<!--        <el-button type="primary" @click="openForm('add')">鏂板鍏ヨ亴</el-button>-->
+        <el-button type="primary" @click="openEdit('add')">鏂板鍛樺伐</el-button>
         <el-button @click="handleOut">瀵煎嚭</el-button>
-<!--        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>-->
       </div>
+    </div>
+    <div class="stat_bar">
+      <span>鍦ㄨ亴浜烘暟锛�<b>{{ stats.onJobCount }}</b></span>
+      <span style="margin-left: 24px">钖祫鍚堣锛�<b>{{ stats.salaryTotal }}</b></span>
     </div>
     <div class="table_list">
       <PIMTable
@@ -37,25 +40,56 @@
           :total="page.total"
       ></PIMTable>
     </div>
+
+    <!-- 缂栬緫/鏂板鍦ㄨ亴鍛樺伐 -->
+    <el-dialog v-model="editVisible" :title="editType === 'add' ? '鏂板鍦ㄨ亴鍛樺伐' : '缂栬緫鍦ㄨ亴鍛樺伐'" width="60%" @close="closeEdit">
+      <el-form :model="editForm" label-width="120px" label-position="top" :rules="editRules" ref="editFormRef">
+        <el-row :gutter="30">
+          <el-col :span="12"><el-form-item label="濮撳悕锛�" prop="staffName"><el-input v-model="editForm.staffName" placeholder="璇疯緭鍏�" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="鍛樺伐缂栧彿锛�" prop="staffNo"><el-input v-model="editForm.staffNo" placeholder="璇疯緭鍏�" /></el-form-item></el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12"><el-form-item label="宀椾綅锛�" prop="postJob"><el-input v-model="editForm.postJob" placeholder="璇疯緭鍏�" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="鑱旂郴鐢佃瘽锛�" prop="phone"><el-input v-model="editForm.phone" placeholder="璇疯緭鍏�" /></el-form-item></el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12"><el-form-item label="鍏ヨ亴鏃堕棿锛�" prop="entryDate"><el-date-picker v-model="editForm.entryDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" placeholder="璇烽�夋嫨" style="width:100%" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="钖祫锛�" prop="salary"><el-input-number v-model="editForm.salary" :min="0" :precision="2" :step="100" style="width:100%" /></el-form-item></el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12"><el-form-item label="鍚堝悓骞撮檺锛�" prop="contractTerm"><el-input v-model="editForm.contractTerm" placeholder="璇疯緭鍏�" /></el-form-item></el-col>
+          <el-col :span="12"><el-form-item label="鍚堝悓缁撴潫鏃ユ湡锛�" prop="contractExpireTime"><el-date-picker v-model="editForm.contractExpireTime" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" placeholder="璇烽�夋嫨" style="width:100%" /></el-form-item></el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitEdit">纭</el-button>
+          <el-button @click="editVisible = false">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
     <form-dia ref="formDia" @close="handleQuery"></form-dia>
   </div>
 </template>
 
 <script setup>
 import { Search } from "@element-plus/icons-vue";
-import {onMounted, ref} from "vue";
+import { onMounted, reactive, ref, toRefs, getCurrentInstance, nextTick } from "vue";
 import FormDia from "@/views/personnelManagement/employeeRecord/components/formDia.vue";
-import {ElMessageBox} from "element-plus";
-import {staffOnJobListPage} from "@/api/personnelManagement/employeeRecord.js";
+import { ElMessageBox } from "element-plus";
+import { staffOnJobListPage } from "@/api/personnelManagement/employeeRecord.js";
+import { createStaffOnJob, updateStaffOnJob, staffOnJobStatistics } from "@/api/personnelManagement/staffOnJob.js";
 import dayjs from "dayjs";
 
+const { proxy } = getCurrentInstance();
 const data = reactive({
   searchForm: {
     staffName: "",
     entryDate: [
       dayjs().format("YYYY-MM-DD"),
       dayjs().add(1, "day").format("YYYY-MM-DD"),
-    ], // 褰曞叆鏃ユ湡
+    ],
     entryDateStart: dayjs().format("YYYY-MM-DD"),
     entryDateEnd: dayjs().add(1, "day").format("YYYY-MM-DD"),
   },
@@ -66,123 +100,97 @@
     label: "鐘舵��",
     prop: "staffState",
     dataType: "tag",
-    formatData: (params) => {
-      if (params == 0) {
-        return "绂昏亴";
-      } else if (params == 1) {
-        return "鍦ㄨ亴";
-      } else {
-        return null;
-      }
-    },
-    formatType: (params) => {
-      if (params == 0) {
-        return "danger";
-      } else if (params == 1) {
-        return "primary";
-      } else {
-        return null;
-      }
-    },
+    formatData: (params) => (params == 0 ? "绂昏亴" : params == 1 ? "鍦ㄨ亴" : null),
+    formatType: (params) => (params == 0 ? "danger" : params == 1 ? "primary" : null),
   },
-  {
-    label: "鍛樺伐缂栧彿",
-    prop: "staffNo",
-  },
-  {
-    label: "濮撳悕",
-    prop: "staffName",
-  },
-  {
-    label: "鎬у埆",
-    prop: "sex",
-  },
-  {
-    label: "绫嶈疮",
-    prop: "nativePlace",
-  },
-  {
-    label: "宀椾綅",
-    prop: "postJob",
-  },
-  {
-    label: "瀹跺涵浣忓潃",
-    prop: "adress",
-    width:200
-  },
-  {
-    label: "绗竴瀛﹀巻",
-    prop: "firstStudy",
-  },
-  {
-    label: "涓撲笟",
-    prop: "profession",
-    width:100
-  },
-  {
-    label: "韬唤璇佸彿",
-    prop: "identityCard",
-    width:200
-  },
-  {
-    label: "骞撮緞",
-    prop: "age",
-  },
-  {
-    label: "鑱旂郴鐢佃瘽",
-    prop: "phone",
-    width:150
-  },
-  {
-    label: "绱ф�ヨ仈绯讳汉",
-    prop: "emergencyContact",
-    width: 120
-  },
-  {
-    label: "绱ф�ヨ仈绯讳汉鐢佃瘽",
-    prop: "emergencyContactPhone",
-    width:150
-  },
-  {
-    label: "鍚堝悓骞撮檺",
-    prop: "contractTerm",
-  },
-  // {
-  //   label: "鍚堝悓寮�濮嬫棩鏈�",
-  //   prop: "contractStartTime",
-  //   width: 120
-  // },
-  {
-    label: "鍚堝悓缁撴潫鏃ユ湡",
-    prop: "contractExpireTime",
-    width: 120
-  },
+  { label: "鍛樺伐缂栧彿", prop: "staffNo" },
+  { label: "濮撳悕", prop: "staffName" },
+  { label: "鎬у埆", prop: "sex" },
+  { label: "绫嶈疮", prop: "nativePlace" },
+  { label: "宀椾綅", prop: "postJob" },
+  { label: "鍏ヨ亴鏃堕棿", prop: "entryDate", width: 120 },
+  { label: "钖祫", prop: "salary" },
+  { label: "瀹跺涵浣忓潃", prop: "adress", width: 200 },
+  { label: "绗竴瀛﹀巻", prop: "firstStudy" },
+  { label: "涓撲笟", prop: "profession", width: 100 },
+  { label: "韬唤璇佸彿", prop: "identityCard", width: 200 },
+  { label: "骞撮緞", prop: "age" },
+  { label: "鑱旂郴鐢佃瘽", prop: "phone", width: 150 },
+  { label: "鍚堝悓骞撮檺", prop: "contractTerm" },
+  { label: "鍚堝悓缁撴潫鏃ユ湡", prop: "contractExpireTime", width: 120 },
   {
     dataType: "action",
     label: "鎿嶄綔",
     align: "center",
     fixed: 'right',
+    width: 120,
     operation: [
-      {
-        name: "璇︽儏",
-        type: "text",
-        clickFun: (row) => {
-          openForm("edit", row);
-        },
-      },
+      { name: "璇︽儏", type: "text", clickFun: (row) => openForm("edit", row) },
+      { name: "缂栬緫", type: "text", clickFun: (row) => openEdit("edit", row) },
     ],
   },
 ]);
 const tableData = ref([]);
 const selectedRows = ref([]);
 const tableLoading = ref(false);
-const page = reactive({
-  current: 1,
-  size: 100,
-  total: 0
-});
-const formDia = ref()
-const { proxy } = getCurrentInstance()
+const page = reactive({ current: 1, size: 100, total: 0 });
+const formDia = ref();
+
+// 缁熻
+const stats = reactive({ onJobCount: 0, salaryTotal: 0 });
+const getStats = () => {
+  staffOnJobStatistics().then((res) => {
+    stats.onJobCount = res.data.onJobCount;
+    stats.salaryTotal = res.data.salaryTotal;
+  });
+};
+
+// 缂栬緫/鏂板
+const editVisible = ref(false);
+const editType = ref("edit");
+const editFormRef = ref();
+const editForm = ref({});
+const editRules = {
+  staffName: [{ required: true, message: "璇疯緭鍏ュ鍚�", trigger: "blur" }],
+  staffNo: [{ required: true, message: "璇疯緭鍏ュ憳宸ョ紪鍙�", trigger: "blur" }],
+};
+const openEdit = (type, row) => {
+  editType.value = type;
+  if (type === "add") {
+    editForm.value = { staffState: 1, salary: 0 };
+  } else {
+    editForm.value = { ...row };
+  }
+  editVisible.value = true;
+};
+const closeEdit = () => {
+  proxy.resetForm("editFormRef");
+  editVisible.value = false;
+};
+const submitEdit = () => {
+  editFormRef.value.validate((valid) => {
+    if (!valid) return;
+    const payload = { ...editForm.value };
+    if (editType.value === "add") {
+      payload.staffState = 1;
+      delete payload.id;
+      createStaffOnJob(payload).then(() => {
+        proxy.$modal.msgSuccess("鏂板鎴愬姛");
+        closeEdit();
+        handleQuery();
+        getStats();
+      });
+    } else {
+      const id = payload.id;
+      updateStaffOnJob(id, payload).then(() => {
+        proxy.$modal.msgSuccess("淇濆瓨鎴愬姛");
+        closeEdit();
+        handleQuery();
+        getStats();
+      });
+    }
+  });
+};
 
 const changeDaterange = (value) => {
   searchForm.value.entryDateStart = undefined;
@@ -193,57 +201,46 @@
   }
   getList();
 };
-// 鏌ヨ鍒楄〃
-/** 鎼滅储鎸夐挳鎿嶄綔 */
-const handleQuery = () => {
-  page.current = 1;
-  getList();
-};
-const pagination = (obj) => {
-  page.current = obj.page;
-  page.size = obj.limit;
-  getList();
-};
+const handleQuery = () => { page.current = 1; getList(); };
+const pagination = (obj) => { page.current = obj.page; page.size = obj.limit; getList(); };
 const getList = () => {
   tableLoading.value = true;
   const params = { ...searchForm.value, ...page };
-  params.entryDate = undefined
-  staffOnJobListPage({...params, staffState: 1}).then(res => {
+  params.entryDate = undefined;
+  staffOnJobListPage({ ...params, staffState: 1 }).then((res) => {
     tableLoading.value = false;
-    tableData.value = res.data.records
+    tableData.value = res.data.records;
     page.total = res.data.total;
-  }).catch(err => {
-    tableLoading.value = false;
-  })
+  }).catch(() => { tableLoading.value = false; });
 };
-// 琛ㄦ牸閫夋嫨鏁版嵁
-const handleSelectionChange = (selection) => {
-  selectedRows.value = selection;
-};
+const handleSelectionChange = (selection) => { selectedRows.value = selection; };
 
-// 鎵撳紑寮规
 const openForm = (type, row) => {
-  nextTick(() => {
-    formDia.value?.openDialog(type, row)
-  })
+  nextTick(() => { formDia.value?.openDialog(type, row); });
 };
-// 瀵煎嚭
 const handleOut = () => {
   ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
-    confirmButtonText: "纭",
-    cancelButtonText: "鍙栨秷",
-    type: "warning",
-  })
-      .then(() => {
-        proxy.download("/staff/staffOnJob/export", {staffState: 1}, "鍦ㄨ亴鍛樺伐鍙拌处.xlsx");
-      })
-      .catch(() => {
-        proxy.$modal.msg("宸插彇娑�");
-      });
+    confirmButtonText: "纭", cancelButtonText: "鍙栨秷", type: "warning",
+  }).then(() => {
+    proxy.download("/staff/staffOnJob/export", { staffState: 1 }, "鍦ㄨ亴鍛樺伐鍙拌处.xlsx");
+  }).catch(() => { proxy.$modal.msg("宸插彇娑�"); });
 };
 onMounted(() => {
   getList();
+  getStats();
 });
 </script>
 
-<style scoped></style>
+<style scoped>
+.stat_bar {
+  margin: 6px 0 10px;
+  padding: 8px 12px;
+  background: #f0f1f5;
+  border-radius: 4px;
+  font-size: 14px;
+}
+.stat_bar b {
+  color: #409eff;
+  font-size: 16px;
+}
+</style>

--
Gitblit v1.9.3