github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/static_source/admin/src/views/Scripts/edit.vue (about) 1 <script setup lang="ts"> 2 import {computed, onMounted, onUnmounted, ref, unref} from 'vue' 3 import {useI18n} from '@/hooks/web/useI18n' 4 import { 5 ElButton, 6 ElCol, 7 ElDescriptions, 8 ElDescriptionsItem, 9 ElFormItem, 10 ElMessage, 11 ElOption, 12 ElPopconfirm, 13 ElRow, 14 ElSelect, 15 ElTabPane, 16 ElTabs 17 } from 'element-plus' 18 import {useRoute, useRouter} from 'vue-router' 19 import api from "@/api/api"; 20 import Form from './components/Form.vue' 21 import {ApiScript} from "@/api/stub"; 22 import {ScriptEditor} from "@/components/ScriptEditor"; 23 import {ContentWrap} from "@/components/ContentWrap"; 24 import {useEmitt} from "@/hooks/web/useEmitt"; 25 import {Infotip} from '@/components/Infotip' 26 import {parseTime} from "@/utils"; 27 import {UUID} from "uuid-generator-ts"; 28 import stream from "@/api/stream"; 29 import {MergeEditor} from "@/components/MergeEditor"; 30 import {EventUpdatedScriptModel} from "@/api/types"; 31 32 const {emitter} = useEmitt() 33 const {push} = useRouter() 34 const route = useRoute(); 35 const {t} = useI18n() 36 37 const writeRef = ref<ComponentRef<typeof Form>>() 38 const loading = ref(false) 39 const scriptId = computed(() => parseInt(route.params.id)); 40 const currentScript = ref<Nullable<ApiScript>>(null) 41 const activeTab = ref('source') 42 const currentVersionIdx = ref(0) 43 const currentVersion = ref<Nullable<ApiScript>>(null) 44 const versions = ref<Nullable<ApiScript[]>>([]) 45 46 const currentID = ref('') 47 48 onMounted(() => { 49 const uuid = new UUID() 50 currentID.value = uuid.getDashFreeUUID() 51 52 setTimeout(() => { 53 stream.subscribe('event_updated_script_model', currentID.value, eventHandler) 54 }, 1000) 55 }) 56 57 onUnmounted(() => { 58 stream.unsubscribe('event_updated_script_model', currentID.value) 59 }) 60 61 const eventHandler = (event: EventUpdatedScriptModel) => { 62 if (event.script_id && event.script_id === scriptId.value) { 63 fetch() 64 } 65 } 66 67 const fetch = async () => { 68 loading.value = true 69 const res = await api.v1.scriptServiceGetScriptById(scriptId.value) 70 .catch(() => { 71 }) 72 .finally(() => { 73 loading.value = false 74 }) 75 if (res) { 76 currentScript.value = res.data 77 if (res.data?.versions && res.data.versions.length) { 78 versions.value = res.data.versions; 79 if (res.data.versions.length > 1) { 80 currentVersion.value = res.data.versions[1] 81 } 82 } 83 } else { 84 currentScript.value = null 85 } 86 } 87 88 const exec = async () => { 89 await api.v1.scriptServiceExecSrcScriptById({ 90 name: currentScript.value?.name, 91 source: currentScript.value?.source, 92 lang: currentScript.value?.lang 93 }) 94 ElMessage({ 95 title: t('Success'), 96 message: t('message.callSuccessful'), 97 type: 'success', 98 duration: 2000 99 }) 100 } 101 102 const copy = async () => { 103 const res = await api.v1.scriptServiceCopyScriptById(scriptId.value) 104 .catch(() => { 105 }) 106 .finally(() => { 107 }) 108 if (res) { 109 const {id} = res.data; 110 push(`/scripts/edit/${id}`) 111 } 112 } 113 114 const updateVersions = async () => { 115 loading.value = true 116 const res = await api.v1.scriptServiceGetScriptById(scriptId.value) 117 .catch(() => { 118 }) 119 .finally(() => { 120 loading.value = false 121 }) 122 if (res) { 123 if (res.data?.versions && res.data.versions.length) { 124 currentVersion.value = res.data.versions[0] 125 versions.value = res.data.versions 126 } 127 } 128 } 129 130 const save = async () => { 131 const write = unref(writeRef) 132 const validate = await write?.elFormRef?.validate()?.catch(() => { 133 }) 134 if (validate) { 135 loading.value = true 136 const data = (await write?.getFormData()) as ApiScript 137 const body = { 138 id: data.id, 139 lang: data.lang, 140 name: data.name, 141 source: currentScript.value?.source || '', 142 description: data.description, 143 } 144 const res = await api.v1.scriptServiceUpdateScriptById(scriptId.value, body) 145 .catch(() => { 146 }) 147 .finally(async () => { 148 updateVersions(); 149 }) 150 if (res) { 151 ElMessage({ 152 title: t('Success'), 153 message: t('message.updatedSuccessfully'), 154 type: 'success', 155 duration: 2000 156 }) 157 } 158 } 159 } 160 161 const cancel = () => { 162 push('/scripts') 163 } 164 165 const remove = async () => { 166 loading.value = true 167 const res = await api.v1.scriptServiceDeleteScriptById(scriptId.value) 168 .catch(() => { 169 }) 170 .finally(() => { 171 loading.value = false 172 }) 173 if (res) { 174 cancel() 175 } 176 } 177 178 const updateCurrentTab = (tab: any, ev: any) => { 179 const {index, paneName} = tab; 180 if (paneName == 'source' || paneName == 'versions') { 181 emitter.emit('updateEditor') 182 } 183 } 184 185 const onMergeEditorChange = (val: string) => { 186 currentScript.value.source = val 187 reload() 188 } 189 190 const onScriptEditorChange = (val: string) => { 191 if (currentScript.value?.source == val) { 192 return 193 } 194 currentScript.value.source = val 195 } 196 197 const selectVersionHandler = () => { 198 currentVersion.value = currentScript.value?.versions[currentVersionIdx.value] || null 199 } 200 201 const reloadKey = ref(0) 202 const reload = () => reloadKey.value += 1 203 204 fetch() 205 206 </script> 207 208 <template> 209 <ContentWrap> 210 211 <ElTabs class="demo-tabs" v-model="activeTab" @tab-click="updateCurrentTab"> 212 <!-- main --> 213 <ElTabPane :label="$t('scripts.main')" name="main"> 214 215 <Form ref="writeRef" :current-row="currentScript"/> 216 217 </ElTabPane> 218 <!-- /main --> 219 220 <!-- source --> 221 <ElTabPane :label="$t('scripts.source')" name="source"> 222 <Infotip 223 :show-index="false" 224 title="INFO" 225 :schema="[ 226 { 227 label: t('scripts.info1'), 228 keys: ['scripts'] 229 }, 230 { 231 label: t('scripts.info2'), 232 keys: ['scripts'] 233 }, 234 { 235 label: t('scripts.info3'), 236 keys: ['scripts'] 237 }, 238 ]" 239 /> 240 <ScriptEditor :key="reloadKey" 241 v-model="currentScript" 242 class="mb-20px" 243 @update:source="onScriptEditorChange" 244 @save="save"/> 245 </ElTabPane> 246 <!-- /source --> 247 248 <!-- versions --> 249 <ElTabPane :label="$t('scripts.scriptVersions')" name="versions"> 250 251 <ElRow v-if="activeTab == 'versions' && !loading && versions" class="mb-20px"> 252 <ElCol> 253 <ElFormItem :label="$t('scripts.scriptVersions')" prop="action"> 254 <ElSelect 255 v-model="currentVersionIdx" 256 clearable 257 :placeholder="$t('dashboard.editor.selectAction')" 258 style="width: 100%" 259 @change="selectVersionHandler" 260 > 261 <ElOption 262 v-for="(p, index) in versions" 263 :key="index" 264 :label="parseTime(p.createdAt)" 265 :value="index"/> 266 </ElSelect> 267 268 </ElFormItem> 269 </ElCol> 270 <ElCol> 271 <MergeEditor :source="currentScript" 272 :destination="currentVersion" 273 @update:source="onMergeEditorChange"/> 274 </ElCol> 275 </ElRow> 276 277 </ElTabPane> 278 <!-- /versions --> 279 280 <!-- info --> 281 <ElTabPane :label="$t('scripts.scriptInfo')" name="info"> 282 <ElDescriptions v-if="currentScript?.scriptInfo" 283 class="ml-10px mr-10px mb-20px" 284 :title="$t('scripts.scriptInfo')" 285 direction="vertical" 286 :column="2" 287 border 288 > 289 <ElDescriptionsItem :label="$t('scripts.alexaIntents')">{{ currentScript.scriptInfo.alexaIntents }} 290 </ElDescriptionsItem> 291 <ElDescriptionsItem :label="$t('scripts.entityActions')">{{ currentScript.scriptInfo.entityActions }} 292 </ElDescriptionsItem> 293 <ElDescriptionsItem :label="$t('scripts.entityScripts')">{{ currentScript.scriptInfo.entityScripts }} 294 </ElDescriptionsItem> 295 <ElDescriptionsItem :label="$t('scripts.automationTriggers')"> 296 {{ currentScript.scriptInfo.automationTriggers }} 297 </ElDescriptionsItem> 298 <ElDescriptionsItem :label="$t('scripts.automationConditions')"> 299 {{ currentScript.scriptInfo.automationConditions }} 300 </ElDescriptionsItem> 301 <ElDescriptionsItem :label="$t('scripts.automationActions')"> 302 {{ currentScript.scriptInfo.automationActions }} 303 </ElDescriptionsItem> 304 </ElDescriptions> 305 </ElTabPane> 306 <!-- /info --> 307 308 </ElTabs> 309 310 <div style="text-align: right"> 311 312 <ElButton type="success" @click="exec()">{{ t('main.exec') }}</ElButton> 313 <ElButton type="primary" @click="save()">{{ t('main.save') }}</ElButton> 314 <ElButton type="default" @click="copy()">{{ t('main.copy') }}</ElButton> 315 <ElButton type="default" @click="fetch()">{{ t('main.loadFromServer') }}</ElButton> 316 <ElButton type="default" @click="cancel()">{{ t('main.return') }}</ElButton> 317 318 <ElPopconfirm 319 :confirm-button-text="$t('main.ok')" 320 :cancel-button-text="$t('main.no')" 321 width="250" 322 style="margin-left: 10px;" 323 :title="$t('main.are_you_sure_to_do_want_this?')" 324 @confirm="remove" 325 > 326 <template #reference> 327 <ElButton class="mr-10px" type="danger" plain> 328 <Icon icon="ep:delete" class="mr-5px"/> 329 {{ t('main.remove') }} 330 </ElButton> 331 </template> 332 </ElPopconfirm> 333 334 </div> 335 </ContentWrap> 336 337 </template> 338 339 <style lang="less" scoped> 340 341 </style>