173 lines
6.5 KiB
Vue
173 lines
6.5 KiB
Vue
<script setup lang="ts">
|
||
import { computed, onMounted, ref } from "vue";
|
||
import { ElMessage } from "element-plus";
|
||
import { adminApi, type AdminContentPolicyConfig, type AdminContentPolicyItem, type AdminHelpArticleItem } from "../../api/admin";
|
||
import { createPolicyItem, normalizePolicyConfig } from "./shared";
|
||
|
||
const loading = ref(false);
|
||
const saving = ref(false);
|
||
const articles = ref<AdminHelpArticleItem[]>([]);
|
||
const policyForm = ref<AdminContentPolicyConfig>({
|
||
legal_entries: [],
|
||
appraisal_agreements: [],
|
||
});
|
||
|
||
const helpArticleOptions = computed(() =>
|
||
articles.value.map((item) => ({
|
||
label: `${item.title}(${item.category_text})`,
|
||
value: item.id,
|
||
})),
|
||
);
|
||
|
||
async function fetchPolicy() {
|
||
loading.value = true;
|
||
try {
|
||
const [policyResult, articleResult] = await Promise.all([
|
||
adminApi.getContentPolicy(),
|
||
adminApi.getHelpArticles(),
|
||
]);
|
||
policyForm.value = normalizePolicyConfig(policyResult.data.policy_config);
|
||
articles.value = articleResult.data.list;
|
||
} catch (error) {
|
||
console.error(error);
|
||
ElMessage.error("协议与说明加载失败");
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
}
|
||
|
||
function addPolicyItem(section: "legal_entries" | "appraisal_agreements") {
|
||
policyForm.value[section].push(createPolicyItem());
|
||
}
|
||
|
||
function removePolicyItem(section: "legal_entries" | "appraisal_agreements", index: number) {
|
||
policyForm.value[section].splice(index, 1);
|
||
}
|
||
|
||
function bindPolicyArticle(item: AdminContentPolicyItem, articleId: number) {
|
||
item.article_id = Number(articleId || 0);
|
||
item.target_url = item.article_id > 0 ? `/pages/help/detail?id=${item.article_id}` : "";
|
||
}
|
||
|
||
async function savePolicy() {
|
||
saving.value = true;
|
||
try {
|
||
const response = await adminApi.saveContentPolicy(policyForm.value);
|
||
policyForm.value = normalizePolicyConfig(response.data.policy_config);
|
||
ElMessage.success("协议与说明已保存");
|
||
} catch (error) {
|
||
console.error(error);
|
||
ElMessage.error("协议与说明保存失败");
|
||
} finally {
|
||
saving.value = false;
|
||
}
|
||
}
|
||
|
||
onMounted(fetchPolicy);
|
||
</script>
|
||
|
||
<template>
|
||
<el-card class="panel-card" shadow="never" v-loading="loading">
|
||
<div class="filters-row" style="justify-content: space-between;">
|
||
<div>
|
||
<div style="font-size: 16px; font-weight: 700;">协议与说明</div>
|
||
<div style="color: var(--admin-text-subtle); margin-top: 6px;">
|
||
维护设置页说明入口,以及下单确认页展示的服务协议、鉴定须知与隐私政策。
|
||
</div>
|
||
</div>
|
||
<el-button type="primary" :loading="saving" @click="savePolicy">保存协议与说明</el-button>
|
||
</div>
|
||
|
||
<el-form label-position="top">
|
||
<el-divider content-position="left">设置页说明入口</el-divider>
|
||
<div v-for="(item, index) in policyForm.legal_entries" :key="`legal-${index}`" class="content-block">
|
||
<div class="content-block__header">
|
||
<div class="content-block__title">入口 {{ index + 1 }}</div>
|
||
<el-button link type="danger" @click="removePolicyItem('legal_entries', index)">删除</el-button>
|
||
</div>
|
||
<el-row :gutter="16">
|
||
<el-col :span="6"><el-form-item label="编码"><el-input v-model="item.code" /></el-form-item></el-col>
|
||
<el-col :span="6"><el-form-item label="标题"><el-input v-model="item.title" /></el-form-item></el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="绑定文章">
|
||
<el-select
|
||
v-model="item.article_id"
|
||
clearable
|
||
filterable
|
||
style="width: 100%"
|
||
placeholder="请选择帮助中心文章"
|
||
@change="bindPolicyArticle(item, Number($event || 0))"
|
||
>
|
||
<el-option v-for="option in helpArticleOptions" :key="option.value" :label="option.label" :value="option.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="24">
|
||
<el-form-item label="详情页链接">
|
||
<el-input v-model="item.target_url" placeholder="/pages/help/detail?id=12" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="24"><el-form-item label="说明"><el-input v-model="item.desc" /></el-form-item></el-col>
|
||
</el-row>
|
||
</div>
|
||
<el-button plain @click="addPolicyItem('legal_entries')">新增设置入口</el-button>
|
||
|
||
<el-divider content-position="left">下单确认协议</el-divider>
|
||
<div v-for="(item, index) in policyForm.appraisal_agreements" :key="`agreement-${index}`" class="content-block">
|
||
<div class="content-block__header">
|
||
<div class="content-block__title">协议 {{ index + 1 }}</div>
|
||
<el-button link type="danger" @click="removePolicyItem('appraisal_agreements', index)">删除</el-button>
|
||
</div>
|
||
<el-row :gutter="16">
|
||
<el-col :span="6"><el-form-item label="编码"><el-input v-model="item.code" /></el-form-item></el-col>
|
||
<el-col :span="6"><el-form-item label="标题"><el-input v-model="item.title" /></el-form-item></el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="绑定文章">
|
||
<el-select
|
||
v-model="item.article_id"
|
||
clearable
|
||
filterable
|
||
style="width: 100%"
|
||
placeholder="请选择帮助中心文章"
|
||
@change="bindPolicyArticle(item, Number($event || 0))"
|
||
>
|
||
<el-option v-for="option in helpArticleOptions" :key="option.value" :label="option.label" :value="option.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="24">
|
||
<el-form-item label="详情页链接">
|
||
<el-input v-model="item.target_url" placeholder="/pages/help/detail?id=12" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="24"><el-form-item label="说明"><el-input v-model="item.desc" /></el-form-item></el-col>
|
||
</el-row>
|
||
</div>
|
||
<el-button plain @click="addPolicyItem('appraisal_agreements')">新增协议项</el-button>
|
||
</el-form>
|
||
</el-card>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.content-block {
|
||
margin-bottom: 18px;
|
||
padding: 16px 18px;
|
||
border: 1px solid var(--admin-border);
|
||
border-radius: 14px;
|
||
background: linear-gradient(180deg, rgba(255, 251, 244, 0.7) 0%, rgba(255, 255, 255, 0.96) 100%);
|
||
}
|
||
|
||
.content-block__header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.content-block__title {
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
color: var(--admin-text);
|
||
}
|
||
</style>
|