github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/static_source/admin/src/views/Dashboard/editor/TabEditor.vue (about)

     1  <script setup lang="ts">
     2  import {computed, onMounted, onUnmounted, PropType, reactive, ref, unref, watch} from 'vue'
     3  import {Form} from '@/components/Form'
     4  import {ElButton, ElCol, ElDivider, ElMessage, ElPopconfirm, ElRow} from 'element-plus'
     5  import {useI18n} from '@/hooks/web/useI18n'
     6  import {useForm} from '@/hooks/web/useForm'
     7  import {useValidator} from '@/hooks/web/useValidator'
     8  import {FormSchema} from '@/types/form'
     9  import {Core, Tab, eventBus} from "@/views/Dashboard/core";
    10  import {JsonViewer} from "@/components/JsonViewer";
    11  import {Dialog} from "@/components/Dialog";
    12  import FontEditor from "@/views/Dashboard/components/src/FontEditor.vue";
    13  import TabListWindow from "@/views/Dashboard/editor/TabListWindow.vue";
    14  
    15  const {register, elFormRef, methods} = useForm()
    16  const {required} = useValidator()
    17  const {t} = useI18n()
    18  const {setValues} = methods
    19  
    20  const props = defineProps({
    21    core: {
    22      type: Object as PropType<Nullable<Core>>,
    23      default: () => null
    24    },
    25    tab: {
    26      type: Object as PropType<Nullable<Tab>>,
    27      default: () => null
    28    },
    29  })
    30  
    31  const currentCore = computed(() => props.core as Core)
    32  
    33  const activeTab = computed({
    34    get(): Tab {
    35      return currentCore.value.getActiveTab
    36    },
    37    set(val: Tab) {
    38    }
    39  })
    40  
    41  const rules = {
    42    name: [required()],
    43  }
    44  
    45  const schema = reactive<FormSchema[]>([
    46    {
    47      field: 'name',
    48      label: t('dashboard.name'),
    49      component: 'Input',
    50      colProps: {
    51        span: 24
    52      },
    53      componentProps: {
    54        placeholder: t('dashboard.name')
    55      }
    56    },
    57    {
    58      field: 'icon',
    59      label: t('dashboard.icon'),
    60      component: 'Input',
    61      colProps: {
    62        span: 24
    63      },
    64      componentProps: {
    65        placeholder: t('dashboard.icon')
    66      }
    67    },
    68    {
    69      field: 'enabled',
    70      label: t('dashboard.enabled'),
    71      component: 'Switch',
    72      value: false,
    73      colProps: {
    74        md: 24,
    75        span: 24
    76      },
    77    },
    78    {
    79      field: 'appearance',
    80      label: t('dashboard.editor.appearanceOptions'),
    81      component: 'Divider',
    82      colProps: {
    83        span: 24
    84      },
    85    },
    86    {
    87      field: 'gap',
    88      label: t('dashboard.gap'),
    89      component: 'Switch',
    90      value: false,
    91      colProps: {
    92        md: 12,
    93        span: 12
    94      },
    95    },
    96    {
    97      field: 'columnWidth',
    98      label: t('dashboard.columnWidth'),
    99      component: 'InputNumber',
   100      value: 300,
   101      colProps: {
   102        span: 12
   103      },
   104    },
   105    {
   106      field: 'background',
   107      label: t('dashboard.background'),
   108      component: 'ColorPicker',
   109      colProps: {
   110        span: 12
   111      },
   112      componentProps: {
   113        placeholder: t('dashboard.background'),
   114      }
   115    },
   116    {
   117      field: 'backgroundAdaptive',
   118      label: t('dashboard.editor.backgroundAdaptive'),
   119      component: 'Switch',
   120      value: true,
   121      colProps: {
   122        span: 12
   123      },
   124      componentProps: {
   125        placeholder: t('dashboard.backgroundAdaptive'),
   126      }
   127    },
   128    {
   129      field: 'backgroundImage',
   130      label: t('dashboard.editor.image'),
   131      component: 'Image',
   132      colProps: {
   133        span: 24
   134      },
   135      value: null,
   136      componentProps: {
   137        placeholder: t('dashboard.image')
   138      }
   139    },
   140  ])
   141  
   142  const eventHandler = (event: string, args: any[]) => {
   143    showExportDialog()
   144  }
   145  
   146  onMounted(() => {
   147    eventBus.subscribe('showTabExportDialog', eventHandler)
   148  })
   149  
   150  onUnmounted(() => {
   151    eventBus.unsubscribe('showTabExportDialog', eventHandler)
   152  })
   153  
   154  watch(
   155      () => props.tab,
   156      (val?: Tab) => {
   157        if (!val) return
   158        setValues({
   159          name: val.name,
   160          columnWidth: val.columnWidth,
   161          gap: val.gap,
   162          background: val.background,
   163          icon: val.icon,
   164          enabled: val.enabled,
   165          weight: val.weight,
   166          backgroundImage: val.backgroundImage || undefined,
   167          backgroundAdaptive: val.backgroundAdaptive,
   168        })
   169      },
   170      {
   171        deep: false,
   172        immediate: true
   173      }
   174  )
   175  
   176  // ---------------------------------
   177  // common
   178  // ---------------------------------
   179  const updateTab = async () => {
   180    const formRef = unref(elFormRef)
   181    await formRef?.validate(async (isValid) => {
   182      if (isValid) {
   183        const {getFormData} = methods
   184        const formData = await getFormData()
   185  
   186        console.log(formData.backgroundImage)
   187  
   188        activeTab.value.background = formData.background;
   189        activeTab.value.backgroundImage = formData.backgroundImage || undefined;
   190        activeTab.value.backgroundAdaptive = formData.backgroundAdaptive;
   191        activeTab.value.columnWidth = formData.columnWidth;
   192        activeTab.value.enabled = formData.enabled;
   193        activeTab.value.gap = formData.gap;
   194        activeTab.value.icon = formData.icon;
   195        activeTab.value.name = formData.name;
   196        activeTab.value.weight = formData.weight;
   197  
   198        const res = await currentCore.value?.updateTab();
   199        if (res) {
   200          ElMessage({
   201            title: t('Success'),
   202            message: t('message.updatedSuccessfully'),
   203            type: 'success',
   204            duration: 2000
   205          });
   206        }
   207      }
   208    })
   209  
   210  }
   211  
   212  const removeTab = async () => {
   213    if (!activeTab.value) return;
   214    await currentCore.value.removeTab();
   215  }
   216  
   217  const cancel = () => {
   218    if (!activeTab.value) return;
   219    setValues({
   220      name: activeTab.value.name,
   221      columnWidth: activeTab.value.columnWidth,
   222      gap: activeTab.value.gap,
   223      background: activeTab.value.background,
   224      icon: activeTab.value.icon,
   225      enabled: activeTab.value.enabled,
   226      weight: activeTab.value.weight,
   227      backgroundImage: activeTab.value?.backgroundImage || undefined,
   228      backgroundAdaptive: activeTab.value?.backgroundAdaptive,
   229    })
   230  }
   231  
   232  // ---------------------------------
   233  // import/export
   234  // ---------------------------------
   235  
   236  const dialogSource = ref({})
   237  const exportDialogVisible = ref(false)
   238  
   239  const prepareForExport = () => {
   240    if (currentCore.value.activeTabIdx == undefined) {
   241      return;
   242    }
   243    dialogSource.value = activeTab.value.serialize()
   244  }
   245  
   246  const showExportDialog = () => {
   247    prepareForExport()
   248    exportDialogVisible.value = true
   249  }
   250  
   251  </script>
   252  
   253  <template>
   254  
   255    <ElRow class="mb-10px">
   256      <ElCol>
   257        <ElDivider content-position="left">{{ $t('dashboard.tabOptions') }}</ElDivider>
   258      </ElCol>
   259    </ElRow>
   260  
   261    <Form v-if="currentCore.tabs.length"
   262          :schema="schema"
   263          :rules="rules"
   264          label-position="top"
   265          @register="register"
   266    />
   267  
   268    <FontEditor v-if="activeTab" :tab="activeTab"/>
   269  
   270    <ElRow class="mb-10px">
   271      <ElCol>
   272        <ElDivider content-position="left">{{ $t('main.actions') }}</ElDivider>
   273      </ElCol>
   274    </ElRow>
   275  
   276    <div class="text-right" v-if="currentCore.tabs.length">
   277      <ElButton type="primary" @click.prevent.stop="updateTab" plain>{{ $t('main.update') }}</ElButton>
   278      <ElButton @click.prevent.stop="cancel" plain>{{ t('main.cancel') }}</ElButton>
   279      <ElPopconfirm
   280          :confirm-button-text="$t('main.ok')"
   281          :cancel-button-text="$t('main.no')"
   282          width="250"
   283          style="margin-left: 10px;"
   284          :title="$t('main.are_you_sure_to_do_want_this?')"
   285          @confirm="removeTab"
   286      >
   287        <template #reference>
   288          <ElButton class="mr-10px" type="danger" plain>
   289            <Icon icon="ep:delete" class="mr-5px"/>
   290            {{ t('main.remove') }}
   291          </ElButton>
   292        </template>
   293      </ElPopconfirm>
   294    </div>
   295  
   296    <!-- tab list window -->
   297    <TabListWindow :core="currentCore"/>
   298    <!-- /tab list window -->
   299  
   300    <!-- export dialog -->
   301    <Dialog v-model="exportDialogVisible" :title="t('main.dialogExportTitle')" :maxHeight="400" width="80%">
   302      <JsonViewer v-model="dialogSource"/>
   303    </Dialog>
   304    <!-- /export dialog -->
   305  
   306  </template>
   307  
   308  <style lang="less">
   309  
   310  </style>