refactor: 重构项目结构,迁移后端至 mengyastore-backend-go,新增 Java 后端、前端功能更新及部署文档

This commit is contained in:
2026-03-27 15:10:53 +08:00
parent 84874707f5
commit 63781358b2
71 changed files with 2123 additions and 250 deletions

View File

@@ -135,7 +135,7 @@ const load = async () => {
loading.value = true
try {
conversations.value = await fetchAdminAllConversations(props.adminToken)
// Refresh current conversation messages if one is selected
// 若当前已选中某个会话,则刷新其消息列表
if (selectedAccount.value) {
currentMessages.value = conversations.value[selectedAccount.value] || []
await scrollThreadBottom()

View File

@@ -98,7 +98,7 @@ const pagedOrders = computed(() => {
return props.orders.slice(start, start + PAGE_SIZE)
})
// Reset to page 1 when orders list changes
// 订单列表变化时重置到第一页
watch(() => props.orders.length, () => { currentPage.value = 1 })
const remove = (id) => {

View File

@@ -5,26 +5,35 @@
<span class="smtp-desc tag">下单/发货时自动给用户发送通知邮件支持 QQ / 163 / Gmail / 自定义域名邮箱</span>
<span v-if="message" class="msg-tag" :class="{ error: message.includes('失败') }">{{ message }}</span>
</div>
<div class="smtp-fields">
<div class="smtp-enable-row">
<label class="smtp-toggle">
<input type="checkbox" v-model="form.enabled" />
<span>启用邮件通知</span>
</label>
<span class="smtp-status-tag" :class="form.enabled ? 'tag-on' : 'tag-off'">
{{ form.enabled ? '已启用' : '已关闭' }}
</span>
</div>
<div class="smtp-fields" :class="{ 'smtp-fields-disabled': !form.enabled }">
<label class="smtp-field">
<span>发件邮箱</span>
<input v-model="form.email" type="email" placeholder="noreply@yourdomain.com" />
<input v-model="form.email" type="email" placeholder="noreply@yourdomain.com" :disabled="!form.enabled" />
</label>
<label class="smtp-field">
<span>SMTP 密码 / 授权码</span>
<input v-model="form.password" type="password" placeholder="QQ/163 填授权码;其他填密码" autocomplete="new-password" />
<input v-model="form.password" type="password" placeholder="QQ/163 填授权码;其他填密码" autocomplete="new-password" :disabled="!form.enabled" />
</label>
<label class="smtp-field">
<span>发件人名称</span>
<input v-model="form.fromName" type="text" placeholder="萌芽小店" />
<input v-model="form.fromName" type="text" placeholder="萌芽小店" :disabled="!form.enabled" />
</label>
<label class="smtp-field">
<span>SMTP 主机</span>
<input v-model="form.host" type="text" placeholder="smtp.qq.com" />
<input v-model="form.host" type="text" placeholder="smtp.qq.com" :disabled="!form.enabled" />
</label>
<label class="smtp-field smtp-field-port">
<span>端口</span>
<input v-model="form.port" type="text" placeholder="465" />
<input v-model="form.port" type="text" placeholder="465" :disabled="!form.enabled" />
</label>
<button class="primary smtp-save-btn" type="button" :disabled="saving" @click="save">
{{ saving ? '保存中...' : '保存配置' }}
@@ -46,6 +55,7 @@ const emit = defineEmits(['save'])
const saving = ref(false)
const form = reactive({
enabled: true,
email: '',
password: '',
fromName: '',
@@ -55,6 +65,7 @@ const form = reactive({
watch(() => props.config, (cfg) => {
if (!cfg) return
form.enabled = cfg.enabled !== false
form.email = cfg.email || ''
form.password = cfg.password || ''
form.fromName = cfg.fromName || ''
@@ -101,6 +112,47 @@ const save = async () => {
color: var(--muted);
}
.smtp-enable-row {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 12px;
}
.smtp-toggle {
display: flex;
align-items: center;
gap: 6px;
cursor: pointer;
font-size: 14px;
color: var(--text);
font-weight: 500;
}
.smtp-toggle input[type="checkbox"] {
width: 16px;
height: 16px;
accent-color: var(--accent);
cursor: pointer;
}
.smtp-status-tag {
font-size: 12px;
font-weight: 600;
padding: 2px 8px;
border-radius: 999px;
}
.tag-on {
background: rgba(74, 222, 128, 0.15);
color: #2d8a4e;
}
.tag-off {
background: rgba(0,0,0,0.06);
color: #888;
}
.smtp-fields {
display: flex;
gap: 10px;
@@ -108,6 +160,11 @@ const save = async () => {
align-items: flex-end;
}
.smtp-fields-disabled {
opacity: 0.45;
pointer-events: none;
}
.smtp-field {
display: flex;
flex-direction: column;

View File

@@ -3,8 +3,7 @@
<div class="form-field token-field">
<label>管理 Token</label>
<div class="token-input-wrap">
<input :value="token" @input="$emit('update:token', $event.target.value)" placeholder="粘贴 token 后自动加载…" />
<button class="ghost small" type="button" @click="$emit('auto-get')">自动获取</button>
<input :value="token" @input="$emit('update:token', $event.target.value)" placeholder="粘贴管理员令牌后自动加载…" />
</div>
</div>
<p
@@ -28,7 +27,7 @@ defineProps({
inlineMessage: { type: String, default: '' }
})
defineEmits(['update:token', 'auto-get'])
defineEmits(['update:token'])
</script>
<style scoped>