Browse Source

列表页

CzRger 7 months ago
parent
commit
b9cd31ed74

+ 4 - 0
src/api/modules/mock/mock.ts

@@ -7,6 +7,10 @@ export const mockGetUserInfo = () => handle({
   url: `/${suffix}/getUserInfo`,
   method: 'get',
 })
+export const mockGetConfig = () => handle({
+  url: `/${suffix}/getConfig`,
+  method: 'get',
+})
 export const mockGetSearchHistory = () => handle({
   url: `/${suffix}/getSearchHistory`,
   method: 'get',

BIN
src/assets/images/web/wen-list_table-head-bg-1.png


BIN
src/assets/images/web/wen-list_table-head-bg-2.png


BIN
src/assets/images/web/wen-list_table-head-icon-1.png


BIN
src/assets/images/web/wen-list_table-head-icon-2.png


BIN
src/assets/images/web/wen-list_table-head-icon-3.png


BIN
src/assets/images/web/wen-list_table-head-icon-4.png


File diff suppressed because it is too large
+ 5 - 0
src/assets/svg/archives_1.svg


File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/card_1.svg


+ 12 - 0
src/assets/svg/detail_1.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 26.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 17" style="enable-background:new 0 0 16 17;" xml:space="preserve">
+<g>
+	<path class="st0" d="M12.6,1H3.2C2.3,1,1.6,1.8,1.6,2.7v12c0,0.9,0.7,1.7,1.7,1.7h9.3c0.9,0,1.7-0.7,1.7-1.7v-12
+		C14.2,1.8,13.6,1,12.6,1z M7.9,13.2H5.6c-0.3,0-0.5-0.2-0.5-0.5s0.2-0.5,0.5-0.5h2.3c0.3,0,0.5,0.2,0.5,0.5S8.2,13.2,7.9,13.2z
+		 M10.2,11.2H5.6c-0.3,0-0.5-0.2-0.5-0.5s0.2-0.5,0.5-0.5h4.7c0.3,0,0.5,0.2,0.5,0.5S10.6,11.2,10.2,11.2z M10.8,8
+		c0,0.3-0.2,0.5-0.5,0.5H5.6C5.3,8.5,5.1,8.3,5.1,8V4.7c0-0.3,0.2-0.5,0.5-0.5h4.7c0.3,0,0.5,0.2,0.5,0.5L10.8,8L10.8,8z"/>
+	<rect x="6.1" y="5.2" class="st0" width="3.7" height="2.3"/>
+</g>
+</svg>

+ 9 - 0
src/assets/svg/list_1.svg

@@ -0,0 +1,9 @@
+<svg width="16" height="17" viewBox="0 0 16 17" xmlns="http://www.w3.org/2000/svg">
+<g id="icon/&#229;&#136;&#151;&#232;&#161;&#168;">
+<g id="Group 4860">
+<rect id="Rectangle 3693" x="2.28564" y="2.98022" width="11.4286" height="1.52538" rx="0.762691"/>
+<rect id="Rectangle 3694" x="2.28564" y="7.93408" width="11.4286" height="1.52538" rx="0.762691"/>
+<rect id="Rectangle 3695" x="2.28564" y="12.8882" width="11.4286" height="1.52538" rx="0.762691"/>
+</g>
+</g>
+</svg>

+ 38 - 0
src/components/cus/CusPage.vue

@@ -0,0 +1,38 @@
+<template>
+  <el-pagination
+    :current-page="pageNum"
+    :page-size="pageSize"
+    :page-sizes="pageSizes"
+    layout="total, sizes, prev, pager, next, jumper"
+    :total="total"
+    size="small"
+    @size-change="handleSizeChange"
+    @current-change="handleCurrentChange"
+  />
+</template>
+
+<script setup lang="ts">
+defineOptions({
+  name: 'CusPage',
+});
+import {getCurrentInstance, reactive} from "vue";
+
+const {proxy} = getCurrentInstance()
+const emit = defineEmits(['page'])
+const props = defineProps({
+  pageNum: {required: true},
+  pageSize: {required: true},
+  total: {required: true},
+  pageSizes: {default: () => [10, 20, 30, 40, 50, 100]}
+})
+const state: any = reactive({})
+const handleSizeChange = (val) => {
+  emit('page', props.pageNum, val)
+}
+const handleCurrentChange = (val) => {
+  emit('page', val, props.pageSize)
+}
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 6 - 3
src/router/index.ts

@@ -3,10 +3,11 @@ import staticRouter from './modules/static'
 import webRouter from './modules/web'
 import manageRouter from './modules/manage'
 import Temp404 from '@/views/global/temp/404.vue'
-import {mockGetUserInfo} from "@/api/modules/mock/mock";
+import {mockGetUserInfo, mockGetConfig} from "@/api/modules/mock/mock";
 import {ElLoading, ElMessage} from "element-plus";
 import {useAppStore} from "@/stores";
 import {toLogin} from "@/utils/permissions";
+import initRootVar from "@/style/initRootVar";
 
 
 const routes = [
@@ -50,14 +51,16 @@ export const initMainRouter = async () => {
             background: 'rgba(0, 0, 0, 0.7)',
         })
         await Promise.all([
-            mockGetUserInfo()
-        ]).then(async ([user]) => {
+            mockGetUserInfo(),
+            mockGetConfig()
+        ]).then(async ([user, config]) => {
             userInfo = user.data
             console.log('管理员:', userInfo?.isAdmin)
             if (userInfo?.isAdmin) {
                 router.addRoute(manageRouter)
             }
             loading.close()
+            initRootVar(config.data)
         })
     } else if (location.pathname !== '/login') {
         toLogin()

+ 5 - 1
src/stores/web.ts

@@ -16,7 +16,7 @@ export const useWebStore = defineStore('web', {
       })
       return num
     },
-    searchAreaIndexMap() {
+    searchAreaTypeMap() {
       const map = new Map()
       this.searchAreaTree.forEach(v => {
         v.children?.forEach(c => {
@@ -36,6 +36,10 @@ export const useWebStore = defineStore('web', {
             v.children?.forEach(c => {
               c.treeId = c.indexKey
               c.treeName = c.indexName
+              c.children.forEach(s => {
+                s.treeId = s.indexKey
+                s.treeName = s.indexName
+              })
             })
             return v
           }))

+ 0 - 5
src/style/cus.scss

@@ -1,9 +1,4 @@
 :root {
-  --cus-main-color: #2E81FF;
-  --cus-text-color-1: #303133;
-  --cus-text-color-2: #606266;
-  --cus-text-color-3: #909399;
-  --cus-text-color-4: #C0C4CC;
 }
 
 .__hover {

+ 17 - 0
src/style/initRootVar.ts

@@ -0,0 +1,17 @@
+export default (config) => {
+  const extractRgbFromRgba = (rgbaString) => {
+    const match = rgbaString.match(/^rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})(?:,\s*[\d.]+)?\)$/);
+    if (match) {
+      return [parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3], 10)];
+    }
+    return [46, 129, 255];
+  }
+  const mainDefault = 'rgba(46, 129, 255, 1)'
+  console.log(config)
+  document.documentElement.style.setProperty('--cus-main-color', config.mainColor || mainDefault) // 主题色
+  document.documentElement.style.setProperty('--cus-main-color-rgb', extractRgbFromRgba(config.mainColor || mainDefault).join(',')) // 主题色rgb
+  document.documentElement.style.setProperty('--cus-text-color-1', config.textColor1 || 'rgba(48,49,51,1)') // 文字色1
+  document.documentElement.style.setProperty('--cus-text-color-2', config.textColor2 || 'rgba(96,98,102,1)') // 文字色1
+  document.documentElement.style.setProperty('--cus-text-color-3', config.textColor3 || 'rgba(144,147,153,1)') // 文字色1
+  document.documentElement.style.setProperty('--cus-text-color-4', config.textColor4 || 'rgba(192,196,204,1)') // 文字色1
+}

+ 576 - 8
src/views/web/list/index.vue

@@ -28,7 +28,7 @@
           <template v-else>
             <template v-for="(item, index) in state.cascaderParams.value">
               <div class="filter-item">
-                {{ WebStore.searchAreaIndexMap.get(item) }}
+                {{ WebStore.searchAreaTypeMap.get(item) }}
                 <SvgIcon class="__hover" name="close_1" size="10" color="var(--cus-text-color-3)" @click="onDelFilter(index)"/>
               </div>
             </template>
@@ -37,19 +37,168 @@
       </div>
       <div class="list-tab">
         <template v-for="item in state.resultParams.tree">
-          <div class="list-tab-item __hover" :class="{active: item.treeId === state.resultParams.activeTab}">{{item.treeName}}<span class="total">(898989898989)</span></div>
+          <div class="list-tab-item __hover" :class="{active: item.treeId === state.resultParams.activeTab}" @click="state.resultParams.activeTab = item.treeId">
+            {{item.treeName}}<span class="total">(898989898989)</span>
+          </div>
         </template>
       </div>
-      <div class="list-result">
-        <div class="list-result-tree"></div>
-        <div class="list-result-table"></div>
+      <div class="list-result" v-if="state.resultParams.activeTab">
+        <div class="list-result-tree">
+          <template v-for="item in state.resultParams.tree.filter(v => v.treeId === state.resultParams.activeTab)[0].children">
+            <div class="list-result-tree-item">
+              <div class="item-parent __hover" @click="item.__expend = !item.__expend">
+                <SvgIcon class="flag" name="flag_1" color="var(--cus-main-color)"/>
+                {{item.treeName}}
+                <span class="total">({{item.__total}})</span>
+                <SvgIcon class="expend" name="arrow_1" :rotate="item.__expend ? -90 : 90" color="var(--cus-text-color-4)"/>
+              </div>
+              <template v-if="item.__expend">
+                <template v-for="son in item.children">
+                  <div class="item-son __hover" :class="{active: son.treeId === state.resultParams.activeIndex}" @click="state.resultParams.activeIndex = son.treeId">
+                    {{son.treeName}}<span class="total">({{son.__total}})</span>
+                  </div>
+                </template>
+              </template>
+            </div>
+          </template>
+        </div>
+        <div class="list-result-table">
+          <div class="table-head">
+            <div class="table-head-index">
+              <SvgIcon class="flag" name="flag_1" color="var(--cus-main-color)"/>
+              {{currentIndexCpt.treeName}}
+              <span class="total">({{currentIndexCpt.__total}})</span>
+            </div>
+            <div class="table-head-infos">
+              <div class="main">
+                <img src="@/assets/images/web/wen-list_table-head-icon-1.png"/>
+                <div class="one">
+                  <div>更新时间:</div>
+                  <div>{{ state.resultParams.indexConfig?.updateTime }}</div>
+                  <div>接入时间:</div>
+                  <div>{{ state.resultParams.indexConfig?.createTime }}</div>
+                </div>
+                <div>
+                  <div>共享方式:</div>
+                  <div>{{ state.resultParams.indexConfig?.shareMethod }}</div>
+                  <div>更新周期:</div>
+                  <div>{{ state.resultParams.indexConfig?.updateCycle }}</div>
+                </div>
+              </div>
+              <div class="info">
+                <img src="@/assets/images/web/wen-list_table-head-icon-2.png"/>
+                <div>
+                  <div>数据共享来源</div>
+                  <div>{{ state.resultParams.indexConfig?.dataShareSource }}</div>
+                </div>
+              </div>
+              <div class="info">
+                <img src="@/assets/images/web/wen-list_table-head-icon-3.png"/>
+                <div>
+                  <div>数据提供来源</div>
+                  <div>{{ state.resultParams.indexConfig?.dataProvideSource }}</div>
+                </div>
+              </div>
+              <div class="info">
+                <img src="@/assets/images/web/wen-list_table-head-icon-4.png"/>
+                <div>
+                  <div>数据量</div>
+                  <div>{{ state.resultParams.indexConfig?.dataTotal }}<span>条</span></div>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="table-switch" v-if="tableConfigCpt.hasCard">
+            <div class="__hover" :class="{active: state.tableParams.model === 'list'}" @click="state.tableParams.model = 'list'">
+              <SvgIcon name="list_1" size="16" :color="state.tableParams.model === 'list' ? '#ffffff' : 'var(--cus-text-color-3)'"/>
+            </div>
+            <div class="__hover" :class="{active: state.tableParams.model === 'card'}" @click="state.tableParams.model = 'card'">
+              <SvgIcon name="card_1" size="16" :color="state.tableParams.model === 'card' ? '#ffffff' : 'var(--cus-text-color-3)'"/>
+            </div>
+          </div>
+          <div class="table-content">
+            <div class="table-content-result">
+              <div class="table-list" v-if="state.tableParams.model === 'list'">
+                <template v-for="(item, index) in state.tableParams.data">
+                  <div class="list-item __hover">
+                    <div class="index">{{index + 1 + (state.tableParams.pageNum - 1) * state.tableParams.pageSize }}</div>
+                    <div class="cols" :style="{
+                      gridTemplateColumns: `repeat(${tableConfigCpt.listCol}, 1fr)`
+                    }">
+                      <template v-for="c in tableConfigCpt.listConfig">
+                        <div class="cols-item" :style="{
+                          gridColumn: `span ${c.col}`
+                        }">
+                          <div class="cols-item-label">{{c.key}}:</div>
+                          <div class="cols-item-value" v-html="item[c.value]"/>
+                        </div>
+                      </template>
+                    </div>
+                    <div class="operation">
+                      <div class="__hover">
+                        <SvgIcon name="detail_1" color="var(--cus-main-color)"/>详情
+                      </div>
+                      <div class="__hover">
+                        <SvgIcon name="archives_1" color="var(--cus-main-color)"/>档案
+                      </div>
+                    </div>
+                  </div>
+                </template>
+              </div>
+              <div class="table-card" v-if="state.tableParams.model === 'card'" :style="{
+                gridTemplateColumns: `repeat(${tableConfigCpt.cardLayout}, 1fr)`
+              }">
+                <template v-for="(item, index) in state.tableParams.data">
+                  <div class="card-item __hover">
+                    <div class="main-row">
+                      <template v-if="tableConfigCpt?.cardImg.value">
+                        <div class="main-row-img">
+                          <img :src="item[tableConfigCpt?.cardImg.value]"/>
+                        </div>
+                      </template>
+                      <div class="main-row-param" v-html="item[tableConfigCpt.cardMain.value]"/>
+                      <div class="main-row-operation">
+                        <div class="__hover">
+                          <SvgIcon name="detail_1" color="var(--cus-main-color)"/>详情
+                        </div>
+                        <div class="__hover">
+                          <SvgIcon name="archives_1" color="var(--cus-main-color)"/>档案
+                        </div>
+                      </div>
+                    </div>
+                    <div class="cols" :style="{
+                      gridTemplateColumns: `repeat(${tableConfigCpt.cardCol}, 1fr)`
+                    }">
+                      <template v-for="c in tableConfigCpt.cardConfig">
+                        <div class="cols-item" :style="{
+                          gridColumn: `span ${c.col}`
+                        }">
+                          <div class="cols-item-label">{{c.key}}:</div>
+                          <div class="cols-item-value" v-html="item[c.value]"/>
+                        </div>
+                      </template>
+                    </div>
+                  </div>
+                </template>
+              </div>
+            </div>
+            <div class="table-content-page">
+              <CusPage
+                :page-num="state.tableParams.pageNum"
+                :page-size="state.tableParams.pageSize"
+                :total="state.tableParams.total"
+                @page="onPage"
+              />
+            </div>
+          </div>
+        </div>
       </div>
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
-import {computed, getCurrentInstance, onMounted, reactive, ref} from "vue";
+import {computed, getCurrentInstance, onBeforeMount, onMounted, reactive, ref, watch} from "vue";
 import {useRoute, useRouter} from "vue-router";
 import {useWebStore} from "@/stores";
 
