Browse Source

feat:首页完成

st 2 months ago
parent
commit
5e31d280b0

+ 2 - 1
.eslintrc-auto-import.json

@@ -101,6 +101,7 @@
     "onWatcherCleanup": true,
     "useId": true,
     "useModel": true,
-    "useTemplateRef": true
+    "useTemplateRef": true,
+    "useGameTimer": true
   }
 }

+ 4 - 3
package.json

@@ -79,6 +79,7 @@
     "@telegram-apps/sdk-vue": "^1.0.1",
     "@twa-dev/sdk": "^7.10.1",
     "@vueuse/core": "^12.0.0",
+    "crypto-js": "^4.1.1",
     "dayjs": "1.11.10",
     "lodash": "^4.17.21",
     "lottie-web": "^5.12.2",
@@ -86,14 +87,14 @@
     "pinia": "2.0.36",
     "pinia-plugin-persistedstate": "3.2.1",
     "qs": "6.5.3",
+    "sm-crypto": "^0.3.13",
     "vconsole": "^3.15.1",
     "vue": "3.4.21",
     "vue-clipboard3": "^2.0.0",
+    "vue-countup-v3": "^1.4.2",
     "vue-i18n": "^9.1.9",
     "wot-design-uni": "^1.3.12",
-    "z-paging": "^2.7.10",
-    "crypto-js": "^4.1.1",
-    "sm-crypto": "^0.3.13"
+    "z-paging": "^2.7.10"
   },
   "devDependencies": {
     "@commitlint/cli": "^18.6.1",

+ 167 - 0
src/hooks/useGameTimer.ts

@@ -0,0 +1,167 @@
+import { ref, computed, watch } from 'vue'
+import {
+  getBoostResidueTimes,
+  getGoldCoinProductState,
+  ProductionPlayIncreaseInterface,
+  startCoinGame,
+  UserCenter,
+} from '@/service/index/foo'
+
+const TWELVE_HOURS = 12 * 60 * 60 // 12 hours in seconds
+const REFRESH_INTERVAL = 10 // 10 seconds
+
+export const useGameTimer = () => {
+  const currentLibaoData = ref<UserCenter>({} as UserCenter)
+  const playData = ref<ProductionPlayIncreaseInterface>({} as ProductionPlayIncreaseInterface)
+  const displayTime = ref('00h 00m 00s')
+  const gamePlayTime = ref('00h 00m 00s')
+  const percentage = ref(0)
+  const isAnimating = ref(false)
+
+  let countdownTimer: number | null = null
+  let refreshTimer: number | null = null
+  let playTimer: number | null = null
+
+  const libaoShow = computed(() => {
+    return currentLibaoData.value.status === 0 || currentLibaoData.value.status === 2
+  })
+
+  const formatDisplayTime = (seconds: number): string => {
+    if (
+      !seconds ||
+      isNaN(seconds) ||
+      seconds <= 0 ||
+      currentLibaoData.value.status === 0 ||
+      currentLibaoData.value.status === 2
+    ) {
+      return '00h 00m 00s'
+    }
+    seconds = Math.min(seconds, TWELVE_HOURS)
+    const hours = Math.floor(seconds / 3600)
+    const minutes = Math.floor((seconds % 3600) / 60)
+    const remainingSecs = Math.round(seconds % 60)
+
+    return `${hours.toString().padStart(2, '0')}h ${minutes.toString().padStart(2, '0')}m ${remainingSecs.toString().padStart(2, '0')}s`
+  }
+
+  const updateTimerAndProgress = () => {
+    if (currentLibaoData.value.status === 1 && currentLibaoData.value.residueTimestamp > 0) {
+      currentLibaoData.value.residueTimestamp--
+      displayTime.value = formatDisplayTime(currentLibaoData.value.residueTimestamp)
+      percentage.value =
+        ((TWELVE_HOURS - currentLibaoData.value.residueTimestamp) / TWELVE_HOURS) * 100
+      isAnimating.value = false
+    } else if (currentLibaoData.value.status === 0 || currentLibaoData.value.status === 2) {
+      displayTime.value = '00h 00m 00s'
+      percentage.value = currentLibaoData.value.status === 2 ? 100 : 0
+      isAnimating.value = true
+    } else {
+      stopTimers()
+      refreshGameState()
+    }
+  }
+  const updateGamePlayTime = async () => {
+    if (!playData.value.temporaryRate) {
+      gamePlayTime.value = '00h 00m 00s'
+    }
+    if (playData.value.boostResidueTimestamp > 0) {
+      playData.value.boostResidueTimestamp--
+      gamePlayTime.value = formatDisplayTime(playData.value.boostResidueTimestamp)
+    } else {
+      gamePlayTime.value = '00h 00m 00s'
+      clearInterval(playTimer)
+    }
+  }
+  const initPlayGame = async () => {
+    const { data } = await getBoostResidueTimes()
+    playData.value = data
+  }
+  const refreshGameState = async () => {
+    try {
+      const { data } = await getGoldCoinProductState()
+      currentLibaoData.value = data
+      if (currentLibaoData.value.status === 1) {
+        startTimers()
+        isAnimating.value = false
+      } else if (currentLibaoData.value.status === 0 || currentLibaoData.value.status === 2) {
+        displayTime.value = '00h 00m 00s'
+        percentage.value = currentLibaoData.value.status === 2 ? 100 : 0
+        isAnimating.value = true
+        stopTimers()
+      } else {
+        stopTimers()
+        percentage.value = 0
+        isAnimating.value = false
+      }
+      await initPlayGame()
+    } catch (error) {
+      console.error('Failed to refresh game state:', error)
+    }
+  }
+
+  const startTimers = () => {
+    stopTimers() // Ensure any existing timers are stopped
+    countdownTimer = setInterval(updateTimerAndProgress, 1000)
+    refreshTimer = setInterval(refreshGameState, REFRESH_INTERVAL * 1000)
+    playTimer = setInterval(updateGamePlayTime, 1000)
+  }
+
+  const stopTimers = () => {
+    if (countdownTimer) {
+      clearInterval(countdownTimer)
+      countdownTimer = null
+    }
+    if (refreshTimer) {
+      clearInterval(refreshTimer)
+      refreshTimer = null
+    }
+    if (playTimer) {
+      clearInterval(playTimer)
+      playTimer = null
+    }
+  }
+
+  const restartGame = async () => {
+    try {
+      // 调用后端 API 来重新开始游戏
+      await startCoinGame()
+      // 重新获取游戏状态
+      await refreshGameState()
+    } catch (error) {
+      console.error('Failed to restart game:', error)
+      // 这里可以添加错误处理逻辑,比如显示一个错误通知
+    }
+  }
+
+  watch(
+    () => currentLibaoData.value.status,
+    (newStatus) => {
+      if (newStatus === 1) {
+        startTimers()
+        isAnimating.value = false
+      } else if (newStatus === 0 || newStatus === 2) {
+        stopTimers()
+        percentage.value = newStatus === 2 ? 100 : 0
+        displayTime.value = '00h 00m 00s'
+        isAnimating.value = true
+      } else {
+        stopTimers()
+        percentage.value = 0
+        isAnimating.value = false
+      }
+    },
+  )
+
+  return {
+    currentLibaoData,
+    displayTime,
+    percentage,
+    isAnimating,
+    libaoShow,
+    refreshGameState,
+    stopTimers,
+    restartGame,
+    gamePlayTime,
+    playData,
+  }
+}

+ 179 - 271
src/pages/index/index.vue

@@ -56,22 +56,31 @@
     </view>
     <view class="w-690rpx mt-15rpx h-90rpx w-full flex items-center justify-center text-white">
       <image src="@/static/images/trophy/jinbi.png" class="w-60rpx h-60rpx mr-10rpx"></image>
-      <text class="text-[60rpx] font-700 mr-10rpx" ref="goldCoinEl">
-        {{ currentLibaoData.currentValue }}
-      </text>
+      <count-up
+        ref="goldCoinEl"
+        class="text-[60rpx] font-700 mr-10rpx"
+        :end-val="currentLibaoData.currentValue || 0"
+        :duration="1"
+        :options="options"
+      />
       <text class="text-24rpx font-400 pt-20rpx">BHCoin</text>
     </view>
     <view
       id="lottieContainer"
       class="w-690rpx flex items-center justify-center mt-30rpx h-557rpx"
       @click="tishiShow = true"
-    >
-      <!--      <image src="@/static/images/production/cat.png" class="w-250rpx h-557rpx"></image>-->
-    </view>
-    <view class="w-full flex items-center justify-center mt-20rpx">
+    ></view>
+    <view class="w-full flex items-center justify-center mt-20rpx relative">
       <view class="custrom-bg w-650rpx flex text-white items-center">
         <wd-progress :percentage="percentage" hide-text :duration="0.1" />
       </view>
+      <view
+        @click.stop="goPage('/pages/play/index')"
+        class="absolute right-50rpx bottom-100rpx libao-scale flex flex-col items-center z-10"
+      >
+        <image src="@/static/images/production/maozhuao.png" class="w-100rpx h-100rpx"></image>
+        <text class="text-28rpx font-700 text-white">game</text>
+      </view>
     </view>
     <view class="w-650rpx flex items-center justify-between mt-20rpx">
       <view class="flex items-center">
@@ -85,7 +94,6 @@
       </view>
     </view>
     <view class="w-650rpx flex items-center mt-20rpx justify-between">
-      <!--      @click="goPage('/pages/play/index')"-->
       <view
         @click="startGame"
         class="w-310rpx h-80rpx flex items-center justify-center relative bg-#111 rounded-20rpx"
@@ -97,7 +105,7 @@
         </text>
       </view>
       <view
-        @click="shengjiShow = true"
+        @click="shengji"
         class="w-310rpx h-80rpx flex items-center justify-center relative bg-#111 rounded-20rpx"
       >
         <image src="@/static/images/production/btn.png" class="w-310rpx h-80rpx absolute"></image>
@@ -113,16 +121,20 @@
         src="@/static/images/production/playbg.png"
         class="w-243rpx h-44rpx absolute left-36rpx"
       ></image>
-      <view class="flex items-center justify-center z-1 ml-77rpx mt-10rpx">
+      <view class="w-full flex items-center justify-start z-1 ml-55rpx mt-10rpx">
         <image
           src="@/static/images/production/shangsheng.png"
           class="w-14rpx h-19rpx mr-10rpx"
         ></image>
-        <text class="text-18rpx font-400 text-white">08:01:11(+0.02/s)</text>
+        <text class="text-18rpx font-400 text-white">
+          {{ gamePlayTime }}(+{{
+            playData.temporaryRate
+              ? (playData.temporaryRate ? playData.temporaryRate / 100 : 0).toFixed(2)
+              : 0
+          }}/s)
+        </text>
       </view>
     </view>
-    <!--    <view id="lottieContainer" class="box"></view>-->
-    <!--    <button @click="show = !show">Solana Wallet</button>-->
   </view>
   <!-- 语言 -->
   <wd-popup v-model="show" position="top">
@@ -153,15 +165,22 @@
       </view>
     </view>
   </wd-popup>
-  <Dialog v-model:show-value="shengjiShow" position="bottom" width="690rpx" height="672rpx">
-    <view class="w-full flex flex-col items-center">
+  <Dialog
+    v-model:show-value="shengjiShow"
+    position="bottom"
+    width="690rpx"
+    :height="uprule.status !== 1 ? '672rpx' : '400rpx'"
+  >
+    <view class="w-full flex flex-col items-center" v-if="uprule.status !== 1">
       <text class="text-white mt-90rpx text-36rpx font-700">Speed up the process!</text>
       <view
         class="w-650rpx h-150rpx flex bg-cards rounded-20rpx items-center justify-between mt-30rpx"
       >
         <view class="flex flex-col text-primary ml-20rpx">
-          <text class="text-42rpx font-700 h-63rpx">BH 0</text>
-          <text class="font-400 text-24rpx mt-10rpx">360 HB Coin/H</text>
+          <text class="text-42rpx font-700 h-63rpx">BH {{ uprule.list[0].level }}</text>
+          <text class="font-400 text-24rpx mt-10rpx">
+            {{ uprule.list[0].numericalValueHour }} HB Coin/H
+          </text>
         </view>
         <image
           src="@/static/images/production/maozhuao.png"
@@ -172,8 +191,10 @@
         class="w-650rpx h-280rpx flex flex-col bg-cards rounded-20rpx items-center justify-around mt-30rpx"
       >
         <view class="flex items-center justify-between text-white w-full">
-          <text class="text-42rpx font-700 ml-20rpx">BH 1</text>
-          <text class="text-24rpx font-400 mr-20rpx">720 HB Coin/H</text>
+          <text class="text-42rpx font-700 ml-20rpx">BH {{ uprule.list[1].level }}</text>
+          <text class="text-24rpx font-400 mr-20rpx">
+            {{ uprule.list[1].numericalValueHour }} HB Coin/H
+          </text>
         </view>
         <view class="w-full flex items-center justify-around">
           <view
@@ -181,11 +202,9 @@
           >
             <view class="flex items-center w-full justify-start ml-30rpx">
               <image src="@/static/images/purse/u.png" class="w-30rpx h-30rpx mr-10rpx"></image>
-              <text class="text-24rpx font-400 text-white">100</text>
+              <text class="text-24rpx font-400 text-white">{{ uprule.list[1].realMoney }}</text>
             </view>
-            <view
-              class="w-245rpx h-60rpx bg-primary rounded-20rpx flex items-center justify-center"
-            >
+            <view class="w-245rpx h-60rpx bg-gray rounded-20rpx flex items-center justify-center">
               <text class="text-26rpx font-700 text-textc">Upgrade</text>
             </view>
           </view>
@@ -197,9 +216,12 @@
                 src="@/static/images/trophy/jinbi.png"
                 class="w-30rpx h-30rpx mr-10rpx"
               ></image>
-              <text class="text-24rpx font-400 text-white">100</text>
+              <text class="text-24rpx font-400 text-white">
+                {{ uprule.list[1].consumeGoldCoin }}
+              </text>
             </view>
             <view
+              @click="upRules('coin')"
               class="w-245rpx h-60rpx bg-primary rounded-20rpx flex items-center justify-center"
             >
               <text class="text-26rpx font-700 text-textc">Upgrade</text>
@@ -208,6 +230,23 @@
         </view>
       </view>
     </view>
+    <view v-else class="w-full flex flex-col items-center justify-center">
+      <text class="text-white mt-90rpx text-36rpx font-700">level is top!</text>
+      <view
+        class="w-650rpx h-200rpx flex bg-cards rounded-20rpx items-center justify-between mt-30rpx"
+      >
+        <view class="flex flex-col text-primary ml-20rpx">
+          <text class="text-42rpx font-700 h-63rpx">BH {{ uprule.list[0].level }}</text>
+          <text class="font-400 text-24rpx mt-10rpx">
+            {{ uprule.list[0].numericalValueHour }} HB Coin/H
+          </text>
+        </view>
+        <image
+          src="@/static/images/production/maozhuao.png"
+          class="w-90rpx h-90rpx mr-20rpx"
+        ></image>
+      </view>
+    </view>
   </Dialog>
   <Dialog v-model:show-value="tishiShow" width="690rpx" height="577rpx">
     <view class="w-full flex flex-col items-center">
@@ -287,127 +326,57 @@
 import i18n, { t } from '@/locale/index'
 import { useLaunchParams } from '@telegram-apps/sdk-vue'
 import lottie from 'lottie-web'
-import animationData from '@/static/Animation.json'
+import animationData from '@/static/data.json'
 import Dialog from '@/components/common/Dialog/index.vue'
 import { useUserStore } from '@/store/user'
 import tabbar from '@/components/TabBar/index.vue'
 import { useNotify } from 'wot-design-uni'
 import { useImgPath } from '@/hooks/useImgPath'
+import { useGameTimer } from '@/hooks/useGameTimer'
 import {
-  getGoldCoinProductState,
+  getRateUpgradesRules,
+  ProductionIncreaseInterface,
   stageCoinAdd,
-  startCoinGame,
-  UserCenter,
+  updateGoldCoinProductRate,
 } from '@/service/index/foo'
+import CountUp from 'vue-countup-v3'
+
+const {
+  currentLibaoData,
+  displayTime,
+  percentage,
+  isAnimating,
+  libaoShow,
+  refreshGameState,
+  restartGame,
+  stopTimers,
+  gamePlayTime,
+  playData,
+} = useGameTimer()
 const { getAssetsImages } = useImgPath()
 const { showNotify } = useNotify()
-
+const options = ref({
+  decimalPlaces: 0, // 保留小数位数
+  useEasing: true, // 是否使用缓动效果
+  separator: ',',
+  useGrouping: true,
+})
 // 用户信息
 const pl = useLaunchParams()
 const useStore = useUserStore()
 const initUser = async (user: any, shareCode: string) => {
-  const data = await useStore.setUserInfo(user, shareCode)
-}
-
-// 获取当前礼包数据
-const currentLibaoData = ref<UserCenter>({} as UserCenter)
-const getGoldCoinProduct = async () => {
-  const { data } = await getGoldCoinProductState()
-  currentLibaoData.value = data
-}
-const isAnimating = ref(false)
-// 是否有动画
-const libaoShow = computed(() => {
-  return currentLibaoData.value.status === 0 || currentLibaoData.value.status === 2
-})
-watch(
-  () => libaoShow.value,
-  (newValue) => {
-    isAnimating.value = newValue
-  },
-)
-const formatDisplayTime = (seconds: number): string => {
-  if (!seconds || isNaN(seconds)) {
-    return '00h 00m 00s'
-  }
-  if (currentLibaoData.value.status === 0 || currentLibaoData.value.status === 2) {
-    return '00h 00m 00s'
-  }
-  // 限制最大时间为12小时
-  seconds = Math.min(seconds, TWELVE_HOURS)
-  // 如果小于0,返回0
-  seconds = Math.max(0, seconds)
-  const hours = Math.floor(seconds / 3600)
-  const minutes = Math.floor((seconds % 3600) / 60)
-  const remainingSecs = seconds % 60
-  return `${hours.toString().padStart(2, '0')}h ${minutes.toString().padStart(2, '0')}m ${remainingSecs.toString().padStart(2, '0')}s`
-}
-const percentage = ref(0) // 进度条
-const TWELVE_HOURS = 12 * 60 * 60 // 12小时的秒数
-const remainingSeconds = ref(0)
-const lastRefreshTime = ref(0)
-const REFRESH_INTERVAL = 10000
-const progressTimer = ref<number | null>(null)
-const initDisplayTime = () => {
-  if (currentLibaoData.value?.status === 1 && currentLibaoData.value?.startTimestamp) {
-    const currentTimestamp = Math.floor(Date.now() / 1000)
-    const startTime = currentLibaoData.value.startTimestamp
-    // 计算已经过去的时间
-    let elapsedTime: number
-    // 如果服务器返回的 endTimestamp 不为 0,优先使用服务器时间
-    if (currentLibaoData.value.endTimestamp) {
-      elapsedTime = currentLibaoData.value.endTimestamp - startTime
-    } else {
-      // 使用本地时间计算,但需要校验
-      elapsedTime = currentTimestamp - startTime
-    }
-    // 检查是否超过12小时
-    if (elapsedTime >= TWELVE_HOURS) {
-      // 如果超过12小时,说明游戏应该已经结束
-      remainingSeconds.value = 0
-      displayTime.value = '00h 00m 00s'
-
-      // 停止所有计时器并刷新状态
-      stopAllTimers()
-      // refreshData()
-    } else if (elapsedTime < 0) {
-      // 如果出现负数时间(比如服务器时间与本地时间不同步)
-      // 使用服务器时间或重置为0
-      remainingSeconds.value = TWELVE_HOURS
-      displayTime.value = formatDisplayTime(TWELVE_HOURS)
-    } else {
-      // 正常情况:计算剩余时间
-      remainingSeconds.value = TWELVE_HOURS - elapsedTime
-      displayTime.value = formatDisplayTime(remainingSeconds.value)
-    }
-  } else {
-    // 游戏未开始或已结束
-    remainingSeconds.value = 0
-    displayTime.value = '00h 00m 00s'
-  }
+  await useStore.setUserInfo(user, shareCode)
 }
 // 开始游戏
 const startGame = async () => {
   if (currentLibaoData.value.status === 2) {
     lingquShow.value = true
+  } else if (currentLibaoData.value.status === 1) {
+    tishiShow.value = true
   } else {
-    // stopAllTimers()
-
+    stopTimers()
     try {
-      if (currentLibaoData.value.status === 0) {
-        await startCoinGame()
-        await getGoldCoinProduct()
-        percentage.value = 0
-        // // 初始化显示时间
-        initDisplayTime()
-        //
-        // // 启动动画和计时器
-        isAnimating.value = false
-        startCountdown()
-        // startProgressAnimation()
-      } else {
-        tishiShow.value = true
-      }
+      await restartGame()
     } catch (error) {
       console.error('Failed to start game:', error)
       setTimeout(() => startGame(), 5000)
@@ -422,129 +391,21 @@ const lingqu = async () => {
     showNotify({ type: 'warning', message: msg })
   }
   lingquShow.value = false
-  await startCoinGame()
-  await getGoldCoinProduct()
-  if (currentLibaoData.value.status === 1) {
-    // 先停止所有计时器
-    stopAllTimers()
-    // 重新初始化显示时间
-    initDisplayTime()
-    // 重新启动动画和计时器
-    isAnimating.value = true
-    startCountdown()
-    startProgressAnimation()
-    // 更新最后刷新时间
-    lastRefreshTime.value = Date.now()
-  }
+  await restartGame()
 }
+
 watch(
-  () => currentLibaoData.value.status,
+  () => isAnimating.value,
   (newStatus) => {
-    console.info('🚀 ~ file:index method: line:443 -----', 11)
-    // 确保进度条状态正确
-    percentage.value = getProgressPercentage()
-    // 如果变成了进行中状态,启动动画
-    if (newStatus === 1) {
-      // isAnimating.value = false
-      startCountdown()
-      // startProgressAnimation()
-    } else {
-      // 其他状态停止动画
-      stopAllTimers()
-    }
+    nextTick(() => {
+      if (!newStatus) {
+        lottie.play()
+      } else {
+        lottie.pause()
+      }
+    })
   },
 )
-const startProgressAnimation = () => {
-  if (progressTimer.value) {
-    cancelAnimationFrame(progressTimer.value)
-  }
-
-  const updateProgress = async () => {
-    percentage.value = getProgressPercentage()
-
-    // 每10秒刷新一次数据
-    const now = Date.now()
-    if (now - lastRefreshTime.value >= REFRESH_INTERVAL) {
-      lastRefreshTime.value = now
-      await refreshData()
-    }
-
-    // 只有在游戏进行中状态才继续动画
-    if (currentLibaoData.value.status === 1) {
-      progressTimer.value = requestAnimationFrame(updateProgress)
-    }
-  }
-
-  updateProgress()
-}
-const refreshData = async () => {
-  const now = Date.now()
-  try {
-    // 更新最后刷新时间
-    lastRefreshTime.value = now
-    await getGoldCoinProduct()
-    // // 根据状态显示音符动画
-    // if (currentLibaoData.value.status === 1) {
-    //   showNote.value = true
-    //   setTimeout(() => {
-    //     showNote.value = false
-    //   }, 800)
-    // }
-    // 不再在这里停止计时器,让外部控制
-  } catch (error) {
-    console.error('Refresh failed:', error)
-    throw error // 向上传递错误
-  }
-}
-// countdown
-const countdownTimer = ref<number | null>(null)
-const startCountdown = () => {
-  if (countdownTimer.value) {
-    clearInterval(countdownTimer.value)
-  }
-  const updateCountdown = () => {
-    if (currentLibaoData.value.status !== 1) {
-      stopAllTimers()
-      return
-    }
-    if (remainingSeconds.value > 0) {
-      remainingSeconds.value--
-      displayTime.value = formatDisplayTime(remainingSeconds.value)
-      // 每次时间更新时也更新进度条
-      const progress = ((TWELVE_HOURS - remainingSeconds.value) / TWELVE_HOURS) * 100
-      percentage.value = Math.min(Math.max(0, progress), 100)
-    } else {
-      stopAllTimers()
-      refreshData()
-    }
-  }
-  // 确保初始时间正确
-  if (!remainingSeconds.value) {
-    initDisplayTime()
-  }
-  // 立即执行一次更新
-  updateCountdown()
-  // 启动定时器
-  countdownTimer.value = setInterval(updateCountdown, 1000)
-}
-const stopAllTimers = () => {
-  if (countdownTimer.value) {
-    clearInterval(countdownTimer.value)
-    countdownTimer.value = null
-  }
-  // if (progressTimer.value) {
-  //   cancelAnimationFrame(progressTimer.value)
-  //   progressTimer.value = null
-  // }
-  //
-  // if (timerInterval.value) {
-  //   clearInterval(timerInterval.value)
-  //   timerInterval.value = null
-  // }
-  percentage.value = 0
-  isAnimating.value = false
-  // showNote.value = false
-}
 // Lott
 const initLott = () => {
   const query = uni.createSelectorQuery()
@@ -559,45 +420,23 @@ const initLott = () => {
           autoplay: false,
           animationData,
         })
-        lottie.play()
+        if (isAnimating.value) {
+          lottie.pause()
+        } else {
+          lottie.play()
+        }
       } else {
         console.error('Container element not found')
       }
     })
     .exec()
 }
