|
|
@@ -6,7 +6,7 @@
|
|
|
</div>
|
|
|
<el-form :model="overtimeForm" :rules="rules" ref="overtimeForm" label-width="100px">
|
|
|
<el-form-item label="加班日期" prop="overtimeDate">
|
|
|
- <el-date-picker
|
|
|
+ <el-date-picker style="width:300px;"
|
|
|
v-model="overtimeForm.overtimeDate"
|
|
|
type="date"
|
|
|
placeholder="选择加班日期"
|
|
|
@@ -16,21 +16,44 @@
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="加班人员" prop="employees">
|
|
|
- <el-cascader
|
|
|
+ <el-cascader style="width:300px;"
|
|
|
v-model="overtimeForm.employees"
|
|
|
:options="departmentTree"
|
|
|
:props="cascaderProps"
|
|
|
clearable
|
|
|
filterable
|
|
|
- multiple
|
|
|
collapse-tags
|
|
|
placeholder="请选择部门及人员"
|
|
|
@change="handleEmployeeChange">
|
|
|
</el-cascader>
|
|
|
- <el-button type="primary" size="small" @click="showEmployeeDialog" style="margin-left: 10px;">添加加班人员</el-button>
|
|
|
</el-form-item>
|
|
|
|
|
|
- <el-form-item label="开始时间" prop="startTime">
|
|
|
+ <el-form-item label="用餐类别" prop="mealType">
|
|
|
+ <el-select
|
|
|
+ v-model="overtimeForm.mealType"
|
|
|
+ style="width:300px;"
|
|
|
+ placeholder="请选择用餐类别"
|
|
|
+ multiple
|
|
|
+ collapse-tags
|
|
|
+ clearable>
|
|
|
+ <el-option value="中餐" label="中餐"></el-option>
|
|
|
+ <el-option value="晚餐" label="晚餐"></el-option>
|
|
|
+ <el-option value="夜宵" label="夜宵"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+
|
|
|
+ <el-form-item label="加班时段" prop="timeType" >
|
|
|
+ <el-select
|
|
|
+ v-model="overtimeForm.timeType" style="width:300px;"
|
|
|
+ placeholder="选择开始时间">
|
|
|
+ <el-option v-for="item in timeTypeList" :value="item.id" :label="item.startTime+'-'+item.endTime+', '+item.hours+'小时'">
|
|
|
+ </el-option>
|
|
|
+ </el-select>
|
|
|
+ <el-button type="primary" @click="showTimeEditDialog" style="margin-left: 10px;" v-if="permissions.manageTimeType">管理时间段</el-button>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- <el-form-item label="开始时间" prop="startTime">
|
|
|
<el-time-picker
|
|
|
v-model="overtimeForm.startTime"
|
|
|
value-format="HH:mm"
|
|
|
@@ -46,13 +69,13 @@
|
|
|
format="HH:mm"
|
|
|
placeholder="选择结束时间">
|
|
|
</el-time-picker>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
+ </el-form-item> -->
|
|
|
+<!--
|
|
|
<el-form-item label="加班时长" prop="duration">
|
|
|
<el-input v-model="overtimeForm.duration" placeholder="自动计算或手动输入" readonly>
|
|
|
<template slot="append">小时</template>
|
|
|
</el-input>
|
|
|
- </el-form-item>
|
|
|
+ </el-form-item> -->
|
|
|
|
|
|
<el-form-item label="工作内容" prop="workContent">
|
|
|
<el-input
|
|
|
@@ -64,31 +87,83 @@
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item>
|
|
|
- <el-button type="primary" @click="submitForm('overtimeForm')">提交申请</el-button>
|
|
|
- <el-button @click="resetForm('overtimeForm')">重置</el-button>
|
|
|
+ <el-button type="primary" @click="submitForm('overtimeForm')" >提交申请</el-button>
|
|
|
+ <el-button @click="resetForm('overtimeForm')" >重置</el-button>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
</el-card>
|
|
|
|
|
|
- <!-- 添加人员对话框 -->
|
|
|
- <el-dialog title="添加加班人员" :visible.sync="employeeDialogVisible" width="600px">
|
|
|
- <el-table :data="allEmployees" style="width: 100%" max-height="400">
|
|
|
- <el-table-column prop="name" label="姓名" width="120"></el-table-column>
|
|
|
- <el-table-column prop="department" label="部门"></el-table-column>
|
|
|
- <el-table-column prop="position" label="职位"></el-table-column>
|
|
|
- <el-table-column label="操作" width="100">
|
|
|
+ <!-- 时间段管理对话框 -->
|
|
|
+ <el-dialog title="管理时间段" :visible.sync="timeDialogVisible" width="650px">
|
|
|
+ <div style="margin-bottom: 20px;">
|
|
|
+ <el-button type="primary" @click="showTimeForm" >添加时间段</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-table :data="timeTypeList" style="width: 100%" max-height="400">
|
|
|
+ <el-table-column type="index" label="序号" width="60" :index="indexMethod"></el-table-column>
|
|
|
+ <el-table-column prop="startTime" label="开始时间" width="120"></el-table-column>
|
|
|
+ <el-table-column prop="endTime" label="结束时间" width="120"></el-table-column>
|
|
|
+ <el-table-column prop="hours" label="加班时长" width="120">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ {{ scope.row.hours }}小时
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="150">
|
|
|
<template slot-scope="scope">
|
|
|
<el-button
|
|
|
size="mini"
|
|
|
- @click="addEmployee(scope.row)"
|
|
|
- :disabled="isEmployeeSelected(scope.row.id)">
|
|
|
- 添加
|
|
|
+ type="primary"
|
|
|
+ @click="editTimeType(scope.row)">
|
|
|
+ 编辑
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ size="mini"
|
|
|
+ type="danger"
|
|
|
+ @click="deleteTimeType(scope.row)">
|
|
|
+ 删除
|
|
|
</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
+
|
|
|
<span slot="footer" class="dialog-footer">
|
|
|
- <el-button @click="employeeDialogVisible = false">关闭</el-button>
|
|
|
+ <el-button @click="timeDialogVisible = false">关闭</el-button>
|
|
|
+ </span>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 添加/编辑时间段对话框 -->
|
|
|
+ <el-dialog :title="timeFormTitle" :visible.sync="timeFormVisible" width="500px">
|
|
|
+ <el-form :model="timeForm" :rules="timeFormRules" ref="timeForm" label-width="100px">
|
|
|
+ <el-form-item label="开始时间" prop="startTime">
|
|
|
+ <el-time-picker
|
|
|
+ v-model="timeForm.startTime"
|
|
|
+ value-format="HH:mm"
|
|
|
+ format="HH:mm"
|
|
|
+ placeholder="选择开始时间"
|
|
|
+ style="width: 100%;">
|
|
|
+ </el-time-picker>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="结束时间" prop="endTime">
|
|
|
+ <el-time-picker
|
|
|
+ v-model="timeForm.endTime"
|
|
|
+ value-format="HH:mm"
|
|
|
+ format="HH:mm"
|
|
|
+ placeholder="选择结束时间"
|
|
|
+ style="width: 100%;">
|
|
|
+ </el-time-picker>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="加班时长" prop="hours">
|
|
|
+ <el-input v-model="timeForm.hours" placeholder="自动计算或手动输入" readonly>
|
|
|
+ <template slot="append">小时</template>
|
|
|
+ </el-input>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <span slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="timeFormVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="saveTimeType" :loading="timeFormLoading">保存</el-button>
|
|
|
</span>
|
|
|
</el-dialog>
|
|
|
</div>
|
|
|
@@ -101,25 +176,27 @@
|
|
|
overtimeForm: {
|
|
|
overtimeDate: '',
|
|
|
employees: [],
|
|
|
- startTime: '',
|
|
|
- endTime: '',
|
|
|
- duration: '',
|
|
|
+ mealType: [],
|
|
|
+ timeType: '',
|
|
|
workContent: ''
|
|
|
},
|
|
|
+ user: JSON.parse(sessionStorage.getItem("user")),
|
|
|
+ permissions: JSON.parse(sessionStorage.getItem("permissions")),
|
|
|
// 级联选择器配置
|
|
|
cascaderProps: {
|
|
|
- value: 'id',
|
|
|
- label: 'label',
|
|
|
- children: 'children',
|
|
|
- emitPath: false,
|
|
|
- checkStrictly: false,
|
|
|
- expandTrigger: 'hover',
|
|
|
- // 添加以下配置以支持用户选择
|
|
|
- leaf: (data, node) => {
|
|
|
- // 可以根据数据特征判断是否为叶子节点(如用户节点)
|
|
|
- return !data.children || data.children.length === 0;
|
|
|
- }
|
|
|
-},
|
|
|
+ value: 'id',
|
|
|
+ label: 'label',
|
|
|
+ children: 'children',
|
|
|
+ emitPath: false,
|
|
|
+ checkStrictly: false,
|
|
|
+ expandTrigger: 'hover',
|
|
|
+ multiple: true,
|
|
|
+ // 添加以下配置以支持用户选择
|
|
|
+ leaf: (data, node) => {
|
|
|
+ // 可以根据数据特征判断是否为叶子节点(如用户节点)
|
|
|
+ return !data.children || data.children.length === 0;
|
|
|
+ }
|
|
|
+ },
|
|
|
departmentTree: [],
|
|
|
rules: {
|
|
|
overtimeDate: [
|
|
|
@@ -128,11 +205,11 @@
|
|
|
employees: [
|
|
|
{ required: true, message: '请选择加班人员', trigger: 'change' }
|
|
|
],
|
|
|
- startTime: [
|
|
|
- { required: true, message: '请选择开始时间', trigger: 'change' }
|
|
|
+ timeType: [
|
|
|
+ { required: true, message: '请选择加班时段', trigger: 'change' }
|
|
|
],
|
|
|
- endTime: [
|
|
|
- { required: true, message: '请选择结束时间', trigger: 'change' }
|
|
|
+ mealType: [
|
|
|
+ { required: true, message: '请选择用餐类别', trigger: 'change' }
|
|
|
],
|
|
|
workContent: [
|
|
|
{ required: true, message: '请输入工作内容', trigger: 'blur' }
|
|
|
@@ -141,12 +218,31 @@
|
|
|
employeeOptions: [],
|
|
|
allEmployees: [],
|
|
|
employeeLoading: false,
|
|
|
- employeeDialogVisible: false
|
|
|
+ timeDialogVisible: false,
|
|
|
+ timeFormVisible: false,
|
|
|
+ timeFormLoading: false,
|
|
|
+ timeForm: {
|
|
|
+ id: null,
|
|
|
+ startTime: '',
|
|
|
+ endTime: '',
|
|
|
+ hours: ''
|
|
|
+ },
|
|
|
+ timeFormTitle: '添加时间段',
|
|
|
+ timeFormRules: {
|
|
|
+ startTime: [
|
|
|
+ { required: true, message: '请选择开始时间', trigger: 'change' }
|
|
|
+ ],
|
|
|
+ endTime: [
|
|
|
+ { required: true, message: '请选择结束时间', trigger: 'change' }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ timeTypeList: []
|
|
|
}
|
|
|
},
|
|
|
mounted() {
|
|
|
// 初始化加载部门数据
|
|
|
this.searchEmployees();
|
|
|
+ this.getTimeTypeList();
|
|
|
},
|
|
|
watch: {
|
|
|
// 监听开始时间和结束时间变化,自动计算时长
|
|
|
@@ -155,6 +251,13 @@
|
|
|
},
|
|
|
'overtimeForm.endTime'(newVal) {
|
|
|
this.calculateDuration();
|
|
|
+ },
|
|
|
+ // 监听时间段表单的开始时间和结束时间变化,自动计算时长
|
|
|
+ 'timeForm.startTime'(newVal) {
|
|
|
+ this.calculateTimeFormDuration();
|
|
|
+ },
|
|
|
+ 'timeForm.endTime'(newVal) {
|
|
|
+ this.calculateTimeFormDuration();
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
@@ -179,32 +282,24 @@
|
|
|
this.overtimeForm.duration = diff.toFixed(2);
|
|
|
}
|
|
|
},
|
|
|
+ getTimeTypeList() {
|
|
|
+ this.http.post('/overtime-setting/list',{
|
|
|
+ },
|
|
|
+ res => {
|
|
|
+ if (res.code == "ok") {
|
|
|
+ this.timeTypeList = res.data
|
|
|
+ } else {
|
|
|
+
|
|
|
+ }
|
|
|
+ },
|
|
|
+ error => {
|
|
|
+ }
|
|
|
+ )
|
|
|
+ },
|
|
|
// 获取部门树形结构
|
|
|
searchEmployees() {
|
|
|
- // this.employeeLoading = true;
|
|
|
- // this.http.post('/department/list'),{},
|
|
|
- // res=> {
|
|
|
- // this.employeeLoading = false;
|
|
|
- // if (res.code == "ok") {
|
|
|
- // this.departmentTree = this.transformDepartmentData(res.data);
|
|
|
- // } else {
|
|
|
- // this.departmentTree = [];
|
|
|
- // this.$message({
|
|
|
- // message: res.message || '获取部门数据失败',
|
|
|
- // type: "error"
|
|
|
- // });
|
|
|
- // }
|
|
|
- // },
|
|
|
- // error => {
|
|
|
- // this.employeeLoading = false;
|
|
|
- // this.$message({
|
|
|
- // message: '请求异常',
|
|
|
- // type: "error"
|
|
|
- // });
|
|
|
- // };
|
|
|
- //
|
|
|
this.listLoading = true;
|
|
|
- this.http.post('/department/userlist',{
|
|
|
+ this.http.post('/department/userListInMyRange',{
|
|
|
},
|
|
|
res => {
|
|
|
this.listLoading = false;
|
|
|
@@ -213,7 +308,7 @@
|
|
|
} else {
|
|
|
this.departmentTree = [];
|
|
|
this.$message({
|
|
|
- message: res.message || '获取部门数据失败',
|
|
|
+ message: res.msg || '获取部门数据失败',
|
|
|
type: "error"
|
|
|
});
|
|
|
}
|
|
|
@@ -295,16 +390,137 @@
|
|
|
// }
|
|
|
// },
|
|
|
|
|
|
- // 显示添加员工对话框
|
|
|
- showEmployeeDialog() {
|
|
|
- this.employeeDialogVisible = true;
|
|
|
- this.allEmployees = [
|
|
|
- { id: 1, name: '张三', department: '技术部', position: '前端工程师' },
|
|
|
- { id: 2, name: '李四', department: '产品部', position: '产品经理' },
|
|
|
- { id: 3, name: '王五', department: '设计部', position: 'UI设计师' },
|
|
|
- { id: 4, name: '赵六', department: '技术部', position: '后端工程师' },
|
|
|
- { id: 5, name: '钱七', department: '测试部', position: '测试工程师' }
|
|
|
- ];
|
|
|
+ // 计算时间段表单的加班时长
|
|
|
+ calculateTimeFormDuration() {
|
|
|
+ if (this.timeForm.startTime && this.timeForm.endTime) {
|
|
|
+ const start = this.timeForm.startTime.split(':');
|
|
|
+ const end = this.timeForm.endTime.split(':');
|
|
|
+
|
|
|
+ const startDate = new Date();
|
|
|
+ startDate.setHours(start[0], start[1], 0);
|
|
|
+
|
|
|
+ const endDate = new Date();
|
|
|
+ endDate.setHours(end[0], end[1], 0);
|
|
|
+
|
|
|
+ // 处理跨天情况
|
|
|
+ if (endDate < startDate) {
|
|
|
+ endDate.setDate(endDate.getDate() + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ let diff = (endDate - startDate) / (1000 * 60 * 60); // 转换为小时
|
|
|
+
|
|
|
+ // 检查是否包含午休时间 12:00-13:00,如果包含则减去1小时
|
|
|
+ const lunchStart = new Date();
|
|
|
+ lunchStart.setHours(12, 0, 0);
|
|
|
+ const lunchEnd = new Date();
|
|
|
+ lunchEnd.setHours(13, 0, 0);
|
|
|
+
|
|
|
+ // 如果跨天,午休时间也要相应调整
|
|
|
+ if (endDate.getDate() > startDate.getDate()) {
|
|
|
+ // 跨天情况下,检查第一天是否包含午休
|
|
|
+ if (startDate <= lunchStart) {
|
|
|
+ diff -= 1; // 减去午休1小时
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 同一天内,检查时间段是否包含午休时间
|
|
|
+ if (startDate <= lunchStart && endDate >= lunchEnd) {
|
|
|
+ diff -= 1; // 减去午休1小时
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.timeForm.hours = Math.max(0, diff).toFixed(2); // 确保不为负数
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 显示时间段管理对话框
|
|
|
+ showTimeEditDialog() {
|
|
|
+ this.timeDialogVisible = true;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 序号方法
|
|
|
+ indexMethod(index) {
|
|
|
+ return index + 1;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 显示添加时间段表单
|
|
|
+ showTimeForm() {
|
|
|
+ this.timeFormTitle = '添加时间段';
|
|
|
+ this.timeForm = {
|
|
|
+ id: null,
|
|
|
+ startTime: '',
|
|
|
+ endTime: '',
|
|
|
+ hours: ''
|
|
|
+ };
|
|
|
+ this.timeFormVisible = true;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 编辑时间段
|
|
|
+ editTimeType(row) {
|
|
|
+ this.timeFormTitle = '编辑时间段';
|
|
|
+ this.timeForm = {
|
|
|
+ id: row.id,
|
|
|
+ startTime: row.startTime,
|
|
|
+ endTime: row.endTime,
|
|
|
+ hours: row.hours
|
|
|
+ };
|
|
|
+ this.timeFormVisible = true;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 保存时间段
|
|
|
+ saveTimeType() {
|
|
|
+ this.$refs.timeForm.validate((valid) => {
|
|
|
+ if (valid) {
|
|
|
+ this.timeFormLoading = true;
|
|
|
+ const params = {
|
|
|
+ id: this.timeForm.id,
|
|
|
+ startTime: this.timeForm.startTime,
|
|
|
+ endTime: this.timeForm.endTime,
|
|
|
+ hours: this.timeForm.hours
|
|
|
+ };
|
|
|
+
|
|
|
+ this.http.post('/overtime-setting/addOrUpdate', params,
|
|
|
+ res => {
|
|
|
+ this.timeFormLoading = false;
|
|
|
+ if (res.code == "ok") {
|
|
|
+ this.$message.success(this.timeForm.id ? '编辑成功' : '添加成功');
|
|
|
+ this.timeFormVisible = false;
|
|
|
+ this.getTimeTypeList(); // 重新加载列表
|
|
|
+ } else {
|
|
|
+ this.$message.error(res.msg);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ error => {
|
|
|
+ this.timeFormLoading = false;
|
|
|
+ this.$message.error('请求异常');
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 删除时间段
|
|
|
+ deleteTimeType(row) {
|
|
|
+ this.$confirm('确定要删除这个时间段吗?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ this.http.post('/overtime-setting/delete', { id: row.id },
|
|
|
+ res => {
|
|
|
+ if (res.code == "ok") {
|
|
|
+ this.$message.success('删除成功');
|
|
|
+ this.getTimeTypeList(); // 重新加载列表
|
|
|
+ } else {
|
|
|
+ this.$message.error(res.msg || '删除失败');
|
|
|
+ }
|
|
|
+ },
|
|
|
+ error => {
|
|
|
+ this.$message.error('请求异常');
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }).catch(() => {
|
|
|
+ // 用户取消删除
|
|
|
+ });
|
|
|
},
|
|
|
|
|
|
// 添加员工到加班列表
|
|
|
@@ -323,9 +539,39 @@
|
|
|
submitForm(formName) {
|
|
|
this.$refs[formName].validate((valid) => {
|
|
|
if (valid) {
|
|
|
- // 这里处理表单提交逻辑
|
|
|
- console.log('提交表单:', this.overtimeForm);
|
|
|
- this.$message.success('加班申请提交成功!');
|
|
|
+ // 获取选中的时间段信息
|
|
|
+ const selectedTimeType = this.timeTypeList.find(item => item.id === this.overtimeForm.timeType);
|
|
|
+ if (!selectedTimeType) {
|
|
|
+ this.$message.error('请选择有效的加班时段!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建提交参数,映射到后端实体字段
|
|
|
+ const params = {
|
|
|
+ // applicant: 申请人 - 可以从用户信息中获取,这里暂时留空让后端处理
|
|
|
+ employeeIds: this.overtimeForm.employees.join(','), // 加班员工ID列表,用逗号分隔
|
|
|
+ workDate: this.overtimeForm.overtimeDate, // 加班日期
|
|
|
+ startTime: selectedTimeType.startTime, // 加班开始时间
|
|
|
+ endTime: selectedTimeType.endTime, // 加班结束时间
|
|
|
+ hours: parseFloat(selectedTimeType.hours), // 加班时长
|
|
|
+ content: this.overtimeForm.workContent, // 工作内容
|
|
|
+ timeTypeId: this.overtimeForm.timeType, // 加班时段ID
|
|
|
+ mealType: this.overtimeForm.mealType.join(',') // 用餐类别,用逗号分隔
|
|
|
+ };
|
|
|
+
|
|
|
+ this.http.post('/work-overtime/addOrUpdate', params,
|
|
|
+ res => {
|
|
|
+ if (res.code == "ok") {
|
|
|
+ this.$message.success('加班申请提交成功!');
|
|
|
+ this.resetForm(formName); // 重置表单
|
|
|
+ } else {
|
|
|
+ this.$message.error(res.msg || '提交失败');
|
|
|
+ }
|
|
|
+ },
|
|
|
+ error => {
|
|
|
+ this.$message.error('请求异常');
|
|
|
+ }
|
|
|
+ );
|
|
|
} else {
|
|
|
this.$message.error('请完善表单信息!');
|
|
|
return false;
|
|
|
@@ -357,4 +603,4 @@
|
|
|
width: 100%;
|
|
|
}
|
|
|
}
|
|
|
-</style>
|
|
|
+</style>
|