1 Star 0 Fork 10

ScottXia / 微信小程序Demo

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

页面效果展示

输入图片说明 输入图片说明

集成腾讯地图SDK

腾讯位置服务为微信小程序提供了基础的标点能力、线和圆的绘制接口等地图组件和位置展示、地图选点等地图API位置服务能力支持,使得开发者可以自由地实现自己的微信小程序产品。 在此基础上,腾讯位置服务微信小程序JavaScript SDK是专为小程序开发者提供的LBS数据服务工具包,可以在小程序中调用腾讯位置服务的POI检索、关键词输入提示、地址解析、逆地址解析、行政区划和距离计算等数据服务,让您的小程序更强大!

文档地址:微信小程序JavaScript SDK

使用步骤说明:

1.申请开发者密钥(key):申请密钥

2.开通webserviceAPI服务

控制台 ->应用管理 -> 我的应用 ->添加key-> 勾选WebServiceAPI -> 保存

(小程序SDK需要用到webserviceAPI的部分服务,所以使用该功能的KEY需要具备相应的权限)

3.下载微信小程序JavaScriptSDK

微信小程序JavaScriptSDK v1.1 JavaScriptSDK v1.2 ,这里推荐下载1.2版本,将下载好的SDK放在对应文件夹中,去引用它(即 qqmap-wx-jssdk.min.js 文件)引用到你小程序项目中。

4.安全域名设置

在小程序管理后台 -> 开发 -> 开发管理 -> 开发设置 -> “服务器域名” 中设置request合法域名,添加https://apis.map.qq.com

这个操作需要小程序管理员进到后台去配置 本地环境开发只需设置 勾上 不校验合法域名 即可

5.小程序核心代码示例

// 引入SDK核心类,js文件根据自己业务,位置可自行放置
var QQMapWX = require('../../libs/qqmap-wx-jssdk.js');
var qqmapsdk;
Page({
 
    onLoad: function () {
        // 实例化API核心类
        qqmapsdk = new QQMapWX({
            key: '申请的key'
        });
    },
    onShow: function () {
        // 调用接口
        qqmapsdk.search({
            keyword: 'DreamCoders',
            success: function (res) {
                console.log(res);
            },
            fail: function (res) {
                console.log(res);
            },
        complete: function (res) {
            console.log(res);
        }
     });
  }
})

微信小程序代码

wx.getLocation(Object object)

功能描述 获取当前的地理位置、速度。当用户离开小程序后,此接口无法调用。开启高精度定位,接口耗时会增加,可指定 highAccuracyExpireTime 作为超时时间。地图相关使用的坐标格式应为 gcj02。 高频率调用会导致耗电,如有需要可使用持续定位接口 wx.onLocationChange。 基础库 2.17.0 版本起 wx.getLocation 增加调用频率限制,相关公告。

使用方法 自 2022 年 7 月 14 日后发布的小程序,若使用该接口,需要在 app.json 中进行声明,否则将无法正常使用该接口,2022年7月14日前发布的小程序不受影响。具体规则见公告

申请开通 暂只针对如下类目的小程序开放,需要先通过类目审核,再在小程序管理后台,「开发」-「开发管理」-「接口设置」中自助开通该接口权限。 接口权限申请入口将于2022年3月11日开始内测,于3月31日全量上线。并从4月18日开始,在代码审核环节将检测该接口是否已完成开通,如未开通,将在代码提审环节进行拦截。

微信小程序获取定位关键方法 getLocation。因此需要在 app.json 中进行声明,后期小程序上线还需要单独申请getLocation 接口权限。

app.json 部分关键代码

{
  "pages": [
    "pages/index/index",
    "pages/sign/sign"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "Weixin",
    "navigationBarTextStyle": "black"
  },
  "tabBar": {
		"custom": false,
		"backgroundColor": "#fefefe",
		"color": "#999999",
		"selectedColor": "#1C9D9D",
		"list": [{
				"pagePath": "pages/index/index",
				"text": "首页",
				"iconPath": "/images/home.png",
				"selectedIconPath": "/images/home_cur.png"
			},
			{
				"pagePath": "pages/sign/sign",
				"text": "打卡",
				"iconPath": "/images/day.png",
				"selectedIconPath": "/images/day_cur.png"
			},
		
			{
        "pagePath": "pages/index/index",
				"text": "我的",
				"iconPath": "/images/my.png",
				"selectedIconPath": "/images/my_cur.png"
			}
		]
	},
  "permission": {
		"scope.userLocation": {
			"desc": "您的位置信息将用于小程序考勤签到功能"
		}
	},
	"requiredPrivateInfos":[
		"getLocation"
	],
  "style": "v2",
  "sitemapLocation": "sitemap.json",
  "lazyCodeLoading": "requiredComponents"
}

