launcher/ui/src/pages/Launch.vue

238 lines
6.6 KiB
Vue

<script setup>
import { useConfigStore } from '@/stores/config.js'
import { NButton } from 'naive-ui'
import { Add, Pencil, Play, Folder, TrashOutline, Archive } from '@vicons/ionicons5'
const notification = useNotification()
const config_store = useConfigStore()
const conf = config_store.config
const instance_name_input_refs = ref([])
const update_instance_name_index = ref(null)
const migrate_options = [
{
label: '迁移单开配置',
key: 'default'
},
{
label: '迁移多开配置',
key: 'instances'
}
]
const check_all = computed(
() => conf.instances.length > 0 && conf.instances.every((item) => item.checked)
)
const check_part = computed(() => !check_all.value && conf.instances.some((item) => item.checked))
function click_check_all(ckecked) {
if (ckecked) {
conf.instances.forEach((item) => {
item.checked = true
})
} else {
conf.instances.forEach((item) => {
item.checked = false
})
}
}
function setInstanceNameInputRef(el, index) {
if (el) {
instance_name_input_refs.value[index] = el
}
}
async function add_instance() {
const instance_path = await pywebview.api.add_instance()
conf.instances.push({
checked: false,
name: '新实例',
path: instance_path
})
}
async function delete_instance(index, path) {
await pywebview.api.delete_instance(path)
conf.instances.splice(index, 1)
}
function start_update_instance_name(index) {
update_instance_name_index.value = index
nextTick(() => {
instance_name_input_refs.value[index]?.focus()
})
}
function end_update_instance_name() {
update_instance_name_index.value = null
}
function open_folder(path) {
pywebview.api.open_folder(path)
}
function start_instance(instance) {
pywebview.api.run('webview', 'mower-ng', {
instance_path: instance.path
})
}
function start_checked_instance() {
pywebview.api.start_checked_instance()
}
async function handle_migrate(key) {
if (key == 'default') {
const response = await pywebview.api.migrate_default_instance()
console.log(response)
if (response.status) {
conf.instances.push({
checked: false,
name: '默认实例',
path: response.data
})
notification['success']({
content: '信息',
meta: response.message,
duration: 3000
})
} else {
notification['error']({
content: '错误',
meta: response.message,
duration: 3000
})
}
} else {
const response = await pywebview.api.migrate_instances_config()
console.log('多开配置内容:', response)
if (response.data) {
await config_store.load_config()
conf.instances = [...config_store.config.instances]
}
if (response.status) {
notification['info']({
title: '信息',
content: response.message,
duration: 3000
})
} else {
notification['error']({
title: '错误',
content: response.message,
duration: 3000
})
}
}
}
</script>
<template>
<n-flex vertical style="gap: 16px; height: 100%; padding: 16px; box-sizing: border-box">
<n-space class="top" justify="space-between">
<n-space>
<n-button class="launch-btn" type="primary" secondary @click="add_instance">
<template #icon>
<n-icon :component="Add"></n-icon>
</template>
添加实例
</n-button>
<n-button
class="launch-btn"
type="primary"
secondary
@click="start_checked_instance"
:disabled="!check_all && !check_part"
>
<template #icon>
<n-icon :component="Play"></n-icon>
</template>
启动所选实例
</n-button>
<n-dropdown trigger="click" :options="migrate_options" @select="handle_migrate">
<n-button class="launch-btn" type="primary" secondary>
<template #icon>
<n-icon :component="Archive"></n-icon>
</template>
迁移配置
</n-button>
</n-dropdown>
</n-space>
<div class="is_show_log_switch">
<n-switch v-model:value="conf.is_show_log" />
显示日志
</div>
</n-space>
<n-list class="instance-list" bordered>
<n-list-item>
<template #prefix>
<n-checkbox
v-model:checked="check_all"
:indeterminate="check_part"
style="white-space: nowrap"
@update:checked="click_check_all"
>全选</n-checkbox
>
</template>
</n-list-item>
<n-list-item v-for="(item, index) in conf.instances" :key="index">
<template #prefix>
<n-checkbox v-model:checked="item.checked"></n-checkbox>
</template>
<n-space vertical>
<n-space v-if="update_instance_name_index != index">
<n-text>{{ item.name }}</n-text>
<n-button size="tiny" @click="start_update_instance_name(index)">
<template #icon>
<n-icon :component="Pencil"></n-icon>
</template>
</n-button>
<n-button @click="open_folder(item.path)" size="tiny">
<template #icon>
<n-icon :component="Folder"></n-icon>
</template>
</n-button>
</n-space>
<n-input
v-else
:ref="(el) => setInstanceNameInputRef(el, index)"
v-model:value="item.name"
@blur="end_update_instance_name"
></n-input>
</n-space>
<template #suffix>
<n-space :wrap="false">
<n-button type="primary" size="small" @click="start_instance(item)">
<template #icon>
<n-icon :component="Play"></n-icon>
</template>
</n-button>
<n-popconfirm @positive-click="delete_instance(index, item.path)">
<template #trigger>
<n-button type="error" ghost size="small">
<template #icon>
<n-icon :component="TrashOutline"></n-icon>
</template>
</n-button>
</template>
删除操作将导致实例配置丢失请谨慎操作
</n-popconfirm>
</n-space>
</template>
</n-list-item>
</n-list>
<log-component v-show="conf.is_show_log" class="log" />
</n-flex>
</template>
<style scoped>
.launch-btn {
height: 38px;
}
.instance-list {
overflow: auto;
}
.log {
min-height: 40vh;
max-height: 40vh;
margin-top: auto;
}
.top {
align-items: center;
}
.is_show_log_switch {
margin-right: 20px;
}
</style>