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