Browse Source

优化周报和日报,新增防双击按钮组件,天气预报接口节流控制

songxy 1 month ago
parent
commit
5b664804c5

+ 0 - 0
client/src/components/NButton/index.ts


+ 33 - 0
client/src/components/NButton/src/NButton.vue

@@ -0,0 +1,33 @@
+<template>
+  <el-button :type="type" @click="onClickHandle" :second="second" :disabled="disabled"
+    >发送</el-button
+  >
+</template>
+
+<script setup lang="ts">
+defineOptions({
+  name: 'NButton'
+})
+const disabled = ref<boolean>(false)
+const $props = defineProps({
+  type: {
+    type: String,
+    default: ''
+  },
+  second: {
+    type: Number,
+    default: 500
+  }
+})
+const $emits = defineEmits<{
+  (e: 'nclick', v: void): void
+}>()
+const onClickHandle = () => {
+  disabled.value = true
+  $emits('nclick')
+  const timer = setTimeout(() => {
+    disabled.value = false
+    clearTimeout(timer)
+  }, $props.second)
+}
+</script>

+ 30 - 0
client/src/utils/index.ts

@@ -277,3 +277,33 @@ export const parseFloatNumber = (val: string | number | undefined): number => {
   if (!val) return 0
   return parseFloat(val.toString())
 }
+
+type ExpireType = {
+  value: any
+  expiry: number
+}
+// 存储数据(默认2小时后失效)
+export function setWithExpire(key, value, second = 2 * 3600): void {
+  const now: number = new Date().getTime()
+  const expireTime: number = second * 1000
+  const item: ExpireType = {
+    value: value,
+    expiry: now + expireTime // 过期时间戳
+  }
+  localStorage.setItem(key, JSON.stringify(item))
+}
+
+// 读取数据(自动处理过期)
+export function getWithExpire(key): any {
+  const itemStr: string | null = localStorage.getItem(key)
+  if (!itemStr) return null
+
+  const item: ExpireType = JSON.parse(itemStr)
+  const now = new Date().getTime()
+
+  if (now > item.expiry) {
+    localStorage.removeItem(key) // 过期则删除
+    return null
+  }
+  return item.value // 未过期返回值
+}

+ 0 - 1
client/src/views/OaSystem/home/components/ProcessChart.vue

@@ -43,7 +43,6 @@ watch(
         }
       ]
     }
-    console.log('初始化')
   }
 )
 </script>

+ 48 - 28
client/src/views/OaSystem/oaLayout/weather.vue

@@ -1,30 +1,41 @@
 <template>
-  <div class="weatherBox" v-if="cityName">
+  <div class="weatherBox" v-if="weatherInfo.cityName">
     <div class="tqBox">
-      <img :src="getAssetsFile(iconPath)" alt="" />
+      <img :src="getAssetsFile(weatherInfo.iconPath)" alt="" />
       <div>
-        <div class="day">{{ temperature }}</div>
+        <div class="day">{{ weatherInfo.temperature }}</div>
         <div>
           <p>℃</p>
-          <p>{{ weather }}</p>
+          <p>{{ weatherInfo.weather }}</p>
         </div>
       </div>
     </div>
     <div class="posBox">
-      <span class="quality">{{ winddirection }} {{ windpower }}</span>
-      <span class="location"><Icon icon="ep:location" />{{ cityName }}</span>
+      <span class="quality">{{ weatherInfo.winddirection }} {{ weatherInfo.windpower }}</span>
+      <span class="location"><Icon icon="ep:location" />{{ weatherInfo.cityName }}</span>
     </div>
   </div>
 </template>
 <script setup lang="ts">
 import axios from 'axios'
+import { setWithExpire, getWithExpire } from '@/utils'
 
