Files
trade-assistant/admin-frontend/src/views/Quota.vue
T
TradeMate Dev f17a6ccbac chore: post-deployment cleanup and docs update
- Make AI routing rules DB-driven (read from system_configs, removed from config.py)
- Add translation quota tracking to LLM translation (OpenAIProvider)
- Add Alibaba MT ECS RAM role support (STS token, no AccessKey needed)
- Fix admin sidebar link for AI模型配置 page
- Fix Quota.vue API path (quotas → translation-quotas)
- Fix login auto-redirect to dashboard
- Add provider dropdown selects to AI routing config UI
- Clean up stale ai_provider_* system_configs records
- Remove OpencodeGo, Spark providers (code + DB)
- Update deploy config: nginx port 8000, systemd cwd
2026-06-02 15:40:02 +08:00

87 lines
3.5 KiB
Vue

<template>
<div>
<div v-for="q in quotas" :key="q.version" class="quota-card">
<el-card shadow="never">
<template #header>
<div class="quota-header">
<span class="quota-version">{{ { ecommerce: '电商版', general: '通用版', llm: 'AI模型翻译' }[q.version] || q.version }}</span>
<el-tag size="small" v-if="q.description">{{ q.description }}</el-tag>
</div>
</template>
<div class="quota-stat">
<span class="quota-label">{{ q.current_month || '当前月' }}</span>
<el-progress :percentage="quotaPercent(q)" :stroke-width="20" />
<span class="quota-value">{{ q.used_chars }} / {{ q.monthly_limit }}</span>
</div>
<div class="quota-actions">
<el-form :inline="true" size="small">
<el-form-item label="月限额">
<el-input-number :model-value="q._edit_limit !== undefined ? q._edit_limit : q.monthly_limit" :min="1000" :step="10000" style="width:140px" @update:model-value="q._edit_limit=$event" />
</el-form-item>
<el-form-item label="启用">
<el-switch :model-value="q._edit_enabled !== undefined ? q._edit_enabled : q.enabled" @update:model-value="q._edit_enabled=$event" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="save(q)">保存</el-button>
<el-button @click="resetQuota(q.version)">重置用量</el-button>
</el-form-item>
</el-form>
</div>
</el-card>
</div>
<el-empty v-if="!quotas.length" description="暂无配额数据" />
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { listQuotas, updateQuota, resetQuota as resetApi } from '@/api'
const quotas = ref([])
function quotaPercent(q) {
const limit = q.monthly_limit || 1
return Math.min(100, Math.round((q.used_chars / limit) * 100))
}
async function load() {
try {
const r = await listQuotas()
quotas.value = (r.items || r || []).map(q => ({ ...q, _edit_limit: undefined, _edit_enabled: undefined }))
} catch (e) { console.error(e) }
}
async function save(q) {
try {
const data = {}
if (q._edit_limit !== undefined && q._edit_limit !== null) data.monthly_limit = q._edit_limit
if (q._edit_enabled !== undefined && q._edit_enabled !== null) data.enabled = q._edit_enabled
if (!Object.keys(data).length) { ElMessage.info('无改动'); return }
await updateQuota(q.version, data)
if (data.monthly_limit !== undefined) q.monthly_limit = data.monthly_limit
if (data.enabled !== undefined) q.enabled = data.enabled
q._edit_limit = undefined; q._edit_enabled = undefined
ElMessage.success('已保存')
} catch (e) { ElMessage.error(e?.detail || '保存失败') }
}
async function resetQuota(version) {
try { await resetApi(version); ElMessage.success('已重置'); load() }
catch (e) { ElMessage.error(e?.detail || '重置失败') }
}
onMounted(load)
</script>
<style scoped>
.quota-card { margin-bottom: 16px; }
.quota-header { display: flex; align-items: center; gap: 12px; }
.quota-version { font-size: 15px; font-weight: 600; }
.quota-stat { display: flex; align-items: center; gap: 16px; margin-bottom: 16px; }
.quota-label { width: 80px; font-size: 13px; color: #666; flex-shrink: 0; }
.el-progress { flex: 1; }
.quota-value { width: 180px; font-size: 13px; color: #333; text-align: right; flex-shrink: 0; }
.quota-actions { }
</style>