From fdd6bb96d8aad1ab796ce10038d170b47a19f661 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 13 十一月 2025 13:45:41 +0800
Subject: [PATCH] 1.排班管理-班次、加一个午休时间(h)、人员多选、人员从用户管理获取,加一条列表也只展示一条 2.薪资管理-只要,人员、薪资、月份三个字段
---
src/views/index.vue | 54 +++
src/api/personnelManagement/payrollManagement.js | 16 +
src/api/system/user.js | 7
src/views/personnelManagement/payrollManagement/components/formDia.vue | 168 ------------
src/views/personnelManagement/payrollManagement/index.vue | 219 +++++++++-------
src/views/personnelManagement/scheduling/index.vue | 301 +++++++++++++---------
6 files changed, 388 insertions(+), 377 deletions(-)
diff --git a/src/api/personnelManagement/payrollManagement.js b/src/api/personnelManagement/payrollManagement.js
index c29a6b1..c7284d4 100644
--- a/src/api/personnelManagement/payrollManagement.js
+++ b/src/api/personnelManagement/payrollManagement.js
@@ -32,4 +32,20 @@
method: "delete",
data: query,
});
+}
+// 瀵煎叆
+export function importData(query) {
+ return request({
+ url: "/compensationPerformance/importData",
+ method: "post",
+ data: query,
+ });
+}
+// 涓嬭浇妯$増
+export function exportTemplate(query) {
+ return request({
+ url: "/compensationPerformance/exportTemplate",
+ method: "post",
+ data: query,
+ });
}
\ No newline at end of file
diff --git a/src/api/system/user.js b/src/api/system/user.js
index 431f6b0..1a455c7 100644
--- a/src/api/system/user.js
+++ b/src/api/system/user.js
@@ -8,6 +8,13 @@
method: 'get',
params: query
})
+}// 鏌ヨ鐢ㄦ埛鍒楄〃
+export function listAll(query) {
+ return request({
+ url: '/system/user//listAll',
+ method: 'get',
+ params: query
+ })
}
// 鏌ヨ鐢ㄦ埛璇︾粏
diff --git a/src/views/index.vue b/src/views/index.vue
index 2888b16..e616dc9 100644
--- a/src/views/index.vue
+++ b/src/views/index.vue
@@ -13,9 +13,13 @@
<div class="company-meta">{{userStore.roleName}}</div>
</div>
<div style="display: flex;align-items: center;gap: 8px">
- <el-icon color="#5053B5" size="22"><Clock /></el-icon>
- <span>鐧婚檰鏃ユ湡锛歿{userStore.currentLoginTime}}</span>
- </div>
+ <el-icon color="#5053B5" size="22"><Clock /></el-icon>
+ <span>鐧婚檰鏃ユ湡锛歿{userStore.currentLoginTime}}</span>
+ </div>
+ <div style="display: flex;align-items: center;gap: 8px">
+ <el-icon color="#5053B5" size="22"><Calendar /></el-icon>
+ <span>鎺掔彮鏃堕棿锛歿{scheduleTime}}</span>
+ </div>
</div>
</div>
<div class="data-cards">
@@ -169,6 +173,7 @@
import Echarts from "@/components/Echarts/echarts.vue";
import * as echarts from 'echarts';
import useUserStore from "@/store/modules/user.js";
+import { Clock, Calendar } from '@element-plus/icons-vue'
import {
analysisCustomerContractAmounts, getAmountHalfYear,
getBusiness,
@@ -176,6 +181,8 @@
qualityStatistics,
statisticsReceivablePayable
} from "@/api/viewIndex.js";
+import { listPage } from "@/api/personnelManagement/scheduling.js";
+import dayjs from "dayjs";
const userStore = useUserStore()
@@ -341,6 +348,10 @@
const todoList = ref([])
const radio1 = ref(1)
+// 鎺掔彮鏃堕棿
+const scheduleTime = ref('')
+const scheduleInfo = ref({})
+
// 鍥捐〃寮曠敤
const barChart = ref(null)
const lineChart = ref(null)
@@ -358,6 +369,7 @@
statisticsReceivable()
qualityStatisticsInfo()
getAmountHalfYearNum()
+ getCurrentUserSchedule()
})
// 鏁版嵁缁熻
const getBusinessData = () => {
@@ -409,6 +421,42 @@
qualityStatisticsObject.value.factoryNum = res.data.factoryNum
})
}
+// 鑾峰彇褰撳墠鐢ㄦ埛鎺掔彮淇℃伅
+const getCurrentUserSchedule = async () => {
+ try {
+ const today = dayjs().format('YYYY-MM-DD')
+ const res = await listPage({
+ staffName: userStore.name,
+ startDate: today,
+ endDate: today,
+ current: 1,
+ size: 10
+ })
+
+ if (res.data && res.data.records && res.data.records.length > 0) {
+ const currentSchedule = res.data.records[0]
+ scheduleInfo.value = currentSchedule
+
+ // 鏍煎紡鍖栨帓鐝椂闂存樉绀�
+ if (currentSchedule.startTime && currentSchedule.endTime) {
+ scheduleTime.value = `${currentSchedule.startTime} - ${currentSchedule.endTime}`
+ } else if (currentSchedule.workStartTime && currentSchedule.workEndTime) {
+ const startTime = dayjs(currentSchedule.workStartTime).format('HH:mm')
+ const endTime = dayjs(currentSchedule.workEndTime).format('HH:mm')
+ scheduleTime.value = `${startTime} - ${endTime}`
+ } else {
+ scheduleTime.value = '浠婃棩鏃犳帓鐝�'
+ }
+ } else {
+ scheduleTime.value = '浠婃棩鏃犳帓鐝�'
+ scheduleInfo.value = {}
+ }
+ } catch (error) {
+ console.error('鑾峰彇鎺掔彮淇℃伅澶辫触:', error)
+ scheduleTime.value = '鑾峰彇鎺掔彮淇℃伅澶辫触'
+ }
+}
+
const getAmountHalfYearNum = async () => {
const res = await getAmountHalfYear()
console.log(res)
diff --git a/src/views/personnelManagement/payrollManagement/components/formDia.vue b/src/views/personnelManagement/payrollManagement/components/formDia.vue
index e4cf0b3..8da9fb3 100644
--- a/src/views/personnelManagement/payrollManagement/components/formDia.vue
+++ b/src/views/personnelManagement/payrollManagement/components/formDia.vue
@@ -27,128 +27,15 @@
<el-select v-model="form.staffId" placeholder="璇烽�夋嫨浜哄憳" style="width: 100%" @change="handleSelect" :disabled="operationType === 'edit'">
<el-option
v-for="item in personList"
- :key="item.id"
- :label="item.staffName"
- :value="item.id"
+ :key="item.userId"
+ :label="item.nickName"
+ :value="item.userId"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="搴斿嚭鍕ゅぉ鏁帮細" prop="shouldAttendedNum">
- <el-input v-model="form.shouldAttendedNum" placeholder="璇疯緭鍏�" clearable type="number"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="瀹為檯鍑哄嫟澶╂暟锛�" prop="actualAttendedNum">
- <el-input v-model="form.actualAttendedNum" placeholder="璇疯緭鍏�" clearable type="number"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="鍩烘湰宸ヨ祫锛�" prop="basicSalary">
- <el-input v-model="form.basicSalary" placeholder="璇疯緭鍏�" clearable type="number"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="宀椾綅宸ヨ祫锛�" prop="postSalary">
- <el-input v-model="form.postSalary" placeholder="璇疯緭鍏�" clearable type="number"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="鍏ョ鑱岀己鍕ゆ墸娆撅細" prop="deductionAbsenteeism">
- <el-input v-model="form.deductionAbsenteeism" placeholder="璇疯緭鍏�" clearable type="number"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="鐥呭亣鎵f锛�" prop="sickLeaveDeductions">
- <el-input v-model="form.sickLeaveDeductions" placeholder="璇疯緭鍏�" clearable type="number"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="浜嬪亣鎵f锛�" prop="deductionPersonalLeave">
- <el-input v-model="form.deductionPersonalLeave" placeholder="璇疯緭鍏�" clearable type="number"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="蹇樿鎵撳崱鎵f锛�" prop="forgetClockDeduct">
- <el-input v-model="form.forgetClockDeduct" style="width: 100%" type="number"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="缁╂晥寰楀垎锛�" prop="performanceScore">
- <el-input v-model="form.performanceScore" placeholder="璇疯緭鍏�" clearable type="number"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="缁╂晥宸ヨ祫锛�" prop="performancePay">
- <el-input v-model="form.performancePay" placeholder="璇疯緭鍏�" clearable type="number"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="搴斿彂鍚堣锛�" prop="payableWages">
- <el-input v-model="form.payableWages" placeholder="璇疯緭鍏�" clearable type="number"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="绀句繚涓汉锛�" prop="socialSecurityIndividuals">
- <el-input v-model="form.socialSecurityIndividuals" :precision="0" :step="1" style="width: 100%" type="number"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="绀句繚鍏徃锛�" prop="socialSecurityCompanies">
- <el-input v-model="form.socialSecurityCompanies" :precision="0" :step="1" style="width: 100%" type="number"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="绀句繚鍚堣锛�" prop="socialSecurityTotal">
- <el-input v-model="form.socialSecurityTotal" :precision="0" :step="1" style="width: 100%" type="number"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="鍏Н閲戜釜浜猴細" prop="providentFundIndividuals">
- <el-input v-model="form.providentFundIndividuals" :precision="0" :step="1" style="width: 100%" type="number"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="鍏Н閲戝叕鍙革細" prop="providentFundCompany">
- <el-input v-model="form.providentFundCompany" :precision="0" :step="1" style="width: 100%" type="number"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="鍏Н閲戝悎璁★細" prop="providentFundTotal">
- <el-input v-model="form.providentFundTotal" :precision="0" :step="1" style="width: 100%" type="number"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="搴旂◣宸ヨ祫锛�" prop="taxableWaget">
- <el-input v-model="form.taxableWaget" :precision="0" :step="1" style="width: 100%" type="number"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="涓汉鎵�寰楃◣锛�" prop="personalIncomeTax">
- <el-input v-model="form.personalIncomeTax" :step="0.1" style="width: 100%" type="number"/>
- </el-form-item>
- </el-col>
<el-col :span="12">
<el-form-item label="瀹炲彂宸ヨ祫锛�" prop="actualWages">
<el-input v-model="form.actualWages" style="width: 100%" type="number"/>
@@ -170,6 +57,7 @@
import {ref} from "vue";
import {getStaffJoinInfo, getStaffOnJob, staffJoinAdd, staffJoinUpdate} from "@/api/personnelManagement/onboarding.js";
import {compensationAdd, compensationUpdate} from "@/api/personnelManagement/payrollManagement.js";
+import {listUser} from "@/api/system/user.js";
const { proxy } = getCurrentInstance()
const emit = defineEmits(['close'])
@@ -180,50 +68,11 @@
payDate: "",
staffId: "",
name: "",
- shouldAttendedNum: "",
- actualAttendedNum: "",
- basicSalary: "",
- postSalary: "",
- deductionAbsenteeism: "",
- sickLeaveDeductions: "",
- deductionPersonalLeave: "",
- forgetClockDeduct: "",
- performanceScore: "",
- performancePay: "",
- payableWages: "",
- socialSecurityIndividuals: "",
- socialSecurityCompanies: "",
- socialSecurityTotal: "",
- providentFundIndividuals: "",
- providentFundCompany: "",
- providentFundTotal: "",
- taxableWaget: "",
- personalIncomeTax: "",
actualWages: "",
},
rules: {
payDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" },],
staffId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" },],
- staffName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- shouldAttendedNum: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- actualAttendedNum: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- basicSalary: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- postSalary: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- deductionAbsenteeism: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- sickLeaveDeductions: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- deductionPersonalLeave: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- forgetClockDeduct: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- performanceScore: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- performancePay: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- payableWages: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- socialSecurityIndividuals: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- socialSecurityCompanies: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- socialSecurityTotal: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- providentFundIndividuals: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- providentFundCompany: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- providentFundTotal: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- taxableWaget: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- personalIncomeTax: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
actualWages: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
},
});
@@ -234,8 +83,8 @@
const openDialog = (type, row) => {
operationType.value = type;
dialogFormVisible.value = true;
- getStaffOnJob().then(res => {
- personList.value = res.data
+ listUser().then(res => {
+ personList.value = res.rows
})
form.value = {}
if (operationType.value === 'edit') {
@@ -246,10 +95,9 @@
}
}
const handleSelect = (value) => {
- console.log('value', value)
- const index = personList.value.findIndex(row => row.id === value)
+ const index = personList.value.findIndex(row => row.userId === value)
if (index > -1) {
- form.value.name = personList.value[index].staffName
+ form.value.name = personList.value[index].nickName
}
}
// 鎻愪氦浜у搧琛ㄥ崟
diff --git a/src/views/personnelManagement/payrollManagement/index.vue b/src/views/personnelManagement/payrollManagement/index.vue
index 24e3dd8..a116316 100644
--- a/src/views/personnelManagement/payrollManagement/index.vue
+++ b/src/views/personnelManagement/payrollManagement/index.vue
@@ -27,9 +27,10 @@
>
</div>
<div>
- <el-button @click="handleExport" style="margin-right: 10px">瀵煎嚭</el-button>
+ <el-button @click="handleImport">瀵煎叆</el-button>
<el-button type="primary" @click="openForm('add')">鏂板钖祫</el-button>
<el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+ <el-button @click="handleExport">瀵煎嚭</el-button>
</div>
</div>
<div class="table_list">
@@ -46,17 +47,56 @@
></PIMTable>
</div>
<form-dia ref="formDia" @close="handleQuery"></form-dia>
+
+ <!-- 瀵煎叆寮圭獥 -->
+ <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body @close="handleUploadClose">
+ <el-upload
+ ref="uploadRef"
+ :limit="1"
+ accept=".xlsx, .xls"
+ :headers="upload.headers"
+ :action="upload.url"
+ :disabled="upload.isUploading"
+ :on-progress="upload.onProgress"
+ :on-success="upload.onSuccess"
+ :on-error="upload.onError"
+ :on-change="upload.onChange"
+ :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>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="submitFileForm">纭� 瀹�</el-button>
+ <el-button @click="handleUploadCancel">鍙� 娑�</el-button>
+ </div>
+ </template>
+ </el-dialog>
</div>
</template>
<script setup>
-import { Search } from "@element-plus/icons-vue";
+import { Search, UploadFilled } from "@element-plus/icons-vue";
import {onMounted, ref, reactive, toRefs, getCurrentInstance, nextTick} from "vue";
import FormDia from "@/views/personnelManagement/payrollManagement/components/formDia.vue";
import {staffJoinDel} from "@/api/personnelManagement/onboarding.js";
import {ElMessageBox} from "element-plus";
import dayjs from "dayjs";
import {compensationDelete, compensationListPage} from "@/api/personnelManagement/payrollManagement.js";
+import { getToken } from "@/utils/auth.js";
const data = reactive({
searchForm: {
@@ -73,98 +113,6 @@
{
label: "濮撳悕",
prop: "name",
- },
- {
- label: "搴斿嚭鍕ゅぉ鏁�",
- prop: "shouldAttendedNum",
- width:100
- },
- {
- label: "瀹為檯鍑哄嫟澶╂暟",
- prop: "actualAttendedNum",
- width:110
- },
- {
- label: "鍩烘湰宸ヨ祫",
- prop: "basicSalary",
- },
- {
- label: "宀椾綅宸ヨ祫",
- prop: "postSalary",
- width:100
- },
- {
- label: "鍏ョ鑱岀己鍕ゆ墸娆�",
- prop: "deductionAbsenteeism",
- width:130
- },
- {
- label: "鐥呭亣鎵f",
- prop: "sickLeaveDeductions",
- width:100
- },
- {
- label: "浜嬪亣鎵f",
- prop: "deductionPersonalLeave",
- width:100
- },
- {
- label: "蹇樿鎵撳崱鎵f",
- prop: "forgetClockDeduct",
- width:110
- },
- {
- label: "缁╂晥寰楀垎",
- prop: "performanceScore",
- width:150
- },
- {
- label: "缁╂晥宸ヨ祫",
- prop: "performancePay",
- width: 120
- },
- {
- label: "搴斿彂鍚堣",
- prop: "payableWages",
- width:150
- },
- {
- label: "绀句繚涓汉",
- prop: "socialSecurityIndividuals",
- },
- {
- label: "绀句繚鍏徃",
- prop: "socialSecurityCompanies",
- width: 120
- },
- {
- label: "绀句繚鍚堣",
- prop: "socialSecurityTotal",
- width: 120
- },
- {
- label: "鍏Н閲戜釜浜�",
- prop: "providentFundIndividuals",
- width: 120
- },
- {
- label: "鍏Н閲戝叕鍙�",
- prop: "providentFundCompany",
- width: 120
- },
- {
- label: "鍏Н閲戝悎璁�",
- prop: "providentFundTotal",
- width: 120
- },
- {
- label: "搴旂◣宸ヨ祫",
- prop: "taxableWaget",
- },
- {
- label: "涓汉鎵�寰楃◣",
- prop: "personalIncomeTax",
- width: 120
},
{
label: "瀹炲彂宸ヨ祫",
@@ -197,6 +145,56 @@
});
const formDia = ref()
const { proxy } = getCurrentInstance()
+
+// 瀵煎叆鍔熻兘閰嶇疆
+const upload = reactive({
+ // 鏄惁鏄剧ず寮瑰嚭灞傦紙钖祫瀵煎叆锛�
+ open: false,
+ // 寮瑰嚭灞傛爣棰橈紙钖祫瀵煎叆锛�
+ title: "",
+ // 鏄惁绂佺敤涓婁紶
+ isUploading: false,
+ // 璁剧疆涓婁紶鐨勮姹傚ご閮�
+ headers: { Authorization: "Bearer " + getToken() },
+ // 涓婁紶鐨勫湴鍧�
+ url: import.meta.env.VITE_APP_BASE_API + "/compensationPerformance/importData",
+ // 鏂囦欢涓婁紶鍓嶇殑鍥炶皟
+ beforeUpload: (file) => {
+ // 鍙互鍦ㄦ澶勫仛鏂囦欢绫诲瀷鎴栧ぇ灏忔牎楠�
+ const isValid = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || file.name.endsWith('.xlsx') || file.name.endsWith('.xls');
+ if (!isValid) {
+ proxy.$modal.msgError("鍙兘涓婁紶 Excel 鏂囦欢");
+ }
+ return isValid;
+ },
+ // 鏂囦欢鐘舵�佹敼鍙樻椂鐨勫洖璋�
+ onChange: (file, fileList) => {
+ console.log('鏂囦欢鐘舵�佹敼鍙�', file, fileList);
+ },
+ // 鏂囦欢涓婁紶鎴愬姛鏃剁殑鍥炶皟
+ onSuccess: (response, file, fileList) => {
+ upload.isUploading = false;
+ if(response.code === 200){
+ proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
+ handleUploadClose();
+ getList();
+ }else if(response.code === 500){
+ proxy.$modal.msgError(response.msg);
+ }else{
+ proxy.$modal.msgWarning(response.msg);
+ }
+ },
+ // 鏂囦欢涓婁紶澶辫触鏃剁殑鍥炶皟
+ onError: (error, file, fileList) => {
+ console.error('涓婁紶澶辫触', error, file, fileList);
+ upload.isUploading = false;
+ proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+ },
+ // 鏂囦欢涓婁紶杩涘害鍥炶皟
+ onProgress: (event, file, fileList) => {
+ console.log('涓婁紶涓�...', event.percent);
+ }
+});
const handleDateChange = (value,type) => {
searchForm.value.entryDateEnd = null
@@ -299,6 +297,39 @@
});
};
+/** 瀵煎叆鎸夐挳鎿嶄綔 */
+function handleImport() {
+ upload.title = "钖祫瀵煎叆";
+ upload.open = true;
+}
+
+/** 鎻愪氦涓婁紶鏂囦欢 */
+function submitFileForm() {
+ upload.isUploading = true;
+ proxy.$refs["uploadRef"].submit();
+}
+
+/** 涓嬭浇妯℃澘 */
+function importTemplate() {
+ proxy.download("/compensationPerformance/exportTemplate", {}, "钖祫瀵煎叆妯℃澘.xlsx");
+}
+
+// 澶勭悊涓婁紶寮规鍙栨秷
+function handleUploadCancel() {
+ upload.open = false;
+ handleUploadClose();
+}
+
+// 澶勭悊涓婁紶寮规鍏抽棴
+function handleUploadClose() {
+ upload.open = false;
+ upload.isUploading = false;
+ // 娓呯┖涓婁紶鏂囦欢缂撳瓨
+ if (proxy.$refs.uploadRef) {
+ proxy.$refs.uploadRef.clearFiles();
+ }
+}
+
onMounted(() => {
getList();
});
diff --git a/src/views/personnelManagement/scheduling/index.vue b/src/views/personnelManagement/scheduling/index.vue
index 251dbe9..7c6324f 100644
--- a/src/views/personnelManagement/scheduling/index.vue
+++ b/src/views/personnelManagement/scheduling/index.vue
@@ -11,34 +11,14 @@
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')">
@@ -61,48 +41,53 @@
@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">
+ <el-table-column prop="staffName" label="鍛樺伐濮撳悕"/>
+ <!-- <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">
+ </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="workStartTime" label="寮�濮嬫椂闂�"/>
+ <el-table-column prop="workEndTime" label="缁撴潫鏃堕棿"/>
+ <el-table-column prop="lunchTime" label="鍗堜紤鏃堕棿(h)">
+ <template #default="scope">
+ {{ scope.row.lunchTime }}灏忔椂
+ </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">
+ <!-- <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">
+ </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">
+ </el-table-column> -->
+ <!-- <el-table-column prop="remark" label="澶囨敞" min-width="150"/> -->
+ <el-table-column label="鎿嶄綔" width="200" fixed="right" align="center">
<template #default="scope">
<el-button
- type="primary"
- size="small"
+ link
+ type="primary"
@click="openScheduleDialog('edit', scope.row)"
>
缂栬緫
</el-button>
<el-button
- type="danger"
- size="small"
+ link
+ type="danger"
@click="handleDelete(scope.row)"
>
鍒犻櫎
@@ -144,22 +129,26 @@
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%"
+ <el-col :span="24">
+ <el-form-item label="鍛樺伐濮撳悕锛�" prop="staffIds">
+ <el-select v-model="scheduleForm.staffIds" placeholder="璇烽�夋嫨鍛樺伐濮撳悕" style="width: 100%"
+ multiple filterable collapse-tags-tooltip
@change="handleSelectStaff">
- <el-option v-for="item in personList" :label="item.staffName" :value="item.id" :key="item.id"/>
- </el-select>
- </el-form-item>
+ <el-option v-for="item in personList" :label="item.nickName" :value="item.userId" :key="item.userId"/>
+ </el-select>
+ </el-form-item>
</el-col>
+ </el-row>
+
+ <!-- <el-row :gutter="20">
<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> -->
- <el-row :gutter="20">
+ <!-- <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="閮ㄩ棬锛�" prop="department">
<el-select v-model="scheduleForm.department" placeholder="璇烽�夋嫨閮ㄩ棬" style="width: 100%">
@@ -174,9 +163,9 @@
</el-select>
</el-form-item>
</el-col>
- </el-row>
+ </el-row> -->
- <el-row :gutter="20">
+ <!-- <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="宸ヤ綔鏃ユ湡锛�" prop="workDate">
<el-date-picker
@@ -196,34 +185,49 @@
</el-select>
</el-form-item>
</el-col>
- </el-row>
+ </el-row> -->
<el-row :gutter="20">
<el-col :span="12">
- <el-form-item label="寮�濮嬫椂闂达細" prop="startTime">
+ <el-form-item label="寮�濮嬫椂闂达細" prop="workStartTime">
<el-time-picker
- v-model="scheduleForm.startTime"
+ v-model="scheduleForm.workStartTime"
placeholder="閫夋嫨寮�濮嬫椂闂�"
style="width: 100%"
format="HH:mm"
- value-format="HH:mm"
+ value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="缁撴潫鏃堕棿锛�" prop="endTime">
+ <el-form-item label="缁撴潫鏃堕棿锛�" prop="workEndTime">
<el-time-picker
- v-model="scheduleForm.endTime"
+ v-model="scheduleForm.workEndTime"
placeholder="閫夋嫨缁撴潫鏃堕棿"
style="width: 100%"
format="HH:mm"
- value-format="HH:mm"
+ value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="鍗堜紤鏃堕棿(h)锛�" prop="lunchTime">
+ <el-input-number
+ v-model="scheduleForm.lunchTime"
+ :min="0"
+ :max="8"
+ :step="0.5"
+ placeholder="璇疯緭鍏ュ崍浼戞椂闂�"
+ style="width: 100%"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <!-- <el-row :gutter="20">
<el-col :span="24">
<el-form-item label="澶囨敞锛�" prop="remark">
<el-input
@@ -234,7 +238,7 @@
/>
</el-form-item>
</el-col>
- </el-row>
+ </el-row> -->
</el-form>
<template #footer>
@@ -248,7 +252,7 @@
</template>
<script setup>
-import {ref, reactive, computed, onMounted, getCurrentInstance} from 'vue'
+import {ref, reactive, computed, onMounted, getCurrentInstance, watch} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus'
import {useDict} from "@/utils/dict.js"
import {Plus, Download, Search, Refresh} from '@element-plus/icons-vue'
@@ -256,6 +260,7 @@
import {getStaffOnJob} from "@/api/personnelManagement/onboarding.js";
import dayjs from "dayjs";
import pagination from "@/components/PIMTable/Pagination.vue";
+import {listUser} from "@/api/system/user.js";
const { proxy } = getCurrentInstance();
@@ -269,8 +274,6 @@
// 绛涢�夎〃鍗�
const filterForm = reactive({
staffName: '',
- shiftType: '',
- dateRange: [],
current:1,
size: 10
})
@@ -278,29 +281,31 @@
// 鎺掔彮琛ㄥ崟
const scheduleForm = reactive({
id: '',
- staffId: '',
- staffNo: '',
- department: '',
- shiftType: '',
- workDate: '',
- startTime: '',
- endTime: '',
+ staffIds: [],
+ // staffNo: '',
+ // department: '',
+ // shiftType: '',
+ // workDate: '',
workStartTime: '',
workEndTime: '',
- workHours: 0,
- status: '',
- remark: ''
+ lunchTime: 3,
+ // 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'}]
+ staffIds: [{required: true, message: '璇烽�夋嫨鍛樺伐', trigger: 'change'}],
+ // department: [{required: true, message: '璇烽�夋嫨閮ㄩ棬', trigger: 'change'}],
+ // shiftType: [{required: true, message: '璇烽�夋嫨鐝绫诲瀷', trigger: 'change'}],
+ // workDate: [{required: true, message: '璇烽�夋嫨宸ヤ綔鏃ユ湡', trigger: 'change'}],
+ workStartTime: [{required: true, message: '璇烽�夋嫨寮�濮嬫椂闂�', trigger: 'change'}],
+ workEndTime: [{required: true, message: '璇烽�夋嫨缁撴潫鏃堕棿', trigger: 'change'}],
+ lunchTime: [{required: true, message: '璇疯緭鍏ュ崍浼戞椂闂�', trigger: 'blur'}],
+ // status: [{required: true, message: '璇烽�夋嫨鐘舵��', trigger: 'change'}]
})
const tableLoading = ref(false)
@@ -317,9 +322,9 @@
* 鑾峰彇褰撳墠鍦ㄨ亴浜哄憳鍒楄〃
*/
const getPersonList = () => {
- getStaffOnJob().then(res => {
- personList.value = res.data
- })
+ listUser().then(res => {
+ personList.value = res.rows
+ })
};
const paginationChange = (obj) => {
filterForm.current = obj.page;
@@ -328,9 +333,9 @@
};
const handleSelectStaff = (val) => {
- let obj = personList.value.find(item => item.id === val)
- scheduleForm.staffNo = obj.staffNo
-
+ // 澶氶�夊憳宸ワ紝涓嶅啀鑷姩璁剧疆鍛樺伐宸ュ彿
+ // let obj = personList.value.find(item => item.id === val)
+ // scheduleForm.staffNo = obj.staffNo
}
// 鑾峰彇鐝鏍囩绫诲瀷
@@ -349,19 +354,19 @@
const handleFilter = async () => {
tableLoading.value = true
let searchForm = {
- ...filterForm,
- ...(filterForm.dateRange.length > 0 && {
- startDate: filterForm.dateRange[0],
- endDate: filterForm.dateRange[1],
- })
+ ...filterForm
}
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'),
+ // 淇濆瓨鍘熷鏃堕棿鏍煎紡鐢ㄤ簬缂栬緫
+ 'originalWorkStartTime': it.workStartTime,
+ 'originalWorkEndTime': it.workEndTime,
+ // 鏍煎紡鍖栨椂闂寸敤浜庤〃鏍兼樉绀�
+ 'workStartTime': dayjs(it.workStartTime).format('HH:mm'),
+ 'workEndTime': dayjs(it.workEndTime).format('HH:mm'),
}
})
tableLoading.value = false
@@ -371,8 +376,6 @@
// 閲嶇疆绛涢��
const resetFilter = () => {
filterForm.staffName = ''
- filterForm.shiftType = ''
- filterForm.dateRange = []
}
// 鎵撳紑鎺掔彮瀵硅瘽妗�
@@ -381,16 +384,29 @@
scheduleDialog.value = true
getPersonList()
if (type === 'edit' && data) {
- // 缂栬緫妯″紡锛屽鍒舵暟鎹�
- Object.assign(scheduleForm, {...data})
- } else {
- // 鏂板妯″紡锛岄噸缃〃鍗�
- Object.keys(scheduleForm).forEach(key => {
- scheduleForm[key] = ''
+ // 缂栬緫妯″紡锛屽鍒舵暟鎹紝灏嗗憳宸D瀛楃涓茶浆鎹负鏁扮粍鏍煎紡锛屽苟澶勭悊鏃堕棿瀛楁
+ Object.assign(scheduleForm, {
+ ...data,
+ lunchTime: Number(data.lunchTime),
+ staffIds: data.staffId ? data.staffId.split(',').map(id => parseInt(id)) : [],
+ // 浣跨敤鍘熷鏃堕棿瀛楃涓诧紝鍥犱负琛ㄦ牸涓樉绀虹殑鏄牸寮忓寲鍚庣殑HH:mm
+ workStartTime: data.originalWorkStartTime || '',
+ workEndTime: data.originalWorkEndTime || ''
})
- // scheduleForm.status = '宸插畨鎺�'
- scheduleForm.workDate = new Date().toISOString().split('T')[0]
- }
+ } else {
+ // 鏂板妯″紡锛岄噸缃〃鍗�
+ Object.keys(scheduleForm).forEach(key => {
+ if (key === 'staffIds') {
+ scheduleForm[key] = []
+ } else if (key === 'lunchTime') {
+ scheduleForm[key] = 3
+ } else {
+ scheduleForm[key] = ''
+ }
+ })
+ // scheduleForm.status = '宸插畨鎺�'
+ // scheduleForm.workDate = new Date().toISOString().split('T')[0]
+ }
}
// 鍏抽棴鎺掔彮瀵硅瘽妗�
@@ -401,37 +417,86 @@
// 璁$畻宸ヤ綔鏃堕暱
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 (!scheduleForm.workStartTime || !scheduleForm.workEndTime) {
+ return;
+ }
+
+ try {
+ // 浣跨敤dayjs姝g‘瑙f瀽鏃堕棿
+ const startDayjs = dayjs(scheduleForm.workStartTime);
+ const endDayjs = dayjs(scheduleForm.workEndTime);
+
+ if (!startDayjs.isValid() || !endDayjs.isValid()) {
+ return;
+ }
+
+ const startDateTime = startDayjs.toDate();
+ const endDateTime = endDayjs.toDate();
// 澶勭悊璺ㄥぉ鎯呭喌锛堢粨鏉熸椂闂存棭浜庡紑濮嬫椂闂达級
if (endDateTime < startDateTime) {
// 璺ㄥぉ锛屽皢缁撴潫鏃ユ湡鍔犱竴澶�
- endDateTime.setDate(endDateTime.getDate() + 1)
+ 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 diffMs = endDateTime - startDateTime;
+ const diffHours = diffMs / (1000 * 60 * 60);
+ scheduleForm.workHours = Math.round(diffHours * 100) / 100;
+ } catch (error) {
+ console.error('鏃堕棿璁$畻閿欒:', error);
}
}
+
+// 鐩戝惉鏃堕棿瀛楁鍙樺寲锛岃嚜鍔ㄨ绠楀伐浣滄椂闀�
+watch(
+ () => [scheduleForm.workStartTime, scheduleForm.workEndTime],
+ () => {
+ calculateWorkHours()
+ },
+ { deep: true }
+)
// 鎻愪氦鎺掔彮琛ㄥ崟
const submitScheduleForm = async () => {
const valid = await scheduleFormRef.value.validate()
if (!valid) return
- calculateWorkHours()
- const newSchedule = {...scheduleForm}
+ // 鐢变簬鍛樺伐鏄閫夛紝闇�瑕佷负姣忎釜閫変腑鐨勫憳宸ュ垱寤烘帓鐝褰�
+ const selectedStaffIds = scheduleForm.staffIds || []
+
+ if (selectedStaffIds.length === 0) {
+ ElMessage.warning('璇疯嚦灏戦�夋嫨涓�涓憳宸�')
+ return
+ }
try {
+ // 鑾峰彇閫変腑鐨勫憳宸ュ鍚嶅垪琛�
+ const selectedStaffNames = selectedStaffIds.map(staffId => {
+ const staff = personList.value.find(item => item.userId === staffId)
+ return staff ? staff.nickName : ''
+ }).filter(name => name !== '')
+
+ // 灏嗗憳宸ュ鍚嶇粍瑁呮垚閫楀彿鍒嗛殧鐨勫瓧绗︿覆
+ const staffNameString = selectedStaffNames.join(',')
+
+ // 鍒涘缓鎺掔彮璁板綍锛屽皢鍛樺伐濮撳悕淇濆瓨涓哄瓧绗︿覆鏍煎紡
+ const newSchedule = {
+ ...scheduleForm,
+ staffName: staffNameString,
+ staffId: selectedStaffIds.join(','), // 灏嗗憳宸D涔熶繚瀛樹负閫楀彿鍒嗛殧鐨勫瓧绗︿覆
+ // 璁剧疆鍏朵粬蹇呰瀛楁鐨勯粯璁ゅ��
+ staffNo: '', // 鍙互鏍规嵁闇�瑕佷粠personList涓幏鍙�
+ department: '',
+ shiftType: '',
+ workDate: '',
+ status: '',
+ remark: ''
+ }
+
await save(newSchedule)
- ElMessage.success('淇濆瓨鎺掔彮鎴愬姛')
+
+ ElMessage.success(`鎴愬姛涓� ${selectedStaffNames.length} 涓憳宸ュ垱寤烘帓鐝璥)
handleFilter()
closeScheduleDialog()
@@ -491,11 +556,7 @@
// 瀵煎嚭
const handleExport = () => {
let searchForm = {
- ...filterForm,
- ...(filterForm.dateRange.length > 0 && {
- startDate: filterForm.dateRange[0],
- endDate: filterForm.dateRange[1],
- })
+ ...filterForm
}
proxy.download('/staff/staffScheduling/export', {}, '浜哄憳鎺掔彮.xlsx')
}
--
Gitblit v1.9.3