新增 system_prompts 目录、admin.ai_config.read 与 admin-h5「AI」页;本切片不改运行时 Prompt、禁写发布/UGC/真支付。 Co-authored-by: Cursor <cursoragent@cursor.com>
105 lines
3.0 KiB
Vue
105 lines
3.0 KiB
Vue
<script setup lang="ts">
|
|
import { onMounted, ref } from 'vue'
|
|
import { adminApi } from '@/api/client'
|
|
|
|
type Prompt = Awaited<ReturnType<typeof adminApi.systemPrompts>>['items'][number]
|
|
|
|
const loading = ref(false)
|
|
const error = ref('')
|
|
const items = ref<Prompt[]>([])
|
|
const selected = ref<Prompt | null>(null)
|
|
const detailErr = ref('')
|
|
|
|
async function load() {
|
|
loading.value = true
|
|
error.value = ''
|
|
try {
|
|
const res = await adminApi.systemPrompts()
|
|
items.value = res.items || []
|
|
} catch (e) {
|
|
error.value = e instanceof Error ? e.message : '加载失败'
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function openPrompt(id: string) {
|
|
detailErr.value = ''
|
|
try {
|
|
selected.value = await adminApi.systemPrompt(id)
|
|
} catch (e) {
|
|
detailErr.value = e instanceof Error ? e.message : '详情失败'
|
|
selected.value = null
|
|
}
|
|
}
|
|
|
|
function fmtTime(iso?: string) {
|
|
if (!iso) return '—'
|
|
try {
|
|
return new Date(iso).toLocaleString('zh-CN')
|
|
} catch {
|
|
return iso
|
|
}
|
|
}
|
|
|
|
onMounted(load)
|
|
</script>
|
|
|
|
<template>
|
|
<section>
|
|
<h1>AI 配置</h1>
|
|
<p class="muted">SystemPrompt 只读目录 · 本切片不可编辑发布</p>
|
|
<p v-if="loading" class="muted">加载中…</p>
|
|
<p v-else-if="error" class="err">{{ error }}</p>
|
|
<div v-else class="layout">
|
|
<div class="card">
|
|
<h2>系统提示词</h2>
|
|
<p v-if="!items.length" class="muted">暂无</p>
|
|
<table v-else>
|
|
<thead>
|
|
<tr><th>代码</th><th>标题</th><th>版本</th><th>状态</th><th></th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="p in items" :key="p.id">
|
|
<td><code>{{ p.code }}</code></td>
|
|
<td>{{ p.title }}</td>
|
|
<td>v{{ p.version }}</td>
|
|
<td>{{ p.active ? '启用' : '停用' }}{{ p.system ? ' · 系统' : '' }}</td>
|
|
<td><button class="btn" type="button" @click="openPrompt(p.id)">查看</button></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="card">
|
|
<h2>正文</h2>
|
|
<p v-if="detailErr" class="err">{{ detailErr }}</p>
|
|
<template v-else-if="selected">
|
|
<p class="meta">{{ selected.title }} · 更新 {{ fmtTime(selected.updated_at) }}</p>
|
|
<pre>{{ selected.body }}</pre>
|
|
</template>
|
|
<p v-else class="muted">选择左侧提示词查看正文</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<style scoped>
|
|
h1 { margin: 0 0 0.35rem; font-size: 1.35rem; }
|
|
h2 { margin: 0 0 0.6rem; font-size: 1.05rem; }
|
|
.layout { display: grid; grid-template-columns: 1fr 1.1fr; gap: 1rem; margin-top: 1rem; }
|
|
.meta { color: var(--muted); font-size: 0.85rem; margin-bottom: 0.5rem; }
|
|
pre {
|
|
margin: 0;
|
|
white-space: pre-wrap;
|
|
word-break: break-word;
|
|
font-size: 0.85rem;
|
|
line-height: 1.45;
|
|
border: 1px solid var(--line);
|
|
border-radius: 10px;
|
|
padding: 0.75rem;
|
|
background: rgba(255, 253, 251, 0.8);
|
|
}
|
|
code { font-size: 0.8rem; }
|
|
@media (max-width: 900px) { .layout { grid-template-columns: 1fr; } }
|
|
</style>
|