bd7635986a
Vue 前端 + FastAPI 后端,含部署脚本与词典数据。 Co-authored-by: Cursor <cursoragent@cursor.com>
125 lines
3.5 KiB
Vue
125 lines
3.5 KiB
Vue
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
import { api, type TranslateResult } from '../api/request'
|
|
|
|
const input = ref('')
|
|
const result = ref<TranslateResult | null>(null)
|
|
const message = ref('')
|
|
const messageType = ref<'success' | 'error'>('success')
|
|
const loading = ref(false)
|
|
|
|
async function handleTranslate() {
|
|
if (!input.value.trim()) return
|
|
loading.value = true
|
|
message.value = ''
|
|
result.value = null
|
|
try {
|
|
const { data } = await api.translate(input.value.trim())
|
|
result.value = data
|
|
} catch (e: unknown) {
|
|
const err = e as { response?: { data?: { detail?: string } } }
|
|
message.value = err.response?.data?.detail || '翻译失败'
|
|
messageType.value = 'error'
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function addToLibrary() {
|
|
if (!result.value) return
|
|
message.value = ''
|
|
try {
|
|
await api.createWord({
|
|
source_text: result.value.source_text,
|
|
target_text: result.value.target_text,
|
|
source_lang: result.value.source_lang,
|
|
target_lang: result.value.target_lang,
|
|
phonetic: result.value.phonetic,
|
|
example_en: result.value.example_en,
|
|
example_cn: result.value.example_cn,
|
|
})
|
|
message.value = '已加入单词库 ✅'
|
|
messageType.value = 'success'
|
|
} catch (e: unknown) {
|
|
const err = e as { response?: { data?: { detail?: string } } }
|
|
message.value = err.response?.data?.detail || '添加失败'
|
|
messageType.value = 'error'
|
|
}
|
|
}
|
|
|
|
const langLabel = (s: string, t: string) =>
|
|
s === 'zh' ? '中文 → 英文' : '英文 → 中文'
|
|
</script>
|
|
|
|
<template>
|
|
<div class="page">
|
|
<h1 class="page-title">翻译</h1>
|
|
<textarea
|
|
v-model="input"
|
|
class="input translate-input"
|
|
rows="3"
|
|
placeholder="输入中文或英文,例如:苹果 或 apple"
|
|
/>
|
|
<button class="btn btn-primary" style="margin-top: 12px" :disabled="loading" @click="handleTranslate">
|
|
{{ loading ? '翻译中...' : '翻译' }}
|
|
</button>
|
|
|
|
<div v-if="message" :class="['message', messageType]">{{ message }}</div>
|
|
|
|
<div v-if="result" class="card result-card">
|
|
<div class="lang-dir">{{ langLabel(result.source_lang, result.target_lang) }}</div>
|
|
<div class="result-row">
|
|
<span class="label-sm">原文</span>
|
|
<span>{{ result.source_text }}</span>
|
|
</div>
|
|
<div class="result-row main">
|
|
<span class="label-sm">译文</span>
|
|
<span>{{ result.target_text }}</span>
|
|
</div>
|
|
<div v-if="result.phonetic" class="result-row">
|
|
<span class="label-sm">音标</span>
|
|
<span>{{ result.phonetic }}</span>
|
|
</div>
|
|
<div v-if="result.example_en" class="result-row">
|
|
<span class="label-sm">英文例句</span>
|
|
<span>{{ result.example_en }}</span>
|
|
</div>
|
|
<div v-if="result.example_cn" class="result-row">
|
|
<span class="label-sm">中文例句</span>
|
|
<span>{{ result.example_cn }}</span>
|
|
</div>
|
|
<button class="btn btn-primary" style="margin-top: 14px" @click="addToLibrary">
|
|
加入单词库
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.translate-input {
|
|
resize: vertical;
|
|
min-height: 80px;
|
|
font-family: inherit;
|
|
}
|
|
.result-card { margin-top: 16px; }
|
|
.lang-dir {
|
|
font-size: 12px;
|
|
color: var(--primary);
|
|
margin-bottom: 12px;
|
|
}
|
|
.result-row {
|
|
margin-bottom: 10px;
|
|
font-size: 15px;
|
|
}
|
|
.result-row.main {
|
|
font-size: 22px;
|
|
font-weight: 700;
|
|
}
|
|
.label-sm {
|
|
display: block;
|
|
font-size: 12px;
|
|
color: var(--muted);
|
|
margin-bottom: 2px;
|
|
}
|
|
</style>
|