Add admin-frontend and user-frontend standalone projects, certification/invoice/discovery features, fix auth header and theme consistency

This commit is contained in:
TradeMate Dev
2026-05-22 18:35:30 +08:00
parent 18c6cf5406
commit 52dba37f22
79 changed files with 10333 additions and 248 deletions
+70
View File
@@ -0,0 +1,70 @@
<template>
<div>
<el-card v-for="cfg in configs" :key="cfg.key" shadow="never" class="cfg-card">
<template #header>
<div class="cfg-header">
<span>{{ configLabels[cfg.key] || cfg.key }}</span>
<el-tag size="small" v-if="cfg.description">{{ cfg.description }}</el-tag>
</div>
</template>
<div v-if="typeof cfg.value === 'object' && !Array.isArray(cfg.value)">
<div class="cfg-field" v-for="(v, k) in cfg.value" :key="k">
<span class="cfg-label">{{ fieldLabel(cfg.key, k) }}</span>
<el-input v-if="typeof v === 'string'" v-model="edits[cfg.key][k]" size="small" style="width:300px" />
<el-input-number v-else-if="typeof v === 'number'" v-model="edits[cfg.key][k]" size="small" />
<el-switch v-else-if="typeof v === 'boolean'" v-model="edits[cfg.key][k]" />
<el-input v-else v-model="edits[cfg.key][k]" type="textarea" :rows="2" size="small" style="width:400px" />
</div>
</div>
<div v-else-if="typeof cfg.value === 'boolean'">
<el-switch v-model="edits[cfg.key]" />
</div>
<div v-else>
<el-input v-model="edits[cfg.key]" type="textarea" :rows="3" style="max-width:600px" />
</div>
<div class="cfg-actions">
<el-button type="success" size="small" @click="save(cfg.key)">保存</el-button>
</div>
</el-card>
<el-empty v-if="!configs.length" description="暂无配置" />
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { listConfig, updateConfig } from '@/api'
const configs = ref([])
const edits = reactive({})
const configLabels = { system_maintenance: '系统维护', feature_flags: '功能开关', translation_providers: '翻译服务', ai_model_config: 'AI模型', cache_ttl: '缓存时间' }
const fieldLabelsMap = { system_maintenance: { maintenance_mode: '维护模式', maintenance_message: '维护消息' }, feature_flags: { feature_wechat_login: '微信登录', feature_export: '数据导出' }, translation_providers: { primary: '首选服务', fallback: '备用服务' }, ai_model_config: { default_model: '默认模型', max_tokens: '最大Token' } }
function fieldLabel(key, k) { return fieldLabelsMap[key]?.[k] || k }
async function load() {
try {
const r = await listConfig()
configs.value = r.items || r || []
for (const cfg of configs.value) {
edits[cfg.key] = JSON.parse(JSON.stringify(cfg.value))
}
} catch (e) { console.error(e) }
}
async function save(key) {
try {
await updateConfig(key, edits[key])
ElMessage.success('已保存')
} catch (e) { ElMessage.error(e?.detail || '保存失败') }
}
onMounted(load)
</script>
<style scoped>
.cfg-card { margin-bottom: 16px; }
.cfg-header { display: flex; align-items: center; gap: 12px; font-weight: 600; }
.cfg-field { display: flex; align-items: center; gap: 12px; padding: 8px 0; }
.cfg-label { width: 160px; font-size: 13px; color: #666; flex-shrink: 0; }
.cfg-actions { margin-top: 12px; }
</style>