li.shaoyi 3 年 前
コミット
daf20d0477

+ 32 - 2
package-lock.json

@@ -21,7 +21,8 @@
         "vant": "^3.4.8",
         "vue": "^3.2.13",
         "vue-class-component": "^8.0.0-0",
-        "vue-router": "^4.0.3"
+        "vue-router": "^4.0.3",
+        "vuedraggable": "^4.1.0"
       },
       "devDependencies": {
         "@types/crypto-js": "^4.1.1",
@@ -10604,6 +10605,11 @@
         "websocket-driver": "^0.7.4"
       }
     },
+    "node_modules/sortablejs": {
+      "version": "1.14.0",
+      "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
+      "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
+    },
     "node_modules/source-map": {
       "version": "0.5.7",
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -11762,6 +11768,17 @@
       "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
       "dev": true
     },
+    "node_modules/vuedraggable": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz",
+      "integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
+      "dependencies": {
+        "sortablejs": "1.14.0"
+      },
+      "peerDependencies": {
+        "vue": "^3.0.1"
+      }
+    },
     "node_modules/watchpack": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
@@ -20335,6 +20352,11 @@
         "websocket-driver": "^0.7.4"
       }
     },
+    "sortablejs": {
+      "version": "1.14.0",
+      "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
+      "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
+    },
     "source-map": {
       "version": "0.5.7",
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -21204,6 +21226,14 @@
       "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
       "dev": true
     },
+    "vuedraggable": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz",
+      "integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
+      "requires": {
+        "sortablejs": "1.14.0"
+      }
+    },
     "watchpack": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
@@ -21769,4 +21799,4 @@
       }
     }
   }
-}
+}

+ 3 - 2
package.json

@@ -23,7 +23,8 @@
     "vant": "^3.4.8",
     "vue": "^3.2.13",
     "vue-class-component": "^8.0.0-0",
-    "vue-router": "^4.0.3"
+    "vue-router": "^4.0.3",
+    "vuedraggable": "^4.1.0"
   },
   "devDependencies": {
     "@types/crypto-js": "^4.1.1",
@@ -46,4 +47,4 @@
     "typescript": "~4.5.5",
     "vconsole": "^3.14.6"
   }
-}
+}

+ 25 - 0
src/components/base/tab/index.less

@@ -0,0 +1,25 @@
+.app-tab {
+    &__list {
+        display: flex;
+
+        &-item {
+            display        : flex;
+            justify-content: center;
+            align-items    : center;
+            height         : 22px;
+            color          : #7a8a94;
+            cursor         : pointer;
+            border         : 1px solid #22292c;
+            padding        : 0 16px;
+
+            &:not(:first-child) {
+                border-left: 0;
+            }
+
+            &.active {
+                color           : #0866b8;
+                background-color: #0e2f4c;
+            }
+        }
+    }
+}

+ 53 - 0
src/components/base/tab/index.vue

@@ -0,0 +1,53 @@
+<!-- 标签栏组件 -->
+<template>
+  <div class="app-tab">
+    <ul class="app-tab__list" v-if="dataSource.length">
+      <li :class="['app-tab__list-item', selectedIndex === index && 'active']" v-for="(item, index) in dataSource"
+        :key="index" @click="onChange(index)">
+        {{ prop ? item[prop] : '标签' + index }}
+      </li>
+    </ul>
+    <slot></slot>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, watch } from 'vue'
+
+const emit = defineEmits(['update:dataIndex', 'change']);
+
+const props = defineProps({
+  dataSource: {
+    type: Array,
+    default: () => ([]),
+  },
+  // 当前标签索引
+  dataIndex: {
+    type: Number,
+    default: 0,
+  },
+  // 标签对应的字段名
+  prop: {
+    type: String,
+    default: 'label',
+  },
+})
+
+const selectedIndex = ref(props.dataIndex);
+
+const onChange = (index: number) => {
+  if (selectedIndex.value !== index) {
+    selectedIndex.value = index;
+    emit('update:dataIndex', index);
+    emit('change', index, props.dataSource[index]);
+  }
+}
+
+watch(() => props.dataIndex, (val) => {
+  selectedIndex.value = val;
+})
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 0 - 27
src/components/base/tabbar/index.less

