فهرست منبع

feat:添加tab组件

liu.shiyi 1 سال پیش
والد
کامیت
217be05b7d

+ 152 - 0
data-room-ui/packages/BasicComponents/ChartTab/index.vue

@@ -0,0 +1,152 @@
+<template>
+  <div
+    class="bs-design-wrap"
+    :class="`bs-chart-tab-${customTheme}`"
+  >
+    <div
+      v-if="config.customize.tabList.length"
+      class="tab-title-box"
+    >
+      <div
+        v-for="(tab,index) in config.customize.tabList"
+        :key="index"
+        class="tab-title-item"
+        :style="
+          'font-size:' +
+            config.customize.fontSize +
+            'px;color:' +
+            config.customize.color +
+            ';font-weight:' +
+            config.customize.fontWeight
+        "
+        @click="changeTab(index)"
+      >
+        {{ tab.name }}
+      </div>
+    </div>
+    <div
+      v-if="config.customize.tabList &&config.customize.tabList.length"
+      class="chart-item-box"
+    >
+      <Configuration
+        :config="config.customize.tabList[currentIndex].chart"
+        @openRightPanel="openRightPanel"
+      >
+        <RenderCardInner
+          :ref="'RenderCard' + config.customize.tabList[currentIndex].chartCode"
+          :config="config.customize.tabList[currentIndex].chart"
+          @click.native="currentChartHandler"
+        />
+      </Configuration>
+    </div>
+    <el-empty
+      v-else-if="!config.customize.tabList.length"
+      description="请在右侧面板选择图表加入"
+    />
+  </div>
+</template>
+
+<script>
+import paramsMixins from 'data-room-ui/js/mixins/paramsMixins'
+import { settingToTheme } from 'data-room-ui/js/utils/themeFormatting'
+import cloneDeep from 'lodash/cloneDeep'
+import { mapMutations, mapState } from 'vuex'
+import RenderCardInner from 'data-room-ui/Render/RenderCard2.vue'
+// import RenderCardInner from 'data-room-ui/Render/RenderCard2.vue'
+import Configuration from 'data-room-ui/Render/Configuration.vue'
+import { EventBus } from 'data-room-ui/js/utils/eventBus'
+export default {
+  name: 'ChartTab',
+  components: { Configuration, RenderCardInner },
+  mixins: [paramsMixins],
+  props: {
+    config: {
+      type: Object,
+      default: () => ({})
+    }
+  },
+  computed: {
+    ...mapState({
+      pageCode: state => state.bigScreen.pageInfo.code,
+      customTheme: state => state.bigScreen.pageInfo.pageConfig.customTheme,
+      activeCode: state => state.bigScreen.activeCode,
+      chartList: (state) => state.bigScreen.pageInfo.chartList
+    })
+    // currentChart () {
+    //   if (this.config.customize.tabList && this.config.customize.tabList.length) {
+    //     return { ...this.config.customize.tabList[this.currentIndex].chart, key: new Date().getTime() }
+    //   } else {
+    //     return null
+    //   }
+    // }
+  },
+  data () {
+    return {
+      // currentChart: null
+      currentIndex: 0
+    }
+  },
+  mounted () {
+  },
+  // 销毁定时器
+  destroyed () {
+    if (this.timer) {
+      clearInterval(this.timer) // 关闭
+    }
+  },
+  methods: {
+    ...mapMutations({
+      changeChartConfig: 'bigScreen/changeChartConfig',
+      changeActiveItemConfig: 'bigScreen/changeActiveItemConfig',
+      changeActiveCode: 'bigScreen/changeActiveCode'
+    }),
+    changeStyle (config) {
+      config = { ...this.config, ...config }
+      // 样式改变时更新主题配置
+      config.theme = settingToTheme(cloneDeep(config), this.customTheme)
+      this.changeChartConfig(config)
+      if (config.code === this.activeCode) {
+        this.changeActiveItemConfig(config)
+      }
+    },
+    // 切换tab页
+    changeTab (index) {
+      this.currentIndex = index
+      // this.currentChart = this.config.customize.tabList[index]?.chart
+      // this.changeActiveItemConfig(this.currentChart)
+      // this.currentChart.key = new Date().getTime()
+    },
+    // 点击Tab中的某个组件
+    currentChartHandler () {
+      this.changeActiveCode(this.config.customize.tabList[this.currentIndex]?.chartCode)
+      this.changeActiveItemConfig(this.config.customize.tabList[this.currentIndex]?.chart)
+      console.log()
+    },
+    // 打开右侧面板
+    openRightPanel () {
+      // EventBus.$emit('openRightPanel', this.currentChart)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.bs-design-wrap{
+  width: 100%;
+  .tab-title-box{
+    height: 40px;
+    display: flex;
+    border-bottom: 1px solid  var(--bs-el-background-2);
+    &:hover{
+      cursor: pointer;
+    }
+    .tab-title-item{
+      padding:10px;
+    }
+  }
+  .chart-item-box{
+    width: 100%;
+    height: calc(100% - 40px);
+  }
+}
+</style>

+ 236 - 0
data-room-ui/packages/BasicComponents/ChartTab/setting.vue

@@ -0,0 +1,236 @@
+<template>
+  <div>
+    <el-form
+      ref="form"
+      :model="config"
+      label-width="120px"
+      label-position="left"
+      class="setting-body bs-el-form"
+    >
+      <SettingTitle>基础</SettingTitle>
+      <el-form-item
+        class="lc-field-body"
+        label="名称"
+      >
+        <el-input
+          v-model="config.title"
+          clearable
+        />
+      </el-form-item>
+      <SettingTitle>位置</SettingTitle>
+      <div class="lc-field-body">
+        <PosWhSetting
+          :config="config"
+          label-width="120px"
+        />
+      </div>
+      <SettingTitle>基础</SettingTitle>
+      <div class="lc-field-body">
+        <div class="select-item select-item-title">
+          <span class="option-drag" />
+          <span class="input-wrap_left">标签页名称</span>
+          <span class="input-wrap_left">图表类型</span>
+        </div>
+        <draggable
+          :list="config.customize.tabList"
+          :animation="340"
+          group="selectItem"
+          handle=".option-drag"
+          style="padding: 10px"
+        >
+          <template>
+            <div
+              v-for="(tab, index) in config.customize.tabList"
+              :key="index"
+              class="select-item"
+            >
+              <div class="select-line-icon option-drag">
+                <i class="el-icon-rank" />
+              </div>
+              <div class="input-wrap">
+                <el-form-item
+                  :prop="'customize.tabList.' + index + '.name'"
+                  :rules="rules.name"
+                  label-width="0px"
+                >
+                  <el-input
+                    v-model="tab.name"
+                    placeholder="请输入标签页标题"
+                    size="mini"
+                  />
+                </el-form-item>
+              </div>
+              <div class="input-wrap">
+                <el-form-item
+                  :prop="'customize.tabList.' + index + '.chart'"
+                  :rules="rules.chart"
+                  label-width="0px"
+                >
+                  <el-select
+                    v-model="tab.chart.title"
+                    size="mini"
+                    @change="handleChangeBindCompnents(...arguments, index)"
+                  >
+                    <el-option
+                      v-for="item in componentList"
+                      :key="item.title"
+                      :label="item.title"
+                      :value="item.title"
+                    />
+                  </el-select>
+                </el-form-item>
+              </div>
+              <div
+                class="select-line-icon option-add"
+                @click="addTab(index)"
+              >
+                <i class="el-icon-circle-plus-outline" />
+              </div>
+              <div
+                class="select-line-icon option-delete"
+                @click="deleteTab(index)"
+              >
+                <i class="el-icon-remove-outline" />
+              </div>
+            </div>
+          </template>
+        </draggable>
+        <el-button
+          type="primary"
+          @click="addTab"
+        >
+          新增标签页
+        </el-button>
+      </div>
+    </el-form>
+  </div>
+</template>
+<script>
+import draggable from 'vuedraggable'
+import SettingTitle from 'data-room-ui/SettingTitle/index.vue'
+import { chartSettingMixins } from 'data-room-ui/js/mixins/chartSettingMixins'
+import PosWhSetting from 'data-room-ui/BigScreenDesign/RightSetting/PosWhSetting.vue'
+import CloneDeep from 'lodash-es/cloneDeep'
+import plotList from 'data-room-ui/G2Plots/plotList'
+import { randomString } from 'data-room-ui/js/utils'
+import { settingToTheme } from 'data-room-ui/js/utils/themeFormatting'
+export default {
+  components: {
+    PosWhSetting,
+    SettingTitle,
+    draggable
+  },
+  mixins: [chartSettingMixins],
+  data () {
+    const validateChart = (rule, value, callback) => {
+      if (!value) {
+        return callback(new Error('请选择图表'))
+      }
+      callback()
+    }
+    return {
+      rules: {
+        name: [
+          {
+            required: true,
+            message: '请输入标签页标题',
+            trigger: 'blur'
+          }
+        ],
+        chart: [
+          { required: true, trigger: 'change', validator: validateChart }
+        ]
+      }
+    }
+  },
+  computed: {
+    config: {
+      get () {
+        return this.$store.state.bigScreen.activeItemConfig
+      },
+      set (val) {
+        this.$store.state.bigScreen.activeItemConfig = val
+      }
+    },
+    pageCode () {
+      return this.$route.query.code
+    },
+    componentList () {
+      return [...plotList]
+    }
+  },
+  watch: {},
+  mounted () { },
+  methods: {
+    deleteTab (index) {
+      this.config.customize.tabList.splice(index, 1)
+    },
+    addTab () {
+      const newTab = {
+        code: '',
+        chartCode: new Date().getTime() + '',
+        name: '',
+        chart: { parentCode: this.config.code }
+      }
+      this.config.customize.tabList.push(newTab)
+    },
+    handleChangeBindCompnents (configName, index) {
+      const config = this.componentList.find(
+        item => item.title === configName
+      )
+      config.code = randomString(12)
+      this.$set(this.config.customize.tabList[index], 'name', configName)
+      this.$set(this.config.customize.tabList[index], 'chart', { ...config, parentCode: this.config.code })
+      this.$set(this.config.customize.tabList[index], 'chartCode', config.code)
+      this.$set(this.config.customize.tabList[index].chart, 'key', settingToTheme(config, config.code))
+      this.$set(this.config.customize.tabList[index].chart, 'theme', settingToTheme(config, 'dark'))
+      this.$set(this.config.customize.tabList[index].chart, 'theme', settingToTheme(config, 'light'))
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "../../assets/style/settingWrap.scss";
+.lc-field-body {
+  padding: 12px 16px;
+}
+.select-item {
+  display: flex;
+  margin-bottom: 8px;
+
+  .option-drag {
+    cursor: move !important;
+    width: 30px;
+    font-size: 24px;
+  }
+  .input-wrap {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-right: 2px;
+
+    .el-input-number--mini {
+      width: 90px !important;
+    }
+  }
+  .input-wrap_left {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: left;
+  }
+
+  .select-line-icon {
+    width: 30px;
+    font-size: 18px;
+    cursor: pointer;
+    text-align: center;
+  }
+
+  .option-delete {
+    color: #f56c6c;
+  }
+}
+</style>

+ 30 - 0
data-room-ui/packages/BasicComponents/ChartTab/settingConfig.js

@@ -0,0 +1,30 @@
+import { commonConfig } from '../../js/config'
+
+export const settingConfig = {
+  time: '',
+  theme: 'dark',
+  // 设置面板属性的显隐
+  displayOption: {
+    dataAllocation: {
+      // 是否存在数据配置
+      enable: false
+    }
+  }
+}
+const customConfig = {
+
+  type: 'chartTab',
+  root: {
+    version: '2023071001'
+  },
+  customize: {
+    tabList: [],
+    fontSize: 14,
+    fontWeight: 700,
+    color: 'rgb(155 159 172)'
+  }
+
+}
+export const dataConfig = {
+  ...commonConfig(customConfig)
+}

+ 135 - 0
data-room-ui/packages/BasicComponents/ThemeSelect/index.vue

@@ -0,0 +1,135 @@
+<template>
+  <div
+    class="bs-design-wrap theme-switcher-wrap"
+    :class="`bs-theme-switcher-${customTheme}`"
+  >
+    <el-dropdown
+      trigger="click"
+      @command="handleChange"
+    >
+      <div
+        class="el-dropdown-link content-box"
+        :style="{'font-size': config.customize.fontSize +'px','font-weight': +config.customize.fontWeight,'background-image': `-webkit-linear-gradient(${config.customize.color})`}"
+      >
+        暗黑主题
+      </div>
+      <el-dropdown-menu
+        slot="dropdown"
+        class="theme-dropdown-menu"
+      >
+        <el-dropdown-item command="light">
+          明亮主题
+        </el-dropdown-item>
+        <el-dropdown-item command="dark">
+          暗黑主题
+        </el-dropdown-item>
+      </el-dropdown-menu>
+    </el-dropdown>
+  </div>
+</template>
+<script>
+import paramsMixins from 'data-room-ui/js/mixins/paramsMixins'
+import { themeToSetting } from 'data-room-ui/js/utils/themeFormatting'
+import { mapMutations, mapState } from 'vuex'
+import { refreshComponentMixin } from 'data-room-ui/js/mixins/refreshComponent'
+
+export default {
+  name: 'ThemeSwitcher',
+  components: {},
+  mixins: [paramsMixins, refreshComponentMixin],
+  props: {
+    // 卡片的属性
+    config: {
+      type: Object,
+      default: () => ({})
+    }
+  },
+  computed: {
+    ...mapState({
+      pageInfo: (state) => state.bigScreen.pageInfo
+    }),
+    isPreview () {
+      return (this.$route.path === window?.BS_CONFIG?.routers?.previewUrl) || (this.$route.path === '/big-screen/preview')
+    }
+  },
+  data () {
+    return {
+    }
+  },
+  watch: {
+  },
+  mounted () {
+    document.documentElement.style.setProperty('--radio-label-color', this.config.customize.activeColor)
+  },
+  methods: {
+    ...mapMutations({
+      changePageInfo: 'bigScreen/changePageInfo'
+    }),
+    // 点击切换主题
+    handleChange (val) {
+      const pageInfo = this.pageInfo
+      this.pageInfo.pageConfig.customTheme = val
+      pageInfo.chartList = themeToSetting(pageInfo.chartList, val)
+      this.changePageInfo(pageInfo)
+      pageInfo.chartList.forEach(chart => {
+        if (chart.type === 'remoteComponent') {
+          this.$emit('styleHandler', chart)
+        }
+      })
+      if (!this.isPreview) {
+        const themeLabel = val === 'light' ? '明亮' : '暗黑'
+        const htmlStr = `<span>当前已切换为<strong>${themeLabel}</strong>主题,涉及到颜色的配置仅针对当前主题生效</span>`
+        this.$notify({
+          title: '注意',
+          dangerouslyUseHTMLString: true,
+          message: htmlStr,
+          customClass: 'ds-el-notify',
+          duration: 5000,
+          type: 'warning'
+        })
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.bs-design-wrap{
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.content-box{
+  text-align: center;
+  /* 将背景设为渐变 */
+  /*background-image: -webkit-linear-gradient(left, #6294F7, #C85D14);*/
+  /* 规定背景绘制区域 */
+  -webkit-background-clip: text;
+  /* 将文字隐藏 */
+  -webkit-text-fill-color: transparent;
+}
+// 自定义dropdown的样式
+.theme-dropdown-menu{
+  //background-color: var(--bs-background-2)!important;
+  //border: 1px solid var(--bs-border-1);
+  /deep/ .el-dropdown-menu__item{
+    //background-color: var(--bs-background-2)!important;
+    &:hover {
+      //color: var(--bs-el-color-primary) !important;
+      //background-color: var(--bs-el-background-3) !important;
+    }
+  }
+
+}
+::v-deep .el-input__inner,
+::v-deep .el-color-picker__color-inner,
+::v-deep .el-input-number--mini,
+::v-deep .el-textarea__inner,
+::v-deep .el-input-group__append {
+  //background: var(--bs-el-background-1);
+  //color: var(--bs-el-text);
+  //border: 0 !important;
+  //width: 100px;
+}
+</style>

+ 107 - 0
data-room-ui/packages/BasicComponents/ThemeSelect/setting.vue

@@ -0,0 +1,107 @@
+
+<template>
+  <div class="bs-setting-wrap">
+    <el-form
+      ref="form"
+      label-width="100px"
+      label-position="left"
+      :model="config"
+      :rules="rules"
+      class="bs-el-form"
+    >
+      <SettingTitle>标题</SettingTitle>
+      <div class="bs-setting-wrap">
+        <el-form-item
+          label="标题"
+          label-width="100px"
+          prop="title"
+        >
+          <el-input
+            v-model="config.customize.title"
+            placeholder="请输入标题"
+            clearable
+          />
+        </el-form-item>
+      </div>
+      <SettingTitle>位置</SettingTitle>
+      <div class="lc-field-body">
+        <PosWhSetting :config="config" />
+      </div>
+      <SettingTitle>基础</SettingTitle>
+      <div class="lc-field-body">
+        <el-form-item
+          label="标题字体大小"
+          label-width="100px"
+        >
+          <el-input
+            v-model="config.customize.fontSize"
+            placeholder="请输入标题字体大小"
+            clearable
+          >
+            <template slot="append">
+              px
+            </template>
+          </el-input>
+        </el-form-item>
+        <el-form-item
+          label="标题字体权重"
+          label-width="100px"
+        >
+          <el-input-number
+            v-model="config.customize.fontWeight"
+            class="bs-el-input-number"
+            placeholder="请输入标题字体权重"
+          />
+        </el-form-item>
+        <TextGradient v-model="config.customize.color" />
+      </div>
+    </el-form>
+  </div>
+</template>
+<script>
+import SettingTitle from 'data-room-ui/SettingTitle/index.vue'
+import TextGradient from 'data-room-ui/BigScreenDesign/RightSetting/TextGradient/index'
+import PosWhSetting from 'data-room-ui/BigScreenDesign/RightSetting/PosWhSetting.vue'
+export default {
+  name: 'TextSetting',
+  components: {
+    TextGradient,
+    PosWhSetting,
+    SettingTitle
+  },
+  data () {
+    return {
+      rules: {
+        title: [
+          { required: true, message: '请输入标题', trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  computed: {
+    config: {
+      get () {
+        return this.$store.state.bigScreen.activeItemConfig
+      },
+      set (val) {
+        this.$store.state.bigScreen.activeItemConfig = val
+      }
+    }
+  },
+  watch: {
+  },
+  mounted () {},
+  methods: {
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "../../assets/style/settingWrap.scss";
+.bs-setting-wrap{
+  padding-top: 16px;
+}
+.lc-field-body {
+  padding: 12px 16px;
+}
+</style>

+ 33 - 0
data-room-ui/packages/BasicComponents/ThemeSelect/settingConfig.js

@@ -0,0 +1,33 @@
+/*
+ * @Descripttion:
+ * @Author: liu.shiyi
+ * @Date: 2022-10-13 11:18:03
+ * @LastEditTime: 2022-10-13 13:55:11
+ */
+import { commonConfig } from 'data-room-ui/js/config'
+
+export const settingConfig = {
+  // 设置面板属性的显隐
+  displayOption: {
+    dataAllocation: {
+      // 是否存在数据配置
+      enable: false
+    }
+  }
+}
+const customConfig = {
+  type: 'themeSelect',
+  root: {
+    version: '2023071001'
+  },
+  customize: {
+    title: '文本标签占位符',
+    fontSize: 20,
+    fontWeight: 700,
+    color: 'left,#bcc9d4,#bcc9d4'
+  }
+
+}
+export const dataConfig = {
+  ...commonConfig(customConfig)
+}

+ 16 - 32
data-room-ui/packages/BasicComponents/ThemeSwitcher/index.vue

@@ -17,13 +17,13 @@
         style="color: red!important;"
         :style="{color:config.customize.inactiveColor}"
       >
-        明亮
+        明亮主题
       </el-radio>
       <el-radio
         label="dark"
         :style="{color:config.customize.inactiveColor}"
       >
-        暗黑
+        暗黑主题
       </el-radio>
     </el-radio-group>
   </div>
@@ -84,12 +84,13 @@ export default {
       })
       if (!this.isPreview) {
         const themeLabel = val === 'light' ? '明亮' : '暗黑'
-        const htmlStr = `<span>当前已切换到<strong>${themeLabel}</strong>主题,颜色设置针对当前主题生效</span>`
+        const htmlStr = `<span>当前已切换为<strong>${themeLabel}</strong>主题,涉及到颜色的配置仅针对当前主题生效</span>`
         this.$notify({
           title: '注意',
           dangerouslyUseHTMLString: true,
           message: htmlStr,
           customClass: 'ds-el-notify',
+          duration: 5000,
           type: 'warning'
         })
       }
@@ -99,33 +100,16 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-  .bs-design-wrap{
-    width: 100%;;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    flex-wrap: nowrap;
-    color: #fff;
-    .label-box{
-      padding: 10px;
-      margin-right: 10px;
-      font-size: 14px;
-    }
-    //.el-radio.is-checked {
-    //  color: red; /* 修改激活状态下的字体颜色 */
-    //}
-    //
-    ///* 修改未激活状态下的字体颜色 */
-    //.el-radio:not(.is-checked) {
-    //  color: #fff; /* 修改未激活状态下的字体颜色 */
-    //}
-    /deep/ .el-radio__input.is-checked+.el-radio__label {
-      /* 使用 CSS 变量来设置字体颜色 */
-      color: var(--radio-label-color);
-    }
-    /deep/ .el-radio__input.is-checked .el-radio__inner{
-      background: var(--radio-label-color);
-      border-color: var(--radio-label-color);
-    }
-  }
+.bs-design-wrap{
+  width: 100%;
+}
+.content-box{
+  text-align: center;
+  /* 将背景设为渐变 */
+  /*background-image: -webkit-linear-gradient(left, #6294F7, #C85D14);*/
+  /* 规定背景绘制区域 */
+  -webkit-background-clip: text;
+  /* 将文字隐藏 */
+  -webkit-text-fill-color: transparent;
+}
 </style>

+ 1 - 1
data-room-ui/packages/BigScreenDesign/RightSetting/ComponentBinding/index.vue

@@ -116,7 +116,7 @@ export default {
           })
         }
       })
-      layouts = layouts?.filter(item => item.code !== code && !['Tabs', 'titles', 'currentTime', 'timeCountDown', 'iframeChart', 'linkChart', 'carousel', 'themeSwitcher'].includes(item.type))
+      layouts = layouts?.filter(item => item.code !== code && !['Tabs', 'titles', 'currentTime', 'timeCountDown', 'iframeChart', 'linkChart', 'carousel', 'themeSwitcher', 'themeSelect'].includes(item.type))
       layouts = [...layouts, ...tabComponents]?.map(item => ({
         name: item.code,
         comment: item.title

+ 2 - 2
data-room-ui/packages/BigScreenDesign/RightSetting/index.vue

@@ -152,9 +152,9 @@ export default {
       if (!isEqual(val, oldValue)) {
         if (type === 'configStyle') {
           if (this.config.type === 'iframeChart') {
-            this.debounce(500, { ...val, type: this.config.type, code: this.config.code })
+            this.debounce(500, { ...val, type: this.config.type, code: this.config.code, parentCode: this.config?.parentCode })
           } else {
-            this.$emit('updateSetting', { ...val, type: this.config.type, code: this.config.code, theme: this.config.theme })
+            this.$emit('updateSetting', { ...val, type: this.config.type, code: this.config.code, theme: this.config.theme, parentCode: this.config?.parentCode })
           }
         } else {
           this.$emit('updateDataSetting', this.config)

+ 14 - 4
data-room-ui/packages/BigScreenDesign/index.vue

@@ -407,13 +407,23 @@ export default {
     },
     // 自定义属性更新
     updateSetting (config) {
-      if (config.type === 'map'|| config.type==='remoteComponent' || config.type === 'video' || config.type === 'flyMap') {
+      if (config.type === 'map' || config.type === 'remoteComponent' || config.type === 'video' || config.type === 'flyMap') {
         config.key = new Date().getTime()
       }
       this.changeChartConfig(cloneDeep(config))
-      this.$refs.Render?.$refs['RenderCard' + config.code][0]?.$refs[
-        config.code
-      ]?.changeStyle(cloneDeep(config))
+      // 如果是tab内的组件
+      if (config.parentCode) {
+        const dom = this.$refs.Render?.$refs['RenderCard' + config.parentCode][0]?.$refs[config.parentCode]?.$refs['RenderCard' + config.code]?.$refs[config.code]
+        if (dom) {
+          dom?.changeStyle(cloneDeep(config))
+        }
+      } else {
+        if (this.$refs.Render?.$refs['RenderCard' + config.code]) {
+          this.$refs.Render?.$refs['RenderCard' + config.code][0]?.$refs[
+            config.code
+          ]?.changeStyle(cloneDeep(config))
+        }
+      }
     },
     // 动态属性更新
     updateDataSetting (config) {

+ 4 - 0
data-room-ui/packages/Render/RenderCard.vue

@@ -72,6 +72,10 @@ export default {
     styleHandler (config) {
       this.$emit('styleHandler', config)
     }
+    // // 打开右侧面板
+    // openRightPanel () {
+    //   this.$emit('openRightPanel', this.currentChart)
+    // }
   }
 }
 </script>

+ 91 - 0
data-room-ui/packages/Render/RenderCard2.vue

@@ -0,0 +1,91 @@
+<!--
+ * @description: 渲染组件
+ * @Date: 2022-08-18 09:42:45
+ * @Author: xingheng
+-->
+
+<template>
+  <div class="render-item-wrap">
+    <component
+      :is="resolveComponentType(config.type)"
+      :id="`${config.code}`"
+      :ref="config.code"
+      :key="config.key"
+      :config="config"
+      @styleHandler="styleHandler"
+    />
+  </div>
+</template>
+<script>
+// import commonMixins from 'data-room-ui/js/mixins/commonMixins'
+import { mapMutations } from 'vuex'
+import { resolveComponentType } from 'data-room-ui/js/utils'
+import pcComponent from 'data-room-ui/js/utils/componentImport'
+import { dataInit, destroyedEvent } from 'data-room-ui/js/utils/eventBus'
+import CustomComponent from '../PlotRender/index.vue'
+import Svgs from '../Svgs/index.vue'
+import RemoteComponent from 'data-room-ui/RemoteComponents/index.vue'
+import cloneDeep from 'lodash/cloneDeep'
+const components = {}
+for (const key in pcComponent) {
+  if (Object.hasOwnProperty.call(pcComponent, key)) {
+    components[key] = pcComponent[key]
+  }
+}
+export default {
+  name: 'RenderCard',
+  // mixins: [commonMixins],
+  components: {
+    ...components,
+    CustomComponent,
+    Svgs,
+    RemoteComponent
+  },
+  props: {
+    // 卡片的属性
+    config: {
+      type: Object,
+      default: () => ({})
+    },
+    ruleKey: {
+      type: Number,
+      default: 0
+    }
+  },
+  data () {
+    return {}
+  },
+  computed: {},
+  mounted () {
+    // 调用初始化方法
+    dataInit(this)
+  },
+  beforeDestroy () {
+    destroyedEvent()
+  },
+  methods: {
+    ...mapMutations('bigScreen', [
+      'changeChartConfig'
+    ]),
+    resolveComponentType,
+    // 切换主题时针对远程组件触发样式修改的方法
+    styleHandler (config) {
+      this.$emit('styleHandler', config)
+    },
+    // // 打开右侧面板
+    // openRightPanel () {
+    //   this.$emit('openRightPanel', this.currentChart)
+    // }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.render-item-wrap {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  overflow: hidden;
+  box-sizing: border-box;
+}
+</style>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
data-room-ui/packages/assets/images/bigScreenIcon/svg/19chartTab.svg


+ 1 - 0
data-room-ui/packages/assets/images/bigScreenIcon/svg/20themeSelect.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1693807714061" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13871" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M912.6912 205.380267H110.3872A109.397333 109.397333 0 0 0 1.024 314.7776v364.680533a109.397333 109.397333 0 0 0 109.397333 109.397334H912.725333a109.397333 109.397333 0 0 0 109.397334-109.397334V314.7776a109.397333 109.397333 0 0 0-109.397334-109.397333z m36.4544 455.816533c0 30.208-24.507733 54.715733-54.715733 54.715733H128.682667a54.715733 54.715733 0 0 1-54.715734-54.715733V333.0048c0-30.208 24.4736-54.715733 54.715734-54.715733h765.781333c30.208 0 54.715733 24.507733 54.715733 54.715733v328.192z" fill="#3366FF" p-id="13872"></path><path d="M850.670933 490.530133a18.2272 18.2272 0 0 0-13.858133-29.9008h-119.6032a18.2272 18.2272 0 0 0-13.858133 29.9008l59.8016 70.0416a18.2272 18.2272 0 0 0 27.716266 0l59.8016-70.0416z" fill="#32EDCC" p-id="13873"></path></svg>

+ 3 - 1
data-room-ui/packages/js/config/basicComponentsConfig.js

@@ -28,7 +28,9 @@ const typeList = [
   'input',
   'button',
   'marquee',
-  'themeSwitcher'
+  'themeSwitcher',
+  'chartTab',
+  'themeSelect'
 ]
 let basicConfigList = []
 basicConfigList = typeList.map((type) => {

+ 58 - 21
data-room-ui/packages/js/store/mutations.js

@@ -31,10 +31,27 @@ export default {
   changeActiveCode (state, code) {
     state.activeCode = code
     state.hoverCode = code
-
-    const activeItem = cloneDeep(state.pageInfo.chartList?.find(
-      item => item.code === code
-    ))
+    let activeItem = {}
+    // let activeItem = cloneDeep(state.pageInfo.chartList?.find(
+    //   item => item.code === code
+    // ))
+    for (const item of state.pageInfo.chartList) {
+      // 检查当前项的 code 是否与 currentCode 匹配
+      if (item.code === code) {
+        activeItem = item
+        break // 找到匹配的项后,退出循环
+      }
+      // 如果当前项的 type 为 'chartTab',则进一步检查其 tabList
+      if (item.type === 'chartTab') {
+        for (const tabItem of item.customize.tabList) {
+          // 检查 tabList 中的每一项的 code 是否与 currentCode 匹配
+          if (tabItem.chartCode === code) {
+            activeItem = tabItem.chart
+            break // 找到匹配的项后,退出循环
+          }
+        }
+      }
+    }
     changeGroup(code, state)
     state.activeItemConfig = cloneDeep(activeItem)
   },
@@ -62,28 +79,48 @@ export default {
   changeHoverCode (state, code) {
     state.hoverCode = code
   },
+  // 改变当前选中组件id
   changePageLoading (state, booleanValue) {
+    // 改变loading状态
     state.pageLoading = booleanValue
   },
   // 改变当前组件配置
   changeChartConfig (state, itemConfig) {
-    const index = state.pageInfo.chartList.findIndex(
-      item => item.code === itemConfig.code
-    )
-    Vue.set(state.pageInfo.chartList, index, {
-      ...state.pageInfo.chartList[index],
-      ...itemConfig
-    })
-    // 对比之前的config和当前的itemConfig的xywh,如果有变化,就改变卡尺对齐线
-    const oldConfig = state.pageInfo.chartList[index]
-    if (
-      oldConfig.x !== itemConfig.x ||
-      oldConfig.y !== itemConfig.y ||
-      oldConfig.w !== itemConfig.w ||
-      oldConfig.h !== itemConfig.h
-    ) {
-      // 改变当前组件的卡尺对齐线
-      changePresetLine(state, itemConfig)
+    // 如果存在parentCode的组件,则是tab中的组件
+    if (itemConfig.parentCode) {
+      state.pageInfo.chartList.forEach((chart, index) => {
+        if (chart.code === itemConfig.parentCode) {
+          chart.customize.tabList.forEach((tabItem, i) => {
+            if (tabItem.chartCode === itemConfig.code) {
+              Vue.set(state.pageInfo.chartList[index].customize.tabList[i], 'chart', {
+                ...state.pageInfo.chartList[index].customize.tabList[i].chart,
+                ...itemConfig
+              })
+            }
+          })
+        }
+      })
+    } else {
+      // 如果是一般的组件
+      let index = null
+      index = state.pageInfo.chartList.findIndex(
+        item => item.code === itemConfig.code
+      )
+      Vue.set(state.pageInfo.chartList, index, {
+        ...state.pageInfo.chartList[index],
+        ...itemConfig
+      })
+      // 对比之前的config和当前的itemConfig的xywh,如果有变化,就改变卡尺对齐线
+      const oldConfig = state.pageInfo.chartList[index]
+      if (
+        oldConfig.x !== itemConfig.x ||
+        oldConfig.y !== itemConfig.y ||
+        oldConfig.w !== itemConfig.w ||
+        oldConfig.h !== itemConfig.h
+      ) {
+        // 改变当前组件的卡尺对齐线
+        changePresetLine(state, itemConfig)
+      }
     }
   },
   setPresetLine (state, { x, y, w, h }) {

+ 25 - 1
data-room-ui/packages/js/utils/getComponentConfig.js

@@ -219,7 +219,31 @@ export default function getComponentConfig (type) {
         title: '主题切换',
         icon: Icon.getNameList()[17],
         className: 'com.gccloud.dataroom.core.module.chart.components.ThemeSwitcherChart',
-        w: 500,
+        w: 260,
+        h: 100,
+        x: 0,
+        y: 0,
+        type
+      }
+    case 'chartTab':
+      return {
+        name: '图表Tab页',
+        title: '图表Tab页',
+        icon: Icon.getNameList()[19],
+        className: 'com.gccloud.dataroom.core.module.chart.components.ChartTabChart',
+        w: 600,
+        h: 400,
+        x: 0,
+        y: 0,
+        type
+      }
+    case 'themeSelect':
+      return {
+        name: '主题切换',
+        title: '主题切换',
+        icon: Icon.getNameList()[20],
+        className: 'com.gccloud.dataroom.core.module.chart.components.ThemeSelectChart',
+        w: 200,
         h: 100,
         x: 0,
         y: 0,

+ 58 - 40
data-room-ui/packages/js/utils/themeFormatting.js

@@ -49,52 +49,70 @@ export function settingToTheme (config, type) {
 }
 // 将保存的theme主题设置(颜色)存放到chartList
 export function themeToSetting (chartList, type) {
+  let modifiedChartList = chartList
+  let finalChartList = chartList
   // 排除掉主题非暗黑非明亮的情况
   if (['dark', 'light'].includes(type)) {
-    chartList.forEach(chart => {
-      chart.option.theme = type === 'dark' ? 'transparent' : 'light'
-      if (chart.theme && chart.theme[type]) {
-        // 如果是g2组件或者远程组件
-        if (['customComponent', 'remoteComponent'].includes(chart.type)) {
-          for (const item of chart.setting) {
-            // 检查 obj 中是否存在与 item.field 相对应的属性
-            if (Object.prototype.hasOwnProperty.call(chart.theme[type], item.field)) {
-              // 更新 setting 中对应项的 value 值为 theme 中的属性值
-              item.value = chart.theme[type][item.field]
-            }
-          }
-        } else {
-          // 如果是普通组件
-          if (chart.customize && Object.keys(chart.customize).length) {
-            for (const key in chart.theme[type]) {
-              const value = chart.theme[type][key]
-              // 如果对应的是二级属性
-              if (key.includes('_')) {
-                const [propertyName, subPropertyName] = key.split('_')
-                if (!chart.customize[propertyName]) {
-                  chart.customize[propertyName] = {}
-                } else {
-                  chart.customize[propertyName][subPropertyName] = value
-                }
-              } else {
-                // 对应的一级属性
-                if (Object.prototype.hasOwnProperty.call(chart.customize, key)) {
-                  // 更新 customize 中对应项的值为 theme 中的属性值
-                  chart.customize[key] = chart.theme[type][key]
-                }
-              }
+    modifiedChartList = chartList.map((item) => {
+      // 使用 map 方法遍历 chartList 数组并执行操作chartThemeToSetting
+      return chartThemeToSetting(item, type)
+    })
+    finalChartList = modifiedChartList.map((item) => {
+      // 如果当前项的 type 为 'chartTab',遍历其 tabList 数组并执行操作chartThemeToSetting
+      if (item.type === 'chartTab' && Array.isArray(item.customize.tabList) && item.customize.tabList.length) {
+        const modifiedChildren = item.customize.tabList.map((child) => {
+          return { ...child, chart: chartThemeToSetting(child.chart, type) }
+        })
+        return { ...item, customize: { ...item.customize, tabList: modifiedChildren } }
+      }
+      return item
+    })
+  }
+  return finalChartList
+}
+// 对单个组件进行主题设置(从theme到Setting)
+function chartThemeToSetting (chart, type) {
+  chart.option.theme = type === 'dark' ? 'transparent' : 'light'
+  if (chart.theme && chart.theme[type]) {
+    // 如果是g2组件或者远程组件
+    if (['customComponent', 'remoteComponent'].includes(chart.type)) {
+      for (const item of chart.setting) {
+        // 检查 obj 中是否存在与 item.field 相对应的属性
+        if (Object.prototype.hasOwnProperty.call(chart.theme[type], item.field)) {
+          // 更新 setting 中对应项的 value 值为 theme 中的属性值
+          item.value = chart.theme[type][item.field]
+        }
+      }
+    } else {
+      // 如果是普通组件
+      if (chart.customize && Object.keys(chart.customize).length) {
+        for (const key in chart.theme[type]) {
+          const value = chart.theme[type][key]
+          // 如果对应的是二级属性
+          if (key.includes('_')) {
+            const [propertyName, subPropertyName] = key.split('_')
+            if (!chart.customize[propertyName]) {
+              chart.customize[propertyName] = {}
+            } else {
+              chart.customize[propertyName][subPropertyName] = value
             }
-            for (const item in chart.customize) {
-              // 检查 obj 中是否存在与 customize 相对应的属性
-              if (Object.prototype.hasOwnProperty.call(chart.theme[type], item)) {
-                // 更新 customize 中对应项的值为 theme 中的属性值
-                chart.customize[item] = chart.theme[type][item]
-              }
+          } else {
+            // 对应的一级属性
+            if (Object.prototype.hasOwnProperty.call(chart.customize, key)) {
+              // 更新 customize 中对应项的值为 theme 中的属性值
+              chart.customize[key] = chart.theme[type][key]
             }
           }
         }
+        for (const item in chart.customize) {
+          // 检查 obj 中是否存在与 customize 相对应的属性
+          if (Object.prototype.hasOwnProperty.call(chart.theme[type], item)) {
+            // 更新 customize 中对应项的值为 theme 中的属性值
+            chart.customize[item] = chart.theme[type][item]
+          }
+        }
       }
-    })
+    }
   }
-  return chartList
+  return chart
 }

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است