120 lines
3.1 KiB
Vue
120 lines
3.1 KiB
Vue
<!-- Author: fruit.com.cn -->
|
||
|
||
<script setup lang="ts">
|
||
import { onMounted, reactive, ref } from 'vue'
|
||
import { ElMessage } from 'element-plus'
|
||
import {
|
||
listLegalDocumentsApi,
|
||
saveLegalDocumentsApi,
|
||
type LegalDocument
|
||
} from '@/api/admin/legalDocument'
|
||
|
||
const languages = [
|
||
{ code: 'zh', label: '中文' },
|
||
{ code: 'en', label: 'English' },
|
||
{ code: 'id', label: 'Indonesia' }
|
||
]
|
||
|
||
const documents = [
|
||
{ code: 'terms', label: '服务条款', path: '/terms' },
|
||
{ code: 'privacy', label: '隐私协议', path: '/privacy' }
|
||
]
|
||
|
||
const loading = ref(false)
|
||
const saving = ref(false)
|
||
const activeDoc = ref('terms')
|
||
const form = reactive<Record<string, LegalDocument>>({})
|
||
|
||
const blank = (docCode: string, lang: string): LegalDocument => ({
|
||
docCode,
|
||
lang,
|
||
title: '',
|
||
content: ''
|
||
})
|
||
|
||
const fieldKey = (docCode: string, lang: string) => `${docCode}:${lang}`
|
||
|
||
function ensureFields() {
|
||
for (const doc of documents) {
|
||
for (const lang of languages) {
|
||
const key = fieldKey(doc.code, lang.code)
|
||
if (!form[key]) form[key] = blank(doc.code, lang.code)
|
||
}
|
||
}
|
||
}
|
||
|
||
async function load() {
|
||
loading.value = true
|
||
try {
|
||
ensureFields()
|
||
const res = await listLegalDocumentsApi()
|
||
for (const item of res.data || []) {
|
||
form[fieldKey(item.docCode, item.lang)] = { ...item }
|
||
}
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
async function save() {
|
||
saving.value = true
|
||
try {
|
||
ensureFields()
|
||
const items = documents.flatMap((doc) =>
|
||
languages.map((lang) => ({ ...form[fieldKey(doc.code, lang.code)], title: '' }))
|
||
)
|
||
await saveLegalDocumentsApi(items)
|
||
ElMessage.success('协议已保存')
|
||
await load()
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
|
||
onMounted(load)
|
||
ensureFields()
|
||
</script>
|
||
|
||
<template>
|
||
<div class="page-heading">
|
||
<div>
|
||
<div class="eyebrow">系统管理</div>
|
||
<h1>协议设置</h1>
|
||
<p>服务条款与隐私协议各维护中文、英文、印尼语。正文用 Markdown,打开后的页面不另加标题。</p>
|
||
</div>
|
||
</div>
|
||
<section v-loading="loading" class="panel settings-panel">
|
||
<el-tabs v-model="activeDoc">
|
||
<el-tab-pane v-for="doc in documents" :key="doc.code" :name="doc.code" :label="doc.label" />
|
||
</el-tabs>
|
||
<template v-for="doc in documents" :key="doc.code">
|
||
<div v-show="activeDoc === doc.code">
|
||
<p class="legal-path"
|
||
>公开地址:{{ doc.path }}/zh 、{{ doc.path }}/en 、{{ doc.path }}/id</p
|
||
>
|
||
<div v-for="lang in languages" :key="`${doc.code}-${lang.code}`" class="legal-block">
|
||
<h2>{{ lang.label }}</h2>
|
||
<el-input
|
||
v-model="form[`${doc.code}:${lang.code}`].content"
|
||
type="textarea"
|
||
:rows="14"
|
||
placeholder="直接写 Markdown,页面不再另加标题"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<el-button type="primary" :loading="saving" @click="save">保存</el-button>
|
||
</section>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.legal-path {
|
||
margin: 0 0 12px;
|
||
color: var(--el-text-color-secondary);
|
||
}
|
||
|
||
.legal-block + .legal-block {
|
||
margin-top: 8px;
|
||
}
|
||
</style>
|