sign.wxml代码

<!-- 部分UI代码参考苏苏就是小苏苏 -->
<view class="index">
  <!-- 用户信息 -->
  <view class="head ">
    <view class="head_box flex-row" style="justify-content:left">
      <view class="user_ava">
        <open-data type="userAvatarUrl"></open-data>
      </view>
      <view>
        <view class="user_name">DreamCoders <text>{{tip}}</text></view>
        <view class="user_add">新的一天开始了,加油哦~</view>
      </view>
      <view class="mealBtn" bindtap="ToMealTap">
        <image src="/images/meal.png"></image>
        <view class="mealText">{{is_meal==2 ? '已订':'订餐'}}</view>
      </view>
    </view>
  </view>
 
  <view class="contentBox">
    <!-- 打卡记录 -->
    <view class="signRecord">
      <view class="signInfo">上班打卡
        <text class="text-green">{{record[0].times ? record[0].times : '未打卡'}}</text>
        <view class="sign_address">
          <view class="">{{record[0].address ? record[0].address : '暂无打卡地址'}}</view>
        </view>
      </view>
      <view class="signInfo">下班打卡
        <text class="text-green">{{record[1].times ? record[1].times : '未打卡'}}</text>
        <view class="sign_address">
          <view class="">{{record[1].address ? record[1].address : '暂无打卡地址'}}</view>
        </view>
      </view>
    </view>
    <view class="dateInfo ">
      <text>{{nowDate}} {{nowDay}}</text>
    </view>
    <!-- 打卡按钮 -->
    <view class="c_clock flex-column">
      <view class="clock_time flex-column j_c {{status==1?'c1':''}} {{is_out==2 ? 'outArea' : ''}}" catchtap="signTap">
        <text>{{signType>0 ? "下班打卡" : "上班打卡"}}</text>
        <text>{{now_time}}</text>
      </view>
      <view class="clock_time_over flex-column j_c  {{status==1?'c2':''}}" catchtap="clockInStart">
        <text>已打卡</text>
        <text>{{now_time_stop}}</text>
      </view>
    </view>
    <!-- 打卡地址 -->
    <view class="clock_address ">
      <image src="/images/add0.png" class="add_icon" />
      <text>{{current_address}}</text>
    </view>
    <view class="refresh" catchtap="refreshAdd">刷新位置</view>
  </view>
</view>

sign.js代码

let qqMapSdk= require("../../utils/qqmap.js");
let util = require('../../utils/util.js')
 
