Browse Source

update code

kevin.T 2 months ago
parent
commit
3006663772

BIN
packages/app/src/assets/pngs/platform.png


+ 9 - 0
packages/app/src/assets/svgs/leader-v1.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="50" height="26" viewBox="0 0 50 26" fill="none">
+  <path d="M0 16L5.5 25.5H45L50 16C47.3333 17 41.6 18.8 40 18C38.4 17.2 39.3333 10.3333 40 7C38 9 33.5 13 31.5 13C29.5 13 26.6667 4.33333 25.5 0C24.5 4.33333 21.8 13 19 13C16.2 13 12.5 9 11 7C11.5 10.3333 12 17.2 10 18C8 18.8 2.5 17 0 16Z" fill="url(#paint0_linear_946_2979)"/>
+  <defs>
+    <linearGradient id="paint0_linear_946_2979" x1="25" y1="0" x2="25" y2="25.5" gradientUnits="userSpaceOnUse">
+      <stop stop-color="#FAE867"/>
+      <stop offset="1" stop-color="#FCC02C"/>
+    </linearGradient>
+  </defs>
+</svg>

+ 9 - 0
packages/app/src/assets/svgs/leader-v2.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="48" height="24" viewBox="0 0 48 24" fill="none">
+  <path d="M0.510742 15.0188L5.62646 23.8551H42.3667L47.0173 15.0188C44.537 15.949 39.2042 17.6232 37.716 16.8791C36.2278 16.135 37.0959 9.74808 37.716 6.64764C35.8557 8.5079 31.6701 12.2284 29.8099 12.2284C27.9496 12.2284 25.3142 4.16729 24.2291 0.136719C23.299 4.16729 20.7876 12.2284 18.1832 12.2284C15.5789 12.2284 12.1374 8.5079 10.7422 6.64764C11.2073 9.74808 11.6723 16.135 9.81206 16.8791C7.95179 17.6232 2.83607 15.949 0.510742 15.0188Z" fill="url(#paint0_linear_946_2990)"/>
+  <defs>
+    <linearGradient id="paint0_linear_946_2990" x1="23.764" y1="0.136719" x2="23.764" y2="23.8551" gradientUnits="userSpaceOnUse">
+      <stop stop-color="#E9F1F8"/>
+      <stop offset="1" stop-color="#D1E0EE"/>
+    </linearGradient>
+  </defs>
+</svg>

+ 9 - 0
packages/app/src/assets/svgs/leader-v3.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="48" height="24" viewBox="0 0 48 24" fill="none">
+  <path d="M0.510742 15.0188L5.62646 23.8551H42.3667L47.0173 15.0188C44.537 15.949 39.2042 17.6232 37.716 16.8791C36.2278 16.135 37.0959 9.74808 37.716 6.64764C35.8557 8.5079 31.6701 12.2284 29.8099 12.2284C27.9496 12.2284 25.3142 4.16729 24.2291 0.136719C23.299 4.16729 20.7876 12.2284 18.1832 12.2284C15.5789 12.2284 12.1374 8.5079 10.7422 6.64764C11.2073 9.74808 11.6723 16.135 9.81206 16.8791C7.95179 17.6232 2.83607 15.949 0.510742 15.0188Z" fill="url(#paint0_linear_946_3001)"/>
+  <defs>
+    <linearGradient id="paint0_linear_946_3001" x1="23.764" y1="0.136719" x2="23.764" y2="23.8551" gradientUnits="userSpaceOnUse">
+      <stop stop-color="#F1DBD0"/>
+      <stop offset="1" stop-color="#A87F79"/>
+    </linearGradient>
+  </defs>
+</svg>

+ 19 - 0
packages/app/src/assets/svgs/platform-v1.svg

@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="137" height="95" viewBox="0 0 137 95" fill="none">
+  <path d="M137 12H0L28.1157 0H110.418L137 12Z" fill="url(#paint0_linear_946_2969)"/>
+  <mask id="path-2-outside-1_946_2969" maskUnits="userSpaceOnUse" x="0" y="11" width="137" height="84" fill="black">
+    <rect fill="white" y="11" width="137" height="84"/>
+    <path d="M0 13C0 12.4477 0.447715 12 1 12H136C136.552 12 137 12.4477 137 13V94C137 94.5523 136.552 95 136 95H0.999996C0.447712 95 0 94.5523 0 94V13Z"/>
+  </mask>
+  <path d="M0 13C0 12.4477 0.447715 12 1 12H136C136.552 12 137 12.4477 137 13V94C137 94.5523 136.552 95 136 95H0.999996C0.447712 95 0 94.5523 0 94V13Z" fill="url(#paint1_linear_946_2969)"/>
+  <path d="M0 13C0 12.0335 0.783502 11.25 1.75 11.25H135.25C136.216 11.25 137 12.0335 137 13C137 12.8619 136.552 12.75 136 12.75H1C0.447715 12.75 0 12.8619 0 13ZM137 95H0H137ZM0 95V12V95ZM137 12V95V12Z" fill="#3A3633" mask="url(#path-2-outside-1_946_2969)"/>
+  <defs>
+    <linearGradient id="paint0_linear_946_2969" x1="68.5" y1="12" x2="68.5" y2="-2.854e-08" gradientUnits="userSpaceOnUse">
+      <stop stop-color="#353130"/>
+      <stop offset="1" stop-color="#262629" stop-opacity="0.6"/>
+    </linearGradient>
+    <linearGradient id="paint1_linear_946_2969" x1="68.5" y1="12" x2="68.5" y2="95" gradientUnits="userSpaceOnUse">
+      <stop stop-color="#2A272D"/>
+      <stop offset="1" stop-color="#1C1D23"/>
+    </linearGradient>
+  </defs>
+</svg>

+ 19 - 0
packages/app/src/assets/svgs/platform-v2.svg

