Forráskód Böngészése

更新表格数据请求逻辑,现在会直接带查询参数进行请求;新增表格请求取消功能,防止在快速切换表格菜单的时候,出现数据混乱;修复表格查询表单,关于搜索字段的BUG,现在可以正确的传入需要搜索的字段;更新右上角用户信息弹出框;

fxs 7 hónapja
szülő
commit
2db81acace

+ 1 - 0
components.d.ts

@@ -34,6 +34,7 @@ declare module 'vue' {
     ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
     ElTable: typeof import('element-plus/es')['ElTable']
     ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
+    ElText: typeof import('element-plus/es')['ElText']
     HomeAnalysisLine: typeof import('./src/components/echarts/HomeAnalysisLine.vue')['default']
     IconIcBaselineVisibility: typeof import('~icons/ic/baseline-visibility')['default']
     IconIcBaselineVisibilityOff: typeof import('~icons/ic/baseline-visibility-off')['default']

+ 8 - 2
src/components/dialog/customIndicatorDialog.vue

@@ -73,7 +73,7 @@ const fixedIndicator = reactive<TableFields[]>([])
 // 所有需要不固定的指标
 const unFixedIndicator = reactive<TableFields[]>([])
 
-const { dragStart, dragEnter, dragOver } = useDialogDrag(
+const { dragStart, dragEnter, dragOver, dragEnd } = useDialogDrag(
   dragingRef,
   dragContentRef,
 )
@@ -329,6 +329,7 @@ defineExpose({ showCustomIndicator })
             @dragstart="dragStart"
             @dragenter="dragEnter"
             @dragover="dragOver"
+            @dragend="dragEnd"
           >
             <div
               draggable="true"
@@ -505,6 +506,11 @@ defineExpose({ showCustomIndicator })
   }
 }
 
