拆分宣传页视图并扩充 Mock 数据,合作订单支持获客员备注名并修复线索图片网格尺寸。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -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
|
||||
Reference in New Issue
Block a user