@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="137" height="95" viewBox="0 0 137 95" fill="none">
+  <path d="M137 12H0L28.1157 0H110.418L137 12Z" fill="url(#paint0_linear_946_2966)"/>
+  <mask id="path-2-outside-1_946_2966" maskUnits="userSpaceOnUse" x="0" y="11" width="137" height="84" fill="black">
+    <rect fill="white" y="11" width="137" height="84"/>
+    <path d="M0 13C0 12.4477 0.447715 12 1 12H136C136.552 12 137 12.4477 137 13V94C137 94.5523 136.552 95 136 95H0.999996C0.447712 95 0 94.5523 0 94V13Z"/>
+  </mask>
+  <path d="M0 13C0 12.4477 0.447715 12 1 12H136C136.552 12 137 12.4477 137 13V94C137 94.5523 136.552 95 136 95H0.999996C0.447712 95 0 94.5523 0 94V13Z" fill="url(#paint1_linear_946_2966)"/>
+  <path d="M0 13C0 12.0335 0.783502 11.25 1.75 11.25H135.25C136.216 11.25 137 12.0335 137 13C137 12.8619 136.552 12.75 136 12.75H1C0.447715 12.75 0 12.8619 0 13ZM137 95H0H137ZM0 95V12V95ZM137 12V95V12Z" fill="#3A3633" mask="url(#path-2-outside-1_946_2966)"/>
+  <defs>
+    <linearGradient id="paint0_linear_946_2966" x1="68.5" y1="12" x2="68.5" y2="-2.854e-08" gradientUnits="userSpaceOnUse">
+      <stop stop-color="#353130"/>
+      <stop offset="1" stop-color="#262629" stop-opacity="0.6"/>
+    </linearGradient>
+    <linearGradient id="paint1_linear_946_2966" x1="68.5" y1="12" x2="68.5" y2="95" gradientUnits="userSpaceOnUse">
+      <stop stop-color="#2A272D"/>
+      <stop offset="1" stop-color="#1C1D23"/>
+    </linearGradient>
+  </defs>
+</svg>

+ 19 - 0
packages/app/src/assets/svgs/platform-v3.svg

@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="137" height="95" viewBox="0 0 137 95" fill="none">
+  <path d="M137 12H0L28.1157 0H110.418L137 12Z" fill="url(#paint0_linear_946_2963)"/>
+  <mask id="path-2-outside-1_946_2963" maskUnits="userSpaceOnUse" x="0" y="11" width="137" height="84" fill="black">
+    <rect fill="white" y="11" width="137" height="84"/>
+    <path d="M0 13C0 12.4477 0.447715 12 1 12H136C136.552 12 137 12.4477 137 13V94C137 94.5523 136.552 95 136 95H0.999996C0.447712 95 0 94.5523 0 94V13Z"/>
+  </mask>
+  <path d="M0 13C0 12.4477 0.447715 12 1 12H136C136.552 12 137 12.4477 137 13V94C137 94.5523 136.552 95 136 95H0.999996C0.447712 95 0 94.5523 0 94V13Z" fill="url(#paint1_linear_946_2963)"/>
+  <path d="M0 13C0 12.0335 0.783502 11.25 1.75 11.25H135.25C136.216 11.25 137 12.0335 137 13C137 12.8619 136.552 12.75 136 12.75H1C0.447715 12.75 0 12.8619 0 13ZM137 95H0H137ZM0 95V12V95ZM137 12V95V12Z" fill="#3A3633" mask="url(#path-2-outside-1_946_2963)"/>
+  <defs>
+    <linearGradient id="paint0_linear_946_2963" x1="68.5" y1="12" x2="68.5" y2="-2.854e-08" gradientUnits="userSpaceOnUse">
+      <stop stop-color="#353130"/>
+      <stop offset="1" stop-color="#262629" stop-opacity="0.6"/>
+    </linearGradient>
+    <linearGradient id="paint1_linear_946_2963" x1="68.5" y1="12" x2="68.5" y2="95" gradientUnits="userSpaceOnUse">
+      <stop stop-color="#2A272D"/>
+      <stop offset="1" stop-color="#1C1D23"/>
+    </linearGradient>
+  </defs>
+</svg>

+ 15 - 0
packages/app/src/core/libs/models.ts

