瀏覽代碼

加班申请手机端

lxy_01 6 小時之前
父節點
當前提交
3075b5f1b7

+ 523 - 0
fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/overtime/overtimeApplication.vue

@@ -0,0 +1,523 @@
+<template>
+  <div class="overtime-apply">
+    <van-card class="form-card">
+      <template #header>
+        <div class="clearfix">
+          <span>加班申请</span>
+        </div>
+      </template>
+      
+      <van-form ref="overtimeForm">
+        <!-- 加班日期 -->
+        <van-field
+          label="加班日期"
+          v-model="overtimeForm.overtimeDate"
+          readonly
+          clickable
+          placeholder="选择加班日期"
+          @click="showDatePicker = true"
+          :rules="[{ required: true, message: '请选择加班日期' }]"
+        />
+
+        <!-- 加班人员 -->
+        <van-field
+          label="加班人员"
+          v-model="overtimeForm.employees"
+          readonly
+          clickable
+          placeholder="请选择部门及人员"
+          @click="popupShow = true"
+          :rules="[{ required: true, message: '请选择加班人员' }]"
+        />
+
+        <!-- 用餐类别 -->
+        <van-field
+          label="用餐类别"
+          v-model="overtimeForm.mealTypeText"
+          readonly
+          clickable
+          placeholder="请选择用餐类别"
+          @click="showMealTypePicker = true"
+          :rules="[{ required: true, message: '请选择用餐类别' }]"
+        />
+
+        <van-popup v-model:show="showMealTypePicker" position="bottom" round closeable>
+          <div style="max-height: 80vh; overflow-y: auto; padding: 20px;">
+            <h3 style="font-size: 16px; margin-bottom: 15px;">选择餐型</h3>
+            <van-checkbox-group v-model="mealTypeIndex">
+              <van-checkbox
+                v-for="(item, index) in mealTypeColumns"
+                :key="index"
+                :name="item.value"
+                style="margin-bottom: 10px;"
+              >
+                {{ item.value }}
+              </van-checkbox>
+            </van-checkbox-group>
+          
+            <div style="margin-top: 20px; display: flex; gap: 10px;">
+              <van-button type="default" block @click="showMealTypePicker = false">取消</van-button>
+              <van-button type="primary" block @click="onMealTypeSubmit">确定</van-button>
+            </div>
+          </div>
+        </van-popup>
+
+        <!-- 加班时段 -->
+        <van-field
+          label="加班时段"
+          v-model="timeTypeText"
+          readonly
+          clickable
+          placeholder="选择开始时间"
+          @click="showTimeTypePickerClick"
+          :rules="[{ required: true, message: '请选择加班时段' }]"
+          class="time-field-with-button"
+        >
+        </van-field>
+        <van-popup v-model:show="showTimeTypePicker" position="bottom">
+          <van-picker
+            v-model="timeTypeIndex"
+            :columns="timeTypeColumnsText"
+            @change="handleTimeTypeChange"
+            @confirm="handleTimeTypeConfirm"
+            @cancel="showTimeTypePicker = false"
+          />
+        </van-popup>
+
+
+        
+
+        <!-- 工作内容 -->
+        <van-field
+          label="工作内容"
+          v-model="overtimeForm.workContent"
+          type="textarea"
+          :rows="4"
+          placeholder="请输入工作内容"
+        />
+
+        <!-- 提交按钮 -->
+        <div style="margin-top: 20px;">
+          <van-button type="primary" @click="submit" native-type="submit" block>提交申请</van-button>
+          <van-button @click="resetForm" plain block style="margin-top: 10px;">重置</van-button>
+        </div>
+      </van-form>
+    </van-card>
+
+     
+    <!-- 弹出层选人 -->
+    <van-popup v-model="popupShow" round position="bottom" :style="{ height: '80%',background: '#F4F4F4' }" >
+      <ChooseSomeone ref="ChooseSomeoneOne" :groupView="this.groupViewNum" :groupViewBack="true" :peopleList="peopleList" :IsOverTime="true" :deptIdTree="deptIdTree" @ChooseSomeoneChanhe="chooseSomeoneChanhe" :peopleListId="peopleListId" ></ChooseSomeone>
+    </van-popup>
+    
+    <!-- 加班日期 -->
+    <!-- 日期 -->
+    <van-calendar v-model="showDatePicker" ref="calendarRef" @confirm="dateOnConfirm" />
+  </div>
+</template>
+
+<script>
+
+import axios from 'axios';
+import ChooseSomeone from '../../components/chooseSomeone.vue'
+import { Dialog, Toast } from 'vant';
+export default {
+
+name: 'OvertimeApply',
+
+  components: {
+    ChooseSomeone,
+  },
+  data() {
+    return {overtimeForm: {
+        overtimeDate: '',       // 加班日期
+        employees: [],          // 选中的员工ID数组
+        employeeIds: [],        // 选中的员工ID数组
+        mealType: [],           // 选中的用餐类别
+        mealTypeId: [],         // 选中的用餐类别ID
+        timeType: '',           // 选中的时间段ID
+        workContent: '',        // 工作内容描述
+        startTime: '',          // 加班开始时间
+        endTime: '',            // 加班结束时间
+        duration: ''            // 加班时长
+      },
+      
+      // 用户信息和权限控制
+      user: JSON.parse(sessionStorage.getItem("user") || '{}'),       // 当前登录用户信息
+      permissions: JSON.parse(sessionStorage.getItem("permissions") || '[]'), // 用户权限列表
+      hasManagePermission: false,  // 是否有时间段管理权限
+      
+      // 日期选择器控制
+      showDatePicker: false,    // 日期选择器弹窗显示状态
+
+      // 部门及人员选择
+      popupShow: false,    // 日期选择器弹窗显示状态
+
+      
+      peopleList: [],   // 可选人员列表
+      peopleListId: [],
+      deptIdTree: [],//部门及人员树状结构数据
+      groupViewNum:3,
+      peopleType:0,
+      //用餐类别
+      mealTypeText: '',
+      // 用餐类别选择器
+      showMealTypePicker: false,
+      // 用餐类别数据
+      mealTypeColumns: [
+        { value: '中餐', id: 0 },
+        { value: '晚餐', id: 1 },
+        { value: '夜宵', id: 2 }
+      ],
+      // 选中的用餐类别索引
+        mealTypeIndex: [],
+      //时间段
+      timeTypeText: '',
+      // 时间段选择器
+      showTimeTypePicker: false,
+      // 时间段编辑器
+      showTimeEditDialog: false,
+      // 时间段数据
+      timeTypeColumns: [
+        { text: '8:00-12:00', value: 1 },
+        { text: '12:00-16:00', value: 2 },
+        { text: '16:00-20:00', value: 3 }
+      ],
+      // 选中的时间段索引
+      timeTypeIndex: 0,
+      showTimeFormDialog: false,
+
+      // 添加编辑时间段的中转数据
+      timeForm: {
+        startTime: '',
+        endTime: '',
+        hours: ''
+      },
+
+      // 开始时间选择器弹窗显示状态
+      showStartPicker: false,
+
+      // 结束时间选择器弹窗显示状态
+      showEndPicker: false,
+
+      // 时间段弹窗显示状态
+      showTimeDialog: false,
+
+      //部门id
+      desId: null,
+      
+    }
+  },
+
+  computed: {
+    timeTypeColumnsText() {
+      return this.timeTypeColumns.map(item => `${item.startTime} - ${item.endTime}, ${item.hours}小时`);
+    }
+  },
+  mounted() {
+    this.getPeople()
+    this.getTimeTypeList();
+  },
+  watch: {
+    // 监听开始时间和结束时间变化,自动计算时长
+    'overtimeForm.startTime'(newVal) {
+      this.calculateDuration();
+    },
+    'overtimeForm.endTime'(newVal) {
+      this.calculateDuration();
+    },
+    // 监听时间段表单的开始时间和结束时间变化,自动计算时长
+    'timeForm.startTime'(newVal) {
+      this.calculateTimeFormDuration();
+    },
+    'timeForm.endTime'(newVal) {
+      this.calculateTimeFormDuration();
+    }
+  },
+  methods: {
+    //时间选择相关
+    dateOnConfirm(date) {
+      this.overtimeForm.overtimeDate = this.formatDate(date);
+      this.showDatePicker = false;
+    },
+    
+
+    formatDate(date) {
+      // 中国标准时间转成 YYYY-MM-DD
+      const year = date.getFullYear();
+      const month = date.getMonth() + 1;
+      const day = date.getDate();
+      return `${year}-${month < 10 ? '0' + month : month}-${day < 10 ? '0' + day : day}`;
+    },
+
+    
+    // 选中人员
+    chooseSomeoneChanhe(item) {
+      console.log('当前点击的人员', item)
+      let arr = item.map(item => {
+        return item.id
+      })
+      let nameArr = item.map(item => {
+        return item.name
+      })
+      this.employeeIds = arr
+      
+      this.overtimeForm.employeeIds = arr
+      this.overtimeForm.employees = nameArr
+      this.popupShow = false
+      this.$emit('flashList')
+    },
+    // 时间段选择器确认事件
+    handleTimeTypeConfirm() {
+      this.timeTypeText = this.timeTypeColumns.find(item => item.value == this.overtimeForm.timeType).text;
+      this.showTimeTypePicker = false;
+    },
+    // 重置表单
+    resetForm() {   
+      this.overtimeForm = {
+        overtimeDate: '',       // 加班日期
+        employees: [],          // 选中的员工ID数组
+        mealType: [],           // 选中的用餐类别
+        timeType: '',           // 选中的时间段ID
+        workContent: '',        // 工作内容描述
+        startTime: '',          // 加班开始时间
+        endTime: '',            // 加班结束时间
+        duration: ''            // 加班时长
+      }
+      this.timeTypeText = ''
+      this.timeForm = {
+        startTime: '',
+        endTime: '',
+        hours: ''
+      }
+      this.mealTypeText = ''
+      this.mealTypeIndex = []
+      
+      if (this.$refs.calendarRef && this.$refs.calendarRef.reset) {
+        this.$refs.calendarRef.reset();
+      }
+    },
+
+    
+    getPeople() {
+      this.$axios.post('/department/userListInMyRange', {
+      })
+      .then(res => {
+        if (res.code == "ok") {
+          let list = res.data;
+          let newList = JSON.parse(JSON.stringify(list))
+          if(newList && newList.length > 0) {
+            this.desId = newList[0].id
+          }
+          this.deptIdTree = list
+          console.log(this.peopleList)
+        } else {
+          JSON.parse()
+          this.$toast.clear();
+          this.$toast.fail(res.msg);
+        }
+      }).catch(err => { this.$toast.clear(); });
+    },
+
+
+    showTimeForm() {
+      // 显示添加时间段表单的逻辑
+      console.log("显示添加时间段表单")
+    },
+
+    // 用餐类别 提交选择
+    onMealTypeSubmit() {
+      this.overtimeForm.mealTypeText = this.mealTypeIndex.join(',')
+      this.overtimeForm.mealTypeId = this.mealTypeIndex.map(item => item.id)
+      this.mealTypeText = this.mealTypeIndex.join(',')
+      this.showMealTypePicker = false;
+    },
+
+    // 加班时段选择器点击事件
+    showTimeTypePickerClick() {
+      this.showTimeTypePicker = true;
+    },
+
+    //时间段弹窗点击事件
+    handleTimeTypeChange(picker,value,index) {
+      console.log(value, index)
+      this.overtimeForm.startTime = this.timeTypeColumns[index].startTime
+      this.overtimeForm.endTime = this.timeTypeColumns[index].endTime
+      this.overtimeForm.timeType = this.timeTypeColumns[index].id
+      this.timeTypeText = this.overtimeForm.startTime + ' - ' + this.overtimeForm.endTime + ', ' + this.timeTypeColumns[index].hours + '小时';
+      this.showTimeTypePicker = false;
+    },
+
+    //加载时间段列表
+    getTimeTypeList() {
+      this.$axios.post('/overtime-setting/list',{
+          }).then(
+          res => {
+            if (res.code == "ok") {
+              this.timeTypeColumns = res.data
+            } else {
+              
+            }
+          },
+          error => {
+            console.error('获取时间段列表失败:', error);
+          }
+      ).catch(err => { this.$toast.clear(); });
+    },
+
+    //时间段编辑
+    editTimeType(item) {
+      this.showTimeFormDialog = true;
+      this.timeForm = { ...item }; // 复制当前时间段数据到表单
+      this.showStartPicker = false;
+      this.showEndPicker = false;
+    },
+
+    //时间段删除
+    deleteTimeType(item) {
+      Dialog.confirm({
+          title: '确认删除',
+          message: `确定要删除该时间段吗?\n此操作不可撤销`,
+          messageAlign: 'left',
+          confirmButtonText: '删除',
+          cancelButtonText: '取消',
+          theme: 'round-button',
+        })
+          .then(() => {
+            // 用户点击“删除”
+            this.$axios.post('/overtime-setting/delete', {
+              id: item.id
+            }).then(res => {
+              if (res.code == "ok") {
+                this.getTimeTypeList()
+                Toast.success('时间段删除成功');
+              } else {
+                JSON.parse()
+                this.$toast.clear();
+                this.$toast.fail(res.msg);
+              }
+            })
+          })
+          .catch(() => {
+            // 用户点击“取消”,什么也不做
+          });
+    },
+
+    // 开始时间选择器确认事件
+    onStartConfirm(value) {
+      this.timeForm.startTime = value;
+      this.showStartPicker = false;
+    },
+    // 结束时间选择器确认事件
+    onEndConfirm(value) {
+      this.timeForm.endTime = value;
+      this.showEndPicker = false;
+    },
+
+    //提交申请
+    submit() {
+      if (
+          this.overtimeForm.overtimeDate && this.overtimeForm.overtimeDate.trim() !== '' &&
+          this.overtimeForm.employeeIds && this.overtimeForm.employeeIds.length > 0 &&
+          this.overtimeForm.mealTypeText && this.overtimeForm.mealTypeText.trim() !== '' &&
+          this.overtimeForm.timeType &&
+          this.overtimeForm.workContent && this.overtimeForm.workContent.trim() !== '' &&
+          this.overtimeForm.startTime && this.overtimeForm.startTime.trim() !== '' &&
+          this.overtimeForm.endTime && this.overtimeForm.endTime.trim() !== '' &&
+          this.overtimeForm.duration && this.overtimeForm.duration.trim() !== ''
+        ) {
+        // 所有必填项均已填写,继续提交
+      } else {
+        this.$toast.fail('请填写完整的加班申请信息');
+        return;
+      } 
+      // 构建提交参数,映射到后端实体字段
+      const params = {
+        // applicant: 申请人 - 可以从用户信息中获取,这里暂时留空让后端处理
+        employeeIds: this.overtimeForm.employeeIds.join(','), // 加班员工ID列表,用逗号分隔
+        workDate: this.overtimeForm.overtimeDate, // 加班日期
+        startTime: this.overtimeForm.startTime, // 加班开始时间
+        endTime: this.overtimeForm.endTime, // 加班结束时间
+        hours: parseFloat(this.overtimeForm.duration), // 加班时长
+        content: this.overtimeForm.workContent, // 工作内容
+        timeTypeId: this.overtimeForm.timeType, // 加班时段ID
+        mealType: this.overtimeForm.mealTypeText, // 用餐类别,用逗号分隔
+      }
+      console.log(params)
+      this.$axios.post('/work-overtime/addOrUpdate', params)
+      .then(
+        res => {
+          if (res.code == "ok") {
+            console.log(res)
+            Toast.success('加班申请提交成功!');
+            this.resetForm(); // 重置表单
+          } else {
+            console.log(res)
+            Toast.fail(res.msg || '提交失败');
+          }
+        },
+
+      )
+      .catch(
+        error => {
+          console.log('catch 错误:', error)
+          Toast.fail('请求异常');
+        });
+    },
+
+    
+    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);
+      }
+    },
+ }
+}
+</script>
+
+<style scoped>
+.overtime-apply {
+  padding: 10px;
+}
+
+.form-card {
+  margin-bottom: 10px;
+}
+
+.clearfix::after {
+  content: "";
+  display: table;
+  clear: both;
+}
+
+.van-table {
+  --van-table-row-height: 40px;
+}
+
+.time-field-with-button {
+  position: relative;
+}
+
+.manage-time-btn {
+  position: absolute;
+  right: 10px;
+  top: 50%;
+  transform: translateY(-50%);
+  z-index: 1;
+}
+</style>