+.dragMove {
+  background-color: white;
+  border: 1px solid #197afb;
+}
+
 .closeBtn {
   display: none;
   cursor: pointer;
@@ -514,7 +520,7 @@ defineExpose({ showCustomIndicator })
 }
 
 .dragBlock:not(.notAllow):hover {
-  background-color: #e7e7e7;
+  // background-color: #e7e7e7;
 }
 // 禁止拖拽
 .notAllow {

+ 6 - 3
src/components/echarts/HomeAnalysisLine.vue

@@ -2,7 +2,7 @@
 import type { EChartsOption, SeriesOption } from 'echarts'
 import type { LegendInfo } from '@/types/echarts/homeAnalysisChart'
 
-import { ref, shallowRef, watch } from 'vue'
+import { onMounted, ref, shallowRef, watch } from 'vue'
 import { cloneDeep } from 'lodash'
 import { nextTick } from 'vue'
 import { debounceFunc } from '@/utils/common'
@@ -151,7 +151,6 @@ const chartResize = () => {
  */
 const initChart = () => {
   if (!chartRef.value) return
-
   chartInstance.value = echarts.init(chartRef.value)
   // 只监听window会导致当侧边栏缩放时,dom大小变化但无法resize
   // 所以需要使用ovserver对整个dom进行监听
@@ -261,7 +260,6 @@ watch(
   (newState: boolean) => {
     changeChartsLoading(newState)
     if (newState === false) {
-      if (!chartInstance.value) initChart()
       initOptions()
     }
   },
@@ -281,6 +279,11 @@ watch(
     deep: true,
   },
 )
+
+onMounted(() => {
+  initChart()
+  changeChartsLoading(props.loading)
+})
 </script>
 
 <template>

+ 31 - 13
src/components/promotion/MenuTable.vue

@@ -83,19 +83,34 @@ const openOperationDialog = () => {
   operationDialog.value = true
 }
 
-const { menuActiveChange, changeScheme, updateCustomIndicator, initData } =
-  useMenuTable(
-    props.saveTableName,
-    fileName,
-    activeMenu,
-    customIndicatorScheme,
-    tableControllers,
-    props.tableInfo,
-    props.tableReqInfo,
-    props.tablePaginationConfig,
-    tableRef,
-    props.menuList,
-  )
+/**
+ * @description: 查询表格
+ * @param {*} params 请求参数
+ * @return {*}
+ */
+const queryTable = (params: any) => {
+  props.tableReqInfo[activeMenu.value].config.params = params
+  updateTableData()
+}
+
+const {
+  menuActiveChange,
+  changeScheme,
+  updateCustomIndicator,
+  initData,
+  updateTableData,
+} = useMenuTable(
+  props.saveTableName,
+  fileName,
+  activeMenu,
+  customIndicatorScheme,
+  tableControllers,
+  props.tableInfo,
+  props.tableReqInfo,
+  props.tablePaginationConfig,
+  tableRef,
+  props.menuList,
+)
 
 const emits = defineEmits(['changeDate'])
 
@@ -127,6 +142,7 @@ onMounted(() => {
           end-placeholder="End date"
           :shortcuts="shortcuts"
           :size="'small'"
+          :clearable="false"
         >
         </el-date-picker>
       </div>
@@ -134,6 +150,7 @@ onMounted(() => {
     <div class="menuTableContent">
       <Table
         ref="tableRef"
+        :active-menu="activeMenu"
         :pagination-config="tablePaginationConfig"
         :table-fields="tableInfo[activeMenu].fields"
         :sorted-table-fields="tableInfo[activeMenu].tableSortedFields"
@@ -144,6 +161,7 @@ onMounted(() => {
         :exclude-export-fields="props.excludeFields[activeMenu]"
         @update-custom-indicator="updateCustomIndicator"
         @change-scheme="changeScheme"
+        @query-table="queryTable"
       >
         <template #operations>
           <div>

+ 59 - 13
src/components/table/Table.vue

@@ -55,12 +55,18 @@ const customIndicatorDialogRef = ref<CustomIndicatorDialog>()
 // 表格上方查询表单
 const tableQueryFormRef = ref<TableQueryForm>()
 
+// 当前滚动条是否固定状态,这个主要用于在给sizeOb使用
+// 如果是固定状态,那么在表格大小改变的时候,left需要重置到表格的最左侧的left位置
+// 如果不是,那么设为0即可
+const isFixed = ref<boolean>(true)
+
 const emits = defineEmits([
   'updateCustomIndicator',
   'pageSizeChange',
   'curPageChange',
   'saveToTemplate',
   'changeScheme',
+  'queryTable',
 ])
 
 const {
@@ -76,6 +82,7 @@ const { initScroll, setScrollAndHeader, obScroll } = useTableScroll(
   tableContent,
   tableContainer,
   tableHeaderRef,
+  isFixed,
 )
 
 const rowHeight = 56 // 表格行高
@@ -109,9 +116,14 @@ const tableSizeOb = new ResizeObserver((entries: ResizeObserverEntry[]) => {
   // 找到表格容器
   let container = entries.find(item => item.target === tableContainer.value)
   if (!container) return
-  // console.log(container)
-  let left = container.target.getBoundingClientRect().left
-  elScrollBarH.value.style.left = left + 'px'
+
+  // 看当前的固定状态,分别去调整滚动条的位置
+  if (isFixed.value) {
+    let left = container.target.getBoundingClientRect().left
+    elScrollBarH.value.style.left = left + 'px'
+  } else {
+    elScrollBarH.value.style.left = 0 + 'px'
+  }
 })
 
 // 表格加载状态
@@ -193,11 +205,9 @@ const paginationTableData = computed<Array<TableData>>(() => {
  * @return {*}
  */
 const queryTable = (queryParams: any) => {
-  console.log(queryParams)
+  emits('queryTable', queryParams)
 }
 
-const resetTable = () => {}
-
 /**
  * @description: 初始化分页配置项
  * @return {*}
@@ -298,6 +308,29 @@ const changeTableLoading = (state: boolean) => {
   tableLoading.value = state
 }
 
+/**
+ * @description: 获取当前的查询参数
+ * @return {*}
+ */
+const getTableReqParams = () => {
+  if (tableQueryFormRef.value) {
+    return tableQueryFormRef.value.getParams()
+  } else {
+    return {}
+  }
+}
+
+/**
+ * @description: 初始化查询框
+ * @return {*}
+ */
+const initQueryForm = () => {
+  if (tableQueryFormRef.value) {
+    tableQueryFormRef.value.initFilterForm()
+    tableQueryFormRef.value.initFilterFields()
+  }
+}
+
 watch(
   () => props.tableData,
   newData => {
@@ -309,9 +342,6 @@ watch(
       cacheTableData,
       newData,
     )
-
-    tableQueryFormRef.value?.initFilterForm()
-    tableQueryFormRef.value?.initFilterFields()
     updateIndicatorScheme() // 更新指标方案
     schemeActive.value = '默认'
   },
@@ -319,10 +349,22 @@ watch(
     deep: true,
   },
 )
+
+watch(
+  () => props.activeMenu,
+  () => {
+    nextTick(() => {
+      initQueryForm()
+      let queryParams = tableQueryFormRef.value?.getParams()
+      emits('queryTable', queryParams)
+    })
+  },
+  { deep: true },
+)
+
 onMounted(() => {
   initScroll()
-  tableQueryFormRef.value?.initFilterForm()
-  tableQueryFormRef.value?.initFilterFields()
+
   tableVisOb.observe(tableContent.value as HTMLElement)
   tableSizeOb.observe(tableContainer.value as HTMLElement)
 })
@@ -330,6 +372,7 @@ onMounted(() => {
 defineExpose({
   updateIndicatorScheme,
   changeTableLoading,
+  getTableReqParams,
 })
 </script>
 
@@ -340,7 +383,6 @@ defineExpose({
         ref="tableQueryFormRef"
         :filters-info="props.filtersInfo"
         @query-table="queryTable"
-        @reset-table="resetTable"
       ></TableQueryForm>
       <div class="operationContainer">
         <div class="tableOperationLeft">
@@ -354,6 +396,7 @@ defineExpose({
               class="batchOper w120"
               v-model="batchOper"
               placeholder="批量操作"
+              :disabled="tableLoading"
             >
               <el-option
                 v-for="item in batchOperList"
@@ -370,6 +413,7 @@ defineExpose({
               class="exportData w120 ml16"
               plain
               @click="exportDialogVisble = true"
+              :disabled="tableLoading"
               >导出数据</el-button
             >
           </slot>
@@ -378,7 +422,8 @@ defineExpose({
               placement="bottom"
               trigger="hover"
               popper-style="padding:0 0px; background-color: #fff;
-  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);"
+               box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);"
+              :disabled="tableLoading"
             >
               <div class="popoverContainer">
                 <div
@@ -392,6 +437,7 @@ defineExpose({
               </div>
               <template #reference>
                 <el-button
+                  :disabled="tableLoading"
                   @click="showCustomIndicator"
                   class="customIndicator w120 ml16"
                   plain

+ 66 - 26
src/components/table/TableQueryForm.vue

@@ -2,7 +2,7 @@
 import type { TableFilterItem } from '@/types/Tables/table'
 import { TableFilterType } from '@/types/Tables/table'
 
-import { reactive, ref } from 'vue'
+import { nextTick, onMounted, reactive, ref, shallowRef } from 'vue'
 
 import { resetReactive } from '@/utils/common'
 import { useDate } from '@/hooks/useDate'
@@ -19,7 +19,7 @@ interface TableQueryFormProps {
 
 const props = defineProps<TableQueryFormProps>()
 
-const emits = defineEmits(['queryTable', 'resetTable'])
+const emits = defineEmits(['queryTable'])
 
 // 表单ref
 const filterFormRef = ref<FormInstance>()
@@ -51,19 +51,24 @@ const filterFields = ref<Array<any>>([])
 const initFilterForm = () => {
   resetReactive(filterFormData)
   resetReactive(filterFieldsStateList)
+
   for (let [k, v] of Object.entries(props.filtersInfo)) {
     let val = JSON.parse(JSON.stringify(v)) as TableFilterItem
-    // 如果是搜索框,需要赋初值字段,即作为搜索的字段
-    if (k === 'search') {
-      searchSelected.value = val.value
-    }
+
     // 把时间类型给个默认值
     if (val.type === TableFilterType.Date) {
       val.value = shortcuts[0].value
     }
 
-    // 表单给初始值
-    filterFormData[k] = val.value ? val.value : ''
+    // 如果是搜索框,需要赋初值字段,即作为搜索的字段
+    // searchSelected只是用来确认哪个字段作为搜索的参数字段,不是实际数据
+    if (k === 'search') {
+      searchSelected.value = val.value
+      filterFormData['search'] = ''
+    } else {
+      // 表单给初始值
+      filterFormData[k] = val.value ? val.value : ''
+    }
 
     // 初始化查询表单字段的状态信息
     filterFieldsStateList.push({
@@ -96,22 +101,34 @@ const createQueryParams = (): {
     [key: string]: any
   } = {}
   for (let i in filterFormData) {
+    if (i === 'search') continue
     // 当前字段没有被隐藏,则加入查询参数
     if (filterFields.value.includes(i)) {
       queryParams[i] = filterFormData[i]
     }
   }
+  // 单独处理查询框的参数
+  queryParams[searchSelected.value] = filterFormData['search']
   return queryParams
 }
 
 /**
- * @description: 查询表格
+ * @description: 获取当前的查询参数
  * @return {*}
  */
-const queryTable = () => {
+const getParams = () => {
   let queryParams: {
     [key: string]: any
   } = createQueryParams()
+  return queryParams
+}
+
+/**
+ * @description: 查询表格
+ * @return {*}
+ */
+const queryTable = () => {
+  let queryParams = getParams()
   emits('queryTable', queryParams)
 }
 
@@ -120,13 +137,21 @@ const queryTable = () => {
  * @return {*}
  */
 const resetFilterForm = () => {
-  filterFormRef.value?.resetFields()
-  emits('resetTable')
+  initFilterForm()
+  queryTable()
 }
 
+onMounted(() => {
+  initFilterForm()
+  initFilterFields()
+
+  // queryTable()
+})
+
 defineExpose({
   initFilterFields,
   initFilterForm,
+  getParams,
 })
 </script>
 
@@ -139,7 +164,7 @@ defineExpose({
         ref="filterFormRef"
         :inline="true"
       >
-        <el-form-item>
+        <el-form-item style="height: 30px">
           <el-input
             :readonly="true"
             placeholder="筛选字段"
@@ -167,7 +192,7 @@ defineExpose({
         </el-form-item>
         <!-- </div> -->
         <template v-for="item in filtersInfo" :key="item.name">
-          <el-form-item :prop="item.name">
+          <el-form-item :prop="item.name" style="height: 30px">
             <el-input
               v-model="filterFormData[item.name]"
               style="max-width: 600px"
@@ -214,22 +239,28 @@ defineExpose({
               />
             </el-select>
 
-            <el-date-picker
+            <div
+              class="dateItem"
               v-if="
                 filterFields.includes(item.name) &&
                 item.type === TableFilterType.Date
               "
-              v-model="filterFormData[item.name]"
-              type="daterange"
-              unlink-panels
-              :disableDate="disableDate"
-              range-separator="至"
-              :default-value="[item.startDate, item.endDate]"
-              start-placeholder="开始时间"
-              end-placeholder="结束时间"
-              :shortcuts="shortcuts"
-              size="small"
-            />
+            >
+              <span class="dateLabel">{{ item.label }}:</span>
+              <el-date-picker
+                v-model="filterFormData[item.name]"
+                type="daterange"
+                unlink-panels
+                :disableDate="disableDate"
+                range-separator="至"
+                :default-value="[item.startDate, item.endDate]"
+                start-placeholder="开始时间"
+                end-placeholder="结束时间"
+                :shortcuts="shortcuts"
+                size="default"
+                :clearable="false"
+              />
+            </div>
           </el-form-item>
         </template>
       </el-form>
@@ -276,4 +307,13 @@ defineExpose({
 .filterFields {
   width: 112px;
 }
+
+.dateLabel {
+  color: rgb(96, 98, 102);
+  font-size: 14px;
+  line-height: 30px;
+  height: 30px;
+  display: inline-block;
+  margin-right: 5px;
+}
 </style>

+ 9 - 1
src/hooks/useDialogDrag.ts

@@ -2,7 +2,7 @@
  * @Author: fxs bjnsfxs@163.com
  * @Date: 2024-10-25 15:26:00
  * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-10-25 15:32:53
+ * @LastEditTime: 2024-10-30 09:24:13
  * @FilePath: \Quantity-Creation-Management-System\src\hooks\useDialogDrag.ts
  * @Description: 只用于自定义指标对话框的拖拽功能
  *
@@ -38,6 +38,7 @@ export function useDialogDrag(
     if (!dragContentRef.value || !e.target || !e.dataTransfer) return
     e.dataTransfer.effectAllowed = 'move' // 设置拖拽类型
     dragingRef.value = e.target as HTMLElement // 获取当前拖拽的元素
+    dragingRef.value.classList.add('dragMove') // 添加拖拽样式
   }
 
   /**
@@ -74,9 +75,16 @@ export function useDialogDrag(
     e.preventDefault()
     if (!e.target) return
   }
+
+  const dragEnd = (e: DragEvent) => {
+    if (!e.target) return
+    dragingRef.value?.classList.remove('dragMove')
+  }
+
   return {
     dragStart,
     dragEnter,
     dragOver,
+    dragEnd,
   }
 }

+ 10 - 8
src/hooks/useMenuTable.ts

@@ -8,16 +8,14 @@ import type { BaseTableInfo } from '@/types/Tables/tablePageData'
 import type { ComputedRef, Reactive, Ref } from 'vue'
 import type { TablePaginationProps } from '@/types/Tables/pagination'
 import type { BaseMenu } from '@/types/Promotion/Menu'
+import type { MenuTableReq } from '@/types/Tables/MenuTable/menuTableReq'
 
 import { useTable } from './useTable'
 import Table from '@/components/table/Table.vue'
 import TableCustomIndicatorController from '@/utils/localStorage/tableCustomIndicatorController'
-import axiosCanceler from '@/utils/axios/axiosCanceler'
 
 type TableType = InstanceType<typeof Table>
 
-const { getData, updateTableFields } = useTable()
-
 export function useMenuTable(
   saveName: string, // 保存的文件名
   fileName: ComputedRef<string>, // 动态的文件名
@@ -28,13 +26,12 @@ export function useMenuTable(
     [key: string]: TableCustomIndicatorController
   },
   tableInfo: Reactive<BaseTableInfo>, // 表格信息
-  tableReqInfo: { [key: string]: any }, // 表格请求信息
+  tableReqInfo: MenuTableReq, // 表格请求信息
   tablePaginationConfig: Reactive<TablePaginationProps>, // 表格分页配置
   tableRef: Ref<TableType | null>, // 表格实例
   menuList: BaseMenu[], // 菜单列表
 ) {
-  // 备份的上次请求的信息
-  let backupReqInfo: any = {}
+  const { tableReqList, getData, updateTableFields } = useTable()
 
   /**
    * @description: 更新表格数据
@@ -44,6 +41,10 @@ export function useMenuTable(
     try {
       tableRef.value?.changeTableLoading(true)
       updateTableInfo()
+      if (tableRef.value) {
+        tableReqInfo[activeMenu.value].config.params =
+          tableRef.value?.getTableReqParams()
+      }
 
       await getData(tableReqInfo[activeMenu.value]).then(
         (res: Array<TableData>) => {
@@ -59,7 +60,8 @@ export function useMenuTable(
       ElMessage.error('获取数据失败')
       console.log(err)
     } finally {
-      tableRef.value?.changeTableLoading(false)
+      // 只有当表格中没有请求的时候,再去把加载状态关闭
+      if (tableReqList.length === 0) tableRef.value?.changeTableLoading(false)
     }
   }
 
@@ -72,7 +74,7 @@ export function useMenuTable(
     activeMenu.value = val
     customIndicatorScheme.value =
       tableControllers[fileName.value].getSchemeList()
-    updateTableData()
+    // updateTableData()
   }
 
   /**

+ 19 - 11
src/hooks/useTable.ts

@@ -4,27 +4,31 @@ import type { ResponseInfo } from '@/types/axios'
 import type { BaseFieldItem, TableFields } from '@/types/Tables/table'
 import type { Ref } from 'vue'
 import type { PaginationConfig } from '@/types/Tables/pagination'
+import type { TableReq } from '@/types/Tables/MenuTable/menuTableReq'
 
 import { resetReactive } from '@/utils/common'
 import { writeFileXLSX, utils } from 'xlsx'
 
 import axiosInstance from '@/utils/axios/axiosInstance'
-import axiosCanceler from '@/utils/axios/axiosCanceler'
 
 export function useTable() {
-  const tableReqList:string[] = []
+  let controller: AbortController | null = null // 请求控制器,用于取消请求
+  let tableReqList: Array<string> = [] // 表格的请求列表,暂时只存了url,可以存其他的
 
-  const getData = async (
-    url: string,
-    config: Object = {},
-  ): Promise<Array<TableData>> => {
+  /**
+   * @description: 获取表格数据
+   * @param {string} url 请求地址
+   * @param {Object} config 配置
+   * @return {*}
+   */
+  const getData = async (reqInfo: TableReq): Promise<Array<TableData>> => {
     try {
-      let reqInfo = url + JSON.stringify(config);
-      if(tableReqList.length > 0){
-        
-      }
-      tableReqList.push(reqInfo)
+      let { url, config } = reqInfo
+      tableReqList.push(url) // 添加请求
+      controller && controller.abort() // 取消上一次请求
+      controller = new AbortController()
 
+      config.signal = controller.signal
       const res = (await axiosInstance.get(url, config)) as ResponseInfo
 
       if (res.code !== 0) throw new Error('请求失败')
@@ -33,6 +37,8 @@ export function useTable() {
       console.log('数据请求失败')
       console.log(err)
       return []
+    } finally {
+      tableReqList.pop() // 请求完成后移除一个请求
     }
   }
 
@@ -194,7 +200,9 @@ export function useTable() {
   }
 
   return {
+    tableReqList,
     getData,
+
     isFixedField,
     exportDataToExcel,
     updateTableFields,

+ 5 - 3
src/hooks/useTableScroll.ts

@@ -4,6 +4,7 @@ export function useTableScroll(
   tableContent: Ref<HTMLElement | null>,
   tableContainer: Ref<HTMLElement | null>,
   tableHeaderRef: Ref<HTMLElement | null>,
+  isFixed: Ref<boolean>,
 ) {
   /**
    * @description: 设置滚动条的位置
@@ -37,7 +38,7 @@ export function useTableScroll(
   }
 
   /**
-   * @description: 判定当前横向滑动条是否在表格内,有BUG
+   * @description: 判定当前横向滑动条是否在表格内
    * 滑动距离加可见区域高度不大于表格总高度,则说明在表格内
    * @return {*}
    */
@@ -45,7 +46,9 @@ export function useTableScroll(
     if (!tableContent.value || !tableContainer.value) return false
     const { scrollTop, offsetHeight, scrollHeight } =
       tableContainer.value as HTMLElement
-    return scrollTop + offsetHeight < scrollHeight
+    let result = scrollTop + offsetHeight < scrollHeight
+    isFixed.value = result
+    return result
   }
 
   /**
@@ -71,7 +74,6 @@ export function useTableScroll(
    */
   const setScrollAndHeader = () => {
     setScrollPos(isIntable())
-    console.log('直接走')
     if (tableHeaderRef.value) {
       const { scrollTop } = tableContainer.value as HTMLElement
       let contentOffsetTop = tableContent.value!.offsetTop // 父容器距离顶部的高度

+ 8 - 2
src/types/Tables/MenuTable/menuTableReq.ts

@@ -1,6 +1,12 @@
+import type { AxiosRequestConfig } from 'axios'
+interface TableReq {
+  url: string
+  config: AxiosRequestConfig
+}
+
 // 没个菜单的请求信息格式
 interface MenuTableReq {
-  [key: string]: string
+  [key: string]: TableReq
 }
 
-export type { MenuTableReq }
+export type { MenuTableReq, TableReq }

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

@@ -87,6 +87,7 @@ interface TableProps {
   paginationConfig: TablePaginationProps // 分页配置
   schemeList: Array<CustomIndicatorScheme> // 自定义方案列表
   excludeExportFields?: Array<string> // 需要排除导出的字段
+  activeMenu: string // 当前选中的菜单
 }
 
 // 保存的表格信息格式

+ 0 - 74
src/utils/axios/axiosCanceler.ts

@@ -1,74 +0,0 @@
-import type { AxiosRequestConfig } from 'axios'
-export class AxiosCanceler {
-  #pendingMap: Map<string, AbortController> // 存储每个请求的控制器
-
-  constructor() {
-    this.#pendingMap = new Map<string, AbortController>()
-  }
-
-  /**
-   * @description: 添加请求
-   * @param {AxiosRequestConfig} config 请求配置
-   */
-  public addPending(config: AxiosRequestConfig): void {
-    this.removePending(config)
-    const url = this.getPendingUrl(config)
-    const controller = new AbortController()
-    config.signal = controller.signal
-    if (!this.#pendingMap.has(url)) {
-      // 如果当前请求不在等待中,将其添加到等待中
-      this.#pendingMap.set(url, controller)
-    }
-  }
-
-  /**
-   * @description: 移除所有等待中的请求
-   * @return {*}
-   */
-  public removeAllPending(): void {
-    this.#pendingMap.forEach(abortController => {
-      if (abortController) {
-        abortController.abort()
-      }
-    })
-    this.reset()
-  }
-
-  /**
-   * @description: 移除请求
-   * @param {AxiosRequestConfig} config 请求配置
-   * @return {*}
-   */
-  public removePending(config: AxiosRequestConfig): void {
-    const url = this.getPendingUrl(config)
-    if (this.#pendingMap.has(url)) {
-      // 如果当前请求在等待中,取消它并将其从等待中移除
-      const abortController = this.#pendingMap.get(url)
-      if (abortController) {
-        abortController.abort(url)
-      }
-      this.#pendingMap.delete(url)
-    }
-  }
-
-  /**
-   * @description: 重置整个管理器
-   * @return {*}
-   */
-  public reset(): void {
-    this.#pendingMap.clear()
-  }
-
-  /**
-   * @description: 获取正在请求的请求地址和方法的拼接字符串
-   * @param {AxiosRequestConfig} config 请求配置
-   * @return {string} 请求地址和方法的拼接字符串
-   */
-  public getPendingUrl = (config: AxiosRequestConfig): string => {
-    return [config.method, config.url].join('&')
-  }
-}
-
-const axiosCanceler = new AxiosCanceler()
-
-export default axiosCanceler

+ 146 - 25
src/views/Index.vue

@@ -7,6 +7,7 @@ import { removeAllToeken } from '@/utils/token/token'
 
 import Menu from '@/components/navigation/Menu.vue'
 import router from '@/router'
+import CIcon from '@/components/cIcon/cIcon.vue'
 // import cIcon from '@/components/cIcon/CIcon.vue'
 
 // 资源的加载路径
@@ -70,6 +71,22 @@ const goHome = () => {
   router.push('/home')
 }
 
+const userInfoTools = [
+  {
+    label: '查看角色权限',
+    url: '/',
+  },
+  {
+    label: '查看角色权限',
+    url: '/',
+  },
+]
+
+const userInfo = {
+  name: '张三',
+  post: '产品经理',
+}
+
 onMounted(() => {})
 </script>
 
@@ -103,24 +120,55 @@ onMounted(() => {})
         <el-popover
           popper-class="headPopper"
           placement="bottom-end"
-          trigger="click"
+          trigger="hover"
+          :width="300"
+          :offset="20"
         >
           <template #reference>
-            <!-- <el-image
-              class="headPortrait"
-              :src="blobUrlInfo.defaultHead"
-            ></el-image> -->
             <cIcon :src="resourceInfo.defaultHead" :size="24"></cIcon>
           </template>
-          <div class="userTools">
-            <span class="userToolsItem" @click="logOut">
-              <icon-material-symbols-light-logout></icon-material-symbols-light-logout>
-              <span> 退出登录</span>
-            </span>
+          <div class="userInfoContainer">
+            <div class="userInfoContent">
+              <div class="userInfo">
+                <div class="headPortrait">
+                  <cIcon :src="resourceInfo.defaultHead" :size="48"></cIcon>
+                </div>
+                <div class="info">
+                  <span class="userName infoItem">{{ userInfo.name }}</span>
+                  <span class="userPost infoItem">{{ userInfo.post }}</span>
+                </div>
+              </div>
+            </div>
+            <div class="toolsContainer">
+              <div class="toolItem" v-for="item in userInfoTools">
+                <RouterLink
+                  class="userInfoToolLink userInfoText"
+                  :to="item.url"
+                  :key="item.label"
+                  >{{ item.label }}</RouterLink
+                >
+              </div>
+              <div class="userInfoText toolBtnGroup">
+                <div class="leftTool toolBtnItem">
+                  <el-text class="userInfoText">
+                    <el-icon><Setting /></el-icon>
+                    管理中心
+                  </el-text>
+                </div>
+                <el-divider direction="vertical" />
+                <div class="rightTool toolBtnItem">
+                  <el-text class="userInfoText" @click="logOut">
+                    <el-icon><SwitchButton /></el-icon>
+                    退出登录
+                  </el-text>
+                </div>
+              </div>
+            </div>
           </div>
         </el-popover>
       </div>
     </div>
+
     <div class="content">
       <router-view v-slot="{ Component, route }">
         <keep-alive>
@@ -223,37 +271,110 @@ onMounted(() => {})
   align-items: center;
 }
 
-.userTools {
+.userInfoContainer {
+  width: 300px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+  border: 1px solid #ebeef5;
+}
+
+.userInfoContent {
   width: 100%;
-  height: 100%;
+  position: relative;
+}
+
+.userInfo {
+  position: relative;
+
+  display: flex;
+  padding: 10px 20px;
+  /* justify-content: space-around; */
+}
+
+.headPortrait {
+  cursor: pointer;
+  margin-right: 10px;
+}
+
+.infoItem {
+  font-size: 12px;
+  font-weight: 500;
+  color: #999;
+  margin-bottom: 3px;
+}
+
+.toolsContainer {
   display: flex;
   flex-direction: column;
-  justify-content: space-around;
-  align-items: center;
 }
 
-.userToolsItem {
+.toolItem {
+  height: 36px;
+  padding: 16px 24px;
+  line-height: normal;
+  color: #333;
+  font-size: 14px;
+  display: flex;
+  align-items: center;
+  border-top: 1px solid #ebeef5;
   cursor: pointer;
+}
+
+.toolItem:hover {
+  background-color: #ecf5ff;
+  color: #66b1ff;
+}
+
+.userName {
+  font-weight: 700;
+  font-size: 14px;
+  color: black;
+}
+
+.info {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-start;
+  justify-content: center;
+}
+
+.userTools {
   width: 100%;
-  height: 4vh;
+  height: 100%;
   display: flex;
+  flex-direction: column;
+  justify-content: space-around;
   align-items: center;
-  justify-content: center;
-  /* padding: 10px; */
-  margin: 2%;
 }
 
-.userToolsItem > span {
-  margin-left: 10%;
+.userInfoText {
+  color: #333;
+  font-size: 14px;
 }
 
-.userToolsItem:hover {
-  background-color: #f2f3f5;
+.userInfoToolLink {
+  text-decoration: none;
+  display: inline-block;
 }
 
-.headPortrait {
+.toolBtnGroup {
+  height: 40px;
+  padding: 12px 24px;
+  line-height: normal;
+  color: #333;
+  font-size: 14px;
+
+  display: flex;
+  align-items: center;
+  justify-content: space-around;
+  border-top: 1px solid #ebeef5;
+}
+
+.toolBtnItem {
   cursor: pointer;
-  width: 25px;
+}
+
+.toolBtnItem:hover > .userInfoText {
+  color: #66b1ff;
 }
 
 .content {

+ 21 - 4
src/views/Promotion/adManage/ttad.vue

@@ -28,6 +28,7 @@ import type {
   BaseAllFilterInfo,
   BaseAllFixedFiledsInfo,
 } from '@/types/Tables/tablePageData'
+import type { MenuTableReq } from '@/types/Tables/MenuTable/menuTableReq'
 
 import { TableFilterType } from '@/types/Tables/table'
 import { useRequest } from '@/hooks/useRequest'
@@ -498,10 +499,26 @@ const allFixedFileds: AllFixedFiledsInfo = {
 }
 
 // 所有的表格请求
-const tableReqInfo: { [key: string]: any } = {
-  account: AllApi.mockAdTTAcc,
-  project: AllApi.mockAdTTProj,
-  advertise: AllApi.mockAdTTAd,
+const tableReqInfo: MenuTableReq = {
+  account: {
+    url: AllApi.mockAdTTAcc,
+    config: {
+      params: {},
+    },
+  },
+  project: {
+    url: AllApi.mockAdTTProj,
+    config: {
+      params: {},
+    },
+  },
+
+  advertise: {
+    url: AllApi.mockAdTTAd,
+    config: {
+      params: {},
+    },
+  },
 }
 
 // 所有表格需要排除的字段信息