index.vue 21 KB

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