Page({
  /**
   * 页面的初始数据
   */
  data: {
    signType:0,//0上班打卡 1下班打卡
    is_out:2,//1办公地点打卡 2外勤打卡
    is_meal:1,//1未定餐 2已订餐
    now_time: '',//当前时间
    nowDate:'',//当前年月日
    nowDay:'',//星期几
    tip:'',//提示 上午好、下午好
    current_address: '',//当前定位地址
    status: 0, //0未打卡 1已打卡
    latlng:[],//经纬度
    now_time_stop: '', //已打卡时间
    area:{},//考勤点多个
    record:[],//打卡记录
  },
 
 
  onLoad: function (options) {
    this.getCurrentTime();
    this.setData({
      now_time: this.getTime(),
      nowDate: util.formatTime(new Date()),
      nowDay: util.formatDay(new Date()),
      tip: util.formatSole(),
    })
  },
 
  onShow: function () {
    this.getLocation();
    this.setData({
      status:0,
      current_address:'',
    })
  },
 
 
  signTap() {
    var that = this;
    if (!that.data.current_address) {
      return wx.showToast({
        title: '未获取当前定位',
        icon: 'error'
      })
    }
    var list =  that.data.record.concat({'times':that.data.now_time,'address':that.data.current_address});
    wx.vibrateLong();//手机震动提示
    that.getSignRecord();
    that.setData({
      status: 1, //已打卡
      record:list,
      now_time_stop: that.data.now_time,
    })
    console.log(list);
    console.log(that.data.record);
    wx.showToast({
      title: '打卡成功',
      icon: 'none'
    })
  },
 
  getCurrentTime: function () {
    var time = setInterval(() => {
      this.setData({
        now_time: this.getTime()
      })
    }, 1000)
  },
  getTime() {
    let dateTime = '';
    let hh = new Date().getHours()
    let mf = new Date().getMinutes() < 10 ? '0' + new Date().getMinutes() :
      new Date().getMinutes()
    let ss = new Date().getSeconds() < 10 ? '0' + new Date().getSeconds() :
      new Date().getSeconds()
    dateTime = hh + ':' + mf + ':' + ss;
    return dateTime;
  },
 
  // 请求获取定位授权
  getUserAuth: function () {
    return new Promise((resolve, reject) => {
      wx.authorize({
        scope: 'scope.userLocation'
      }).then(() => {
        resolve()
      }).catch(() => {
        let that = this;
        wx.getSetting({
          success: (res) => {
            if (res.authSetting['scope.userLocation'] != undefined && res.authSetting['scope.userLocation'] != true) {
              wx.showModal({
                title: '请求授权当前位置',
                content: '需要获取您的地理位置,请确认授权',
                success: function (res) {
                  if (res.cancel) {
                    wx.showToast({
                      title: '拒绝授权',
                      icon: 'none',
                      duration: 1000
                    })
                  } else if (res.confirm) {
                    wx.openSetting({
                      success: function (dataAu) {
                        if (dataAu.authSetting["scope.userLocation"] == true) {
                          //再次授权,调用wx.getLocation的API
                          that.getLocation();
                        } else {
                          wx.showToast({
                            title: '授权失败',
                            icon: 'none',
                            duration: 1000
                          })
                        }
                      }
                    })
                  }
                }
              })
            } else if (res.authSetting['scope.userLocation'] == undefined) {
              that.getLocation();
            } else {
              that.getLocation();
            }
          }
        })
      })
    })
  },
 
  getLocation: function () {
    const that = this
		// 实例化腾讯地图API核心类
    const QQMapWX = new qqMapSdk({
      key: '你申请的KEY'// KEY必填
    });
    //获取当前位置
    wx.getLocation({
      type: 'gcj02',
      success: function(res) {
        that.latitude = res.latitude
        that.longitude = res.longitude
        QQMapWX.reverseGeocoder({
          location: {
            latitude: res.latitude,
            longitude: res.longitude
          },
          success: function(res) {
            let address = res.result.address + res.result.formatted_addresses.recommend;
            that.getSignRecord();
            that.setData({
              current_address:address,
              latlng:[res.result.location.lat,res.result.location.lng]
            })
          },
          fail: function(res) {
            this.getUserAuth()
            wx.showToast({
              title: '获取定位失败,请打开手机定位,重新进入!',
              icon: 'none'
            });
          }
        })
      },
    })
  },
  // 刷新定位
  refreshAdd() {
    this.getLocation(),
    this.getSignRecord()
  },
 
  //处理打卡记录及判断打卡位置是否办公地点打卡
  getSignRecord: function () {
    var that = this;
    console.log(that.data.latlng);
    var distance = that.getDistance(that.data.latlng[0],that.data.latlng[1],31.370450,121.228252);
    if(distance < 200000000000000){
      that.setData({
        is_out:1,
      })
    }
  },
 
 
//经纬度距离计算
getDistance:function (lat1, lng1, lat2, lng2, unit = false) {
    var radLat1 = lat1 * Math.PI / 180.0
    var radLat2 = lat2 * Math.PI / 180.0
    var a = radLat1 - radLat2
    var b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0
    var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
      Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)))
    s = s * 6378.137 // EARTH_RADIUS;
    s = Math.round(s * 10000) / 10000 //输出为公里
    if (0) { //是否返回带单位
      if (s < 1) { //如果距离小于1km返回m
        s = s.toFixed(3)
        s = s * 1000 + "m"
      } else {
        s = s.toFixed(2)
        s = s + "km"
      }
    } else {
      s = s.toFixed(3)
      s = s * 1000
    }
	return s
},
 