@@ -78,12 +227,72 @@ const state: any = reactive({
     tree: [],
     activeTab: '',
     activeIndex: '',
+    indexConfig: {}
+  },
+  wsFunc: {
+    total: () => {},
+    page: () => {}
+  },
+  tableParams: {
+    model: 'list',
+    pageNum: 1,
+    pageSize: 10,
+    total: 0,
+    data: []
   }
 })
 const ref_area = ref()
 const isSelectAllCpt = computed(() => {
   return WebStore.searchAreaIndexTotal === state.cascaderParams.value.length
 })
+const currentIndexCpt = computed(() => {
+  let obj = {}
+  state.resultParams.tree.forEach(v => {
+    v.children.forEach(c => {
+      c.children.forEach(s => {
+        if (s.treeId === state.resultParams.activeIndex) {
+          obj = s
+        }
+      })
+    })
+  })
+  return JSON.parse(JSON.stringify(obj))
+})
+const tableConfigCpt = computed(() => {
+  return {
+    listCol: 5,
+    listConfig: [
+      {key: '姓名', value: 'name', col: 3},
+      {key: '性别', value: 'sex', col: 1},
+      {key: '出生日期', value: 'a', col: 1},
+      {key: '出生日期1', value: 'a', col: 1},
+      {key: '出生日期2', value: 'a', col: 3},
+      {key: '出生日期3', value: 'a', col: 1},
+      {key: '出生日期4', value: 'a', col: 1},
+      {key: '出生日期5', value: 'a', col: 1},
+      {key: '出生日期6', value: 'a', col: 1},
+      {key: '出生日期7', value: 'a', col: 1},
+      {key: '出生日期8', value: 'a', col: 1},
+      {key: '出生日期9', value: 'a', col: 1},
+    ],
+    hasCard: true,
+    cardLayout: 3,
+    cardCol: 2,
+    cardMain: {key: '姓名', value: 'name', col: 1},
+    cardImg: {key: '头像', value: 'avatar', isImg: true},
+    cardConfig: [
+      {key: '性别', value: 'sex', col: 1},
+      {key: '出生日期', value: 'a', col: 2},
+      {key: '出生日期1', value: 'a', col: 1},
+      {key: '出生日期2', value: 'a', col: 1},
+      {key: '出生日期3', value: 'a', col: 1},
+      {key: '出生日期4', value: 'a', col: 1},
+      {key: '出生日期5', value: 'a', col: 1},
+      {key: '出生日期6', value: 'a', col: 1},
+    ]
+  }
+})
+
 const initArea = () => {
   WebStore.getSearchAreaTree().then(res => {
     state.cascaderParams.options = res
@@ -96,6 +305,26 @@ const onDelFilter = (index) => {
   state.cascaderParams.value = temp
 }
 const onSearch = () => {
+  state.tableParams = {
+    model: 'card',
+    pageNum: 1,
+    pageSize: 10,
+    total: 0,
+    data: [
+      {name: '胡杰<span style="color: red;">顶顶顶</span>顶顶', sex: '男', a: 1, b: 2, c: 3, d: 4, avatar: 'https://element-plus.org/images/element-plus-logo.svg'},
+      {name: '胡杰<span style="color: red;">顶顶顶</span>顶顶', sex: '男', a: 1, b: 2, c: 3, d: 4, avatar: 'https://element-plus.org/images/element-plus-logo.svg'},
+      {name: '胡杰<span style="color: red;">顶顶顶</span>顶顶', sex: '男', a: 1, b: 2, c: 3, d: 4, avatar: 'https://element-plus.org/images/element-plus-logo.svg'},
+      {name: '胡杰<span style="color: red;">顶顶顶</span>顶顶', sex: '男', a: 1, b: 2, c: 3, d: 4, avatar: 'https://element-plus.org/images/element-plus-logo.svg'},
+      {name: '胡杰<span style="color: red;">顶顶顶</span>顶顶', sex: '男', a: 1, b: 2, c: 3, d: 4, avatar: 'https://element-plus.org/images/element-plus-logo.svg'},
+      {name: '胡杰<span style="color: red;">顶顶顶</span>顶顶', sex: '男', a: 1, b: 2, c: 3, d: 4, avatar: 'https://element-plus.org/images/element-plus-logo.svg'},
+      {name: '胡杰<span style="color: red;">顶顶顶</span>顶顶', sex: '男', a: 1, b: 2, c: 3, d: 4, avatar: 'https://element-plus.org/images/element-plus-logo.svg'},
+      {name: '胡杰<span style="color: red;">顶顶顶</span>顶顶', sex: '男', a: 1, b: 2, c: 3, d: 4, avatar: 'https://element-plus.org/images/element-plus-logo.svg'},
+      {name: '胡杰<span style="color: red;">顶顶顶</span>顶顶', sex: '男', a: 1, b: 2, c: 3, d: 4, avatar: 'https://element-plus.org/images/element-plus-logo.svg'},
+      {name: '胡杰<span style="color: red;">顶顶顶</span>顶顶', sex: '男', a: 1, b: 2, c: 3, d: 4, avatar: 'https://element-plus.org/images/element-plus-logo.svg'},
+      {name: '胡杰<span style="color: red;">顶顶顶</span>顶顶', sex: '男', a: 1, b: 2, c: 3, d: 4, avatar: 'https://element-plus.org/images/element-plus-logo.svg'},
+      {name: '胡杰<span style="color: red;">顶顶顶</span>顶顶', sex: '男', a: 1, b: 2, c: 3, d: 4, avatar: 'https://element-plus.org/images/element-plus-logo.svg'},
+    ]
+  }
   state.searchParams = JSON.parse(JSON.stringify({
     text: state.searchText,
     indexKey: state.cascaderParams.value
@@ -103,6 +332,8 @@ const onSearch = () => {
   initResultTree()
 }
 const initResultTree = () => {
+  state.resultParams.activeTab = ''
+  state.resultParams.activeIndex = ''
   const arr = []
   WebStore.searchAreaTree.forEach(v => {
     const t = {
@@ -119,13 +350,54 @@ const initResultTree = () => {
     }
   })
   if (arr.length > 0) {
-    state.resultParams.tree = arr
+    state.resultParams.tree = JSON.parse(JSON.stringify(arr))
   } else {
     state.resultParams.tree = JSON.parse(JSON.stringify(WebStore.searchAreaTree))
   }
   state.resultParams.activeTab = state.resultParams.tree[0].treeId
-  state.resultParams.activeIndex = state.resultParams.tree[0].children[0].treeId
+  state.resultParams.tree[0].children[0].__expend = true
+  state.resultParams.activeIndex = state.resultParams.tree[0].children[0].children[0].treeId
 }
+const getIndexConfig = () => {
+  state.resultParams.indexConfig = {}
+  setTimeout(() => {
+    state.resultParams.indexConfig = {
+      updateTime: '2024-09-09 14:20:20',
+      createTime: '2024-09-09 14:20:20',
+      shareMethod: '数据库表',
+      updateCycle: 'T+1',
+      dataShareSource: '海南省大数据管理局',
+      dataProvideSource: '海南省大数据管理局',
+      dataTotal: '9125815819',
+    }
+  },500)
+}
+const onPage = (pageNum, pageSize) => {
+  state.tableParams.pageNum = pageNum
+  state.tableParams.pageSize = pageSize
+}
+watch(() => state.resultParams.activeIndex, (n) => {
+  if (n) {
+    getIndexConfig()
+  }
+})
+onBeforeMount(() => {
+  const ws: any = new WebSocket('ws://localhost:18375')
+  ws.onopen = (e) => {
+    console.log(e)
+    // const str = {}
+    // ws.send(JSON.stringify(str))
+  }
+  ws.onmessage = (e) => {
+    try {
+      const json = JSON.parse(e.data)
+      console.log(json)
+    } catch (e) {
+
+    }
+  }
+  state.ws = ws
+})
 onMounted(() => {
   initArea()
   const {text, index} = route.query
@@ -217,6 +489,7 @@ onMounted(() => {
     }
   }
   .list-content {
+    overflow: hidden;
     flex: 1;
     padding: 24px;
     display: flex;
@@ -288,6 +561,301 @@ onMounted(() => {
     .list-result {
       flex: 1;
       background-color: #ffffff;
+      padding: 16px;
+      display: flex;
+      gap: 16px;
+      overflow: hidden;
+      .list-result-tree {
+        height: 100%;
+        width: 300px;
+        padding-right: 10px;
+        overflow-y: auto;
+        .list-result-tree-item {
+          .item-parent {
+            min-height: 38px;
+            display: flex;
+            align-items: center;
+            padding-right: 16px;
+            line-height: 1;
+            color: var(--cus-text-color-1);
+            .flag {
+              margin-right: 10px;
+            }
+            .total {
+              font-size: 14px;
+            }
+            .expend {
+              margin-left: auto;
+            }
+          }
+          .item-son {
+            padding: 10px 34px;
+            font-weight: 400;
+            font-size: 14px;
+            color: var(--cus-text-color-2);
+            border-radius: 4px;
+            .total {
+              font-size: 12px;
+            }
+            &.active {
+              background-color: rgba(var(--cus-main-color-rgb), 0.1);
+              color: var(--cus-main-color);
+            }
+          }
+        }
+      }
+      .list-result-table {
+        display: flex;
+        flex-direction: column;
+        flex: 1;
+        .table-head {
+          width: 100%;
+          height: 162px;
+          padding: 16px;
+          background: linear-gradient( 90deg, rgba(var(--cus-main-color-rgb),0.1) 0%, rgba(var(--cus-main-color-rgb),0.05) 100%), #FFFFFF;
+          box-shadow: 0px 2px 4px 0px rgba(var(--cus-main-color-rgb),0.3);
+          border-radius: 4px;
+          display: flex;
+          flex-direction: column;
+          .table-head-index {
+            display: flex;
+            align-items: center;
+            padding-right: 16px;
+            line-height: 1;
+            color: var(--cus-text-color-1);
+            .flag {
+              margin-right: 10px;
+            }
+            .total {
+              font-size: 14px;
+            }
+          }
+          .table-head-infos {
+            flex: 1;
+            display: flex;
+            align-items: flex-end;
+            overflow: hidden;
+            gap: 10px;
+            .main {
+              height: 92px;
+              width: 455px;
+              display: flex;
+              align-items: center;
+              background-image: url("@/assets/images/web/wen-list_table-head-bg-2.png");
+              background-repeat: no-repeat;
+              background-size: 100% 100%;
+              font-weight: 400;
+              font-size: 12px;
+              >img {
+                margin-left: 24px;
+                height: 100%;
+              }
+              >div {
+                >div {
+                  &:nth-child(odd) {
+                    color: var(--cus-text-color-3);
+                  }
+                  &:nth-child(even) {
+                    color: var(--cus-text-color-2);
+                  }
+                  &:nth-child(2) {
+                    margin-bottom: 6px;
+                  }
+                }
+              }
+              .one {
+                margin: 0 32px;
+              }
+            }
+            .info {
+              flex: 1;
+              height: 70px;
+              background-image: url("@/assets/images/web/wen-list_table-head-bg-1.png");
+              background-repeat: no-repeat;
+              background-size: 100% 100%;
+              position: relative;
+              >img {
+                position: absolute;
+                bottom: 0;
+                left: 20px;
+              }
+              >div {
+                margin-left: 144px;
+                margin-top: 14px;
+                >div:nth-child(1) {
+                  font-weight: 400;
+                  font-size: 14px;
+                  color: var(--cus-text-color-2);
+                }
+                >div:nth-child(2) {
+                  margin-top: 4px;
+                  font-weight: 500;
+                  font-size: 16px;
+                  color: var(--cus-main-color);
+                  >span {
+                    font-size: 12px;
+                  }
+                }
+              }
+            }
+          }
+        }
+        .table-switch {
+          margin: 10px 0 10px auto;
+          display: flex;
+          >div {
+            width: 34px;
+            height: 34px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            background-color: #F5F7FA;
+            border: 1px solid #DCDFE5;
+            &:nth-child(1) {
+              border-radius: 4px 0 0 4px;
+            }
+            &:nth-child(2) {
+              border-radius: 0 4px 4px 0;
+            }
+            &.active {
+              background-color: var(--cus-main-color);
+              border-color: var(--cus-main-color);
+            }
+          }
+        }
+        .table-content {
+          flex: 1;
+          display: flex;
+          flex-direction: column;
+          overflow: hidden;
+          .table-content-result {
+            flex: 1;
+            overflow: hidden;
+            .table-list {
+              width: 100%;
+              height: 100%;
+              display: flex;
+              flex-direction: column;
+              overflow-y: auto;
+              border: 1px solid #EAEBEF;
+              border-radius: 4px;
+              .list-item {
+                display: flex;
+                align-items: center;
+                font-weight: 400;
+                font-size: 14px;
+                color: var(--cus-text-color-2);
+                padding: 12px 16px;
+                &:hover {
+                  background-color: rgba(46,129,255,0.05);
+                }
+                &:not(:last-child) {
+                  border-bottom: 1px solid #EAEBEF;
+                }
+                .index {
+                  margin-right: 16px;
+                }
+                .cols {
+                  flex: 1;
+                  display: grid;
+                  row-gap: 4px;
+                  .cols-item {
+                    display: flex;
+                    .cols-item-label {
+                      color: var(--cus-text-color-1);
+                      font-weight: bold;
+                    }
+                    .cols-item-value {
+                      color: var(--cus-text-color-2);
+                    }
+                  }
+                }
+                .operation {
+                  display: flex;
+                  align-items: center;
+                  gap: 10px;
+                  font-size: 14px;
+                  color: var(--cus-text-color-2);
+                  >div {
+                    display: flex;
+                    align-items: center;
+                    .svg-icon {
+                      margin-right: 2px;
+                    }
+                  }
+                }
+              }
+            }
+            .table-card {
+              width: 100%;
+              height: 100%;
+              display: grid;
+              overflow-y: auto;
+              gap: 16px;
+              .card-item {
+                padding: 16px;
+                background: linear-gradient( 180deg, rgba(var(--cus-main-color-rgb), 0.1) 0%, rgba(var(--cus-main-color-rgb),0) 100%), #FFFFFF;
+                box-shadow: 0px 2px 4px 0px rgba(var(--cus-main-color-rgb),0.2);
+                border-radius: 4px;
+                .main-row {
+                  display: flex;
+                  align-items: center;
+                  .main-row-img {
+                    width: 40px;
+                    height: 40px;
+                    border-radius: 4px;
+                    margin-right: 10px;
+                    >img {
+                      width: 100%;
+                      height: 100%;
+                    }
+                  }
+                  .main-row-param {
+                    font-size: 20px;
+                    color: var(--cus-text-color-1);
+                    font-weight: bold;
+                  }
+                  .main-row-operation {
+                    display: flex;
+                    align-items: center;
+                    gap: 10px;
+                    font-size: 14px;
+                    color: var(--cus-text-color-2);
+                    margin-left: auto;
+                    >div {
+                      display: flex;
+                      align-items: center;
+                      .svg-icon {
+                        margin-right: 2px;
+                      }
+                    }
+                  }
+                }
+                .cols {
+                  flex: 1;
+                  display: grid;
+                  row-gap: 4px;
+                  font-size: 14px;
+                  .cols-item {
+                    display: flex;
+                    .cols-item-label {
+                      color: var(--cus-text-color-1);
+                      font-weight: bold;
+                    }
+                    .cols-item-value {
+                      color: var(--cus-text-color-2);
+                    }
+                  }
+                }
+              }
+            }
+          }
+          .table-content-page {
+            margin-top: 10px;
+            margin-left: auto;
+          }
+        }
+      }
     }
   }
 }