feat(web): WorkspaceHomeView with worktrees/main/settings tabs and CommitDialog

This commit is contained in:
2026-05-02 23:24:16 +08:00
parent d962ba2f16
commit 0423f0566c
6 changed files with 747 additions and 0 deletions
@@ -0,0 +1,132 @@
<template>
<NModal
:show="true"
preset="card"
title="提交修改"
:style="{ width: '640px' }"
@close="emit('close')"
>
<p class="text-sm text-gray-600 mb-2">
{{ status.length }} 个改动
</p>
<NScrollbar
:style="{ maxHeight: '240px' }"
class="mb-4 border rounded p-2 bg-gray-50"
>
<div
v-for="f in status"
:key="f.path"
class="font-mono text-sm py-1"
>
<NTag
size="small"
type="info"
class="mr-2"
>
{{ f.index_x }}{{ f.worktree_y }}
</NTag>{{ f.path }}
</div>
<div
v-if="status.length === 0"
class="text-sm text-gray-400"
>
无改动
</div>
</NScrollbar>
<NForm label-placement="top">
<NFormItem
label="Commit message"
required
>
<NInput
v-model:value="message"
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
/>
</NFormItem>
<NFormItem>
<NCheckbox v-model:checked="push">
提交后推送到远端
</NCheckbox>
</NFormItem>
</NForm>
<template #footer>
<NSpace justify="end">
<NButton @click="emit('close')">
取消
</NButton>
<NButton
type="primary"
:loading="submitting"
:disabled="status.length === 0"
@click="submit"
>
提交
</NButton>
</NSpace>
</template>
</NModal>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import {
NModal,
NForm,
NFormItem,
NInput,
NCheckbox,
NButton,
NSpace,
NScrollbar,
NTag,
useMessage,
} from 'naive-ui'
import { useWorkspacesStore } from '@/stores/workspaces'
import type { FileStatus } from '@/api/types'
// target: 'main' 时用 wsID 调 commitOnMain;'worktree' 时用 wtID 调 commitOnWorktree。
const props = defineProps<{ target: 'main' | 'worktree'; targetId: string }>()
const emit = defineEmits<{ close: []; committed: [sha: string] }>()
const store = useWorkspacesStore()
const msg = useMessage()
const status = ref<FileStatus[]>([])
const message = ref<string>('')
const push = ref<boolean>(true)
const submitting = ref<boolean>(false)
onMounted(async () => {
try {
status.value =
props.target === 'main'
? await store.statusOnMain(props.targetId)
: await store.statusOnWorktree(props.targetId)
} catch (e: unknown) {
msg.error('读取 git status 失败:' + (e instanceof Error ? e.message : String(e)))
}
})
async function submit() {
if (!message.value.trim()) {
msg.warning('请填写 commit message')
return
}
submitting.value = true
try {
const body = { message: message.value, push: push.value, add_all: true }
const resp =
props.target === 'main'
? await store.commitOnMain(props.targetId, body)
: await store.commitOnWorktree(props.targetId, body)
msg.success('已提交:' + resp.sha.slice(0, 8))
emit('committed', resp.sha)
} catch (e: unknown) {
msg.error('提交失败:' + (e instanceof Error ? e.message : String(e)))
} finally {
submitting.value = false
}
}
</script>