@@ -1339,6 +1339,21 @@ export interface Collection {
   badgeSize: number | string
 }
 /**
+ * 典藏徽章详情
+ * */
+export interface CollectionDetail extends Collection {
+  badgeList: Badge[]
+}
+/**
+ * 排名
+ * */
+export interface Rank {
+  rank1: number
+  avatar: string
+  name: string
+  acquisitionTime: string | number
+}
+/**
  * 证书
  */
 export interface Certificate {

+ 1 - 0
packages/app/src/core/libs/net-images.ts

@@ -18,4 +18,5 @@ export enum NetImages {
   RankingOne = 'https://image.zhuchaohui.com/zhucaohui/5743d060b96571f4540adf66b1f40ed8f0c313d721ce0932d06227b4e31e6a48.svg',
   RankingTwo = 'https://image.zhuchaohui.com/zhucaohui/2709798b4445b57e349b8e244825885983bf634e2b7f3706f181912753e2d567.svg',
   RankingThree = 'https://image.zhuchaohui.com/zhucaohui/d70fae2ba6688e0e82bfc1025f2005432de2dc1a1353eddb0da061245b37d970.svg',
+  savePosterIcon = 'https://image.zhuchaohui.com/zhucaohui/fce65f7e789b228aeeeb19906c4ed62bb985386c421fb9ddc09db4b19b01b4c6.png',
 }

+ 12 - 0
packages/app/src/core/libs/requests.ts

@@ -25,6 +25,8 @@ import {
   Product,
   ConfirmOrder,
   Collection,
+  CollectionDetail,
+  Rank,
 } from './models'
 import dayjs from 'dayjs'
 import { AgreementType } from '@/core/libs/enums'
@@ -937,6 +939,16 @@ export const getBadges = (query = {}) =>
 export const getListCollectionBadge = (query = {}) =>
   httpGet<Collection[]>('/app-api/member/stylist-honor/listCollectionBadge', query)
 /**
+ * 获取典藏榜单
+ * */
+export const getCollectionBadgeNotice = (query = {}) =>
+  httpGet<Rank[]>('/app-api/member/stylist-honor/getCollectionBadgeNotice', query)
+/**
+ * 典藏徽章 详情
+ * */
+export const getCollectionBadge = (query = {}) =>
+  httpGet<CollectionDetail>('/app-api/member/stylist-honor/getCollectionBadge', query)
+/**
  * 获取个人徽章
  */
 export const getOwnBadges = (query = {}) =>

+ 12 - 0
packages/app/src/core/libs/svgs.ts

@@ -30,6 +30,12 @@ import memberIconV1 from '@/assets/svgs/member-icon-v1.svg'
 import memberIconV2 from '@/assets/svgs/member-icon-v2.svg'
 import memberIconV3 from '@/assets/svgs/member-icon-v3.svg'
 import memberIconV4 from '@/assets/svgs/member-icon-v4.svg'
+import leaderV1 from '@/assets/svgs/leader-v1.svg'
+import leaderV2 from '@/assets/svgs/leader-v2.svg'
+import leaderV3 from '@/assets/svgs/leader-v3.svg'
+import platformV1 from '@/assets/svgs/platform-v1.svg'
+import platformV2 from '@/assets/svgs/platform-v2.svg'
+import platformV3 from '@/assets/svgs/platform-v3.svg'
 import phone from '@/assets/svgs/phone.svg'
 import route from '@/assets/svgs/route.svg'
 import system from '@/assets/svgs/system.svg'
@@ -59,6 +65,12 @@ export {
   memberIconV2,
   memberIconV3,
   memberIconV4,
+  leaderV1,
+  leaderV2,
+  leaderV3,
+  platformV1,
+  platformV2,
+  platformV3,
   material,
   homeActive,
   home,

+ 0 - 7
packages/app/src/manifest.json

@@ -87,13 +87,6 @@
     "setting": {
       "urlCheck": false
     },
-    "requiredPrivateInfos": [
-      "getLocation", "chooseLocation", "chooseAddress"
-    ],
-    "permission": {
-      "scope.userLocation": {
-        "desc": "你的位置信息将用于小程序位置接口的效果展示"
-    },
     "usingComponents": true
   },
   "mp-alipay": {

+ 28 - 1
packages/app/src/pages.json

@@ -522,6 +522,14 @@
       }
     },
     {
+      "path": "pages/mine/honors/detail/collection",
+      "type": "page",
+      "style": {
+        "navigationBarTitleText": "我的典藏",
+        "navigationStyle": "custom"
+      }
+    },
+    {
       "path": "pages/mine/honors/detail/index",
       "type": "page",
       "style": {
@@ -530,6 +538,14 @@
       }
     },
     {
+      "path": "pages/mine/honors/leaderboard/index",
+      "type": "page",
+      "style": {
+        "navigationBarTitleText": "获取榜单",
+        "navigationStyle": "custom"
+      }
+    },
+    {
       "path": "pages/mine/levels/rules/index",
       "type": "page",
       "style": {
@@ -614,5 +630,16 @@
       }
     }
   ],
+  "requiredPrivateInfos": [
+    "getLocation",
+    "onLocationChange",
+    "startLocationUpdateBackground",
+    "chooseAddress"
+  ],
+  "permission": {
+    "scope.userLocation": {
+      "desc": "你的位置信息将用于小程序位置接口的效果展示" // 高速公路行驶持续后台定位
+    }
+  },
   "subPackages": []
-}
+}

+ 143 - 0
packages/app/src/pages/mine/honors/detail/collection.vue

@@ -0,0 +1,143 @@
+<route lang="json">
+{
+  "style": {
+    "navigationBarTitleText": "我的典藏",
+    "navigationStyle": "custom"
+  }
+}
+</route>
+<script setup lang="ts">
+import NavbarEvo from '@/components/navbar-evo.vue'
+import { getCollectionBadge } from '../../../../core/libs/requests'
+import { Collection, CollectionDetail } from '../../../../core/libs/models'
+import { NetImages } from '../../../../core/libs/net-images'
+import dayjs from 'dayjs'
+
+const id = ref<string | number>()
+// 游学徽章,活动徽章,积分徽章,典藏勋章,传播徽章,打卡徽章,课程徽章
+const badgeTypes = ref([
+  { label: '游学徽章', value: '游学徽章' },
+  { label: '活动徽章', value: '活动徽章' },
+  { label: '积分徽章', value: '积分徽章' },
+  { label: '典藏勋章', value: '典藏勋章' },
+  { label: '传播徽章', value: '传播徽章' },
+  { label: '打卡徽章', value: '打卡徽章' },
+  { label: '课程徽章', value: '课程徽章' },
+])
+const { data: collectionBadges, run: setCollectionBadges } = useRequest(
+  () => getCollectionBadge({ badgeId: id.value }),
+  {
+    initialData: {
+      badgeList: [],
+      id: 0,
+      userId: 0,
+      quantity: 0,
+      badgeId: 0,
+      badgeType: '',
+      badgeName: '',
+      badgeNotObtainedImage: '',
+      badgeYesObtainedImage: '',
+      badgeDescription: '',
+      popUp: false,
+      userSize: '',
+      badgeSize: '',
+    },
+  },
+)
+const data = ref<CollectionDetail>({
+  badgeList: [],
+  id: 0,
+  userId: 0,
+  quantity: 0,
+  badgeId: 0,
+  badgeType: '',
+  badgeName: '',
+  badgeNotObtainedImage: '',
+  badgeYesObtainedImage: '',
+  badgeDescription: '',
+  popUp: false,
+  userSize: '',
+  badgeSize: '',
+})
+onLoad(async (query: Record<string | 'id', string>) => {
+  if (query?.id) {
+    id.value = query.id
+    await setCollectionBadges()
+    data.value = collectionBadges.value
+    console.log('data', data.value)
+  }
+})
+</script>
+<template>
+  <div
+    class="flex-grow bg-[#100f18] backdrop-blur-2xl flex flex-col items-center justify-between py-32 gap-4 relative"
+  >
+    <div class="absolute top-[-60px] left-0 right-0 rotate-[-50deg]">
+      <wd-img
+        width="100%"
+        mode="widthFix"
+        custom-clas="vertical-bottom"
+        :src="NetImages.TopSpotlight"
+      ></wd-img>
+    </div>
+    <div class="absolute top-[-60px] left-0 right-[0px] rotate-[50deg]">
+      <wd-img
+        width="100%"
+        mode="widthFix"
+        custom-clas="vertical-bottom"
+        :src="NetImages.TopSpotlight"
+      ></wd-img>
+    </div>
+    <div class="absolute top-20 left-0 right-0 flex flex-col items-center">
+      <wd-img
+        width="40%"
+        mode="widthFix"
+        custom-clas="vertical-bottom mx-auto"
+        :src="NetImages.Stars"
+      ></wd-img>
+    </div>
+    <NavbarEvo fixed dark transparent></NavbarEvo>
+    <wd-img width="42%" mode="widthFix" :src="data.badgeImage"></wd-img>
+    <div class="flex flex-col items-center gap-1">
+      <div class="text-white text-[26px] font-normal font-['PingFang_SC'] uppercase">
+        {{ data.badgeName }}
+      </div>
+      <div class="text-center text-white text-sm font-normal font-['PingFang_SC'] uppercase">
+        <!-- 参加东方艺术设计研学营 -->
+        {{ `${data.badgeDescription}` }}
+      </div>
+      <div class="text-[#868686] text-[16px] font-normal font-['PingFang_SC'] uppercase">
+        已解锁:
+        <text class="text-white text-[18px]">{{ data.userSize }}</text>
+        / {{ data.badgeSize }} 枚
+      </div>
+      <div class="mt-6 flex items-center gap-4">
+        <div
+          class="w-[37px] h-[1px] bg-gradient-to-l from-[#D9D9D9] to-[rgba(217, 217, 217, 0.00)]"
+        ></div>
+        <div class="text-center text-white text-sm font-normal font-['PingFang_SC'] uppercase">
+          需解锁全部徽章
+        </div>
+        <div
+          class="w-[37px] h-[1px] bg-gradient-to-r from-[#D9D9D9] to-[rgba(217, 217, 217, 0.00)]"
+        ></div>
+      </div>
+      <div
+        class="text-center pt-[55px] text-white text-sm font-normal font-['PingFang_SC'] uppercase"
+      >
+        <div class="grid grid-cols-3 gap-y-6">
+          <template v-for="(item, i) in data.badgeList" :key="i">
+            <div class="w-full px-4 box-border">
+              <wd-img width="100%" mode="widthFix" :src="item.badgeImage"></wd-img>
+              <div
+                class="text-center text-white text-xs font-normal font-['PingFang_SC'] leading-relaxed"
+              >
+                {{ item.badgeName }}
+              </div>
+            </div>
+          </template>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>

