feat: 官网代码全量更新 (2026-04-18)
这个提交包含在:
+41
-5
@@ -46,6 +46,29 @@
|
||||
<n-form-item label="副标题">
|
||||
<n-input v-model:value="form.subtitle" placeholder="输入副标题(可选)" />
|
||||
</n-form-item>
|
||||
<n-form-item label="卡片摘要">
|
||||
<n-input
|
||||
v-model:value="form.summary"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="在客户故事墙卡片上展示的 1-2 句话(代替副标题)"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-grid :cols="2" :x-gap="16">
|
||||
<n-gi>
|
||||
<n-form-item label="作者 / 客户昵称">
|
||||
<n-input v-model:value="form.author" placeholder="如:张女士" />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item label="外部来源 URL">
|
||||
<n-input v-model:value="form.sourceUrl" placeholder="如小红书链接,有则卡片外跳" />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
<n-form-item label="标签">
|
||||
<n-dynamic-tags v-model:value="form.tags" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-card>
|
||||
|
||||
@@ -169,6 +192,12 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
NBreadcrumb, NBreadcrumbItem, NButton, NSpace, NCard, NGrid, NGi,
|
||||
NForm, NFormItem, NInput, NSelect, NDynamicInput, NDynamicTags,
|
||||
useMessage,
|
||||
} from 'naive-ui'
|
||||
|
||||
definePageMeta({ layout: 'admin', middleware: 'admin' })
|
||||
|
||||
const route = useRoute()
|
||||
@@ -184,6 +213,10 @@ const form = ref({
|
||||
title: '',
|
||||
slug: '',
|
||||
subtitle: '',
|
||||
summary: '',
|
||||
author: '',
|
||||
sourceUrl: '',
|
||||
tags: [],
|
||||
familyType: '',
|
||||
childrenAge: '',
|
||||
fromCity: '',
|
||||
@@ -205,6 +238,12 @@ async function loadItem() {
|
||||
...data,
|
||||
published: !!data.published,
|
||||
coverImage: data.coverImage || '',
|
||||
summary: data.summary || '',
|
||||
author: data.author || '',
|
||||
sourceUrl: data.sourceUrl || '',
|
||||
tags: Array.isArray(data.tags)
|
||||
? data.tags
|
||||
: (typeof data.tags === 'string' ? (() => { try { return JSON.parse(data.tags || '[]') } catch { return [] } })() : []),
|
||||
sections:
|
||||
typeof data.sections === 'string'
|
||||
? JSON.parse(data.sections || '[]')
|
||||
@@ -233,11 +272,8 @@ async function handleSave() {
|
||||
|
||||
saving.value = true
|
||||
|
||||
const payload = {
|
||||
...form.value,
|
||||
sections: JSON.stringify(form.value.sections),
|
||||
keyMoments: JSON.stringify(form.value.keyMoments),
|
||||
}
|
||||
// 直接传数组,由服务端统一 stringify,避免双重编码
|
||||
const payload = { ...form.value }
|
||||
|
||||
try {
|
||||
if (isNew.value) {
|
||||
|
||||
@@ -37,10 +37,19 @@ definePageMeta({ layout: 'admin', middleware: 'admin' })
|
||||
|
||||
const { adminFetch } = useAdmin()
|
||||
const message = useMessage()
|
||||
const { moveUp, moveDown } = useAdminSort('/api/admin/stories')
|
||||
const list = ref([]); const total = ref(0); const page = ref(1); const totalPages = ref(1); const loading = ref(false); const search = ref('')
|
||||
|
||||
const columns = [
|
||||
{ title: 'ID', key: 'id', width: 50, render: (row) => h('span', { style: 'color: #9ca3af; font-size: 12px' }, row.id) },
|
||||
{
|
||||
title: '排序', key: 'sortOrder', width: 110,
|
||||
render: (row, idx) => h(NSpace, { size: 4, align: 'center' }, () => [
|
||||
h('span', { style: 'color: #9ca3af; font-size: 12px; min-width: 20px' }, row.sortOrder),
|
||||
h(NButton, { size: 'tiny', disabled: idx === 0, onClick: async () => { await moveUp(list.value, idx); message.success('已上移') } }, () => '↑'),
|
||||
h(NButton, { size: 'tiny', disabled: idx === list.value.length - 1, onClick: async () => { await moveDown(list.value, idx); message.success('已下移') } }, () => '↓'),
|
||||
]),
|
||||
},
|
||||
{
|
||||
title: '标题', key: 'title',
|
||||
render: (row) => h('a', { style: 'color: #111827; text-decoration: none; font-weight: 500; cursor: pointer', onClick: () => navigateTo(`/admin/stories/${row.id}`) }, row.title),
|
||||
|
||||
在新工单中引用
屏蔽一个用户