feat(admin): 新增三语协议设置页
This commit is contained in:
1 parent
91f1f7d793
commit
c1fb6cc21c
3 files changed
+145
No files matched your search
@@ -0,0 +1,18 @@
|
|||||||
|
// Author: fruit.com.cn
|
||||||
|
|
||||||
|
import request from '@/axios'
|
||||||
|
|
||||||
|
export interface LegalDocument {
|
||||||
|
docCode: 'terms' | 'privacy' | string
|
||||||
|
lang: 'zh' | 'en' | 'id' | string
|
||||||
|
title: string
|
||||||
|
content: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listLegalDocumentsApi = () => {
|
||||||
|
return request.get<LegalDocument[]>({ url: '/admin/legal-documents' })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const saveLegalDocumentsApi = (items: LegalDocument[]) => {
|
||||||
|
return request.put<void>({ url: '/admin/legal-documents', data: items })
|
||||||
|
}
|
||||||
@@ -211,6 +211,14 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
|
|||||||
meta: {
|
meta: {
|
||||||
title: '操作日志'
|
title: '操作日志'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'legal-documents',
|
||||||
|
name: 'legal-documents',
|
||||||
|
component: () => import('@/views/systemManagement/LegalDocumentView.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '协议设置'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
<!-- 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>
|
||||||
Reference in new issue
Block a user