//订餐操作
ToMealTap:function (e) {
  wx.showToast({
    title: '订餐成功',
    icon: 'none'
  })
  this.setData({
    is_meal: 2,
  })
}
 
})

sign.json 代码

{
  "usingComponents": {},
  "navigationBarTitleText": "考勤打卡"
}

sign.wxss 代码

page {
  height: calc(100% - 10px)
}
 
.index {
  margin-top: 10px;
  background: #fff;
  min-height: 100%;
}
 
.head {
  padding-bottom: 10rpx;
  border-bottom: 2rpx solid #E5E5E5;
}
 
.head_box {
  padding: 26rpx 28rpx 8px;
  width: 750rpx;
  box-sizing: border-box;
}
 
.user_ava {
  width: 116rpx;
  height: 116rpx;
  overflow: hidden;
  border-radius: 25%;
  margin-right: 32rpx;
}
 
.user_name {
  font-size: 32rpx;
  font-weight: 600;
  color: #333333;
  margin-bottom: 18rpx;
}
 
.user_name text {
  font-size: 24rpx;
  color: #999999;
  font-weight: 400;
  margin-left: 40rpx;
}
 
.user_add {
  font-size: 28rpx;
  color: #3380F3;
}
 
.contentBox {
  padding: 44rpx 28rpx;
}
 
.signRecord{
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-between;
  margin-top: 15px;
}
 
.dateInfo{
  text-align: center;
  position: relative;
  top: 50px;
  font-size: 35rpx;
}
 
.c_title {
  font-size: 28rpx;
  color: #666666;
  margin-bottom: 26rpx;
}
 
 
.c_section .c_item {
  position: relative;
  font-size: 30rpx;
  font-weight: 600;
  color: #333333;
  padding-left: 40rpx;
  margin-bottom: 110rpx;
}
 
.c_section text {
  color: #307CED;
  text-overflow: ellipsis;
  overflow: hidden;
  width: 80%;
  white-space: nowrap;
}
 
.c_section .c_item::before {
  content: '';
  position: absolute;
  width: 18rpx;
  height: 18rpx;
  border: 2rpx solid #999999;
  left: 0;
  top: 50%;
  margin-top: -9rpx;
  border-radius: 50%;
}
 
.c_section {
  position: relative;
}
 
.c_section .c_item::after {
  content: '';
  position: absolute;
  width: 2rpx;
  height: 178rpx;
  background: #E6E6E6;
  left: 10rpx;
  top: 34rpx;
}
 
.c_section view:last-child::after {
  display: none;
}
 
.start_lo {
  position: absolute;
  top: 30px;
  left: -5px;
}
 
.start_end {
  position: absolute;
  bottom: -108px;
  left: 20px;
}
 
.c_clock {
  margin: 180rpx auto 0;
  width: 350rpx;
  height: 380rpx;
  perspective: 1500;
  -webkit-perspective: 1500;
  -moz-perspective: 1500;
}
 
.clock_time {
  width: 350rpx;
  height: 350rpx;
  margin-bottom: 30rpx;
  position: absolute;
  transition: all 1s;
  backface-visibility: hidden;
}
 
.clock_time::after {
  content: '';
  top: 0;
  left: 0;
  width: 350rpx;
  height: 350rpx;
  border-radius: 50%;
  position: absolute;
  z-index: 9;
  background: rgba(48, 124, 237, 0.08);
  animation: scale 1s infinite alternate-reverse;
}
 
/* 已打卡 */
.clock_time_over {
  width: 350rpx;
  height: 350rpx;
  margin-bottom: 30rpx;
  border-radius: 50%;
  background: rgba(48, 124, 237, 0.08);
  position: absolute;
  transition: all 1s;
  backface-visibility: hidden;
  transform: rotateY(-180deg);
}
 
