拆分宣传页视图并扩充 Mock 数据,合作订单支持获客员备注名并修复线索图片网格尺寸。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -0,0 +1,101 @@
|
||||
//
|
||||
// ScenicPromotionSpotTabsView.swift
|
||||
// suixinkan
|
||||
//
|
||||
// Created by Codex on 2026/7/2.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// 宣传页打卡点标签区,5 个以内等分,超过 5 个时横向滚动。
|
||||
struct ScenicPromotionSpotTabsView: View {
|
||||
let spots: [ScenicPromotionSpot]
|
||||
let selectedSpotID: String?
|
||||
let onSelectSpot: (ScenicPromotionSpot) -> Void
|
||||
|
||||
var body: some View {
|
||||
if spots.isEmpty {
|
||||
EmptyView()
|
||||
} else {
|
||||
Color.clear
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 42)
|
||||
.overlay {
|
||||
GeometryReader { proxy in
|
||||
let visibleCount = min(CGFloat(max(spots.count, 1)), ScenicPromotionLayout.visibleSpotTabCount)
|
||||
let tabWidth = proxy.size.width / visibleCount
|
||||
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack(spacing: 0) {
|
||||
ForEach(spots) { spot in
|
||||
ScenicPromotionSpotTabButton(
|
||||
spot: spot,
|
||||
isSelected: selectedSpotID == spot.id,
|
||||
onTap: { onSelectSpot(spot) }
|
||||
)
|
||||
.frame(width: tabWidth)
|
||||
}
|
||||
}
|
||||
}
|
||||
.scrollDisabled(spots.count <= Int(ScenicPromotionLayout.visibleSpotTabCount))
|
||||
}
|
||||
}
|
||||
.background(.white.opacity(0.84), in: RoundedRectangle(cornerRadius: 14))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 14)
|
||||
.stroke(.white.opacity(0.8), lineWidth: 1)
|
||||
)
|
||||
.shadow(color: Color(hex: 0x0D47A1, alpha: 0.12), radius: 12, y: 5)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 单个打卡点标签按钮。
|
||||
struct ScenicPromotionSpotTabButton: View {
|
||||
let spot: ScenicPromotionSpot
|
||||
let isSelected: Bool
|
||||
let onTap: () -> Void
|
||||
|
||||
var body: some View {
|
||||
Button(action: onTap) {
|
||||
HStack(spacing: 3) {
|
||||
Image(systemName: spot.iconName)
|
||||
.font(.system(size: 13, weight: .bold))
|
||||
Text(spot.name)
|
||||
.font(.system(size: 12, weight: .bold))
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.66)
|
||||
}
|
||||
.foregroundStyle(isSelected ? .white : Color(hex: 0x14213D))
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 42)
|
||||
.padding(.horizontal, 4)
|
||||
.background(
|
||||
Group {
|
||||
if isSelected {
|
||||
LinearGradient(
|
||||
colors: [Color(hex: 0x1286FF), Color(hex: 0x006BFF)],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
} else {
|
||||
Color.clear
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#Preview("打卡点标签") {
|
||||
ScenicPromotionSpotTabsView(
|
||||
spots: ScenicPromotionPreviewSupport.sampleBoard.spots,
|
||||
selectedSpotID: "bridge",
|
||||
onSelectSpot: { _ in }
|
||||
)
|
||||
.padding(.horizontal, 20)
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user