소스 검색

更新表格筛选,更新自定义指标

fxs 1 년 전
부모
커밋
df49ed3eb8

+ 1 - 0
auto-imports.d.ts

@@ -6,6 +6,7 @@
 // biome-ignore lint: disable
 export {}
 declare global {
+  const ElBtnType2: typeof import('element-plus/es')['ElBtnType2']
   const ElMessage: typeof import('element-plus/es')['ElMessage']
   const ElNotification: (typeof import('element-plus/es'))['ElNotification']
 }

+ 86 - 28
src/components/dialog/customIndicatorDialog.vue

@@ -3,13 +3,13 @@ import type { BaseFieldItem, TableFields } from '@/types/Tables/table'
 
 import { ref, reactive, watch } from 'vue'
 import { useTable } from '@/hooks/useTable'
+import { computed } from 'vue'
 
 const { isFixedField } = useTable()
 
 interface DialogProps {
   indicatorFields: Array<BaseFieldItem<TableFields>>
-  fixedIndicator: Array<TableFields>
-  unFixedIndicator: Array<TableFields>
+  defaultActiveNav: string
   tableFieldsInfo: Array<TableFields>
   fixedFields: Array<string>
 }
@@ -31,15 +31,55 @@ const customIndicatorVisible = ref<boolean>(false)
 const indicatorSearch = ref<string>('')
 
 // 自定义指标左侧导航选中值
-const indicatorNavActive = ref<string>()
+const indicatorNavActive = ref<string>(props.defaultActiveNav)
 
-const watchIndicatorFields = watch(
-  () => props.indicatorFields[0]?.name,
-  (newName: string) => {
-    indicatorNavActive.value = newName
-  },
-  { deep: true },
-)
+// 自定义指标中需要固定的指标
+const fixedIndicator = computed<TableFields[]>(() => {
+  let result: TableFields[] = []
+  // 对于固定的指标,为了防止传入的数据有误,所有直接state设置为true
+  props.indicatorFields.forEach(item => {
+    result.push(
+      ...item.children.filter(item => {
+        if (item.fixed) item.state = true
+        return item.fixed
+      }),
+    )
+  })
+  console.log('asdf')
+  console.log(JSON.parse(JSON.stringify(result)))
+  return result
+})
+
+// 没有被固定的指标
+// 这里去更新state是为了让表格的字段能够正确同步
+const unFixedIndicator = computed<TableFields[]>(() => {
+  let result: TableFields[] = []
+  // 拿到所有的子元素
+  let allChilds = props.indicatorFields.flatMap(
+    item => item.children,
+  ) as Array<TableFields>
+  allChilds.map(item => (item.state = false))
+
+  // 拿到所有的选中值
+  let allSelected = props.indicatorFields.flatMap(
+    item => item.value,
+  ) as Array<string>
+
+  // 之所以要这样去筛选,是为了保证顺序,
+  // 如果直接通过filter去找存在于allSelected中的元素,
+  // 那么当一个在前面的选项首先取消选择,然后又重新选中的时候,这个选项又会直接出现在他原来的位置,而不是末尾
+  allSelected.forEach(item => {
+    let child = allChilds.find(
+      child => !child.fixed && child.name === item,
+    ) as TableFields
+    if (child) {
+      child.state = true
+      result.push(child)
+    }
+  })
+  console.log(result)
+  return result
+})
 
 // 拖拽的容器
 const dragContentRef = ref<HTMLElement>()
@@ -47,6 +87,17 @@ const dragContentRef = ref<HTMLElement>()
 // 当前正在被拖拽的元素
 const dragingRef = ref<HTMLElement>()
 
