vue vant仿钉钉打卡,提交到接口存储打卡数据

index--切换打卡和统计页面的tab

<template>
  <div>
    <van-tabbar v-model="active">
      <van-tabbar-item :active="0">打卡</van-tabbar-item>
      <van-tabbar-item :active="1">统计</van-tabbar-item>
    </van-tabbar>
    <check v-if="active == 0"></check>
    <record v-if="active == 1"></record>
  </div>
</template>

<script>
import { Tabbar, TabbarItem } from 'vant';
import check from './check.vue';
import record from './record.vue';
export default {
  name: 'clock',
  components: {
    [Tabbar.name]: Tabbar,
    [TabbarItem.name]: TabbarItem,
    check,
    record
  },
  data() {
    return {
      active: 0
    };
  },

  mounted() {},

  methods: {}
};
</script>

<style></style>

check--打卡页面,打卡页面设有更新打卡功能,只在下班打卡时才有,上班打卡取最早一次打卡所以不用更新打卡,下班打卡取最晚一次打卡

<template>
  <div class="main">
    <div class="maintop">
      <div class="user">
        <img class="user-icon" :src="loginInfo.userIcon" alt="" />
        <div>{{ loginInfo.userNickName }}</div>
      </div>
      <div>{{ today }}</div>
    </div>
    <div class="tip">打卡记录时间和位置</div>
    <!-- 打卡时间 -->
    <div class="checktime">
      <van-steps direction="vertical" :active="active" active-color="#3791F9">
        <van-step class="clock-in" :active="0">
          <div v-if="clockInfo.startTime">
            <h3>上班时间{{ clockInfo.startTime | fmtTime }}</h3>
            <p><van-icon name="location" color="#999" />{{ clockInfo.startPlace }}</p>
          </div>
          <div v-else>
            <h3>上班打卡{{ clockTime }}</h3>
            <p v-if="list[0].place"><van-icon name="location" color="#999" />{{ list[0].place }}</p>
          </div>
        </van-step>
        <van-step class="clock-out" :active="1" v-if="active == 1">
          <div v-if="clockInfo.endTime">
            <h3>下班时间{{ clockInfo.endTime | fmtTime }}</h3>
            <p><van-icon name="location" color="#999" />{{ clockInfo.endPlace }}</p>
            <div @click="updateclock">更新打卡></div>
          </div>
          <div v-else>
            <h3>下班打卡{{ clockTime }}</h3>
            <p v-if="list[1].place"><van-icon name="location" color="#999" />{{ list[1].place }}</p>
          </div>
        </van-step>
      </van-steps>
    </div>
    <!-- 打卡按钮 -->
    <div v-show="this.btnshow">
      <div class="check-container">
        <div class="checkbtn">
          <div class="btn-content" @click="daka">
            <div>{{ active == 0 ? '上班打卡' : '下班打卡' }}</div>
            <div>{{ showTime }}</div>
          </div>
        </div>
      </div>
    </div>
    <!-- 打卡成功弹窗 -->
    <van-dialog v-model="show" @confirm="handlesure">
      <div class="success">
        <img src="../../../../assets/img/img_daka@2x.png" style="width: 160px;height: 105px;" />
        <div class="successTime">{{ clockTime }}</div>
        <div class="successType">{{ active == 0 ? '上班' : '下班' }}打卡成功</div>
      </div>
    </van-dialog>
  </div>
</template>

<script>
import { Step, Steps, Icon, Dialog } from 'vant';
import AMapLoader from '@amap/amap-jsapi-loader';

