initialize project with Vue 3, Vite, and Element Plus; set up basic routing, components, configuration, and project structure

This commit is contained in:
2025-12-14 18:55:20 +08:00
commit 0959754d1e
24 changed files with 5575 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import axios from 'axios'
import { ElMessage } from 'element-plus'
const props = defineProps({
inline: {
type: Boolean,
default: false,
},
})
const emit = defineEmits(['created'])
const router = useRouter()
const apiBase = import.meta.env.VITE_API_BASE || 'http://localhost:8000/api'
const creating = ref(false)
const sessionName = ref('')
const lastSessionId = ref(localStorage.getItem('ars-last-session') || '')
const popoverVisible = ref(false)
const togglePopover = () => {
popoverVisible.value = !popoverVisible.value
}
const createSession = async () => {
const token = localStorage.getItem('ars-token') || ''
if (!token) {
router.replace({ name: 'login' })
return
}
creating.value = true
const payload = {
session_name: sessionName.value.trim() || '新会话',
}
try {
const { data } = await axios.post(`${apiBase}/sessions`, payload, {
headers: { Authorization: `Bearer ${token}` },
})
lastSessionId.value = data.session_id
localStorage.setItem('ars-last-session', data.session_id)
ElMessage.success('新会话已创建')
sessionName.value = ''
popoverVisible.value = false
emit('created', data)
} catch (err) {
const message = err.response?.data?.message || '创建会话失败'
ElMessage.error(message)
if (err.response?.status === 401) {
router.replace({ name: 'login' })
}
} finally {
creating.value = false
}
}
</script>
<template>
<el-popover
v-model:visible="popoverVisible"
trigger="manual"
placement="bottom-start"
popper-class="mini-popper"
width="260"
:teleported="false"
>
<template #reference>
<button
class="new-chat-btn"
:class="{ inline: props.inline }"
aria-label="新建会话"
data-testid="new-chat-trigger"
@click.stop="togglePopover"
>
<span class="plus"></span>
<span class="label">新建聊天</span>
</button>
</template>
<div class="new-chat-card">
<p class="title">新建 Chat Session</p>
<el-input
v-model="sessionName"
size="large"
placeholder="可选:会话名称"
data-testid="session-name"
/>
<el-button
type="primary"
class="create-btn"
color="#1d4ed8"
:loading="creating"
data-testid="create-session"
@click="createSession"
>
创建
</el-button>
<p v-if="lastSessionId" class="last">
最近会话<code>{{ lastSessionId }}</code>
</p>
</div>
</el-popover>
</template>
<style scoped>
.new-chat-btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
border-radius: 12px;
border: 1px solid rgba(0, 0, 0, 0.08);
background: rgba(255, 255, 255, 0.88);
box-shadow: 0 8px 20px rgba(17, 24, 39, 0.12);
cursor: pointer;
transition: transform 0.18s ease, box-shadow 0.18s ease;
color: #111827;
}
.new-chat-btn.inline {
width: 100%;
justify-content: center;
box-shadow: none;
border: 1px solid rgba(0, 0, 0, 0.04);
}
.new-chat-btn:hover {
transform: translateY(-2px);
box-shadow: 0 12px 28px rgba(17, 24, 39, 0.15);
}
.plus {
font-size: 18px;
font-weight: 700;
}
.label {
font-weight: 700;
letter-spacing: 0.02em;
}
.new-chat-card {
display: flex;
flex-direction: column;
gap: 10px;
}
.title {
margin: 0;
font-weight: 700;
color: #0f172a;
}
.create-btn {
width: 100%;
font-weight: 700;
}
.last {
margin: 0;
font-size: 12px;
color: #4b5563;
word-break: break-all;
}
</style>