index2.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. <!--
  2. 成就 v2
  3. http://localhost:5173/card/#/pages/achievement/index2
  4. https://oss-mbh5.colormaprun.com/card/#/pages/achievement/index2
  5. -->
  6. <template>
  7. <view class="body">
  8. <view class="content uni-column">
  9. <view class="topbar uni-row">
  10. <view></view>
  11. <text>成就</text>
  12. <text style="color: rgba(46, 133, 236, 1);"></text>
  13. </view>
  14. <view class="tab uni-row">
  15. <text :class="tabCurrent == 0 ? 'tab-active boder-radius-left' : 'tab-unactive boder-solid-right'"
  16. @click="tabCurrent=0">挑战</text>
  17. <text :class="tabCurrent == 1 ? 'tab-active' : 'tab-unactive'" @click="tabCurrent=1">奖牌</text>
  18. <text :class="tabCurrent == 2 ? 'tab-active boder-radius-right' : 'tab-unactive boder-solid-left'"
  19. @click="tabCurrent=2">兑换</text>
  20. </view>
  21. <view class="main">
  22. <!-- 挑战 -->
  23. <view v-if="tabCurrent == 0">
  24. <view class="norecord" v-if="challengeRs == null || challengeRs.length == 0">暂无记录</view>
  25. <view class="uni-column" v-for="(item, index) in challengeRs" :key="index">
  26. <text class="year">{{item.year}}</text>
  27. <view class="list uni-row">
  28. <view class="item uni-column" v-for="(item2, index2) in item.monthRs" :key="index2">
  29. <view class="item-cup" :style="getCupStyle('cup', item2.month)">
  30. <view class="item-cup-gray"
  31. :style="getCupStyle('cup-gray', item2.month, getCupProgress(item2.targetNum, item2.realNum))">
  32. </view>
  33. </view>
  34. <view class="item-title uni-row">
  35. <text class="item-title-month">{{item2.month}}月</text>
  36. <view class="item-title-divide"></view>
  37. <text class="item-title-progress">{{item2.realNum}}/{{item2.targetNum}}</text>
  38. </view>
  39. </view>
  40. </view>
  41. </view>
  42. </view>
  43. <!-- 奖牌 -->
  44. <view v-if="tabCurrent == 1">
  45. <view class="norecord" v-if="activityRs == null || activityRs.length == 0">暂无记录</view>
  46. <view class="uni-column" v-for="(item, index) in activityRs" :key="index">
  47. <text class="year">{{item.year}}</text>
  48. <view class="list uni-row">
  49. <view class="item item-bg uni-column" v-for="(item2, index2) in item.aiRs" :key="index2"
  50. @click="showAchDetail(item2)">
  51. <view class="item-medal" :style="getMedalStyle(item2.iconUrl)"></view>
  52. <view class="item-title uni-column">
  53. <view class="item-title-ainame">{{item2.aiName}}</view>
  54. <view class="item-title-aitime">{{fmtTime(item2.aiTime)}}</view>
  55. </view>
  56. </view>
  57. </view>
  58. </view>
  59. </view>
  60. <!-- 兑换 -->
  61. <view v-if="tabCurrent == 2">
  62. <view class="norecord" v-if="exchangeRs == null || exchangeRs.length == 0">暂无记录</view>
  63. <view class="uni-column" v-for="(item, index) in exchangeRs" :key="index">
  64. <text class="year">{{item.year}}</text>
  65. <view class="list uni-row">
  66. <view class="item uni-column"
  67. :class="item2.exState==1 ? 'item-convertible' : 'item-converted'"
  68. v-for="(item2, index2) in item.aiRs" :key="index2" @click="showAchDetail(item2)">
  69. <view class="item-medal" :style="getMedalStyle(item2.iconUrl)"></view>
  70. <view class="item-title uni-column">
  71. <view class="item-title-ainame">{{item2.aiName}}</view>
  72. <view class="item-title-aitime">{{fmtTime(item2.aiTime)}}</view>
  73. </view>
  74. </view>
  75. </view>
  76. </view>
  77. </view>
  78. </view>
  79. </view>
  80. <!-- 页面载入后,弹窗显示新获取的成就 -->
  81. <my-popup ref="popupNewach" :dataList="popupDataList" @popup-close="onPopupNewachClose"></my-popup>
  82. <!-- 点击成就列表项后,弹窗显示对应的成就内容 -->
  83. <my-popup ref="popupAchdet" :dataList="popupAchdet" @popup-close="onPopupAchdetClose"></my-popup>
  84. <!-- <my-popup-map ref="mypopupmap" :point="point"></my-popup-map> -->
  85. </view>
  86. </template>
  87. <script>
  88. import tools from '../../common/tools';
  89. import {
  90. token,
  91. apiMonthlyChallengeQuery,
  92. apiAchievementQuery,
  93. apiExchangeListQuery,
  94. apiExchangeDetailQuery,
  95. apiUnReadMessageQuery,
  96. apiReadMessage,
  97. checkResCode
  98. } from '../../common/api';
  99. export default {
  100. data() {
  101. return {
  102. queryObj: {},
  103. queryString: "",
  104. token: "",
  105. tokenValid: false,
  106. challengeRs: [], // 挑战成就集合
  107. activityRs: [], // 活动成就集合
  108. exchangeRs: [], // 兑换记录集合
  109. unReadMessageRs: [], // 未读消息列表
  110. mqIdListStr: "", // 已读消息id列表 逗号分隔
  111. tabCurrent: 0,
  112. popupDataList: [], // 弹窗数据:新获取的成就
  113. popupAchdet: [], // 弹窗数据:用户点击的成就列表项
  114. point: {
  115. longitude: 117.022194,
  116. latitude: 36.661612,
  117. name: "泉城广场定向赛起始点",
  118. },
  119. interval: null,
  120. }
  121. },
  122. computed: {},
  123. onLoad(query) { // 类型非必填,可自动推导
  124. // console.log(query);
  125. this.queryObj = query;
  126. this.queryString = tools.objectToQueryString(this.queryObj);
  127. // console.log(queryString);
  128. this.token = query["token"] ?? token;
  129. this.getMonthlyChallengeQuery();
  130. this.getAchievementQuery();
  131. this.getExchangeListQuery();
  132. this.getUnReadMessageQuery();
  133. },
  134. // 页面初次渲染完成,此时组件已挂载完成,DOM 树($el)已可用
  135. onReady() {},
  136. onUnload() {
  137. if (this.interval != null) {
  138. clearInterval(this.interval);
  139. this.interval = null;
  140. }
  141. },
  142. methods: {
  143. getCupProgress(targetNum, realNum) {
  144. let cupProgress = 100;
  145. if (targetNum > 0 && realNum > 0) {
  146. if (realNum < targetNum) {
  147. const progress = realNum / targetNum * 100;
  148. cupProgress = 100 - progress;
  149. } else {
  150. cupProgress = 0;
  151. }
  152. }
  153. // console.log("cupProgress:", cupProgress);
  154. return cupProgress;
  155. },
  156. getCupStyle(type, month, cupProgress = 0) {
  157. if (!(month > 0)) {
  158. return '';
  159. }
  160. let group = 1;
  161. if (type == 'cup') {
  162. return `background-image: url("static/cup/${group}/${month}.png")`;
  163. } else if (type == 'cup-gray') {
  164. return `background-image: url("static/cup/${group}/${month}h.png"); height:${cupProgress}% ;`;
  165. }
  166. },
  167. getMedalStyle(bgurl) {
  168. return `background-image: url("${bgurl}")`;
  169. },
  170. fmtTime(timestamp, type = 2) {
  171. return tools.timestampToTime(timestamp * 1000, type);
  172. },
  173. // 玩家所有月挑战记录查询
  174. getMonthlyChallengeQuery() {
  175. uni.request({
  176. url: apiMonthlyChallengeQuery,
  177. header: {
  178. "Content-Type": "application/x-www-form-urlencoded",
  179. "token": this.token,
  180. },
  181. method: "POST",
  182. data: {},
  183. success: (res) => {
  184. // console.log("getMonthlyChallengeQuery", res);
  185. if (checkResCode(res)) {
  186. if (res.statusCode == 401) { // 未登录
  187. this.tokenValid = false;
  188. } else {
  189. this.tokenValid = true;
  190. }
  191. this.challengeRs = res.data.data;
  192. }
  193. },
  194. fail: (err) => {
  195. console.log("getMonthlyChallengeQuery err", err)
  196. },
  197. });
  198. },
  199. // 玩家活动成就查询
  200. getAchievementQuery() {
  201. uni.request({
  202. url: apiAchievementQuery,
  203. header: {
  204. "Content-Type": "application/x-www-form-urlencoded",
  205. "token": this.token,
  206. },
  207. method: "POST",
  208. data: {},
  209. success: (res) => {
  210. // console.log("getAchievementQuery", res);
  211. if (checkResCode(res)) {
  212. if (res.statusCode == 401) { // 未登录
  213. this.tokenValid = false;
  214. } else {
  215. this.tokenValid = true;
  216. }
  217. this.activityRs = res.data.data;
  218. }
  219. },
  220. fail: (err) => {
  221. console.log("getAchievementQuery err", err);
  222. },
  223. });
  224. },
  225. // 玩家兑换记录查询
  226. getExchangeListQuery() {
  227. uni.request({
  228. url: apiExchangeListQuery,
  229. header: {
  230. "Content-Type": "application/x-www-form-urlencoded",
  231. "token": this.token,
  232. },
  233. method: "POST",
  234. data: {},
  235. success: (res) => {
  236. // console.log("getExchangeListQuery", res);
  237. if (checkResCode(res)) {
  238. if (res.statusCode == 401) { // 未登录
  239. this.tokenValid = false;
  240. } else {
  241. this.tokenValid = true;
  242. }
  243. this.exchangeRs = res.data.data;
  244. }
  245. },
  246. fail: (err) => {
  247. console.log("getExchangeListQuery err", err);
  248. },
  249. });
  250. },
  251. // 玩家兑换详情查询
  252. exchangeDetailQuery(oarId) {
  253. uni.request({
  254. url: apiExchangeDetailQuery,
  255. header: {
  256. "Content-Type": "application/x-www-form-urlencoded",
  257. "token": this.token,
  258. },
  259. method: "POST",
  260. data: {
  261. oarId: oarId
  262. },
  263. success: (res) => {
  264. // console.log("exchangeDetailQuery", res);
  265. if (checkResCode(res)) {
  266. const data = res.data.data;
  267. // 弹窗已获取数据且可兑换状态时,不再更新弹窗数据
  268. if (this.popupAchdet.length > 0 && this.popupAchdet[0].qrCode != "" && data
  269. .qrCode != "") {
  270. return;
  271. }
  272. this.popupAchdet = [{
  273. "type": 4,
  274. "data": {
  275. "title": "兑换",
  276. "img": data.iconUrl,
  277. "content": data.aiName,
  278. "qrCode": data.qrCode,
  279. "exTime": this.fmtTime(data.exTime, 0)
  280. },
  281. }];
  282. if (data.qrCode == "") { // 已兑换
  283. clearInterval(this.interval);
  284. this.interval = null;
  285. }
  286. if (!this.$refs.popupAchdet.isOpen) {
  287. setTimeout(() => {
  288. this.$refs.popupAchdet.popupOpen();
  289. }, 100);
  290. }
  291. }
  292. },
  293. fail: (err) => {
  294. console.log("exchangeDetailQuery err", err);
  295. },
  296. });
  297. },
  298. // 未读消息列表查询
  299. getUnReadMessageQuery() {
  300. uni.request({
  301. url: apiUnReadMessageQuery,
  302. header: {
  303. "Content-Type": "application/x-www-form-urlencoded",
  304. "token": this.token,
  305. },
  306. method: "POST",
  307. data: {},
  308. success: (res) => {
  309. // console.log("getUnReadMessageQuery", res);
  310. if (checkResCode(res)) {
  311. if (res.statusCode == 401) { // 未登录
  312. this.tokenValid = false;
  313. } else {
  314. this.tokenValid = true;
  315. }
  316. this.unReadMessageRs = res.data.data;
  317. this.mqIdListStr = "";
  318. for (var i = 0; i < this.unReadMessageRs.length; i++) {
  319. let popupData = {
  320. type: 3,
  321. data: {}
  322. };
  323. if (this.unReadMessageRs[i].mqType == 1) { // 消息类型 1: 成就
  324. popupData.data.title = "恭喜";
  325. }
  326. popupData.data.img = this.unReadMessageRs[i].iconUrl;
  327. popupData.data.content = "恭喜获得成就 \r\n" + this.unReadMessageRs[i].aiName;
  328. this.popupDataList.push(popupData);
  329. this.mqIdListStr += this.unReadMessageRs[i].mqId;
  330. if (i < this.unReadMessageRs.length - 1) {
  331. this.mqIdListStr += ",";
  332. }
  333. }
  334. if (this.popupDataList.length > 0) {
  335. this.$refs.popupNewach.popupOpen();
  336. }
  337. }
  338. },
  339. fail: (err) => {
  340. console.log("getUnReadMessageQuery err", err);
  341. },
  342. });
  343. },
  344. // 标记消息已读
  345. readMessage() {
  346. uni.request({
  347. url: apiReadMessage,
  348. header: {
  349. "Content-Type": "application/x-www-form-urlencoded",
  350. "token": this.token,
  351. },
  352. method: "POST",
  353. data: {
  354. "mqIdListStr": this.mqIdListStr
  355. },
  356. success: (res) => {
  357. // console.log("readMessage", res);
  358. },
  359. fail: (err) => {
  360. console.log("readMessage err", err);
  361. },
  362. });
  363. },
  364. showAchDetail(data) {
  365. // console.log("showAchDetail", data);
  366. this.popupAchdet.length = 0;
  367. if (this.tabCurrent == 1) { // 奖牌
  368. let popupData = {
  369. type: 3,
  370. data: {}
  371. };
  372. popupData.data.title = "恭喜";
  373. popupData.data.img = data.iconUrl;
  374. popupData.data.content = "恭喜获得成就 \r\n" + data.aiName;
  375. this.popupAchdet.push(popupData);
  376. this.$refs.popupAchdet.popupOpen();
  377. }
  378. if (this.tabCurrent == 2) { // 兑换
  379. this.exchangeDetailQuery(data.oarId);
  380. this.interval = setInterval(this.exchangeDetailQuery, 2000, data.oarId);
  381. }
  382. },
  383. onPopupNewachClose() {
  384. // console.log("onPopupNewachClose");
  385. this.readMessage();
  386. },
  387. onPopupAchdetClose() {
  388. // console.log("onPopupAchdetClose");
  389. if (this.interval != null) {
  390. clearInterval(this.interval);
  391. this.interval = null;
  392. }
  393. if (this.tabCurrent == 2) { // 兑换
  394. this.getExchangeListQuery();
  395. }
  396. },
  397. test() {
  398. // this.$refs.mypopupmap.popupOpen();
  399. const url =
  400. `action://to_map_app?title=${this.point.name}&latitude=${this.point.latitude}&longitude=${this.point.longitude}`;
  401. // window.location.href = url;
  402. tools.appAction(url);
  403. }
  404. }
  405. }
  406. </script>
  407. <style scoped>
  408. .content {
  409. width: 100vw;
  410. height: 100vh;
  411. justify-content: flex-start;
  412. }
  413. .topbar {
  414. width: 90%;
  415. margin-top: 70rpx;
  416. justify-content: space-between;
  417. font-weight: 550;
  418. color: #333333;
  419. font-size: 16px;
  420. }
  421. .tab {
  422. width: 90%;
  423. height: 60rpx;
  424. margin-top: 30rpx;
  425. background: #e7ecef;
  426. border-radius: 18px;
  427. justify-content: space-around;
  428. }
  429. .tab-active {
  430. width: 50%;
  431. height: 60rpx;
  432. background: #2e85ec;
  433. font-weight: 500;
  434. color: #ffffff;
  435. font-size: 16px;
  436. text-align: center;
  437. line-height: 60rpx;
  438. }
  439. .tab-unactive {
  440. width: 50%;
  441. height: 60rpx;
  442. font-weight: 500;
  443. color: #818181;
  444. font-size: 16px;
  445. text-align: center;
  446. line-height: 60rpx;
  447. }
  448. .boder-radius-left {
  449. border-radius: 18px 0 0 18px;
  450. }
  451. .boder-radius-right {
  452. border-radius: 0 18px 18px 0;
  453. }
  454. .boder-solid-left {
  455. border-left: #d7d7d7 1px solid;
  456. }
  457. .boder-solid-right {
  458. border-right: #d7d7d7 1px solid;
  459. }
  460. .main {
  461. width: 90%;
  462. padding-top: 30rpx;
  463. padding-bottom: 30rpx;
  464. }
  465. .norecord {
  466. font-weight: 500;
  467. color: #818181;
  468. font-size: 14px;
  469. text-align: center;
  470. line-height: 80vh;
  471. }
  472. .year {
  473. width: 100%;
  474. margin-left: 20rpx;
  475. text-align: left;
  476. font-weight: 550;
  477. color: #818181;
  478. font-size: 16px;
  479. }
  480. .list {
  481. width: 100%;
  482. padding-bottom: 10rpx;
  483. flex-wrap: wrap;
  484. justify-content: flex-start;
  485. }
  486. .item {
  487. width: 31.85%;
  488. margin: 20rpx 5rpx;
  489. }
  490. .item-bg {
  491. background: #e7ecef;
  492. border-radius: 5px;
  493. }
  494. .item-cup {
  495. width: 28vw;
  496. height: 28vw;
  497. /* background: #e7ecef; */
  498. border-radius: 5px;
  499. background-image: url("/static/cup/1/004.png");
  500. background-position-x: center;
  501. /* background-position-y: center; */
  502. background-repeat: no-repeat;
  503. background-size: 100% auto;
  504. /* background-clip: padding-box; */
  505. mask-image: url('/static/backgroud/mask.png');
  506. mask-size: 100%;
  507. mask-repeat: no-repeat;
  508. mask-clip: padding-box;
  509. }
  510. .item-cup-gray {
  511. width: 100%;
  512. /* height: 60%; */
  513. background-image: url("/static/cup/1/004h.png");
  514. background-position-x: center;
  515. background-repeat: no-repeat;
  516. background-size: 100% auto;
  517. overflow: hidden;
  518. /* filter: grayscale(1); */
  519. }
  520. .item-medal {
  521. width: 20vw;
  522. height: 20vw;
  523. margin-top: 25rpx;
  524. background-position-x: center;
  525. /* background-position-y: center; */
  526. background-repeat: no-repeat;
  527. background-size: auto 100%;
  528. }
  529. .item-title {
  530. width: 100%;
  531. margin-top: 10rpx;
  532. justify-content: center;
  533. }
  534. .item-title-month {
  535. color: #333333;
  536. font-size: 14px;
  537. font-weight: 550;
  538. }
  539. .item-title-divide {
  540. width: 4px;
  541. height: 14px;
  542. margin: 0 12rpx;
  543. background: #c6c6c6;
  544. border-radius: 2px;
  545. }
  546. .item-title-progress {
  547. color: #818181;
  548. font-size: 13px;
  549. font-weight: 500;
  550. }
  551. .item-title-ainame {
  552. margin-top: 12rpx;
  553. font-weight: 500;
  554. color: #333333;
  555. font-size: 12px;
  556. }
  557. .item-title-aitime {
  558. margin-top: 12rpx;
  559. margin-bottom: 20rpx;
  560. color: #818181;
  561. font-size: 11px;
  562. }
  563. .item-convertible {
  564. background: url("/static/medal/convertible.png") #e7ecef no-repeat;
  565. background-size: 30%;
  566. border-radius: 5px;
  567. }
  568. .item-converted {
  569. background: url("/static/medal/converted.png") #e7ecef no-repeat;
  570. background-size: 30%;
  571. border-radius: 5px;
  572. }
  573. </style>