Complete V2 user H5 flow

This commit is contained in:
2026-07-06 18:00:21 +08:00
parent 207340973c
commit 86cbed2437
10 changed files with 383 additions and 15 deletions

View File

@@ -1,16 +1,31 @@
<script setup lang="ts">
defineProps<{
import MarkdownIt from "markdown-it";
import { computed } from "vue";
const props = defineProps<{
role: "user" | "assistant";
content: string;
streaming?: boolean;
}>();
const markdown = new MarkdownIt({
breaks: true,
html: false,
linkify: true,
});
const renderedContent = computed(() => {
if (props.role === "user") return props.content;
return markdown.render(props.content || "");
});
</script>
<template>
<article class="message" :class="role">
<div class="avatar">{{ role === "assistant" ? "AI" : "我" }}</div>
<div class="bubble">
<div class="content">{{ content }}</div>
<div v-if="role === 'assistant'" class="content markdown-content" v-html="renderedContent"></div>
<div v-else class="content">{{ renderedContent }}</div>
<span v-if="streaming" class="typing">正在生成</span>
</div>
</article>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts">
import { ref } from "vue";
import type { ChatSession } from "../types/api";
defineProps<{
@@ -11,8 +13,29 @@ const emit = defineEmits<{
close: [];
select: [sessionId: number];
create: [];
rename: [sessionId: number, title: string];
delete: [sessionId: number];
}>();
const editingId = ref<number | null>(null);
const editingTitle = ref("");
function startEdit(session: ChatSession) {
editingId.value = session.id;
editingTitle.value = session.title;
}
function submitEdit(sessionId: number) {
const title = editingTitle.value.trim();
if (title) emit("rename", sessionId, title);
editingId.value = null;
editingTitle.value = "";
}
function confirmDelete(session: ChatSession) {
const ok = window.confirm(`确定删除会话「${session.title}」吗?`);
if (ok) emit("delete", session.id);
}
</script>
<template>
@@ -24,17 +47,27 @@ const emit = defineEmits<{
</div>
<button type="button" class="new-session-btn" @click="emit('create')"> 新聊天</button>
<div class="session-list">
<button
<div
v-for="session in sessions"
:key="session.id"
type="button"
class="session-item"
:class="{ active: session.id === activeSessionId }"
@click="emit('select', session.id)"
>
<span>{{ session.title }}</span>
<small>{{ session.messageCount }} 条消息</small>
</button>
<form v-if="editingId === session.id" class="session-edit" @submit.prevent="submitEdit(session.id)">
<input v-model="editingTitle" maxlength="100" @keydown.escape="editingId = null" />
<button type="submit">保存</button>
</form>
<template v-else>
<button type="button" class="session-main" @click="emit('select', session.id)">
<span>{{ session.title }}</span>
<small>{{ session.messageCount }} 条消息</small>
</button>
<div class="session-actions">
<button type="button" @click="startEdit(session)">改名</button>
<button type="button" @click="confirmDelete(session)">删除</button>
</div>
</template>
</div>
</div>
</aside>
</template>