拆分宣传页视图并扩充 Mock 数据,合作订单支持获客员备注名并修复线索图片网格尺寸。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-02 17:43:04 +08:00
parent 1b1e93b9ca
commit 328c4321f4
41 changed files with 2529 additions and 1436 deletions

View File

@ -0,0 +1,98 @@
//
// ScenicPromotionMediaStripView.swift
// suixinkan
//
// Created by Codex on 2026/7/2.
//
import SwiftUI
///
struct ScenicPromotionMediaStripView: View {
let mediaItems: [ScenicPromotionMedia]
let selectedMediaID: String?
let emptyMode: ScenicPromotionMediaMode
let onSelectMedia: (ScenicPromotionMedia) -> Void
let onMoveMedia: (Int) -> Void
var body: some View {
HStack(spacing: 8) {
Button {
onMoveMedia(-1)
} label: {
Image(systemName: "chevron.left")
.font(.system(size: 22, weight: .heavy))
.foregroundStyle(Color(hex: 0x326EAE))
.frame(width: 28, height: 100)
}
.buttonStyle(.plain)
if mediaItems.isEmpty {
ScenicPromotionMediaEmptyView(mode: emptyMode)
} else {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 10) {
ForEach(mediaItems) { media in
Button {
onSelectMedia(media)
} label: {
ScenicPromotionMediaArtwork(media: media, compact: true, useHeroAsset: false)
.frame(width: media.previewWidth, height: 66)
.overlay(alignment: .bottomTrailing) {
if let duration = media.duration {
Text(duration)
.font(.system(size: 11, weight: .bold))
.foregroundStyle(.white)
.padding(.horizontal, 6)
.padding(.vertical, 3)
.background(.black.opacity(0.42), in: Capsule())
.padding(6)
}
}
.overlay(
RoundedRectangle(cornerRadius: 12)
.stroke(
selectedMediaID == media.id ? Color(hex: 0x0B79FF) : .white.opacity(0.75),
lineWidth: selectedMediaID == media.id ? 3 : 1
)
)
}
.buttonStyle(.plain)
}
}
.padding(.vertical, 2)
}
}
Button {
onMoveMedia(1)
} label: {
Image(systemName: "chevron.right")
.font(.system(size: 22, weight: .heavy))
.foregroundStyle(Color(hex: 0x326EAE))
.frame(width: 28, height: 100)
}
.buttonStyle(.plain)
}
.padding(10)
.background(.white.opacity(0.72), in: RoundedRectangle(cornerRadius: 18))
.overlay(
RoundedRectangle(cornerRadius: 18)
.stroke(.white.opacity(0.85), lineWidth: 1)
)
}
}
#if DEBUG
#Preview("素材横向列表") {
let board = ScenicPromotionPreviewSupport.sampleBoard
ScenicPromotionMediaStripView(
mediaItems: board.spots[0].videos,
selectedMediaID: board.spots[0].videos[0].id,
emptyMode: .video,
onSelectMedia: { _ in },
onMoveMedia: { _ in }
)
.padding(.horizontal, 20)
}
#endif