@@ -1,27 +0,0 @@
-.app-tabbar {
-    &--menu {
-        .list {
-            display: flex;
-
-            &-item {
-                display        : flex;
-                justify-content: center;
-                align-items    : center;
-                height         : 22px;
-                color          : #7a8a94;
-                cursor         : pointer;
-                border         : 1px solid #22292c;
-                padding        : 0 16px;
-
-                &:not(:first-child) {
-                    border-left: 0;
-                }
-
-                &.active {
-                    color           : #0866b8;
-                    background-color: #0e2f4c;
-                }
-            }
-        }
-    }
-}

+ 0 - 45
src/components/base/tabbar/index.vue

@@ -1,45 +0,0 @@
-<!-- 标签栏组件 -->
-<template>
-  <div :class="['app-tabbar', 'app-tabbar--' + theme]">
-    <ul class="list">
-      <li :class="['list-item', activeIndex === index && 'active']" v-for="(item,index) in dataSource" :key="index" @click="onChange(item,index)">
-        {{item.label}}
-      </li>
-    </ul>
-    <slot></slot>
-  </div>
-</template>
-
-<script lang="ts" setup>
-import { PropType, ref } from 'vue'
-import { Tabbar } from './interface'
-
-const emit = defineEmits(['update:active', 'change']);
-
-const props = defineProps({
-  dataSource: {
-    type: Array as PropType<Tabbar[]>,
-    default: () => ([]),
-  },
-  dataIndex: {
-    type: Number,
-    default: 0,
-  },
-  theme: {
-    type: String as PropType<'bar' | 'menu'>,
-    default: 'bar',
-  }
-})
-
-const activeIndex = ref(props.dataIndex);
-
-const onChange = (item: Tabbar, index: number) => {
-  activeIndex.value = index;
-  emit('update:active', index);
-  emit('change', item, index);
-}
-</script>
-
-<style lang="less">
-@import './index.less';
-</style>

+ 0 - 7
src/components/base/tabbar/interface.ts

@@ -1,7 +0,0 @@
-/** 
- * 标签栏
- */
-export interface Tabbar<T = unknown> {
-    label: string;
-    value: T;
-}

+ 30 - 26
src/components/modules/echarts-kline/index.vue

@@ -2,52 +2,57 @@
   <div class="app-echats-kline">
     <div class="app-echats-kline__container main">
       <ul class="legend">
-        <li class="legend-item">开: {{klineDetail ? klineDetail.open : '--'}}</li>
-        <li class="legend-item">收: {{klineDetail ? klineDetail.close : '--'}}</li>
-        <li class="legend-item">高: {{klineDetail ? klineDetail.highest : '--'}}</li>
-        <li class="legend-item">低: {{klineDetail ? klineDetail.lowest : '--'}}</li>
-        <li class="legend-item">MA5: {{klineDetail ? klineDetail.ma5 : '--'}}</li>
-        <li class="legend-item">MA10: {{klineDetail ? klineDetail.ma10 : '--'}}</li>
-        <li class="legend-item">MA15: {{klineDetail ? klineDetail.ma15 : '--'}}</li>
+        <li class="legend-item">开: {{ klineDetail ? klineDetail.open : '--' }}</li>
+        <li class="legend-item">收: {{ klineDetail ? klineDetail.close : '--' }}</li>
+        <li class="legend-item">高: {{ klineDetail ? klineDetail.highest : '--' }}</li>
+        <li class="legend-item">低: {{ klineDetail ? klineDetail.lowest : '--' }}</li>
+        <li class="legend-item">MA5: {{ klineDetail ? klineDetail.ma5 : '--' }}</li>
+        <li class="legend-item">MA10: {{ klineDetail ? klineDetail.ma10 : '--' }}</li>
+        <li class="legend-item">MA15: {{ klineDetail ? klineDetail.ma15 : '--' }}</li>
       </ul>
-      <app-echarts :option="klineOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading" @ready="mainReady" />
+      <app-echarts :option="klineOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading"
+        @ready="mainReady" />
     </div>
     <template v-if="showIndicator">
       <div class="app-echats-kline__container indicator">
         <!-- MACD -->
         <section class="section" v-if="activeSeriesType === EChartsSeriesType.MACD">
           <ul class="legend">
-            <li class="legend-item">MACD: {{macdDetail ? macdDetail.macd : '--'}}</li>
-            <li class="legend-item">DIF: {{macdDetail ? macdDetail.dif : '--'}}</li>
-            <li class="legend-item">DEA: {{macdDetail ? macdDetail.dea : '--'}}</li>
+            <li class="legend-item">MACD: {{ macdDetail ? macdDetail.macd : '--' }}</li>
+            <li class="legend-item">DIF: {{ macdDetail ? macdDetail.dif : '--' }}</li>
+            <li class="legend-item">DEA: {{ macdDetail ? macdDetail.dea : '--' }}</li>
           </ul>
