From db42d47f5692ef64e5436c5a6d29dcb537b44596 Mon Sep 17 00:00:00 2001
From: zouyu <2723363702@qq.com>
Date: 星期一, 26 一月 2026 16:36:13 +0800
Subject: [PATCH] 浪潮对接单点登录:mis调整

---
 src/views/personnelManagement/scheduling/index.vue |  622 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 622 insertions(+), 0 deletions(-)

diff --git a/src/views/personnelManagement/scheduling/index.vue b/src/views/personnelManagement/scheduling/index.vue
new file mode 100644
index 0000000..19d2062
--- /dev/null
+++ b/src/views/personnelManagement/scheduling/index.vue
@@ -0,0 +1,622 @@
+<template>
+  <div class="app-container scheduling-container">
+    <!-- 绛涢�夊尯鍩� -->
+    <div class="filter-section">
+      <el-form :inline="true" :model="filterForm" class="filter-form">
+        <el-form-item label="鍛樺伐濮撳悕锛�">
+          <el-input
+              v-model="filterForm.staffName"
+              placeholder="璇疯緭鍏ュ憳宸ュ鍚�"
+              clearable
+              style="width: 150px"
+          />
+        </el-form-item>
+        <el-form-item label="鐝绫诲瀷锛�">
+          <el-select v-model="filterForm.shiftType" placeholder="璇烽�夋嫨鐝" clearable style="width: 120px">
+            <el-option v-for="item in shift_type" :label="item.label" :value="item.value" :key="item.value"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鏃ユ湡鑼冨洿锛�">
+          <el-date-picker
+              v-model="filterForm.dateRange"
+              type="daterange"
+              range-separator="鑷�"
+              start-placeholder="寮�濮嬫棩鏈�"
+              end-placeholder="缁撴潫鏃ユ湡"
+              format="YYYY-MM-DD"
+              value-format="YYYY-MM-DD"
+              style="width: 250px"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleFilter">
+            <el-icon><Search/></el-icon>
+            绛涢��
+          </el-button>
+          <el-button @click="resetFilter">
+            <el-icon><Refresh/></el-icon>
+            閲嶇疆
+          </el-button>
+          <el-button @click="handleExport">
+            <el-icon><Download/></el-icon>
+            瀵煎嚭
+          </el-button>
+          <el-button type="primary" @click="openScheduleDialog('add')">
+          <el-icon><Plus/></el-icon>
+          鏂板鎺掔彮
+        </el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <!-- 鎺掔彮琛ㄦ牸 -->
+    <div class="table-section">
+      <el-table
+          :data="scheduleList"
+          border
+          :loading="tableLoading"
+          stripe
+          style="width: 100%"
+          height="calc(100vh - 18.5em)"
+          @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="55"/>
+        <el-table-column prop="staffName" label="鍛樺伐濮撳悕" width="120"/>
+        <el-table-column prop="staffNo" label="鍛樺伐宸ュ彿" width="100"/>
+        <el-table-column prop="department" label="閮ㄩ棬" width="120">
+          <template #default="scope">
+              {{ (department_type.find(i => i.value === String(scope.row.department)) || {}).label }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="shiftType" label="鐝绫诲瀷" width="100">
+          <template #default="scope">
+            <el-tag :type="getShiftTagType(scope.row.shiftType)">
+              {{ (shift_type.find(i => i.value === String(scope.row.shiftType)) || {}).label }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="workDate" label="宸ヤ綔鏃ユ湡" width="120"/>
+        <el-table-column prop="startTime" label="寮�濮嬫椂闂�" width="100"/>
+        <el-table-column prop="endTime" label="缁撴潫鏃堕棿" width="100"/>
+        <el-table-column prop="workHours" label="宸ヤ綔鏃堕暱" width="100">
+          <template #default="scope">
+            {{ scope.row.workHours }}灏忔椂
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="鐘舵��" width="100">
+          <template #default="scope">
+            <el-tag :type="getStatusTagType(scope.row.status)">
+              {{ (schedule_status.find(i => i.value === String(scope.row.status)) || {}).label }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="remark" label="澶囨敞" min-width="150"/>
+        <el-table-column label="鎿嶄綔" width="200" fixed="right">
+          <template #default="scope">
+            <el-button
+                type="primary"
+                size="small"
+                @click="openScheduleDialog('edit', scope.row)"
+            >
+              缂栬緫
+            </el-button>
+            <el-button
+                type="danger"
+                size="small"
+                @click="handleDelete(scope.row)"
+            >
+              鍒犻櫎
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+        <pagination
+            v-if="tableCount > 0"
+            :total="tableCount"
+            :page="filterForm.current"
+            :limit="filterForm.size"
+            @pagination="paginationChange"
+        />
+    </div>
+
+    <!-- 鎵归噺鎿嶄綔 -->
+    <div class="batch-actions" v-if="selectedRows.length > 0">
+      <el-button
+          type="danger"
+          @click="handleBatchDelete"
+          :disabled="selectedRows.length === 0"
+      >
+        鎵归噺鍒犻櫎 ({{ selectedRows.length }})
+      </el-button>
+    </div>
+
+    <!-- 鎺掔彮鏂板/缂栬緫瀵硅瘽妗� -->
+    <el-dialog
+        v-model="scheduleDialog"
+        :title="dialogType === 'add' ? '鏂板鎺掔彮' : '缂栬緫鎺掔彮'"
+        width="700px"
+        @close="closeScheduleDialog"
+    >
+      <el-form
+          :model="scheduleForm"
+          :rules="scheduleRules"
+          ref="scheduleFormRef"
+          label-width="120px"
+      >
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鍛樺伐濮撳悕锛�" prop="staffId">
+              <el-select v-model="scheduleForm.staffId" placeholder="璇疯緭鍏ュ憳宸ュ鍚�" style="width: 100%"
+                         @change="handleSelectStaff">
+                <el-option v-for="item in personList" :label="item.staffName" :value="item.id" :key="item.id"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍛樺伐宸ュ彿锛�" prop="staffNo">
+              <el-input :disabled="true" v-model="scheduleForm.staffNo" placeholder=""/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="閮ㄩ棬锛�" prop="department">
+              <el-select v-model="scheduleForm.department" placeholder="璇烽�夋嫨閮ㄩ棬" style="width: 100%">
+                <el-option v-for="item in department_type" :label="item.label" :value="item.value" :key="item.value"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐝绫诲瀷锛�" prop="shiftType">
+              <el-select v-model="scheduleForm.shiftType" placeholder="璇烽�夋嫨鐝" style="width: 100%">
+                <el-option v-for="item in shift_type" :label="item.label" :value="item.value" :key="item.value"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="宸ヤ綔鏃ユ湡锛�" prop="workDate">
+              <el-date-picker
+                  v-model="scheduleForm.workDate"
+                  type="date"
+                  placeholder="閫夋嫨宸ヤ綔鏃ユ湡"
+                  style="width: 100%"
+                  format="YYYY-MM-DD"
+                  value-format="YYYY-MM-DD"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐘舵�侊細" prop="status">
+              <el-select v-model="scheduleForm.status" placeholder="璇烽�夋嫨鐘舵��" style="width: 100%">
+                <el-option v-for="item in schedule_status" :label="item.label" :value="item.value" :key="item.value"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="寮�濮嬫椂闂达細" prop="startTime">
+              <el-time-picker
+                  v-model="scheduleForm.startTime"
+                  placeholder="閫夋嫨寮�濮嬫椂闂�"
+                  style="width: 100%"
+                  format="HH:mm"
+                  value-format="HH:mm"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="缁撴潫鏃堕棿锛�" prop="endTime">
+              <el-time-picker
+                  v-model="scheduleForm.endTime"
+                  placeholder="閫夋嫨缁撴潫鏃堕棿"
+                  style="width: 100%"
+                  format="HH:mm"
+                  value-format="HH:mm"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="澶囨敞锛�" prop="remark">
+              <el-input
+                  v-model="scheduleForm.remark"
+                  type="textarea"
+                  :rows="3"
+                  placeholder="璇疯緭鍏ュ娉ㄤ俊鎭�"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitScheduleForm">纭</el-button>
+          <el-button @click="closeScheduleDialog">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import {ref, reactive, computed, onMounted, getCurrentInstance} from 'vue'
+import {ElMessage, ElMessageBox} from 'element-plus'
+import {useDict} from "@/utils/dict.js"
+import {Plus, Download, Search, Refresh} from '@element-plus/icons-vue'
+import {save, del, delByIds, listPage} from "@/api/personnelManagement/scheduling.js"
+import dayjs from "dayjs";
+import pagination from "@/components/PIMTable/Pagination.vue";
+import {staffOnJobListPage} from "@/api/personnelManagement/staffOnJob.js";
+
+const { proxy } = getCurrentInstance();
+
+const tableCount = ref(0)
+// 鍝嶅簲寮忔暟鎹�
+const scheduleDialog = ref(false)
+const dialogType = ref('add')
+const selectedRows = ref([])
+const scheduleFormRef = ref()
+
+// 绛涢�夎〃鍗�
+const filterForm = reactive({
+  staffName: '',
+  shiftType: '',
+  dateRange: [],
+  current:1,
+  size: 10
+})
+
+// 鎺掔彮琛ㄥ崟
+const scheduleForm = reactive({
+  id: '',
+  staffId: '',
+  staffNo: '',
+  department: '',
+  shiftType: '',
+  workDate: '',
+  startTime: '',
+  endTime: '',
+  workStartTime: '',
+  workEndTime: '',
+  workHours: 0,
+  status: '',
+  remark: ''
+})
+
+// 琛ㄥ崟楠岃瘉瑙勫垯
+const scheduleRules = reactive({
+  staffId: [{required: true, message: '璇烽�夋嫨鍛樺伐', trigger: 'change'}],
+  department: [{required: true, message: '璇烽�夋嫨閮ㄩ棬', trigger: 'change'}],
+  shiftType: [{required: true, message: '璇烽�夋嫨鐝绫诲瀷', trigger: 'change'}],
+  workDate: [{required: true, message: '璇烽�夋嫨宸ヤ綔鏃ユ湡', trigger: 'change'}],
+  startTime: [{required: true, message: '璇烽�夋嫨寮�濮嬫椂闂�', trigger: 'change'}],
+  endTime: [{required: true, message: '璇烽�夋嫨缁撴潫鏃堕棿', trigger: 'change'}],
+  status: [{required: true, message: '璇烽�夋嫨鐘舵��', trigger: 'change'}]
+})
+const tableLoading = ref(false)
+
+//瀛楀吀
+const {department_type, schedule_status, shift_type} = useDict("department_type", "schedule_status", "shift_type")
+// 浜哄憳鍒楄〃
+const personList = ref([]);
+
+// 妯℃嫙鎺掔彮鏁版嵁
+const scheduleList = ref([])
+
+
+/**
+ * 鑾峰彇褰撳墠鍦ㄨ亴浜哄憳鍒楄〃
+ */
+const getPersonList = () => {
+  staffOnJobListPage({
+    current: -1,
+    size: -1,
+    staffState: 1
+  }).then(res => {
+    personList.value = res.data.records || []
+  })
+};
+const paginationChange = (obj) => {
+  filterForm.current = obj.page;
+  filterForm.size = obj.limit;
+  handleFilter();
+};
+
+const handleSelectStaff = (val) => {
+  let obj = personList.value.find(item => item.id === val)
+  scheduleForm.staffNo = obj.staffNo
+
+}
+
+// 鑾峰彇鐝鏍囩绫诲瀷
+const getShiftTagType = (shiftType) => {
+  const typeMap = Object.fromEntries(shift_type.value.map(i => [i.value, i.elTagType]))
+  return typeMap[shiftType] || 'info'
+}
+
+// 鑾峰彇鐘舵�佹爣绛剧被鍨�
+const getStatusTagType = (status) => {
+  const typeMap = Object.fromEntries(schedule_status.value.map(i => [i.value, i.elTagType]))
+  return typeMap[status] || 'info'
+}
+
+// 绛涢��
+const handleFilter = async () => {
+  tableLoading.value = true
+  let searchForm = {
+    ...filterForm,
+    ...(filterForm.dateRange.length > 0 && {
+      startDate: filterForm.dateRange[0],
+      endDate: filterForm.dateRange[1],
+    })
+  }
+  let resp = await listPage(searchForm)
+  tableCount.value = resp.data.total
+  scheduleList.value = resp.data.records.map(it => {
+    return {
+      ...it,
+      'startTime': dayjs(it.workStartTime).format('HH:mm'),
+      'endTime': dayjs(it.workEndTime).format('HH:mm'),
+    }
+  })
+  tableLoading.value = false
+
+}
+
+// 閲嶇疆绛涢��
+const resetFilter = () => {
+  filterForm.staffName = ''
+  filterForm.shiftType = ''
+  filterForm.dateRange = []
+}
+
+// 鎵撳紑鎺掔彮瀵硅瘽妗�
+const openScheduleDialog = (type, data) => {
+  dialogType.value = type
+  scheduleDialog.value = true
+  getPersonList()
+  if (type === 'edit' && data) {
+    // 缂栬緫妯″紡锛屽鍒舵暟鎹�
+    Object.assign(scheduleForm, {...data})
+  } else {
+    // 鏂板妯″紡锛岄噸缃〃鍗�
+    Object.keys(scheduleForm).forEach(key => {
+      scheduleForm[key] = ''
+    })
+    // scheduleForm.status = '宸插畨鎺�'
+    scheduleForm.workDate = new Date().toISOString().split('T')[0]
+  }
+}
+
+// 鍏抽棴鎺掔彮瀵硅瘽妗�
+const closeScheduleDialog = () => {
+  scheduleFormRef.value?.resetFields()
+  scheduleDialog.value = false
+}
+
+// 璁$畻宸ヤ綔鏃堕暱
+const calculateWorkHours = () => {
+  if (scheduleForm.workDate && scheduleForm.startTime && scheduleForm.endTime) {
+    // 浣跨敤 workDate 涓� startTime 鍜� endTime 缁勫悎
+    const startDateTime = new Date(`${scheduleForm.workDate} ${scheduleForm.startTime}`)
+    const endDateTime = new Date(`${scheduleForm.workDate} ${scheduleForm.endTime}`)
+
+    // 澶勭悊璺ㄥぉ鎯呭喌锛堢粨鏉熸椂闂存棭浜庡紑濮嬫椂闂达級
+    if (endDateTime < startDateTime) {
+      // 璺ㄥぉ锛屽皢缁撴潫鏃ユ湡鍔犱竴澶�
+      endDateTime.setDate(endDateTime.getDate() + 1)
+    }
+    // 璁$畻宸ヤ綔鏃堕暱锛堝皬鏃讹級
+    const diffMs = endDateTime - startDateTime
+    const diffHours = diffMs / (1000 * 60 * 60)
+    scheduleForm.workHours = Math.round(diffHours * 100) / 100
+    scheduleForm.workStartTime = dayjs(startDateTime).format("YYYY-MM-DD HH:mm:ss")
+    scheduleForm.workEndTime = dayjs(endDateTime).format("YYYY-MM-DD HH:mm:ss")
+
+  }
+}
+
+// 鎻愪氦鎺掔彮琛ㄥ崟
+const submitScheduleForm = async () => {
+  const valid = await scheduleFormRef.value.validate()
+  if (!valid) return
+
+  calculateWorkHours()
+  const newSchedule = {...scheduleForm}
+
+  try {
+    await save(newSchedule)
+    ElMessage.success('淇濆瓨鎺掔彮鎴愬姛')
+
+    handleFilter()
+    closeScheduleDialog()
+  } catch (err) {
+    ElMessage.error('淇濆瓨澶辫触')
+  }
+}
+
+// 鍒犻櫎鎺掔彮
+const handleDelete = (row) => {
+  ElMessageBox.confirm(
+      `纭畾瑕佸垹闄� ${row.staffName} 鐨勬帓鐝褰曞悧锛焋,
+      '鍒犻櫎鎻愮ず',
+      {
+        confirmButtonText: '纭',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      }
+  ).then(() => {
+    del(row.id)
+    ElMessage.success('鍒犻櫎鎴愬姛')
+    handleFilter()
+  }).catch(() => {
+    ElMessage.info('宸插彇娑堝垹闄�')
+  })
+}
+
+// 鎵归噺鍒犻櫎
+const handleBatchDelete = () => {
+  if (selectedRows.value.length === 0) {
+    ElMessage.warning('璇烽�夋嫨瑕佸垹闄ょ殑璁板綍')
+    return
+  }
+
+  ElMessageBox.confirm(
+      `纭畾瑕佸垹闄ら�変腑鐨� ${selectedRows.value.length} 鏉℃帓鐝褰曞悧锛焋,
+      '鎵归噺鍒犻櫎鎻愮ず',
+      {
+        confirmButtonText: '纭',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      }
+  ).then(() => {
+    delByIds(selectedRows.value.map(item => item.id))
+    handleFilter()
+    ElMessage.success('鎵归噺鍒犻櫎鎴愬姛')
+  }).catch(() => {
+    ElMessage.info('宸插彇娑堝垹闄�')
+  })
+}
+
+// 閫夋嫨鍙樺寲浜嬩欢
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection
+}
+
+// 瀵煎嚭
+const handleExport = () => {
+  let searchForm = {
+    ...filterForm,
+    ...(filterForm.dateRange.length > 0 && {
+      startDate: filterForm.dateRange[0],
+      endDate: filterForm.dateRange[1],
+    })
+  }
+  proxy.download('/staff/staffScheduling/export', {}, '浜哄憳鎺掔彮.xlsx')
+}
+
+// 鐢熷懡鍛ㄦ湡
+onMounted(() => {
+  // 椤甸潰鍒濆鍖�
+  handleFilter()
+})
+</script>
+
+<style scoped>
+.scheduling-container {
+  padding: 20px;
+  background-color: #f5f7fa;
+  min-height: 100vh;
+}
+
+.page-header {
+  text-align: center;
+  margin-bottom: 30px;
+  padding: 20px;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  border-radius: 12px;
+  color: white;
+}
+
+.page-header h2 {
+  color: white;
+  margin-bottom: 10px;
+  font-size: 28px;
+  font-weight: 600;
+}
+
+.page-header p {
+  color: rgba(255, 255, 255, 0.9);
+  font-size: 14px;
+  margin: 0 0 15px 0;
+}
+
+.header-controls {
+  display: flex;
+  justify-content: center;
+  gap: 15px;
+}
+
+.filter-section {
+  background: white;
+  padding: 20px;
+  border-radius: 8px;
+  margin-bottom: 20px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.filter-form {
+  margin: 0;
+}
+
+.table-section {
+  background: white;
+  border-radius: 8px;
+  overflow: hidden;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  margin-bottom: 20px;
+}
+
+.batch-actions {
+  background: white;
+  padding: 15px 20px;
+  border-radius: 8px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.dialog-footer {
+  text-align: right;
+}
+
+:deep(.el-form-item__label) {
+  font-weight: 500;
+  color: #303133;
+}
+
+:deep(.el-input__wrapper) {
+  box-shadow: 0 0 0 1px #dcdfe6 inset;
+}
+
+:deep(.el-input__wrapper:hover) {
+  box-shadow: 0 0 0 1px #c0c4cc inset;
+}
+
+:deep(.el-input__wrapper.is-focus) {
+  box-shadow: 0 0 0 1px #409eff inset;
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 768px) {
+  .scheduling-container {
+    padding: 10px;
+  }
+
+  .page-header {
+    padding: 15px;
+  }
+
+  .page-header h2 {
+    font-size: 24px;
+  }
+
+  .header-controls {
+    flex-direction: column;
+    gap: 10px;
+  }
+}
+
+@media (max-width: 768px) {
+  .filter-form .el-form-item {
+    margin-bottom: 10px;
+  }
+}
+</style>

--
Gitblit v1.9.3