+// 当默认值变化的时候,要更新一下,这里主要用在初始化的时候,数据可能还没有获取到
+watch(
+  () => props.defaultActiveNav,
+  (newMenu: string) => {
+    indicatorNavActive.value = newMenu
+  },
+  {
+    deep: true,
+  },
+)
+
 const indicatorOpen = () => {}
 
 const indicatorClose = () => {
@@ -151,7 +202,13 @@ const dragEnter = (e: DragEvent) => {
 const dragOver = (e: DragEvent) => {
   e.preventDefault()
   if (!e.target) return
-  // 把被排序过的字段信息先清空一下,防止之前的污染
+}
+
+/**
+ * @description: 更新一下排序后的表格字段信息
+ * @return {*}
+ */
+const updateSortedTableFieldsInfo = () => {
   sortedTableFieldsInfo.splice(0, sortedTableFieldsInfo.length)
   let sortedNodes = Array.from(dragContentRef.value!.children)
   let sortedFields: Array<string> = []
@@ -162,19 +219,18 @@ const dragOver = (e: DragEvent) => {
       sortedFields.push(node.getAttribute('name') as string)
     }
   })
-  // 临时复制一份原本的字段信息,防止污染
-  let tempFields: Array<TableFields> = JSON.parse(
-    JSON.stringify(props.tableFieldsInfo),
-  )
 
   // 根据排好序的字段名,去原本的字段信息中去找对应的字段名,把他加入到新字段信息中
+  // 这里的排序与unFixedIndicator的排序不一样,这里是为了同步用户的拖动
+  // unFixedIndicator的排序是为了同步新增的选项
   sortedFields.forEach((item: string) => {
-    let fFiled = tempFields.find(field => field.name === item)
+    let fFiled = unFixedIndicator.value.find(field => field.name === item)
     if (fFiled) sortedTableFieldsInfo.push(fFiled)
   })
-
+  console.log('fixed')
+  console.log(fixedIndicator.value)
   // 还剩下固定字段的信息,把他加入数组头部
-  sortedTableFieldsInfo.unshift(...props.fixedIndicator)
+  sortedTableFieldsInfo.unshift(...fixedIndicator.value)
 }
 
 /**
@@ -197,7 +253,7 @@ const getActivedIndicator = (): string[] => {
  */
 const applyCustomIndicator = () => {
   customIndicatorVisible.value = false
-
+  updateSortedTableFieldsInfo() // 排序
   // 拿到当前激活的所有自定义指标
   let actived = getActivedIndicator()
   // 把目前排好序的字段信息复制给新的字段信息
@@ -206,7 +262,6 @@ const applyCustomIndicator = () => {
     newTableFieldsInfo.length,
     ...JSON.parse(JSON.stringify(sortedTableFieldsInfo)),
   )
-
   // 根据当前已经激活的字段name,去吧字段信息中的state改为true
   newTableFieldsInfo.map(item => {
     // console.log(item.name)
@@ -216,7 +271,7 @@ const applyCustomIndicator = () => {
       item.state = false
     }
   })
-
+  console.log(newTableFieldsInfo)
   emits('updateFields', newTableFieldsInfo)
 }
 
@@ -284,13 +339,16 @@ defineExpose({ showCustomIndicator })
                 <span>{{ field.label }}</span>
               </div>
               <el-row class="indicatorItem">
-                <el-col :span="8" v-for="item in field.children"
-                  ><el-checkbox
-                    style="margin-bottom: 16px"
-                    v-model="item.state"
-                    :label="item.label"
-                    :disabled="isFixedField(props.fixedFields, item)"
-                /></el-col>
+                <el-col :span="8" v-for="item in field.children">
+                  <el-checkbox-group v-model="field.value">
+                    <el-checkbox
+                      style="margin-bottom: 16px"
+                      :value="item.name"
+                      :label="item.label"
+                      :disabled="isFixedField(props.fixedFields, item)"
+                    />
+                  </el-checkbox-group>
+                </el-col>
               </el-row>
             </div>
           </div>

+ 102 - 38
src/components/table/Table.vue

@@ -2,6 +2,7 @@
 import type {
   BaseFieldItem,
   TableFields,
+  TableFilterItem,
   TableProps,
 } from '@/types/Tables/table'
 import type { FormInstance } from 'element-plus'
@@ -13,6 +14,7 @@ import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'
 import { Search } from '@element-plus/icons-vue'
 import { Plus, Operation } from '@element-plus/icons-vue'
 import { useTable } from '@/hooks/useTable'
+import { useDate } from '@/hooks/useDate'
 
 import customIndicatorDialog from '../dialog/customIndicatorDialog.vue'
 
@@ -23,6 +25,7 @@ const props = withDefaults(defineProps<TableProps>(), {})
 const emits = defineEmits(['updateCustomIndicator'])
 
 const { isFixedField } = useTable()
+const { disableDate, shortcuts } = useDate()
 
 const tableFieldLWidth = 200 // 长单元格的宽度
 const tableFieldSWidth = 150 // 短单元格的宽度
@@ -45,11 +48,17 @@ const indicatorFields = reactive<Array<BaseFieldItem<TableFields>>>([])
 // 表格整体容器
 const tableContainer = ref<HTMLElement>()
 
+// 自定义指标侧边栏的默认选中
+const defaultActiveNav = ref<string>('')
+
 // 表单数据
 const filterFormData = reactive<{
   [key: string]: any
 }>({})
 
+// 表单搜索框所对应的字段,因为可能是多选,会在初始化的时候给初值
+const searchSelected = ref('')
+
 // 表单ref
 const filterFormRef = ref<FormInstance>()
 
@@ -96,6 +105,7 @@ const initIndicatorFields = () => {
     indicatorFields.length,
     ...JSON.parse(JSON.stringify(props.tableFields)),
   )