-          <app-echarts :option="macdOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading" @ready="indicatorReady" />
+          <app-echarts :option="macdOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading"
+            @ready="indicatorReady" />
         </section>
         <!-- VOL -->
         <section class="section" v-if="activeSeriesType === EChartsSeriesType.VOL">
           <ul class="legend">
-            <li class="legend-item">VOL: {{volDetail ? volDetail.vol : '--'}}</li>
+            <li class="legend-item">VOL: {{ volDetail ? volDetail.vol : '--' }}</li>
           </ul>
-          <app-echarts :option="volOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading" @ready="indicatorReady" />
+          <app-echarts :option="volOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading"
+            @ready="indicatorReady" />
         </section>
         <!-- KDJ -->
         <section class="section" v-if="activeSeriesType === EChartsSeriesType.KDJ">
           <ul class="legend">
-            <li class="legend-item">K: {{kdjDetail ? kdjDetail.k : '--'}}</li>
-            <li class="legend-item">D: {{kdjDetail ? kdjDetail.d : '--'}}</li>
-            <li class="legend-item">J: {{kdjDetail ? kdjDetail.j : '--'}}</li>
+            <li class="legend-item">K: {{ kdjDetail ? kdjDetail.k : '--' }}</li>
+            <li class="legend-item">D: {{ kdjDetail ? kdjDetail.d : '--' }}</li>
+            <li class="legend-item">J: {{ kdjDetail ? kdjDetail.j : '--' }}</li>
           </ul>
-          <app-echarts :option="kdjOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading" @ready="indicatorReady" />
+          <app-echarts :option="kdjOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading"
+            @ready="indicatorReady" />
         </section>
         <!-- CCI -->
         <section class="section" v-if="activeSeriesType === EChartsSeriesType.CCI">
           <ul class="legend">
-            <li class="legend-item">CCI: {{cciDetail ? cciDetail.cci : '--'}}</li>
+            <li class="legend-item">CCI: {{ cciDetail ? cciDetail.cci : '--' }}</li>
           </ul>
-          <app-echarts :option="cciOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading" @ready="indicatorReady" />
+          <app-echarts :option="cciOption" :empty="showEmpty" v-model:index="dataIndex" v-model:loading="loading"
+            @ready="indicatorReady" />
         </section>
       </div>
-      <app-tabbar theme="menu" :data-source="tabs" @change="tabChange" />
+      <app-tab theme="menu" :data-source="tabs" @change="tabChange" />
     </template>
   </div>
 </template>
@@ -61,8 +66,7 @@ import { useOptions } from './options'
 import moment from 'moment';
 import * as echarts from 'echarts'
 import AppEcharts from '@/components/base/echarts/index.vue'
