Browse Source

更新表格组件

fxs 8 months ago
parent
commit
d7c1ecc99c

+ 1 - 0
components.d.ts

@@ -11,6 +11,7 @@ declare module 'vue' {
     ElCol: typeof import('element-plus/es')['ElCol']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
+    ElDialog: typeof import('element-plus/es')['ElDialog']
     ElDivider: typeof import('element-plus/es')['ElDivider']
     ElForm: typeof import('element-plus/es')['ElForm']
     ElFormItem: typeof import('element-plus/es')['ElFormItem']

+ 363 - 0
package-lock.json

@@ -31,6 +31,7 @@
         "npm-run-all2": "^6.2.3",
         "prettier": "^3.3.3",
         "rollup-plugin-visualizer": "^5.12.0",
+        "sass": "^1.80.2",
         "typescript": "~5.5.4",
         "unplugin-auto-import": "^0.18.3",
         "unplugin-icons": "^0.19.3",
@@ -851,6 +852,292 @@
         "node": ">= 8"
       }
     },
+    "node_modules/@parcel/watcher": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.4.1.tgz",
+      "integrity": "sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "detect-libc": "^1.0.3",
+        "is-glob": "^4.0.3",
+        "micromatch": "^4.0.5",
+        "node-addon-api": "^7.0.0"
+      },
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "optionalDependencies": {
+        "@parcel/watcher-android-arm64": "2.4.1",
+        "@parcel/watcher-darwin-arm64": "2.4.1",
+        "@parcel/watcher-darwin-x64": "2.4.1",
+        "@parcel/watcher-freebsd-x64": "2.4.1",
+        "@parcel/watcher-linux-arm-glibc": "2.4.1",
+        "@parcel/watcher-linux-arm64-glibc": "2.4.1",
+        "@parcel/watcher-linux-arm64-musl": "2.4.1",
+        "@parcel/watcher-linux-x64-glibc": "2.4.1",
+        "@parcel/watcher-linux-x64-musl": "2.4.1",
+        "@parcel/watcher-win32-arm64": "2.4.1",
+        "@parcel/watcher-win32-ia32": "2.4.1",
+        "@parcel/watcher-win32-x64": "2.4.1"
+      }
+    },
+    "node_modules/@parcel/watcher-android-arm64": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz",
+      "integrity": "sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-darwin-arm64": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz",
+      "integrity": "sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-darwin-x64": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz",
+      "integrity": "sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-freebsd-x64": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz",
+      "integrity": "sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm-glibc": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz",
+      "integrity": "sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm64-glibc": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz",
+      "integrity": "sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm64-musl": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz",
+      "integrity": "sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-x64-glibc": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz",
+      "integrity": "sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-x64-musl": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz",
+      "integrity": "sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-arm64": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz",
+      "integrity": "sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-ia32": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz",
+      "integrity": "sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-x64": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz",
+      "integrity": "sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
     "node_modules/@pkgr/core": {
       "version": "0.1.1",
       "resolved": "https://registry.npmmirror.com/@pkgr/core/-/core-0.1.1.tgz",
@@ -2054,6 +2341,19 @@
         "node": ">=8"
       }
     },
+    "node_modules/detect-libc": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz",
+      "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "detect-libc": "bin/detect-libc.js"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
     "node_modules/echarts": {
       "version": "5.5.1",
       "resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.5.1.tgz",
@@ -2761,6 +3061,13 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/immutable": {
+      "version": "4.3.7",
+      "resolved": "https://registry.npmmirror.com/immutable/-/immutable-4.3.7.tgz",
+      "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/import-fresh": {
       "version": "3.3.0",
       "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -3257,6 +3564,13 @@
         "node": ">= 4.4.x"
       }
     },
+    "node_modules/node-addon-api": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz",
+      "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/normalize-path": {
       "version": "3.0.0",
       "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -3847,6 +4161,55 @@
       "license": "MIT",
       "optional": true
     },
