feat: fix backend some error;fix frontend display error

This commit is contained in:
2025-07-28 14:14:11 +08:00
parent eeb3b4b0df
commit f1b39d22a5
5 changed files with 470 additions and 241 deletions

View File

@@ -1,257 +1,158 @@
<template>
<div id="app-container">
<h1>临时邮箱</h1>
<div class="email-generator">
<input v-model="randomEmail" type="text" readonly @click="copyToClipboard" title="点击复制"/>
<button @click="generateRandomEmail">生成新地址</button>
</div>
<header class="app-header">
<div class="logo">Email Unlimit</div>
<nav class="nav-links">
<a href="https://gitea.shenjianl.cn/shenjianZ/email-unlimit" target="_blank">Gitee</a>
<a href="#" @click.prevent="showHowItWorks">How it Works</a>
</nav>
</header>
<div class="inbox">
<h2>收件箱 ({{ currentEmail }})</h2>
<button @click="fetchMessages" :disabled="loading">
{{ loading ? '刷新中...' : '刷新邮件' }}
</button>
<div v-if="error" class="error">{{ error }}</div>
<ul v-if="messages.length > 0" class="message-list">
<li v-for="msg in messages" :key="msg.id" @click="selectMessage(msg)" :class="{ selected: selectedMessage && selectedMessage.id === msg.id }">
<div class="sender"><strong>发件人:</strong> {{ msg.sender }}</div>
<div class="subject"><strong>主题:</strong> {{ msg.subject }}</div>
<div class="time">{{ new Date(msg.received_at).toLocaleString() }}</div>
</li>
</ul>
<div v-else class="no-messages">
<p>{{ loading ? '正在加载...' : '收件箱是空的。' }}</p>
<main id="app-main">
<section class="hero-section">
<h1>您的专属临时邮箱无限且私密</h1>
<p>输入任何<code>@shenjianl.cn</code>地址立即在此查看收件箱</p>
<form @submit.prevent="fetchMessages" class="input-group">
<input
type="email"
v-model="recipient"
class="email-input"
placeholder="输入您的临时邮箱地址..."
required
/>
<button type="submit" class="btn btn-primary">查看收件箱</button>
<button @click="generateRandomEmail" type="button" class="btn btn-secondary">随机生成</button>
</form>
</section>
<section class="inbox-section">
<div class="inbox-container">
<div class="message-list">
<div class="message-list-header">
<h2>收件箱</h2>
<button @click="fetchMessages" class="refresh-btn" title="刷新">
&#x21bb;
</button>
</div>
<div v-if="loading" class="loading-state">正在加载...</div>
<div v-else-if="messages.length === 0" class="empty-state">暂无邮件</div>
<div v-else>
<div
v-for="message in messages"
:key="message.id"
class="message-item"
:class="{ selected: selectedMessage && selectedMessage.id === message.id }"
@click="selectMessage(message)"
>
<div class="from">{{ message.sender }}</div>
<div class="subject">{{ message.subject }}</div>
</div>
</div>
</div>
<div class="message-detail">
<div v-if="!selectedMessage" class="empty-state">
<p>请从左侧选择一封邮件查看</p>
</div>
<div v-else>
<div class="message-content-header">
<h3>{{ selectedMessage.subject }}</h3>
<p><strong>发件人:</strong> {{ selectedMessage.sender }}</p>
<p><strong>收件人:</strong> {{ selectedMessage.recipient }}</p>
</div>
<div class="message-body">
{{ selectedMessage.body }}
</div>
</div>
</div>
</div>
</div>
</section>
</main>
<div v-if="selectedMessage" class="message-view">
<h3>{{ selectedMessage.subject }}</h3>
<p><strong>发件人:</strong> {{ selectedMessage.sender }}</p>
<p><strong>收件人:</strong> {{ currentEmail }}</p>
<p><strong>时间:</strong> {{ new Date(selectedMessage.received_at).toLocaleString() }}</p>
<hr>
<div v-html="selectedMessage.body" class="email-body"></div>
<!-- How it Works Modal -->
<div v-if="showModal" class="modal-overlay" @click.self="closeModal">
<div class="modal-content">
<button @click="closeModal" class="close-btn">&times;</button>
<h3>工作原理</h3>
<ol>
<li>在上面的输入框中随意编造一个以<code>@{{ domain }}</code>结尾的邮箱地址</li>
<li>使用这个地址去注册任何网站或接收邮件</li>
<li>在这里输入您刚刚使用的地址点击查看收件箱即可看到邮件</li>
</ol>
</div>
</div>
</template>
<script>
import axios from 'axios';
const API_URL = '/api';
import { ref, onMounted } from 'vue';
export default {
name: 'App',
data() {
return {
randomEmail: '',
currentEmail: '',
messages: [],
selectedMessage: null,
loading: false,
error: null,
domain: 'shenjianl.cn', // 从 info.md 获取
refreshInterval: null
};
},
methods: {
generateRandomString(length) {
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
},
generateRandomEmail() {
const name = this.generateRandomString(8);
this.randomEmail = `${name}@${this.domain}`;
this.currentEmail = this.randomEmail;
this.messages = [];
this.selectedMessage = null;
this.fetchMessages();
},
async fetchMessages() {
if (!this.currentEmail) {
setup() {
const recipient = ref('');
const messages = ref([]);
const selectedMessage = ref(null);
const loading = ref(false);
const showModal = ref(false);
// !!! 生产环境<E78EAF><E5A283>要提示 !!!
// 请务必将下面的 'yourdomain.com' 替换为您的真实域名
const domain = 'shenjianl.cn';
const fetchMessages = async () => {
if (!recipient.value) {
alert('请输入一个邮箱地址');
return;
}
this.loading = true;
this.error = null;
loading.value = true;
selectedMessage.value = null; // Clear selected message on new fetch
try {
const response = await axios.get(`${API_URL}/messages`, {
params: { recipient: this.currentEmail }
});
this.messages = response.data;
// 如果有新邮件,且当前选中了邮件,则更新选中的邮件内容
if (this.selectedMessage) {
const updatedSelected = this.messages.find(m => m.id === this.selectedMessage.id);
if (updatedSelected) {
this.selectedMessage = updatedSelected;
} else {
this.selectedMessage = null; // 如果邮件被删除,则取消选中
}
// API URL 已修改为相对路径,以适配 Nginx 反向代理
const response = await fetch(`/api/messages?recipient=${recipient.value}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
} catch (err) {
this.error = '无法加载邮件。请检查后端服务是否运行。';
console.error(err);
const data = await response.json();
messages.value = data;
// Automatically select the first message if available
if (messages.value.length > 0) {
selectedMessage.value = messages.value[0];
}
} catch (error) {
console.error('Failed to fetch messages:', error);
alert('无法获取邮件,请检查后端服务和 Nginx 配置是否正常。');
} finally {
this.loading = false;
loading.value = false;
}
},
selectMessage(message) {
this.selectedMessage = message;
},
copyToClipboard() {
navigator.clipboard.writeText(this.randomEmail).then(() => {
alert('邮箱地址已复制到剪贴板');
}, (err) => {
console.error('Could not copy text: ', err);
});
},
startAutoRefresh() {
this.refreshInterval = setInterval(this.fetchMessages, 15000); // 每15秒刷新一次
},
stopAutoRefresh() {
if (this.refreshInterval) {
clearInterval(this.refreshInterval);
}
}
};
const selectMessage = (message) => {
selectedMessage.value = message;
};
const generateRandomEmail = () => {
const randomPart = Math.random().toString(36).substring(2, 10);
recipient.value = `${randomPart}@${domain}`;
};
const showHowItWorks = () => {
showModal.value = true;
};
const closeModal = () => {
showModal.value = false;
};
return {
recipient,
messages,
selectedMessage,
loading,
showModal,
domain,
fetchMessages,
selectMessage,
generateRandomEmail,
showHowItWorks,
closeModal,
};
},
created() {
this.generateRandomEmail();
this.startAutoRefresh();
},
beforeUnmount() {
this.stopAutoRefresh();
}
};
</script>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background-color: #f4f7f9;
color: #333;
margin: 0;
padding: 20px;
}
#app-container {
max-width: 900px;
margin: 0 auto;
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
h1, h2, h3 {
color: #2c3e50;
}
.email-generator {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.email-generator input {
flex-grow: 1;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
background: #f9f9f9;
cursor: pointer;
}
button {
padding: 10px 15px;
border: none;
background-color: #42b983;
color: white;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
}
button:hover {
background-color: #36a374;
}
button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.inbox {
margin-bottom: 20px;
}
.message-list {
list-style: none;
padding: 0;
border: 1px solid #eee;
border-radius: 4px;
max-height: 300px;
overflow-y: auto;
}
.message-list li {
padding: 15px;
border-bottom: 1px solid #eee;
cursor: pointer;
transition: background-color 0.2s;
}
.message-list li:last-child {
border-bottom: none;
}
.message-list li:hover {
background-color: #f9f9f9;
}
.message-list li.selected {
background-color: #e8f5e9;
}
.sender, .subject, .time {
margin-bottom: 5px;
}
.time {
font-size: 0.8em;
color: #777;
}
.no-messages {
text-align: center;
padding: 20px;
color: #777;
}
.message-view {
border: 1px solid #eee;
padding: 20px;
border-radius: 4px;
background: #fdfdfd;
}
.email-body {
margin-top: 15px;
white-space: pre-wrap;
word-wrap: break-word;
background-color: #fff;
padding: 1em;
border-radius: 4px;
border: 1px solid #ddd;
overflow: auto;
}
.error {
color: #e74c3c;
margin: 10px 0;
}
</style>
</script>