瀏覽代碼

更新时间选择器,优化快速选择栏的时间,更改时间选择器的选中值;更新菜单组件,现在可以根据路由正确的选中菜单项,并且当子菜单选中时,父菜单也可以高亮显示;新增CIcon图标组件,图标将由assets文件夹提供并直接缓存;更新网站logo;

fxs 1 年之前
父節點
當前提交
1fd9479bf0

+ 1 - 0
components.d.ts

@@ -7,6 +7,7 @@ export {}
 /* prettier-ignore */
 declare module 'vue' {
   export interface GlobalComponents {
+    CIcon: typeof import('./src/components/cIcon/cIcon.vue')['default']
     CSelect: typeof import('./src/components/form/CSelect.vue')['default']
     CustomDialog: typeof import('./src/components/dialog/customDialog.vue')['default']
     CustomIndicatorDialog: typeof import('./src/components/dialog/customIndicatorDialog.vue')['default']

+ 1 - 1
index.html

@@ -2,7 +2,7 @@
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
-    <link rel="icon" href="/logo.svg" />
+    <link rel="icon" href="/src/assets/icon/logo//logo.svg" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>淳皓创量系统管理平台</title>
   </head>

+ 1 - 0
src/assets/defaultGame.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1725591308908" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4433" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M704.32 974.4H321.81333333c-77.54666667 0-150.61333333-30.4-205.76-85.54666667S30.50666667 760.64 30.50666667 683.2v-0.42666667c0-77.54666667 30.4-150.61333333 85.54666666-205.76C171.2 421.86666667 244.26666667 391.46666667 321.81333333 391.46666667h382.61333334c77.54666667 0 150.61333333 30.4 205.76 85.54666666 55.14666667 55.14666667 85.54666667 128.21333333 85.54666666 205.76v0.42666667c0 77.54666667-30.4 150.61333333-85.54666666 205.76s-128.32 85.44-205.86666667 85.44zM321.81333333 466.24c-119.36 0-216.53333333 97.17333333-216.53333333 216.53333333v0.42666667c0 119.36 97.17333333 216.53333333 216.53333333 216.53333333h382.61333334c119.36 0 216.53333333-97.17333333 216.53333333-216.53333333v-0.42666667c0-119.36-97.17333333-216.53333333-216.53333333-216.53333333H321.81333333z" fill="#ac4cfd" p-id="4434"></path><path d="M263.89333333 655.68H412.8v57.38666667H263.89333333z" fill="#ac4cfd" p-id="4435"></path><path d="M311.11466667 756.24106667l0.35093333-148.90666667 57.38666667 0.1344-0.352 148.90666667zM682.77333333 764.69333333c-45.65333333 0-82.88-37.12-82.88-82.88s37.12-82.88 82.88-82.88 82.88 37.12 82.88 82.88-37.12 82.88-82.88 82.88z m0-117.65333333c-19.2 0-34.88 15.68-34.88 34.88s15.68 34.88 34.88 34.88 34.88-15.68 34.88-34.88-15.57333333-34.88-34.88-34.88zM545.70666667 463.78666667L488.53333333 432.74666667l100.05333334-184.42666667H385.81333333l-27.84-49.38666667 86.4-143.36 55.78666667 33.49333334-56.74666667 94.18666666h199.89333334l28.58666666 48z" fill="#ac4cfd" p-id="4436"></path></svg>

+ 1 - 0
src/assets/icon/header/defaultGame.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1725591308908" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4433" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M704.32 974.4H321.81333333c-77.54666667 0-150.61333333-30.4-205.76-85.54666667S30.50666667 760.64 30.50666667 683.2v-0.42666667c0-77.54666667 30.4-150.61333333 85.54666666-205.76C171.2 421.86666667 244.26666667 391.46666667 321.81333333 391.46666667h382.61333334c77.54666667 0 150.61333333 30.4 205.76 85.54666666 55.14666667 55.14666667 85.54666667 128.21333333 85.54666666 205.76v0.42666667c0 77.54666667-30.4 150.61333333-85.54666666 205.76s-128.32 85.44-205.86666667 85.44zM321.81333333 466.24c-119.36 0-216.53333333 97.17333333-216.53333333 216.53333333v0.42666667c0 119.36 97.17333333 216.53333333 216.53333333 216.53333333h382.61333334c119.36 0 216.53333333-97.17333333 216.53333333-216.53333333v-0.42666667c0-119.36-97.17333333-216.53333333-216.53333333-216.53333333H321.81333333z" fill="#ac4cfd" p-id="4434"></path><path d="M263.89333333 655.68H412.8v57.38666667H263.89333333z" fill="#ac4cfd" p-id="4435"></path><path d="M311.11466667 756.24106667l0.35093333-148.90666667 57.38666667 0.1344-0.352 148.90666667zM682.77333333 764.69333333c-45.65333333 0-82.88-37.12-82.88-82.88s37.12-82.88 82.88-82.88 82.88 37.12 82.88 82.88-37.12 82.88-82.88 82.88z m0-117.65333333c-19.2 0-34.88 15.68-34.88 34.88s15.68 34.88 34.88 34.88 34.88-15.68 34.88-34.88-15.57333333-34.88-34.88-34.88zM545.70666667 463.78666667L488.53333333 432.74666667l100.05333334-184.42666667H385.81333333l-27.84-49.38666667 86.4-143.36 55.78666667 33.49333334-56.74666667 94.18666666h199.89333334l28.58666666 48z" fill="#ac4cfd" p-id="4436"></path></svg>

二進制
src/assets/icon/header/defaultHead.png


文件差異過大導致無法顯示
+ 0 - 0
src/assets/icon/logo/logo.svg


文件差異過大導致無法顯示
+ 0 - 0
src/assets/icon/promotion/acc-manage-active.svg


文件差異過大導致無法顯示
+ 0 - 0
src/assets/icon/promotion/acc-manage-default.svg


+ 1 - 0
src/assets/icon/promotion/ad-manage-active.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1729041716770" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6002" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M854.528 34.816H172.032c-79.36 0-143.36 64.512-143.36 143.872v441.344c0 22.016 17.92 39.424 39.424 39.424h752.64c22.016 0 39.424-17.92 39.424-39.424 0-22.016-17.92-39.424-39.424-39.424H107.52V178.688c0-35.328 28.672-64.512 64.512-64.512h682.496c35.328 0 64.512 28.672 64.512 64.512v345.6c0 22.016 17.92 39.424 39.424 39.424s39.424-17.92 39.424-39.424V178.688c0.512-79.36-64-143.872-143.36-143.872zM958.976 747.008h-890.88c-22.016 0-39.424 17.92-39.424 39.424s17.92 39.424 39.424 39.424h407.04c-1.024 3.072-1.536 6.656-1.536 9.728v138.752c0 22.016 17.92 39.424 39.424 39.424s39.424-17.92 39.424-39.424v-138.752c0-3.584-0.512-6.656-1.536-9.728h407.04c22.016 0 39.424-17.92 39.424-39.424s-16.896-39.424-38.4-39.424z" fill="#197afb" p-id="6003"></path><path d="M406.016 207.36c-18.944 1.024-32.768 11.776-40.96 31.744L286.72 449.536v3.072c-1.024 4.096-1.536 7.68-1.536 10.752 1.024 16.384 10.24 24.064 27.136 24.064 14.336 0 23.552-6.144 28.672-17.92l12.288-36.352h107.52l10.752 36.352c5.12 12.288 14.848 17.92 28.672 17.92 17.408 0 26.112-7.68 27.136-22.528 0-4.096-1.024-9.216-3.072-15.36L448.512 239.104c-9.216-21.504-23.04-31.744-42.496-31.744z m-36.352 172.544l36.352-112.128 36.352 112.128H369.664zM574.464 211.968c-17.92 1.024-27.648 10.752-28.672 28.672v218.112c1.024 17.92 11.264 27.648 30.208 28.672h66.56c84.992-4.096 129.024-49.152 133.12-134.656-3.072-90.624-48.64-137.728-136.192-140.8h-65.024z m140.8 139.264c-2.048 53.248-26.112 81.408-72.704 83.456h-39.424V264.704h34.816c50.176 1.024 76.288 29.696 77.312 86.528z" fill="#197afb" p-id="6004"></path></svg>

+ 1 - 0
src/assets/icon/promotion/ad-manage-default.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1729041826578" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="859" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M854.528 34.816H172.032c-79.36 0-143.36 64.512-143.36 143.872v441.344c0 22.016 17.92 39.424 39.424 39.424h752.64c22.016 0 39.424-17.92 39.424-39.424 0-22.016-17.92-39.424-39.424-39.424H107.52V178.688c0-35.328 28.672-64.512 64.512-64.512h682.496c35.328 0 64.512 28.672 64.512 64.512v345.6c0 22.016 17.92 39.424 39.424 39.424s39.424-17.92 39.424-39.424V178.688c0.512-79.36-64-143.872-143.36-143.872zM958.976 747.008h-890.88c-22.016 0-39.424 17.92-39.424 39.424s17.92 39.424 39.424 39.424h407.04c-1.024 3.072-1.536 6.656-1.536 9.728v138.752c0 22.016 17.92 39.424 39.424 39.424s39.424-17.92 39.424-39.424v-138.752c0-3.584-0.512-6.656-1.536-9.728h407.04c22.016 0 39.424-17.92 39.424-39.424s-16.896-39.424-38.4-39.424z" fill="#333333" p-id="860"></path><path d="M406.016 207.36c-18.944 1.024-32.768 11.776-40.96 31.744L286.72 449.536v3.072c-1.024 4.096-1.536 7.68-1.536 10.752 1.024 16.384 10.24 24.064 27.136 24.064 14.336 0 23.552-6.144 28.672-17.92l12.288-36.352h107.52l10.752 36.352c5.12 12.288 14.848 17.92 28.672 17.92 17.408 0 26.112-7.68 27.136-22.528 0-4.096-1.024-9.216-3.072-15.36L448.512 239.104c-9.216-21.504-23.04-31.744-42.496-31.744z m-36.352 172.544l36.352-112.128 36.352 112.128H369.664zM574.464 211.968c-17.92 1.024-27.648 10.752-28.672 28.672v218.112c1.024 17.92 11.264 27.648 30.208 28.672h66.56c84.992-4.096 129.024-49.152 133.12-134.656-3.072-90.624-48.64-137.728-136.192-140.8h-65.024z m140.8 139.264c-2.048 53.248-26.112 81.408-72.704 83.456h-39.424V264.704h34.816c50.176 1.024 76.288 29.696 77.312 86.528z" fill="#333333" p-id="861"></path></svg>

文件差異過大導致無法顯示
+ 0 - 0
src/assets/icon/promotion/ad-tencent.svg


+ 1 - 0
src/assets/icon/promotion/ad-tt.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1729042167533" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2214" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M751.84 328.88L611.472 83.04l-166.2 41.144 188.536 322.152z" fill="#01C6D2" p-id="2215"></path><path d="M195.024 212.424l-48.48 158.272h369.88l-47.824-158.272z" fill="#76E4D9" p-id="2216"></path><path d="M231.584 397.92L96 636.48 205.248 754.48l184.208-319.096z" fill="#3468D4" p-id="2217"></path><path d="M385.184 576.192L273.16 695.888l136.896 238.896 160.296-37.856z" fill="#3058B0" p-id="2218"></path><path d="M505.288 651.128l45.712 157.816h275.848l48.12-157.816z" fill="#3568D5" p-id="2219"></path><path d="M814.544 263.76l-183.52 321.968L786.96 623.76 928 385.496z" fill="#3C8BFF" p-id="2220"></path></svg>

文件差異過大導致無法顯示
+ 0 - 1
src/assets/logo.svg


+ 45 - 0
src/components/cIcon/cIcon.vue

@@ -0,0 +1,45 @@
+<script setup lang="ts">
+import { ref, watch } from 'vue'
+import { getAssetsImageUrl } from '@/utils/common'
+import { loadResource } from '@/utils/resource'
+
+const props = withDefaults(
+  defineProps<{
+    src: string
+    size?: number
+  }>(),
+  {
+    size: 20,
+  },
+)
+
+const iconSrc = ref<string>()
+
+watch(
+  () => props.src,
+  async (newSrc: string) => {
+    const assetUrl = getAssetsImageUrl('icon' + newSrc)
+    const blobUrl = await loadResource(assetUrl)
+    iconSrc.value = blobUrl
+  },
+  { deep: true, immediate: true },
+)
+</script>
+
+<template>
+  <div :style="{ width: `${size}px`, height: `${size}px` }">
+    <el-image
+      v-bind="{ ...$attrs }"
+      :fit="$attrs['fit'] ? $attrs['fit'] : 'fill'"
+      :src="iconSrc"
+      class="cIcon"
+    ></el-image>
+  </div>
+</template>
+
+<style scoped>
+.cIcon {
+  display: flex;
+  align-items: center;
+}
+</style>

+ 0 - 4
src/components/echarts/HomeAnalysisLine.vue

@@ -232,10 +232,7 @@ watch(
     if (newState === false) {
       if (!chartInstance.value) initChart()
       initOptions()
-      console.log(props.data)
     }
-
-    console.log(newState)
   },
   { deep: true },
 )
@@ -248,7 +245,6 @@ watch(
   () => props.legend,
   newLegned => {
     initOptions()
-    console.log(newLegned)
   },
 )
 </script>

+ 2 - 0
src/components/form/CSelect.vue

@@ -29,6 +29,7 @@ const changeSelect = (newVal: any, name: string) => {
           v-if="selectItem.type === CSelectType.RadioLegend"
           :style="{ backgroundColor: selectItem.color }"
         ></div>
+        <!-- 对于值为对象的选项需要给value-key,默认为value -->
         <el-select
           v-model="selectItem.value"
           placeholder="Select"
@@ -40,6 +41,7 @@ const changeSelect = (newVal: any, name: string) => {
           "
           collapse-tags
           :style="selectStyle"
+          :value-key="typeof selectItem.value === 'object' ? 'name' : 'value'"
         >
           <el-option
             v-for="listItem in selectItem.options"

+ 122 - 51
src/components/navigation/Menu.vue

@@ -1,9 +1,11 @@
 <script setup lang="ts">
 import type { BaseMenu } from '@/types/Promotion/Menu'
-import { useMenu } from '@/hooks/useMenu'
-import { ref, useAttrs, watch } from 'vue'
 
-const { setRouterDefaultActive } = useMenu()
+import { computed, nextTick, ref, watch } from 'vue'
+import { useRoute } from 'vue-router'
+import { useAttrs } from 'vue'
+import router from '@/router'
+import CIcon from '../cIcon/CIcon.vue'
 
 interface MenuProps {
   menuStyle?: string
@@ -13,32 +15,89 @@ interface MenuProps {
 }
 
 const props = withDefaults(defineProps<MenuProps>(), {})
+const routes = useRoute()
 const attrs = useAttrs()
+
 const emits = defineEmits(['activeChange'])
 
 // 纵向菜单折叠,仅在mode为vertical时生效
 const isCollapse = ref(false)
 
-// 默认激活
-const defaultActive = ref()
+// 高亮菜单的name
+const highlightMenu = ref()
 
 /**
- * @description: 初始化默认菜单
+ * @description: 菜单项改变
+ * @param {*} newVal
  * @return {*}
  */
-const initDefaultActive = () => {
-  if (!(attrs.router || props.defaultActive))
-    throw new Error('defaultActive or router is required')
-  if (attrs.router) {
-    setRouterDefaultActive(defaultActive, props.menuList)
-  } else defaultActive.value = props.defaultActive
-}
-
 const changeSelect = (newVal: string) => {
   emits('activeChange', newVal)
 }
 
-initDefaultActive()
+/**
+ * @description: 改变箭头颜色
+ * @return {*}
+ */
+const changeArrow = () => {
+  nextTick(() => {
+    // 只有被加上这两个特殊类的箭头才去处理
+    let activeItem = document.querySelector(
+      '.activeItem .el-sub-menu__icon-arrow',
+    ) as HTMLElement
+
+    let noActiveItem = document.querySelector(
+      '.noActiveItem .el-sub-menu__icon-arrow',
+    ) as HTMLElement
+
+    if (activeItem) {
+      activeItem.style.color = '#409eff'
+    }
+    if (noActiveItem) {
+      noActiveItem.style.color = 'unset'
+    }
+  })
+}
+
+/**
+ * @description: 根据当前路由,高亮父菜单
+ * @return {*}
+ */
+watch(
+  () => routes.path,
+  (newval: string) => {
+    props.menuList.forEach(item => {
+      let result = item.children?.find(child => child.path === newval)
+      // 有可能该选项卡没有子菜单,但他本身也可以高亮
+      if (result || item.path === newval) highlightMenu.value = item.name
+    })
+    // 去调整箭头颜色
+    changeArrow()
+  },
+  { deep: true, immediate: true },
+)
+
+/**
+ * @description: 在使用router模式下的默认选中
+ * @return {*}
+ */
+const routerDefaultActive = computed(() => {
+  if (attrs.router) {
+    let menuItem = props.menuList.find(item => {
+      let basePath = item.path // 你可以动态设置这个值
+      console.log(basePath)
+      if (basePath) {
+        const escapedBasePath = basePath.replace(/\//g, '\\/') // 转义斜杠
+        const regex = new RegExp(`^${escapedBasePath}(?:\/.*)?$`)
+        if (regex.test(routes.path)) return true
+      }
+      return false
+    })
+    return menuItem?.path
+  } else {
+    return ''
+  }
+})
 </script>
 
 <template>
@@ -50,46 +109,49 @@ initDefaultActive()
     ]"
   >
     <el-menu
-      v-bind="$attrs"
-      :default-active="defaultActive"
+      v-bind="{ ...$attrs }"
       class="menu"
       :collapse="isCollapse"
       :style="menuStyle"
       :ellipsis="false"
+      :default-active="
+        props.defaultActive ? props.defaultActive : routerDefaultActive
+      "
       @select="changeSelect"
     >
       <template v-for="menuItem in menuList" :key="menuItem.name">
         <!-- 有子菜单 -->
-        <el-sub-menu v-if="menuItem.children" :index="menuItem.name">
+        <el-sub-menu
+          v-if="menuItem.children"
+          :class="
+            highlightMenu === menuItem.name ? 'activeItem' : 'noActiveItem'
+          "
+          :index="menuItem.name"
+        >
           <template #title>
-            <el-image
-              v-if="menuItem.iconDefault"
-              style="
-                width: 20px;
-                height: 20px;
-                vertical-align: middle;
-                padding-right: 5px;
-              "
+            <CIcon
+              v-if="menuItem.iconDefault && highlightMenu !== menuItem.name"
               :src="menuItem.iconDefault"
-              :fit="'fill'"
-            />
-            <span>{{ menuItem.title }}</span>
+              class="menuIcon"
+            ></CIcon>
+            <CIcon
+              v-if="menuItem.iconActive && highlightMenu === menuItem.name"
+              class="menuIcon"
+              :src="menuItem.iconActive"
+            ></CIcon>
+            <span
+              class="menuTitle"
+              :class="{ menuActiveColor: highlightMenu === menuItem.name }"
+              >{{ menuItem.title }}</span
+            >
           </template>
-          <el-menu-item
-            v-for="item in menuItem.children"
-            :index="$attrs.router ? item.path : item.name"
-          >
-            <el-image
+          <el-menu-item v-for="item in menuItem.children" :index="item.path">
+            <CIcon
+              class="menuChildIcon"
               v-if="item.iconDefault"
-              style="
-                width: 20px;
-                height: 20px;
-                vertical-align: middle;
-                padding-right: 5px;
-              "
               :src="item.iconDefault"
-              :fit="'fill'"
-            />
+            ></CIcon>
+
             <span>{{ item.title }}</span>
           </el-menu-item>
         </el-sub-menu>
@@ -99,17 +161,12 @@ initDefaultActive()
           :index="$attrs.router ? menuItem.path : menuItem.name"
           v-else
         >
-          <el-image
+          <CIcon
+            class="menuIcon"
             v-if="menuItem.iconDefault"
-            style="
-              width: 20px;
-              height: 20px;
-              vertical-align: middle;
-              padding-right: 5px;
-            "
             :src="menuItem.iconDefault"
-            :fit="'fill'"
-          />
+          ></CIcon>
+
           <span>{{ menuItem.title }}</span>
         </el-menu-item>
       </template>
@@ -155,6 +212,20 @@ initDefaultActive()
     background-color: white;
     /* text-align: right; */
   }
+  .menuIcon {
+    margin-right: 5px;
+  }
+  .menuChildIcon {
+    margin-right: 2px;
+  }
+
+  .menuActiveColor {
+    color: #409eff;
+  }
+
+  .menuTitle {
+    font-weight: 700;
+  }
 }
 
 /* 水平样式 */

+ 5 - 2
src/components/table/Table.vue

@@ -129,7 +129,9 @@ const paginationTableData = computed<Array<TableData>>(() => {
  * @description: 查询表格
  * @return {*}
  */
-const queryTable = () => {}
+const queryTable = (queryParams: any) => {
+  console.log(queryParams)
+}
 
 const resetTable = () => {}
 
@@ -264,7 +266,8 @@ onMounted(() => {
           border
           table-layout="fixed"
           :scrollbar-always-on="true"
-          :row-style="() => `height:${rowHeight}px`"
+          :row-style="() => `height:${rowHeight}px;color:#333;`"
+          :header-row-style="() => `color:black`"
         >
           <template v-for="item in tableFieldsInfo" :key="item.name">
             <el-table-column

+ 1 - 1
src/components/table/TableQueryForm.vue

@@ -59,7 +59,7 @@ const initfilterForm = () => {
     }
     // 把时间类型给个默认值
     if (val.type === TableFilterType.Date) {
-      val.value = [shortcuts[0].value()[0], shortcuts[0].value()[1]]
+      val.value = shortcuts[0].value
     }
 
     // 表单给初始值

+ 3 - 12
src/hooks/HomeSelect/useAnalysisSelect.ts

@@ -6,6 +6,7 @@ import type {
   CSelectRadio,
   CSelectDate,
   CSelectLegend,
+  DateOptionVal,
 } from '@/types/HomeTypes'
 import { reactive } from 'vue'
 
@@ -75,9 +76,8 @@ export type {
   RightToolsSelectInfo,
 }
 
-import { resetTimeToMidnight } from '@/utils/common'
 import { useDate } from '../useDate'
-const { shortcuts } = useDate()
+const { createSelectDateOption } = useDate()
 
 export function useAnalysisSelect() {
   // 媒体选择选项
@@ -93,16 +93,7 @@ export function useAnalysisSelect() {
   ]
 
   // 日期选择
-  const dateSelectOptions: Array<DateOption> = [
-    {
-      label: '今天',
-      value: [resetTimeToMidnight(new Date()), resetTimeToMidnight(new Date())],
-    },
-    {
-      label: '上一周',
-      value: shortcuts[0].value().map(resetTimeToMidnight),
-    },
-  ]
+  const dateSelectOptions: Array<DateOption> = createSelectDateOption()
 
   // 项目选择
   const projSelectOptions: Array<BaseOption> = [

+ 5 - 14
src/hooks/HomeSelect/useOverviewSelect.ts

@@ -15,9 +15,9 @@ interface OverviewSelectInfo extends CSelectInfo {
   dateSelect: CSelectDate
   customIndicatorSelect: CSelectMutipleTag
 }
-import { resetTimeToMidnight } from '@/utils/common'
+import { batchFormatterTime } from '@/utils/common'
 import { useDate } from '../useDate'
-const { shortcuts } = useDate()
+const { createSelectDateOption } = useDate()
 export type { OverviewSelectInfo }
 
 export function useOverviewSelect() {
@@ -28,22 +28,13 @@ export function useOverviewSelect() {
       value: 'all',
     },
     {
-      label: '全部媒体',
-      value: 'all',
+      label: '全部媒体1',
+      value: 'all1',
     },
   ]
 
   // 日期选择
-  const dateSelectOptions: Array<DateOption> = [
-    {
-      label: '今天',
-      value: [resetTimeToMidnight(new Date()), resetTimeToMidnight(new Date())],
-    },
-    {
-      label: '上一周',
-      value: shortcuts[0].value().map(resetTimeToMidnight),
-    },
-  ]
+  const dateSelectOptions: Array<DateOption> = createSelectDateOption()
 
   // 自定义指标选择
   const indicatorSelectOptions: Array<BaseOption> = [

+ 150 - 14
src/hooks/useDate.ts

@@ -1,36 +1,171 @@
+import type { DateOptionVal } from '@/types/HomeTypes'
+import type { DateOption } from '@/types/HomeTypes'
+import { batchFormatterTime } from '@/utils/common'
+
+interface ShortCutsDate {
+  name: string
+  text: string
+  value: Date[]
+  formatterVal: string[]
+}
+
+export type { ShortCutsDate }
+
 export function useDate() {
   /**
    * @description: 创建一个日期范围
-   * @param {*} day 天数
+   * 如-7,1表示从今天开始往前推7天,到昨天结束
+   * -1,-1,表示昨天,0,0表示今天,1,1,也表示昨天
+   * @param {number} startDay 开始的日期,可正可负,均表示距离今天的天数
+   * @param {number} endDay 结束日期,可正可负,也表示距离今天的天数,如不传则为开始日期,表示同一天
    * @return {*}
    */
-  const createDateRange = (day: number): Array<Date> => {
-    const end = new Date()
+  const createDateRange = (startDay: number, endDay?: number) => {
+    if (endDay === undefined) endDay = startDay
+
+    startDay = Math.abs(startDay)
+    endDay = Math.abs(endDay)
+    if (startDay < endDay) [startDay, endDay] = [endDay, startDay]
     const start = new Date()
-    start.setTime(start.getTime() - 3600 * 1000 * 24 * day)
+    const end = new Date()
+    start.setTime(start.getTime() - 3600 * 1000 * 24 * startDay)
+    end.setTime(end.getTime() - 3600 * 1000 * 24 * endDay)
     return [start, end]
   }
 
+  /**
+   * @description: 根据type值来获取指定count之前的日期范围
+   * @param {*} type 类型
+   * @param {number} count 往前推的周数、月数、年数
+   * @return {date[]} 开始日期和结束日期
+   */
+  const getRangeForPeriod = (
+    type: 'week' | 'month' | 'year',
+    count: number,
+  ) => {
+    const now = new Date()
+    count = Math.abs(count) // 确保count为正数,表示往前推的周数或月数
+
+    if (type === 'week') {
+      // 计算指定前N周的开始和结束日期
+      const startOfWeek = new Date(now)
+      const endOfWeek = new Date(now)
+
+      // 获取当前是星期几 (周日为0,设为7)
+      const dayOfWeek = now.getDay() || 7
+
+      // 计算目标周的开始和结束
+      startOfWeek.setDate(now.getDate() - dayOfWeek + 1 - count * 7) // 前N周的周一
+      endOfWeek.setDate(now.getDate() + (7 - dayOfWeek) - count * 7) // 前N周的周日
+
+      return [startOfWeek, endOfWeek]
+    } else if (type === 'month') {
+      // 计算指定前N个月的开始和结束日期
+      const startOfMonth = new Date(
+        now.getFullYear(),
+        now.getMonth() - count,
+        1,
+      ) // 前N个月的1号
+      const endOfMonth = new Date(
+        now.getFullYear(),
+        now.getMonth() - count + 1,
+        0,
+      ) // 前N个月的最后一天
+
+      return [startOfMonth, endOfMonth]
+    } else if (type === 'year') {
+      // 计算指定前N年的开始和结束日期
+      const startOfYear = new Date(now.getFullYear() - count, 0, 1) // 前N年的1月1号
+      const endOfYear = new Date(now.getFullYear() - count, 11, 31) // 前N年的12月31号
+      return [startOfYear, endOfYear]
+    } else {
+      return [new Date(), new Date()]
+    }
+  }
+
   // 快速选择日期
-  const shortcuts: Array<{
-    text: string
-    value: () => Date[]
-  }> = [
+  const shortcuts: Array<ShortCutsDate> = [
+    {
+      name: 'today',
+      text: '今天',
+      value: (() => createDateRange(0))(),
+      formatterVal: (() => batchFormatterTime(createDateRange(0)))(),
+    },
     {
-      text: '上一周',
-      value: () => createDateRange(7),
+      name: 'yesterday',
+      text: '昨天',
+      value: (() => createDateRange(-1, -1))(),
+      formatterVal: (() => batchFormatterTime(createDateRange(-1, -1)))(),
     },
     {
-      text: '上个月',
-      value: () => createDateRange(30),
+      name: 'last7days',
+      text: '过去7天(不含今天)',
+      value: (() => createDateRange(-7, -1))(),
+      formatterVal: (() => batchFormatterTime(createDateRange(-7, -1)))(),
     },
     {
-      text: '近三个月',
-      value: () => createDateRange(90),
+      name: 'last30days',
+      text: '过去30天(不含今天)',
+      value: (() => createDateRange(-30, -1))(),
+      formatterVal: (() => batchFormatterTime(createDateRange(-30, -1)))(),
+    },
+    {
+      name: 'thisweek',
+      text: '本周',
+      value: (() => getRangeForPeriod('week', 0))(),
+      formatterVal: (() => batchFormatterTime(getRangeForPeriod('week', 0)))(),
+    },
+    {
+      name: 'lastweek',
+      text: '上周',
+      value: (() => getRangeForPeriod('week', 1))(),
+      formatterVal: (() => batchFormatterTime(getRangeForPeriod('week', 1)))(),
+    },
+    {
+      name: 'thismonth',
+      text: '本月',
+      value: (() => getRangeForPeriod('month', 0))(),
+      formatterVal: (() => batchFormatterTime(getRangeForPeriod('month', 0)))(),
+    },
+    {
+      name: 'lastmonth',
+      text: '上月',
+      value: (() => getRangeForPeriod('month', 1))(),
+      formatterVal: (() => batchFormatterTime(getRangeForPeriod('month', 1)))(),
+    },
+    {
+      name: 'thisyear',
+      text: '本年',
+      value: (() => getRangeForPeriod('year', 0))(),
+      formatterVal: (() => batchFormatterTime(getRangeForPeriod('year', 0)))(),
+    },
+    {
+      name: 'lastyear',
+      text: '去年',
+      value: (() => getRangeForPeriod('year', 1))(),
+      formatterVal: (() => batchFormatterTime(getRangeForPeriod('year', 1)))(),
     },
   ]
 
   /**
+   * @description: 生成日期选择器所需要的options
+   * @param {*} Array
+   * @return {*}
+   */
+  const createSelectDateOption = (): Array<DateOption> => {
+    return shortcuts.map(item => {
+      return {
+        label: item.text,
+        value: {
+          name: item.name,
+          startTime: item.formatterVal[0],
+          endTime: item.formatterVal[1],
+        },
+      }
+    })
+  }
+
+  /**
    * @description: 禁止选取今天之后的日期
    * @param {*} date
    * @return {*}
@@ -41,6 +176,7 @@ export function useDate() {
 
   return {
     shortcuts,
+    createSelectDateOption,
     disableDate,
     createDateRange,
   }

+ 1 - 0
src/hooks/useRequest.ts

@@ -16,6 +16,7 @@ export function useRequest() {
   }
 
   const AllApi = {
+    userLogin: ``,
     mockAdTTAcc: `http://127.0.0.1:8003/mock/ad/ttacc`,
     mockAdTTProj: `http://127.0.0.1:8003/mock/ad/ttproj`,
     mockAdTTAd: `http://127.0.0.1:8003/mock/ad/ttad`,

+ 1 - 0
src/router/index.ts

@@ -5,6 +5,7 @@ import { authLogin } from '@/utils/axios/auth'
 import LoginRoutes from './login'
 import HomeRoutes from './home'
 
+// 路由配置
 const routes = [
   ...LoginRoutes,
 

+ 18 - 2
src/types/HomeTypes/index.ts

@@ -25,9 +25,19 @@ interface BaseOption extends CSelectOption {
   value: string
 }
 
+/**
+ * @description: 日期类型选项值
+ * @return {*}
+ */
+interface DateOptionVal {
+  name: string
+  startTime: string
+  endTime: string
+}
+
 // 日期下拉框选项类型
 interface DateOption extends CSelectOption {
-  value: string[]
+  value: DateOptionVal
 }
 
 // 总览数据选择框格式
@@ -51,7 +61,7 @@ interface CSelectRadio extends CSelectItem {
 interface CSelectDate extends CSelectItem {
   type: CSelectType.Radio
   options: Array<DateOption>
-  value: string[]
+  value: DateOptionVal
 }
 
 // 多选带
@@ -81,8 +91,13 @@ interface CSelectInfo {
   [key: string]: CSelectItem
 }
 
+// 所有选项值类型
+type AllOptionsVal = string | DateOptionVal | string[]
+
 export { CSelectType }
 
+export type { AllOptionsVal }
+
 export type {
   overviewAdvertisingData,
   CSelectOption,
@@ -91,6 +106,7 @@ export type {
   CSelectInfo,
   CSelectItem,
   CSelectRadio,
+  DateOptionVal,
   CSelectDate,
   CSelectMutiple,
   CSelectMutipleTag,

+ 38 - 23
src/utils/common/index.ts

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-26 15:46:42
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-10-19 16:35:03
+ * @LastEditTime: 2024-10-24 10:31:17
  * @FilePath: \Quantity-Creation-Management-System\src\utils\common\index.ts
  * @Description:
  *
@@ -76,38 +76,53 @@ export function generateHourlyArray(count: number) {
   return result
 }
 
-// 格式化时间,20240816=>2024-8-16
-export function formatDate(dateString: string) {
-  // 从字符串中提取年份、月份和日期
-  const year = dateString.slice(0, 4)
-  const month = dateString.slice(4, 6)
-  const day = dateString.slice(6, 8)
+// // 格式化时间,20240816=>2024-8-16
+// export function formatDate(dateString: string) {
+//   // 从字符串中提取年份、月份和日期
+//   const year = dateString.slice(0, 4)
+//   const month = dateString.slice(4, 6)
+//   const day = dateString.slice(6, 8)
 
-  // 将月份和日期转换为整数以去除前导零
-  const formattedMonth = parseInt(month, 10)
-  const formattedDay = parseInt(day, 10)
+//   // 将月份和日期转换为整数以去除前导零
+//   const formattedMonth = parseInt(month, 10)
+//   const formattedDay = parseInt(day, 10)
 
-  // 生成新的日期字符串
-  return `${year}-${formattedMonth}-${formattedDay}`
-}
-
-// 将date对象转为yaer-month-day的格式
-export function resetTimeToMidnight(dateTime: Date): string {
-  // 创建一个 Date 对象来解析输入的日期时间字符串
-
-  // 将时间部分设置为 00:00:00
-  dateTime.setHours(0, 0, 0, 0)
+//   // 生成新的日期字符串
+//   return `${year}-${formattedMonth}-${formattedDay}`
+// }
 
+/**
+ * @description: 格式化一个时间为year-month-day的格式
+ * @param {Date} date 日期
+ * @return {string} 返回格式化后的字符串
+ */
+export function formatterDate(date: Date): string {
+  date.setHours(0, 0, 0, 0)
   // 格式化日期为 'YYYY-MM-DD' 格式
-  const year = dateTime.getFullYear()
-  const month = String(dateTime.getMonth() + 1).padStart(2, '0') // 月份从0开始,需要加1
-  const day = String(dateTime.getDate()).padStart(2, '0')
+  const year = date.getFullYear()
+  const month = String(date.getMonth() + 1).padStart(2, '0') // 月份从0开始,需要加1
+  const day = String(date.getDate()).padStart(2, '0')
 
   // 返回格式化的字符串
   return `${year}-${month}-${day}`
 }
 
 /**
+ * @description: 将日期或日期数组转为year-month-day格式
+ * @param {Date} dateTime 日期或日期数组
+ * @return {string | string[]} 返回格式化的日期或日期数组
+ */
+export function batchFormatterTime<T extends Date | Date[]>(
+  dateTime: T,
+): T extends Date[] ? string[] : string {
+  if (Array.isArray(dateTime)) {
+    return dateTime.map(item => formatterDate(item)) as any
+  }
+  // 返回格式化的字符串
+  return formatterDate(dateTime) as any
+}
+
+/**
  * @description:  判断日期范围是否有效
  * @param {string} startTime 开始时间
  * @param {string} endTime 结束时间

+ 8 - 8
src/utils/resource/index.ts

@@ -2,8 +2,8 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-31 14:51:20
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-10-14 16:11:04
- * @FilePath: \Game-Backstage-Management-System\src\utils\resource\index.ts
+ * @LastEditTime: 2024-10-24 14:09:36
+ * @FilePath: \Quantity-Creation-Management-System\src\utils\resource\index.ts
  * @Description:
  *
  */
@@ -33,8 +33,8 @@ export const loadResource = async (url: string): Promise<string> => {
     resourceCache[url] = objectURL
     return objectURL
   } catch (err) {
-    console.log(err)
-    throw new Error('资源加载失败')
+    console.error(err)
+    return ''
   }
 }
 
@@ -44,7 +44,7 @@ export const loadResource = async (url: string): Promise<string> => {
  * @return {*} 返回一个包含了key和blobURL的对象,用来表示所有资源的请求情况
  */
 export const initLoadResouce = (
-  resourceObj: Record<string, string>
+  resourceObj: Record<string, string>,
 ): Promise<Record<string, string>> => {
   // 获取所有的 URL 列表
   let urlList = Object.entries(resourceObj) // [key, url] 格式
@@ -52,12 +52,12 @@ export const initLoadResouce = (
   // 创建请求列表
   let reqList: Promise<[string, string | null]>[] = urlList.map(([key, url]) =>
     loadResource(url)
-      .then((objectURL) => [key, objectURL] as [string, string])
-      .catch(() => [key, null] as [string, string | null])
+      .then(objectURL => [key, objectURL] as [string, string])
+      .catch(() => [key, null] as [string, string | null]),
   )
 
   // 使用 Promise.all 处理所有请求
-  return Promise.all(reqList).then((results) => {
+  return Promise.all(reqList).then(results => {
     // 创建返回对象
     let resultObj: Record<string, string> = {}
     results.forEach(([key, value]) => {

+ 14 - 4
src/views/Home/Home.vue

@@ -1,5 +1,9 @@
 <script setup lang="ts">
-import type { overviewAdvertisingData } from '@/types/HomeTypes'
+import type {
+  DateOption,
+  DateOptionVal,
+  overviewAdvertisingData,
+} from '@/types/HomeTypes'
 import type { BaseMenu } from '@/types/Promotion/Menu'
 import type {
   HomeAnalysisChartData,
@@ -19,6 +23,7 @@ import { useHomeSelect } from '@/hooks/HomeSelect/useHomeSelect'
 
 import axiosInstance from '@/utils/axios/axiosInstance'
 import type { ResponseInfo } from '@/types/axios'
+import type { AllOptionsVal } from '@/types/HomeTypes'
 
 const { AllApi } = useRequest()
 
@@ -122,14 +127,19 @@ const chartData = reactive<Array<HomeAnalysisChartData>>([])
  * @param {*} name 字段名
  * @return {*}
  */
-const changeChartSelect = (newVal: string, name: string) => {
+const changeChartSelect = (newVal: AllOptionsVal, name: string) => {
   // 对于date字段特殊处理一下
   if (name === 'date') {
-    analysisReqParams[analysisiMenuActive.value]['startTime'] = newVal[0]
-    analysisReqParams[analysisiMenuActive.value]['endTime'] = newVal[1]
+    analysisReqParams[analysisiMenuActive.value]['startTime'] = (
+      newVal as DateOptionVal
+    ).startTime
+    analysisReqParams[analysisiMenuActive.value]['endTime'] = (
+      newVal as DateOptionVal
+    ).endTime
   } else {
     analysisReqParams[analysisiMenuActive.value][name] = newVal
   }
+  console.log(analysisReqParams[analysisiMenuActive.value])
   getChartData()
 }
 

+ 23 - 37
src/views/Index.vue

@@ -1,11 +1,11 @@
 <script setup lang="ts">
 import type { BaseMenu } from '@/types/Promotion/Menu'
-import { initLoadResouce } from '@/utils/resource'
-import { reactive, onMounted, ref } from 'vue'
+import { reactive, onMounted, ref, watch } from 'vue'
 import router from '@/router'
 import { setLoginState } from '@/utils/localStorage/localStorage'
 import { removeAllToeken } from '@/utils/token/token'
 import Menu from '@/components/navigation/Menu.vue'
+import cIcon from '@/components/cIcon/CIcon.vue'
 
 interface NavBarMenu {
   name: string
@@ -13,14 +13,11 @@ interface NavBarMenu {
 }
 
 // 资源的加载路径
-const resourceInfo: Record<string, string> = {
-  logo: `/logo.svg`,
-  defaultHead: `/img/default/defaultHead.png`,
+const resourceInfo = {
+  logo: `/logo/logo.svg`,
+  defaultHead: `/header/defaultHead.png`,
 }
 
-// 使用blob的资源路径信息
-const blobUrlInfo = reactive<Record<string, string>>({})
-
 // 顶部导航栏信息
 const navBarMenuList: Array<BaseMenu> = [
   {
@@ -89,24 +86,19 @@ const logOut = () => {
   router.push('/login')
 }
 
-onMounted(() => {
-  // 去加载所有需要的资源
-  initLoadResouce(resourceInfo).then(data => {
-    Object.assign(blobUrlInfo, data)
-  })
-})
+const goHome = () => {
+  router.push('/home')
+}
+
+onMounted(() => {})
 </script>
 
 <template>
   <div class="body">
     <div class="navBarBox">
-      <div class="logoBox">
-        <el-image
-          :fit="'fill'"
-          class="logoImg"
-          :src="blobUrlInfo.logo"
-        ></el-image>
-        <span>淳皓科技</span>
+      <div class="logoBox" @click="goHome">
+        <cIcon :src="resourceInfo.logo" :size="30"></cIcon>
+        <span class="logoTitle">淳皓创量</span>
       </div>
 
       <!-- 顶部导航栏 -->
@@ -117,19 +109,6 @@ onMounted(() => {
           :menu-item-style="'padding: 0px 20px;'"
           :menu-list="navBarMenuList"
         ></Menu>
-        <!-- <el-menu
-          :default-active="defaultActive"
-          class="el-menu-demo"
-          mode="horizontal"
-          router
-        >
-          <el-menu-item
-            v-for="item in navBarMenuList"
-            class="navBarMenuItem"
-            :index="item.path"
-            >{{ item.title }}</el-menu-item
-          >
-        </el-menu> -->
       </div>
 
       <div class="headPortraitBox">
@@ -147,10 +126,11 @@ onMounted(() => {
           trigger="click"
         >
           <template #reference>
-            <el-image
+            <!-- <el-image
               class="headPortrait"
               :src="blobUrlInfo.defaultHead"
-            ></el-image>
+            ></el-image> -->
+            <cIcon :src="resourceInfo.defaultHead"></cIcon>
           </template>
           <div class="userTools">
             <span class="userToolsItem" @click="logOut">
@@ -236,10 +216,16 @@ onMounted(() => {
   box-sizing: border-box;
   left: 30px;
   position: relative;
-
+  width: 110px;
   display: flex;
   justify-content: space-between;
   align-items: center;
+  cursor: pointer;
+  user-select: none;
+}
+.logoTitle {
+  font-size: 18px;
+  font-weight: 600;
 }
 
 .navBarMenu {

+ 5 - 17
src/views/Login/LoginView.vue

@@ -3,7 +3,6 @@ import type { RuleInfo } from '@/types/input'
 
 import { onMounted, reactive, ref } from 'vue'
 import { useRequest } from '@/hooks/useRequest'
-import { initLoadResouce } from '@/utils/resource'
 import { setToken, setRefreshToken } from '@/utils/token/token'
 import { setLoginState } from '@/utils/localStorage/localStorage'
 
@@ -11,6 +10,7 @@ import router from '@/router'
 import axiosInstance from '@/utils/axios/axiosInstance'
 import MyButton from '@/components/form/MyButton.vue'
 import MyInput from '@/components/form/MyInput.vue'
+import CIcon from '@/components/cIcon/CIcon.vue'
 
 const { AllApi, analysisResCode } = useRequest()
 
@@ -75,13 +75,10 @@ const formFieldsRules = reactive<{
 })
 
 // 资源的加载路径
-const resourceInfo: Record<string, string> = {
-  logo: `/img/logo.svg`,
+const resourceInfo = {
+  logo: `/logo/logo.svg`,
 }
 
-// 使用blob的资源路径数组
-const blobUrlInfo = reactive<Record<string, string>>({})
-
 /**
  * @description: 验证登录信息是否符合表单规则
  * @param {*} loginInfo 登录信息
@@ -119,12 +116,7 @@ const userLogin = async () => {
   }
 }
 
-onMounted(() => {
-  // 去加载所有需要的资源
-  initLoadResouce(resourceInfo).then(data => {
-    Object.assign(blobUrlInfo, data)
-  })
-})
+onMounted(() => {})
 </script>
 
 <template>
@@ -134,11 +126,7 @@ onMounted(() => {
       <div class="banner"></div>
       <div class="logoBox">
         <div class="logoImg">
-          <el-image
-            :fit="'fill'"
-            class="logoImg"
-            :src="blobUrlInfo.logo"
-          ></el-image>
+          <CIcon :src="resourceInfo.logo"></CIcon>
         </div>
 
         <span class="logoText">淳皓科技</span>

+ 3 - 3
src/views/Promotion/adManage/ttad.vue

@@ -338,8 +338,8 @@ const projectFilter: FilterInfo = {
     label: '创建时间',
     name: 'creationTime',
     type: TableFilterType.Date,
-    startDate: shortcuts[0].value()[0],
-    endDate: shortcuts[0].value()[1],
+    startDate: shortcuts[0].value[0],
+    endDate: shortcuts[0].value[1],
     value: '',
   },
   adType: {
@@ -606,7 +606,7 @@ const ttAdMenu: BaseMenu[] = [
 ]
 
 // 选择的日期
-const selectDate = ref(shortcuts[0].value())
+const selectDate = ref(shortcuts[0].value)
 
 /**
  * @description: 保存的文件名

+ 12 - 10
src/views/Promotion/promotion.vue

@@ -42,24 +42,26 @@ const isCollapse = ref(false)
 // 菜单默认选中
 const defaultActive = ref<string>(router.currentRoute.value.path)
 
+// 菜单配置
+// 其中父菜单的path需要配置,如果没有子菜单,父菜单的path将作为跳转路由和高亮的依据,参考Meun组件
 const menu: Array<BaseMenu> = [
   {
     name: 'adManage',
     title: '广告管理',
-    iconDefault: '/img/promotion/ad-manage-default.svg',
-    iconActive: '/img/promotion/ad-manage-active.svg',
-    path: '/promotion/ttAd',
+    iconDefault: '/promotion/ad-manage-default.svg',
+    iconActive: '/promotion/ad-manage-active.svg',
+    path: '/promotion',
     children: [
       {
         name: 'TtAd',
         title: '巨量广告',
-        iconDefault: '/img/promotion/ad-tt.svg',
+        iconDefault: '/promotion/ad-tt.svg',
         path: '/promotion/ttAd',
       },
       {
         name: 'TencentAd',
         title: '腾讯广告',
-        iconDefault: '/img/promotion/ad-tencent.svg',
+        iconDefault: '/promotion/ad-tencent.svg',
         path: '/promotion/tencentAd',
       },
     ],
@@ -67,20 +69,20 @@ const menu: Array<BaseMenu> = [
   {
     name: 'accManage',
     title: '账号管理',
-    iconDefault: '/img/promotion/acc-manage-default.svg',
-    iconActive: '/img/promotion/acc-manage-active.svg',
-    path: '/promotion/accTtAd',
+    iconDefault: '/promotion/acc-manage-default.svg',
+    iconActive: '/promotion/acc-manage-active.svg',
+    path: '/promotion',
     children: [
       {
         name: 'AccTtAd',
         title: '巨量广告',
-        iconDefault: '/img/promotion/ad-tt.svg',
+        iconDefault: '/promotion/ad-tt.svg',
         path: '/promotion/accTtAd',
       },
       {
         name: 'AccTencentAd',
         title: '腾讯广告',
-        iconDefault: '/img/promotion/ad-tencent.svg',
+        iconDefault: '/promotion/ad-tencent.svg',
         path: '/promotion/accTencentAd',
       },
     ],

部分文件因文件數量過多而無法顯示