feat: 官网代码全量更新 (2026-04-18)

这个提交包含在:
wx
2026-04-18 15:13:28 +08:00
父节点 fcac8f88db
当前提交 f91ecbb093
共修改 135 个文件,包含 10307 行新增和 3349 行删除
+40
查看文件
@@ -0,0 +1,40 @@
// 通用排序工具:在分页列表内与相邻行交换 sortOrder
// 用法:
// const { swapAdjacent } = useAdminSort('/api/admin/faqs')
// await swapAdjacent(currentRow, neighborRow) // 把两条的 sortOrder 字段互换并落库
export function useAdminSort(apiBase) {
const { adminFetch } = useAdmin()
async function swapAdjacent(a, b) {
if (!a || !b) return
const orderA = a.sortOrder ?? 0
const orderB = b.sortOrder ?? 0
// 同时发两次 PUT(并行)
await Promise.all([
adminFetch(`${apiBase}/${a.id}`, { method: 'PUT', body: { sortOrder: orderB } }),
adminFetch(`${apiBase}/${b.id}`, { method: 'PUT', body: { sortOrder: orderA } }),
])
a.sortOrder = orderB
b.sortOrder = orderA
}
// 在列表内按 UI 位置上移/下移(仅与相邻行交换)
async function moveUp(list, index) {
if (index <= 0) return
const a = list[index]
const b = list[index - 1]
await swapAdjacent(a, b)
// UI 顺序也要立即交换,让人看见结果
;[list[index - 1], list[index]] = [list[index], list[index - 1]]
}
async function moveDown(list, index) {
if (index >= list.length - 1) return
const a = list[index]
const b = list[index + 1]
await swapAdjacent(a, b)
;[list[index], list[index + 1]] = [list[index + 1], list[index]]
}
return { swapAdjacent, moveUp, moveDown }
}
+1 -1
查看文件
@@ -300,7 +300,7 @@ export function useHowToSchema(sections) {
'@context': 'https://schema.org',
'@type': 'HowTo',
name: '呼伦贝尔出行准备指南',
description: '呼籁旅行根据11年带队经验整理的呼伦贝尔出行指南:证件准备、各月穿搭建议(含气温数据)、行李清单、骑马/ATV/滑草安全须知、0-3岁幼童活动推荐、实用信息汇总。',
description: '呼籁旅行根据11年带队经验整理的呼伦贝尔出行指南:证件准备、各月穿搭建议(含气温数据)、行李清单、骑马/全地形越野车/滑草安全须知、0-3岁幼童活动推荐、实用信息汇总。',
step: steps,
totalTime: 'PT30M',
estimatedCost: { '@type': 'MonetaryAmount', currency: 'CNY', value: '0' },
+33
查看文件
@@ -0,0 +1,33 @@
/**
* 栏目标题(CommonSectionTitle)统一读取器
*
* 用法:
* const st = await useSectionTitles()
* <CommonSectionTitle
* :title="st('summerCamp.principles', '行程设计四大原则')"
* :subtitle="st('summerCamp.principles', '每一处安排都经过精心考量', 'subtitle')"
* />
*
* st(path, fallback, field = 'title') 三个参数都是字符串。
* field 可选 'title' | 'subtitle' | 'label'。
*/
export async function useSectionTitles() {
const { data } = await usePublicApi('section-titles')
return (path, fallback = '', field = 'title') => {
const parts = (path || '').split('.')
let cursor = data.value
for (const p of parts) {
if (cursor && typeof cursor === 'object' && p in cursor) {
cursor = cursor[p]
} else {
return fallback
}
}
if (cursor && typeof cursor === 'object') {
return cursor[field] || fallback
}
return fallback
}
}