EvilDragon пре 6 месеци
родитељ
комит
4563cea5f4

+ 2 - 0
packages/app/package.json

@@ -103,6 +103,8 @@
     "@designer-hub/merchant": "workspace:*",
     "czg": "^1.9.3",
     "dayjs": "1.11.10",
+    "extract-colors": "^4.1.0",
+    "miniapp-color-thief": "^1.0.5",
     "pinia": "2.0.36",
     "pinia-plugin-persistedstate": "3.2.1",
     "qs": "6.5.3",

+ 28 - 0
packages/app/src/core/utils/common.ts

@@ -50,3 +50,31 @@ export const getActivityStatusButtonText = (startAt: string | number, endAt: str
   ({ running: '立即报名', waiting: '查看详情', overdue: '查看详情' })[
     getActivityStatus(startAt, endAt)
   ]
+export const getCountsArr = (data, imgWidth, imgHeight) => {
+  let r = 1
+  let g = 1
+  let b = 1
+  // 获取所有像素的累加值
+  for (let row = 0; row < imgHeight; row++) {
+    for (let col = 0; col < imgWidth; col++) {
+      if (row == 0) {
+        r += data[imgWidth * row + col]
+        g += data[imgWidth * row + col + 1]
+        b += data[imgWidth * row + col + 2]
+      } else {
+        r += data[(imgWidth * row + col) * 4]
+        g += data[(imgWidth * row + col) * 4 + 1]
+        b += data[(imgWidth * row + col) * 4 + 2]
+      }
+    }
+  }
+  // 求rgb平均值
+  r /= imgWidth * imgHeight
+  g /= imgWidth * imgHeight
+  b /= imgWidth * imgHeight
+  // 四舍五入
+  r = Math.round(r)
+  g = Math.round(g)
+  b = Math.round(b)
+  return [r, g, b].join(',')
+}

+ 52 - 6
packages/app/src/pages/home/activity/detail/index.vue

@@ -12,7 +12,7 @@ import { bell, map, rightFill } from '@designer-hub/assets/src/assets/svgs'
 import TiltedButton from '@/components/tilted-button.vue'
 import dayjs from 'dayjs'
 import BottomAppBar from '@/components/bottom-app-bar.vue'
-import { useRouter } from '../../../../core/utils/router'
+import { back, useRouter } from '../../../../core/utils/router'
 import PageHelper from '@/components/page-helper.vue'
 import { ConfigProviderThemeVars } from 'wot-design-uni'
 import SectionHeading from '@/components/section-heading.vue'
@@ -21,7 +21,10 @@ import { calendar, clock, funnel, location, user } from '@designer-hub/assets/sr
 import { signupSuccessDialogBg } from '@designer-hub/assets/src/bgs'
 import { NetImages } from '../../../../core/libs/net-images'
 import signupListDialogBg from '@designer-hub/assets/src/libs/assets/signupListDialogBg'
-import { getActivityStatusText } from '../../../../core/utils/common'
+import { getActivityStatusText, getCountsArr } from '../../../../core/utils/common'
+import colorThief from 'miniapp-color-thief'
+import { extractColors, extractColorsFromImageData } from 'extract-colors/lib/extract-colors.mjs'
+import { sort, orderBy } from 'radash'
 
 const themeVars = ref<ConfigProviderThemeVars>({
   tableBorderColor: 'white',
@@ -40,6 +43,8 @@ const { data: signups, run: setSignups } = useRequest(
 const show = ref(false)
 const successShow = ref(false)
 const listShow = ref(false)
+const dominantColor = ref()
+const palette = ref()
 const isActivity = computed(() => type.value === 'activity')
 const isStudyTour = computed(() => type.value === 'studyTour')
 const infos = computed(() => [
@@ -76,7 +81,7 @@ const infos = computed(() => [
   {
     icon: funnel,
     title: `等级限制`,
-    content: [data.value.memberLevel.join('、')],
+    content: [data.value.memberLevel?.join('、')],
     visable: true,
   },
 ])
@@ -94,18 +99,59 @@ onLoad(async (query: { id: string; type: 'activity' }) => {
   id.value = query.id
   type.value = query.type
   await setData()
-  console.log(data.value)
+  const { path } = await uni.getImageInfo({ src: data.value.backgroundUrl })
+  const ctx = uni.createCanvasContext('firstCanvas')
+  uni
+    .createSelectorQuery()
+    .select('#firstCanvas')
+    .fields({ size: true }, async ({ width, height }: any) => {
+      // ctx.setFillStyle('#ffffff')
+      ctx.drawImage(path, 0, 0, width, height)
+      ctx.draw(true, async () => {
+        const res1 = await uni.canvasGetImageData({
+          canvasId: 'firstCanvas',
+          x: 0,
+          y: 0,
+          width: width.toFixed(0),
+          height: height.toFixed(0),
+        })
+        const { data: imageData } = res1
+        dominantColor.value = `rgb(${getCountsArr(imageData, width, height)})`
+        const a = await extractColorsFromImageData(
+          {
+            data: [...imageData],
+            width: width.toFixed(0),
+            height: height.toFixed(0),
+          },
+          {
+            pixels: 64000,
+            distance: 0.22,
+            colorValidator: (red, green, blue, alpha = 255) => alpha > 250,
+            saturationDistance: 0.2,
+            lightnessDistance: 0.2,
+            hueDistance: 0.083333333,
+          },
+        )
+        console.log(a)
+        const colors = sort(a, (it: any) => it.intensity, true)
+        dominantColor.value = a[0].hex
+      })
+    })
+    .exec()
   await setSignups()
 })
 </script>
 <template>
   <div
     class="flex-grow bg-white px-3.5 bg-[length:100%_100%]"
-    :style="{ backgroundImage: `url(${data.backgroundUrl})` }"
+    :style="{
+      backgroundColor: `${dominantColor}`,
+    }"
   >
     <NavbarEvo transparent dark></NavbarEvo>
     <div class="aspect-[1.26/1] relative mx--3.5">
-      <wd-img width="100%" height="100%" :src="data.bannerUrl?.at(0)"></wd-img>
+      <!-- <wd-img width="100%" height="100%" :src="data.bannerUrl?.at(0)"></wd-img> -->
+      <canvas class="w-full h-full" canvas-id="firstCanvas" id="firstCanvas"></canvas>
       <div class="absolute left-3.5 bottom-3" @click="listShow = true">
         <div
           v-if="isStudyTour"

+ 9 - 4
packages/app/src/pages/home/components/register-card.vue

@@ -1,9 +1,9 @@
 <script lang="ts" setup>
 import Card from '@/components/card.vue'
-import { Activity } from '../../../core/models/moment'
+import { Activity, DictType } from '../../../core/models/moment'
 import dayjs from 'dayjs'
 import TiltedButton from '@/components/tilted-button.vue'
-import { getActivitySignups } from '../../../core/libs/requests'
+import { getActivitySignups, getByDictType } from '../../../core/libs/requests'
 import { NetImages } from '../../../core/libs/net-images'
 import { useRouter } from '../../../core/utils/router'
 import { getActivityStatusButtonText, getActivityStatusText } from '../../../core/utils/common'
@@ -14,6 +14,7 @@ const { data: signups, run: setSignups } = useRequest(
   () => getActivitySignups({ activityId: props.options!.id.toString() }),
   { initialData: { list: [], total: 0 } },
 )
+// const {} = useRequest(() => getByDictType(DictType))
 onMounted(async () => {
   await setSignups()
 })
@@ -33,7 +34,7 @@ onMounted(async () => {
         class="w-[63px] h-[29px] bg-black/60 rounded-[20px] backdrop-blur-[15px] absolute top-5 right-3.5 flex items-center justify-center"
       >
         <div class="text-white text-sm font-normal font-['PingFang_SC'] leading-relaxed">
-          {{ getActivityStatusText(options?.applyStartTime, options?.activityEndTime) }}
+          {{ getActivityStatusText(options?.applyStartTime, options?.applyEndTime) }}
         </div>
       </div>
       <view class="absolute bottom-0 left-0 right-0">
@@ -83,7 +84,11 @@ onMounted(async () => {
               <div class="ml-1 text-white/60 text-sm font-normal font-['PingFang_SC']">积分</div>
             </view>
             <tilted-button custom-class="" size="large" color="white">
-              {{ getActivityStatusButtonText(options?.applyStartTime, options?.activityEndTime) }}
+              {{
+                options?.ifSingnUp
+                  ? '已报名'
+                  : getActivityStatusButtonText(options?.applyStartTime, options?.activityEndTime)
+              }}
             </tilted-button>
           </view>
         </div>

+ 5 - 4
packages/app/src/pages/home/offline-activity/list/index.vue

@@ -9,7 +9,7 @@ import TiltedButton from '@/components/tilted-button.vue'
 import { useRouter } from '../../../../core/utils/router'
 import dayjs from 'dayjs'
 import ActivityCountDown from '../../components/activity-count-down.vue'
-import { getActivityStatus } from '../../../../core/utils/common'
+import { getActivityStatus, getActivityStatusButtonText } from '../../../../core/utils/common'
 import { DictType } from '../../../../core/models/moment'
 
 const tab = ref<number>(0)
@@ -34,6 +34,7 @@ onMounted(async () => {
       v-if="tabs.length"
       :request="getActivities"
       :query="{ activityType: tabs[tab].value }"
+      class="flex flex-col flex-grow"
     >
       <template #default="{ source }">
         <div class="flex flex-col gap-6">
@@ -123,9 +124,9 @@ onMounted(async () => {
                     </view>
                     <tilted-button>
                       {{
-                        getActivityStatus(it.applyStartTime, it.applyEndTime) === 'running'
-                          ? '立即报名'
-                          : '查看详情'
+                        it.ifSingnUp
+                          ? '报名'
+                          : getActivityStatusButtonText(it.applyStartTime, it.applyEndTime)
                       }}
                     </tilted-button>
                   </view>

+ 24 - 0
pnpm-lock.yaml

@@ -67,6 +67,12 @@ importers:
       dayjs:
         specifier: 1.11.10
         version: 1.11.10
+      extract-colors:
+        specifier: ^4.1.0
+        version: 4.1.0
+      miniapp-color-thief:
+        specifier: ^1.0.5
+        version: 1.0.5
       pinia:
         specifier: 2.0.36
         version: 2.0.36(typescript@4.9.5)(vue@3.4.21(typescript@4.9.5))
@@ -5035,6 +5041,9 @@ packages:
   extend@3.0.2:
     resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
 
+  extract-colors@4.1.0:
+    resolution: {integrity: sha512-BWZxUwpYra1G91rnq/xxuhVNkkbixdi74xdlebo6744lXYx8SUsOMdFU9FQGoVJZpEmcXC9dXS3lc0/8WyNVkw==}
+
   extsprintf@1.3.0:
     resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==}
     engines: {'0': node >=0.6.0}
@@ -6476,6 +6485,9 @@ packages:
     resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
     engines: {node: '>=4'}
 
+  miniapp-color-thief@1.0.5:
+    resolution: {integrity: sha512-vBfmh8rY1pYeRSFi3RPCkp4ExtFtrdbye/qYs/XTgrt4qpIlIRAC4XynSJRd1KumGFAKi8UUN/spxw2BqcSTBg==}
+
   minicode-compile-bundled@2.11.26:
     resolution: {integrity: sha512-kiV08PMB7mNvhDlOHfJri/QFYfUv5auke8oJOlt89E0ZgF5mzffc3dMgu+JqCVi/VCNxrSSI5M7f6X3w2FlGNQ==}
 
@@ -7339,6 +7351,10 @@ packages:
     resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==}
     engines: {node: '>=0.6'}
 
+  quantize@1.0.2:
+    resolution: {integrity: sha512-25P7wI2UoDbIQsQp50ARkt+5pwPsOq7G/BqvT5xAbapnRoNWMN8/p55H9TXd5MuENiJnm5XICB2H2aDZGwts7w==}
+    engines: {node: '>=0.10.21'}
+
   query-string@5.1.1:
     resolution: {integrity: sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==}
     engines: {node: '>=0.10.0'}
@@ -15690,6 +15706,8 @@ snapshots:
 
   extend@3.0.2: {}
 
+  extract-colors@4.1.0: {}
+
   extsprintf@1.3.0: {}
 
   fast-deep-equal@3.1.3: {}
@@ -17332,6 +17350,10 @@ snapshots:
 
   min-indent@1.0.1: {}
 
+  miniapp-color-thief@1.0.5:
+    dependencies:
+      quantize: 1.0.2
+
   minicode-compile-bundled@2.11.26: {}
 
   minidev@1.9.5:
@@ -18313,6 +18335,8 @@ snapshots:
 
   qs@6.5.3: {}
 
+  quantize@1.0.2: {}
+
   query-string@5.1.1:
     dependencies:
       decode-uri-component: 0.2.2