export default {
  components: {
    [Step.name]: Step,
    [Steps.name]: Steps,
    [Icon.name]: Icon,
    [Dialog.name]: Dialog
  },
  data() {
    return {
      loginInfo: {
        userIcon: '', // 用户头像路径
        userNickName: '' // 用户昵称
      },
      today: '',
      t: null,
      showTime: '',
      active: 0,
      clockin: {},
      clockout: {},
      btnshow: true,
      date: '',
      clockInfo: {},
      list: [
        {
          place: ''
        },
        {
          place: ''
        }
      ],
      clockType: '',
      show: false,
      clockTime: ''
    };
  },
  methods: {
    getCurrentDate() {
      let now = new Date();
      let year = now.getFullYear();
      let month = now.getMonth() + 1;
      let day = now.getDate();
      let h = now.getHours();
      let m = now.getMinutes();
      let s = now.getSeconds();
      this.date = Date.parse(year + '-' + month + '-' + day + ' ' + h + ':' + m + ':' + s);
      this.today = year + '-' + month + '-' + day;
    },
    time() {
      clearTimeout(this.t); //清除定时器
      var dt = new Date();
      var h = this.addZero(dt.getHours()); //获取时,并补全零
      var m = this.addZero(dt.getMinutes()); //获取分,并补全零
      var s = this.addZero(dt.getSeconds()); //获取秒,并补全零
      this.showTime = h + ':' + m + ':' + s;
      this.t = setTimeout(() => this.time(), 1000); //设定定时器,循环运行
    },
    // 时分秒补全零
    addZero(i) {
      if (i < 10) {
        i = '0' + i;
      }
      return i;
    },
    // 初始化获取数据
    getclockInfo() {
      this.$loading();
      this.request('queryInfo', { startTime: this.date }).then(res => {
        this.clockInfo = res;
        if (this.clockInfo.startTime && this.clockInfo.endTime) {
          this.btnshow = false;
          this.active = 1;
        } else {
          this.btnshow = true;
          if (this.clockInfo.startTime) {
            this.active = 1;
          }
        }
      }).finally(()=>{
        this.$loading().close();
      });
    },
    daka() {
      AMapLoader.reset();
      AMapLoader.load({
        key: process.env.VUE_APP_AMPKEY,
        version: '2.0',
        plugins: ['AMap.AutoComplete', 'AMap.CitySearch', 'AMap.Geolocation', 'AMap.Geocoder']
      }).then(AMap => {
        const geocoder = new AMap.Geocoder();
        const geolocation = new AMap.Geolocation({
          enableHighAccuracy: true,
          timeout: 10000
        });
        this.$loading();
        geolocation.getCurrentPosition((status, res) => {
          if (status === 'complete') {
            const dt = new Date();
            this.clockTime =
              this.addZero(dt.getHours()) + ':' + this.addZero(dt.getMinutes()) + ':' + this.addZero(dt.getSeconds());
            const position = res.position;
            const lnglat = [position.lng, position.lat];
            geocoder.getAddress(lnglat, (geoStatus, result) => {
              if (geoStatus === 'complete' && result.info === 'OK') {
                this.$loading().close();
                if (this.clockType == 1) {
                  this.list[0].place = result.regeocode.formattedAddress;
                  this.show = true;
                } else {
                  this.list[1].place = result.regeocode.formattedAddress;
                }
              }
            });
          } else {
            this.$loading().close();
            this.$toast.fail('获取位置失败,请打开手机定位功能');
          }
        });
      });
    },
    handlesure() {
      this.show = false;
      this.clockIn();
    },
    clockIn() {
      // 将打卡信息提交到接口
      const params = {
        clockType: this.clockInfo.startTime ? 2 : 1,
        place: this.clockType == 1 ? this.list[0].place : this.list[1].place,
        dateTime: this.date,
        userId: this.loginInfo.userId
      };
      this.request('insert', params).then(() => {
        this.getclockInfo();
      });
    },
    // 更新打卡
    updateclock() {
      Dialog.confirm({
        message: '确定更新此次打卡记录吗?'
      })
        .then(() => {
          // on confirm
          this.clockType = 2;
          this.daka();
          this.clockIn();
          this.getclockInfo();
        })
        .catch(() => {
          // on cancel
        });
    }
  },
  mounted() {
    this.loginInfo = this.getLoginInfo();
    this.getCurrentDate();
    this.getclockInfo();
    if (this.list[0].place == '') {
      this.clockType = 1;
      this.active = 0;
    } else {
      this.clockType = 2;
      this.active = 1;
    }
  },
  created() {
    this.t = setTimeout(this.time, 1000);
  }
};
</script>