-import AppTabbar from '@/components/base/tabbar/index.vue'
-import { Tabbar } from '@/components/base/tabbar/interface'
+import AppTab from '@/components/base/tab/index.vue'
 
 const props = defineProps({
   goodsCode: String,
@@ -93,7 +97,7 @@ const volDetail = computed(() => volData.source[dataIndex.value]);
 const kdjDetail = computed(() => kdjData.source[dataIndex.value]);
 const cciDetail = computed(() => cciData.source[dataIndex.value]);
 
-const tabs: Tabbar[] = [
+const tabs = [
   { label: 'MACD', value: EChartsSeriesType.MACD },
   { label: 'VOL', value: EChartsSeriesType.VOL },
   { label: 'KDJ', value: EChartsSeriesType.KDJ },
@@ -153,8 +157,8 @@ const initData = () => {
 }
 
 // 指标切换
-const tabChange = (item: Tabbar<EChartsSeriesType>) => {
-  activeSeriesType.value = item.value;
+const tabChange = (index: number) => {
+  activeSeriesType.value = tabs[index].value;
   setTimeout(() => {
     initOptions();
   }, 0);

+ 8 - 8
src/packages/mobile/components/base/tabbar/index.vue

@@ -6,14 +6,14 @@
           <slot :item="item" :index="index">
             <!--判断是否图片图标-->
             <template v-if="(item.icon instanceof Object)">
-              <div :class="['g-icon', active === index && 'active']">
-                <img :src="item.icon.active" v-if="active === index" />
+              <div :class="['g-icon', selectedIndex === index && 'active']">
+                <img :src="item.icon.active" v-if="selectedIndex === index" />
                 <img :src="item.icon.inactive" v-else />
                 <span>{{ item.label }}</span>
               </div>
             </template>
             <template v-else>
-              <div :class="['g-icon', item.icon, active === index && 'active']">
+              <div :class="['g-icon', item.icon, selectedIndex === index && 'active']">
                 <span>{{ item.label }}</span>
               </div>
             </template>
@@ -49,7 +49,7 @@ const props = defineProps({
   }
 })
 
-const active = ref(props.dataIndex);
+const selectedIndex = ref(props.dataIndex);
 const { clientWidth } = client.getState();
 
 const styles = computed(() => ({
@@ -58,14 +58,14 @@ const styles = computed(() => ({
 }))
 
 const onChange = (index: number) => {
-  if (active.value !== index) {
-    active.value = index;
+  if (selectedIndex.value !== index) {
+    selectedIndex.value = index;
     emit('update:dataIndex', index);
-    emit('change', props.dataSource[index], index);
+    emit('change', index, props.dataSource[index]);
   }
 }
 
-watch(() => props.dataIndex, (val) => active.value = val);
+watch(() => props.dataIndex, (val) => selectedIndex.value = val);
 </script>
 
 <style lang="less" scoped>

+ 15 - 0
src/packages/mobile/components/base/table/index.less

@@ -0,0 +1,15 @@
+.app-table {
+    overflow: auto;
+
+    &__body {
+        width           : 100%;
+        text-align      : center;
+        background-color: #fff;
+        margin-bottom   : .2rem;
+
+        th,
+        td {
+            padding: .1rem 0;
+        }
+    }
+}

+ 68 - 0
src/packages/mobile/components/base/table/index.vue

@@ -0,0 +1,68 @@
+<template>
+    <div class="app-table">
+        <table class="app-table__body">
+            <thead>
+                <Draggable :list="columns" tag="tr" item-key="key">
+                    <template #header v-if="$slots.expand">
+                        <th></th>
+                    </template>
+                    <template #item="{ element }">
+                        <th>{{ element.label }}</th>
+                    </template>
+                </Draggable>
+            </thead>
+            <tbody>
+                <template v-for="(row, i) in dataSource" :key="i">
+                    <tr class="app-table__row" @click="rowClick(i)">
+                        <td v-if="$slots.expand">
+                            <Icon name="arrow-down" v-if="selectedIndex === i" />
+                            <Icon name="arrow" v-else />
+                        </td>
+                        <td :class="column.className" v-for="(column, n) in columns" :key="i + n.toString()">
+                            <slot :name="column.key" :value="row[column.key]" :row="row">{{ row[column.key] }}</slot>
+                        </td>
+                    </tr>
+                    <!-- expand -->
+                    <tr class="app-table__row expand" v-show="selectedIndex === i" v-if="$slots.expand">
+                        <td :colspan="columns.length + 1">
+                            <slot name="expand" :row="row"></slot>
+                        </td>
+                    </tr>
+                </template>
+            </tbody>
+        </table>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { PropType, ref } from 'vue'
+import { Icon } from 'vant'
+import { TableColumn } from './interface'
+import Draggable from 'vuedraggable'
+
+defineProps({
+    // 数据列表
+    dataSource: {
+        type: Array,
+        default: () => ([]),
+    },
+    columns: {
+        type: Array as PropType<TableColumn[]>,
+        default: () => ([]),
+    },
+})
+
+const selectedIndex = ref(-1);
+
+const rowClick = (index: number) => {
+    if (selectedIndex.value === index) {
+        selectedIndex.value = -1;
+    } else {
+        selectedIndex.value = index;
+    }
+}
+</script>
+
+<style lang="less" scoped>
+@import './index.less';
+</style>

+ 8 - 0
src/packages/mobile/components/base/table/interface.ts

@@ -0,0 +1,8 @@
+export interface TableColumn {
+    key: string;
+    label: string;
+    className?: string;
+    align?: string;
+    width?: number;
+    sort?: number;
+}

+ 1 - 1
src/packages/mobile/main.ts

@@ -2,7 +2,7 @@ import { createApp } from 'vue'
 import App from './App.vue'
 import router from './router'
 import directives from '@/directives' // 自定义指令集
-import 'default-passive-events'
+//import 'default-passive-events'
 import '@/mock' // 模拟数据
 import '@/utils/h5plus' // 加载html5+
 import '@/utils/client' // 适配客户端屏幕

+ 29 - 19
src/packages/mobile/views/home/components/market/index.vue

@@ -5,24 +5,23 @@
       <Grid :column-num="3" style="margin-bottom: .2rem;">
         <GridItem icon="photo-o" text="商品" :to="{ name: 'order' }" v-for="index in 6" :key="index" />
       </Grid>
-      <table style="width: 100%;text-align: center;background-color: #fff;margin-bottom: .2rem;">
-        <tr>
-          <th style="padding: .1rem 0;">合约</th>
-          <th>最新</th>
-          <th>最高</th>
-          <th>最低</th>
-          <th>买量</th>
-          <th>卖量</th>
-        </tr>
-        <tr v-for="(item, index) in quoteList" :key="index">
-          <td style="padding: .1rem 0;">{{ item.goodscode }}</td>
-          <td :class="handlePriceColor(item.last, item.presettle)">{{ handleNoneValue(item.last) }}</td>
-          <td :class="handlePriceColor(item.highest, item.presettle)">{{ handleNoneValue(item.highest) }}</td>
-          <td :class="handlePriceColor(item.lowest, item.presettle)">{{ handleNoneValue(item.lowest) }}</td>
-          <td :class="handlePriceColor(item.bid, item.presettle)">{{ handleNoneValue(item.bidvolume) }}</td>
-          <td :class="handlePriceColor(item.ask, item.presettle)">{{ handleNoneValue(item.askvolume) }}</td>
-        </tr>
-      </table>
+      <AppTable :data-source="quoteList" :columns="columns">
+        <template #last="{ row }">
+          <span :class="handlePriceColor(row.last, row.presettle)">{{ handleNoneValue(row.last) }}</span>
+        </template>
+        <template #highest="{ row }">
+          <span :class="handlePriceColor(row.highest, row.presettle)">{{ handleNoneValue(row.highest) }}</span>
+        </template>
+        <template #lowest="{ row }">
+          <span :class="handlePriceColor(row.lowest, row.presettle)">{{ handleNoneValue(row.lowest) }}</span>
+        </template>
+        <template #bidvolume="{ row }">
+          <span :class="handlePriceColor(row.bid, row.presettle)">{{ handleNoneValue(row.bidvolume) }}</span>
+        </template>
+        <template #askvolume="{ row }">
+          <span :class="handlePriceColor(row.ask, row.presettle)">{{ handleNoneValue(row.askvolume) }}</span>
+        </template>
+      </AppTable>
       <Button @click="showAction = true" plain block>更换主题</Button>
     </div>
     <ActionSheet v-model:show="showAction" :actions="actions" teleport="body" cancel-text="取消" @select="onSelect" />
@@ -30,18 +29,29 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, onActivated, onDeactivated } from 'vue'
+import { ref, reactive, onActivated, onDeactivated } from 'vue'
 import { v4 } from 'uuid'
 import { Grid, GridItem, Button, ActionSheet, ActionSheetAction } from 'vant'
 import { addSubscribe, removeSubscribe } from '@/business/quote'
 import { globalState } from '@/store'
 import { handlePriceColor, handleNoneValue } from '@/filters'
 import theme from '@/hooks/theme'
+import AppTable from '@mobile/components/base/table/index.vue'
+import { TableColumn } from '@mobile/components/base/table/interface'
 
 const uuid = v4();
 const showAction = ref(false);
 const quoteList = globalState.getRef('quoteList');
 
+const columns = reactive<TableColumn[]>([
+  { key: 'goodscode', label: '合约' },
+  { key: 'last', label: '最新' },
+  { key: 'highest', label: '最高' },
+  { key: 'lowest', label: '最低' },
+  { key: 'bidvolume', label: '买量' },
+  { key: 'askvolume', label: '卖量' }
+])
+
 const actions: ActionSheetAction[] = [
   { name: '默认' },
   { name: '浅色' },

+ 2 - 2
src/packages/mobile/views/home/index.vue

@@ -46,8 +46,8 @@ const tabList: Tabbar[] = [
   }
 ]
 
-const onChange = (tab: Tabbar) => {
-  componentId.value = tab.component;
+const onChange = (index: number) => {
+  componentId.value = tabList[index].component;
 }
 </script>
 

+ 7 - 5
src/packages/pc/components/base/table/index.vue

@@ -1,13 +1,15 @@
 <template>
   <el-table class="app-table" border>
     <el-table-column type="expand" v-if="$slots.expand">
-      <template #default="{row}">
+      <template #default="{ row }">
         <slot name="expand" :row="row"></slot>
       </template>
     </el-table-column>
-    <el-table-column v-for="(item,index) in columns" :key="index" :filters="item.filters" :filter-method="item.filterMethod" :class-name="item.className" :label="item.label" :align="item.align ?? 'center'" :width="item.width">
-      <template #default="{row}">
-        <slot :name="item.key" :row="row">{{row[item.key]}}</slot>
+    <el-table-column v-for="(item, index) in columns" :key="index" :filters="item.filters"
+      :filter-method="item.filterMethod" :class-name="item.className" :label="item.label"
+      :align="item.align ?? 'center'" :width="item.width">
+      <template #default="{ row }">
+        <slot :name="item.key" :row="row">{{ row[item.key] }}</slot>
       </template>
     </el-table-column>
   </el-table>
@@ -20,7 +22,7 @@ import { TableColumn } from './interface'
 defineProps({
   columns: {
     type: Array as PropType<TableColumn[]>,
-    default: () => []
+    default: () => ([])
   }
 })
 </script>

+ 5 - 6
src/packages/pc/views/market/goods/index.vue

@@ -2,7 +2,7 @@
   <app-view class="futures-goods" @ready="onReady">
     <div>全局共享数据:{{ goodsList }}</div>
     <el-button @click="clearGoods">清空</el-button>
-    <app-tabbar theme="menu" :data-source="tabs" :data-index="1" @change="tabChange" />
+    <app-tab theme="menu" :data-source="tabs" :data-index="1" @change="tabChange" />
     <app-echarts-timeline style="height:70%;" v-if="activeCycleType === EChartsCycleType.time" />
     <app-echarts-kline :cycle-type="activeCycleType" style="height:70%;" v-else />
     <!-- <div ref="scrollEl" style="height:300px;overflow-y:auto;">
@@ -18,14 +18,13 @@ import { globalState } from '@/store';
 import { EChartsCycleType } from '@/constants/enum';
 import AppEchartsKline from '@/components/modules/echarts-kline/index.vue'
 import AppEchartsTimeline from '@/components/modules/echarts-timeline/index.vue'
-import AppTabbar from '@/components/base/tabbar/index.vue'
-import { Tabbar } from '@/components/base/tabbar/interface'
+import AppTab from '@/components/base/tab/index.vue'
 
 const scrollEl = ref<HTMLDivElement>();
 const activeCycleType = ref(EChartsCycleType.minutes); // 当前选中的图表周期
 const goodsList = globalState.getRef('goodsList');
 
-const tabs: Tabbar[] = [
+const tabs = [
   { label: '分时', value: EChartsCycleType.time },
   { label: '1分钟', value: EChartsCycleType.minutes },
   { label: '5分钟', value: EChartsCycleType.minutes5 },
@@ -36,8 +35,8 @@ const tabs: Tabbar[] = [
 ]
 
 // 指标切换
-const tabChange = (item: Tabbar<EChartsCycleType>) => {
-  activeCycleType.value = item.value;
+const tabChange = (index: number) => {
+  activeCycleType.value = tabs[index].value;
 }
 
 const clearGoods = () => {

+ 6 - 9
src/packages/pc/views/market/quote/components/detail/index.vue

@@ -1,14 +1,12 @@
 <!-- 详情 -->
 <template>
   <app-modal class="quote-detail" direction="bottom" :delay="delay" :fixed="false" :show="showDrawer" @mask="closed">
-    <app-tabbar>
-      <el-table class="app-table" :data="tableList" border>
-        <el-table-column prop="id" label="序号" />
-        <el-table-column prop="goodsCode" label="合约" />
-        <el-table-column prop="goodsName" label="商品" />
-        <el-table-column prop="lastPrice" label="最新价" />
-      </el-table>
-    </app-tabbar>
+    <el-table class="app-table" :data="tableList" border>
+      <el-table-column prop="id" label="序号" />
+      <el-table-column prop="goodsCode" label="合约" />
+      <el-table-column prop="goodsName" label="商品" />
+      <el-table-column prop="lastPrice" label="最新价" />
+    </el-table>
   </app-modal>
 </template>
 
@@ -16,7 +14,6 @@
 import { ref } from 'vue'
 import { queryGoodsList } from '@/services/api/goods'
 import AppModal from '@pc/components/base/modal/index.vue'
-import AppTabbar from '@/components/base/tabbar/index.vue'
 
 const emit = defineEmits(['closed'])