Ver Fonte

fix: BsUi-Tabs的封装

hanxiaohui há 7 meses atrás
pai
commit
aa4c8e7e1f

+ 1 - 1
src/components/BsUi/ContentsWrapper/index.vue

@@ -8,6 +8,6 @@
 .content-wrap {
   display: flex;
   flex-direction: column;
-  gap: 10px;
+  gap: 15px;
 }
 </style>

+ 80 - 19
src/components/BsUi/Descriptions/index.vue

@@ -1,26 +1,40 @@
 <template>
   <div class="description">
-    <div class="d-title">{{ title }}</div>
-    <slot></slot>  
-    <a-descriptions v-if="!isEmpty(items)" :bordered="false">
-      <a-descriptions-item v-for="(item, index) in items" :key="index" v-bind="item.extraProps">
-        <template #label>
-          <slot v-if="item.labelSlot" :name="item.labelSlot"></slot>
-          <span v-else>{{ item.label }}</span>
-        </template>
+    <div class="d-title" @click="handleClkHeader">
+      <span>{{ title }}</span>
+      <div>
+        <DownOutlined style="font-size:12px; color: #979797" v-if="foldState" />
+        <UpOutlined style="font-size:12px; color: #979797" size="10px" v-if="!foldState" />
+      </div>
+    </div>
 
-        <template v-if="item.valueSlot">
-          <slot :name="item.valueSlot"></slot>
-        </template>
-        <template v-if="!item.valueSlot">
-          {{ item.value }}
-        </template>
-      </a-descriptions-item>
-    </a-descriptions>
+    <div v-show="foldState">
+      <div class="default_slot" v-if="slots.default">
+        <slot></slot>
+      </div>
+      <a-descriptions v-if="!isEmpty(items)" :bordered="false">
+        <a-descriptions-item v-for="(item, index) in items" :key="index" v-bind="item.extraProps">
+          <template #label>
+            <slot v-if="item.labelSlot" :name="item.labelSlot"></slot>
+            <span v-else class="dsc-label">{{ item.label }}</span>
+          </template>
+
+          <template v-if="item.valueSlot">
+            <slot :name="item.valueSlot"></slot>
+          </template>
+          <template v-if="!item.valueSlot">
+            <div class="dsc-value">
+              {{ item.value }}
+            </div>
+          </template>
+        </a-descriptions-item>
+      </a-descriptions>
+    </div>
   </div>
 </template>
 <script setup>
   import { isEmpty } from 'lodash';
+  import {ref, useSlots} from 'vue';
 
   const props = defineProps({
     title: {
@@ -31,7 +45,21 @@
       required: false,
       default: [],
     },
+    isFolded: {
+      required: false,
+      default: false,
+    },
   });
+
+  const foldState = ref(true);
+
+  const emits = defineEmits(['update:isFolded']);
+
+  const slots = useSlots();
+
+  const handleClkHeader = () => {
+    foldState.value = !foldState.value;
+  };
 </script>
 <style lang="scss" scoped>
   .description {
@@ -39,14 +67,47 @@
     .d-title {
       font-size: 16px;
       font-weight: 600;
-      padding: 0 0 10px 0;
+      padding: 10px 0 10px 10px;
+      border-bottom: 1px solid #e4e7ed;
+      cursor: pointer;
+      position: relative;
+      display: flex;
+      align-items: center;
+      gap: 10px;
+      &:hover {
+        background: rgba(#000, .1);
+        border-radius: 8px;
+      }
+      &::before {
+        width: 4px;
+        height: 18px;
+        background: var(--webchat-toolbar-background-color);
+        position: absolute;
+        left: 0;
+        top: 50%;
+        transform: translateY(-50%);
+        content: '';
+        border-radius: 4px;
+      }
+    }
+    .dsc-label {
+      font-size: 14px;
+      color: #6c6c6c;
+    }
+    .dsc-value {
+      font-size: 14px;
+      color: #000;
+      font-weight: 500;
     }
     :deep(.ant-descriptions-header) {
       margin: 0 0 10px 0;
     }
     :deep(.ant-descriptions-item) {
-      margin: 0 0 10px 0;
-      padding: 0;
+      margin: 0;
+      padding: 10px 0 0 0;
+    }
+    .default_slot {
+      padding: 10px 0;
     }
   }
 </style>

+ 58 - 0
src/components/BsUi/Tabs/index.vue

@@ -0,0 +1,58 @@
+<template>
+  <a-tabs v-model:activeKey="activeKey">
+    <a-tab-pane :key="tab.key" v-for="tab in tabs">
+      <template #tab>
+        <div class="tab-title">
+          <span>
+            <img :src="tab.key === activeKey ? tab.selectedIcon : tab.unSelectedIcon" alt="" />
+          </span>
+
+          <span class="tab-title-t">{{ tab.title }}</span>
+        </div>
+      </template>
+      <div class="tabs-content">
+        <slot :name="tab.slotName" v-if="tab.key === activeKey"></slot>
+      </div>
+    </a-tab-pane>
+  </a-tabs>
+</template>
+<script setup>
+import { ref, watch } from 'vue';
+import { isEmpty } from 'lodash';
+const emits = defineEmits(['update:tabActiveKey', 'change']);
+const props = defineProps({
+  tabs: {
+    required: true,
+    default: [],
+  },
+  tabActiveKey: {
+    required: false,
+    default: '',
+  },
+});
+
+const activeKey = ref(isEmpty(props.tabActiveKey) ? props.tabs[0].key : props.tabActiveKey);
+
+watch(
+    activeKey,
+    (val) => {
+      emits('change', val);
+    },
+    { immediate: true }
+);
+</script>
+
+<style lang="scss" scoped>
+.tab-title {
+  display: flex;
+  align-items: center;
+  gap: 5px;
+  .tab-title-t {
+    font-size: 16px;
+    font-weight: 400;
+  }
+}
+.tabs-content {
+  padding: 0 20px 10px 20px;
+}
+</style>

+ 4 - 1
src/components/BsUi/index.js

@@ -9,6 +9,7 @@ import BsForm, { useBsForm } from './Form/index.js';
 import BsModalTableSelector from './ModalTableSelector/index.vue';
 import BsDescriptions from "./Descriptions/index.vue"
 import BsContentsWrapper from "./ContentsWrapper/index.vue"
+import BsTabs from "./Tabs/index.vue"
 
 const BsUi = {
   install(app) {
@@ -21,6 +22,7 @@ const BsUi = {
     app.component('BsModalTableSelector', BsModalTableSelector);
     app.component('BsDescriptions', BsDescriptions)
     app.component('BsContentsWrapper', BsContentsWrapper)
+    app.component('BsTabs', BsTabs)
   },
 };
 
@@ -41,5 +43,6 @@ export {
   BsForm,
   useBsForm,
   BsDescriptions,
-  BsContentsWrapper
+  BsContentsWrapper,
+  BsTabs
 };