fix: 修复新建项目无响应问题

- 替换 prompt() 为 InputDialog Vue 模态组件
- 替换 alert()/confirm() 为 Electron showMessageBox IPC
- 添加 dialog:showMessage / dialog:showConfirm IPC 通道
This commit is contained in:
gmh01
2026-07-23 19:44:04 +08:00
parent 95116e2338
commit 686d94e178
7 changed files with 180 additions and 14 deletions

View File

@@ -0,0 +1,100 @@
<template>
<Teleport to="body">
<div v-if="visible" class="dialog-overlay" @click.self="cancel">
<div class="dialog-box card">
<h3 class="dialog-title">{{ title }}</h3>
<p v-if="message" class="dialog-message">{{ message }}</p>
<input
ref="inputRef"
class="dialog-input"
v-model="inputValue"
:placeholder="placeholder"
@keydown.enter="confirm"
@keydown.esc="cancel"
/>
<div class="dialog-actions">
<button class="btn btn-secondary" @click="cancel">{{ cancelText }}</button>
<button class="btn btn-primary" @click="confirm" :disabled="!inputValue.trim()">{{ okText }}</button>
</div>
</div>
</div>
</Teleport>
</template>
<script setup>
import { ref, watch, nextTick } from 'vue'
const props = defineProps({
visible: Boolean,
title: { type: String, default: '输入' },
message: { type: String, default: '' },
placeholder: { type: String, default: '' },
defaultValue: { type: String, default: '' },
cancelText: { type: String, default: '取消' },
okText: { type: String, default: '确定' }
})
const emit = defineEmits(['confirm', 'cancel'])
const inputValue = ref('')
const inputRef = ref(null)
watch(() => props.visible, (val) => {
if (val) {
inputValue.value = props.defaultValue
nextTick(() => {
inputRef.value?.focus()
inputRef.value?.select()
})
}
})
function confirm() {
if (inputValue.value.trim()) {
emit('confirm', inputValue.value.trim())
}
}
function cancel() {
emit('cancel')
}
</script>
<style scoped>
.dialog-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.4);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.dialog-box {
width: 400px;
padding: 24px;
}
.dialog-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 8px;
}
.dialog-message {
color: var(--text-secondary);
font-size: 13px;
margin-bottom: 12px;
}
.dialog-input {
width: 100%;
margin-bottom: 16px;
}
.dialog-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
}
</style>

View File

@@ -42,6 +42,15 @@
</div>
</div>
</div>
<InputDialog
:visible="showInput"
title="新建项目"
message="请输入项目名称"
placeholder="例如MyApp"
@confirm="onNameConfirmed"
@cancel="onNameCancelled"
/>
</div>
</template>
@@ -49,25 +58,40 @@
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useProjectStore } from '../stores/project'
import InputDialog from '../components/InputDialog.vue'
const router = useRouter()
const store = useProjectStore()
const recentProjects = ref(loadRecentProjects())
const showInput = ref(false)
const pendingDir = ref('')
async function createNewProject() {
const dir = await window.api.dialog.selectDirectory()
if (!dir) return
const name = prompt('请输入项目名称:')
if (!name) return
pendingDir.value = dir
showInput.value = true
}
async function onNameConfirmed(name) {
showInput.value = false
try {
await store.createProject(name, dir)
addRecentProject(dir, name)
await store.createProject(name, pendingDir.value)
addRecentProject(pendingDir.value, name)
router.push('/editor')
} catch (err) {
alert('创建失败: ' + err.message)
await window.api.dialog.showMessage({
type: 'error',
title: '创建失败',
message: err.message
})
}
}
function onNameCancelled() {
showInput.value = false
}
async function openExistingProject() {
const dir = await window.api.dialog.selectDirectory()
if (!dir) return
@@ -80,7 +104,11 @@ async function openProject(dir) {
addRecentProject(dir, store.config.name)
router.push('/editor')
} catch (err) {
alert('打开失败: ' + err.message)
await window.api.dialog.showMessage({
type: 'error',
title: '打开失败',
message: err.message
})
}
}

View File

@@ -74,7 +74,11 @@ async function importFromFiles() {
}
async function handleDelete(relativePath) {
if (confirm(`确定删除 "${relativePath}"`)) {
const ok = await window.api.dialog.showConfirm({
title: '删除确认',
message: `确定要删除 "${relativePath}" 吗?`
})
if (ok) {
await store.removeFile(relativePath)
}
}