Files
multi-simadmin/apps/ios/Sources/MultiSimAdmin/Features/Messages/SendMessageFormView.swift
T
chick 802ddd1102 release(ios): 0.2.2 构建 10 修消息卡空洞、标签胶囊假宽与表单标题层级
- 消息卡片删除按钮移出正文行,改用 overlay 悬在右侧,44pt 点击区不再把行撑高
- 批量标签胶囊由等宽栅格改为流式布局,新增 AIFlowLayout 并让节点页复用同一实现
- 设置页应用信息补「构建」一行,版本号全程不带括号
- 添加实例与发送消息两张表单表统一行内标题,去掉大标题留下的空白带
- 节点空态文案改为「节点未返回设备信息」,与量表条实际返回的数据不矛盾
- 图标石墨底、面板阴影与插槽统一压暖 3~4 级,全图 0 蓝色像素
2026-09-15 13:03:23 +08:00

127 lines
4.0 KiB
Swift

import SwiftUI
struct SendMessageFormView: View {
@Environment(\.dismiss) private var dismiss
@ObservedObject var model: MessagesViewModel
@State private var phoneNumber = ""
@State private var content = ""
@State private var validationMessage: String?
@State private var isSending = false
private var trimmedPhoneNumber: String {
phoneNumber.trimmingCharacters(in: .whitespacesAndNewlines)
}
private var trimmedContent: String {
content.trimmingCharacters(in: .whitespacesAndNewlines)
}
private var canSend: Bool {
!model.instances.isEmpty && !trimmedPhoneNumber.isEmpty && !trimmedContent.isEmpty
}
var body: some View {
NavigationStack {
ScrollView {
VStack(spacing: 12) {
AICard {
VStack(alignment: .leading, spacing: 14) {
VStack(alignment: .leading, spacing: 6) {
AIFieldLabel("实例")
Picker(
"实例",
selection: Binding(
get: { model.selectedInstanceID ?? model.instances.first?.id },
set: { model.selectedInstanceID = $0 }
)
) {
if model.instances.isEmpty {
Text("暂无实例").tag(Optional<UUID>.none)
}
ForEach(model.instances) { instance in
Text(instance.name).tag(Optional(instance.id))
}
}
.pickerStyle(.menu)
.aiSelectSurface()
}
VStack(alignment: .leading, spacing: 6) {
AIFieldLabel("收件号码")
TextField("收件号码", text: $phoneNumber)
.textFieldStyle(AIFieldStyle())
.accessibilityLabel("收件号码")
.submitLabel(.next)
#if os(iOS)
.keyboardType(.phonePad)
#endif
}
VStack(alignment: .leading, spacing: 6) {
AIFieldLabel("消息内容")
TextField("消息内容", text: $content, axis: .vertical)
.textFieldStyle(AIFieldStyle())
.accessibilityLabel("消息内容")
.submitLabel(.send)
.onSubmit {
if canSend { send() }
}
.lineLimit(4...8)
}
}
}
if let validationMessage {
AIStatusBanner(
validationMessage, tint: AITheme.danger, systemImage: "exclamationmark.triangle")
}
}
.padding(16)
.padding(.bottom, 8)
}
.aiBottomActionBar {
AIActionRow {
Button("取消") { dismiss() }
.buttonStyle(AIButtonStyle(kind: .secondary, size: .regular, fillsWidth: true))
Button {
send()
} label: {
HStack(spacing: 8) {
if isSending {
ProgressView()
.controlSize(.small)
}
Text(isSending ? "发送中" : "发送")
}
}
.buttonStyle(AIButtonStyle(kind: .primary, size: .regular, fillsWidth: true))
.disabled(!canSend || isSending)
}
}
.background(AITheme.canvas.ignoresSafeArea())
.navigationTitle("发送消息")
#if os(iOS)
// 与「添加实例」一致:表行内标题,避免大标题在表单上方留出一整条空白。
.navigationBarTitleDisplayMode(.inline)
.scrollDismissesKeyboard(.interactively)
#endif
}
}
private func send() {
guard !isSending else { return }
isSending = true
Task {
do {
try await model.send(phoneNumber: trimmedPhoneNumber, content: trimmedContent)
phoneNumber = ""
content = ""
validationMessage = nil
dismiss()
} catch {
validationMessage = "发送失败,请检查号码、内容和实例登录状态。"
}
isSending = false
}
}
}