feat: 新增路线详情关联管家顾问及相关功能

详细变更如下:
- 更新 .gitignore 文件,添加 pnpm-store 忽略规则
- 新增数据库迁移脚本,为 DetailRecord 添加可空的 conciergeAdvisorId 字段用于关联管家顾问
- 完善 Admin 后台玩法详情编辑器,支持选择关联的管家顾问并校验合法性
- 公共 API 支持返回已启用的管家顾问完整数据,不在详情表中冗余存储管家资料
- 小程序端新增详情页联系管家入口、个人页最近浏览历史功能
- 更新所有相关文档与测试用例,修复下拉选择框的 z-index 样式问题
This commit is contained in:
duanshuwen committed 2026-08-22 08:26:23 +08:00
1 parent e7b8c5bf43
commit b7a81964c9
34 files changed
+739 -63

No files matched your search

@@ -28,6 +28,7 @@
price }}万</text>
</view>
<view
v-if="showConcierge"
class="tap-feedback flex items-center justify-center m-0 h-11 rounded-full bg-[#e96635] px-4 text-[13px] font-semibold text-white shadow-[0_6px_16px_rgba(233,102,53,0.22)]"
@click="$emit('concierge')">联系管家</view>
</view>
@@ -38,10 +39,13 @@
<script setup lang="ts">
import { formatWan } from "@/lib/data";
defineProps<{
withDefaults(defineProps<{
price: number;
favorite: boolean;
}>();
showConcierge?: boolean;
}>(), {
showConcierge: true,
});
defineEmits<{
call: [];
@@ -1,5 +1,6 @@
import { playCategories, type PlayRoute } from "../../play/components/playData";
import type { PublicDetail } from "@/lib/types";
import { normalizeConciergeAdvisor } from "../../concierge/components/conciergeTypes";
export type DetailPresentation = PublicDetail;
@@ -30,6 +31,7 @@ function createRouteFallback(route: PlayRoute): DetailPresentation {
"最终行程以出行日期、人数和资源确认结果为准。",
],
gallery: Array.from(new Set([route.image, ...sharedGallery])).slice(0, 5),
conciergeAdvisor: null,
};
}
@@ -75,6 +77,7 @@ export function normalizeDetailPresentation(
const subtitle = cleanText(source.subtitle) || fallback?.subtitle || "";
const intro = cleanText(source.intro) || fallback?.intro || "";
const gallery = cleanGallery(source.gallery);
const conciergeAdvisor = normalizeConciergeAdvisor(source.conciergeAdvisor);
if (!key || !eyebrow || !duration || !title || !subtitle || !intro) {
return fallback;
@@ -92,5 +95,6 @@ export function normalizeDetailPresentation(
excluded: cleanList(source.excluded).length ? cleanList(source.excluded) : fallback?.excluded ?? [],
notes: cleanList(source.notes).length ? cleanList(source.notes) : fallback?.notes ?? [],
gallery: gallery.length ? gallery : fallback?.gallery ?? [],
conciergeAdvisor,
};
}