|
|
@@ -0,0 +1,360 @@
|
|
|
+<template>
|
|
|
+ <div class="overtime-apply">
|
|
|
+ <el-card class="form-card">
|
|
|
+ <div slot="header" class="clearfix">
|
|
|
+ <span>加班申请</span>
|
|
|
+ </div>
|
|
|
+ <el-form :model="overtimeForm" :rules="rules" ref="overtimeForm" label-width="100px">
|
|
|
+ <el-form-item label="加班日期" prop="overtimeDate">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="overtimeForm.overtimeDate"
|
|
|
+ type="date"
|
|
|
+ placeholder="选择加班日期"
|
|
|
+ value-format="yyyy-MM-dd"
|
|
|
+ format="yyyy-MM-dd">
|
|
|
+ </el-date-picker>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="加班人员" prop="employees">
|
|
|
+ <el-cascader
|
|
|
+ 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-time-picker
|
|
|
+ v-model="overtimeForm.startTime"
|
|
|
+ value-format="HH:mm"
|
|
|
+ format="HH:mm"
|
|
|
+ placeholder="选择开始时间">
|
|
|
+ </el-time-picker>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="结束时间" prop="endTime">
|
|
|
+ <el-time-picker
|
|
|
+ v-model="overtimeForm.endTime"
|
|
|
+ value-format="HH:mm"
|
|
|
+ format="HH:mm"
|
|
|
+ placeholder="选择结束时间">
|
|
|
+ </el-time-picker>
|
|
|
+ </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 label="工作内容" prop="workContent">
|
|
|
+ <el-input
|
|
|
+ type="textarea"
|
|
|
+ :rows="4"
|
|
|
+ placeholder="请输入工作内容"
|
|
|
+ v-model="overtimeForm.workContent">
|
|
|
+ </el-input>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item>
|
|
|
+ <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">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-button
|
|
|
+ size="mini"
|
|
|
+ @click="addEmployee(scope.row)"
|
|
|
+ :disabled="isEmployeeSelected(scope.row.id)">
|
|
|
+ 添加
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <span slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="employeeDialogVisible = false">关闭</el-button>
|
|
|
+ </span>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>export default {
|
|
|
+ name: 'OvertimeApply',
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ overtimeForm: {
|
|
|
+ overtimeDate: '',
|
|
|
+ employees: [],
|
|
|
+ startTime: '',
|
|
|
+ endTime: '',
|
|
|
+ duration: '',
|
|
|
+ workContent: ''
|
|
|
+ },
|
|
|
+ // 级联选择器配置
|
|
|
+ cascaderProps: {
|
|
|
+ value: 'id',
|
|
|
+ label: 'label',
|
|
|
+ children: 'children',
|
|
|
+ emitPath: false,
|
|
|
+ checkStrictly: false,
|
|
|
+ expandTrigger: 'hover',
|
|
|
+ // 添加以下配置以支持用户选择
|
|
|
+ leaf: (data, node) => {
|
|
|
+ // 可以根据数据特征判断是否为叶子节点(如用户节点)
|
|
|
+ return !data.children || data.children.length === 0;
|
|
|
+ }
|
|
|
+},
|
|
|
+ departmentTree: [],
|
|
|
+ rules: {
|
|
|
+ overtimeDate: [
|
|
|
+ { required: true, message: '请选择加班日期', trigger: 'change' }
|
|
|
+ ],
|
|
|
+ employees: [
|
|
|
+ { required: true, message: '请选择加班人员', trigger: 'change' }
|
|
|
+ ],
|
|
|
+ startTime: [
|
|
|
+ { required: true, message: '请选择开始时间', trigger: 'change' }
|
|
|
+ ],
|
|
|
+ endTime: [
|
|
|
+ { required: true, message: '请选择结束时间', trigger: 'change' }
|
|
|
+ ],
|
|
|
+ workContent: [
|
|
|
+ { required: true, message: '请输入工作内容', trigger: 'blur' }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ employeeOptions: [],
|
|
|
+ allEmployees: [],
|
|
|
+ employeeLoading: false,
|
|
|
+ employeeDialogVisible: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ // 初始化加载部门数据
|
|
|
+ this.searchEmployees();
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ // 监听开始时间和结束时间变化,自动计算时长
|
|
|
+ 'overtimeForm.startTime'(newVal) {
|
|
|
+ this.calculateDuration();
|
|
|
+ },
|
|
|
+ 'overtimeForm.endTime'(newVal) {
|
|
|
+ this.calculateDuration();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 计算加班时长
|
|
|
+ calculateDuration() {
|
|
|
+ if (this.overtimeForm.startTime && this.overtimeForm.endTime) {
|
|
|
+ const start = this.overtimeForm.startTime.split(':');
|
|
|
+ const end = this.overtimeForm.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);
|
|
|
+ }
|
|
|
+
|
|
|
+ const diff = (endDate - startDate) / (1000 * 60 * 60); // 转换为小时
|
|
|
+ this.overtimeForm.duration = diff.toFixed(2);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 获取部门树形结构
|
|
|
+ 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',{
|
|
|
+ },
|
|
|
+ res => {
|
|
|
+ this.listLoading = 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"
|
|
|
+ });
|
|
|
+ }
|
|
|
+ )
|
|
|
+ },
|
|
|
+
|
|
|
+// 转换部门数据为级联选择器格式
|
|
|
+ transformDepartmentData(departments) {
|
|
|
+ return departments.map(dept => {
|
|
|
+ const item = {
|
|
|
+ id: dept.id,
|
|
|
+ label: dept.label,
|
|
|
+ value: dept.id
|
|
|
+ };
|
|
|
+
|
|
|
+ // 如果有子部门,递归处理
|
|
|
+ if (dept.children && dept.children.length > 0) {
|
|
|
+ item.children = this.transformDepartmentData(dept.children);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果有用户列表,添加到子节点中
|
|
|
+ if (dept.userList && dept.userList.length > 0) {
|
|
|
+ if (!item.children) {
|
|
|
+ item.children = [];
|
|
|
+ }
|
|
|
+ dept.userList.forEach(user => {
|
|
|
+ item.children.push({
|
|
|
+ id: user.id,
|
|
|
+ label: user.name,
|
|
|
+ value: user.id
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ return item;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ handleEmployeeChange(value) {
|
|
|
+ console.log('选择的员工:', value);
|
|
|
+ },
|
|
|
+ // 搜索员工
|
|
|
+ // searchEmployees(query) {
|
|
|
+ // if (query !== '') {
|
|
|
+ // this.employeeLoading = true;
|
|
|
+ // request({
|
|
|
+ // url: "/department/list",
|
|
|
+ // method: "get",
|
|
|
+ //
|
|
|
+ // })
|
|
|
+ // .then(response => {
|
|
|
+ // this.loading = false;
|
|
|
+ // if (response.code == 'ok') {
|
|
|
+ // this.$message({
|
|
|
+ // message: "操作成功",
|
|
|
+ // type: "success"
|
|
|
+ // });
|
|
|
+ // this.dialogVisible = false;
|
|
|
+ // this.employeeOptions=response.data;
|
|
|
+ // } else {
|
|
|
+ // this.employeeOptions=[];
|
|
|
+ // this.$message({
|
|
|
+ // message: response.message,
|
|
|
+ // type: "error"
|
|
|
+ // });
|
|
|
+ // }
|
|
|
+ //
|
|
|
+ // })
|
|
|
+ // .catch(error => {
|
|
|
+ // this.loading = false;
|
|
|
+ // });
|
|
|
+ // }
|
|
|
+ // },
|
|
|
+
|
|
|
+ // 显示添加员工对话框
|
|
|
+ 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: '测试工程师' }
|
|
|
+ ];
|
|
|
+ },
|
|
|
+
|
|
|
+ // 添加员工到加班列表
|
|
|
+ addEmployee(employee) {
|
|
|
+ if (!this.overtimeForm.employees.includes(employee.id)) {
|
|
|
+ this.overtimeForm.employees.push(employee.id);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 检查员工是否已选择
|
|
|
+ isEmployeeSelected(employeeId) {
|
|
|
+ return this.overtimeForm.employees.includes(employeeId);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 提交表单
|
|
|
+ submitForm(formName) {
|
|
|
+ this.$refs[formName].validate((valid) => {
|
|
|
+ if (valid) {
|
|
|
+ // 这里处理表单提交逻辑
|
|
|
+ console.log('提交表单:', this.overtimeForm);
|
|
|
+ this.$message.success('加班申请提交成功!');
|
|
|
+ } else {
|
|
|
+ this.$message.error('请完善表单信息!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 重置表单
|
|
|
+ resetForm(formName) {
|
|
|
+ this.$refs[formName].resetFields();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">.overtime-apply {
|
|
|
+ padding: 20px;
|
|
|
+
|
|
|
+ .form-card {
|
|
|
+ max-width: 800px;
|
|
|
+ margin: 0 auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-form-item {
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-select {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|