-// 添加一个统一的检查和启动函数
-const checkAndStartTimers = async () => {
-  try {
-    await getGoldCoinProduct()
-    // 设置初始进度
-    percentage.value = getProgressPercentage()
-    if (currentLibaoData.value.status === 1) {
-      initDisplayTime()
-    }
-  } catch (error) {
-    console.error('Failed to check and start timers:', error)
-    setTimeout(() => checkAndStartTimers(), 5000)
-  }
-}
-const getProgressPercentage = (): number => {
-  // 如果状态为0且有金币可以领取,返回100%
-  if (currentLibaoData.value.status === 2 && currentLibaoData.value.currentValue > 0) {
-    return 100
-  }
 
-  // 如果是游戏进行中状态,根据剩余时间计算进度
-  if (currentLibaoData.value.status === 1) {
-    const progress = ((TWELVE_HOURS - remainingSeconds.value) / TWELVE_HOURS) * 100
-    return Math.min(Math.max(0, progress), 100)
-  }
-  return 0
-}
 onShow(async () => {
   generateStars()
   addStarsGradually()
   await initUser(pl.initData.user, uni.getStorageSync('shareCode') || '')
-  await checkAndStartTimers()
+  await refreshGameState()
   nextTick(() => {
     initLott()
   })
@@ -606,6 +445,7 @@ onHide(() => {
   if (addStarTimer) {
     clearInterval(addStarTimer)
   }
+  stopTimers()
   lottie.destroy()
 })
 
@@ -635,11 +475,39 @@ const changeLocale = async (item) => {
   // await postCheckLang(item.value)
 }
 const show = ref(false)
-const displayTime = ref('00h 00m 00s')
 const shengjiShow = ref(false)
 const tishiShow = ref(false)
 const lingquShow = ref(false)
 
+const uprule = ref<{
+  status: number
+  list: ProductionIncreaseInterface[]
+}>(
+  {} as {
+    status: number
+    list: ProductionIncreaseInterface[]
+  },
+)
+const shengji = async () => {
+  const { data } = await getRateUpgradesRules()
+  uprule.value = data
+  shengjiShow.value = true
+  console.info('🚀 ~ file:index method:shengji line:442 -----', uprule.value)
+}
+const upRules = async (upgradeType: 'coin' | 'currency') => {
+  const { code, msg } = await updateGoldCoinProductRate({
+    ruleId: uprule.value.list[1].id,
+    upgradeType,
+  })
+  if (code === 1) {
+    showNotify({ type: 'success', message: msg })
+  } else {
+    showNotify({ type: 'warning', message: msg })
+    return
+  }
+  shengjiShow.value = false
+  await restartGame()
+}
 // 星星
 const stars = ref([])
 const visibleStars = ref([])
@@ -689,6 +557,36 @@ const addStarsGradually = () => {
   :deep(.wd-progress__inner) {
     border-radius: 20px;
     background: linear-gradient(90deg, #fff199 0%, #ffdc00 100%) !important;
+    position: relative;
+    overflow: hidden;
+
+    &::before {
+      content: '';
+      position: absolute;
+      top: 0;
+      left: -100%;
+      width: 50%;
+      height: 100%;
+      background: linear-gradient(
+        90deg,
+        transparent,
+        hsla(0, 100%, 50%, 0.5) 5%,
+        hsla(15, 100%, 50%, 0.5) 10%,
+        hsla(30, 100%, 50%, 0.5) 15%,
+        hsla(45, 100%, 50%, 0.5) 20%,
+        hsla(60, 100%, 50%, 0.5) 25%,
+        hsla(90, 100%, 50%, 0.5) 35%,
+        hsla(120, 100%, 50%, 0.5) 45%,
+        hsla(180, 100%, 50%, 0.5) 55%,
+        hsla(240, 100%, 50%, 0.5) 65%,
+        hsla(270, 100%, 50%, 0.5) 75%,
+        hsla(300, 100%, 50%, 0.5) 85%,
+        hsla(330, 100%, 50%, 0.5) 90%,
+        hsla(360, 100%, 50%, 0.5) 95%,
+        transparent
+      );
+      animation: flow 1.5s linear infinite;
+    }
   }
 
   :deep(.wd-progress__outer) {
@@ -697,6 +595,15 @@ const addStarsGradually = () => {
   }
 }
 
+@keyframes flow {
+  0% {
+    left: -50%;
+  }
+  100% {
+    left: 100%;
+  }
+}
+
 .star-container {
   perspective: 1000px;
   transform-style: preserve-3d;
@@ -743,6 +650,7 @@ const addStarsGradually = () => {
     opacity: 0;
   }
 }
+
 .libao-scale {
   transform-origin: center center;
   animation: libaoGuitar 1s ease-out infinite;

+ 3 - 3
src/pages/play/detail.vue

@@ -95,8 +95,9 @@
 <script setup lang="ts">
 import { onLoad } from '@dcloudio/uni-app'
 import { useTelegramBackButton } from '@/hooks/useTelegramBackButton'
+import { updateGoldCoinProductTemporaryRate } from '@/service/index/foo'
 
-const { isVisible } = useTelegramBackButton(() => {
+useTelegramBackButton(() => {
   uni.navigateTo({
     url: '/pages/play/index',
   })
@@ -138,9 +139,8 @@ const submit = async () => {
     da(2)
     console.log('告级难度')
   }
-
   // 提交数据
-  // const { data } = await postMusicRewardApi(proportion.value)
+  await updateGoldCoinProductTemporaryRate(String(proportion.value))
 }
 
 onLoad((res) => {

+ 3 - 3
src/pages/play/index.vue

@@ -146,7 +146,7 @@ const updateLists = () => {
       title: i18n.global.t('play.Relaxed'),
       type: 'one',
       correct: 30,
-      time: 90,
+      time: 45,
       grade1: 5,
       grade2: 10,
       grade3: 15,
@@ -155,7 +155,7 @@ const updateLists = () => {
       title: i18n.global.t('play.Ordinary'),
       type: 'two',
       correct: 60,
-      time: 90,
+      time: 45,
       grade1: 6,
       grade2: 11,
       grade3: 16,
@@ -164,7 +164,7 @@ const updateLists = () => {
       title: i18n.global.t('play.Nervousness'),
       type: 'three',
       correct: 90,
-      time: 90,
+      time: 45,
       grade1: 7,
       grade2: 12,
       grade3: 17,

+ 39 - 11
src/service/index/foo.ts

@@ -31,9 +31,11 @@ export interface UserCenter {
   temporaryRate: string
   status: number
 }
+
 interface LoginCheck {
   show: number
 }
+
 export interface JinbiT {
   id: number
   sn: number
@@ -57,13 +59,22 @@ export interface JinbiT {
 }
 
 export interface ProductionIncreaseInterface {
-  id: number
-  name: string
+  id: string
+  consumeGoldCoin: number
+  realMoney: number
+  numericalValue: string
   level: number
-  gold_coin: number
-  value: number
-  image: string
-  upgrades: boolean
+  createdBy: string
+  createdTime: string
+  updatedBy: string
+  updatedTime: string
+  numericalValueHour: string
+}
+
+export interface ProductionPlayIncreaseInterface {
+  currentRate: string
+  temporaryRate: number
+  boostResidueTimestamp: number
 }
 
 // 登录接口
@@ -71,7 +82,7 @@ export const coinLoginApi = (data: LoginI) => {
   return httpPost<UserT>('/app/login/coinLogin', data)
 }
 
-// 获取当前登录用户金币数量
+// 获取当前产出信息
 export const getGoldCoinProductState = () => {
   return httpPost<UserCenter>('/app/gold/coin/product/getGoldCoinProductState')
 }
@@ -79,6 +90,7 @@ export const getGoldCoinProductState = () => {
 export const startCoinGame = () => {
   return http.post<LoginCheck>('/app/gold/coin/product/start')
 }
+
 // 统计用户在线时长
 export const updateOnlineTime = (onlineTime: number) => {
   return http.post<UserCenter>('/app/user/updateOnlineTime', { online_time: onlineTime })
@@ -95,15 +107,31 @@ export const stageCoinAdd = () => {
 }
 
 // 获取推进器信息
-export const propellerAllTwo = () => {
-  return http.get<ProductionIncreaseInterface[]>('/app/propeller/propellerAllTwo')
+export const getRateUpgradesRules = () => {
+  return http.post<{
+    status: number
+    list: ProductionIncreaseInterface[]
+  }>('/app/gold/coin/product/getRateUpgradesRules')
 }
 // 升级推进器
-export const prepellerDeduction = (id: number) => {
-  return http.post<any>('/app/propeller/prepellerDeduction', { id })
+export const updateGoldCoinProductRate = (data: {
+  ruleId: string
+  upgradeType: 'coin' | 'currency'
+}) => {
+  return http.post<any>('/app/gold/coin/product/updateGoldCoinProductRate', data)
 }
 
 // 存入当前语言 user/checkLanguage
 export const postCheckLang = (lang: string) => {
   return http.post<any>('/app/user/checkLanguage', { lang })
 }
+
+// 游戏加成速度
+export const updateGoldCoinProductTemporaryRate = (rate: string) => {
+  return http.post<any>('/app/gold/coin/product/updateGoldCoinProductTemporaryRate', { rate })
+}
+
+// 游戏剩余时间
+export const getBoostResidueTimes = () => {
+  return http.post<ProductionPlayIncreaseInterface>('/app/gold/coin/product/getBoostResidueTimes')
+}

File diff suppressed because it is too large
+ 0 - 0
src/static/Animation.json


File diff suppressed because it is too large
+ 0 - 0
src/static/data.json


+ 91 - 5
src/types/auto-import.d.ts

@@ -79,6 +79,7 @@ declare global {
   const useAttrs: typeof import('vue')['useAttrs']
   const useCssModule: typeof import('vue')['useCssModule']
   const useCssVars: typeof import('vue')['useCssVars']
+  const useGameTimer: typeof import('../hooks/useGameTimer')['useGameTimer']
   const useId: typeof import('vue')['useId']
   const useImgPath: typeof import('../hooks/useImgPath')['useImgPath']
   const useModel: typeof import('vue')['useModel']
@@ -97,7 +98,7 @@ declare global {
 // for type re-export
 declare global {
   // @ts-ignore
-  export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
+  export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
   import('vue')
 }
 // for vue template auto import
@@ -161,7 +162,6 @@ declare module 'vue' {
     readonly onUnload: UnwrapRef<typeof import('@dcloudio/uni-app')['onUnload']>
     readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
     readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
-    readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']>
     readonly provide: UnwrapRef<typeof import('vue')['provide']>
     readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
     readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
@@ -179,13 +179,99 @@ declare module 'vue' {
     readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
     readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
     readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
-    readonly useId: UnwrapRef<typeof import('vue')['useId']>
+    readonly useGameTimer: UnwrapRef<typeof import('../hooks/useGameTimer')['useGameTimer']>
+    readonly useImgPath: UnwrapRef<typeof import('../hooks/useImgPath')['useImgPath']>
+    readonly useRequest: UnwrapRef<typeof import('../hooks/useRequest')['default']>
+    readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
+    readonly useTelegramBackButton: UnwrapRef<typeof import('../hooks/useTelegramBackButton')['useTelegramBackButton']>
+    readonly useUpload: UnwrapRef<typeof import('../hooks/useUpload')['default']>
+    readonly watch: UnwrapRef<typeof import('vue')['watch']>
+    readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
+    readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
+    readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
+  }
+}
+declare module '@vue/runtime-core' {
+  interface GlobalComponents {}
+  interface ComponentCustomProperties {
+    readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
+    readonly computed: UnwrapRef<typeof import('vue')['computed']>
+    readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
+    readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
+    readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
+    readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
+    readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
+    readonly formatAmount: UnwrapRef<typeof import('../hooks/moneyProcessing')['formatAmount']>
+    readonly formatAmountNoFloat: UnwrapRef<typeof import('../hooks/moneyProcessing')['formatAmountNoFloat']>
+    readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
+    readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
+    readonly h: UnwrapRef<typeof import('vue')['h']>
+    readonly inject: UnwrapRef<typeof import('vue')['inject']>
+    readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
+    readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
+    readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
+    readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
+    readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
+    readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
+    readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
+    readonly onAddToFavorites: UnwrapRef<typeof import('@dcloudio/uni-app')['onAddToFavorites']>
+    readonly onBackPress: UnwrapRef<typeof import('@dcloudio/uni-app')['onBackPress']>
+    readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
+    readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
+    readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
+    readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
+    readonly onError: UnwrapRef<typeof import('@dcloudio/uni-app')['onError']>
+    readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
+    readonly onHide: UnwrapRef<typeof import('@dcloudio/uni-app')['onHide']>
+    readonly onLaunch: UnwrapRef<typeof import('@dcloudio/uni-app')['onLaunch']>
+    readonly onLoad: UnwrapRef<typeof import('@dcloudio/uni-app')['onLoad']>
+    readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
+    readonly onNavigationBarButtonTap: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap']>
+    readonly onNavigationBarSearchInputChanged: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged']>
+    readonly onNavigationBarSearchInputClicked: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked']>
+    readonly onNavigationBarSearchInputConfirmed: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed']>
+    readonly onNavigationBarSearchInputFocusChanged: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged']>
+    readonly onPageNotFound: UnwrapRef<typeof import('@dcloudio/uni-app')['onPageNotFound']>
+    readonly onPageScroll: UnwrapRef<typeof import('@dcloudio/uni-app')['onPageScroll']>
+    readonly onPullDownRefresh: UnwrapRef<typeof import('@dcloudio/uni-app')['onPullDownRefresh']>
+    readonly onReachBottom: UnwrapRef<typeof import('@dcloudio/uni-app')['onReachBottom']>
+    readonly onReady: UnwrapRef<typeof import('@dcloudio/uni-app')['onReady']>
+    readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
+    readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
+    readonly onResize: UnwrapRef<typeof import('@dcloudio/uni-app')['onResize']>
+    readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
+    readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
+    readonly onShareAppMessage: UnwrapRef<typeof import('@dcloudio/uni-app')['onShareAppMessage']>
+    readonly onShareTimeline: UnwrapRef<typeof import('@dcloudio/uni-app')['onShareTimeline']>
+    readonly onShow: UnwrapRef<typeof import('@dcloudio/uni-app')['onShow']>
+    readonly onTabItemTap: UnwrapRef<typeof import('@dcloudio/uni-app')['onTabItemTap']>
+    readonly onThemeChange: UnwrapRef<typeof import('@dcloudio/uni-app')['onThemeChange']>
+    readonly onUnhandledRejection: UnwrapRef<typeof import('@dcloudio/uni-app')['onUnhandledRejection']>
+    readonly onUnload: UnwrapRef<typeof import('@dcloudio/uni-app')['onUnload']>
+    readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
+    readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
+    readonly provide: UnwrapRef<typeof import('vue')['provide']>
+    readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
+    readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
+    readonly ref: UnwrapRef<typeof import('vue')['ref']>
+    readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
+    readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
+    readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
+    readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
+    readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
+    readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
+    readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
+    readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
+    readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
+    readonly unref: UnwrapRef<typeof import('vue')['unref']>
+    readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
+    readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
+    readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
+    readonly useGameTimer: UnwrapRef<typeof import('../hooks/useGameTimer')['useGameTimer']>
     readonly useImgPath: UnwrapRef<typeof import('../hooks/useImgPath')['useImgPath']>
-    readonly useModel: UnwrapRef<typeof import('vue')['useModel']>
     readonly useRequest: UnwrapRef<typeof import('../hooks/useRequest')['default']>
     readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
     readonly useTelegramBackButton: UnwrapRef<typeof import('../hooks/useTelegramBackButton')['useTelegramBackButton']>
-    readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
     readonly useUpload: UnwrapRef<typeof import('../hooks/useUpload')['default']>
     readonly watch: UnwrapRef<typeof import('vue')['watch']>
     readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>

+ 1 - 5
src/utils/http.ts

@@ -1,6 +1,5 @@
 import { CustomRequestOptions } from '@/interceptors/request'
 import type { IResData } from '@/typings'
-import NProgress from '@/utils/nprogress'
 import { SmCrypto } from '@/utils/crypto'
 
 const smCrypto = new SmCrypto(import.meta.env.VITE_PRIVATE_KEY, import.meta.env.VITE_PUBLIC_KEY)
@@ -8,7 +7,6 @@ export const http = <T>(options: CustomRequestOptions) => {
   // let resdata = options.data
   // console.info('🚀 ~ 请求数据', resdata)
   // options.data = smCrypto.doEncrypt(options.data)
-  NProgress.start()
   // 1. 返回 Promise 对象
   return new Promise<IResData<T>>((resolve, reject) => {
     // console.log('当前语言:', uni.getStorageSync('lang'))
@@ -18,7 +16,7 @@ export const http = <T>(options: CustomRequestOptions) => {
         Authorization: `Bearer ${uni.getStorageSync('token')}` || '',
         lang: uni.getStorageSync('lang') || 'en',
       },
-      timeout: 50000,
+      timeout: 100000,
       //
       dataType: 'json',
       // #ifndef MP-WEIXIN
@@ -27,7 +25,6 @@ export const http = <T>(options: CustomRequestOptions) => {
       // 响应成功
       success(res) {
         // res.data = smCrypto.doDecrypt(res.data)
-        NProgress.done()
         // 状态码 2xx,参考 axios 的设计
         if (res.statusCode >= 200 && res.statusCode < 300) {
           // 2.1 提取核心数据 res.data
@@ -49,7 +46,6 @@ export const http = <T>(options: CustomRequestOptions) => {
       },
       // 响应失败
       fail(err) {
-        NProgress.done()
         uni.showToast({
           icon: 'none',
           title: 'inter error please try again',

Some files were not shown because too many files changed in this diff