Răsfoiți Sursa

考勤功能

cyy 1 an în urmă
părinte
comite
ec3eed5c5e

+ 1 - 1
.env

@@ -1,7 +1,7 @@
 # 所有环境默认
 
 # 页面 title 前缀
-VUE_APP_TITLE= '深圳金源信通科技有限公司'
+VUE_APP_TITLE= '深圳金源信通科技有限公司'
 
 # 是否启用CDN
 VUE_APP_CDN = false

+ 2 - 0
public/config.js

@@ -3,6 +3,8 @@
   global.__IBPS_CONFIG__ = {
     // 是否启用配置
     ENABLE_CONFIG: true,
+    // 是否启用打卡
+    CLOCK_CONFIG: true,
     BASE_URL,
     //  api
     BASE_API: `${BASE_URL}ibps`,

+ 27 - 0
src/api/platform/feature/clockReissue.js

@@ -0,0 +1,27 @@
+import request from '@/utils/request'
+import { BPMN_URL } from '@/api/baseUrl'
+import ActionUtil from '@/utils/action'
+
+/**
+ * 打卡
+ * @param {*} params
+ */
+export function saveClockIn(params) {
+  return request({
+    url: BPMN_URL() + '/employee/attendanceDetail/clockIn',
+    method: 'post',
+    // data
+    params: params
+  })
+}
+/**
+ * 补卡
+ * @param {*} params
+ */
+export function saveReissue(data) {
+  return request({
+    url: BPMN_URL() + '/employee/attendanceReissue/save',
+    method: 'post',
+    data
+  })
+}

+ 3 - 0
src/constant.js

@@ -70,3 +70,6 @@ export const SYSTEM_NAME = __IBPS_CONFIG__.SYSTEM_NAME || '金通医学实验室
 export const SHOW_PLAINTEXT = __IBPS_CONFIG__.SHOW_PLAINTEXT || env.NODE_ENV === 'development'
 // 是否加密 GET 请求参数
 export const ENCRYPT_GET_PARAMS = __IBPS_CONFIG__.ENCRYPT_GET_PARAMS || false
+
+export const clockConfig = __IBPS_CONFIG__.CLOCK_CONFIG || false
+

+ 1 - 1
src/locales/zh-CN.json

@@ -32,7 +32,7 @@
       "ts": "暂存",
       "undo": "重做"
     },
-    "company": "深圳金源信通科技有限公司",
+    "company": "深圳金源信通科技有限公司",
     "copyright": "版权所有",
     "dialog": {
       "multipleSelected": "已经选择了多项,请选择一项进行操作!",

+ 1 - 1
src/locales/zh-TW.json

@@ -32,7 +32,7 @@
 			"ts": "暫存",
 			"undo": "重做"
 		},
