Quellcode durchsuchen

feat: 新增图表展示模式切换

奔跑的面条 vor 3 Jahren
Ursprung
Commit
18d976cf3c

+ 10 - 4
src/plugins/icon.ts

@@ -63,7 +63,8 @@ import {
   Images as ImagesIcon,
   List as ListIcon,
   EyeOutline as EyeOutlineIcon,
-  EyeOffOutline as EyeOffOutlineIcon
+  EyeOffOutline as EyeOffOutlineIcon,
+  Albums as AlbumsIcon
 } from '@vicons/ionicons5'
 
 import {
@@ -95,7 +96,8 @@ import {
   Carbon3DCursor as Carbon3DCursorIcon,
   Carbon3DSoftware as Carbon3DSoftwareIcon,
   Filter as FilterIcon,
-  FilterEdit as FilterEditIcon
+  FilterEdit as FilterEditIcon,
+  Laptop as LaptopIcon
 } from '@vicons/carbon'
 
 const ionicons5 = {
@@ -228,7 +230,9 @@ const ionicons5 = {
   ListIcon,
   // 眼睛
   EyeOutlineIcon,
-  EyeOffOutlineIcon
+  EyeOffOutlineIcon,
+  // 图表列表 
+  AlbumsIcon
 }
 
 const carbon = {
@@ -279,7 +283,9 @@ const carbon = {
   Carbon3DSoftwareIcon,
   // 过滤器
   FilterIcon,
-  FilterEditIcon
+  FilterEditIcon,
+  // 图层
+  LaptopIcon
 }
 
 // https://www.xicons.org/#/ 还有很多

+ 8 - 0
src/store/modules/chartLayoutStore/chartLayoutStore.d.ts

@@ -1,3 +1,8 @@
+export enum ChartModeEnum {
+  SINGLE= 'single',
+  DOUBLE = 'double'
+}
+
 export enum LayerModeEnum {
   THUMBNAIL = 'thumbnail',
   TEXT = 'text'
@@ -7,6 +12,7 @@ export enum ChartLayoutStoreEnum {
   LAYERS = 'layers',
   CHARTS = 'charts',
   DETAILS = 'details',
+  Chart_TYPE = 'chartType',
   LAYER_TYPE = 'layerType'
 }
 
@@ -17,6 +23,8 @@ export interface ChartLayoutType {
   [ChartLayoutStoreEnum.CHARTS]: boolean
   // 详情设置
   [ChartLayoutStoreEnum.DETAILS]: boolean
+  // 组件展示方式
+  [ChartLayoutStoreEnum.Chart_TYPE]: ChartModeEnum
   // 层级展示方式
   [ChartLayoutStoreEnum.LAYER_TYPE]: LayerModeEnum
 }

+ 6 - 1
src/store/modules/chartLayoutStore/chartLayoutStore.ts

@@ -1,5 +1,5 @@
 import { defineStore } from 'pinia'
-import { ChartLayoutType, LayerModeEnum } from './chartLayoutStore.d'
+import { ChartLayoutType, LayerModeEnum, ChartModeEnum } from './chartLayoutStore.d'
 import { setLocalStorage, getLocalStorage } from '@/utils'
 import { StorageEnum } from '@/enums/storageEnum'
 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
@@ -21,6 +21,8 @@ export const useChartLayoutStore = defineStore({
       charts: true,
       // 详情设置(收缩为true)
       details: false,
+      // 组件列表展示类型(默认单列)
+      chartType: ChartModeEnum.SINGLE,
       // 图层类型(默认图片)
       layerType: LayerModeEnum.THUMBNAIL
     },
@@ -34,6 +36,9 @@ export const useChartLayoutStore = defineStore({
     getDetails(): boolean {
       return this.details
     },
+    getChartType(): ChartModeEnum {
+      return this.chartType
+    },
     getLayerType(): LayerModeEnum {
       return this.layerType
     }

+ 61 - 7
src/views/chart/ContentCharts/components/ChartsItemBox/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="go-content-charts-item-box">
+  <div class="go-content-charts-item-box" :class="{ double: chartMode === ChartModeEnum.DOUBLE }">
     <!-- 每一项组件的渲染 -->
     <div
       class="item-box"
@@ -11,21 +11,30 @@
       @dblclick="dblclickHandle(item)"
     >
       <div class="list-header">
-        <mac-os-control-btn :mini="true" :disabled="true"></mac-os-control-btn>
-        <n-text class="list-header-text" depth="3">{{ item.title }}</n-text>
+        <mac-os-control-btn class="list-header-control-btn" :mini="true" :disabled="true"></mac-os-control-btn>
+        <n-text class="list-header-text" depth="3">
+          <n-ellipsis>{{ item.title }}</n-ellipsis>
+        </n-text>
       </div>
       <div class="list-center go-flex-center">
         <img class="list-img" v-lazy="item.image" alt="图表图片" />
       </div>
+      <div class="list-bottom">
+        <n-text class="list-bottom-text" depth="3">
+          <n-ellipsis style="max-width: 90%">{{ item.title }}</n-ellipsis>
+        </n-text>
+      </div>
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
-import { PropType } from 'vue'
+import { PropType, ref, Ref, computed } from 'vue'
 import { MacOsControlBtn } from '@/components/Tips/MacOsControlBtn/index'
 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
 import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
+import { ChartModeEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
+import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
 import { componentInstall, loadingStart, loadingFinish, loadingError } from '@/utils'
 import { DragKeyEnum } from '@/enums/editPageEnum'
 import { createComponent } from '@/packages'
@@ -41,6 +50,13 @@ defineProps({
   }
 })
 
+const chartLayoutStore = useChartLayoutStore()
+
+// 组件展示状态
+const chartMode: Ref<ChartModeEnum> = computed(() => {
+  return chartLayoutStore.getChartType
+})
+
 // 拖拽处理
 const dragStartHandle = (e: DragEvent, item: ConfigType) => {
   // 动态注册图表组件
@@ -80,13 +96,18 @@ const dblclickHandle = async (item: ConfigType) => {
 
 <style lang="scss" scoped>
 /* 列表项宽度 */
-$itemWidth: 86%;
+$itemWidth: 100%;
+$halfItemWidth: 46%;
 /* 内容高度 */
 $centerHeight: 100px;
+$halfCenterHeight: 50px;
 @include go('content-charts-item-box') {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 9px;
+  padding: 10px;
   .item-box {
-    margin: 0 7%;
-    margin-bottom: 15px;
+    margin: 0;
     width: $itemWidth;
     overflow: hidden;
     border-radius: 6px;
@@ -122,6 +143,39 @@ $centerHeight: 100px;
         @extend .go-transition;
       }
     }
+    .list-bottom {
+      display: none;
+      .list-bottom-text {
+        font-size: 12px;
+        padding-left: 5px;
+      }
+    }
+  }
+  /* 缩小展示 */
+  &.double {
+    .list-header {
+      padding: 2px 5px;
+      .list-header-text {
+        display: none;
+      }
+      .list-header-control-btn {
+        transform: scale(0.7);
+      }
+    }
+    .item-box {
+      width: $halfItemWidth;
+    }
+    .list-center {
+      height: $halfCenterHeight;
+      padding-bottom: 0px;
+      .list-img {
+        height: $halfCenterHeight;
+        width: auto;
+      }
+    }
+    .list-bottom {
+      display: block;
+    }
   }
 }
 </style>

+ 0 - 1
src/views/chart/ContentCharts/components/ChartsOptionContent/index.vue

@@ -123,7 +123,6 @@ $menuWidth: 65px;
     display: flex;
     flex-direction: column;
     align-items: center;
-    padding: 10px 0;
   }
   @include deep() {
     .n-menu-item {

+ 158 - 103
src/views/chart/ContentCharts/components/ChartsSearch/index.vue

@@ -1,82 +1,104 @@
 <template>
-  <div class="go-chart-search">
-    <n-popover
-      class="chart-search-popover"
-      :show-arrow="false"
-      :show="showPopover"
-      :to="false"
-      trigger="hover"
-      placement="bottom-start"
-    >
-      <template #trigger>
-        <n-input-group>
-          <n-input
-            v-model:value.trim="search"
-            size="small"
-            :loading="loading"
-            placeholder="请输入组件名称"
-            @update:value="searchHandle"
-          >
-            <template #suffix>
-              <n-icon v-show="!loading" :component="SearchIcon" />
-            </template>
-          </n-input>
-        </n-input-group>
-      </template>
-
-      <div class="search-list-box">
-        <n-scrollbar style="max-height: 500px">
-          <n-empty
-            v-show="!searchRes.length"
-            size="small"
-            description="没有找到组件~"
-          ></n-empty>
-          <div
-            class="list-item go-flex-items-center go-ellipsis-1"
-            v-for="item in searchRes"
-            :key="item.key"
-            :title="item.title"
-            @click="selectChartHandle(item)"
-          >
-            <img class="list-item-img" v-lazy="item.image" alt="展示图" />
-            <n-text class="list-item-fs" depth="2">{{ item.title }}</n-text>
-          </div>
-        </n-scrollbar>
-        <div class="popover-modal"></div>
-      </div>
-    </n-popover>
+  <div class="go-chart-search-box">
+    <div class="chart-search go-transition" :class="{ 'chart-search-focus': isFocus }">
+      <n-popover
+        class="chart-search-popover"
+        :show-arrow="false"
+        :show="showPopover"
+        :to="false"
+        trigger="hover"
+        placement="bottom-start"
+      >
+        <template #trigger>
+          <n-input-group>
+            <n-input
+              size="small"
+              placeholder="搜索组件"
+              v-model:value.trim="search"
+              :loading="loading"
+              @focus="focusHandle(true)"
+              @blur="focusHandle(false)"
+              @update:value="searchHandle"
+            >
+              <template #suffix>
+                <n-icon v-show="!loading" :component="SearchIcon" />
+              </template>
+            </n-input>
+          </n-input-group>
+        </template>
+
+        <div class="search-list-box">
+          <n-scrollbar style="max-height: 500px">
+            <n-empty v-show="!searchRes.length" size="small" description="没有找到组件~"></n-empty>
+            <div
+              class="list-item go-flex-items-center go-ellipsis-1"
+              v-for="item in searchRes"
+              :key="item.key"
+              :title="item.title"
+              @click="selectChartHandle(item)"
+            >
+              <img class="list-item-img" v-lazy="item.image" alt="展示图" />
+              <n-text class="list-item-fs" depth="2">{{ item.title }}</n-text>
+            </div>
+          </n-scrollbar>
+          <div class="popover-modal"></div>
+        </div>
+      </n-popover>
+    </div>
+    <n-button-group class="btn-group go-transition" :class="{ 'btn-group-focus': isFocus }" style="display: flex">
+      <n-button
+        ghost
+        size="small"
+        :key="index"
+        :type="chartMode === item.value ? 'primary' : 'tertiary'"
+        v-for="(item, index) in chartModeList"
+        @click="changeChartModeType(item.value)"
+      >
+        <n-tooltip :show-arrow="false" trigger="hover">
+          <template #trigger>
+            <n-icon size="14" :component="item.icon" />
+          </template>
+          {{ item.label }}
+        </n-tooltip>
+      </n-button>
+    </n-button-group>
   </div>
 </template>
 
 <script setup lang="ts">
 import { ref, onUnmounted } from 'vue'
 import { icon } from '@/plugins'
+import { createComponent } from '@/packages'
+import { ConfigType, CreateComponentType } from '@/packages/index.d'
 import { themeColor, MenuOptionsType } from '../../hooks/useAside.hook'
 import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
-import { ConfigType, CreateComponentType } from '@/packages/index.d'
-import { createComponent } from '@/packages'
+import { ChartModeEnum, ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
+import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
 import { isString, addEventListener, removeEventListener } from '@/utils'
 import { fetchConfigComponent, fetchChartComponent } from '@/packages/index'
-import {
-  componentInstall,
-  loadingStart,
-  loadingFinish,
-  loadingError,
-} from '@/utils'
+import { componentInstall, loadingStart, loadingFinish, loadingError } from '@/utils'
 
 const props = defineProps({
   menuOptions: {
     type: Array,
-    default: () => [],
-  },
+    default: () => []
+  }
 })
 
-const { SearchIcon } = icon.ionicons5
 const chartEditStore = useChartEditStore()
+const chartLayoutStore = useChartLayoutStore()
+const { SearchIcon, AlbumsIcon, GridIcon } = icon.ionicons5
+const isFocus = ref<boolean>(false)
 const showPopover = ref<boolean>(false)
 const loading = ref<boolean | undefined>(undefined)
 const search = ref<string | null>(null)
 const searchRes = ref<ConfigType[]>([])
+const chartMode = ref<ChartModeEnum>(chartLayoutStore.getChartType)
+
+const chartModeList = [
+  { label: '单列', icon: AlbumsIcon, value: ChartModeEnum.SINGLE },
+  { label: '双列', icon: GridIcon, value: ChartModeEnum.DOUBLE }
+]
 
 // 组件数组提取
 const listFormatHandle = (options: any[]) => {
@@ -106,9 +128,7 @@ const searchHandle = (key: string | null) => {
   }
   loading.value = true
   showPopover.value = true
-  searchRes.value = List.filter(
-    (e: ConfigType) => !key || e.title.toLowerCase().includes(key.toLowerCase())
-  )
+  searchRes.value = List.filter((e: ConfigType) => !key || e.title.toLowerCase().includes(key.toLowerCase()))
   setTimeout(() => {
     loading.value = undefined
   }, 500)
@@ -145,6 +165,17 @@ const selectChartHandle = async (item: ConfigType) => {
   }
 }
 
+// 聚焦设置
+const focusHandle = (value: boolean) => {
+  isFocus.value = value
+}
+
+// 修改图表展示方式
+const changeChartModeType = (value: ChartModeEnum) => {
+  chartMode.value = value
+  chartLayoutStore.setItem(ChartLayoutStoreEnum.Chart_TYPE, value)
+}
+
 addEventListener(document, 'click', (e: Event) => {
   listenerCloseHandle(e)
 })
@@ -155,54 +186,78 @@ onUnmounted(() => {
 </script>
 
 <style lang="scss" scoped>
-$width: 178px;
-@include go('chart-search') {
-  width: $width;
-  margin-right: -12px;
-  .chart-search-popover {
-    .search-list-box {
-      width: calc(#{$width} - 30px);
-      .list-item {
-        z-index: 2;
-        position: relative;
-        cursor: pointer;
-        padding: 2px;
-        padding-left: 6px;
-        margin-bottom: 5px;
-        &-fs {
-          font-size: 12px;
-        }
-        &-img {
-          height: 28px;
-          margin-right: 5px;
-          border-radius: 5px;
-        }
-        &:hover {
-          &::before {
-            content: '';
-            position: absolute;
-            width: 3px;
-            height: 100%;
-            left: 0;
-            top: 0;
-            border-radius: 2px;
-            background-color: v-bind('themeColor');
+$width: 98px;
+$searchWidth: 176px;
+
+@include go('chart-search-box') {
+  display: flex;
+  .chart-search {
+    width: $width;
+    margin-right: 10px;
+    &.chart-search-focus {
+      width: $searchWidth;
+      &.chart-search {
+        margin-right: 0;
+      }
+    }
+    @include deep() {
+      .chart-search-popover {
+        padding-left: 5px;
+        padding-right: 8px;
+      }
+    }
+    .chart-search-popover {
+      .search-list-box {
+        width: 163px;
+        .list-item {
+          z-index: 2;
+          position: relative;
+          cursor: pointer;
+          padding: 2px;
+          padding-left: 6px;
+          margin-bottom: 5px;
+          &-fs {
+            font-size: 12px;
           }
-          &::after {
-            z-index: -1;
-            content: '';
-            position: absolute;
-            width: 100%;
-            height: 100%;
-            opacity: 0.1;
-            left: 0;
-            top: 0;
+          &-img {
+            height: 28px;
+            margin-right: 5px;
             border-radius: 5px;
-            background-color: v-bind('themeColor');
+          }
+          &:hover {
+            &::before {
+              content: '';
+              position: absolute;
+              width: 3px;
+              height: 100%;
+              left: 0;
+              top: 0;
+              border-radius: 2px;
+              background-color: v-bind('themeColor');
+            }
+            &::after {
+              z-index: -1;
+              content: '';
+              position: absolute;
+              width: 100%;
+              height: 100%;
+              opacity: 0.1;
+              left: 0;
+              top: 0;
+              border-radius: 5px;
+              background-color: v-bind('themeColor');
+            }
           }
         }
       }
     }
   }
+  .btn-group {
+    width: 68px;
+    overflow: hidden;
+    &.btn-group-focus {
+      width: 0px;
+    }
+  }
 }
-</style>
+</style>

+ 2 - 1
src/views/chart/ContentLayers/index.vue

@@ -81,12 +81,13 @@ import { LayersGroupListItem } from './components/LayersGroupListItem/index'
 import { icon } from '@/plugins'
 
 const { LayersIcon, GridIcon, ListIcon } = icon.ionicons5
+const { LaptopIcon } = icon.carbon
 const chartLayoutStore = useChartLayoutStore()
 const chartEditStore = useChartEditStore()
 const { handleContextMenu, onClickOutSide } = useContextMenu()
 
 const layerModeList = [
-  { label: '缩略图', icon: GridIcon, value: LayerModeEnum.THUMBNAIL },
+  { label: '缩略图', icon: LaptopIcon, value: LayerModeEnum.THUMBNAIL },
   { label: '文本列表', icon: ListIcon, value: LayerModeEnum.TEXT }
 ]