+  defaultActiveNav.value = indicatorFields[0].name
 }
 
 /**
@@ -104,31 +114,26 @@ const initIndicatorFields = () => {
  */
 const initTableFields = () => {
   resetReactive(tableFieldsInfo)
-  props.tableFields.forEach(item => {
-    item.children.forEach(item => {
-      tableFieldsInfo.push(item)
+  if (props.sortedTableFields.length > 0) {
+    tableFieldsInfo.splice(
+      0,
+      tableFieldsInfo.length,
+      ...props.sortedTableFields,
+    )
+  } else {
+    indicatorFields.forEach(item => {
+      item.children.forEach(child => {
+        if (child.fixed || child.state) {
+          item.value.push(child.name)
+          child.state = true
+        }
+        tableFieldsInfo.push(JSON.parse(JSON.stringify(child)))
+      })
     })
-  })
+  }
 }
 
 // 自定义指标中需要固定的指标
-const fixedIndicator = computed<TableFields[]>(() => {
-  let result: TableFields[] = []
-  indicatorFields.forEach(item => {
-    result.push(...item.children.filter(item => item.fixed))
-  })
-  return result
-})
-
-// 没有被固定的指标
-const unFixedIndicator = computed<TableFields[]>(() => {
-  let result: TableFields[] = []
-  indicatorFields.forEach(item => {
-    result.push(...item.children.filter(item => !item.fixed && item.state))
-  })
-  // return JSON.parse(JSON.stringify(result))
-  return result
-})
 
 /**
  * @description: 初始化查询表单
@@ -139,14 +144,24 @@ 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()[0], shortcuts[0].value()[1]]
+    }
+
     // 表单给初始值
-    filterFormData[k] = v.value ? v.value : ''
+    filterFormData[k] = val.value ? val.value : ''
 
     // 初始化查询表单字段的状态信息
     filterFieldsStateList.push({
-      label: v.label,
+      label: val.label,
       state: true,
-      value: v.name,
+      value: val.name,
     })
   }
 }
@@ -260,7 +275,8 @@ const showCustomIndicator = () => {
  */
 const applyCustomIndicator = (newTableFieldsInfo: Array<TableFields>) => {
   tableFieldsInfo.splice(0, tableFieldsInfo.length, ...newTableFieldsInfo)
-  emits('updateCustomIndicator', indicatorFields)
+
+  emits('updateCustomIndicator', indicatorFields, tableFieldsInfo)
 }
 
 watch(
@@ -269,8 +285,8 @@ watch(
     tableData.splice(0, tableData.length, ...newData)
     initfilterForm()
     initFilterFields()
-    initTableFields()
     initIndicatorFields()
+    initTableFields()
   },
   {
     deep: true,
@@ -288,7 +304,7 @@ onMounted(() => {
         <div class="filterContent">
           <el-form
             :model="filterFormData"
-            label-width="auto"
+            label-width="0"
             ref="filterFormRef"
             :inline="true"
           >
@@ -298,7 +314,7 @@ onMounted(() => {
                 :readonly="true"
                 placeholder="筛选字段"
                 prefix-icon="Filter"
-                style="width: 200px; margin-bottom: 10px"
+                style="width: 220px; margin-bottom: 10px"
               >
                 <template #append>
                   <el-select
@@ -307,7 +323,7 @@ onMounted(() => {
                     collapse-tags
                     collapse-tags-tooltip
                     placeholder="Select"
-                    style="width: 100px"
+                    style="width: 110px"
                   >
                     <el-option
                       v-for="item in filterFieldsStateList"
@@ -323,16 +339,28 @@ onMounted(() => {
             <template v-for="item in filtersInfo" :key="item.name">
               <el-form-item :prop="item.name">
                 <el-input
-                  class="filterItem"
+                  v-model="filterFormData[item.name]"
+                  style="max-width: 600px"
+                  placeholder="输入关键字搜索"
+                  class="input-with-select"
                   v-if="
                     filterFields.includes(item.name) &&
                     item.type === TableFilterType.Search
                   "
-                  v-model="filterFormData[item.name]"
-                  style="width: 240px"
-                  placeholder="Please Input"
-                  :suffix-icon="Search"
-                />
+                >
+                  <template #prepend>
+                    <el-select v-model="searchSelected" style="width: 115px">
+                      <el-option
+                        v-for="option in item.options"
+                        :label="option.label"
+                        :value="option.value"
+                      />
+                    </el-select>
+                  </template>
+                  <template #append>
+                    <el-button :icon="Search" />
+                  </template>
+                </el-input>
 
                 <el-select
                   class="filterItem"
@@ -355,6 +383,23 @@ onMounted(() => {
                     :value="option.value"
                   />
                 </el-select>
+
+                <el-date-picker
+                  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"
+                />
               </el-form-item>
             </template>
           </el-form>
@@ -414,10 +459,23 @@ onMounted(() => {
           v-bind="{ ...$attrs, data: tableData }"
           style="width: 100%"
           border
+          table-layout="fixed"
           :scrollbar-always-on="true"
         >
           <template v-for="item in tableFieldsInfo" :key="item.name">
             <el-table-column
+              v-if="item.name === 'action'"
+              label="操作"
+              fixed
+              width="160"
+            >
+              <template #default="scope">
+                <slot name="operations" :row="scope.row">
+                  <!-- {{ scope.row[item.prop] }} -->
+                </slot>
+              </template>
+            </el-table-column>
+            <el-table-column
               :width="
                 isFixedField(props.fixedFields, item)
                   ? tableFieldLWidth
@@ -426,17 +484,23 @@ onMounted(() => {
               :fixed="isFixedField(props.fixedFields, item)"
               :prop="item.name"
               :label="item.label"
-              v-if="item.state"
+              v-if="item.state && item.name !== 'action'"
             >
             </el-table-column>
           </template>
+          <!-- <el-table-column label="操作" fixed width="200">
+            <template #default="scope">
+              <slot name="operations" :row="scope.row">
+          
+              </slot>
+            </template>
+          </el-table-column> -->
         </el-table>
       </div>
     </div>
     <customIndicatorDialog
+      :default-active-nav="defaultActiveNav"
       :indicator-fields="indicatorFields"
-      :un-fixed-indicator="unFixedIndicator"
-      :fixed-indicator="fixedIndicator"
       :table-fields-info="tableFieldsInfo"
       :fixed-fields="props.fixedFields"
       ref="customIndicatorDialogRef"

+ 17 - 2
src/hooks/useDate.ts

@@ -1,7 +1,21 @@
-import { createDateRange } from '@/utils/common'
 export function useDate() {
+  /**
+   * @description: 创建一个日期范围
+   * @param {*} day 天数
+   * @return {*}
+   */
+  const createDateRange = (day: number): Array<Date> => {
+    const end = new Date()
+    const start = new Date()
+    start.setTime(start.getTime() - 3600 * 1000 * 24 * day)
+    return [start, end]
+  }
+
   // 快速选择日期
-  const shortcuts = [
+  const shortcuts: Array<{
+    text: string
+    value: () => Date[]
+  }> = [
     {
       text: '上一周',
       value: () => createDateRange(7),
@@ -28,5 +42,6 @@ export function useDate() {
   return {
     shortcuts,
     disableDate,
+    createDateRange,
   }
 }

+ 84 - 0
src/hooks/useTable.ts

@@ -1,4 +1,12 @@
 import type { TableData, BaseFieldInfo } from '@/types/Tables/table'
+import type { BaseTableInfo } from '@/types/Tables/tablePageData'
+import type {
+  BaseFieldItem,
+  TableFields,
+  TableInfoItem,
+  SaveFields,
+} from '@/types/Tables/table'
+
 import axiosInstance from '@/utils/axios/axiosInstance'
 export function useTable() {
   const getData = async (
@@ -28,8 +36,84 @@ export function useTable() {
     return fixedFields.includes(info.name)
   }
 
+  /**
+   * @description: 保存表格信息
+   * @return {*}
+   */
+  const saveTableInfo = (
+    name: string,
+    tableInfo: TableInfoItem<TableData, BaseFieldItem<TableFields>>,
+  ) => {
+    try {
+      let result = {
+        fields: tableInfo.fields, // 字段数组
+        tableSortedFields: tableInfo.tableSortedFields, // 排序过后的表格字段,仅用于展示表格字段
+      }
+      localStorage.setItem(name, JSON.stringify(result))
+    } catch (err) {
+      console.log('保存失败')
+      console.log(err)
+    }
+  }
+
+  /**
+   * @description: 获取保存的表格信息
+   * @param {*} TableInfo
+   * @return {*}
+   */
+  const getTableInfo = (name: string): SaveFields | undefined => {
+    try {
+      let info = localStorage.getItem(name)
+      if (!info) throw new Error('没有该信息')
+      return JSON.parse(info) as {
+        fields: BaseFieldItem<TableFields>[]
+        tableSortedFields: TableFields[]
+      }
+    } catch (err) {
+      console.log('获取失败')
+      console.log(err)
+      return undefined
+    }
+  }
+
+  /**
+   * @description: 更新自定义指标和表格字段
+   * @param {*} newIndicator  新的指标信息
+   * @param {*} newSortedTablefileds 新的表格字段信息
+   * @return {*}
+   */
+  const updateTableFields = (
+    tableInfo: BaseTableInfo,
+    activeName: string,
+    newTableFiles: Array<BaseFieldItem<TableFields>>,
+    newSortedTablefileds: Array<TableFields>,
+  ): Promise<boolean> => {
+    return new Promise((reslove, reject) => {
+      try {
+        let oldTablefields = tableInfo[activeName].fields
+        let oldSortedFields = tableInfo[activeName].tableSortedFields
+
+        oldTablefields.splice(0, oldTablefields.length, ...newTableFiles)
+
+        oldSortedFields.splice(
+          0,
+          oldSortedFields.length,
+          ...newSortedTablefileds,
+        )
+        reslove(true)
+      } catch (err) {
+        console.log('更新失败')
+        console.log(err)
+        reject(false)
+      }
+    })
+  }
+
   return {
     getData,
     isFixedField,
+    saveTableInfo,
+    getTableInfo,
+    updateTableFields,
   }
 }

+ 11 - 0
src/types/Button/buttonType.ts

@@ -0,0 +1,11 @@
+enum EleBtnType {
+  Default = 'default',
+  Primary = 'primary',
+  Success = 'success',
+  Warning = 'warning',
+  Info = 'info',
+  Danger = 'danger',
+  Text = 'text',
+}
+
+export { EleBtnType }

+ 2 - 0
src/types/Promotion/Menu.ts

@@ -27,3 +27,5 @@ interface BaseMenu {
   iconActive?: string
   path?: string
 }
+
+export type { BaseMenu }

+ 12 - 0
src/types/Tables/Operations/operations.ts

@@ -0,0 +1,12 @@
+import { EleBtnType } from '@/types/Button/buttonType'
+interface OperationItem {
+  label: string
+  type: EleBtnType
+  func: () => void
+}
+
+interface Operations {
+  [keys: string]: OperationItem[]
+}
+
+export type { OperationItem, Operations }

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

@@ -33,6 +33,7 @@ interface BaseFilterItem {
 // 搜索框
 interface SearchFilterItem extends BaseFilterItem {
   type: TableFilterType.Search
+  options: SelectFilterOptions[]
 }
 
 // 选择框
@@ -62,6 +63,7 @@ type TableFields = AllAdmgeTtFields
 interface BaseFieldItem<T extends TableFields> {
   label: string // 用于分段的标签名,即一组数据的标题
   name: string // 用于分段的字段名,即一组数据的字段名
+  value: string[] // 被选中的字段的值
   children: T[] // 每一组数据中的字段
 }
 
@@ -77,10 +79,17 @@ interface TableProps {
   }
   tableData: Array<TableData>
   // tableFields: Array<TableFields>
-  tableFields: Array<BaseFieldItem<TableFields>>
+  tableFields: Array<BaseFieldItem<TableFields>> // 表格字段信息,分段展示
+  sortedTableFields: Array<TableFields> // 排序过后的表格字段,整体的
   fixedFields: Array<string>
 }
 
+// 保存的表格信息格式
+interface SaveFields {
+  fields: BaseFieldItem<TableFields>[]
+  tableSortedFields: TableFields[]
+}
+
 // 每个表格需要的信息格式,包含通用的属性
 
 interface TableInfoItem<
@@ -89,6 +98,7 @@ interface TableInfoItem<
 > {
   data: TData[] // 数据数组
   fields: TFields[] // 字段数组
+  tableSortedFields: TableFields[] // 排序过后的表格字段,仅用于展示表格字段
   filters: FilterInfo // 过滤信息
   fixedFields: string[] // 固定字段
 }
@@ -102,6 +112,7 @@ export type {
   DateFilterItem,
   TableFilterItem,
   TableProps,
+  SaveFields,
   TableData,
   FilterInfo,
   TableFields,

+ 35 - 0
src/types/Tables/tablePageData.ts

@@ -0,0 +1,35 @@
+// 保存一个包含表格的页面所需要的表格信息
+import type {
+  TableInfoItem,
+  TableData,
+  BaseFieldItem,
+  TableFields,
+  FilterInfo,
+} from './table'
+
+//表格基本信息
+interface BaseTableInfo {
+  [key: string]: TableInfoItem<TableData, BaseFieldItem<TableFields>>
+}
+
+// 所有字段的数据
+interface BaseAllFieldsInfo {
+  [key: string]: TableFields[]
+}
+
+// 所有过滤条件的数据
+interface BaseAllFilterInfo {
+  [key: string]: FilterInfo
+}
+
+// 所有固定字段的数据
+interface BaseAllFixedFiledsInfo {
+  [key: string]: Array<string>
+}
+
+export type {
+  BaseTableInfo,
+  BaseAllFieldsInfo,
+  BaseAllFilterInfo,
+  BaseAllFixedFiledsInfo,
+}

+ 0 - 12
src/utils/common/index.ts

@@ -108,18 +108,6 @@ export function resetTimeToMidnight(dateTime: Date): string {
 }
 
 /**
- * @description: 创建一个日期范围
- * @param {*} day 天数
- * @return {*}
- */
-export const createDateRange = (day: number): Array<Date> => {
-  const end = new Date()
-  const start = new Date()
-  start.setTime(start.getTime() - 3600 * 1000 * 24 * day)
-  return [start, end]
-}
-
-/**
  * @description:  判断日期范围是否有效
  * @param {string} startTime 开始时间
  * @param {string} endTime 结束时间

+ 416 - 43
src/views/Promotion/adManage/ttad.vue

@@ -1,10 +1,17 @@
 <script setup lang="ts">
+import { EleBtnType } from '@/types/Button/buttonType'
+
+import type {
+  OperationItem,
+  Operations,
+} from '@/types/Tables/Operations/operations'
 import type {
   TableData,
   FilterInfo,
   TableInfoItem,
   BaseFieldItem,
   TableFields,
+  SaveFields,
 } from '@/types/Tables/table'
 import type { BaseMenu } from '@/types/Promotion/Menu'
 import type {
@@ -17,54 +24,68 @@ import type {
   AdmgeTTProjFileds,
   AdmgeTTAdFileds,
 } from '@/types/Tables/tableData/ttAd'
+import type {
+  BaseTableInfo,
+  BaseAllFieldsInfo,
+  BaseAllFilterInfo,
+  BaseAllFixedFiledsInfo,
+} from '@/types/Tables/tablePageData'
 
 import { TableFilterType } from '@/types/Tables/table'
 
 import { useRequest } from '@/hooks/useRequest'
 import { useDate } from '@/hooks/useDate'
-import { onMounted, reactive, ref } from 'vue'
+import { computed, onMounted, reactive, ref, watch } 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]: TableInfoItem<TableData, BaseFieldItem<TableFields>>
+// 表格信息
+interface TableInfo extends BaseTableInfo {
   account: TableInfoItem<AdmgeTTAccData, BaseFieldItem<AdmgeTTAccFileds>> // 账户信息
   project: TableInfoItem<AdmgeTTProjData, BaseFieldItem<AdmgeTTProjFileds>> // 项目信息
   advertise: TableInfoItem<AdmgeTTAdData, BaseFieldItem<AdmgeTTAdFileds>> // 广告信息
 }
 
-interface AllFieldsInfo {
-  [key: string]: any
+// 所有字段信息
+interface AllFieldsInfo extends BaseAllFieldsInfo {
   account: AdmgeTTAccFileds[]
   project: AdmgeTTProjFileds[]
   advertise: AdmgeTTAdFileds[]
 }
 
-type TableMappingKeys = 'account' | 'project' | 'advertise'
-
-interface AllFilterInfo {
-  [key: string]: FilterInfo
+// 上方查询表单字段
+interface AllFilterInfo extends BaseAllFilterInfo {
   account: FilterInfo
   project: FilterInfo
   advertise: FilterInfo
 }
 
-interface AllFixedFiledsInfo {
-  [key: string]: Array<string>
+// 固定字段
+interface AllFixedFiledsInfo extends BaseAllFixedFiledsInfo {
   account: Array<string>
   project: Array<string>
   advertise: Array<string>
 }
 
+// 操作信息
+interface Operation extends Operations {
+  account: OperationItem[]
+  project: OperationItem[]
+  advertise: OperationItem[]
+}
+
 const { AllApi } = useRequest()
 const { disableDate, shortcuts } = useDate()
-const { getData } = useTable()
+const { getData, saveTableInfo, getTableInfo, updateTableFields } = useTable()
 
 // 当前菜单选中
 const activeMenu = ref('account')
 
+// 修改或新增的弹窗控制
+const tableItemDialog = ref(false)
+
 // 所有子字段信息
 const AllFields: AllFieldsInfo = {
   account: [
@@ -194,11 +215,15 @@ const accFilterInfo: FilterInfo = {
       { label: '优化师2', value: 'rose' },
     ],
   },
-  name: {
-    label: '名称',
-    name: 'name',
+  search: {
+    label: '搜索',
+    name: 'search',
     type: TableFilterType.Search,
-    value: '',
+    value: 'name',
+    options: [
+      { label: '名称', value: 'name' },
+      { label: '备注', value: 'backup' },
+    ],
   },
   product: {
     label: '产品',
@@ -212,11 +237,269 @@ const accFilterInfo: FilterInfo = {
   },
 }
 
+// 项目查询表单信息
+const projectFilter: FilterInfo = {
+  search: {
+    label: '搜索',
+    name: 'search',
+    type: TableFilterType.Search,
+    value: 'name',
+    options: [{ label: '名称', value: 'name' }],
+  },
+  ttProject: {
+    label: '创量项目',
+    name: 'ttProject',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '产品A', value: 'A' },
+      { label: '产品B', value: 'B' },
+    ], // Search 类型一般不需要 options
+  },
+  product: {
+    label: '创量产品',
+    name: 'product',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '产品A', value: 'A' },
+      { label: '产品B', value: 'B' },
+    ],
+  },
+  optimizationGoal: {
+    label: '优化目标',
+    name: 'optimizationGoal',
+    type: TableFilterType.Select,
+    value: 'clicks',
+    options: [
+      { label: '点击量', value: 'clicks' },
+      { label: '转化量', value: 'conversions' },
+      { label: '展示量', value: 'impressions' },
+    ],
+  },
+  deepOptimizationGoal: {
+    label: '深度优化目标',
+    name: 'deepOptimizationGoal',
+    type: TableFilterType.Select,
+    value: 'ROI',
+    options: [
+      { label: '投资回报率 (ROI)', value: 'ROI' },
+      { label: '订单数', value: 'orders' },
+      { label: '注册量', value: 'registrations' },
+    ],
+  },
+  mediaAccount: {
+    label: '媒体账户',
+    name: 'mediaAccount',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '账户1', value: '1' },
+      { label: '账户2', value: '2' },
+    ],
+  },
+  promotionObjective: {
+    label: '推广目的',
+    name: 'promotionObjective',
+    type: TableFilterType.Select,
+    value: 'sales',
+    options: [
+      { label: '销售转化', value: 'sales' },
+      { label: '品牌推广', value: 'branding' },
+      { label: '应用安装', value: 'app_install' },
+    ],
+  },
+  deliveryMode: {
+    label: '投放模式',
+    name: 'deliveryMode',
+    type: TableFilterType.Select,
+    value: 'automated',
+    options: [
+      { label: '自动投放', value: 'automated' },
+      { label: '手动投放', value: 'manual' },
+    ],
+  },
+  status: {
+    label: '状态',
+    name: 'status',
+    type: TableFilterType.Select,
+    value: 'active',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '启用', value: 'active' },
+      { label: '暂停', value: 'paused' },
+      { label: '已结束', value: 'ended' },
+    ],
+  },
+  creationTime: {
+    label: '创建时间',
+    name: 'creationTime',
+    type: TableFilterType.Date,
+    startDate: shortcuts[0].value()[0],
+    endDate: shortcuts[0].value()[1],
+    value: '',
+  },
+  adType: {
+    label: '广告类型',
+    name: 'adType',
+    type: TableFilterType.Select,
+    value: 'display',
+    options: [
+      { label: '展示广告', value: 'display' },
+      { label: '视频广告', value: 'video' },
+      { label: '搜索广告', value: 'search' },
+    ],
+  },
+}
+
+// 广告查询表单信息
+const adFilterInfo: FilterInfo = {
+  ttProject: {
+    label: '创量项目',
+    name: 'ttProject',
+    type: TableFilterType.Select,
+    value: 'name',
+    options: [{ label: '名称', value: 'name' }],
+  },
+  product: {
+    label: '创量产品',
+    name: 'product',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '产品A', value: 'A' },
+      { label: '产品B', value: 'B' },
+    ],
+  },
+  optimizer: {
+    label: '优化师',
+    name: 'optimizer',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '优化师A', value: 'A' },
+      { label: '优化师B', value: 'B' },
+    ],
+  },
+  diagnosticSuggestion: {
+    label: '诊断建议',
+    name: 'diagnosticSuggestion',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '建议A', value: 'A' },
+      { label: '建议B', value: 'B' },
+    ],
+  },
+  strategyGroup: {
+    label: '策略组',
+    name: 'strategyGroup',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '组A', value: 'A' },
+      { label: '组B', value: 'B' },
+    ],
+  },
+  learningStatus: {
+    label: '学习期状态',
+    name: 'learningStatus',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '进行中', value: 'ongoing' },
+      { label: '已完成', value: 'completed' },
+    ],
+  },
+  mediaAssets: {
+    label: '信息素材',
+    name: 'mediaAssets',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '素材A', value: 'A' },
+      { label: '素材B', value: 'B' },
+    ],
+  },
+  mediaAccount: {
+    label: '媒体账户',
+    name: 'mediaAccount',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '账户1', value: '1' },
+      { label: '账户2', value: '2' },
+    ],
+  },
+  promotionObjective: {
+    label: '推广目的',
+    name: 'promotionObjective',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '销售', value: 'sales' },
+      { label: '品牌推广', value: 'branding' },
+    ],
+  },
+  deliveryMode: {
+    label: '投放模式',
+    name: 'deliveryMode',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '自动投放', value: 'automated' },
+      { label: '手动投放', value: 'manual' },
+    ],
+  },
+  status: {
+    label: '状态',
+    name: 'status',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '启用', value: 'active' },
+      { label: '暂停', value: 'paused' },
+    ],
+  },
+  creationTime: {
+    label: '创建时间',
+    name: 'creationTime',
+    type: TableFilterType.Date,
+    startDate: new Date(),
+    endDate: new Date(),
+    value: '',
+  },
+  adType: {
+    label: '广告类型',
+    name: 'adType',
+    type: TableFilterType.Select,
+    value: 'all',
+    options: [
+      { label: '全部', value: 'all' },
+      { label: '展示广告', value: 'display' },
+      { label: '视频广告', value: 'video' },
+    ],
+  },
+}
+
 // 所有的查询表单信息
 const allFilters: AllFilterInfo = {
   account: accFilterInfo,
-  project: {},
-  advertise: {},
+  project: projectFilter,
+  advertise: adFilterInfo,
 }
 
 // 所有需要固定的字段
@@ -233,31 +516,74 @@ const tableReqInfo: { [key: string]: any } = {
   advertise: AllApi.mockAdTTAd,
 }
 
-// 项目查询表单信息
-
-// 广告查询表单信息
-// AllFields['account']
+// 表格信息
 const tableInfo = reactive<TableInfo>({
   account: {
     data: [],
-    fields: [{ label: '基础', name: 'base1', children: AllFields['account'] }],
+    fields: [
+      {
+        label: '基础',
+        name: 'base1',
+        value: [],
+        children: AllFields['account'],
+      },
+    ],
+    tableSortedFields: [],
     filters: allFilters['account'],
     fixedFields: allFixedFileds['account'],
   },
   project: {
     data: [],
-    fields: [{ label: '基础', name: 'base', children: AllFields['project'] }],
+    fields: [
+      {
+        label: '基础',
+        name: 'base2',
+        value: [],
+        children: AllFields['project'],
+      },
+    ],
+    tableSortedFields: [],
     filters: allFilters['project'],
     fixedFields: allFixedFileds['project'],
   },
   advertise: {
     data: [],
-    fields: [{ label: '基础', name: 'base', children: AllFields['advertise'] }],
+    fields: [
+      {
+        label: '基础',
+        name: 'base3',
+        value: [],
+        children: AllFields['advertise'],
+      },
+    ],
+    tableSortedFields: [],
     filters: allFilters['advertise'],
     fixedFields: allFixedFileds['advertise'],
   },
 })
 
+// 自定义的操作字段
+const operations: Operation = {
+  account: [
+    {
+      label: '修改',
+      type: EleBtnType.Primary,
+      func: () => {
+        tableItemDialog.value = true
+      },
+    },
+    {
+      label: '删除',
+      type: EleBtnType.Danger,
+      func: () => {
+        tableItemDialog.value = true
+      },
+    },
+  ],
+  advertise: [],
+  project: [],
+}
+
 // 导航
 const ttAdMenu: BaseMenu[] = [
   {
@@ -278,6 +604,14 @@ const ttAdMenu: BaseMenu[] = [
 const selectDate = ref(shortcuts[0].value())
 
 /**
+ * @description: 保存的文件名
+ * @return {*}
+ */
+const fileName = computed(() => {
+  return `ttad-${activeMenu.value}-tableInfo`
+})
+
+/**
  * @description: 日期改变
  * @param {*} val
  * @return {*}
@@ -297,10 +631,25 @@ const menuActiveChange = (val: string) => {
 }
 
 /**
+ * @description: 更新表格的字段信息
+ * @return {*}
+ */
+const updateTableInfo = () => {
+  let info = getTableInfo(fileName.value)
+
+  if (info) {
+    tableInfo[activeMenu.value].fields = info.fields
+    tableInfo[activeMenu.value].tableSortedFields = info.tableSortedFields
+  }
+}
+
+/**
  * @description: 更新表格数据
  * @return {*}
  */
 const updateTableData = () => {
+  updateTableInfo()
+
   getData(tableReqInfo[activeMenu.value]).then((res: Array<TableData>) => {
     tableInfo[activeMenu.value].data.splice(
       0,
@@ -310,30 +659,37 @@ const updateTableData = () => {
   })
 }
 
-const saveTableInfo = () => {
-  localStorage.setItem(`ttadTableInfo`, JSON.stringify(tableInfo))
-}
-
-const getTableInfo = (): TableInfo => {
-  let info = localStorage.getItem(`ttadTableInfo`)
-  if (!info) return {} as any
-  return JSON.parse(info) as TableInfo
-}
-
+/**
+ * @description: 更新自定义指标和表格字段
+ * @param {*} newIndicator  新的指标信息
+ * @param {*} newSortedTablefileds 新的表格字段信息
+ * @return {*}
+ */
 const updateCustomIndicator = (
   newIndicator: Array<BaseFieldItem<TableFields>>,
+  newSortedTablefileds: Array<TableFields>,
 ) => {
-  let activeTableFields = tableInfo[activeMenu.value].fields
-  activeTableFields.splice(0, activeTableFields.length, ...newIndicator)
-  saveTableInfo()
+  updateTableFields(
+    tableInfo,
+    activeMenu.value,
+    newIndicator,
+    newSortedTablefileds,
+  )
+    .then(() => {
+      saveTableInfo(fileName.value, tableInfo[activeMenu.value])
+    })
+    .catch(() => {
+      ElMessage.error('更新失败')
+    })
+  // saveTableInfo()
 }
 
 updateTableData()
 onMounted(() => {
-  let info: TableInfo = getTableInfo()
-  if (Object.keys(info).length !== 0) {
-    Object.assign(tableInfo, info)
-  }
+  // let info = getTableInfo(fileName.value)
+  // if (Object.keys(info).length !== 0) {
+  //   Object.assign(tableInfo, info)
+  // }
 })
 </script>
 
@@ -367,12 +723,29 @@ onMounted(() => {
     <div class="ttAdContent">
       <Table
         :table-fields="tableInfo[activeMenu].fields"
+        :sorted-table-fields="tableInfo[activeMenu].tableSortedFields"
         :table-data="tableInfo[activeMenu].data"
         :fixed-fields="tableInfo[activeMenu].fixedFields"
         :filters-info="tableInfo[activeMenu].filters"
         @update-custom-indicator="updateCustomIndicator"
-      ></Table>
+      >
+        <template #operations>
+          <div>
+            <el-button
+              text
+              :type="item.type"
+              v-for="item in operations[activeMenu]"
+              @click="item.func"
+            >
+              {{ item.label }}
+            </el-button>
+          </div>
+        </template>
+      </Table>
     </div>
+    <el-dialog v-model="tableItemDialog" title="Tips" width="500">
+      <span>This is a message</span>
+    </el-dialog>
   </div>
 </template>