import SwiftUI // MARK: - 内容输入和预览组件 struct CodeContentInputView: View { let selectedDataType: DataType let selectedBarcodeType: BarcodeType let selectedQRCodeType: QRCodeType @Binding var content: String @Binding var validationResult: BarcodeValidator.ValidationResult? @FocusState.Binding var isContentFieldFocused: Bool var body: some View { VStack(spacing: 16) { // 内容输入区域 contentInputSection // 预览区域 if !content.isEmpty { previewSection } } } // MARK: - 内容输入区域 private var contentInputSection: some View { Section("内容") { VStack(alignment: .leading, spacing: 12) { // 输入框和计数布局 VStack(alignment: .trailing, spacing: 4) { // 条形码格式提示 if selectedDataType == .barcode { HStack { Image(systemName: "info.circle") .font(.caption) .foregroundColor(.blue) Text(getBarcodeFormatHint()) .font(.caption) .foregroundColor(.secondary) .lineLimit(2) Spacer() } .padding(.horizontal, 4) .padding(.vertical, 6) .background( RoundedRectangle(cornerRadius: 6) .fill(Color.blue.opacity(0.1)) ) } TextField(getPlaceholderText(), text: $content) .textFieldStyle(RoundedBorderTextFieldStyle()) .keyboardType(getKeyboardType()) .textInputAutocapitalization(getAutocapitalization()) .disableAutocorrection(true) .focused($isContentFieldFocused) .toolbar { ToolbarItemGroup(placement: .keyboard) { Spacer() Button("完成") { isContentFieldFocused = false } .foregroundColor(.blue) .font(.system(size: 16, weight: .medium)) } } .foregroundColor(.black) .onChange(of: content) { newValue in handleContentChange(newValue) } // 计数显示在输入框下方,右对齐 if let maxLen = getMaxLength(), selectedDataType == .barcode { Text("\(normalizedInputCount())/\(maxLen)") .font(.caption2) .foregroundColor(.blue) .fontWeight(.medium) } } // 输入统计与验证状态 HStack { if let result = validationResult, result.isValid { Text("✓ 格式正确") .font(.caption2) .foregroundColor(.green) } else if !content.isEmpty { Text("⚠ 格式检查中...") .font(.caption2) .foregroundColor(.orange) } } // 条形码验证信息(仅在格式不正确时显示) if selectedDataType == .barcode && !content.isEmpty && (validationResult == nil || !validationResult!.isValid) { BarcodeValidationInfoView( validationResult: validationResult, barcodeType: selectedBarcodeType ) } } } } // MARK: - 预览区域 private var previewSection: some View { Section("预览") { VStack(alignment: .leading, spacing: 12) { HStack { Image(systemName: selectedDataType.icon) Text(selectedDataType.displayName) Spacer() if selectedDataType == .barcode { Text(selectedBarcodeType.displayName) .font(.caption) .padding(.horizontal, 8) .padding(.vertical, 2) .background(Color.green.opacity(0.1)) .foregroundColor(.green) .cornerRadius(8) } else { Text(selectedQRCodeType.displayName) .font(.caption) .padding(.horizontal, 8) .padding(.vertical, 2) .background(Color.orange.opacity(0.1)) .foregroundColor(.orange) .cornerRadius(8) } } if selectedDataType == .barcode && !content.isEmpty && isInputComplete() { // 条形码图片预览(仅在输入完成时显示) BarcodePreviewView( content: content, barcodeType: selectedBarcodeType ) .frame(height: 120) .frame(maxWidth: .infinity) } else { // 二维码或文本预览 Text(content) .font(.body) .foregroundColor(.secondary) .padding() .frame(maxWidth: .infinity, alignment: .leading) } } .padding() .background(Color(.systemGray6)) .cornerRadius(8) } } // MARK: - 辅助方法 private func handleContentChange(_ newValue: String) { // 针对有固定长度与数字要求的类型,进行输入规范化(仅保留数字并按最大长度截断) if selectedDataType == .barcode, let maxLen = getMaxLength(), requiresDigitsOnly() { let digits = newValue.filter { $0.isNumber } let truncated = String(digits.prefix(maxLen)) if truncated != newValue { content = truncated // 播放输入提示音 playInputSound() } } else if selectedDataType == .barcode { // 播放输入提示音 playInputSound() } validateBarcodeContent(content) } private func validateBarcodeContent(_ newContent: String) { guard selectedDataType == .barcode else { return } validationResult = BarcodeValidator.validateBarcode(newContent, type: selectedBarcodeType) } private func getKeyboardType() -> UIKeyboardType { guard selectedDataType == .barcode else { return .default } switch selectedBarcodeType { case .ean13, .ean8, .upce, .itf14: return .numberPad case .code39, .code128, .pdf417: return .asciiCapable } } private func getAutocapitalization() -> TextInputAutocapitalization { guard selectedDataType == .barcode else { return .sentences } switch selectedBarcodeType { case .ean13, .ean8, .upce, .itf14: return .never case .code39, .code128, .pdf417: return .characters } } private func getMaxLength() -> Int? { guard selectedDataType == .barcode else { return nil } switch selectedBarcodeType { case .ean13: return 13 case .ean8: return 8 case .upce: return 8 case .itf14: return 14 default: return nil } } private func requiresDigitsOnly() -> Bool { guard selectedDataType == .barcode else { return false } switch selectedBarcodeType { case .ean13, .ean8, .upce, .itf14: return true default: return false } } private func normalizedInputCount() -> Int { if requiresDigitsOnly() { return content.filter { $0.isNumber }.count } return content.count } private func getBarcodeFormatHint() -> String { switch selectedBarcodeType { case .ean13: return "请输入13位数字,如:1234567890123" case .ean8: return "请输入8位数字,如:12345678" case .upce: return "请输入8位数字,如:12345678" case .code39: return "请输入字母、数字、空格和特殊字符" case .code128: return "请输入任意ASCII字符" case .itf14: return "请输入14位数字,如:12345678901234" case .pdf417: return "请输入任意ASCII字符" } } private func getPlaceholderText() -> String { if selectedDataType == .barcode { switch selectedBarcodeType { case .ean13: return "输入13位数字" case .ean8: return "输入8位数字" case .upce: return "输入8位数字" case .code39: return "输入字母、数字等" case .code128: return "输入任意字符" case .itf14: return "输入14位数字" case .pdf417: return "输入任意字符" } } else { return "请输入内容" } } private func playInputSound() { // 使用系统触觉反馈作为输入提示音 let impactFeedback = UIImpactFeedbackGenerator(style: .light) impactFeedback.impactOccurred() } private func isInputComplete() -> Bool { if selectedDataType == .barcode { // 条形码需要验证格式正确 return validationResult?.isValid == true } else { // 二维码只要有内容就算完成 return !content.isEmpty } } }