-		"company": "深圳金源信通科技有限公司",
+		"company": "深圳金源信通科技有限公司",
 		"copyright": "版權所有",
 		"dialog": {
 			"multipleSelected": "已經選擇了多項,請選擇一項進行操作!",

+ 6 - 0
src/router/routes.js

@@ -426,6 +426,12 @@ const frameCustom = [
         meta: { title: '我的排班' },
         component: _import('/platform/bpmn/my-schedule/index')
       },
+      {
+        path: 'myReissue/index',
+        name: 'myReissue',
+        meta: { title: '补卡记录' },
+        component: _import('/platform/bpmn/my-reissue/index')
+      },
       {
         path: 'shiftTransferApplication/staList',
         name: 'shiftTransferApplication',

+ 1 - 1
src/setting.js

@@ -1,7 +1,7 @@
 import { version } from '../package'
 
 export default {
-  title: '深圳金源信通科技有限公司',
+  title: '深圳金源信通科技有限公司',
   // 版本
   releases: {
     version: version,

+ 799 - 0
src/views/platform/bpmn/my-reissue/components/reissueDialog.vue

@@ -0,0 +1,799 @@
+<template>
+  <van-overlay class="backgroundSty20250425" z-index="2002" :show="showPop" :lock-scroll="false">
+      <div style="height:5%">
+          <van-sticky>
+              <van-nav-bar
+                  :title="
+                      '补卡记录 ' +
+                          (typeValue == '3'
+                              ? '编制'
+                              : typeValue == '4'
+                                  ? '重新申请'
+                                  : typeValue == '1'
+                                      ? '详情'
+                                      : '')
+                  "
+                  :right-text="typeValue == '4' ? '退回原因' : ''"
+                  @click-left="closePop()"
+                  @click-right="getBack()"
+              >
+                  <template #left>
+                      <van-icon name="cross" class="ibps-nav-bar__close-icon" />
+                  </template>
+              </van-nav-bar>
+          </van-sticky>
+      </div>
+      <div class="scrollView">
+          <van-form @submit="onSubmit">
+              <van-field
+                  required
+                  label="补卡日期:"
+                  placeholder="请选择补卡日期"
+                  label-width="6em"
+                  :value="form.buKaRiQi"
+                  :readonly="typeValue != 3 || openType != 'reissue' ? true : false"
+                  @click="typeValue == 3 && openType == 'reissue' ? buKaRiQiClick(form.buKaRiQi):''"
+              />
+              <van-popup v-model="dateShow" position="bottom">
+                  <van-datetime-picker
+                      v-model="xuanzeDate"
+                      type="date"
+                      :min-date="minDate"
+                      :max-date = "maxDate"
+                      @confirm="dateShowCallback"
+                      @cancel="dateShow = false"
+                  />
+              </van-popup>
+              <van-field
+                  required
+                  label="补卡班次:"
+                  placeholder="请选择补卡班次"
+                  label-width="6em"
+                  :value="form.buKaBanCi"
+                  :readonly="list.length===0 || typeValue != 3  || openType != 'reissue'  ? true : false"
+                  @click="list.length>0 && typeValue == 3 && openType == 'reissue'? sheetShow = true:''"
+              />
+              <van-popup v-model="sheetShow" position="bottom">
+                  <van-picker
+                      show-toolbar
+                      :columns="list"
+                      @confirm="actionSheetCallback"
+                      @cancel="sheetShow = false"
+                  />
+              </van-popup>
+              <van-field
+                  required
+                  label="补卡类型:"
+                  :placeholder="form.buKaBanCi!=''&&typeList.length>0&&(typeValue == 3 || typeValue == 4)?'请选择补卡类型':'请先选择补卡班次'"
+                  label-width="6em"
+                  :value="form.buKaLeiXing"
+                  :readonly="form.buKaBanCi==''||typeList.length===0 || typeValue != 3|| openType != 'reissue' ? true : false"
+                  @click="form.buKaBanCi!=''&&typeList.length>0&&typeValue == 3&& openType == 'reissue'  ? typeShow = true:''"
+              />
+              <van-popup v-model="typeShow" position="bottom">
+                  <van-picker
+                      show-toolbar
+                      :columns="typeList"
+                      @confirm="actionTypeCallback"
+                      @cancel="typeShow = false"
+                  />
+              </van-popup>
+              <van-field
+                  required
+                  label="补卡时间:"
+                  :placeholder="form.buKaLeiXing!=''&&(typeValue == 3 || typeValue == 4) ? '请选择补卡时间':'请先选择补卡类型'"
+                  label-width="6em"
+                  :value="form.buKaShiJian"
+                  :readonly="form.buKaLeiXing==''||(typeValue != 3 && typeValue != 4) ? true : false"
+                  @click="form.buKaLeiXing!=''&&(typeValue == 3 || typeValue == 4) ?buKaShiJianClick(form.buKaShiJian):''"
+              />
+              <van-popup v-model="timeShow" position="bottom">
+                  <van-datetime-picker
+                      v-model="xuanzeTime"
+                      type="datetime"
+                      :min-date="minTime"
+                      :max-date = "maxTime"
+                      @confirm="timeShowCallback"
+                      @cancel="timeShow = false"
+                  />
+              </van-popup>
+              <van-cell-group>
+                <div class="verticalLine" style="width:6em;padding: 1em 0;">
+                    补卡事由
+                </div>
+                <van-field
+                    v-model="form.buKaShiYou"
+                    autosize
+                    type="textarea"
+                    label=""
+                    placeholder="请输入补卡事由"
+                    label-width="0"
+                    clearable
+                    :readonly="typeValue != 3 && typeValue != 4 ? true : false"
+                />
+              </van-cell-group>
+          </van-form>
+
+          <ibps-uploader
+              v-model="form.fuJian"
+              label="说明附件"
+              download
+              placeholder="请上传附件"
+              :have-padding="false"
+              multiple
+              clearable
+              :readonly="typeValue != 3 && typeValue != 4 ? true : false"
+          />
+          <div v-if="typeValue == '3'" class="padding flex flex-direction">
+              <van-button
+                  type="success"
+                  class="btn btn-back-color"
+                  @click="onSubmit"
+              >
+                提交
+              </van-button>
+          </div>
+          <div v-if="typeValue == '2'" class="padding flex flex-direction">
+              <van-button
+                  type="success"
+                  class="btn btn-back-color"
+                  @click="onAgree('已完成', '同意', '确定')"
+              >
+                同意
+              </van-button>
+          </div>
+          <div v-if="typeValue == '4'" class="padding flex flex-direction">
+              <van-button
+                  type="success"
+                  class="btn btn-back-color"
+                  @click="onAgree('待审核', '重新提交', '申请')"
+              >
+                重新申请
+              </van-button>
+          </div>
+      </div>
+  </van-overlay>
+</template>
+<script>
+import random from '@/mixins/random'
+import bpmnStatus from '@/mixins/bpmnStatus'
+import IbpsUploader from '@/business/platform/file/uploader'
+import { Toast } from 'vant'
+import { saveReissue } from '@/api/platform/feature/clockReissue'
+
+export default {
+  components: {
+    IbpsUploader
+  },
+  mixins: [random, bpmnStatus],
+  props: {
+    showPop: {
+      type: Boolean,
+      default: false
+    },
+    typeValue: {
+      type: String,
+      default: '3'
+    },
+    id: {
+      type: String,
+      default: ''
+    },
+    openType: {
+      type: String,
+      default: 'reissue'
+    },
+    reissueData: {
+      type: Object,
+      default: () => {}
+    },
+    selectDate: {
+      type: String,
+      default: ''
+    },
+    reissueType: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    const { userId, userInfo } = this.$store.getters
+    return {
+      userId,
+      userInfo,
+      show: this.showPop,
+      sheetShow: false,
+      typeShow: false,
+      taskId: '',
+      form: {
+        buKaBanCi: '',
+        buKaShiYou: '',
+        buKaShiJian: '',
+        buKaRiQi: '',
+        fuJian: ''
+      },
+      list: [],
+      typeList: [
+        { text: '上班' },
+        { text: '下班' }
+      ],
+      backShow: false,
+      option: '',
+      content: '',
+      dateShow: false,
+      timeShow: false,
+      level: null,
+      mainPosition: {
+        id: ''
+      },
+      xuanzeDate: null,
+      xuanzeTime: null,
+      maxDate: new Date(),
+      minTime: new Date(),
+      maxTime: new Date(),
+      approver: ''
+    }
+  },
+  computed: {
+    rightText() {
+      return this.checkMode
+        ? this.$t('common.button.cancel')
+        : this.$t('common.button.manage')
+    },
+    selectedIds() {
+      return this.checkedIds.join(',')
+    },
+    minDate() {
+      const today = new Date()
+      const last = new Date(today)
+      last.setMonth(last.getMonth() - 1)
+      return last
+    }
+  },
+  watch: {
+    showPop: {
+      handler: function(val, oldVal) {
+        if (val === true) {
+          this.form = {
+            buKaBanCi: '',
+            buKaShiYou: '',
+            buKaShiJian: '',
+            buKaRiQi: '',
+            fuJian: '',
+            buKaLeiXing: ''
+          }
+          this.getInit()
+          this.level = this.$store.getters.level
+          const mid = JSON.parse(localStorage.getItem('mainPosition'))
+          const mainPosition = mid || (this.userInfo && this.userInfo.mainPosition ? this.userInfo.mainPosition : null)
+          this.mainPosition = mainPosition
+
+          if (this.id && this.id !== '') {
+            this.getInfo(this.id)
+          }
+        }
+      },
+      immediate: true
+    },
+    xuanzeDate: {
+      handler: async function(val, oldVal) {
+        // console.log(val, 'valvalval')
+        if (val !== null && this.openType === 'reissue') {
+          const scheduleData = await this.schedule(val)
+          const midData = []
+          this.list = []
+          scheduleData.forEach((item, i) => {
+            const diff = this.getDaysDifference(item.start_date_, val)
+            const dateName = item['d' + diff + '_']
+
+            const dateArr = dateName.split(',')
+
+            if (dateArr.length > 1) {
+              dateArr.forEach((x, y) => {
+                const midObj = this.isValidJSON(item.config_) ? JSON.parse(item.config_).scheduleShift.find(d => d.alias === x) : ''
+                const approver = this.isValidJSON(item.config_) ? JSON.parse(item.config_).approver : ''
+                midData.push({ name: x, config: midObj, approver: approver })
+                this.list.push({ text: x, config: midObj, approver: approver })
+              })
+            } else {
+              const midObj = this.isValidJSON(item.config_) ? JSON.parse(item.config_).scheduleShift.find(d => d.alias === dateArr[0]) : ''
+              const approver = this.isValidJSON(item.config_) ? JSON.parse(item.config_).approver : ''
+              midData.push({ name: dateArr[0], config: midObj, approver: approver })
+              this.list.push({ text: dateArr[0], config: midObj, approver: approver })
+            }
+          })
+          console.log(midData)
+        }
+      },
+      immediate: true
+    },
+    'form.buKaBanCi': {
+      handler: async function(val, oldVal) {
+        if (val === '') {
+          this.xuanzeTime = null
+          this.form.buKaShiJian = ''
+          this.typeList = [
+            { text: '上班' },
+            { text: '下班' }
+          ]
+        } else {
+          const reissueDataIn = await this.reissue()
+          if (reissueDataIn.length > 0) {
+            const up = reissueDataIn.filter(t => t.bu_ka_ban_ci_.includes('上班'))
+            const down = reissueDataIn.filter(t => t.bu_ka_ban_ci_.includes('下班'))
+            if (up.length > 0 && down.length > 0) {
+              this.typeList = []
+            } else if (up.length > 0) {
+              this.typeList = [{ text: '下班' }]
+            } else if (down.length > 0) {
+              this.typeList = [{ text: '上班' }]
+            } else {
+              this.typeList = [
+                { text: '上班' },
+                { text: '下班' }
+              ]
+            }
+          } else {
+            this.typeList = [
+              { text: '上班' },
+              { text: '下班' }
+            ]
+          }
+        }
+      },
+      immediate: true
+    }
+  },
+  created() {},
+  methods: {
+    closePop(val = '2') {
+      this.$emit('updataSet', false, val)
+    },
+    actionSheetCallback(e) {
+      this.form.buKaBanCi = e.text
+      const midStr = this.$common.getFormatDate('string', 10, this.xuanzeDate)
+      const midDate = new Date(midStr)
+      const midMax = this.$common.getFormatDate('string', 10, midDate.setDate(midDate.getDate() + 1))
+
+      if (e.config.dateRange[0].isSecondDay === 'Y') {
+        this.minTime = new Date(midStr + ' 00:00:00')
+        this.maxTime = new Date(midMax + ' 23:59:59')
+      } else {
+        this.minTime = new Date(midStr + ' 00:00:00')
+        this.maxTime = new Date(midStr + ' 23:59:59')
+      }
+      this.sheetShow = false
+      this.approver = e.approver
+    },
+    actionTypeCallback(e) {
+      this.form.buKaLeiXing = e.text
+      this.typeShow = false
+    },
+    async schedule(val) {
+      const date = this.$common.getFormatDate('string', 10, val)
+      const sql = `select a.id_ AS fid,a.start_date_,a.end_date_,a.config_,a.overview_,b.* FROM t_schedule_detail b JOIN t_schedule a ON a.id_ = b.parent_id_ WHERE a.status_ = '已发布' AND b.user_id_ = '${this.userId}' AND ('${date}'  BETWEEN CAST( a.start_date_ AS DATE ) AND CAST( a.end_date_ AS DATE ))`
+      return new Promise((resolve, reject) => {
+        this.$common.request('sql', sql).then(res => {
+          const data = res.variables.data || []
+          resolve(data)
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+    async reissue() {
+      const sql = `select * FROM t_attendance_reissue WHERE bian_zhi_ren_ = '${this.userId}' AND bu_ka_ri_qi_ like '%${this.form.buKaRiQi}%' and bu_ka_ban_ci_ like '%${this.form.buKaBanCi}%' and zhuang_tai_ != '已撤销'`
+      return new Promise((resolve, reject) => {
+        this.$common.request('sql', sql).then(res => {
+          const data = res.variables.data || []
+          resolve(data)
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+    async clockIn() {
+      const sql = `select * FROM t_attendance_detail WHERE yong_hu_id_ = '${this.userId}' AND ri_qi_ like '%${this.form.buKaRiQi}%' and ban_ci_bie_ming_ like '%${this.form.buKaBanCi}%' order by create_time_ desc`
+      return new Promise((resolve, reject) => {
+        this.$common.request('sql', sql).then(res => {
+          const data = res.variables.data || []
+          resolve(data)
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+    isValidJSON(text) {
+      try {
+        JSON.parse(text)
+        return true
+      } catch (error) {
+        return false
+      }
+    },
+    dateShowCallback(e) {
+      // const nowDate = new Date(e.getTime() + 8 * 60 * 60 * 1000)
+      const time = this.$common.getFormatDate('string', 10, e)
+      this.form.buKaRiQi = time
+      this.dateShow = false
+    },
+    timeShowCallback(e) {
+      // const nowDate = new Date(e.getTime() + 8 * 60 * 60 * 1000)
+      const time = this.$common.getFormatDate('string', 16, e)
+      this.form.buKaShiJian = time
+      this.timeShow = false
+    },
+    buKaRiQiClick(e) {
+      this.dateShow = true
+    },
+    buKaShiJianClick() {
+      this.timeShow = true
+    },
+    getDaysDifference(date1, date2) {
+      const d1 = new Date(date1)
+      const d2 = new Date(date2)
+      const diffTime = Math.abs(d2.getTime() - d1.getTime())
+      const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
+
+      return diffDays
+    },
+    getInit() {
+      if (this.openType === 'reissue') {
+        this.form.buKaBanCi = ''
+        this.form.buKaRiQi = this.$methCommon.time(10)
+        // this.form.buKaShiJian = this.$methCommon.time(16)
+        // this.xuanzeTime = new Date()
+        this.xuanzeDate = new Date()
+      } else {
+        this.form.buKaBanCi = this.reissueData.name
+        this.form.buKaRiQi = this.selectDate
+        this.form.buKaLeiXing = this.reissueType === '' ? '' : this.reissueType
+        // this.form.buKaShiJian = this.$methCommon.time(16)
+        // this.xuanzeTime = new Date()
+        this.xuanzeDate = new Date(this.selectDate)
+        const midStr = this.$common.getFormatDate('string', 10, this.xuanzeDate)
+        const midDate = new Date(midStr)
+        const midMax = this.$common.getFormatDate('string', 10, midDate.setDate(midDate.getDate() + 1))
+        if (this.reissueData.config.dateRange[0].isSecondDay === 'Y') {
+          this.minTime = new Date(midStr + ' 00:00:00')
+          this.maxTime = new Date(midMax + ' 23:59:59')
+        } else {
+          this.minTime = new Date(midStr + ' 00:00:00')
+          this.maxTime = new Date(midStr + ' 23:59:59')
+        }
+      }
+    },
+    getInfo(id) {
+      const sql = `select * from t_attendance_reissue where id_ = ${id}`
+
+      this.$common.request('sql', sql).then(res => {
+        if (res.state === 200) {
+          const data = res.variables.data[0]
+          this.form = {
+            id: data.id_,
+            buKaBanCi: data.bu_ka_ban_ci_.split('-')[0],
+            buKaLeiXing: data.bu_ka_ban_ci_.split('-')[1] || '',
+            buKaShiYou: data.bu_ka_shi_you_,
+            buKaRiQi: data.bu_ka_ri_qi_,
+            buKaShiJian: data.bu_ka_shi_jian_,
+            fuJian: data.fu_jian_,
+            bianZhiRen: data.bian_zhi_ren_,
+            bianZhiShiJian: data.bian_zhi_shi_jian,
+            // bianZhiBuMen: data.fu_jian_,
+            zhuangTai: '待审核',
+            diDian: data.di_dian_,
+            paiBanId: data.pai_ban_id_,
+            paiBanJiLuId: data.pai_ban_ji_lu_id_,
+            kaoQinId: data.kao_qin_id_,
+            shenHeRen: data.shen_he_ren_
+          }
+          // if (this.typeValue === '2' || this.typeValue === '4') {
+          //   this.updateData(data.id_)
+          // }
+        }
+      })
+    },
+    async onSubmit() {
+      if (!this.getYanZheng()) {
+        return
+      }
+      const clockInData = await this.clockIn()
+      if (clockInData.length <= 0) {
+        // eslint-disable-next-line no-unused-vars
+        const toast = Toast({
+          duration: 2000, // 持续展示 toast
+          message: '没有对应的考勤数据,请联系相关人员反馈!'
+        })
+        return
+      } else if (this.form.buKaLeiXing === '上班' && clockInData[0].hasOwnProperty('da_ka_shi_jian_2_')) {
+        const ciDate = new Date(clockInData[0].da_ka_shi_jian_2_).getTime()
+        const bkDate = new Date(this.form.buKaShiJian).getTime()
+        if (bkDate >= ciDate) {
+          this.$toast('上班打卡时间大于等于考勤记录中的下班时间,请重新选择!')
+          return
+        }
+      } else if (this.form.buKaLeiXing === '下班' && clockInData[0].hasOwnProperty('da_ka_shi_jian_1_')) {
+        const ciDate = new Date(clockInData[0].da_ka_shi_jian_1_).getTime()
+        const bkDate = new Date(this.form.buKaShiJian).getTime()
+        if (bkDate <= ciDate) {
+          this.$toast('下班打卡时间小于等于考勤记录中的上班时间,请重新选择!')
+          return
+        }
+      }
+      const info = this.$store.getters.userInfo
+      const useId = info.user.id
+      // const detpId = info.employee.positions
+      const transmitData = {
+        bianZhiRen: useId,
+        bianZhiShiJian: this.$methCommon.time(16),
+        // bianZhiBuMen: this.mainPosition === null ? detpId : this.mainPosition.id,
+        zhuangTai: '待审核',
+        diDian: this.level.second || this.level.first,
+        buKaBanCi: this.form.buKaBanCi + '-' + this.form.buKaLeiXing,
+        buKaShiYou: this.form.buKaShiYou,
+        buKaRiQi: this.form.buKaRiQi,
+        buKaShiJian: this.form.buKaShiJian,
+        fuJian: this.form.fuJian,
+        paiBanId: clockInData[0].pai_ban_id_,
+        paiBanJiLuId: clockInData[0].pai_ban_ji_lu_id_,
+        kaoQinId: clockInData[0].id_,
+        shenHeRen: this.approver.join(',')
+      }
+      const that = this
+
+      saveReissue(transmitData)
+        .then(res => {
+          if (res.state === 200) {
+            that.$toast.success('提交成功!')
+            setTimeout(() => {
+              that.closePop('1')
+            }, 1000)
+          }
+        })
+        .catch(() => {})
+    },
+    onAgree(shiFouGuoShen, opinion, type) {
+      if (this.typeValue !== '2' && !this.getYanZheng()) {
+        return
+      }
+
+      this.form.shiFouGuoShen = shiFouGuoShen
+      this.form.diDian = this.level.second
+      this.form.shiFouGuoShen = shiFouGuoShen
+      const editData = {
+        data: JSON.stringify(this.form),
+        opinion: opinion,
+        taskId: this.taskId
+      }
+      // agree(editData).then(res => {
+      //   if (res.state === 200) {
+      //     if (this.typeValue === '2') {
+      //     } else {
+      //       this.$toast.success(type + '成功!')
+      //       this.closePop()
+      //     }
+      //     this.$toast.success(type + '成功!')
+      //     setTimeout(() => {
+      //       this.closePop()
+      //     }, 1000)
+      //   } else {
+      //     this.$toast.fail(type + '异常!')
+      //   }
+      // })
+    },
+    updateData(id, fileId) {
+      const pp = {
+        updList: [
+          {
+            where: {
+              id_: id
+            },
+            param: {
+              shi_fou_guo_shen_: '待审核'
+            }
+          }
+        ],
+        tableName: 't_attendance_reissue'
+      }
+      const data = this.$sig(pp)
+      this.$common.request('update', data).then(res => {
+        this.$methCommon.getPrompt('提交成功', 'success')
+        setTimeout(() => {
+          this.closePop()
+        }, 1000)
+      })
+    },
+    getYanZheng() {
+      const suList = [
+        'buKaShiYou'
+      ]
+      const suListName = [
+        '补卡事由'
+      ]
+      for (const item in suList) {
+        if (!this.form[suList[item]]) {
+          this.$toast({
+            duration: 2000, // 持续展示 toast
+            message: '请输入' + suListName[item]
+          })
+          return false
+        }
+      }
+
+      const selList = ['buKaRiQi', 'buKaBanCi', 'buKaShiJian', 'buKaLeiXing']
+      const selListName = ['补卡日期', '补卡班次', '补卡时间', '补卡类型']
+      for (const item in selList) {
+        if (!this.form[selList[item]]) {
+          this.$toast({
+            duration: 2000, // 持续展示 toast
+            message: '请选择' + selListName[item]
+          })
+          return false
+        }
+      }
+
+      return true
+    },
+    // 退回原因
+    getBack() {
+      this.content = this.option
+      this.backShow = true
+      this.$dialog
+        .alert({
+          title: '退回原因',
+          message: this.option,
+          theme: 'round-button',
+          confirmButtonColor: '#1989fa'
+        })
+        .then(() => {
+          // on close
+        })
+    },
+    cancel() {
+      this.backShow = false
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+
+.backgroundSty20250425 {
+  height: 100%;
+  background-color: #f8f8f8;
+  ::v-deep .van-cell__title {
+    width: 65%;
+
+    .van-cell__label {
+      overflow-wrap: break-word;
+    }
+  }
+  .sectionBox {
+    display: flex;
+    align-items: center;
+    margin-bottom: 2px;
+    font-size: 14px;
+    color: rgba(128, 138, 135, 0.9);
+
+    .left {
+      width: 90px;
+    }
+  }
+  .sectionBox::before {
+    content: '';
+    width: 5px;
+    height: 14px;
+    border-radius: 2px;
+    margin-right: 5px;
+  }
+  .btn-back-color {
+    background-color: #1989fa !important;
+    border: none;
+  }
+  .btn-sty {
+    padding: 0 13px;
+    border-radius: 5px;
+  }
+  .u-m-r-15 {
+    margin-right: 8px !important;
+  }
+  .verticalLine {
+    color: #000;
+    font-size: 13px;
+    margin-bottom: 20px;
+  }
+  .verticalLine::before {
+    content: '';
+    width: 5px;
+    height: 14px;
+    background-color: #2979ff;
+    border-radius: 2px;
+    margin-right: 5px;
+  }
+  .suspensionBtn {
+    width: 80px;
+    height: 80px;
+    position: fixed;
+    top: 75%;
+    right: 2%;
+    img {
+      width: 100%;
+      height: 100%;
+    }
+  }
+  .cu-form-group .title {
+    min-width: 180px;
+  }
+  .padding {
+    padding-bottom: 15px;
+    padding-top: 5px;
+    background-color: #f8f8f8;
+    display: flex;
+    justify-content: center;
+  }
+  .btn {
+    width: 90%;
+    padding: 15px;
+    border-radius: 5px;
+  }
+
+  .fileBox {
+    line-height: 50px;
+    color: #888888;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    border: 1px solid #dddddd;
+    border-radius: 8px;
+    padding: 5px;
+    margin-top: 10px;
+  }
+
+  .u-update-content {
+    font-size: 26px;
+    // color: $u-content-color;
+    line-height: 1.7;
+    padding: 30px;
+  }
+  .verticalLine {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 14px;
+    color: rgb(51, 51, 51);
+  }
+  .verticalLine::before {
+    content: '';
+    width: 5px;
+    height: 14px;
+    background-color: #2979ff;
+    border-radius: 2px;
+    margin-right: 5px;
+  }
+  .scrollView {
+    overflow-y: scroll;
+    height: 95%;
+  }
+  .scrollView::-webkit-scrollbar {
+    display: none;
+  }
+  ::v-deep .yonghu .van-cell--borderless {
+    padding-left: 8px;
+  }
+  ::v-deep .yonghu .van-cell .van-field__label {
+    display: flex;
+    align-items: center;
+    justify-content: left;
+    font-size: 14px;
+    color: rgb(51, 51, 51);
+  }
+  ::v-deep .yonghu .van-cell .van-field__label::before {
+    content: '';
+    width: 5px;
+    height: 14px;
+    background-color: #2979ff;
+    border-radius: 2px;
+    margin-right: 5px;
+  }
+}
+
+</style>

+ 432 - 0
src/views/platform/bpmn/my-reissue/index.vue

@@ -0,0 +1,432 @@
+<template>
+  <div :class="{'ibps-fixed-toolbar':checkMode}">
+      <van-sticky>
+          <van-nav-bar
+              :title="generateTitle($route.name,$route.params.title||$route.meta.title)"
+              :left-text="$t('common.button.back')"
+              left-arrow
+              @click-left="$router.push({ name: 'dashboard' })"
+          />
+          <van-search v-model="twoParam" show-action placeholder="请选择补卡记录" @search="onSearch">
+              <template #action>
+                  <van-icon name="filter-o" :class="{'ibps-active':stateActive}" @click="clickMoreSearch" />
+              </template>
+          </van-search>
+      </van-sticky>
+      <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
+          <van-list v-model="loading" :finished="finished" @load="loadData">
+              <van-checkbox-group v-model="checkedIds">
+                  <van-cell v-for="(item,index) in listData" :key="item.id+index">
+                      <div class="sectionBox verticalLine">
+                          <div class="left ">申请时间:</div>
+                          <div>{{ item.bian_zhi_shi_jian || '/' }} </div>
+                          <van-button class="right" size="mini" color="#ae514a" disabled plain hairline round type="info">{{ item.zhuang_tai_ }}</van-button>
+                      </div>
+                      <div class="sectionBox">
+                          <div class="left">补卡日期:</div>
+                          <div>{{ item.bu_ka_ri_qi_ || '/' }} </div>
+                      </div>
+                      <div class="sectionBox">
+                          <div class="left">补卡班次:</div>
+                          <div>{{ item.bu_ka_ban_ci_ || '/' }} </div>
+                      </div>
+                      <div class="sectionBox">
+                          <div class="left">补卡时间:</div>
+                          <div>{{ item.bu_ka_shi_jian_ || '/' }} </div>
+                      </div>
+                      <div class="sectionBox">
+                          <div class="left">补卡事由:</div>
+                          <div>{{ item.bu_ka_shi_you_ || '/' }} </div>
+                      </div>
+                      <div style=" width: 100%; text-align: right; padding-top: 5rpx;padding-bottom: 0rpx;">
+                          <!-- <van-button v-if="item.lei_xing_ == '1' && item.shi_fou_guo_shen_ == '已编制'" type="warning" size="small" class="u-m-r-15 btn-sty" @click="getGo(item.id_,'2')">确定</van-button> -->
+                          <van-button v-if="item.zhuang_tai_ == '未通过'||item.zhuang_tai_ == '已撤销'" type="success" size="small" class="u-m-r-15 btn-sty" @click="getGo(item.id_,'4')">重新申请</van-button>
+                          <van-button v-if="item.zhuang_tai_ == '未通过'||item.zhuang_tai_ == '待审核'" type="success" size="small" class="u-m-r-15 btn-sty btn-yellow-color" @click="revocation(item.id_)">撤销</van-button>
+                          <van-button type="warning" size="small" class="btn-back-color btn-sty" @click="getGo(item.id_,'1')">查阅</van-button>
+                      </div>
+                  </van-cell>
+              </van-checkbox-group>
+          </van-list>
+          <ibps-list-result-page :result-type="resultType" :error-type="errorType" :result-message="resultMessage" />
+      </van-pull-refresh>
+      <div class="suspensionBtn">
+          <img src="@/assets/images/add.png" alt="" srcset="" @click="LiftUpPop()">
+      </div>
+      <approve-popup
+          :visible="batchOpinionPopup"
+          :task-id="selectedIds"
+          :action="actionName"
+          @close="(visible)=>{batchOpinionPopup =visible}"
+          @callback="onRefreshPage"
+      />
+      <!--高级查询-->
+      <ibps-more-search
+          :show="moreSearchPopup"
+          :search-forms="searchForms"
+          @callback="onMoreSearch"
+          @close="callback => moreSearchPopup = callback"
+          @reset-form="resetForm"
+      >
+          <template v-slot:definition>
+              <ibps-bpmn-definition v-model="defKey" value-key="defKey" input-align="left" class="van-hairline--bottom" />
+          </template>
+      </ibps-more-search>
+      <reissueDialog :id="id" :show-pop="showPop" :type-value="typeValue" @updataSet="updataSet" />
+  </div>
+</template>
+<script>
+import i18n from '@/utils/i18n'
+import random from '@/mixins/random'
+import bpmnStatus from '@/mixins/bpmnStatus'
+import ActionUtils from '@/utils/action'
+import { Dialog } from 'vant'
+import ApprovePopup from '@/business/platform/bpmn/form-ext/approve'
+import IbpsMoreSearch from '@/components/ibps-more-search'
+import IbpsListResultPage from '@/components/ibps-list-result-page'
+import IbpsBpmnDefinition from '@/business/platform/bpmn/definition/field'
+
+import reissueDialog from './components/reissueDialog'
+
+export default {
+  components: {
+    IbpsMoreSearch,
+    IbpsListResultPage,
+    IbpsBpmnDefinition,
+    ApprovePopup,
+    reissueDialog
+  },
+  mixins: [random, bpmnStatus],
+  data() {
+    const useId = this.$store.getters.userId
+    return {
+      useId,
+      moreSearchPopup: false,
+      stateActive: false,
+      searchForms: {
+        forms: [
+          { prop: 'bu_ka_ri_qi_', label: '补卡日期', fieldType: 'datePicker' },
+          { prop: 'zhuang_tai_', label: '状态', fieldType: 'checker', cols: 3, options: [
+            {
+              value: '全部',
+              label: '全部'
+            }, {
+              value: '已通过',
+              label: '已通过'
+            }, {
+              value: '待审核',
+              label: '待审核'
+            }, {
+              value: '未通过',
+              label: '未通过'
+            }
+          ]
+          }
+        ]
+      },
+      subject: '',
+      typeId: '',
+      defKey: '',
+      twoParam: '',
+      moreParams: {},
+
+      listData: [],
+      pagination: {},
+      sorts: {},
+
+      loading: false,
+      finished: false,
+      refreshing: false,
+      resultType: 'init',
+      errorType: null,
+      resultMessage: null,
+
+      checkMode: false,
+      checkedIds: [],
+      show: false,
+      batchOpinionPopup: false,
+      actionName: 'agree',
+
+      typeTreePopup: false,
+      scrollWhere: 0,
+      taskId: '',
+      formrenderVisible: false,
+      formrenderTitle: '',
+      page: 0,
+      showPop: false,
+      typeValue: '0',
+      id: ''
+    }
+  },
+  computed: {
+    rightText() {
+      return this.checkMode ? this.$t('common.button.cancel') : this.$t('common.button.manage')
+    },
+    selectedIds() {
+      return this.checkedIds.join(',')
+    }
+  },
+  methods: {
+    updataSet(v, type) {
+      this.showPop = v
+      this.startScroll()
+      if (type === '1') {
+        this.onRefresh()
+      }
+    },
+    generateTitle(name, title) { // generateTitle by vue-i18n
+      return i18n.generateTitle(name, title)
+    },
+    /**
+     * 加载数据
+     */
+    loadData(j) {
+      this.loading = true
+      const params = this.getSearcFormData()
+      if (j === 'search') {
+        this.page = 0
+      }
+      let itemSql = ``
+      const gtlx = params.parameters.find(i => i.key === 'zhuang_tai_') || ''
+      if (gtlx && gtlx.value !== '全部') {
+        itemSql = itemSql + `and zhuang_tai_ = '${gtlx.value}'`
+      }
+      const bdbh = params.parameters.find(i => i.key === 'bu_ka_ri_qi_' || i.key === 'two') || ''
+      if (bdbh && bdbh.value !== '') {
+        itemSql = itemSql + `and bu_ka_ri_qi_ like '%${bdbh.value}%'`
+      }
+
+      const sql =
+        `select * from t_attendance_reissue where (create_by_ = '${this.useId}' or bian_zhi_ren_ = '${this.useId}') ${itemSql}  ORDER BY create_time_ desc LIMIT ${this.page * params.requestPage.limit},${params.requestPage.limit}`
+      this.$common.request('sql', sql).then(response => {
+        // 处理数据
+        ActionUtils.handleListDataCommon(this, response.variables)
+      }).catch((e) => {
+        ActionUtils.handleErrorData(this, e)
+      })
+    },
+    /**
+     * 获取格式化参数
+     */
+    getSearcFormData() {
+      let params = {}
+      if (this.$utils.isNotEmpty(this.twoParam)) {
+        params['two'] = this.twoParam
+      }
+      // if (this.$utils.isNotEmpty(this.typeId)) {
+      //   params['Q^temp.TYPE_ID_^S'] = this.typeId
+      // }
+      // if (this.$utils.isNotEmpty(this.defKey)) {
+      //   params['Q^temp.proc_def_key_^S'] = this.defKey
+      // }
+      if (this.$utils.isNotEmpty(this.moreParams)) {
+        params = Object.assign(params, this.moreParams)
+      }
+      return ActionUtils.formatParams(
+        params,
+        this.pagination,
+        this.sorts)
+    },
+    LiftUpPop() {
+      this.scrollWhere = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop
+      this.stopScroll()
+      this.getGo('', '3')
+    },
+    /**
+     * 下拉刷新
+     */
+    onRefresh() {
+      this.refreshing = true
+      this.finished = false
+      this.loading = true
+      this.onSearch()
+    },
+    /**
+     * 查询
+     */
+    onSearch() {
+      this.stateActive = false
+      ActionUtils.initListData(this)
+      this.loadData('search')
+    },
+    /**
+     * 高级查询
+     */
+    onMoreSearch(params) {
+      this.moreParams = params
+      this.onSearch()
+      if (this.$utils.isNotEmpty(params)) {
+        this.stateActive = true
+      }
+    },
+    /**
+     * 弹窗更多查询条件
+     */
+    clickMoreSearch() {
+      this.moreSearchPopup = true
+      this.stateActive = false
+    },
+    /**
+     * 重置表单
+     */
+    resetForm() {
+      this.typeId = ''
+      this.defKey = ''
+    },
+
+    onRefreshPage() {
+      this.checkedIds = []
+      this.checkMode = false
+      this.onRefresh()
+    },
+
+    onClick(item, index) {
+      if (this.checkMode) {
+        this.$refs.checkboxes[index].toggle()
+      } else {
+        this.taskId = item.id
+        this.formrenderTitle = item.procDefName
+        this.formrenderVisible = true
+      }
+    },
+    clickType() {
+      this.typeTreePopup = true
+    },
+    clickTypeNode(data) {
+      this.typeId = data.id
+      this.onMoreSearch({})
+    },
+    toCheckMode() {
+      if (this.$utils.isEmpty(this.listData)) {
+        return
+      }
+      if (this.checkMode) {
+        this.show = true
+        this.checkedIds = []
+      }
+      this.checkMode = !this.checkMode
+    },
+    stopScroll() {
+      const mid = this.scrollWhere
+      // document.documentElement.style.overflow='hidden';
+      document.body.style.overflow = 'hidden'
+      // document.documentElement.style.position='fixed';
+      document.body.style.position = 'fixed'
+      // document.documentElement.style.top=-mid+'px';
+      document.body.style.top = -mid + 'px'
+    },
+    // 启用页面滚动
+    startScroll() {
+      // document.documentElement.style.overflow='';
+      document.body.style.overflow = 'auto'
+      document.body.style.position = 'static'
+      window.scrollTo(0, this.scrollWhere)
+      this.scrollWhere = 0
+    },
+    getGo(id, typeValue) {
+      this.id = id
+      this.typeValue = typeValue
+      this.showPop = true
+      // uni.navigateTo({
+      // 	url: `./communication?id=${id}&typeValue=${typeValue}`
+      // })
+    },
+    revocation(id) {
+      Dialog.confirm({
+        title: '确认操作',
+        message: '确定撤销么?'
+      }).then(() => {
+        const params = { zhuang_tai_: '已撤销' }
+        const updateParams = {
+          tableName: 't_attendance_reissue',
+          updList: [
+            {
+              where: {
+                id_: id
+              },
+              param: params
+            }
+          ]
+        }
+        this.$common.request('update', updateParams).then((res) => {
+          let str = '撤销失败,请重新操作!'
+          if (res.state === 200) {
+            str = '撤销成功!'
+          }
+          this.$toast.success(str)
+          this.onRefresh()
+        })
+      }).catch(() => {
+      })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+::v-deep .van-cell__title {
+  width: 65%;
+
+  .van-cell__label {
+    overflow-wrap: break-word;
+  }
+}
+.sectionBox {
+  display: flex;
+  align-items: baseline;
+  margin-bottom: 2px;
+  font-size: 14px;
+  color: rgba(128, 138, 135, .9);
+  .left {
+    width: 90px;
+  }
+  .right{
+    position: absolute;
+    right: 0;
+    top: 0;
+  }
+}
+.sectionBox::before {
+  content: '';
+  width: 5px;
+  height: 14px;
+  border-radius: 2px;
+  margin-right: 5px;
+}
+.btn-back-color {
+  background-color: #30c2bd !important;
+}
+.btn-yellow-color {
+  background-color: #e6a23c !important;
+}
+.btn-sty {
+  padding: 0 13px;
+  border-radius: 5px;
+  border: none;
+}
+.u-m-r-15 {
+  margin-right: 8px !important;
+}
+.verticalLine {
+  color: #000;
+  font-size: 13px;
+  margin-bottom: 20px;
+}
+.verticalLine::before {
+  content: '';
+  width: 5px;
+  height: 14px;
+  background-color: #2979ff;
+  border-radius: 2px;
+  margin-right: 5px;
+}
+.suspensionBtn {
+  width: 80px;
+  height: 80px;
+  position: fixed;
+  top: 75%;
+  right: 2%;
+  img {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>

+ 499 - 0
src/views/platform/bpmn/my-reissue/indexTab.vue

@@ -0,0 +1,499 @@
+<template>
+  <div :class="{'ibps-fixed-toolbar':checkMode}">
+      <van-sticky>
+          <van-nav-bar
+              :title="generateTitle($route.name,$route.params.title||$route.meta.title)"
+              :left-text="$t('common.button.back')"
+              left-arrow
+              @click-left="$router.push({ name: 'dashboard' })"
+          />
+          <van-search v-model="twoParam" show-action placeholder="请选择补卡记录" @search="onSearch">
+              <template #action>
+                  <van-icon name="filter-o" :class="{'ibps-active':stateActive}" @click="clickMoreSearch" />
+              </template>
+          </van-search>
+          <van-tabs
+              v-model="active"
+              color="#3396FB"
+              line-width="40"
+              @click="onClickTab"
+          >
+              <van-tab v-for="(item, i) in activeArr" :key="i" :name="item" :title="item">
+                  <!-- <template #title>
+                      <div class="badge">
+                      {{data.title}}
+                      <div class="icon">{{ data.val*1>100?'99+':data.val }}</div>
+                      </div>
+                  </template> -->
+              </van-tab>
+          </van-tabs>
+      </van-sticky>
+
+      <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
+          <van-list v-model="loading" :finished="finished" @load="loadData">
+              <van-checkbox-group v-model="checkedIds">
+                  <van-cell v-for="(item,index) in listData" :key="item.id+index">
+                      <div class="sectionBox verticalLine">
+                          <div class="left ">申请时间:</div>
+                          <div>{{ $common.getFormatDate('string', 16, item.createTime) }} </div>
+                          <!-- <div class="right">{{ item.status }} </div> -->
+                          <van-button class="right" size="mini" color="#ae514a" disabled plain hairline round type="info">{{ item.status }}</van-button>
+                      </div>
+                      <div class="sectionBox">
+                          <div class="left">补卡日期:</div>
+                          <div>{{ item.ke_hu_lian_xi_ren }} </div>
+                      </div>
+                      <div class="sectionBox">
+                          <div class="left">补卡班次:</div>
+                          <div>{{ item.ke_hu_dan_wei_min }} </div>
+                      </div>
+                      <div class="sectionBox">
+                          <div class="left">补卡时间:</div>
+                          <div>{{ item.gou_tong_lei_xing }} </div>
+                      </div>
+                      <div class="sectionBox">
+                          <div class="left">补卡事由:</div>
+                          <div>{{ item.gou_tong_lei_xing }} </div>
+                      </div>
+
+                      <div style=" width: 100%; text-align: right; padding-top: 5rpx;padding-bottom: 0rpx;">
+                          <van-button v-if="active==='我发起的'&& item.status == '已暂存'" type="info" size="mini" class="btn-sty" @click="LiftUpPop(item.id,'6')">编辑</van-button>
+                          <van-button v-if="active==='我发起的'&& (item.status == '已取消' || item.status == '已拒绝')" type="info" size="mini" class="btn-sty" @click="LiftUpPop(item.id,'4')">再次申请</van-button>
+                          <van-button v-if="active==='我发起的'" type="success" size="mini" class="u-m-l-15 btn-sty" @click="LiftUpPop(item.id,'1')">详情</van-button>
+                          <van-button v-if="active==='我发起的'&& item.status == '待审核'" type="warning" size="mini" class="u-m-l-15 btn-sty" @click="LiftUpPop(item.id,'7')">取消</van-button>
+                          <van-button v-if="active==='待我处理'&& (item.status == '待审核'||item.partys.some(obj => obj.value === useId && item.createBy !== useId && obj.status === '待审核'))" type="warning" size="mini" class="btn-back-color btn-sty" @click="LiftUpPop(item.id,'5')">审核</van-button>
+                          <van-button v-if="active==='待我处理'&& item.status == '待审批'" type="warning" size="mini" class="btn-back-color btn-sty" @click="LiftUpPop(item.id,'2')">审批</van-button>
+                      </div>
+                  </van-cell>
+              </van-checkbox-group>
+          </van-list>
+          <ibps-list-result-page :result-type="resultType" :error-type="errorType" :result-message="resultMessage" />
+      </van-pull-refresh>
+      <div class="suspensionBtn">
+          <img src="@/assets/images/add.png" alt="" srcset="" @click="LiftUpPop('','3')">
+      </div>
+      <approve-popup
+          :visible="batchOpinionPopup"
+          :task-id="selectedIds"
+          :action="actionName"
+          @close="(visible)=>{batchOpinionPopup =visible}"
+          @callback="onRefreshPage"
+      />
+      <!--高级查询-->
+      <ibps-more-search
+          :show="moreSearchPopup"
+          :search-forms="searchForms"
+          @callback="onMoreSearch"
+          @close="callback => moreSearchPopup = callback"
+          @reset-form="resetForm"
+      >
+          <template v-slot:definition>
+              <ibps-bpmn-definition v-model="defKey" value-key="defKey" input-align="left" class="van-hairline--bottom" />
+          </template>
+      </ibps-more-search>
+      <reissueDialog :id="id" :show-pop="showPop" :type-value="typeValue" @updataSet="updataSet" />
+  </div>
+</template>
+<script>
+import i18n from '@/utils/i18n'
+import random from '@/mixins/random'
+import bpmnStatus from '@/mixins/bpmnStatus'
+import ActionUtils from '@/utils/action'
+
+import ApprovePopup from '@/business/platform/bpmn/form-ext/approve'
+
+import IbpsMoreSearch from '@/components/ibps-more-search'
+import IbpsListResultPage from '@/components/ibps-list-result-page'
+import IbpsBpmnDefinition from '@/business/platform/bpmn/definition/field'
+
+import { queryAdjustment } from '@/api/platform/feature/changeShift'
+import reissueDialog from './components/reissueDialog'
+
+export default {
+  components: {
+    IbpsMoreSearch,
+    IbpsListResultPage,
+    IbpsBpmnDefinition,
+    ApprovePopup,
+    reissueDialog
+  },
+  mixins: [random, bpmnStatus],
+  data() {
+    const useId = this.$store.getters.userId
+    const { userList = [] } = this.$store.getters || {}
+    const userOption = userList.map(item => ({ label: item.userName, value: item.userId }))
+    return {
+      userOption,
+      useId,
+      active: '我发起的',
+      activeArr: ['待我处理', '我发起的'],
+      moreSearchPopup: false,
+      stateActive: false,
+      subject: '',
+      typeId: '',
+      defKey: '',
+      twoParam: '',
+      moreParams: {},
+      searchForms: {
+        forms: [
+          { prop: 'bu_ka_ri_qi_', label: '补卡日期', fieldType: 'datePicker' },
+          { prop: 'zhuang_tai_', label: '状态', fieldType: 'checker', cols: 3, options: [
+            {
+              value: '全部',
+              label: '全部'
+            }, {
+              value: '已通过',
+              label: '已通过'
+            }, {
+              value: '待审核',
+              label: '待审核'
+            }, {
+              value: '未通过',
+              label: '未通过'
+            }
+          ]
+          }
+        ]
+      },
+      listData: [],
+      pagination: {},
+      sorts: {},
+
+      loading: false,
+      finished: false,
+      refreshing: false,
+      resultType: 'init',
+      errorType: null,
+      resultMessage: null,
+
+      checkMode: false,
+      checkedIds: [],
+      show: false,
+      batchOpinionPopup: false,
+      actionName: 'agree',
+
+      typeTreePopup: false,
+      scrollWhere: 0,
+      taskId: '',
+      formrenderVisible: false,
+      formrenderTitle: '',
+      page: 0,
+      showPop: false,
+      typeValue: '0',
+      id: ''
+    }
+  },
+  computed: {
+    rightText() {
+      return this.checkMode ? this.$t('common.button.cancel') : this.$t('common.button.manage')
+    },
+    selectedIds() {
+      return this.checkedIds.join(',')
+    }
+  },
+  methods: {
+    updataSet(v) {
+      this.showPop = v
+      this.startScroll()
+    },
+    generateTitle(name, title) {
+      return i18n.generateTitle(name, title)
+    },
+    onClickTab(val) {
+      this.page = 0
+      this.listData = []
+      this.loadData()
+    },
+    /**
+     * 加载数据
+     */
+    loadData(j) {
+      this.loading = true
+      const params = this.getSearcFormData()
+      if (j === 'search') {
+        this.page = 0
+      }
+      let itemSql = ``
+      const gtlx = params.parameters.find(i => i.key === 'zhuang_tai_') || ''
+      if (gtlx && gtlx.value !== '全部') {
+        itemSql = itemSql + `and zhuang_tai_ = '${gtlx.value}'`
+      }
+      const bdbh = params.parameters.find(i => i.key === 'bu_ka_ri_qi_' || i.key === 'two') || ''
+      if (bdbh && bdbh.value !== '') {
+        itemSql = itemSql + `and bu_ka_ri_qi_ like '%${bdbh.value}%'`
+      }
+
+      // v1
+      // const two = params.parameters.find(i => i.key === 'two') || ''
+      // if (two) {
+      //   itemSql = itemSql + `and overview_ like '%${two.value}%'`
+      // }
+      // const typeActive = this.active === '我发起的' ? `create_by_ = '${this.useId}' ` : `FIND_IN_SET('${this.useId}', executor_) and `
+      // const sql =
+      // 		`select * from t_adjustment where ${typeActive} ${itemSql}  ORDER BY create_time_ desc LIMIT ${this.page * params.requestPage.limit},${params.requestPage.limit}`
+      if (this.active === '我发起的') {
+        const sql =
+        `select a.id_ as id,a.tenant_id_ as tenantId,a.ip_ as ip,a.create_by_ as createBy,a.create_time_ as createTime,a.update_by_ as updateBy,a.update_time_ as updateTime,a.di_dian_ as diDian,a.reason_ as reason,a.status as status,a.executor_ as executor,a.execute_date_ as executeDate,a.overview_ as overview,a.schedule_id_ as scheduleId,a.type_ as type,a.reject_reason_ as rejectReason,a.partys from (select f.*,GROUP_CONCAT(z.party_) as partys from t_adjustment f left join t_adjustment_detail z on f.id_ = z.parent_id_  GROUP BY f.id_) a where create_by_ = '${this.useId}' ORDER BY a.create_time_ desc LIMIT ${this.page * params.requestPage.limit},${params.requestPage.limit}`
+        this.$common.request('sql', sql).then(response => {
+          // 处理数据
+          ActionUtils.handleListDataCommon(this, response.variables)
+        }).catch((e) => {
+          ActionUtils.handleErrorData(this, e)
+        })
+      } else if (this.active === '待我处理') {
+        console.log('221312312321312321')
+        queryAdjustment(this.getSearcFormData()).then(res => {
+          res.data.dataResult.forEach((el) => { // 遍历子表提取审核人字段
+            el.partys = this.getPartysList(el.adjustmentDetailPoList)
+          })
+          // if (!this.isRoleFilter()) { // 如果不是高权限角色
+          // 审核人审批人过滤
+          res.data.dataResult = this.filteredData(this.isRoleFilter(), res.data.dataResult)
+          ActionUtils.handleListDataCommon(this, res.data, { dataResultKey: 'dataResult' })
+
+          // }
+
+        // this.loading = false
+        }).catch(() => {
+        // this.loading = false
+        })
+      }
+    },
+    getPartysList(poList) {
+      const self = this
+      const result = poList.map(item => ({
+        value: item.party,
+        status: item.status,
+        label: self.userOption.filter(o => o.value === item.party).length > 0 ? (self.userOption.filter(o => o.value === item.party))[0].label : '',
+        type: 'success'
+      }))
+      return result
+    },
+    isRoleFilter() {
+      const highRoles = this.$store.getters.userInfo.highRoles || [] // 高权限角色
+      const userRole = this.$store.getters.userInfo.role || [] // 用户权限角色
+      let isHighRole = false
+      userRole.forEach(el => {
+        const roleAlias = el.alias
+        if (highRoles.includes(roleAlias)) {
+          isHighRole = true
+        }
+      })
+      return (this.$store.getters.isSuper || isHighRole)
+    },
+    filteredData(judge, data) {
+      const { userId = '' } = this.$store.getters
+      const result = data.reduce((acc, item) => {
+      // acc.push(item)
+
+        if (judge) {
+          if (userId && (item.partys.some(obj => obj.value === userId && item.createBy !== userId && obj.status === '待审核') || (item.executor && item.status === '待审批')) && (item.status === '待审核' || item.status === '待审批')) {
+            acc.push(item)
+          }
+        } else {
+          if (userId && (item.partys.some(obj => obj.value === userId && item.createBy !== userId && obj.status === '待审核') || (item.executor && item.executor.includes(userId) && item.status === '待审批'))) {
+            acc.push(item)
+          }
+        }
+        return acc
+      }, [])
+      return result
+    },
+    /**
+     * 获取格式化参数
+     */
+    getSearcFormData() {
+      const params = {}
+      if (this.$utils.isNotEmpty(this.twoParam)) {
+        params['two'] = this.twoParam
+      }
+      // if (this.$utils.isNotEmpty(this.typeId)) {
+      //   params['Q^temp.TYPE_ID_^S'] = this.typeId
+      // }
+      // if (this.$utils.isNotEmpty(this.defKey)) {
+      //   params['Q^temp.proc_def_key_^S'] = this.defKey
+      // }
+      //   if (this.$utils.isNotEmpty(this.moreParams)) {
+      //     params = Object.assign(params, this.moreParams)
+      //   }
+      return ActionUtils.formatParams(
+        params,
+        { page: this.page },
+        this.sorts)
+    },
+    LiftUpPop(id, typeValue) {
+      this.scrollWhere = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop
+      this.stopScroll()
+      // this.getGo('', '3')
+      this.getGo(id, typeValue)
+    },
+    /**
+     * 下拉刷新
+     */
+    onRefresh() {
+      this.refreshing = true
+      this.finished = false
+      this.loading = true
+      this.onSearch()
+    },
+    /**
+     * 查询
+     */
+    onSearch() {
+      this.stateActive = false
+      ActionUtils.initListData(this)
+      this.loadData('search')
+    },
+    /**
+     * 高级查询
+     */
+    onMoreSearch(params) {
+      this.moreParams = params
+      this.onSearch()
+      if (this.$utils.isNotEmpty(params)) {
+        this.stateActive = true
+      }
+    },
+    /**
+     * 弹窗更多查询条件
+     */
+    clickMoreSearch() {
+      this.moreSearchPopup = true
+      this.stateActive = false
+    },
+    /**
+     * 重置表单
+     */
+    resetForm() {
+      this.typeId = ''
+      this.defKey = ''
+    },
+
+    onRefreshPage() {
+      this.checkedIds = []
+      this.checkMode = false
+      this.onRefresh()
+    },
+
+    onClick(item, index) {
+      if (this.checkMode) {
+        this.$refs.checkboxes[index].toggle()
+      } else {
+        this.taskId = item.id
+        this.formrenderTitle = item.procDefName
+        this.formrenderVisible = true
+      }
+    },
+    clickType() {
+      this.typeTreePopup = true
+    },
+    clickTypeNode(data) {
+      this.typeId = data.id
+      this.onMoreSearch({})
+    },
+    toCheckMode() {
+      if (this.$utils.isEmpty(this.listData)) {
+        return
+      }
+      if (this.checkMode) {
+        this.show = true
+        this.checkedIds = []
+      }
+      this.checkMode = !this.checkMode
+    },
+    stopScroll() {
+      const mid = this.scrollWhere
+      // document.documentElement.style.overflow='hidden';
+      document.body.style.overflow = 'hidden'
+      document.body.style.position = 'fixed'
+      document.body.style.top = -mid + 'px'
+    },
+    // 启用页面滚动
+    startScroll() {
+      document.body.style.overflow = 'auto'
+      document.body.style.position = 'static'
+      window.scrollTo(0, this.scrollWhere)
+      this.scrollWhere = 0
+    },
+    getGo(id, typeValue) {
+      this.id = id
+      this.typeValue = typeValue
+      this.showPop = true
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+::v-deep .van-cell__title {
+  width: 65%;
+
+  .van-cell__label {
+    overflow-wrap: break-word;
+  }
+}
+.sectionBox {
+  display: flex;
+  align-items: baseline;
+  margin-bottom: 2px;
+  font-size: 85%;
+  color: rgba(128, 138, 135, .9);
+
+  .left {
+    width: 22%;
+          flex: none;
+  }
+      .right{
+          position: absolute;
+          right: 0;
+          top: 0;
+          // background-color: blue;
+          // color: #fff;
+          // padding: 0 2%;
+          // border-radius: 17%;
+      }
+}
+.sectionBox::before {
+  content: '';
+  width: 5px;
+  height: 14px;
+  border-radius: 2px;
+  margin-right: 5px;
+}
+.btn-back-color {
+  background-color: #30c2bd !important;
+  border: none;
+}
+.btn-sty {
+  padding: 0 13px;
+  border-radius: 5px;
+}
+.u-m-l-15 {
+  margin-left: 8px !important;
+}
+.verticalLine {
+  color: #000;
+  font-size: 100%;
+  margin-bottom: 7px;
+  align-items: center;
+  position: relative;
+}
+.verticalLine::before {
+  content: '';
+  width: 5px;
+  height: 14px;
+  background-color: #2979ff;
+  border-radius: 2px;
+  margin-right: 5px;
+}
+.suspensionBtn {
+  width: 80px;
+  height: 80px;
+  position: fixed;
+  top: 75%;
+  right: 2%;
+  img {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>

+ 34 - 0
src/views/platform/bpmn/my-reissue/reissueJson.json

@@ -0,0 +1,34 @@
+{
+	"clockTypeList": {
+		"beOnButy": {
+			"label": "上班",
+			"labelDialog": "上班打卡",
+			"color": "#49be49"
+		},
+		"beLate": {
+			"label": "迟到",
+			"labelDialog": "迟到打卡",
+			"color": "#f6b932"
+		},
+		"timeNotYetUp": {
+			"label": "下班",
+			"labelDialog": "未到下班时间",
+			"color": "#f6b932"
+		},
+		"getOffwork": {
+			"label": "下班",
+			"labelDialog": "下班打卡",
+			"color": "#49be49"
+		},
+		"upDateTime": {
+			"label": "更新",
+			"labelDialog": "更新打卡",
+			"color": "#49be49"
+		},
+		"clockIn": {
+			"label": "打卡",
+			"labelDialog": "打卡",
+			"color": "#49be49"
+		}
+	}
+}

+ 143 - 0
src/views/platform/bpmn/my-schedule/components/clockDialog.vue

@@ -0,0 +1,143 @@
+<template>
+  <div class="clockV20250423">
+    <van-dialog
+      v-model="visibleShow"
+      :show-cancel-button="false"
+      :show-confirm-button="false"
+    >
+      <div v-if="Object.keys(acceptData).length>0">
+        <div class="closeSty"><van-icon name="cross" color="#909399" @click="btnClickEvent(1)" /></div>
+        <div class="clockBtnContent">
+          <div class="circleBtn" :style="{borderColor: clockTypeList[acceptData.state].color}" @click="btnClickEvent(acceptData.state==='clockedIn'?3:2)">
+            <p class="stateSty">{{ clockTypeList[acceptData.state].labelDialog }}</p>
+            <p v-if="acceptData.state==='beOnButy'||acceptData.state==='beLate'" class="tipsSty">请在{{ acceptData.data.shi_fou_kua_ri_==='Y'&&acceptData.data.hasOwnProperty('ban_ci_kai_shi_')?acceptData.data.ban_ci_kai_shi_: acceptData.data.ban_ci_kai_shi_.substr(-5,5)}}之前打卡</p>
+            <p v-else-if="acceptData.state==='timeNotYetUp'||acceptData.state==='getOffwork'" class="tipsSty">请在{{ acceptData.data.shi_fou_kua_ri_==='Y'&&acceptData.data.hasOwnProperty('ban_ci_jie_shu_')?acceptData.data.ban_ci_jie_shu_ : acceptData.data.ban_ci_jie_shu_.substr(-5,5)}}之后打卡</p>
+            <p v-else-if="acceptData.state==='clockedIn'" class="tipsSty">无需重复打卡</p>
+          </div>
+        </div>
+        <div class="bottomFont">
+          {{acceptData.data.hasOwnProperty('ban_ci_kai_shi_')?acceptData.data.ban_ci_kai_shi_:''}}
+          <van-icon v-if="acceptData.data.hasOwnProperty('zhuang_tai_1_')&&acceptData.data.zhuang_tai_1_==='正常'" name="checked" color="#49be49" />
+           ~
+          {{acceptData.data.hasOwnProperty('ban_ci_jie_shu_')?acceptData.data.ban_ci_jie_shu_:''}}
+          <van-icon v-if="acceptData.data.hasOwnProperty('zhuang_tai_2_')&&acceptData.data.zhuang_tai_1_==='正常'"  name="checked" color="#49be49" />
+        </div>
+      </div>
+    </van-dialog>
+  </div>
+</template>
+<script>
+import meth from '../scheduleJson.json'
+import { saveClockIn } from '@/api/platform/feature/clockReissue'
+import { Toast } from 'vant'
+
+export default {
+  props: {
+    visibleShow: {
+      type: Boolean,
+      default: false
+    },
+    dialogData: {
+      type: Object,
+      default: function() {
+        return {}
+      }
+    }
+  },
+  data() {
+    return {
+      visibleDialog: this.visibleShow,
+      clockTypeList: meth.clockTypeList,
+      acceptData: {}
+    }
+  },
+  watch: {
+    dialogData: {
+      handler: function(val, oldVal) {
+        this.acceptData = val
+        console.log(this.acceptData, '231232131231')
+      },
+      immediate: true,
+      deep: true
+    }
+  },
+  mounted() {
+  },
+  methods: {
+    btnClickEvent(val) {
+      if (val === 2) {
+        saveClockIn({ id: this.acceptData.data.id_ }).then(res => {
+          if (res.state === 200) {
+            // eslint-disable-next-line no-unused-vars
+            const toast = Toast({
+              duration: 2000, // 持续展示 toast
+              message: '打卡成功'
+            })
+            setTimeout(() => {
+              this.$emit('controlVisible', false, true)
+            }, 2000)
+          } else {
+            // eslint-disable-next-line no-unused-vars
+            const toast = Toast({
+              duration: 2000, // 持续展示 toast
+              message: '打卡失败,请重新点击!'
+            })
+          }
+        })
+      } else if (val === 1) {
+        this.$emit('controlVisible', false, false)
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.clockV20250423{
+  // width: 100vw;
+  // height: 100vh;
+  .van-dialog{
+    width: 90vw;
+    height: 50vh;
+    top: 50%;
+    .closeSty{
+      margin: 3% 3% 2% 3%;
+      text-align: right;
+    }
+    .clockBtnContent{
+      width: 100%;
+      height: 25vh;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      .circleBtn{
+        width: 45vw;
+        height: 45vw;
+        border-radius: 100%;
+        border: 3vw solid #f6b932;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        flex-flow: column;
+        color: #15141c;
+        .stateSty{
+          font-weight: 600;
+          font-size: 5.5vw;
+          margin: 2vw 0;
+        }
+        .tipsSty{
+          font-size: 3vw;
+          color: #a1a1a1;
+        }
+      }
+    }
+    .bottomFont{
+      position: absolute;
+      bottom: 0;
+      width: 100%;
+      color: #a2a2a2;
+      text-align: center;
+      margin-bottom: 5vw;
+    }
+  }
+}
+</style>

+ 294 - 17
src/views/platform/bpmn/my-schedule/index.vue

@@ -70,23 +70,68 @@
         </van-collapse-item>
       </van-collapse>
     </div>
-    <div v-show="showInfo&&unfoldInfo!=''&&active==='排班'" class="unfoldMessage">
-      <div class="line">
+    <div v-show="showInfo&&unfoldInfo&&unfoldInfo.data.length>0&&active==='排班'" class="unfoldMessage">
+      <div v-for="(item,i) in unfoldInfo.data" :key="'uif'+ i" class="line">
         <!-- <div class="iconLine"><van-icon name="label" /></div> -->
         <van-icon class="iconLine" name="label" color="rgb(25, 137, 250)" size="125%" />
         <div class="contentLine">
-          {{unfoldInfo.replace(new RegExp(',', 'g'), ',')}}
+          <div class="textAll">
+            <div class="textSty">
+              <div>班次名称:</div>
+              <div>{{item.config.name}}</div>
+            </div>
+            <div class="textSty">
+              <div>班次别名:</div>
+              <div>{{item.name}}</div>
+            </div>
+            <div class="textSty">
+              <div>出勤时间:</div>
+              <div class="timeLine">
+                <div v-for="(m,n) in item.config.dateRange" :key="'time'+n">
+                  <!-- {{ item.state && item.state.data }} -->
+                  <p>{{m.startTime}} — {{m.isSecondDay==='Y'?'第二天':''}}{{ m.endTime }}</p>
+                </div>
+              </div>
+            </div>
+            <div class="textSty">
+              <div>出勤时间:</div>
+              <div class="timeLine">
+                  <p>上班({{ item.state && item.state.data&&item.state.data.da_ka_shi_jian_1_&&item.state.data.da_ka_shi_jian_1_.length===19 ? item.state.data.da_ka_shi_jian_1_.substr(-8,5) : !item.reissue.up?'未打卡':'已有补卡记录'}})
+                    <span v-if="item.reissue&&item.state && item.state.data && !judgeReissueBtn(item.state.data,'am', unfoldInfo.date)&&!item.reissue.up" class="reissueBtn" @click="reissueShow(item,'上班')">补卡</span>
+                  </p>
+                  <div style="height: 5px;"></div>
+                  <p>下班({{item.state && item.state.data&&item.state.data.shi_fou_kua_ri_==='Y'?'第二天':''}}{{item.state && item.state.data&&item.state.data.da_ka_shi_jian_2_&&item.state.data.da_ka_shi_jian_2_.length===19 ? item.state.data.da_ka_shi_jian_2_.substr(-8,5) : !item.reissue.down?'未打卡':'已有补卡记录'}})
+                    <span v-if="item.reissue&&item.state && item.state.data && !judgeReissueBtn(item.state.data,'pm',unfoldInfo.date)&&!item.reissue.down" class="reissueBtn" @click="reissueShow(item,'下班')">补卡</span>
+                  </p>
+              </div>
+            </div>
+          </div>
+          <div v-if="clockConfig && (unfoldInfo.date === entryDate || (item.config.isSecondDayAll&& unfoldInfo.date === getBeforeDate(entryDate)))" class="textBtn" >
+            <div class="btnSty" @click="punchTheClockEvent(item.state)">{{clockTypeList[item.state.state].label||clockTypeList.clockIn.label}}</div>
+          </div>
         </div>
       </div>
     </div>
+    <clock-dialog-vue :visible-show="visibleShow" :dialog-data="dialogData" @controlVisible = "controlVisible"></clock-dialog-vue>
+    <reissueDialog :show-pop="showPop" :open-type="'schedule'" :reissue-type="reissueType" :reissue-data="reissueData" :select-date="selectDate" @updataSet="updataSet"></reissueDialog>
   </div>
 </template>
 <script>
 import { findAllByCurrUserId } from '@/api/platform/system/desktop'
+import clockDialogVue from './components/clockDialog.vue'
+import { clockConfig } from '@/constant'
+import meth from './scheduleJson.json'
+import reissueDialog from '@/views/platform/bpmn/my-reissue/components/reissueDialog'
+
 export default {
+  components: {
+    clockDialogVue,
+    reissueDialog
+  },
   data() {
     const { userId } = this.$store.getters
     return {
+      clockConfig,
       userId,
       active: '排班',
       activeArr: ['排班', '日程'],
@@ -96,7 +141,8 @@ export default {
       configArr: [],
       showDateArr: {},
       infoDataArr: [],
-      unfoldInfo: '',
+      unfoldInfo: { date: '', data: {}},
+      showPop: false,
       stateObj: {
         1: '急',
         2: '重',
@@ -108,7 +154,15 @@ export default {
       showChange: 0,
       showInfo: false,
       collapseSelect: [],
-      calenderVal: ''
+      calenderVal: '',
+      entryDate: this.$common.getDateNow(10),
+      entryTime: this.$common.getDateNow(19),
+      visibleShow: false,
+      dialogData: {},
+      clockTypeList: meth.clockTypeList,
+      reissueData: { clock: {}, config: {}, fid: '', name: '', state: {}},
+      selectDate: '',
+      reissueType: ''
     }
   },
   watch: {
@@ -137,10 +191,11 @@ export default {
   },
   mounted() {
     this.$refs.mySchedule.style.height = document.documentElement.clientHeight + 'px'
+    this.getBeforeDate()
   },
   methods: {
     // 初始化和tab切换函数
-    onClickTab(val) {
+    async onClickTab(val) {
       this.showInfo = false
       if (val === '日程') {
         const time = this.$common.getFormatDate('string', 7, this.yearMonth.year + '-' + this.yearMonth.month)
@@ -172,6 +227,9 @@ export default {
           }
         })
       } else {
+        const clockData = await this.getpunchTheClockData()
+        const reissueDataIn = await this.reissue()
+
         this.schedule().then(res => {
           if (res.length > 0) {
             const objArr = {}
@@ -179,20 +237,58 @@ export default {
               const dArr = this.generationDate(item.start_date_, item.end_date_)
               // let config = JSON.parse(item.config_)
               dArr.forEach((t, n) => {
+                const midClockArr = clockData.filter(y => y.ri_qi_ === t && y.pai_ban_id_ === item.fid) || []
+                const midReissueArr = reissueDataIn.filter(y => y.bu_ka_ri_qi_ === t && y.pai_ban_id_ === item.fid) || []
+                const isAbnormal = midClockArr.length > 0 ? midClockArr.filter(y => y.kao_qin_zhuang_ta === '异常' || !y.hasOwnProperty('da_ka_shi_jian_1_') || !y.hasOwnProperty('da_ka_shi_jian_2_')).length > 0 : true
+                const clockDataAll = { isAbnormal: isAbnormal, data: midClockArr }
                 if (objArr.hasOwnProperty(t)) {
                   // const strArr = objArr[t].name.split(',')
                   // if (strArr.findIndex(e => e === (item['d' + (n + 1) + '_'] ? item['d' + (n + 1) + '_'] : '')) === -1) {
-                  objArr[t].name = objArr[t].name + (item['d' + (n + 1) + '_'] !== '' && objArr[t].name !== '' ? ',' : '') + (item['d' + (n + 1) + '_'] ? item['d' + (n + 1) + '_'] : '')
-                  // }
+                  const mid = item['d' + (n + 1) + '_'] ? item['d' + (n + 1) + '_'] : ''
+                  objArr[t].name = objArr[t].name + (item['d' + (n + 1) + '_'] !== '' && objArr[t].name !== '' ? ',' : '') + mid
+                  // objArr[t].data.push({ name: mid, config: JSON.parse(item.config_) })
+                  if (mid !== '' && mid.split(',').length === 1) {
+                    const midObj = this.isValidJSON(item.config_) ? JSON.parse(item.config_).scheduleShift.find(d => d.alias === mid) : ''
+                    const clockState = midClockArr.length > 0 ? this.judgeClockState(midClockArr, mid) : {}
+                    const midUp = midReissueArr.filter(y => y.bu_ka_ban_ci_.includes(mid) && y.bu_ka_ban_ci_.includes('上班')) || []
+                    const midDown = midReissueArr.filter(y => y.bu_ka_ban_ci_.includes(mid) && y.bu_ka_ban_ci_.includes('下班')) || []
 
-                  // console.log(1, objArr[t].name, item['d' + (n + 1) + '_'], objArr[t].name + ',' + item['d' + (n + 1) + '_'] ? item['d' + (n + 1) + '_'] : '')
+                    objArr[t].data.push({ name: mid, fid: item.fid, config: midObj, clock: clockDataAll, state: clockState, reissue: { up: midUp.length > 0, down: midDown.length > 0 }})
+                  } else if (mid !== '' && mid.split(',').length > 1) {
+                    mid.split(',').forEach((x, y) => {
+                      const midObj = this.isValidJSON(item.config_) ? JSON.parse(item.config_).scheduleShift.find(d => d.alias === x) : ''
+                      const clockState = midClockArr.length > 0 ? this.judgeClockState(midClockArr, x) : {}
+                      const midUp = midReissueArr.filter(y => y.bu_ka_ban_ci_.includes(x) && y.bu_ka_ban_ci_.includes('上班')) || []
+                      const midDown = midReissueArr.filter(y => y.bu_ka_ban_ci_.includes(x) && y.bu_ka_ban_ci_.includes('下班')) || []
 
+                      objArr[t].data.push({ name: x, fid: item.fid, config: midObj, clock: clockDataAll, state: clockState, reissue: { up: midUp.length > 0, down: midDown.length > 0 }})
+                    })
+                  }
+                  // }
                   // let configMsg = config.scheduleStaff.find(d=>{})
                 } else {
                   objArr[t] = { name: item['d' + (n + 1) + '_'] ? item['d' + (n + 1) + '_'] : '' }
+                  objArr[t].data = []
+                  if (objArr[t].name !== '' && objArr[t].name.split(',').length === 1) {
+                    const midObj = this.isValidJSON(item.config_) ? JSON.parse(item.config_).scheduleShift.find(d => d.alias === objArr[t].name) : ''
+                    const clockState = midClockArr.length > 0 ? this.judgeClockState(midClockArr, objArr[t].name) : {}
+                    const midUp = midReissueArr.filter(y => y.bu_ka_ban_ci_.includes(objArr[t].name) && y.bu_ka_ban_ci_.includes('上班')) || []
+                    const midDown = midReissueArr.filter(y => y.bu_ka_ban_ci_.includes(objArr[t].name) && y.bu_ka_ban_ci_.includes('下班')) || []
+
+                    objArr[t].data = [{ name: objArr[t].name, fid: item.fid, config: midObj, clock: clockDataAll, state: clockState, reissue: { up: midUp.length > 0, down: midDown.length > 0 }}]
+                  } else if (objArr[t].name !== '' && objArr[t].name.split(',').length > 1) {
+                    objArr[t].name.split(',').forEach((x, y) => {
+                      const midObj = this.isValidJSON(item.config_) ? JSON.parse(item.config_).scheduleShift.find(d => d.alias === x) : ''
+                      const clockState = midClockArr.length > 0 ? this.judgeClockState(midClockArr, x) : {}
+                      const midUp = midReissueArr.filter(y => y.bu_ka_ban_ci_.includes(x) && y.bu_ka_ban_ci_.includes('上班')) || []
+                      const midDown = midReissueArr.filter(y => y.bu_ka_ban_ci_.includes(x) && y.bu_ka_ban_ci_.includes('下班')) || []
+                      objArr[t].data.push({ name: x, fid: item.fid, config: midObj, clock: clockDataAll, state: clockState, reissue: { up: midUp.length > 0, down: midDown.length > 0 }})
+                    })
+                  }
                 }
               })
             })
+            console.log(objArr)
             this.homologousDate(this.dateArr, objArr)
           }
         })
@@ -201,9 +297,19 @@ export default {
     //
     optFor(val) {
       const selectDate = this.$common.getFormatDate('string', 10, val)
-      if ((this.active === '日程' || this.active === '排班') && this.showDateArr[selectDate] !== '') {
+      this.selectDate = selectDate
+      if (this.active === '日程' && this.showDateArr[selectDate] !== '') {
         this.infoDataArr = this.showDateArr[selectDate] ? this.showDateArr[selectDate].dataArr || {} : {}
-        this.unfoldInfo = this.showDateArr[selectDate] ? this.showDateArr[selectDate].name || '' : ''
+        this.showInfo = true
+      } else if (this.active === '排班' && this.showDateArr[selectDate] !== '') {
+        this.unfoldInfo = this.showDateArr[selectDate] ? { date: selectDate, data: this.showDateArr[selectDate].data } || {} : {}
+
+        if (Object.keys(this.unfoldInfo.data).length > 0) {
+          this.unfoldInfo.data.forEach((m, n) => {
+            const mid = m.config.dateRange.filter(t => t.isSecondDay === 'Y')
+            m.config['isSecondDayAll'] = mid.length > 0
+          })
+        }
         this.showInfo = true
       } else {
         this.showInfo = false
@@ -225,6 +331,20 @@ export default {
       })
     },
 
+    // 打卡记录数据请求
+    async getpunchTheClockData() {
+      const min = this.$common.getFormatDate('string', 10, this.minDate)
+      const max = this.$common.getFormatDate('string', 10, this.maxDate)
+      const sql = `select * FROM t_attendance_detail where yong_hu_id_ = '${this.userId}' and CAST(ri_qi_ AS DATE) between '${min}' and '${max}'`
+      return new Promise((resolve, reject) => {
+        this.$common.request('sql', sql).then(res => {
+          const { data = [] } = res.variables || {}
+          resolve(data)
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
     // 日历数据请求
     async calendar() {
       return new Promise((resolve, reject) => {
@@ -237,7 +357,49 @@ export default {
         })
       })
     },
+    // 补卡数据请求
+    async reissue() {
+      const min = this.$common.getFormatDate('string', 10, this.minDate)
+      const max = this.$common.getFormatDate('string', 10, this.maxDate)
+      const sql = `select * FROM t_attendance_reissue WHERE bian_zhi_ren_ = '${this.userId}' AND CAST(bu_ka_ri_qi_ AS DATE) between '${min}' and '${max}' and zhuang_tai_ != '已撤销'`
+      return new Promise((resolve, reject) => {
+        this.$common.request('sql', sql).then(res => {
+          const data = res.variables.data || []
+          resolve(data)
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+    // 判断打卡状态:目前只有单时间段判断逻辑,pc后续会隐藏配置多时间段入口
+    judgeClockState(arr, name) {
+      // const ind = arr.length - 1
+      const mid = arr.filter(n => n.ban_ci_bie_ming_ === name)[0]
+      const obj = { state: 'clockIn', data: mid }
+      const nowTime = new Date(this.$common.getDateNow(19)).getTime()
+      const startTime = mid ? new Date(mid.ban_ci_kai_shi_).getTime() : ''
+      const endTime = mid ? new Date(mid.ban_ci_jie_shu_).getTime() : ''
 
+      if (nowTime <= startTime) {
+        obj.state = 'beOnButy'
+      }
+      if (nowTime <= startTime && mid && mid.hasOwnProperty('da_ka_shi_jian_1_')) {
+        obj.state = 'clockedIn'
+      }
+      if (nowTime > startTime && nowTime < endTime && mid && !mid.hasOwnProperty('da_ka_shi_jian_1_')) {
+        obj.state = 'beLate'
+      }
+      if ((nowTime > startTime && nowTime < endTime && mid && mid.hasOwnProperty('da_ka_shi_jian_1_'))) {
+        obj.state = 'timeNotYetUp'
+      }
+      if (nowTime >= endTime && mid && !mid.hasOwnProperty('da_ka_shi_jian_2_')) {
+        obj.state = 'getOffwork'
+      }
+      if (nowTime >= endTime && mid && mid.hasOwnProperty('da_ka_shi_jian_2_')) {
+        obj.state = 'upDateTime'
+      }
+      return obj
+    },
     // 日历备注赋值
     formatter(day) {
       const formatterDate = this.$common.getFormatDate('string', 10, day.date)
@@ -245,18 +407,41 @@ export default {
       // const year = day.date.getFullYear()
       // const month = day.date.getMonth() + 1
       // const date = day.date.getDate()
-      // if (year === this.yearMonth.nowYear && month === this.yearMonth.nowMonth && date === this.yearMonth.nowDay) {
-      //   day.className = 'circle'
-      //   day.topInfo = ' '
-      // }
+
       if (this.active === '排班') {
+        let indFT = false
+        if (this.showDateArr && this.showDateArr[formatterDate] && Object.keys(this.showDateArr[formatterDate]).length > 0 && this.showDateArr[formatterDate].data) {
+          this.showDateArr[formatterDate].data.forEach((m, n) => {
+            if (m.clock.isAbnormal === true) {
+              indFT = true
+            }
+          })
+        }
+
+        if (indFT) {
+          day.className = 'circleRed'
+          day.topInfo = ' '
+        } else if (!indFT && this.showDateArr && this.showDateArr[formatterDate] && this.showDateArr[formatterDate].name !== '') {
+          day.className = 'circle'
+          day.topInfo = ' '
+        }
         day.bottomInfo = Object.keys(this.showDateArr).length <= 0 ? '' : this.showDateArr[formatterDate] !== '' && this.showDateArr.hasOwnProperty(formatterDate) ? this.showDateArr[formatterDate].name ? this.showDateArr[formatterDate].name : '' : ''
       } else {
         day.bottomInfo = Object.keys(this.showDateArr).length <= 0 ? '' : this.showDateArr[formatterDate] !== '' && this.showDateArr.hasOwnProperty(formatterDate) ? this.showDateArr[formatterDate].num ? this.showDateArr[formatterDate].num + '项' : '' : ''
       }
       return day
     },
-
+    punchTheClockEvent(val) {
+      this.visibleShow = true
+      this.dialogData = val
+      // this.$set(this, 'dialogData', val)
+    },
+    controlVisible(val, type) {
+      this.visibleShow = val
+      if (type) {
+        this.onClickTab('排班')
+      }
+    },
     // 部分日期数据对应塞入对应整月日期
     homologousDate(all, party) {
       Object.assign(this.showDateArr, {})
@@ -320,6 +505,53 @@ export default {
         stamp = stamp + oneDay
       }
       return dateArr
+    },
+    // compareDates(t1,t2) {
+    //   const t1TimesTamp = new Date(t1).getTime()
+    //   const t2TimesTamp = new Date(t2).getTime()
+    //   return t1TimesTamp
+    // },
+    getBeforeDate(d) {
+      return this.$common.getFormatDate('string', 10, this.$common.getDate('day', -1, d))
+    },
+    isValidJSON(text) {
+      try {
+        JSON.parse(text)
+        return true
+      } catch (error) {
+        return false
+      }
+    },
+    judgeReissueBtn(val, type, date) {
+      const mid = type === 'am' ? ['da_ka_shi_jian_1_', 'ban_ci_kai_shi_', 'zhuang_tai_1_'] : ['da_ka_shi_jian_2_', 'ban_ci_jie_shu_', 'zhuang_tai_2_']
+      const pickDate = new Date(date).getTime()
+      const normDate = new Date(this.$common.getFormatDate('string', 10, this.entryDate)).getTime()
+      const normTime = new Date(this.entryTime).getTime()
+      const bzTime = val.hasOwnProperty(mid[1]) ? new Date(val[mid[1]]).getTime() : ''
+      const dkTime = val.hasOwnProperty(mid[0]) ? new Date(val[mid[0]]).getTime() : ''
+      if (pickDate > normDate) {
+        return true
+      } else if (pickDate === normDate && normTime <= bzTime) {
+        return true
+      } else if (pickDate === normDate) {
+        if (type === 'am' && (!val.hasOwnProperty(mid[0]) || (val.hasOwnProperty(mid[0]) && dkTime > bzTime))) {
+          return false
+        } else if (type === 'pm' && (!val.hasOwnProperty(mid[0]) || (val.hasOwnProperty(mid[0]) && dkTime < bzTime))) {
+          return false
+        }
+      } else if (pickDate < normDate && !val.hasOwnProperty(mid[0]) || !val.hasOwnProperty(mid[2])) {
+        return false
+      }
+      return true
+    },
+    reissueShow(val, type) {
+      this.showPop = true
+      this.reissueData = val
+      this.reissueType = type
+    },
+    updataSet(v) {
+      this.showPop = v
+      this.onClickTab('排班')
     }
   }
 }
@@ -356,6 +588,8 @@ export default {
       width: 98%;
       padding: 1%;
       background-color: #fff;
+      margin-bottom: 2%;
+      line-height: normal;
       .iconLine{
         position: absolute;
         left: 1%;
@@ -368,6 +602,42 @@ export default {
         margin-left: 8%;
         font-size: 75%;
         font-weight: bold;
+        display: flex;
+        justify-content: space-between;
+        .textAll{
+          width: 80%;
+          .textSty{
+            display: flex;
+            align-items: baseline;
+            margin: 3% 0;
+            .timeLine{
+              .reissueBtn{
+                border: 1px solid rgb(25, 137, 250);
+                color: rgb(25, 137, 250);
+                border-radius: 4px;
+                font-size: 0.6rem;
+                padding: 2px 5px;
+                margin-left: 5px;
+              }
+            }
+          }
+        }
+        .textBtn{
+          width: 20%;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          .btnSty{
+            width: 10vw;
+            height: 10vw;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            border-radius: 50%;
+            color: #f56c6c;
+            border: 2px solid #f56c6c;
+          }
+        }
       }
     }
   }
@@ -505,10 +775,17 @@ export default {
   ::v-deep .circle .van-calendar__top-info{
     width: 4px;
     height: 4px;
-    margin: 20% auto;
+    margin: 0.5rem auto;
     background-color: #1989fa;
     border-radius: 6px;
   }
+  ::v-deep .circleRed .van-calendar__top-info{
+    width: 4px;
+    height: 4px;
+    margin: 0.5rem auto;
+    background-color: #f56c6c;
+    border-radius: 6px;
+  }
 }
 
 </style>

+ 39 - 0
src/views/platform/bpmn/my-schedule/scheduleJson.json

@@ -0,0 +1,39 @@
+{
+	"clockTypeList": {
+		"beOnButy": {
+			"label": "上班",
+			"labelDialog": "上班打卡",
+			"color": "#49be49"
+		},
+		"clockedIn": {
+			"label": "已打卡",
+			"labelDialog": "已上班打卡",
+			"color": "#909399"
+		},
+		"beLate": {
+			"label": "迟到",
+			"labelDialog": "迟到打卡",
+			"color": "#f6b932"
+		},
+		"timeNotYetUp": {
+			"label": "下班",
+			"labelDialog": "未到下班时间",
+			"color": "#f6b932"
+		},
+		"getOffwork": {
+			"label": "下班",
+			"labelDialog": "下班打卡",
+			"color": "#49be49"
+		},
+		"upDateTime": {
+			"label": "更新",
+			"labelDialog": "更新打卡",
+			"color": "#49be49"
+		},
+		"clockIn": {
+			"label": "打卡",
+			"labelDialog": "打卡",
+			"color": "#49be49"
+		}
+	}
+}

+ 1 - 1
src/views/platform/my/about-us.vue

@@ -20,7 +20,7 @@
       </div>
     </div>
     <div class="content">
-      &nbsp;&nbsp;&nbsp;&nbsp;深圳金源信通科技有限公司、针对实验室质量管理、日常办公、人员管理、检验管理等,提供一站式解决方案。
+      &nbsp;&nbsp;&nbsp;&nbsp;深圳金源信通科技有限公司、针对实验室质量管理、日常办公、人员管理、检验管理等,提供一站式解决方案。
     </div>
     <div class="content">
       &nbsp;&nbsp;&nbsp;&nbsp;应对客户需求、各工作内容的变动与调整,规范的限制,提供最优的解决方案。