拆分宣传页视图并扩充 Mock 数据,合作订单支持获客员备注名并修复线索图片网格尺寸。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -0,0 +1,96 @@
|
||||
//
|
||||
// ScenicPromotionHeroMediaView.swift
|
||||
// suixinkan
|
||||
//
|
||||
// Created by Codex on 2026/7/2.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// 宣传页底部主视觉区域,展示当前选中的视频或图片。
|
||||
struct ScenicPromotionHeroMediaView: View {
|
||||
let selectedMedia: ScenicPromotionMedia?
|
||||
let emptyMode: ScenicPromotionMediaMode
|
||||
let onVideoTap: () -> Void
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if let media = selectedMedia {
|
||||
Button {
|
||||
if media.mode == .video {
|
||||
onVideoTap()
|
||||
}
|
||||
} label: {
|
||||
ZStack(alignment: .bottomLeading) {
|
||||
ScenicPromotionMediaArtwork(media: media, compact: false, useHeroAsset: true)
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 220)
|
||||
|
||||
if media.heroAssetName == nil {
|
||||
LinearGradient(
|
||||
colors: [.clear, .black.opacity(0.56)],
|
||||
startPoint: .center,
|
||||
endPoint: .bottom
|
||||
)
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
if media.mode == .video {
|
||||
Image(systemName: "play.fill")
|
||||
.font(.system(size: 30, weight: .bold))
|
||||
.foregroundStyle(.white)
|
||||
.frame(width: 64, height: 64)
|
||||
.background(.white.opacity(0.2), in: Circle())
|
||||
.overlay(Circle().stroke(.white, lineWidth: 3))
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
}
|
||||
|
||||
Label(media.title, systemImage: "mappin.circle.fill")
|
||||
.font(.system(size: 20, weight: .heavy))
|
||||
.foregroundStyle(.white)
|
||||
Text(media.subtitle)
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
.foregroundStyle(.white.opacity(0.92))
|
||||
}
|
||||
.padding(18)
|
||||
}
|
||||
}
|
||||
.clipShape(RoundedRectangle(cornerRadius: 18))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 18)
|
||||
.stroke(.white.opacity(0.86), lineWidth: 1)
|
||||
)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
} else {
|
||||
ScenicPromotionMediaEmptyView(mode: emptyMode)
|
||||
.frame(height: 220)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(.white.opacity(0.7), in: RoundedRectangle(cornerRadius: 18))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 18)
|
||||
.stroke(.white.opacity(0.85), lineWidth: 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#Preview("主视觉") {
|
||||
ScenicPromotionHeroMediaView(
|
||||
selectedMedia: ScenicPromotionPreviewSupport.sampleVideoMedia,
|
||||
emptyMode: .video,
|
||||
onVideoTap: {}
|
||||
)
|
||||
.padding(.horizontal, 20)
|
||||
}
|
||||
|
||||
#Preview("主视觉-空") {
|
||||
ScenicPromotionHeroMediaView(
|
||||
selectedMedia: nil,
|
||||
emptyMode: .video,
|
||||
onVideoTap: {}
|
||||
)
|
||||
.padding(.horizontal, 20)
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user