index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. <template>
  2. <main-layout>
  3. <!-- 用户信息区 -->
  4. <view class="user-info">
  5. <span class="nickname" v-if="!userInfoStore.isLogin" @click="goUserInfoPage">登录</span>
  6. <view class="user-icon" v-if="userInfoStore.isLogin">
  7. <uni-icons type="person" size="30"></uni-icons>
  8. </view>
  9. <span class="nickname" v-if="userInfoStore.isLogin" @click="goUserInfoPage">{{ userInfoStore.nickname
  10. }}</span>
  11. <span class="user-btn" v-if="userInfoStore.isLogin" @click="goUserInfoPage">用户中心</span>
  12. </view>
  13. <!-- 结算 -->
  14. <view class="settle-container">
  15. <!-- 刮刮乐、奖励数相关区域 -->
  16. <view class="left-box">
  17. <view class="split-box">
  18. <view class="line-box">
  19. <span>投入</span>
  20. <span class="number-box" @click="addScratchRecord(SCRATCH_ACTION_TYPE_INVEST)">
  21. ¥{{ userInfo.lotteryInvestAmount }}
  22. <uni-icons type="compose" color="#FFFFFF"></uni-icons>
  23. </span>
  24. </view>
  25. <view class="under-line-box">
  26. <span>中奖</span>
  27. <span class="number-box" @click="addScratchRecord(SCRATCH_ACTION_TYPE_WIN)">
  28. ¥{{ userInfo.lotteryWinAmount }}
  29. <uni-icons type="compose" color="#FFFFFF"></uni-icons>
  30. </span>
  31. </view>
  32. </view>
  33. <view class="split-box">
  34. <view class="line-box">
  35. <span>已领取</span>
  36. <span class="number-box">{{ userInfo.claimedRewardNum }}</span>
  37. </view>
  38. <view class="under-line-box">
  39. <span>总奖励</span>
  40. <span class="number-box">{{ userInfo.totalRewardNum }}</span>
  41. </view>
  42. </view>
  43. </view>
  44. <!-- 待领取奖励区 -->
  45. <view class="right-box">
  46. <view class="reward-title">待领取奖励数</view>
  47. <view class="reward-num">{{ userInfo.unclaimedRewardNum }}</view>
  48. <view class="reward-btn-group">
  49. <view class="reward-btn reward-btn-left" @click="claimReward('all')">全部领取</view>
  50. <view class="reward-btn reward-btn-right" @click="claimReward('part')">部分领取</view>
  51. </view>
  52. </view>
  53. <!-- 刷新按钮 -->
  54. <view class="refresh-btn" @click="getUserInfo">
  55. <uni-icons type="refreshempty" color="#406CE7"></uni-icons>
  56. </view>
  57. </view>
  58. <!-- 打卡任务 -->
  59. <view class="task-container">
  60. <view class="task-header">
  61. <view class="task-title" v-if="punchIns.length && punchIns.length > 0">任务({{ punchIns.length }}个)
  62. </view>
  63. <view class="task-title" v-else>任务</view>
  64. <view class="task-add-btn" @click="goPunchInEditPage">
  65. <uni-icons type="plusempty" size="30" color="#406CE7"></uni-icons>
  66. </view>
  67. </view>
  68. <view class="task-item" v-for="punchIn in punchIns" :key="punchIn.punchInId">
  69. <view class="main-box" @click="goPunchInDetailPage(punchIn.punchInId)">
  70. <view class="item-header">
  71. <span class="item-title">{{ punchIn.taskName }}</span>
  72. <span class="item-reward">x{{ punchIn.rewardNum }}</span>
  73. <view class="item-tag" v-if="punchIn.fullAttendanceFlag">全勤奖励</view>
  74. <view class="item-tag" v-if="punchIn.weekendDoubleFlag">周末双倍</view>
  75. </view>
  76. <view class="item-desc" v-if="punchIn.category == 1 || punchIn.category == 2">
  77. <span v-if="punchIn.category == 1">规则:打卡次数</span>
  78. <span v-if="punchIn.category == 2">规则:计时时间</span>
  79. <dict-item :dictCode="dictConst.PUNCH_IN_RULE" :itemCode="punchIn.rule"></dict-item>
  80. <span v-if="punchIn.category == 1">{{ punchIn.countTrack }}次</span>
  81. <span v-if="punchIn.category == 2">{{ punchIn.timeTrack.slice(0, 5) }}</span>
  82. </view>
  83. <view class="item-desc">
  84. 描述:{{ punchIn.description }}
  85. </view>
  86. <view class="item-detail-list">
  87. <view class="item-detail" v-for="punchInRecord in punchIn.punchInRecords"
  88. :key="punchInRecord.punchInDate">
  89. <view class="detail-text">
  90. <uni-dateformat :date="punchInRecord.punchInDate" format="M/d"></uni-dateformat>
  91. </view>
  92. <view class="detail-box" style="background-color: #E5E5E5;"
  93. v-if="punchInRecord.punchInStatus == 'uncreated'"></view>
  94. <view class="detail-box" style="background-color: #A5D63F;"
  95. v-if="punchInRecord.punchInStatus == 'punchIn'"></view>
  96. <view class="detail-box" style="background-color: #D43030;"
  97. v-if="punchInRecord.punchInStatus == 'unPunchIn'"></view>
  98. <view class="detail-box"
  99. v-if="punchInRecord.punchInStatus == 'futureTime' || punchInRecord.punchInStatus == 'todayUnknown'">
  100. </view>
  101. </view>
  102. </view>
  103. </view>
  104. <view
  105. :class="punchIn.punchInStatus == 'punchIn' ? 'func-box func-box-finish' : 'func-box func-box-unfinish'"
  106. v-if="punchIn.category == 0" @click="doPunchIn(punchIn.punchInId)">
  107. <span
  108. v-if="punchIn.punchInStatus == 'unPunchIn' || punchIn.punchInStatus == 'todayUnknown'">打卡</span>
  109. <span v-else>已完成</span>
  110. </view>
  111. <view
  112. :class="punchIn.punchInStatus == 'punchIn' ? 'func-box func-box-finish' : 'func-box func-box-unfinish'"
  113. v-if="punchIn.category == 1" @click="doPunchIn(punchIn.punchInId)">
  114. <span>{{ punchIn.recordCountTrack }}</span>
  115. <span>计数</span>
  116. </view>
  117. <view
  118. :class="punchIn.punchInStatus == 'punchIn' ? 'func-box func-box-finish' : 'func-box func-box-unfinish'"
  119. v-if="punchIn.category == 2" @click="doPunchInForTimeTrack(punchIn.punchInId, punchIn.timeTrack)">
  120. <span>
  121. {{ punchIn.recordTimeTrack.slice(0, 5) }}
  122. </span>
  123. <span>计时</span>
  124. </view>
  125. </view>
  126. <uni-load-more status="no-more" v-if="!punchIns || punchIns.length == 0" />
  127. </view>
  128. <!-- 刮刮乐弹出框 -->
  129. <uni-popup ref="scratchInputDialog" type="dialog" :is-mask-click="false">
  130. <uni-popup-dialog mode="input" :before-close="true"
  131. :title="scratchFormData.actionType == SCRATCH_ACTION_TYPE_INVEST ? '投入金额' : '中奖金额'" confirmText="保存"
  132. @confirm="scratchFormConfirm" @close="scratchFormClose">
  133. <view style="width: 100%;">
  134. <uni-forms ref="scratchForm" :modelValue="scratchFormData" :rules="scratchFormRules"
  135. label-position="top" :label-width="150">
  136. <uni-forms-item label="刮刮乐来源" name="source" required>
  137. <uni-data-select :localdata="dictStore.LOTTERY_SCRATCH_SOURCE"
  138. v-model="scratchFormData.source"></uni-data-select>
  139. </uni-forms-item>
  140. <uni-forms-item label="刮刮乐种类" name="category" required>
  141. <uni-data-select :localdata="dictStore[scratchFormData.source]"
  142. v-model="scratchFormData.category"></uni-data-select>
  143. </uni-forms-item>
  144. <uni-forms-item
  145. :label="scratchFormData.actionType == SCRATCH_ACTION_TYPE_INVEST ? '投入金额' : '中奖金额'"
  146. name="amount" required>
  147. <uni-easyinput type="digit" placeholder="请输入金额"
  148. v-model="scratchFormData.amount"></uni-easyinput>
  149. </uni-forms-item>
  150. </uni-forms>
  151. </view>
  152. </uni-popup-dialog>
  153. </uni-popup>
  154. <!-- 领取奖励弹出框 -->
  155. <uni-popup ref="claimRewardInputDialog" type="dialog" :is-mask-click="false">
  156. <uni-popup-dialog mode="input" :before-close="true" title="领取奖励" confirmText="领取"
  157. @confirm="claimRewardFormConfirm" @close="claimRewardFormClose">
  158. <view style="width: 100%;">
  159. <uni-forms ref="claimRewardForm" :modelValue="claimRewardFormData" :rules="claimRewardFormRules"
  160. label-position="top" :label-width="150">
  161. <uni-forms-item name="claimRewardNum">
  162. <uni-easyinput type="digit" placeholder="请输入领取的奖励数"
  163. v-model="claimRewardFormData.claimRewardNum"></uni-easyinput>
  164. </uni-forms-item>
  165. </uni-forms>
  166. </view>
  167. </uni-popup-dialog>
  168. </uni-popup>
  169. <!-- 计时弹出框 -->
  170. <uni-popup ref="timeTrackInputDialog" type="dialog" :is-mask-click="false">
  171. <uni-popup-dialog mode="input" :before-close="true" title="计时记录" confirmText="保存"
  172. @confirm="timeTrackFormConfirm" @close="timeTrackFormClose">
  173. <view class="pick-box" @click="timeTrackClick">
  174. <picker mode="time" :value="timeTrackFormData.timeTrack" @change="timeTrackChange">
  175. <view class="pick-box-time">{{ timeTrackFormData.timeTrack }}</view>
  176. </picker>
  177. </view>
  178. <view style="display: none;">
  179. <uni-forms ref="timeTrackForm" :modelValue="timeTrackFormData" :rules="timeTrackFormRules">
  180. <uni-forms-item name="timeTrack">
  181. <uni-easyinput v-model="timeTrackFormData.timeTrack" />
  182. </uni-forms-item>
  183. </uni-forms>
  184. </view>
  185. </uni-popup-dialog>
  186. </uni-popup>
  187. </main-layout>
  188. </template>
  189. <script setup>
  190. import { ref } from 'vue';
  191. import { onPullDownRefresh, onShow } from "@dcloudio/uni-app";
  192. import { rewardApi, punchInApi, userApi, scratchApi } from '@/service/apis.js';
  193. import router from '@/common/constants/router.js';
  194. import { SCRATCH_ACTION_TYPE_INVEST, SCRATCH_ACTION_TYPE_WIN } from '@/common/constants/scratch';
  195. import { useUserInfoStore } from '@/stores/userInfo.js';
  196. import { useDictStore } from '@/stores/dict';
  197. import dictConst from '@/common/constants/dict.js';
  198. // 组件
  199. /**
  200. * 刮刮乐弹出框
  201. */
  202. const scratchInputDialog = ref(null);
  203. /**
  204. * 刮刮乐表单
  205. */
  206. const scratchForm = ref(null);
  207. /**
  208. * 领取奖励弹出框
  209. */
  210. const claimRewardInputDialog = ref(null);
  211. /**
  212. * 领取奖励表单
  213. */
  214. const claimRewardForm = ref(null);
  215. /**
  216. * 计时弹出框
  217. */
  218. const timeTrackInputDialog = ref(null);
  219. /**
  220. * 计时表单
  221. */
  222. const timeTrackForm = ref(null);
  223. // 属性
  224. /**
  225. * 字典信息
  226. */
  227. const dictStore = useDictStore();
  228. /**
  229. * 用户信息
  230. */
  231. const userInfoStore = useUserInfoStore();
  232. /**
  233. * 用户信息
  234. */
  235. const userInfo = ref({
  236. totalRewardNum: 0,
  237. unclaimedRewardNum: 0,
  238. claimedRewardNum: 0,
  239. lotteryInvestAmount: 0.00,
  240. lotteryWinAmount: 0.00
  241. });
  242. /**
  243. * 打卡任务
  244. */
  245. const punchIns = ref([]);
  246. /**
  247. * 刮刮乐表单数
  248. */
  249. const scratchFormData = ref({});
  250. /**
  251. * 刮刮乐表单校验规则
  252. */
  253. const scratchFormRules = ref({
  254. "source": {
  255. rules: [{
  256. required: true,
  257. errorMessage: "请选择来源"
  258. }]
  259. },
  260. "category": {
  261. rules: [{
  262. required: true,
  263. errorMessage: "请选择种类"
  264. }]
  265. },
  266. "amount": {
  267. rules: [{
  268. required: true,
  269. errorMessage: "请输入金额"
  270. }, {
  271. format: 'number',
  272. errorMessage: "请输入有效数字"
  273. }, {
  274. minimum: 0.01,
  275. errorMessage: "最小{minimum}元"
  276. }]
  277. }
  278. });
  279. /**
  280. * 领取奖励表单数据
  281. */
  282. const claimRewardFormData = ref({
  283. claimRewardNum: 1
  284. });
  285. /**
  286. * 领取奖励表单规则
  287. */
  288. const claimRewardFormRules = ref({
  289. claimRewardNum: {
  290. rules: [{
  291. required: true,
  292. errorMessage: "请输入领取的奖励数"
  293. }, {
  294. format: 'number',
  295. errorMessage: "请输入有效数字"
  296. }, {
  297. minimum: 1,
  298. errorMessage: "最少领取{minimum}个"
  299. }]
  300. }
  301. });
  302. /**
  303. * 计时表单数据
  304. */
  305. const timeTrackFormData = ref({
  306. timeTrack: '00:00'
  307. });
  308. /**
  309. * 计时表单规则
  310. */
  311. const timeTrackFormRules = ref({
  312. timeTrack: {
  313. rules: [{
  314. required: true,
  315. errorMessage: "请输入时间"
  316. }]
  317. }
  318. });
  319. // 方法
  320. /**
  321. * 获取用户信息
  322. */
  323. const getUserInfo = async () => {
  324. let res = await userApi.queryUserInfo();
  325. userInfo.value = res;
  326. }
  327. /**
  328. * 获取打卡
  329. */
  330. const getPunchIns = async () => {
  331. let res = await punchInApi.queryPunchIns();
  332. punchIns.value = res;
  333. }
  334. /**
  335. * 增加刮刮乐记录
  336. */
  337. const addScratchRecord = async (e) => {
  338. // 重置上一轮的表单数据
  339. scratchFormData.value = {
  340. actionType: e
  341. };
  342. scratchInputDialog.value.open();
  343. }
  344. /**
  345. * 刮刮乐表单提交
  346. */
  347. const scratchFormConfirm = async () => {
  348. scratchForm.value.validate(['actionType']).then(data => {
  349. return scratchApi.addScratchRecord(data);
  350. }).then(e => {
  351. scratchInputDialog.value.close();
  352. getUserInfo();
  353. });
  354. }
  355. /**
  356. * 刮刮乐表单取消
  357. */
  358. const scratchFormClose = async () => {
  359. scratchInputDialog.value.close();
  360. }
  361. /**
  362. * 领取奖励(部分)
  363. * @param {String} claimType 部分领取或全部领取(part-部分/all-全部)
  364. */
  365. const claimReward = (claimType) => {
  366. if (userInfo.value.unclaimedRewardNum == 0) {
  367. uni.showToast({
  368. title: "没有可领取的奖励",
  369. icon: "none"
  370. });
  371. return;
  372. }
  373. // 重置上一轮的表单数据
  374. claimRewardFormData.value = {
  375. claimRewardNum: claimType == 'part' ? 1 : userInfo.value.unclaimedRewardNum
  376. };
  377. claimRewardInputDialog.value.open();
  378. }
  379. /**
  380. * 领取奖励表单提交
  381. */
  382. const claimRewardFormConfirm = async () => {
  383. claimRewardForm.value.validate().then(data => {
  384. return rewardApi.claimReward(data);
  385. }).then(e => {
  386. claimRewardInputDialog.value.close();
  387. getUserInfo();
  388. });
  389. }
  390. /**
  391. * 领取奖励表单取消
  392. */
  393. const claimRewardFormClose = async () => {
  394. claimRewardInputDialog.value.close();
  395. }
  396. /**
  397. * 确认领取奖励
  398. */
  399. const claimRewardConfirm = async (val) => {
  400. await rewardApi.claimReward({
  401. "claimRewardNum": val
  402. });
  403. // getReward();
  404. claimRewardDialog.value.close();
  405. }
  406. /**
  407. * 计时时间选择监听
  408. */
  409. const timeTrackChange = (e) => {
  410. timeTrackFormData.value.timeTrack = e.detail.value;
  411. }
  412. /**
  413. * 打卡(计时)
  414. */
  415. const doPunchInForTimeTrack = (id, timeTrack) => {
  416. // 重置上一轮的表单数据
  417. timeTrackFormData.value = {
  418. id,
  419. timeTrack: timeTrack ? timeTrack.slice(0, 5) : '00:00'
  420. };
  421. timeTrackInputDialog.value.open();
  422. }
  423. /**
  424. * 计时表单提交
  425. */
  426. const timeTrackFormConfirm = async () => {
  427. timeTrackForm.value.validate(['id']).then(data => {
  428. return punchInApi.doPunchIn(data);
  429. }).then(e => {
  430. timeTrackInputDialog.value.close();
  431. getPunchIns();
  432. });
  433. }
  434. /**
  435. * 刮刮乐表单取消
  436. */
  437. const timeTrackFormClose = async () => {
  438. timeTrackInputDialog.value.close();
  439. }
  440. /**
  441. * 打卡
  442. */
  443. const doPunchIn = async (id) => {
  444. await punchInApi.doPunchIn({
  445. id
  446. });
  447. getPunchIns();
  448. }
  449. /**
  450. * 跳转用户用心
  451. */
  452. const goUserInfoPage = () => {
  453. uni.navigateTo({
  454. url: router.USER_INFO_URL
  455. });
  456. }
  457. /**
  458. * 跳转打卡编辑页面
  459. */
  460. const goPunchInEditPage = () => {
  461. uni.navigateTo({
  462. url: router.PUNCHIN_EDIT_URL
  463. });
  464. };
  465. /**
  466. * 跳转打卡详情页面
  467. */
  468. const goPunchInDetailPage = (id) => {
  469. uni.navigateTo({
  470. url: router.PUNCHIN_DETAIL_URL + "?id=" + id
  471. });
  472. };
  473. /**
  474. * 加载数据
  475. */
  476. const loadData = async () => {
  477. // 如果还没登录就结束获取数据
  478. if (!userInfoStore.isLogin) {
  479. userInfo.value = {
  480. totalRewardNum: 0,
  481. unclaimedRewardNum: 0,
  482. claimedRewardNum: 0,
  483. lotteryInvestAmount: 0.00,
  484. lotteryWinAmount: 0.00
  485. };
  486. punchIns.value = [];
  487. return;
  488. }
  489. // 已登录
  490. // isLogin.value = true;
  491. try {
  492. uni.showLoading({
  493. title: '加载中',
  494. mask: true
  495. });
  496. // 获取用户信息
  497. getUserInfo();
  498. // 获取打卡
  499. getPunchIns();
  500. } finally {
  501. uni.hideLoading();
  502. }
  503. };
  504. onShow(() => {
  505. loadData();
  506. });
  507. onPullDownRefresh(() => {
  508. loadData();
  509. uni.stopPullDownRefresh();
  510. });
  511. </script>
  512. <style lang="scss" scoped>
  513. .user-info {
  514. display: flex;
  515. align-items: center;
  516. position: relative;
  517. .user-icon {
  518. display: inline-flex !important;
  519. width: 72rpx;
  520. height: 72rpx;
  521. background: #FFFFFF;
  522. border-radius: 50%;
  523. justify-content: center;
  524. align-items: center;
  525. }
  526. .nickname {
  527. margin-left: 16rpx;
  528. font-size: 24rpx;
  529. font-weight: 400;
  530. letter-spacing: 0rpx;
  531. line-height: 34.75rpx;
  532. color: #000000;
  533. }
  534. .user-btn {
  535. position: absolute;
  536. right: 0px;
  537. width: 122rpx;
  538. height: 40rpx;
  539. opacity: 1;
  540. border-radius: 24rpx;
  541. background: #FFFFFF;
  542. border: 1px solid #406CE7;
  543. /** 文本1 */
  544. font-size: 18rpx;
  545. font-weight: 400;
  546. letter-spacing: 0rpx;
  547. line-height: 26.06rpx;
  548. color: #406CE7;
  549. display: flex;
  550. align-items: center;
  551. justify-content: center;
  552. }
  553. }
  554. .settle-container {
  555. margin-top: 16rpx;
  556. display: flex;
  557. padding: 16rpx 24rpx;
  558. height: 266rpx;
  559. opacity: 1;
  560. background: #406CE7;
  561. border-radius: 21.35rpx;
  562. border: 0.5px solid #E4E4E4;
  563. box-shadow: 0px 1px 6px #D8D8D8;
  564. position: relative;
  565. .left-box {
  566. flex: 1;
  567. display: flex;
  568. flex-direction: column;
  569. border-right: 1px solid #FFFFFF;
  570. padding-right: 24rpx;
  571. font-size: 22rpx;
  572. font-weight: 400;
  573. letter-spacing: 0rpx;
  574. line-height: 31.86rpx;
  575. color: #FFFFFF;
  576. .line-box {
  577. padding-bottom: 16rpx;
  578. border-bottom: 1px solid #FFFFFF;
  579. position: relative;
  580. }
  581. .under-line-box {
  582. padding-top: 16rpx;
  583. position: relative;
  584. }
  585. .number-box {
  586. position: absolute;
  587. right: 0px;
  588. text-align: right;
  589. }
  590. .split-box {
  591. flex: 1;
  592. display: flex;
  593. justify-content: center;
  594. align-content: center;
  595. flex-direction: column;
  596. }
  597. }
  598. .right-box {
  599. flex: 2;
  600. display: flex;
  601. flex-direction: column;
  602. align-items: center;
  603. .reward-title {
  604. font-size: 26rpx;
  605. font-weight: 400;
  606. letter-spacing: 0rpx;
  607. line-height: 37.65rpx;
  608. color: #FFFFFF;
  609. }
  610. .reward-num {
  611. flex-grow: 1;
  612. font-size: 110rpx;
  613. font-weight: 700;
  614. letter-spacing: 0rpx;
  615. color: #FFFFFF;
  616. display: flex;
  617. align-items: center;
  618. justify-content: center;
  619. }
  620. .reward-btn-group {
  621. width: 100%;
  622. height: 36rpx;
  623. display: flex;
  624. align-items: center;
  625. justify-content: center;
  626. .reward-btn {
  627. display: flex;
  628. justify-content: center;
  629. align-items: center;
  630. width: 108rpx;
  631. height: 36rpx;
  632. opacity: 1;
  633. background: #FFFFFF;
  634. font-size: 20rpx;
  635. font-weight: 700;
  636. letter-spacing: 0rpx;
  637. line-height: 28.96rpx;
  638. color: #406CE7;
  639. }
  640. .reward-btn-left {
  641. border-radius: 24rpx 0rpx 0rpx 24rpx;
  642. }
  643. .reward-btn-right {
  644. border-radius: 0rpx 24rpx 24rpx 0rpx;
  645. }
  646. }
  647. }
  648. .refresh-btn {
  649. position: absolute;
  650. top: 16rpx;
  651. right: 24rpx;
  652. border-radius: 50%;
  653. width: 36rpx;
  654. height: 36rpx;
  655. opacity: 1;
  656. background: #F7F7F7;
  657. display: flex;
  658. justify-content: center;
  659. align-items: center;
  660. }
  661. }
  662. .task-container {
  663. margin-top: 16rpx;
  664. .task-header {
  665. position: relative;
  666. height: 80rpx;
  667. display: flex;
  668. justify-content: center;
  669. /* 水平居中 */
  670. align-items: center;
  671. /* 垂直居中 */
  672. .task-title {
  673. position: absolute;
  674. left: 0rpx;
  675. font-size: 30rpx;
  676. font-weight: 400;
  677. line-height: 43.44rpx;
  678. color: rgba(0, 0, 0, 1);
  679. }
  680. .task-add-btn {
  681. display: inline-flex;
  682. justify-content: center;
  683. align-items: center;
  684. position: absolute;
  685. right: 0rpx;
  686. width: 60rpx;
  687. height: 60rpx;
  688. border-radius: 10rpx;
  689. border: 3px solid rgba(64, 108, 231, 1);
  690. }
  691. }
  692. .task-item {
  693. margin-top: 16rpx;
  694. width: 100%;
  695. // height: 239rpx;
  696. border-radius: 24rpx;
  697. background: #FFFFFF;
  698. border: 0.5px solid #E4E4E4;
  699. box-shadow: 0px 1px 6px #D8D8D8;
  700. display: flex;
  701. .main-box {
  702. flex-grow: 1;
  703. padding: 16rpx 16rpx 16rpx 24rpx;
  704. .item-header {
  705. // position: relative;
  706. display: flex;
  707. align-items: center;
  708. .item-title {
  709. font-size: 30rpx;
  710. font-weight: 400;
  711. letter-spacing: 0rpx;
  712. line-height: 43.44rpx;
  713. color: #000000;
  714. }
  715. .item-reward {
  716. margin-left: 8rpx;
  717. font-size: 24rpx;
  718. font-weight: 400;
  719. letter-spacing: 0rpx;
  720. line-height: 34.75rpx;
  721. color: #000000;
  722. }
  723. .item-tag:first-child {
  724. margin-left: 24rpx;
  725. }
  726. .item-tag {
  727. margin-left: 16rpx;
  728. width: 94rpx;
  729. height: 38rpx;
  730. opacity: 1;
  731. border-radius: 24rpx;
  732. background: #FFFFFF;
  733. border: 1px solid #406CE7;
  734. display: inline-flex;
  735. justify-content: center;
  736. align-items: center;
  737. font-size: 18rpx;
  738. font-weight: 400;
  739. letter-spacing: 0rpx;
  740. // line-height: 26.06rpx;
  741. color: #406CE7;
  742. }
  743. .item-btn {
  744. display: inline-flex;
  745. position: absolute;
  746. right: 0rpx;
  747. width: 123rpx;
  748. height: 42rpx;
  749. border-radius: 30rpx;
  750. border: 1rpx solid #2A82E4;
  751. justify-content: center;
  752. align-items: center;
  753. font-size: 20rpx;
  754. font-weight: 400;
  755. line-height: 28.96px;
  756. color: rgba(64, 108, 231, 1);
  757. }
  758. }
  759. .item-desc {
  760. margin-top: 16rpx;
  761. font-size: 24rpx;
  762. font-weight: 400;
  763. letter-spacing: 0rpx;
  764. line-height: 34.75rpx;
  765. color: #000000;
  766. }
  767. .item-detail-list {
  768. margin-top: 16rpx;
  769. display: grid;
  770. grid-template-columns: repeat(7, 1fr);
  771. .item-detail {
  772. display: flex;
  773. flex-direction: column;
  774. justify-content: center;
  775. align-items: center;
  776. .detail-text {
  777. font-size: 20rpx;
  778. font-weight: 400;
  779. letter-spacing: 0rpx;
  780. line-height: 28.96rpx;
  781. color: rgba(0, 0, 0, 1);
  782. }
  783. .detail-box {
  784. // display: block;
  785. width: 42rpx;
  786. height: 42rpx;
  787. margin-top: 5rpx;
  788. border: 5rpx solid #000000;
  789. }
  790. }
  791. }
  792. }
  793. .func-box {
  794. flex-shrink: 0;
  795. width: 160rpx;
  796. border-radius: 0rpx 24rpx 24rpx 0rpx;
  797. font-size: 36rpx;
  798. font-weight: 400;
  799. letter-spacing: 0rpx;
  800. line-height: 52.13rpx;
  801. color: #FFFFFF;
  802. display: flex;
  803. justify-content: center;
  804. align-items: center;
  805. flex-direction: column;
  806. }
  807. .func-box-finish {
  808. background: #F2607A;
  809. }
  810. .func-box-unfinish {
  811. background: #406CE7;
  812. }
  813. }
  814. }
  815. .pick-box {
  816. width: 100%;
  817. height: 100rpx;
  818. border-radius: 8px;
  819. background: #ffffff;
  820. // 阴影
  821. border: 0.5px solid #e4e4e4;
  822. picker {
  823. width: 100%;
  824. height: 100%;
  825. .pick-box-time {
  826. width: 100%;
  827. height: 100rpx;
  828. display: flex;
  829. align-items: center;
  830. justify-content: center;
  831. color: #000000;
  832. border-radius: 24rpx;
  833. text-align: center;
  834. }
  835. }
  836. }
  837. </style>