.clock_time_over::after {
  position: absolute;
  z-index: 11;
  content: '';
  width: 320rpx;
  height: 320rpx;
  background: #C6CED9;
  border-radius: 50%;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
 
 
 
.clock_time_over text {
  position: relative;
  z-index: 13;
  color: #FFFFFF;
}
 
.clock_time_over text:first-child {
  font-size: 36rpx;
  margin-bottom: 14rpx;
}
 
.clock_time_over text:last-child {
  font-size: 28rpx;
}
 
@keyframes scale {
 
  0% {
    transform: scale(1.1);
  }
 
  100% {
    transform: scale(1);
  }
}
 
.clock_time::before {
  position: absolute;
  z-index: 11;
  content: '';
  width: 320rpx;
  height: 320rpx;
  background: rgb(48, 124, 237, 0.79);
  border-radius: 50%;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
 
.clock_time text {
  position: relative;
  z-index: 13;
  color: #FFFFFF;
}
 
.clock_time text:first-child {
  font-size: 36rpx;
  margin-bottom: 14rpx;
}
 
.clock_time text:last-child {
  font-size: 45rpx;
}
 
.clock_address {
  text-align: center;
  font-size: 30rpx;
  color: #333333;
  width: 80%;
  margin: 20px auto;
  overflow:hidden;  
  text-overflow:ellipsis;
  white-space:nowrap;
}
 
.clock_address text {
  vertical-align: middle;
}
 
.add_icon {
  width: 28rpx;
  height: 36rpx;
  margin-right: 16rpx;
  vertical-align: middle;
}
 
.refresh {
  margin-top: 25px;
  color: #307CED;
  display: flex;
  align-items: center;
  justify-content: center;
}
 
 
 
.now_location {
  font-size: 24rpx;
  color: #333333 !important;
}
 
.upload_box {
  width: 260rpx;
  height: 180rpx;
  background: #F5F5F8;
  border-radius: 5rpx;
}
 
.upload_box text {
  font-size: 20rpx;
  color: #999 !important;
  font-weight: 100;
}
 
.camera_icon {
  width: 42rpx;
  height: 44rpx;
  margin-bottom: 10rpx;
}
 
.clock_img {
  width: 100%;
  height: 100%;
}
 
.del_icon {
  width: 32rpx;
  height: 32rpx;
  position: absolute;
  right: -4px;
  top: -11rpx;
}
 
.ative::before {
  background: #307cedc9;
  border: 2rpx solid #307cedc9 !important;
}
 
.c1 {
  transform: rotateY(180deg)
}
 
.c1::after {
  animation: none !important;
}
 
.c2 {
  transform: rotateY(0deg)
}
 
.mealBtn{
  position: absolute;
  right: 15px;
}
.mealBtn image{
  width: 27px;
  height: 27px;
}
.mealText{
 font-size: 12px;
 color: #999999;
}
 
.outArea::before{
  background: #f44336 !important;
}
.signInfo{
  width: 48%;
  height: 65px;
  background: #f1f1f1;
  padding: 10px;
  border-radius: 5px;
}
.signInfo text{
  float: inline-end;
}
.sign_address{
  display: flex;
  margin-top: 5px;
}
 
 
.sign_address view{
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  font-size: 14px;
  margin-top: 1px !important;
  color: #5f5a5a;
}
 
.text-green{
  color: green;
}

util.js 代码

function formatTime(date) {
  var year = date.getFullYear()
  var month = date.getMonth() + 1
  var day = date.getDate()
  return year + "年" + month + "月" + day + "日";
}
const formatDay = dates => {
  let _day = new Array('星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六');
  let date = new Date(dates);
  date.setDate(date.getDate());
  let day = date.getDay();
  return _day[day];
}
const formatSole = () => {
  let timeNow = new Date();
  let hours = timeNow.getHours();
  let text = ``;
  if (hours >= 0 && hours <= 6) {
    text = `深夜了,不要熬夜太久哟`;
  } else if (hours > 6 && hours <= 8) {
    text = `早上好`;
  } else if (hours > 8 && hours <= 10) {
    text = `上午好`;
  } else if (hours > 10 && hours <= 13) {
    text = `中午好`;
  } else if (hours > 13 && hours <= 17) {
    text = `下午好`;
  } else if (hours > 17 && hours <= 23) {
    text = `晚上好`;
  }
  return text;
}
module.exports = {
  formatTime: formatTime,
  formatDay: formatDay,
  formatSole: formatSole
}

版权声明:本文为CSDN博主「DreamCoders」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_31766533/article/details/125968189

MIT License Copyright (c) 2022 陌生人 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

微信小程序考勤打卡示例 展开 收起
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/scott_xia/miniWxDemo.git
git@gitee.com:scott_xia/miniWxDemo.git
scott_xia
miniWxDemo
微信小程序Demo
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891