signIn.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. <template>
  2. <view class="sign-in">
  3. <view class="signin-btn-con">
  4. <div class="circle-box">
  5. <div class="cricle" @click="signIn()">
  6. <span v-if="!ifSign" :class="{ active: signFlag || ifSign }">签到</span>
  7. <span v-else :class="{ active: signFlag || ifSign }" :style="ifSign ? 'transform: rotateY(0deg);' : ''">已签</span>
  8. </div>
  9. </div>
  10. <text class="tips">坚持每天连续签到可以获多重奖励哦</text>
  11. </view>
  12. <div class="date-card">
  13. <view class="date-con">
  14. <view class="date-tit">
  15. <u-row style="width: 100%; justify-content: center;">
  16. <div style="text-align: center; " class="text">{{ currentMonth }} {{ currentYear }}</div>
  17. </u-row>
  18. </view>
  19. <view class="week">
  20. <text v-for="item in weekArr" :key="item.id">{{ item }}</text>
  21. </view>
  22. <view class="date" v-for="obj in dataObj" :key="obj.id">
  23. <view class="item" v-for="item in obj" :key="item.id" :class="item == '' ? 'hide' : ''" :animation="item == currentDay ? animationData : ''">
  24. <view class="just" :class="signArr.indexOf(item) != -1 ? 'active' : ''">
  25. <view class="top">{{ item }} </view>
  26. <view class="bottom">
  27. <u-icon name="error" v-if="item <= currentDay" color="#999"></u-icon>
  28. </view>
  29. </view>
  30. <view class="back" :class="signArr.indexOf(item) != -1 ? 'active' : ''" :style="
  31. signArr.indexOf(item) != -1 && ifSign
  32. ? 'transform: rotateY(0deg);'
  33. : signArr.indexOf(item) != -1 && item != currentDay
  34. ? 'transform: rotateY(0deg);'
  35. : ''
  36. ">
  37. <view class="top">{{ item }}</view>
  38. <view class="bottom">
  39. <u-icon name="checkmark" color="#ff9f28"></u-icon>
  40. </view>
  41. </view>
  42. </view>
  43. </view>
  44. </view>
  45. </div>
  46. <view class="mask" :class="{ show: maskFlag, trans: transFlag }" ref="mask">
  47. <view class="mask-header">
  48. <text class="close"></text>
  49. <text>签到成功</text>
  50. <text class="close" @click="close">×</text>
  51. </view>
  52. <view class="mask-con">
  53. <view class="keep-sign">
  54. 本月已连续签到
  55. <text>{{ continuity }}</text>
  56. </view>
  57. <u-icon size="120" style="margin: 50rpx 0" color="#ff9f28" name="checkmark"></u-icon>
  58. <view class="mark">
  59. <view>获得积分</view>
  60. <text>{{ continuityPoint }}</text>
  61. </view>
  62. <text class="text">连续签到可获得额外奖励哦!</text>
  63. </view>
  64. </view>
  65. </view>
  66. </template>
  67. <script>
  68. import { sign, signTime } from "@/api/point.js";
  69. export default {
  70. data() {
  71. return {
  72. continuity: 1, //本月连续签到天数
  73. continuityPoint: 2, //获得的积分
  74. signFlag: false,
  75. animationData: {},
  76. maskFlag: false, //
  77. transFlag: false, //动画
  78. weekArr: ["日", "一", "二", "三", "四", "五", "六"], //周数组
  79. dateArr: [], //每个月的天数
  80. monthArr: [
  81. //实例化每个月
  82. "1月",
  83. "2月",
  84. "3月",
  85. "4月",
  86. "5月",
  87. "6月",
  88. "7月",
  89. "8月",
  90. "9月",
  91. "10月",
  92. "11月",
  93. "12月",
  94. ], //今天一个月英文
  95. currentMonth: "", //当月
  96. currentMonthIndex: "", //当月
  97. currentYear: "", //今年
  98. currentDay: "", //今天
  99. currentWeek: "", //获取当月一号是周几
  100. dataObj: [], //一个月有多少天这个获取
  101. signArr: [], //本月签到过的天数 该参数用于请求接口后获取当月都哪天签到了
  102. signAll: [], //所有签到数据
  103. ifSign: false, //今天是否签到
  104. };
  105. },
  106. async onLoad() {
  107. //获取签到数据
  108. var response = await signTime(
  109. new Date().getFullYear() + "" + this.makeUp(new Date().getMonth() + 1)
  110. );
  111. this.signAll = response.data.result;
  112. //获取展示数据
  113. this.getDate();
  114. },
  115. methods: {
  116. /**
  117. * 补0
  118. */
  119. makeUp(val) {
  120. if (val >= 10) {
  121. return val;
  122. } else {
  123. return "0" + val;
  124. }
  125. },
  126. /**
  127. * 点击签到
  128. */
  129. async signIn() {
  130. await sign().then((response) => {
  131. if (this.ifSign) return;
  132. if (this.signFlag) return;
  133. if (response.data.code != 200) {
  134. uni.showToast({
  135. title: response.data.message,
  136. duration: 2000,
  137. icon: "none",
  138. });
  139. return false;
  140. }
  141. var that = this;
  142. var animation = uni.createAnimation({
  143. duration: 200,
  144. timingFunction: "linear",
  145. });
  146. this.signArr.push(this.currentDay);
  147. this.animation = animation;
  148. animation.rotateY(0).step();
  149. this.animationData = animation.export();
  150. setTimeout(
  151. function () {
  152. that.signFlag = true;
  153. this.maskFlag = true;
  154. this.ifSign = !this.ifSign;
  155. animation.rotateY(0).step();
  156. this.animationData = animation.export();
  157. }.bind(this),
  158. 200
  159. );
  160. });
  161. },
  162. /**
  163. * 签到成功后关闭弹窗
  164. */
  165. close() {
  166. var that = this;
  167. this.maskFlag = false;
  168. this.transFlag = true;
  169. setTimeout(() => {
  170. that.transFlag = false;
  171. }, 500);
  172. },
  173. /**
  174. * 获取今天时间
  175. *
  176. */
  177. getDate() {
  178. var date = new Date(),
  179. index = date.getMonth(),
  180. curDay = null;
  181. this.currentYear = date.getFullYear();
  182. this.currentMonth = this.monthArr[index];
  183. this.currentMonthIndex = index + 1;
  184. this.currentDay = date.getDate();
  185. if (this.currentDay == this.signArr[this.signArr.length - 1]) {
  186. this.ifSign = true;
  187. }
  188. curDay = this.getWeekByDay(this.currentYear + "-" + (index + 1) + "-1");
  189. this.getMonthDays(index, curDay);
  190. this.curentSignData();
  191. },
  192. /**
  193. * 获取当前已经签到的时间
  194. */
  195. curentSignData() {
  196. var date = new Date(),
  197. index = date.getMonth(),
  198. curDay = null;
  199. this.signArr = [];
  200. for (var i = 0; i < this.signAll.length; i++) {
  201. var item = this.signAll[i];
  202. item.createTime = item.createTime.split(" ")[0];
  203. var itemVal = item.createTime.split("-");
  204. if (
  205. Number(itemVal[0]) === Number(this.currentYear) &&
  206. Number(itemVal[1]) === Number(this.currentMonthIndex)
  207. ) {
  208. this.signArr.push(Number(itemVal[2]));
  209. }
  210. if (
  211. Number(itemVal[0]) === Number(date.getFullYear()) &&
  212. Number(itemVal[1]) === Number(index + 1) &&
  213. Number(itemVal[2]) === Number(date.getDate())
  214. ) {
  215. this.ifSign = true;
  216. }
  217. }
  218. },
  219. /**
  220. * 循环出当前月份的时间
  221. * 例子:
  222. * "","","","","","",1,
  223. * 2 ,3 ,4 ,5 ,6 ,7 ,8,
  224. * ...依次向下排
  225. */
  226. getMonthDays(index, day) {
  227. //day 当月1号是周几
  228. this.dateArr = [];
  229. this.dataObj = [];
  230. for (var i = 0; i < day; i++) {
  231. this.dateArr.push("");
  232. }
  233. if (
  234. index == 0 ||
  235. index == 2 ||
  236. index == 4 ||
  237. index == 6 ||
  238. index == 7 ||
  239. index == 9 ||
  240. index == 11
  241. ) {
  242. for (let i = 1; i < 32; i++) {
  243. this.dateArr.push(i);
  244. }
  245. }
  246. if (index == 3 || index == 5 || index == 8 || index == 10) {
  247. for (let i = 1; i < 31; i++) {
  248. this.dateArr.push(i);
  249. }
  250. }
  251. if (index == 1) {
  252. if (
  253. (this.currentYear % 4 == 0 && this.currentYear % 100 != 0) ||
  254. this.currentYear % 400 == 0
  255. ) {
  256. for (let i = 1; i < 30; i++) {
  257. this.dateArr.push(i);
  258. }
  259. } else {
  260. for (let i = 1; i < 29; i++) {
  261. this.dateArr.push(i);
  262. }
  263. }
  264. }
  265. for (var y = 0; y < 10; y++) {
  266. if (this.dateArr.length > 7) {
  267. this.dataObj.push(this.dateArr.splice(0, 7));
  268. } else {
  269. for (let i = 0; i < 7 - this.dateArr.length; i++) {
  270. this.dateArr.push("");
  271. }
  272. }
  273. }
  274. this.dataObj.push(this.dateArr);
  275. },
  276. /**
  277. * 获取当前月份有几周
  278. */
  279. getWeekByDay(dayValue) {
  280. var day = new Date(Date.parse(dayValue.replace(/-/g, "/"))).getDay(); //将日期值格式化
  281. return day;
  282. },
  283. },
  284. };
  285. </script>
  286. <style lang="scss" scoped>
  287. .date-card {
  288. padding: 0 40rpx;
  289. }
  290. .tips {
  291. margin-top: 34rpx;
  292. }
  293. .circle-box {
  294. width: 200rpx;
  295. height: 200rpx;
  296. border-radius: 50%;
  297. margin-top: 60rpx;
  298. background: #ff9f28;
  299. display: flex;
  300. justify-content: center; //这个是X轴居中
  301. align-items: center; //这个是 Y轴居中
  302. }
  303. .cricle {
  304. width: 160rpx;
  305. height: 160rpx;
  306. border-radius: 50%;
  307. background: #ff9f28;
  308. text-align: center;
  309. line-height: 160rpx;
  310. color: #fff;
  311. font-size: 40rpx;
  312. }
  313. page {
  314. background: #fff;
  315. }
  316. .sign-in {
  317. color: #333;
  318. .signin-btn-con {
  319. width: 100%;
  320. height: 670rpx;
  321. background-image: linear-gradient(180deg, #ff6b35, #ff9f28, #ffcc03);
  322. display: flex;
  323. flex-direction: column;
  324. align-items: center;
  325. text {
  326. color: #fff;
  327. font-size: 28rpx;
  328. font-weight: 400;
  329. }
  330. }
  331. .date-con {
  332. background: #fff;
  333. min-height: 730rpx;
  334. border-radius: 0.8em;
  335. border: 1px solid #ededed;
  336. padding: 0 28rpx;
  337. transform: translateY(-320rpx);
  338. box-shadow: (1px 3px 5px rgba(0, 0, 0, 0.2));
  339. }
  340. .date-tit {
  341. display: flex;
  342. justify-content: space-between;
  343. margin: 30rpx 0;
  344. }
  345. .week {
  346. display: flex;
  347. justify-content: space-between;
  348. color: #a6a6a6;
  349. font-size: 26rpx;
  350. text {
  351. width: 66rpx;
  352. text-align: center;
  353. }
  354. }
  355. .date {
  356. margin: 10rpx 0 36rpx;
  357. display: flex;
  358. justify-content: space-between;
  359. flex-wrap: wrap;
  360. .item {
  361. width: 66rpx;
  362. height: 80rpx;
  363. border-radius: 5px;
  364. overflow: hidden;
  365. position: relative;
  366. &.hide {
  367. opacity: 0;
  368. }
  369. .just,
  370. .back {
  371. display: flex;
  372. flex-direction: column;
  373. width: 100%;
  374. height: 100%;
  375. position: absolute;
  376. .top {
  377. position: relative;
  378. flex: 1;
  379. text-align: center;
  380. line-height: 40rpx;
  381. &:before {
  382. content: "";
  383. width: 40rpx;
  384. height: 40rpx;
  385. position: absolute;
  386. left: 50%;
  387. transform: translateX(-50%);
  388. top: 15rpx;
  389. }
  390. }
  391. }
  392. .just {
  393. &.active {
  394. display: none;
  395. }
  396. }
  397. .back {
  398. display: none;
  399. &.active {
  400. display: flex;
  401. }
  402. .top {
  403. color: #ff9f28;
  404. }
  405. }
  406. .bottom {
  407. color: #999;
  408. font-size: 20rpx;
  409. height: 20rpx;
  410. line-height: 20rpx;
  411. text-align: center;
  412. }
  413. }
  414. }
  415. .mask {
  416. position: fixed;
  417. top: 0;
  418. bottom: 0;
  419. left: -100%;
  420. right: 100%;
  421. background: rgba(0, 0, 0, 0.2);
  422. display: flex;
  423. flex-direction: column;
  424. justify-content: center;
  425. align-items: center;
  426. opacity: 0;
  427. transition: opacity 0.5s;
  428. &.show {
  429. opacity: 1;
  430. left: 0;
  431. right: 0;
  432. }
  433. &.trans {
  434. left: 0;
  435. right: 0;
  436. }
  437. .mask-header {
  438. width: 540rpx;
  439. height: 130rpx;
  440. line-height: 130rpx;
  441. background: #ff9f28;
  442. color: #fff;
  443. font-size: 40rpx;
  444. font-weight: 500;
  445. display: flex;
  446. justify-content: space-between;
  447. .close {
  448. width: 60rpx;
  449. font-size: 66rpx;
  450. font-weight: 400;
  451. line-height: 60rpx;
  452. }
  453. }
  454. .mask-con {
  455. width: 540rpx;
  456. height: 460rpx;
  457. background: #fff;
  458. display: flex;
  459. flex-direction: column;
  460. align-items: center;
  461. color: #999;
  462. font-size: 24rpx;
  463. border-radius: 0 0 9px 9px;
  464. .keep-sign {
  465. font-size: 30rpx;
  466. margin-top: 30rpx;
  467. text {
  468. font-size: 46rpx;
  469. font-weight: 500;
  470. color: #999;
  471. padding: 0 6rpx 0 8rpx;
  472. }
  473. }
  474. .mark {
  475. // flex: 1;
  476. display: flex;
  477. align-items: flex-end;
  478. position: relative;
  479. margin-bottom: 16rpx;
  480. text {
  481. margin-left: 4rpx;
  482. color: #999;
  483. }
  484. }
  485. .text {
  486. color: #6f6f6f;
  487. height: 90rpx;
  488. }
  489. }
  490. }
  491. }
  492. </style>