<style lang="scss" scoped>
.main {
  background-color: #f3f4f6;
  height: 100vh;
}
.user-icon {
  width: 35px;
  height: 35px;
  border-radius: 35px;
}
.maintop {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  font-size: 16px;
  color: #333;
  background-color: #fff;
  .user {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
}
.tip {
  color: #999;
  text-align: center;
  margin-top: 10px;
}
.check-container {
  display: flex;
  justify-content: center;
  align-items: center;
  margin-top: 20px; /* Adjust margin as needed */
}

.checkbtn {
  width: 100px;
  height: 100px;
  border-radius: 50%; /* Use 50% to make a perfect circle */
  color: #fff;
  text-align: center;
  background: linear-gradient(135deg, #97c6fd, #73b2fb, #54a1fa, #4297fa);
}

.btn-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 100%;
}
.checktime {
  padding: 20px;
}
.van-steps {
  background-color: #f3f4f6;
}
/* 隐藏活动状态的图标 */
.van-step__icon--active {
  display: none;
}
.success {
  padding: 50px 75px;
  text-align: center;
  .successTime {
    font-size: 45px;
    font-weight: bold;
    color: #3791f9;
  }
  .successType {
    margin-top: 15px;
    font-size: 16px;
    color: #3791f9;
  }
}
</style>

record--打卡记录页面,当月数据有上下班打卡的日期下加蓝点,只有一次打卡记录的为黄点,没有打卡就不管,可以切换上一个月下一个月,切换上一个月就默认default日期为当月最后一天,切换下一个月就默认日期default为当月第一天,如果切换回当月,就查当月当天的数据。

<template>
  <div>
    <div v-if="cloading" class="loading">
      <van-loading size="24px" vertical>加载中...</van-loading>
    </div>
    <div class="main" v-else>
      <div class="maintop">
        <div class="user">
          <img class="user-icon" :src="loginInfo.userIcon" alt="" />
          <div>{{ loginInfo.userNickName }}</div>
        </div>
        <div>
          <van-icon name="arrow-left" @click="lastMonth" />
          <span style="color: #3791F9;">{{ year }}-{{ month + 1 }}</span>
          <van-icon name="arrow" @click="nextMonth" />
        </div>
      </div>
      <!-- 日历 -->
      <div>
        <van-calendar
          :poppable="false"
          :show-confirm="false"
          :show-mark="false"
          :show-title="false"
          :show-subtitle="false"
          :min-date="minDate"
          :max-date="maxDate"
          :first-day-of-week="1"
          :style="{ height: '400px' }"
          @select="onselect"
          :formatter="formatter"
          :default-date="defaultDate"
        />
        <div class="checktime" v-if="records && (records.startTime || records.endTime)">
          <van-steps direction="vertical" active-color="#999" inactive-color="#999" active-icon="stop">
            <van-step>
              <h3>{{ records.startTime ? `上班时间${formatTimestamp(records.startTime)}` : '上班未打卡' }}</h3>
              <p v-if="records.startPlace"><van-icon name="location" color="#999" />{{ records.startPlace }}</p>
            </van-step>
            <van-step>
              <h3>{{ records.endTime ? `下班时间${formatTimestamp(records.endTime)}` : '下班未打卡' }}</h3>
              <p v-if="records.endPlace"><van-icon name="location" color="#999" />{{ records.endPlace }}</p>
            </van-step>
          </van-steps>
        </div>

        <div class="unavailable" v-else>暂无打卡信息</div>
      </div>
    </div>
  </div>
</template>

<script>
import { Icon, Calendar, Step, Steps, Loading } from 'vant';
export default {
  components: {
    [Icon.name]: Icon,
    [Calendar.name]: Calendar,
    [Step.name]: Step,
    [Steps.name]: Steps,
    [Loading.name]: Loading
  },
  data() {
    return {
      loginInfo: '',
      date: '',
      records: '',
      cloading: false,
      selecttimestamp: '',
      dayDatas: { days: [] },
      // 月份
      minDate: new Date(),
      maxDate: new Date(),
      year: new Date().getFullYear(),
      month: new Date().getMonth(),
      nowDay: new Date().getDate(),
      defaultDate: new Date(),
      cont: 0
    };
  },

  methods: {
    // 将时间戳转为时间展示
    formatTimestamp(timestamp) {
      const date = new Date(timestamp);
      const year = date.getFullYear();
      const month = date.getMonth() + 1; // 月份从 0 开始,所以需要加 1
      const day = date.getDate();
      const hours = this.addZero(date.getHours());
      const minutes = this.addZero(date.getMinutes());
      const seconds = this.addZero(date.getSeconds());
      // 拼接成展示的时间字符串
      const timeString = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
      return timeString;
    },
    // 时分秒补全零
    addZero(i) {
      if (i < 10) {
        i = '0' + i;
      }
      return i;
    },
    // 查询打卡信息
    getclockInfo() {
      let now = new Date();
      let year = now.getFullYear();
      let month = now.getMonth() + 1;
      let day = now.getDate();
      let h = now.getHours();
      let m = '0' + now.getMinutes();
      let s = '0' + now.getSeconds();
      // 判断使用哪个时间参数
      let selectedTime = this.selectTime
        ? this.selectTime
        : this.defaultDate
        ? this.defaultDate.getTime()
        : Date.parse(year + '-' + month + '-' + day + ' ' + h + ':' + m + ':' + s);

      // 检查选择的日期是否在本月内,如果是则使用选择日期的时间戳
      if (new Date(selectedTime).getMonth() + 1 === this.defaultDate.getMonth() + 1) {
        selectedTime = this.selectTime ? this.selectTime : this.defaultDate.getTime();
      } else {
        selectedTime = this.selectTime
          ? this.selectTime
          : Date.parse(year + '-' + month + '-' + day + ' ' + h + ':' + m + ':' + s);
      }
      this.request('queryInfo', { startTime: selectedTime }).then(res => {
        this.records = res;
      });
    },
    // 查询打卡数据
    getclockListInfo() {
      var y = this.defaultDate.getFullYear();
      var m = this.defaultDate.getMonth() + 1;
      m = m < 10 ? '0' + m : m;
      const monthtime = new Date(y + '-' + m).getTime();
      this.cloading = true;
      this.request('queryList', { startTime: monthtime })
        .then(res => {
          this.dayDatas.days = res;
        })
        .finally(() => {
          this.cloading = false;
        });
    },
    formatter(day) {
      let dayTimestamp = new Date(day.date).getTime();
      //判断日期是否有数据用map
      this.dayDatas.days.map(item => {
        let itemDate = new Date(item['dayDate'].replace(/-/g, '/')).getTime();

        if (dayTimestamp == itemDate && item.startTime && item.endTime) {
          day.className = 'addDot';
        }
        if (dayTimestamp == itemDate && (!item.startTime || !item.endTime)) {
          day.className = 'incomplete';
        }
        // return day; // 返回更新后的day对象
      });

      return day;
    },
    onselect(value) {
      this.selecttimestamp = value;
      this.selectTime = Date.parse(value);
      this.getclockInfo();
    },
    // 切换上个月
    lastMonth() {
      this.month--;
      if (this.month < 0) {
        this.month = 11;
        this.year--;
      }
      this.selectTime = undefined;

      let lastDayOfLastMonth = new Date(this.year, this.month + 1, 0);
      let today = new Date();
      if (
        lastDayOfLastMonth.getMonth() === today.getMonth() &&
        lastDayOfLastMonth.getFullYear() === today.getFullYear()
      ) {
        this.defaultDate = today;
      } else {
        this.defaultDate = new Date(this.year, this.month, lastDayOfLastMonth.getDate());
      }
      this.setMinMaxDay();
      this.getclockInfo();
      this.getclockListInfo();
    },
    // 切换下个月
    nextMonth() {
      this.month++;
      if (this.month > 11) {
        this.month = 0;
        this.year++;
      }
      this.selectTime = undefined;
      // 获取下一个月的第一天
      let firstDayOfNextMonth = new Date(this.year, this.month, 1); // 下一个月的第一天
      let today = new Date();
      if (
        firstDayOfNextMonth.getMonth() === today.getMonth() &&
        firstDayOfNextMonth.getFullYear() === today.getFullYear()
      ) {
        this.defaultDate = today;
      } else {
        this.defaultDate = firstDayOfNextMonth;
      }
      // 更新defaultDate为当前选择的年份和月份信息
      this.setMinMaxDay();
      this.getclockInfo();
      this.getclockListInfo(); // 重新获取当月打卡信息数据
    },
    setMinMaxDay() {
      var firstDay = new Date(this.year, this.month, 1);
      this.minDate = firstDay;
      var endDate = new Date(this.year, this.month + 1, 0);
      this.maxDate = endDate;
    }
  },
  mounted() {
    this.loginInfo = this.getLoginInfo();
    this.getclockInfo();
    this.$nextTick(() => {
      this.setMinMaxDay();

      this.getclockListInfo();
    });
  }
};
</script>

<style lang="scss" scoped>
.loading {
  height: calc(100vh - 44px);
  display: flex;
  justify-content: center;
  align-items: center;
}
.main {
  background-color: #f3f4f6;
  height: 100vh;
}
.maintop {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  font-size: 16px;
  color: #333;
  background-color: #fff;
  .user-icon {
    width: 35px;
    height: 35px;
    border-radius: 35px;
  }
  .user {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
}
::v-deep .van-calendar__selected-day {
  background-color: #4297fa !important;
  border-radius: 50% !important;
  width: 40px;
  height: 40px;
}
.checktime {
  padding: 20px;
  .van-steps {
    background-color: #f3f4f6;
  }
}
.unavailable {
  margin-top: 20px;
  color: #999;
  text-align: center;
}
//有数据日期加点
::v-deep(.addDot) {
  position: relative;
}
::v-deep(.addDot::after) {
  position: absolute;
  content: '';
  width: 6px;
  height: 6px;
  top: 55px;
  left: 25px;
  border-radius: 50%;
  background-color: #0084ff;
}

::v-deep(.incomplete) {
  position: relative;
}
::v-deep(.incomplete::after) {
  position: absolute;
  content: '';
  width: 6px;
  height: 6px;
  top: 55px;
  left: 25px;
  border-radius: 50%;
  background-color: #ffae34;
}
</style>

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值