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>