-const cityName = ref<string>()
-const weather = ref<string>()
-const temperature = ref<string>()
-const winddirection = ref<string>()
-const windpower = ref<string>()
-const iconPath = ref<string | undefined>()
+interface WeatherType {
+  cityName: string
+  weather: string
+  temperature: string
+  winddirection: string
+  windpower: string
+  iconPath: string | undefined
+}
+const weatherInfo = reactive<WeatherType>({
+  cityName: '',
+  weather: '',
+  temperature: '',
+  winddirection: '',
+  windpower: '',
+  iconPath: ''
+})
 
 const getAssetsFile = (url: string | undefined): string => {
   if (!url) return ''
@@ -36,42 +47,51 @@ const getCurrentWeatherInfo = async (city: string): Promise<void> => {
   const result = await axios({ url: urlApi, method: 'GET', data: sendData })
   const resultData = result['data']
   const weatherTxt = resultData['lives'][0]['weather']
-  weather.value = weatherTxt
-  temperature.value = resultData['lives'][0]['temperature']
-  winddirection.value = resultData['lives'][0]['winddirection']
-  windpower.value = resultData['lives'][0]['windpower']
+  weatherInfo.weather = weatherTxt
+  weatherInfo.temperature = resultData['lives'][0]['temperature']
+  weatherInfo.winddirection = resultData['lives'][0]['winddirection']
+  weatherInfo.windpower = resultData['lives'][0]['windpower']
   if (weatherTxt.indexOf('大雨') !== -1) {
-    iconPath.value = 'rain_big.png'
+    weatherInfo.iconPath = 'rain_big.png'
   } else if (weatherTxt.indexOf('雷阵雨') !== -1) {
-    iconPath.value = 'rain_thunder.png'
+    weatherInfo.iconPath = 'rain_thunder.png'
   } else if (weatherTxt.indexOf('雨') !== -1) {
-    iconPath.value = 'rain.png'
+    weatherInfo.iconPath = 'rain.png'
   } else if (weatherTxt.indexOf('大雪') !== -1) {
-    iconPath.value = 'snow_big.png'
+    weatherInfo.iconPath = 'snow_big.png'
   } else if (weatherTxt.indexOf('雪') !== -1) {
-    iconPath.value = 'snow.png'
+    weatherInfo.iconPath = 'snow.png'
   } else if (weatherTxt.indexOf('多云') !== -1) {
-    iconPath.value = 'cloud.png'
+    weatherInfo.iconPath = 'cloud.png'
   } else if (weatherTxt.indexOf('阴') !== -1) {
-    iconPath.value = 'sky_overcast.png'
+    weatherInfo.iconPath = 'sky_overcast.png'
   } else if (weatherTxt.indexOf('晴') !== -1) {
-    iconPath.value = 'clear_day.png'
+    weatherInfo.iconPath = 'clear_day.png'
   } else if (weatherTxt.indexOf('雾') !== -1) {
-    iconPath.value = 'fog.png'
+    weatherInfo.iconPath = 'fog.png'
   } else if (weatherTxt.indexOf('霾') !== -1) {
-    iconPath.value = 'haze.png'
+    weatherInfo.iconPath = 'haze.png'
   }
+  setWithExpire('_weathers', weatherInfo)
 }
 const getLocationByIp = async (): Promise<void> => {
   const urlApi = `https://restapi.amap.com/v3/ip?key=10e346e2f3bdcb88fab43e0c950014f5`
   const sendData = {}
   const result = await axios({ url: urlApi, method: 'GET', data: sendData })
   const resultData = result['data']
-  cityName.value = resultData['city']
+  weatherInfo.cityName = resultData['city']
   getCurrentWeatherInfo(resultData['adcode'])
 }
 onMounted(() => {
-  getLocationByIp()
+  const weathers = getWithExpire('_weathers')
+  if (!weathers) {
+    getLocationByIp()
+  } else {
+    const keys = Object.keys(weathers)
+    keys.forEach((key) => {
+      weatherInfo[key] = weathers[key]
+    })
+  }
 })
 </script>
 

+ 4 - 2
client/src/views/OaSystem/personnelManagement/components/AmountOfWork.vue

@@ -6,7 +6,9 @@
     <div class="select-list">
       <div class="title">
         <div class="left">
-          {{ '工作项目' + (defaultTotalTime ? `(总耗时${defaultTotalTime}小时)` : '') }}
+          工作项目<span style="color: #1b80eb">
+            {{ defaultTotalTime ? `(总耗时${defaultTotalTime}小时)` : '' }}
+          </span>
         </div>
         <div class="right">
           <el-input
@@ -132,12 +134,12 @@ const setInitData = () => {
         }
       })
       dataList.value.sort((x, y) => y['count'] - x['count'])
+      getTotalTime()
       clearTimeout(timer)
     }, 0)
   } else {
     getAllProject()
   }
-  getTotalTime()
 }
 
 watch(

+ 2 - 2
client/src/views/OaSystem/personnelManagement/dailyCenter/editorDetail.vue

@@ -43,8 +43,8 @@
       <el-button type="primary" @click="sendReportHandle(false)">更新</el-button>
     </div>
     <div class="footBox" v-else>
-      <el-button type="primary" @click="sendReportHandle(true)">暂存</el-button>
-      <el-button type="primary" @click="sendReportHandle(false)">发送</el-button>
+      <n-button type="primary" @nclick="sendReportHandle(true)">暂存</n-button>
+      <n-button type="primary" @nclick="sendReportHandle(false)">发送</n-button>
     </div>
   </div>
 </template>