+ 164 - 26
packages/app/src/pages/mine/honors/detail/index.vue

@@ -8,32 +8,99 @@
 </route>
 <script setup lang="ts">
 import NavbarEvo from '@/components/navbar-evo.vue'
-import { getBadges, getCertificates } from '../../../../core/libs/requests'
+import { getDesignerInfo } from '../../../../core/libs/requests'
 import { Badge } from '../../../../core/libs/models'
 import { NetImages } from '../../../../core/libs/net-images'
+import { useMessage } from 'wot-design-uni'
+import { pick } from 'radash'
+import ImageEvo from '@/components/image-evo.vue'
 import dayjs from 'dayjs'
+import { storeToRefs } from 'pinia'
+import { useUserStore } from '@/store'
+import { Canvas } from '@/core/utils/canvas'
 
-const active = ref('badge')
-const tabs = ref([
-  { label: '徽章', value: 'badge' },
-  { label: '证书', value: 'certificate' },
+const show = ref<boolean>(false)
+const canvasHidden = ref<boolean>(false)
+const posterUrl = ref<string | any>()
+const userStore = useUserStore()
+const { userInfo } = storeToRefs(userStore)
+const panels = ref([
+  {
+    iconUrl: NetImages.savePosterIcon,
+    title: '保存到本地',
+    index: 0,
+  },
 ])
-// 游学徽章,活动徽章,积分徽章,典藏勋章,传播徽章,打卡徽章,课程徽章
-const badgeTypes = ref([
-  { label: '游学徽章', value: '游学徽章' },
-  { label: '活动徽章', value: '活动徽章' },
-  { label: '积分徽章', value: '积分徽章' },
-  { label: '典藏勋章', value: '典藏勋章' },
-  { label: '传播徽章', value: '传播徽章' },
-  { label: '打卡徽章', value: '打卡徽章' },
-  { label: '课程徽章', value: '课程徽章' },
-])
-const { data: badges, run: setBadges } = useRequest(() => getBadges({}), {
-  initialData: {},
-})
-const { data: certificates, run: setCertificates } = useRequest(() => getCertificates({}), {
-  initialData: [],
-})
+const { data: designer, run: setData } = useRequest(() => getDesignerInfo(userInfo.value.userId))
+/**
+ * 生成分享海拔
+ * */
+const createPoster = () => {
+  return new Promise((resolve, reject) => {
+    ;(async () => {
+      uni.showLoading({ title: '生成中' })
+      const [bgPath, badgePath, avatarPath, icon1, icon2, icon3, icon4] = await Promise.all(
+        [
+          NetImages.TopSpotlight,
+          data.value.quantity ? data.value.activedImage : data.value.image,
+          designer.value.headImgUrl || userInfo.value?.avatar || NetImages.DefaultAvatar,
+          data.value.quantity ? data.value.activedImage : data.value.image,
+          designer.value.headImgUrl || userInfo.value?.avatar || NetImages.DefaultAvatar,
+          'https://image.zhuchaohui.com/zhucaohui/9f89604f285c33200b7e6fda9acc82e130f34c2f5687cfeb78f3541e1fabcc28.png',
+          'https://image.zhuchaohui.com/zhucaohui/2467be55426018856150bd94bbd21865df3d73ce982bc1c82b7585cf26c822f0.png',
+        ].map((it) => uni.getImageInfo({ src: it }).then(({ path }) => path)),
+      )
+      const ctx = uni.createCanvasContext('firstCanvas')
+      ctx.fillStyle = '#141823'
+      ctx.fillRect(0, 0, 345, 500)
+      uni
+        .createSelectorQuery()
+        .select('#firstCanvas')
+        .fields({ size: true }, async ({ width: w, height: h }: any) => {
+          const canvas = new Canvas(ctx, { width: w, height: h }, { width: 345 })
+          canvas.FillImage(bgPath)
+          // ctx.drawImage(path, 0, 0, 16, 18)
+          canvas.CircleImage(avatarPath, 17, 20, 20)
+          canvas.Image(badgePath, 93, 74, 170, 180)
+          canvas.FillText(userInfo.value?.nickname, '#ffffff', 16, 63, 46)
+          const textNameWidth = ctx.measureText(data.value.name).width
+          const textDesWidth = ctx.measureText(subTitle.value).width
+          canvas.FillText(data.value?.name, '#ffffff', 18, (345 - textNameWidth) / 2, 291)
+          canvas.FillText(subTitle.value, '#ffffff', 14, (345 - textDesWidth) / 2, 326)
+
+          canvas.Image(icon1, 17, 415, 28, 28)
+          canvas.FillText('筑巢荟', '#ffffff', 18, 63, 436)
+          canvas.Image(icon2, 250, 393, 80, 80)
+
+          ctx.draw(true, () => {
+            uni.canvasToTempFilePath({
+              canvasId: 'firstCanvas',
+              width: 345,
+              height: 500,
+              success: (res) => {
+                // console.log('生成海报', res)
+                uni.hideLoading()
+                resolve(res.tempFilePath)
+              },
+              fail: (err) => {
+                // uni.hideLoading()
+                reject(err)
+              },
+            })
+          })
+        })
+        .exec()
+    })()
+  })
+}
+const save = async () => {
+  await uni.saveImageToPhotosAlbum({ filePath: posterUrl.value })
+  uni.showToast({ title: '已保存相册', icon: 'none' })
+}
+const cancelSaveImage = () => {
+  uni.showToast({ title: '取消保存', icon: 'none' })
+  show.value = false
+}
 const data = ref<{
   name: string
   quantity: number
@@ -42,16 +109,21 @@ const data = ref<{
   activedImage: string
   badgeType?: string
   badgeDescription?: string
-  createTime?: number | Date
+  createTime?: number | Date | string
 }>({
   name: '',
   quantity: 0,
   image: '',
   activedImage: '',
+  createTime: '',
 })
 const image = computed(() => (data.value.quantity ? data.value.activedImage : data.value.image))
+const subTitle = computed(() =>
+  data.value?.quantity > 1
+    ? `${dayjs(data.value.createTime).format('YYYY年MM月DD日')} 首次获得`
+    : `${dayjs(data.value.createTime).format('YYYY年MM月DD日')}获得`,
+)
 const setBadgesPath = (type: string) => {
-  console.log('========================', type)
   if (type === '活动徽章') {
     uni.redirectTo({
       url: `/pages/home/offline-activity/index`,
@@ -62,9 +134,21 @@ const setBadgesPath = (type: string) => {
     })
   }
 }
+const showActions = () => {
+  show.value = true
+}
+const close = () => {
+  show.value = false
+}
+const select = (item: any) => {
+  console.log(item, '分享选择')
+  let { index } = item
+  if (index === 0) {
+    save()
+  }
+}
 onLoad(async (query: { type: 'badge' | 'certificate'; data: string }) => {
-  console.log(JSON.parse(query.data))
-
+  console.log(query, 'query2')
   if (query.type === 'badge') {
     const badge = JSON.parse(query.data) as Badge
     data.value = {
@@ -76,6 +160,10 @@ onLoad(async (query: { type: 'badge' | 'certificate'; data: string }) => {
       badgeDescription: badge.badgeDescription,
       createTime: badge.createTime,
     }
+    if (data.value.quantity > 0) {
+      await setData()
+      posterUrl.value = await createPoster()
+    }
   }
 })
 </script>
@@ -134,7 +222,11 @@ onLoad(async (query: { type: 'badge' | 'certificate'; data: string }) => {
         累计参与{{ data.quantity }}次
       </div>
     </div>
-    <wd-button custom-class="w-[161px] h-12 bg-[#0cbe7c]! rounded-[30px]" v-if="data.quantity > 0">
+    <wd-button
+      custom-class="w-[161px] h-12 bg-[#0cbe7c]! rounded-[30px]"
+      @click="showActions"
+      v-if="data.quantity > 0"
+    >
       去分享
     </wd-button>
     <wd-button
@@ -144,5 +236,51 @@ onLoad(async (query: { type: 'badge' | 'certificate'; data: string }) => {
     >
       去获得
     </wd-button>
+    <canvas
+      class="w-[347px] h-[494px] absolute rounded-[20px] top--1000"
+      canvas-id="firstCanvas"
+      id="firstCanvas"
+    ></canvas>
+    <wd-popup
+      v-model="show"
+      custom-class="!bg-[rgba(255,255,255,0)] !backdrop-blur-2xl"
+      position="bottom"
+      :safe-area-inset-bottom="true"
+      custom-style="height: 690px;"
+      @close="close"
+    >
+      <div class="rounded-[20px] mx-[14px]">
+        <div class="flex h-[500px]">
+          <ImageEvo
+            class="w-full h-full rounded-[20px] overflow-hidden"
+            :src="posterUrl"
+            @displayed="canvasHidden = true"
+          ></ImageEvo>
+        </div>
+      </div>
+      <div class="bg-[#ffffff] rounded-[20px] mx-[14px] mt-[20px] py-4 px-6">
+        <div class="flex items-center gap-4">
+          <div
+            class="text-white text-[26px] font-normal font-['PingFang_SC'] uppercase text-center"
+            v-for="(item, index) in panels"
+            :key="index"
+            @click="select(item)"
+          >
+            <!-- 分享到 -->
+            <wd-img :src="item.iconUrl" width="40px" mode="widthFix"></wd-img>
+            <div class="text-center text-black text-sm font-normal font-['PingFang_SC'] uppercase">
+              {{ item.title }}
+            </div>
+          </div>
+        </div>
+
+        <div
+          @click="cancelSaveImage"
+          class="bg-[rgb(240,240,240)] line-height-[40px] h-[40px] text-center rounded-[50px] mx-[4px] mt-[20px] text-black font-normal font-['PingFang_SC']"
+        >
+          取消
+        </div>
+      </div>
+    </wd-popup>
   </div>
 </template>

+ 38 - 7
packages/app/src/pages/mine/honors/index.vue

@@ -52,17 +52,47 @@ const { data: certificates, run: setCertificates } = useRequest(
     initialData: [],
   },
 )
-console.log('certificates:::::', certificates)
+const save = async (filePath: string) => {
+  uni.downloadFile({
+    url: filePath, // 下载资源的网络地址
+    success: (res) => {
+      if (res.statusCode === 200) {
+        uni.saveImageToPhotosAlbum({
+          filePath: res.tempFilePath, // 临时文件路径
+          success: () => {
+            uni.showToast({ title: '已保存相册', icon: 'none' })
+          },
+          fail: (err) => {
+            uni.showToast({
+              title: '保存失败',
+              icon: 'none',
+            })
+          },
+        })
+      }
+    },
+    fail: (err) => {
+      uni.showToast({
+        title: '下载失败',
+        icon: 'none',
+      })
+    },
+  })
+}
 const handleSwiperChange = (e: any) => {
   console.log(e)
 }
 
 const handleGetCondition = (badge: any) => {
-  console.log(badge)
+  uni.navigateTo({
+    url: `/pages/mine/honors/detail/collection?id=${badge}`,
+  })
 }
 
 const handleGetBadge = (badge: any) => {
-  console.log(badge)
+  uni.navigateTo({
+    url: `/pages/mine/honors/leaderboard/index?id=${badge}`,
+  })
 }
 const currentCertificate = ref<Certificate | undefined>()
 const isOwner = computed(() => String(userInfo.value?.userId) === id.value)
@@ -172,7 +202,7 @@ onLoad(async (query?: Record<string | 'active' | 'id' | 'isShared', string>) =>
                   <div
                     class="text-center text-[#ffecb9] text-lg font-normal font-['PingFang_SC'] leading-relaxed"
                   >
-                    学习大师
+                    {{ item.badgeName }}
                   </div>
                   <div
                     class="h-[26px] px-2.5 rounded-[30px] border border-solid border-[#ffecb9] justify-center items-center gap-2.5 inline-flex"
@@ -189,7 +219,7 @@ onLoad(async (query?: Record<string | 'active' | 'id' | 'isShared', string>) =>
                   <div
                     class="text-start text-white/60 text-xs font-normal font-['PingFang_SC'] leading-relaxed"
                   >
-                    参加游学解锁典藏徽章
+                    {{ item.badgeDescription }}
                   </div>
                 </div>
                 <div class="row-start-3 col-start-2 flex items-center gap-4">
@@ -261,7 +291,6 @@ onLoad(async (query?: Record<string | 'active' | 'id' | 'isShared', string>) =>
                 <div
                   class="text-center text-white text-xs font-normal font-['PingFang_SC'] leading-relaxed"
                 >
-                  <!-- 清华大学 -->
                   {{ item.badgeName }}
                 </div>
               </div>
@@ -311,7 +340,9 @@ onLoad(async (query?: Record<string | 'active' | 'id' | 'isShared', string>) =>
             <div class="w-3.5 h-[1.5px] bg-white"></div>
           </div>
         </div>
-        <wd-button custom-class="bg-[#0CBE7D]!">去分享</wd-button>
+        <wd-button custom-class="bg-[#0CBE7D]!" @click="save(currentCertificate?.certificateImage)">
+          保存到本地
+        </wd-button>
       </div>
     </wd-overlay>
   </div>

+ 201 - 0
packages/app/src/pages/mine/honors/leaderboard/index.vue

@@ -0,0 +1,201 @@
+<route lang="json">
+{
+  "style": {
+    "navigationBarTitleText": "获取榜单",
+    "navigationStyle": "custom"
+  }
+}
+</route>
+<script setup lang="ts">
+import dayjs from 'dayjs'
+import { useUserStore } from '@/store'
+import { storeToRefs } from 'pinia'
+import { leaderV1, leaderV2, leaderV3 } from '@/core/libs/svgs'
+import { getCollectionBadgeNotice } from '@/core/libs/requests'
+
+const id = ref()
+const theTop3 = ref<any[]>([])
+const otherTop = ref<any[]>([])
+const { data: rankList, run: setRankList } = useRequest(
+  () => getCollectionBadgeNotice({ badgeId: id.value }),
+  {
+    initialData: [],
+  },
+)
+
+const handleClickLeft = () => {
+  uni.navigateBack()
+}
+onLoad(async (query?: Record<string | 'active' | 'id' | 'isShared', string>) => {
+  if (query?.id) {
+    id.value = query.id
+    await setRankList()
+    theTop3.value = rankList.value.length >= 3 ? rankList.value.slice(0, 3) : rankList.value
+    otherTop.value = rankList.value.slice(3)
+  }
+})
+</script>
+<template>
+  <wd-navbar
+    fixed
+    placeholder
+    left-arrow
+    safeAreaInsetTop
+    custom-style="background-color: #22201E !important;"
+    @click-left="handleClickLeft"
+    :bordered="false"
+  >
+    <template #title>
+      <view class="wd-navbar__title" style="color: #fff !important">获取榜单</view>
+    </template>
+    <template #left>
+      <wd-icon name="thin-arrow-left" color="#fff" size="24px"></wd-icon>
+    </template>
+  </wd-navbar>
+  <div class="bg-[#22201E] h-full flex flex-[1] flex-col flex-grow">
+    <!-- 头部区域 -->
+    <div class="h-[134px] px-[14px]">
+      <div class="h-[26px] color-[#999999] font-size-[12px] text-center lh-[26px]">
+        按获取时间排序
+      </div>
+      <div class="mt-[42px] w-[calc(100vw-28px)] mx-[auto] flex justify-around">
+        <!-- 第二名 leader2 -->
+        <div class="w-[60px] h-[60px] relative">
+          <div class="absolute top-[-16px] left-[50%] translate-x-[-50%]">
+            <wd-img :src="leaderV2" width="46" height="23"></wd-img>
+          </div>
+          <!-- 头像 -->
+          <div
+            class="w-[60px] h-[60px] rounded-full bg-[#999999] border-[1px] border-[#D1E0EE] border-solid absolute top-[0] left-[0] overflow-hidden z-0"
+          >
+            <wd-img :src="theTop3[1]?.avatar" width="60" height="60" class="rounded-full"></wd-img>
+          </div>
+          <div
+            class="absolute bottom-[-16px] left-[50%] translate-x-[-50%] sign-bg2 color-[#657A98] text-center font-size-[12px] fw-400 w-[42px] h-[16px]"
+          >
+            NO.2
+          </div>
+        </div>
+        <!-- 第一名 leader1 -->
+        <div class="w-[66px] h-[66px] relative mt-[-13px]">
+          <div class="absolute top-[-18px] left-[25px] translate-x-[-20px]">
+            <wd-img :src="leaderV1" width="50" height="25"></wd-img>
+          </div>
+          <!-- 头像 -->
+          <div
+            class="w-[66px] h-[66px] rounded-full bg-[#999999] border-[1px] border-[#FFC700] border-solid absolute top-[0] left-[0] overflow-hidden z-0"
+          >
+            <wd-img :src="theTop3[0]?.avatar" width="66" height="66" class="rounded-full"></wd-img>
+          </div>
+          <div
+            class="absolute bottom-[-12px] left-[23px] translate-x-[-16px] sign-bg1 color-[#FFDF79] text-center font-size-[12px] fw-400 w-[46px] h-[17px]"
+          >
+            NO.1
+          </div>
+        </div>
+        <!-- 第三名 leader3 -->
+        <div class="w-[60px] h-[60px] relative">
+          <div class="absolute top-[-16px] left-[50%] translate-x-[-50%]">
+            <wd-img :src="leaderV3" width="46" height="23"></wd-img>
+          </div>
+          <!-- 头像 -->
+          <div
+            class="w-[60px] h-[60px] rounded-full bg-[#999999] border-[1px] border-[#A87F79] border-solid absolute top-[0] left-[0] overflow-hidden z-0"
+          >
+            <wd-img :src="theTop3[2]?.avatar" width="60" height="60" class="rounded-full"></wd-img>
+          </div>
+          <div
+            class="absolute bottom-[-16px] left-[50%] translate-x-[-50%] sign-bg3 color-[#856660] text-center font-size-[12px] fw-400 w-[42px] h-[16px]"
+          >
+            NO.3
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 头部 领奖台 -->
+    <div class="bg-gradient-to-b pt-[12px] from-[#22201E] to-[#191818] h-[102px]">
+      <div class="flex justify-around h-[95px] w-[calc(100vw-28px)] mx-[auto]">
+        <div
+          class="w-[87px] pr-[50px] h-[95px] mr-[-50px] relative z-5 bg-[url(https://image.zhuchaohui.com/zhucaohui/e5b96189f235d0dee01209cfe50a1e50751459e03099027528f62a8878a4f1a9.png)] bg-[length:100%_100%]"
+        >
+          <div class="absolute bottom-[20px] left-[0px]">
+            <div class="w-[87px] color-[#fff] font-size-[14px] fw-400 lh-[26px] text-center">
+              {{ theTop3[1]?.name }}
+            </div>
+            <div class="w-[87px] color-[#BDBDBD] font-size-[12px] fw-500 text-center">
+              {{ dayjs(theTop3[1]?.acquisitionTime).format('YYYY-MM-DD') }}
+            </div>
+          </div>
+        </div>
+        <div
+          class="w-[137px] h-[107px] mt-[-12px] relative z-10 bg-[url(https://image.zhuchaohui.com/zhucaohui/e5b96189f235d0dee01209cfe50a1e50751459e03099027528f62a8878a4f1a9.png)] bg-[length:100%_100%]"
+        >
+          <div class="absolute bottom-[20px] left-[0px] w-[137px]">
+            <div class="color-[#fff] font-size-[14px] fw-400 lh-[26px] text-center">
+              {{ theTop3[0]?.name }}
+            </div>
+            <div class="color-[#BDBDBD] font-size-[12px] fw-500 text-center">
+              {{ dayjs(theTop3[0]?.acquisitionTime).format('YYYY-MM-DD') }}
+            </div>
+          </div>
+        </div>
+        <div
+          class="w-[97px] h-[95px] ml-[-40px] pl-[40px] relative z-5 bg-[url(https://image.zhuchaohui.com/zhucaohui/e5b96189f235d0dee01209cfe50a1e50751459e03099027528f62a8878a4f1a9.png)] bg-[length:100%_100%]"
+        >
+          <div class="absolute bottom-[20px] right-[0px]">
+            <div class="w-[97px] color-[#fff] font-size-[14px] fw-400 lh-[26px] text-center">
+              {{ theTop3[2]?.name }}
+            </div>
+            <div class="w-[97px] color-[#BDBDBD] font-size-[12px] fw-500 text-center">
+              {{ dayjs(theTop3[2]?.acquisitionTime).format('YYYY-MM-DD') }}
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 其他人员 -->
+    <div class="bg-gradient-to-t from-[#22201E] to-[#191818]">
+      <div
+        class="h-[626px] bg-gradient-to-b from-[#22201E] to-[#191818] m-[14px] p-[14px]"
+        style="border-radius: 16px"
+      >
+        <div
+          class="flex justify-between items-center pb-[20px]"
+          v-for="item in otherTop"
+          :key="item.rank1"
+        >
+          <div class="w-[20%] color-[#666] text-center font-size-[18px] fw-700">
+            {{ item.rank1 >= 10 ? item.rank1 : '0' + item.rank1 }}
+          </div>
+          <div class="w-[50%] flex items-center">
+            <wd-img :src="item.avatar" width="44" height="44"></wd-img>
+            <div class="color-[#fff] font-size-[16px] fw-400 lh-[26px] ml-[10px]">
+              {{ item.name }}
+            </div>
+          </div>
+          <div class="w-[30%] text-center font-size-[14px] fw-500 color-[#BDBDBD]">
+            {{ dayjs(item.acquisitionTime).format('YYYY-MM-DD') }}
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss">
+.sign-bg1 {
+  border-radius: 20px;
+  border: 1px solid #e5c57f;
+  background: linear-gradient(90deg, #f9a939 0%, #d37c2b 100%);
+}
+.sign-bg2 {
+  border-radius: 18.603px;
+  border: 0.75px solid #d5e8ff;
+  background: linear-gradient(90deg, #d9e4f7 0%, #a8b9d3 100%);
+}
+.sign-bg3 {
+  border-radius: 18.603px;
+  border: 1px solid #dcc4ba;
+  background: linear-gradient(90deg, #fce7dc 0%, #c39f98 100%);
+}
+</style>

+ 2 - 0
packages/app/src/types/uni-pages.d.ts

@@ -59,7 +59,9 @@ interface NavigateToOptions {
        "/pages/mine/homepage/edit/index" |
        "/pages/mine/homepage/qr-code/index" |
        "/pages/mine/homepage/statistics/index" |
+       "/pages/mine/honors/detail/collection" |
        "/pages/mine/honors/detail/index" |
+       "/pages/mine/honors/leaderboard/index" |
        "/pages/mine/levels/rules/index" |
        "/pages/mine/orders/code/index" |
        "/pages/mine/orders/detail/index" |

+ 1 - 1
packages/merchant/src/core/libs/requests.ts

@@ -94,7 +94,7 @@ export const getOrders = (query: {}) =>
       points: string
       orderImgUrl?: string
       orderStatus: string
-      verifyTime: any
+      verifyTime: string | any
       completeTime?: number
       turnDownTime: any
       cancelTime?: number

+ 8 - 0
packages/merchant/src/pages.json

@@ -239,6 +239,14 @@
       }
     },
     {
+      "path": "pages/agent/designer/archives/award/imgs",
+      "type": "page",
+      "style": {
+        "navigationBarTitleText": "个人照片",
+        "navigationBarBackgroundColor": "#fff"
+      }
+    },
+    {
       "path": "pages/agent/designer/archives/basic-info/index",
       "type": "page",
       "style": {

+ 31 - 18
packages/merchant/src/pages/mine/index.vue

@@ -86,6 +86,7 @@ const radioChange = (value: number) => {
   }
 }
 function handleConfirm({ value }) {
+  verifyTime.value = value
   if (value.length) {
     filterQuery.value.verifyTime = `${dayjs(value[0]).format('YYYY-MM-DD hh:mm:ss')},${dayjs(value[1]).format('YYYY-MM-DD hh:mm:ss')}`
     console.log(filterQuery.value.verifyTime)
@@ -118,6 +119,7 @@ onPageScroll(({ scrollTop }: { scrollTop: number }) => {
     <template v-if="isAgent">
       <AgentMine></AgentMine>
     </template>
+
     <template v-if="isMerchant">
       <view class="p-[16px]">
         <div class="aspect-[1.575/1] absolute left-0 right-0 top-0">
@@ -243,15 +245,29 @@ onPageScroll(({ scrollTop }: { scrollTop: number }) => {
             </template>
           </wd-radio-group>
           <SectionHeading custom-class="my-[10px]" title="自定义"></SectionHeading>
-          <!-- <wd-button @click="openCalendar">打开日历</wd-button>
-          <wd-calendar ref="calendar" :with-cell="false" v-model="value" @confirm="handleConfirm" /> -->
-          <wd-datetime-picker
+          <div class="text-[#999] text-xs text-center child-value mt-[10px]" @click="openCalendar">
+            <text :class="[verifyTime[0] ? 'text-[#333]' : 'text-[#999]']">
+              {{ verifyTime[0] ? dayjs(verifyTime[0]).format('YYYY-MM-DD') : '开始时间' }}
+            </text>
+            <view class="w-[10%]">至</view>
+            <text :class="[verifyTime[0] ? 'text-[#333]' : 'text-[#999]']">
+              {{ verifyTime[1] ? dayjs(verifyTime[1]).format('YYYY-MM-DD') : '结束时间' }}
+            </text>
+          </div>
+          <wd-calendar
+            ref="calendar"
+            type="daterange"
+            :with-cell="false"
+            v-model="verifyTime"
+            @confirm="handleConfirm"
+          />
+          <!-- <wd-datetime-picker
             custom-value-class="text-[#333] child-value w=[100%]"
             :disabled="filterQuery.dateTimeType !== 4"
             v-model="verifyTime"
             type="date"
             @confirm="handleConfirm"
-          ></wd-datetime-picker>
+          ></wd-datetime-picker> -->
           <SectionHeading custom-class="my-[10px]" title="订单状态"></SectionHeading>
           <wd-radio-group cell shape="button" v-model="filterQuery.orderStatus">
             <template
@@ -287,20 +303,17 @@ onPageScroll(({ scrollTop }: { scrollTop: number }) => {
 ::v-deep .wd-radio__label {
   line-height: 30px !important;
 }
-::v-deep .child-value {
-  > view,
-  > div {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    > text {
-      display: inline-block;
-      width: 40%;
-      padding-left: 10px;
-      line-height: 30px;
-      background-color: #f0f0f0;
-      border-radius: 4px;
-    }
+.child-value {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  > text {
+    display: inline-block;
+    width: 40%;
+    padding-left: 10px;
+    line-height: 30px;
+    background-color: #f0f0f0;
+    border-radius: 4px;
   }
 }
 </style>

+ 1 - 0
packages/merchant/src/types/uni-pages.d.ts

@@ -27,6 +27,7 @@ interface NavigateToOptions {
        "/pages/common/orders/detail/index" |
        "/pages/mine/agent/invite/index" |
        "/pages/mine/agent/settings/index" |
+       "/pages/agent/designer/archives/award/imgs" |
        "/pages/agent/designer/archives/basic-info/index" |
        "/pages/agent/designer/archives/sale-info/index" |
        "/pages/mine/merchant/orders/detail/index" |