+    "node_modules/sass": {
+      "version": "1.80.2",
+      "resolved": "https://registry.npmmirror.com/sass/-/sass-1.80.2.tgz",
+      "integrity": "sha512-9wXY8cGBlUmoUoT+vwOZOFCiS+naiWVjqlreN9ar9PudXbGwlMTFwCR5K9kB4dFumJ6ib98wZyAObJKsWf1nAA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@parcel/watcher": "^2.4.1",
+        "chokidar": "^4.0.0",
+        "immutable": "^4.0.0",
+        "source-map-js": ">=0.6.2 <2.0.0"
+      },
+      "bin": {
+        "sass": "sass.js"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/sass/node_modules/chokidar": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.1.tgz",
+      "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/sass/node_modules/readdirp": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-4.0.2.tgz",
+      "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
     "node_modules/sax": {
       "version": "1.4.1",
       "resolved": "https://registry.npmmirror.com/sax/-/sax-1.4.1.tgz",

+ 1 - 0
package.json

@@ -39,6 +39,7 @@
     "npm-run-all2": "^6.2.3",
     "prettier": "^3.3.3",
     "rollup-plugin-visualizer": "^5.12.0",
+    "sass": "^1.80.2",
     "typescript": "~5.5.4",
     "unplugin-auto-import": "^0.18.3",
     "unplugin-icons": "^0.19.3",

+ 0 - 4
src/assets/base.css

@@ -23,10 +23,6 @@ div {
   box-sizing: border-box;
 }
 
-div {
-  background-color: white;
-}
-
 /* 字节的样式 */
 .el-button {
   /* display: inline-block; */

+ 11 - 6
src/components/navigation/Menu.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { BaseMenu } from '@/types/Promotion/Menu'
 import { useMenu } from '@/hooks/useMenu'
-import { ref, useAttrs } from 'vue'
+import { ref, useAttrs, watch } from 'vue'
 
 const { setRouterDefaultActive } = useMenu()
 
@@ -14,6 +14,7 @@ interface MenuProps {
 
 const props = withDefaults(defineProps<MenuProps>(), {})
 const attrs = useAttrs()
+const emits = defineEmits(['activeChange'])
 
 // 纵向菜单折叠,仅在mode为vertical时生效
 const isCollapse = ref(false)
@@ -28,8 +29,14 @@ const defaultActive = ref()
 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
+  if (attrs.router) {
+    console.log('router')
+    setRouterDefaultActive(defaultActive, props.menuList)
+  } else defaultActive.value = props.defaultActive
+}
+
+const changeSelect = (newVal: string) => {
+  emits('activeChange', newVal)
 }
 
 initDefaultActive()
@@ -50,6 +57,7 @@ initDefaultActive()
       :collapse="isCollapse"
       :style="menuStyle"
       :ellipsis="false"
+      @select="changeSelect"
     >
       <template v-for="menuItem in menuList" :key="menuItem.name">
         <!-- 有子菜单 -->
@@ -119,9 +127,6 @@ initDefaultActive()
 </template>
 
 <style scoped>
-div {
-  background-color: white;
-}
 .menuContainer {
   position: relative;
   height: 100%;

+ 249 - 226
src/components/table/Table.vue

@@ -1,48 +1,29 @@
 <script setup lang="ts">
 import type { TableProps } from '@/types/Tables/table'
 import type { FormInstance } from 'element-plus'
+import type { TableData, BaseFieldInfo } from '@/types/Tables/table'
+
 import { TableFilterType } from '@/types/Tables/table'
 
-import { nextTick, onMounted, reactive, ref } from 'vue'
+import { onMounted, reactive, ref, watch } from 'vue'
 import { Search } from '@element-plus/icons-vue'
 import { Plus, Operation } from '@element-plus/icons-vue'
-import { useRequest } from '@/hooks/useRequest'
-
-import axiosInstance from '@/utils/axios/axiosInstance'
-
-interface AccountData {
-  accountBalance: number // 账户余额
-  accountFlow: number // 账户流动
-  accountName: string // 账户名
-  accountStatus: string // 账户状态
-  action: string // 操作
-  adAccountCount: number // 广告账户数量
-  dailyBudget: number // 每日预算
-  loginEmail: string // 登录邮箱
-  mediaId: string // 媒体ID
-}
-
-type AccountKeys = keyof AccountData
 
-const { AllApi } = useRequest()
 const props = withDefaults(defineProps<TableProps>(), {})
-const tableFieldLWidth = 200
-const tableFieldSWidth = 150
-const xScrollBaseOffset = 100
-
-// 表格字段
-const accountFields: AccountKeys[] = [
-  'accountName',
-  'accountBalance',
-  'accountFlow',
-
-  'accountStatus',
-  'action',
-  'adAccountCount',
-  'dailyBudget',
-  'loginEmail',
-  'mediaId',
-]
+const tableFieldLWidth = 300 // 长单元格的宽度
+const tableFieldSWidth = 200 // 短单元格的宽度
+
+// 表格数据
+const tableData = reactive<Array<TableData>>(props.tableData)
+
+// table 容器
+const tableContent = ref<HTMLElement>()
+
+// table的横向滚动条
+const elScrollBarH = ref<HTMLElement>()
+
+// 表格整体容器
+const tableContainer = ref<HTMLElement>()
 
 // 表单数据
 const filterFormData = reactive<{
@@ -67,6 +48,8 @@ const filterFields = ref<Array<any>>([])
 // 批量操作选中的值
 const batchOper = ref<string>()
 
+const customIndicatorVisible = ref<boolean>(false)
+
 // 批量操作的选项数组
 const batchOperList = reactive<
   Array<{
@@ -84,12 +67,6 @@ const batchOperList = reactive<
   },
 ])
 
-// 表格数据
-const tableData = reactive<Array<any>>([])
-
-// 需要横向固定的字段
-const fixedFields: Array<string> = ['action', 'accountName']
-
 /**
  * @description: 初始化查询表单
  * @return {*}
@@ -99,7 +76,7 @@ const initfilterForm = () => {
     // 表单给初始值
     filterFormData[k] = v.value ? v.value : ''
 
-    // 初始化过滤表单字段的状态信息
+    // 初始化查询表单字段的状态信息
     filterFieldsStateList.push({
       label: v.label,
       state: true,
@@ -156,205 +133,255 @@ const queryTable = () => {
   } = createQueryParams()
 }
 
-const xScrollBox = ref<HTMLElement>()
-const xScroll = ref<HTMLElement>()
-const tableContent = ref<HTMLElement>()
-// const scrollView = ref<Element>()
+/**
+ * @description: 判定当前横向滑动条是否在表格内,有BUG
+ *
+ * @return {*}
+ */
+const isIntable = () => {
+  if (!tableContainer.value && !tableContent.value) return false
+  const { scrollTop, clientHeight, scrollHeight } =
+    tableContainer.value as HTMLElement
+
+  return scrollTop + clientHeight < scrollHeight
+}
 
 /**
- * @description: 判断表格横向是否满足滚动条的生成条件
- * @param {*} boolean
+ * @description: 初始化滑动条
  * @return {*}
  */
-const canCreateTableXScroll = (): boolean => {
-  if (!xScrollBox.value || !tableContent.value || !xScroll.value) {
-    return false
+const initScroll = () => {
+  let sc = document.querySelector('.el-scrollbar__bar') as HTMLElement
+
+  elScrollBarH.value = sc
+  if (isIntable()) {
+    elScrollBarH.value.style.position = 'fixed'
+    elScrollBarH.value.style.left =
+      tableContent.value?.getBoundingClientRect().left + 'px'
   }
-  return true
 }
 
-const initScroll = () => {
-  let scrViw = document.querySelector('.el-scrollbar__view') // 找到表格的实际容器
-  let lastColumn = document.getElementsByClassName('.el-table__cell')
-  console.log(lastColumn)
-  if (!scrViw || !canCreateTableXScroll()) return
-
-  let scrViewWidth = scrViw.clientWidth // 实际容器的宽度
-  let tableWidth = tableContent.value!.offsetWidth // 表格宽度
-  let residueClientWidth = tableWidth - fixedFields.length * tableFieldLWidth // 表格余下的可视宽度
-  let residueActualWidth = scrViewWidth - fixedFields.length * tableFieldLWidth // 表格余下的实际宽度
-
-  let scrOffsetLeft: number =
-    xScrollBaseOffset + fixedFields.length * tableFieldLWidth // 滑块box的偏移量
-  let scrBoxWidth: number = tableWidth - fixedFields.length * tableFieldLWidth // 滑块box的宽度
-  let xScrollWidth: number =
-    (residueClientWidth / residueActualWidth) * scrBoxWidth
-
-  xScrollBox.value!.style.left = `${scrOffsetLeft}px`
-  xScrollBox.value!.style.width = `${scrBoxWidth}px`
-  xScroll.value!.style.width = `${xScrollWidth}px`
-  console.log(scrOffsetLeft, scrBoxWidth, xScrollWidth)
+/**
+ * @description: 设置横向滑动条的位置
+ * 只有滑动位置到达表格内部时,才需要固定横向滑动条,否则让滚动条回到原来的初始位置,即表格的底部
+ * @return {*}
+ */
+const setElScrollBar = () => {
+  if (isIntable()) {
+    elScrollBarH.value!.style.position = 'fixed'
+    elScrollBarH.value!.style.left =
+      tableContent.value?.getBoundingClientRect().left + 'px'
+  } else {
+    elScrollBarH.value!.style.position = 'absolute'
+  }
+}
+
+/**
+ * @description: 判断当前字段是否是需要固定的字段
+ * @param {*} info 字段信息
+ * @return {boolean}
+ */
+const isFixedField = (info: BaseFieldInfo): boolean => {
+  return props.fixedFields.includes(info.name)
+}
+
+const showCustomIndicator = () => {
+  customIndicatorVisible.value = true
 }
 
 initfilterForm()
 initFilterFields()
 
+watch(
+  () => props.tableData,
+  newData => {
+    tableData.splice(0, tableData.length, ...newData)
+  },
+  {
+    deep: true,
+  },
+)
 onMounted(() => {
-  axiosInstance.get(AllApi.mockData).then(res => {
-    console.log(res)
-    tableData.splice(0, tableData.length, ...res.data)
-    initScroll()
-  })
+  initScroll()
 })
 </script>
 
 <template>
-  <div class="tableContainer">
-    <div class="filterContainer">
-      <div class="filterContent">
-        <el-form
-          :model="filterFormData"
-          label-width="auto"
-          ref="filterFormRef"
-          :inline="true"
-        >
-          <!-- <div class="filterFields"> -->
-          <el-form-item>
-            <el-input
-              :readonly="true"
-              placeholder="筛选字段"
-              prefix-icon="Filter"
-              style="width: 200px; margin-bottom: 10px"
-            >
-              <template #append>
+  <div class="tableContainer" ref="tableContainer" @scroll="setElScrollBar">
+    <div class="testContainer">
+      <div class="filterContainer">
+        <div class="filterContent">
+          <el-form
+            :model="filterFormData"
+            label-width="auto"
+            ref="filterFormRef"
+            :inline="true"
+          >
+            <!-- <div class="filterFields"> -->
+            <el-form-item>
+              <el-input
+                :readonly="true"
+                placeholder="筛选字段"
+                prefix-icon="Filter"
+                style="width: 200px; margin-bottom: 10px"
+              >
+                <template #append>
+                  <el-select
+                    v-model="filterFields"
+                    multiple
+                    collapse-tags
+                    collapse-tags-tooltip
+                    placeholder="Select"
+                    style="width: 100px"
+                  >
+                    <el-option
+                      v-for="item in filterFieldsStateList"
+                      :key="item.value"
+                      :label="item.label"
+                      :value="item.value"
+                    />
+                  </el-select>
+                </template>
+              </el-input>
+            </el-form-item>
+            <!-- </div> -->
+            <template v-for="item in filtersInfo" :key="item.name">
+              <el-form-item :prop="item.name">
+                <el-input
+                  class="filterItem"
+                  v-if="
+                    filterFields.includes(item.name) &&
+                    item.type === TableFilterType.Search
+                  "
+                  v-model="filterFormData[item.name]"
+                  style="width: 240px"
+                  placeholder="Please Input"
+                  :suffix-icon="Search"
+                />
+
                 <el-select
-                  v-model="filterFields"
-                  multiple
-                  collapse-tags
-                  collapse-tags-tooltip
+                  class="filterItem"
+                  v-if="
+                    filterFields.includes(item.name) &&
+                    item.type === TableFilterType.Select
+                  "
+                  v-model="filterFormData[item.name]"
                   placeholder="Select"
-                  style="width: 100px"
+                  style="width: 240px"
                 >
+                  <template #label="{ label, value }">
+                    <span>{{ item.label }}: </span>
+                    <span style="margin-left: 10px">{{ value }}</span>
+                  </template>
                   <el-option
-                    v-for="item in filterFieldsStateList"
-                    :key="item.value"
-                    :label="item.label"
-                    :value="item.value"
+                    v-for="option in item.options"
+                    :key="option.value"
+                    :label="option.label"
+                    :value="option.value"
                   />
                 </el-select>
-              </template>
-            </el-input>
-          </el-form-item>
-          <!-- </div> -->
-          <template v-for="item in filtersInfo" :key="item.name">
-            <el-form-item :prop="item.name">
-              <el-input
-                class="filterItem"
-                v-if="
-                  filterFields.includes(item.name) &&
-                  item.type === TableFilterType.Search
-                "
-                v-model="filterFormData[item.name]"
-                style="width: 240px"
-                placeholder="Please Input"
-                :suffix-icon="Search"
+              </el-form-item>
+            </template>
+          </el-form>
+        </div>
+        <div class="filterButtonContainer">
+          <el-button class="queryBtn" color="#197afb" @click="queryTable"
+            >查询</el-button
+          >
+          <el-button
+            class="queryBtn"
+            color="#626aef"
+            plain
+            @click="resetFilterForm"
+            >重置</el-button
+          >
+        </div>
+      </div>
+      <div class="operationContainer">
+        <div class="tableOperationLeft">
+          <slot name="addItem">
+            <el-button class="addItem w120" plain :icon="Plus"
+              >添加账户</el-button
+            >
+          </slot>
+          <slot name="batchOper">
+            <el-select
+              class="batchOper w120"
+              v-model="batchOper"
+              placeholder="批量操作"
+            >
+              <el-option
+                v-for="item in batchOperList"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
               />
-
-              <el-select
-                class="filterItem"
-                v-if="
-                  filterFields.includes(item.name) &&
-                  item.type === TableFilterType.Select
+            </el-select>
+          </slot>
+        </div>
+        <div class="tableOperationRight">
+          <slot name="exportData">
+            <el-button class="exportData w120 ml16" plain>导出数据</el-button>
+          </slot>
+          <slot name="customIndicator">
+            <el-button
+              @click="showCustomIndicator"
+              class="customIndicator w120 ml16"
+              plain
+              :icon="Operation"
+              >自定义指标</el-button
+            >
+          </slot>
+        </div>
+      </div>
+      <div class="tableContent" ref="tableContent">
+        <el-table
+          v-bind="{ ...$attrs, data: tableData }"
+          style="width: 100%"
+          border
+          :scrollbar-always-on="true"
+        >
+          <template v-for="k in tableFields">
+            <template v-for="item in k.children" :key="item.name">
+              <el-table-column
+                :width="
+                  isFixedField(item) ? tableFieldLWidth : tableFieldSWidth
                 "
-                v-model="filterFormData[item.name]"
-                placeholder="Select"
-                style="width: 240px"
+                :fixed="isFixedField(item)"
+                :prop="item.name"
+                :label="item.label"
+                v-if="item.state"
               >
-                <template #label="{ label, value }">
-                  <span>{{ item.label }}: </span>
-                  <span style="margin-left: 10px">{{ value }}</span>
-                </template>
-                <el-option
-                  v-for="option in item.options"
-                  :key="option.value"
-                  :label="option.label"
-                  :value="option.value"
-                />
-              </el-select>
-            </el-form-item>
+              </el-table-column>
+            </template>
           </template>
-        </el-form>
-      </div>
-      <div class="filterButtonContainer">
-        <el-button class="queryBtn" color="#197afb" @click="queryTable"
-          >查询</el-button
-        >
-        <el-button
-          class="queryBtn"
-          color="#626aef"
-          plain
-          @click="resetFilterForm"
-          >重置</el-button
-        >
-      </div>
-    </div>
-    <div class="operationContainer">
-      <div class="tableOperationLeft">
-        <slot name="addItem">
-          <el-button class="addItem w120" plain :icon="Plus"
-            >添加账户</el-button
-          >
-        </slot>
-        <slot name="batchOper">
-          <el-select
-            class="batchOper w120"
-            v-model="batchOper"
-            placeholder="批量操作"
-          >
-            <el-option
-              v-for="item in batchOperList"
-              :key="item.value"
-              :label="item.label"
-              :value="item.value"
-            />
-          </el-select>
-        </slot>
-      </div>
-      <div class="tableOperationRight">
-        <slot name="exportData">
-          <el-button class="exportData w120 ml16" plain>导出数据</el-button>
-        </slot>
-        <slot name="customIndicator">
-          <el-button class="customIndicator w120 ml16" plain :icon="Operation"
-            >自定义指标</el-button
-          >
-        </slot>
+        </el-table>
       </div>
     </div>
-    <div class="tableContent" ref="tableContent">
-      <!-- height="250" -->
-      <el-table
-        v-bind="{ ...$attrs, data: tableData }"
-        style="width: 100%"
-        border
-        :scrollbar-always-on="true"
+    <div class="customIndicatorContainer">
+      <el-dialog
+        v-model="customIndicatorVisible"
+        title="自定义指标"
+        width="1096"
+        :append-to-body="true"
+        :align-center="true"
       >
-        <el-table-column
-          :width="fixedFields.includes(k) ? tableFieldLWidth : tableFieldSWidth"
-          v-for="k in accountFields"
-          :fixed="k === 'action'"
-          :prop="k"
-          :label="k"
-        />
-      </el-table>
-      <div class="xScrollBox" ref="xScrollBox">
-        <div class="xScroll" ref="xScroll"></div>
-      </div>
+        <template #footer>
+          <div class="dialog-footer">
+            <el-button @click="customIndicatorVisible = false"
+              >Cancel</el-button
+            >
+            <el-button type="primary" @click="customIndicatorVisible = false">
+              Confirm
+            </el-button>
+          </div>
+        </template>
+      </el-dialog>
     </div>
   </div>
 </template>
 
-<style scoped>
+<style lang="scss" scoped>
 .w120 {
   width: 120px;
 }
@@ -364,7 +391,16 @@ onMounted(() => {
 }
 
 .tableContainer {
+  width: 96%;
+  height: 92%;
+  margin: 0 auto;
+  overflow: auto;
+}
+
+.testContainer {
   width: 100%;
+
+  overflow: scroll;
 }
 
 .filterContainer {
@@ -381,7 +417,6 @@ onMounted(() => {
 }
 
 .filterButtonContainer {
-  width: 10%;
   height: 100%;
   display: flex;
 }
@@ -425,22 +460,10 @@ onMounted(() => {
   /* padding: 10px 20px; */
 }
 
-.xScrollBox {
-  width: 811px;
-  position: fixed;
-  top: unset;
-  bottom: 0px;
-  left: 626px;
-  right: unset;
-  display: block;
-}
-
-.xScroll {
-  width: 257.698px;
-  transform: translateX(0px);
-  box-sizing: border-box;
-  height: 10px;
-  background-color: #c1c1c1;
-  border-radius: 3px;
+:deep(.el-scrollbar__bar) {
+  // position: fixed !important;
+  bottom: 5px;
 }
 </style>
+
+<style></style>

+ 4 - 2
src/hooks/useRequest.ts

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-20 17:24:06
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-10-17 12:13:39
+ * @LastEditTime: 2024-10-18 17:15:29
  * @FilePath: \Quantity-Creation-Management-System\src\hooks\useRequest.ts
  * @Description:
  *
@@ -26,7 +26,9 @@ export function useRequest() {
   }
 
   const AllApi = {
-    mockData: `http://127.0.0.1:8003/mock/ad/ttacc`,
+    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`,
   }
 
   /**

+ 21 - 0
src/hooks/useTable.ts

@@ -0,0 +1,21 @@
+import type { TableData } from '@/types/Tables/table'
+import axiosInstance from '@/utils/axios/axiosInstance'
+export function useTable() {
+  const getData = async (
+    url: string,
+    config: Object = {},
+  ): Promise<Array<TableData>> => {
+    try {
+      const res = await axiosInstance.get(url, config)
+      console.log(res)
+      if (res.status !== 0) throw new Error('请求失败')
+      return res.data as TableData[]
+    } catch {
+      console.log('数据请求失败')
+      return []
+    }
+  }
+  return {
+    getData,
+  }
+}

+ 47 - 1
src/types/Tables/table.ts

@@ -1,9 +1,19 @@
+import type { AllAdMgeTtTablesData, AllAdmgeTtFields } from './tableData/ttAd'
+
+// 表格查询表单中表单项的类型
 enum TableFilterType {
   Search,
   Select,
   Date,
 }
 
+// 表格字段的基本信息
+interface BaseFieldInfo {
+  label: string
+  name: string
+  state: boolean // 是否展示这个字段
+}
+
 // 选择框的选项
 interface SelectFilterOptions {
   label: string
@@ -37,15 +47,45 @@ interface DateFilterItem extends BaseFilterItem {
   endDate: Date
 }
 
-// 联合类型
+// 所有表格查询表单中表单项的类型
 type TableFilterItem = SearchFilterItem | SelectFilterItem | DateFilterItem
 
+// 所有表格数据的数据类型
+type TableData = AllAdMgeTtTablesData
+
+// 所有表格的字段
+type TableFields = AllAdmgeTtFields
+
+// 表格每种字段的格式
+interface BaseFieldItem<T> {
+  label: string
+  children: T[]
+}
+
+// 查询字段需要的信息格式
+interface FilterInfo {
+  [key: string]: TableFilterItem
+}
+
 // 表格的props
 interface TableProps {
   filtersInfo: {
     [key: string]: TableFilterItem
   }
+  tableData: Array<TableData>
+  // tableFields: Array<TableFields>
+  tableFields: Array<BaseFieldItem<TableFields>>
+  fixedFields: Array<string>
 }
+
+// 每个表格需要的信息格式,包含通用的属性
+interface TableInfoItem<TData, TFields> {
+  data: TData[] // 数据数组
+  fields: TFields[] // 字段数组
+  filters: FilterInfo // 过滤信息
+  fixedFields: string[] // 固定字段
+}
+
 export { TableFilterType }
 export type {
   SelectFilterOptions,
@@ -55,4 +95,10 @@ export type {
   DateFilterItem,
   TableFilterItem,
   TableProps,
+  TableData,
+  FilterInfo,
+  TableFields,
+  TableInfoItem,
+  BaseFieldInfo,
+  BaseFieldItem,
 }

+ 96 - 0
src/types/Tables/tableData/ttAd.ts

@@ -0,0 +1,96 @@
+// 广告管理-巨量广告表格数据及其字段
+import type { BaseFieldInfo, BaseFieldItem } from '../table'
+
+// 账户表格数据
+interface AdmgeTTAccData {
+  accountBalance: number // 账户余额
+  accountFlow: number // 账户流动
+  accountName: string // 账户名
+  accountStatus: string // 账户状态
+  action: string // 操作
+  adAccountCount: number // 广告账户数量
+  dailyBudget: number // 每日预算
+  loginEmail: string // 登录邮箱
+  mediaId: string // 媒体ID
+}
+
+// 项目表格数据
+interface AdmgeTTProjData {
+  project: string // 项目
+  projectBudget: number // 项目预算(元)
+  creationTime: Date // 创建时间
+  projectBid: number // 项目出价(元)
+  deepConversionBid: number // 深度转化出价(元)
+  consumption: number // 消耗
+  impressions: number // 展示数
+  averageCpm: number // 平均千次展示费用
+  clicks: number // 点击数
+  clickThroughRate: number // 点击率
+  conversions: number // 转化数
+  conversionCost: number // 转化成本
+  conversionRate: number // 转化率
+  deepConversions: number // 深度转化数
+  deepConversionCost: number // 深度转化成本
+  deepConversionRate: number // 深度转化率
+}
+
+// 广告表格数据
+interface AdmgeTTAdData {
+  ad: string // 广告
+  adBudget: number // 广告预算(元)
+  rejectSuggestions: boolean // 拒绝建议
+  adBid: number // 广告出价(元)
+  deepConversionBid: number // 深度转化出价(元)
+  consumption: number // 消耗
+  impressions: number // 展示数
+  averageCpm: number // 平均千次展现费用
+  clicks: number // 点击数
+  clickThroughRate: number // 点击率
+  conversions: number // 转化数
+  conversionCost: number // 转化成本
+  conversionRate: number // 转化率
+  deepConversions: number // 深度转化数
+  deepConversionCost: number // 深度转化成本
+  deepConversionRate: number // 深度转化率
+}
+
+// 账户表格字段key
+type AdmgeTTAccKeys = keyof AdmgeTTAccData
+
+// 账户表格字段信息
+interface AdmgeTTAccFileds extends BaseFieldInfo {
+  name: AdmgeTTAccKeys
+}
+
+// 项目表格字段Key
+type AdmgeTTProjKeys = keyof AdmgeTTProjData
+
+// 项目表格字段信息
+interface AdmgeTTProjFileds extends BaseFieldInfo {
+  name: AdmgeTTProjKeys
+}
+
+// 广告表格字段
+type AdmgeTTAdKeys = keyof AdmgeTTAdData
+
+// 广告表格字段信息
+interface AdmgeTTAdFileds extends BaseFieldInfo {
+  name: AdmgeTTAdKeys
+}
+
+// 巨量广告管理中所有的表格数据类型
+type AllAdMgeTtTablesData = AdmgeTTAccData | AdmgeTTProjData | AdmgeTTAdData
+
+// 巨量广告管理中所有的表格字段
+type AllAdmgeTtFields = AdmgeTTAccFileds | AdmgeTTProjFileds | AdmgeTTAdFileds
+
+export type {
+  AllAdMgeTtTablesData,
+  AllAdmgeTtFields,
+  AdmgeTTAccData,
+  AdmgeTTProjData,
+  AdmgeTTAdData,
+  AdmgeTTAccFileds,
+  AdmgeTTProjFileds,
+  AdmgeTTAdFileds,
+}

+ 1 - 1
src/views/Index.vue

@@ -296,7 +296,7 @@ onMounted(() => {
   position: relative;
   width: 100%;
   height: calc(100% - 64px);
-  overflow: auto;
+  overflow: hidden;
 
   background-color: #f2f3f5;
 

+ 228 - 29
src/views/Promotion/adManage/ttad.vue

@@ -1,42 +1,133 @@
 <script setup lang="ts">
-import { TableFilterType } from '@/types/Tables/table'
-
 import type {
-  SearchFilterItem,
-  SelectFilterItem,
-  DateFilterItem,
-  TableProps,
-  TableFilterItem,
+  TableData,
+  FilterInfo,
+  TableInfoItem,
+  BaseFieldItem,
+  TableFields,
 } from '@/types/Tables/table'
 import type { BaseMenu } from '@/types/Promotion/Menu'
+import type {
+  AdmgeTTAccData,
+  AdmgeTTProjData,
+  AdmgeTTAdData,
+} from '@/types/Tables/tableData/ttAd'
+import type {
+  AdmgeTTAccFileds,
+  AdmgeTTProjFileds,
+  AdmgeTTAdFileds,
+} from '@/types/Tables/tableData/ttAd'
 
+import { TableFilterType } from '@/types/Tables/table'
+
+import { useRequest } from '@/hooks/useRequest'
 import { useDate } from '@/hooks/useDate'
-import { ref } from 'vue'
+import { onMounted, reactive, ref } from 'vue'
+import { useTable } from '@/hooks/useTable'
 
 import Menu from '@/components/navigation/Menu.vue'
 import Table from '@/components/table/Table.vue'
 
+interface TableInfo {
+  [key: string]: any
+  account: TableInfoItem<AdmgeTTAccData, BaseFieldItem<AdmgeTTAccFileds>> // 账户信息
+  project: TableInfoItem<AdmgeTTProjData, BaseFieldItem<AdmgeTTProjFileds>> // 项目信息
+  advertise: TableInfoItem<AdmgeTTAdData, BaseFieldItem<AdmgeTTAdFileds>> // 广告信息
+}
+// interface TableInfo {
+//   [key: string]: any
+//   account: TableInfoItem<AdmgeTTAccData, AdmgeTTAccFileds> // 账户信息
+//   project: TableInfoItem<AdmgeTTProjData, AdmgeTTProjFileds> // 项目信息
+//   advertise: TableInfoItem<AdmgeTTAdData, AdmgeTTAdFileds> // 广告信息
+// }
+
+interface AllFieldsInfo {
+  [key: string]: any
+  account: AdmgeTTAccFileds[]
+  project: AdmgeTTProjFileds[]
+  advertise: AdmgeTTAdFileds[]
+}
+// interface AllFieldsInfo {
+//   [key: string]: BaseFieldItem<TableFields>[]
+//   account: BaseFieldItem<AdmgeTTAccFileds>[]
+//   project: BaseFieldItem<AdmgeTTProjFileds>[]
+//   advertise:  BaseFieldItem<AdmgeTTAdFileds>[]
+// }
+
+interface AllFilterInfo {
+  [key: string]: FilterInfo
+  account: FilterInfo
+  project: FilterInfo
+  advertise: FilterInfo
+}
+
+interface AllFixedFiledsInfo {
+  [key: string]: Array<string>
+  account: Array<string>
+  project: Array<string>
+  advertise: Array<string>
+}
+
+const { AllApi } = useRequest()
 const { disableDate, shortcuts } = useDate()
+const { getData } = useTable()
 
-// 导航
-const ttAdMenu: BaseMenu[] = [
-  {
-    name: 'account',
-    title: '账户',
-  },
-  {
-    name: 'project',
-    title: '项目',
-  },
-  {
-    name: 'advertise',
-    title: '广告',
-  },
-]
+// 当前菜单选中
+const activeMenu = ref('account')
 
-const filterInfo: {
-  [key: string]: TableFilterItem
-} = {
+// 所有子字段信息
+const AllFields: AllFieldsInfo = {
+  account: [
+    { label: '账户余额', name: 'accountBalance', state: true },
+    { label: '账户流动', name: 'accountFlow', state: true },
+    { label: '账户名', name: 'accountName', state: true },
+    { label: '账户状态', name: 'accountStatus', state: true },
+    { label: '操作', name: 'action', state: false },
+    { label: '广告账户数量', name: 'adAccountCount', state: true },
+    { label: '每日预算', name: 'dailyBudget', state: true },
+    { label: '登录邮箱', name: 'loginEmail', state: true },
+    { label: '媒体ID', name: 'mediaId', state: true },
+  ],
+  project: [
+    { label: '项目', name: 'project', state: true },
+    { label: '项目预算(元)', name: 'projectBudget', state: true },
+    { label: '创建时间', name: 'creationTime', state: true },
+    { label: '项目出价(元)', name: 'projectBid', state: true },
+    { label: '深度转化出价(元)', name: 'deepConversionBid', state: true },
+    { label: '消耗', name: 'consumption', state: true },
+    { label: '展示数', name: 'impressions', state: true },
+    { label: '平均千次展示费用', name: 'averageCpm', state: true },
+    { label: '点击数', name: 'clicks', state: true },
+    { label: '点击率', name: 'clickThroughRate', state: true },
+    { label: '转化数', name: 'conversions', state: true },
+    { label: '转化成本', name: 'conversionCost', state: true },
+    { label: '转化率', name: 'conversionRate', state: true },
+    { label: '深度转化数', name: 'deepConversions', state: true },
+    { label: '深度转化成本', name: 'deepConversionCost', state: true },
+    { label: '深度转化率', name: 'deepConversionRate', state: true },
+  ],
+  advertise: [
+    { label: '广告', name: 'ad', state: true },
+    { label: '广告预算(元)', name: 'adBudget', state: true },
+    { label: '拒绝建议', name: 'rejectSuggestions', state: true },
+    { label: '广告出价(元)', name: 'adBid', state: true },
+    { label: '深度转化出价(元)', name: 'deepConversionBid', state: true },
+    { label: '消耗', name: 'consumption', state: true },
+    { label: '展示数', name: 'impressions', state: true },
+    { label: '平均千次展现费用', name: 'averageCpm', state: true },
+    { label: '点击数', name: 'clicks', state: true },
+    { label: '点击率', name: 'clickThroughRate', state: true },
+    { label: '转化数', name: 'conversions', state: true },
+    { label: '转化成本', name: 'conversionCost', state: true },
+    { label: '转化率', name: 'conversionRate', state: true },
+    { label: '深度转化数', name: 'deepConversions', state: true },
+    { label: '深度转化成本', name: 'deepConversionCost', state: true },
+    { label: '深度转化率', name: 'deepConversionRate', state: true },
+  ],
+}
+
+// 账户查询表单信息
+const accFilterInfo: FilterInfo = {
   accMain: {
     label: '账号主体',
     name: 'accMain',
@@ -86,6 +177,85 @@ const filterInfo: {
   },
 }
 
+const allFilters: AllFilterInfo = {
+  account: accFilterInfo,
+  project: {},
+  advertise: {},
+}
+
+const allFixedFileds: AllFixedFiledsInfo = {
+  account: ['accountName', 'action'],
+  project: [],
+  advertise: [],
+}
+
+const tableReqInfo: { [key: string]: any } = {
+  account: AllApi.mockAdTTAcc,
+  project: AllApi.mockAdTTProj,
+  advertise: AllApi.mockAdTTAd,
+}
+
+// 项目查询表单信息
+
+// 广告查询表单信息
+// AllFields['account']
+const tableInfo = reactive<TableInfo>({
+  account: {
+    data: [],
+    fields: [{ label: '基础', children: AllFields['account'] }],
+    filters: allFilters['account'],
+    fixedFields: allFixedFileds['account'],
+  },
+  project: {
+    data: [],
+    fields: [{ label: '基础', children: AllFields['project'] }],
+    filters: allFilters['project'],
+    fixedFields: allFixedFileds['project'],
+  },
+  advertise: {
+    data: [],
+    fields: [{ label: '基础', children: AllFields['advertise'] }],
+    filters: allFilters['advertise'],
+    fixedFields: allFixedFileds['advertise'],
+  },
+})
+// const tableInfo = reactive<TableInfo>({
+//   account: {
+//     data: [],
+//     fields: AllFields['account'],
+//     filters: allFilters['account'],
+//     fixedFields: allFixedFileds['account'],
+//   },
+//   project: {
+//     data: [],
+//     fields: AllFields['project'],
+//     filters: allFilters['project'],
+//     fixedFields: allFixedFileds['project'],
+//   },
+//   advertise: {
+//     data: [],
+//     fields: AllFields['advertise'],
+//     filters: allFilters['advertise'],
+//     fixedFields: allFixedFileds['advertise'],
+//   },
+// })
+
+// 导航
+const ttAdMenu: BaseMenu[] = [
+  {
+    name: 'account',
+    title: '账户',
+  },
+  {
+    name: 'project',
+    title: '项目',
+  },
+  {
+    name: 'advertise',
+    title: '广告',
+  },
+]
+
 // 选择的日期
 const selectDate = ref(shortcuts[0].value())
 
@@ -97,6 +267,27 @@ const selectDate = ref(shortcuts[0].value())
 const dateChange = (val: Array<Date>) => {
   //   emits('changeDate', val)
 }
+
+const menuActiveChange = (val: string) => {
+  activeMenu.value = val
+  updateTableData()
+  console.log('执行')
+  console.log(activeMenu.value)
+  console.log(tableInfo)
+}
+
+const updateTableData = () => {
+  getData(tableReqInfo[activeMenu.value]).then((res: Array<TableData>) => {
+    tableInfo[activeMenu.value].data.splice(
+      0,
+      tableInfo[activeMenu.value].data.length,
+      ...res,
+    )
+  })
+}
+
+updateTableData()
+onMounted(() => {})
 </script>
 
 <template>
@@ -107,6 +298,7 @@ const dateChange = (val: Array<Date>) => {
         :menu-list="ttAdMenu"
         :menu-item-style="'margin-right:30px;'"
         mode="horizontal"
+        @active-change="menuActiveChange"
       ></Menu>
       <div class="datePickerBox">
         <el-date-picker
@@ -126,7 +318,12 @@ const dateChange = (val: Array<Date>) => {
       </div>
     </div>
     <div class="ttAdContent">
-      <Table :filters-info="filterInfo"></Table>
+      <Table
+        :table-fields="tableInfo[activeMenu].fields"
+        :table-data="tableInfo[activeMenu].data"
+        :fixed-fields="tableInfo[activeMenu].fixedFields"
+        :filters-info="tableInfo[activeMenu].filters"
+      ></Table>
     </div>
   </div>
 </template>
@@ -134,6 +331,8 @@ const dateChange = (val: Array<Date>) => {
 <style scoped>
 .ttAdContainer {
   width: 100%;
+  height: 100%;
+  overflow: hidden;
 }
 
 .ttAdHeader {
@@ -145,11 +344,11 @@ const dateChange = (val: Array<Date>) => {
 }
 
 .ttAdContent {
-  width: 96%;
+  width: 100%;
   height: 100%;
   background-color: white;
   margin: 0 auto;
-  overflow: scroll;
+  overflow: hidden;
 }
 
 .datePickerBox {

+ 2 - 1
src/views/Promotion/promotion.vue

@@ -131,8 +131,9 @@ const menu: Array<BaseMenu> = [
 .promotionContent {
   width: 100%;
   height: 100%;
+  overflow: auto;
   /* height: calc(100% - 64px); */
-  overflow: scroll;
+  /* overflow: scroll; */
   /* padding: 20px; */
 }
 </style>

+ 9 - 2
vite.config.ts

@@ -2,8 +2,8 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-08-20 14:06:49
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-10-15 15:39:46
- * @FilePath: \Game-Backstage-Management-Systemc:\Users\NINGMEI\Desktop\Quantity-Creation-Management-System\vite.config.ts
+ * @LastEditTime: 2024-10-18 10:21:28
+ * @FilePath: \Quantity-Creation-Management-System\vite.config.ts
  * @Description:
  *
  */
@@ -133,6 +133,13 @@ export default defineConfig(({ mode }) => {
         autoInstall: true,
       }),
     ],
+    css: {
+      preprocessorOptions: {
+        scss: {
+          api: 'modern-compiler', // or 'modern'
+        },
+      },
+    },
     resolve: {
       alias: {
         '@': fileURLToPath(new URL('./src', import.meta.url)),