clockIn.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. <template>
  2. <view class="content">
  3. <view class="sign-box">
  4. <view class="content-show">
  5. <view :class="['module', moduleColor]" @click="clickSign">
  6. <view class="text">打卡</view>
  7. <view class="time">{{ time }}</view>
  8. </view>
  9. </view>
  10. <view class="sign-info" v-if="amSign.address">
  11. <view>打卡时间: {{ amSign.time }}</view>
  12. <view>打卡地点:{{ amSign.address }}</view>
  13. </view>
  14. </view>
  15. <view class="picture-box">
  16. <button class="picture-btn">拍照</button>
  17. <view class="picture-show">
  18. <image src="../../static/tp.png"></image>
  19. </view>
  20. </view>
  21. <view class="button-container">
  22. <view class="button-pad">
  23. <button class="clockBtn">核验通过</button>
  24. <button class="clockBtn">核验不通过</button>
  25. </view>
  26. </view>
  27. </view>
  28. </template>
  29. <script setup>
  30. import {
  31. ref,
  32. onMounted
  33. } from 'vue';
  34. import {
  35. formateDate,
  36. isSameDay
  37. } from "@/common/util.js";
  38. import {
  39. setSignInfo,
  40. addSignInfo,
  41. getSignInfo,
  42. getInfo,
  43. key
  44. } from "./clockIn.js";
  45. // 定义响应式数据
  46. const moduleColor = ref('CBlue');
  47. const amSign = ref({
  48. time: "",
  49. address: "",
  50. remarks: "",
  51. img: ""
  52. });
  53. const time = ref(formateDate(new Date(), 'h:min:s'));
  54. const week = ref("");
  55. const latitude = ref("");
  56. const longitude = ref("");
  57. const address = ref("我的位置");
  58. const allSign = ref([]);
  59. const signInfo = ref({
  60. mode: "",
  61. latitude: "",
  62. longitude: "",
  63. address: "",
  64. time: "",
  65. remarks: ""
  66. });
  67. // 初始化页面数据
  68. const initializePage = async () => {
  69. const sign = getSignInfo();
  70. if (sign && sign.main) {
  71. const signA = [...sign.main].reverse();
  72. allSign.value = signA;
  73. // 检查当天是否已经签到
  74. checkIfSigned(signA);
  75. }
  76. await getLocation();
  77. getTime();
  78. getWeekDate();
  79. };
  80. // 检查当天是否已经签到
  81. const checkIfSigned = (signA) => {
  82. if (signA.length === 1 && isSameDay(signA[0].nowT)) {
  83. amSign.value = signA[0];
  84. } else if (signA.length > 1) {
  85. amSign.value = signA[1];
  86. }
  87. };
  88. // 获取星期几
  89. const getWeekDate = () => {
  90. const now = new Date();
  91. const weeks = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
  92. week.value = weeks[now.getDay()];
  93. };
  94. // 获取地址信息
  95. const getAdd = async () => {
  96. try {
  97. const res = await uni.request({
  98. url: `https://apis.map.qq.com/ws/geocoder/v1/?location=${latitude.value},${longitude.value}&key=${key}`,
  99. });
  100. const data = res.data;
  101. if (data.status !== 0) {
  102. throw new Error(data.message);
  103. }
  104. let addressStr = `${data.result.address} ${data.result.formatted_addresses.recommend}`;
  105. address.value = addressStr;
  106. signInfo.value.address = addressStr;
  107. } catch (error) {
  108. uni.showToast({
  109. title: error.message || "获取地址失败",
  110. icon: "none"
  111. });
  112. }
  113. };
  114. // 实时时间
  115. const getTime = async () => {
  116. setInterval(function () {
  117. time.value = formateDate(new Date(), 'h:min:s')
  118. }, 1000)
  119. };
  120. // 获取位置信息
  121. const getLocation = async () => {
  122. try {
  123. uni.showLoading({
  124. title: "获取中...",
  125. mask: true
  126. });
  127. const res = await uni.getLocation({
  128. type: 'gcj02'
  129. });
  130. uni.hideLoading();
  131. latitude.value = res.latitude;
  132. longitude.value = res.longitude;
  133. updateLocation(res.latitude, res.longitude);
  134. } catch (error) {
  135. uni.hideLoading();
  136. address.value = "请检查位置信息";
  137. uni.showToast({
  138. title: "请检查位置信息状态!",
  139. icon: "none",
  140. mask: true,
  141. duration: 3000
  142. });
  143. }
  144. };
  145. // 更新位置信息
  146. const updateLocation = (lat, lng) => {
  147. signInfo.value.latitude = lat;
  148. signInfo.value.longitude = lng;
  149. getAdd();
  150. };
  151. // 打卡操作
  152. const clickSign = async () => {
  153. try {
  154. await getLocation(); // 再次获取数据
  155. uni.showLoading({
  156. title: "打卡记录中...",
  157. mask: true
  158. });
  159. signInfo.value.time = formateDate(new Date(), 'Y-M-D h:min:s');
  160. const a = getSignInfo();
  161. if (a) {
  162. addSignInfo(getInfo(signInfo.value), a);
  163. } else {
  164. setSignInfo(getInfo(signInfo.value));
  165. }
  166. const updatedSign = getSignInfo().main.reverse();
  167. allSign.value = updatedSign;
  168. amSign.value = updatedSign[0];
  169. uni.showToast({
  170. title: "打卡成功!"
  171. });
  172. } catch (error) {
  173. uni.showToast({
  174. title: "打卡失败,请稍后再试!",
  175. icon: "none",
  176. mask: true
  177. });
  178. } finally {
  179. uni.hideLoading();
  180. }
  181. };
  182. // 初始化页面
  183. onMounted(() => {
  184. initializePage();
  185. });
  186. </script>
  187. <style lang="scss" scoped>
  188. .module {
  189. overflow: hidden;
  190. margin: 20upx auto;
  191. width: 320upx;
  192. height: 320upx;
  193. border-radius: 50%;
  194. color: #fff;
  195. text-align: center;
  196. }
  197. .sign-box{
  198. margin-top: 40rpx;
  199. }
  200. .module .text {
  201. font-size: 20px;
  202. margin: 100upx auto 10upx;
  203. }
  204. .CBlue {
  205. background-color: #3E7CF7;
  206. box-shadow: 0 3px 3px #3E7CF7;
  207. }
  208. .CAsh {
  209. background-color: #C8C7CC;
  210. box-shadow: 0 3px 3px #C8C7CC;
  211. }
  212. .colorRed {
  213. color: red;
  214. text-align: center;
  215. }
  216. .sign-info{
  217. text-align: center;
  218. color: #747474;
  219. line-height: 60rpx;
  220. }
  221. .picture-box{
  222. margin-top: 40rpx;
  223. .picture-btn {
  224. width: 44%;
  225. height: 70rpx;
  226. line-height: 70rpx;
  227. border-radius: 10rpx;
  228. background-color: #1E5FDF;
  229. color: #fff;
  230. font-size: 28rpx;
  231. text-align: center;
  232. }
  233. .picture-show{
  234. margin: 40rpx 0 20rpx;
  235. text-align: center;
  236. }
  237. }
  238. .button-container {
  239. position: fixed;
  240. bottom: 0;
  241. background-color: #ffffff;
  242. width: 100vw;
  243. padding: 40rpx 0;
  244. .button-pad{
  245. padding: 0 40rpx;
  246. display: flex;
  247. justify-content: space-between;
  248. }
  249. .clockBtn{
  250. width: 44%;
  251. height: 70rpx;
  252. line-height: 70rpx;
  253. border-radius: 10rpx;
  254. background-color: #1E5FDF;
  255. color: #fff;
  256. font-size: 28rpx;
  257. text-align: center;
  258. }
  259. }
  260. </style>