完善实名认证、钱包与打卡点模块 UI 与业务逻辑。
对齐 Android 实名认证流程与审核页、钱包提现/积分兑换界面,优化打卡点列表与详情交互,并补充相关资源、主题 token 与单元测试。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -17,9 +17,9 @@ final class PunchPointFormViewController: BaseViewController {
|
||||
|
||||
private let mapView = PunchPointMapView()
|
||||
private let zoomStack = UIStackView()
|
||||
private let zoomInButton = PunchPointMapControlButton(symbol: "plus")
|
||||
private let zoomOutButton = PunchPointMapControlButton(symbol: "minus")
|
||||
private let locateButton = PunchPointMapControlButton(symbol: "location.fill")
|
||||
private let zoomInButton = PunchPointMapControlButton(assetName: "punch_point_zoom_in")
|
||||
private let zoomOutButton = PunchPointMapControlButton(assetName: "punch_point_zoom_out")
|
||||
private let locateButton = PunchPointMapControlButton(assetName: "punch_point_map_location")
|
||||
private let cardView = UIView()
|
||||
private let scrollView = UIScrollView()
|
||||
private let formStack = UIStackView()
|
||||
@ -105,11 +105,11 @@ final class PunchPointFormViewController: BaseViewController {
|
||||
}
|
||||
zoomStack.snp.makeConstraints { make in
|
||||
make.trailing.equalToSuperview().inset(16)
|
||||
make.bottom.equalTo(cardView.snp.top).offset(-16)
|
||||
make.bottom.equalTo(locateButton.snp.top).offset(-12)
|
||||
}
|
||||
locateButton.snp.makeConstraints { make in
|
||||
make.trailing.equalToSuperview().inset(16)
|
||||
make.bottom.equalTo(zoomStack.snp.top).offset(-12)
|
||||
make.bottom.equalTo(cardView.snp.top).offset(-16)
|
||||
make.size.equalTo(40)
|
||||
}
|
||||
zoomInButton.snp.makeConstraints { make in
|
||||
@ -148,12 +148,11 @@ final class PunchPointFormViewController: BaseViewController {
|
||||
Task { @MainActor in self?.applyViewModel() }
|
||||
}
|
||||
viewModel.onShowMessage = { [weak self] message in
|
||||
Task { @MainActor in self?.showToast(message) }
|
||||
Task { @MainActor in self?.handleMessage(message) }
|
||||
}
|
||||
viewModel.onCoordinateChange = { [weak self] coordinate in
|
||||
Task { @MainActor in
|
||||
self?.mapView.updateMarker(coordinate: coordinate)
|
||||
self?.mapView.setCenter(coordinate, zoomLevel: 17)
|
||||
self?.applyMapCoordinate(coordinate)
|
||||
}
|
||||
}
|
||||
viewModel.onSubmitSuccess = { [weak self] in
|
||||
@ -232,6 +231,39 @@ final class PunchPointFormViewController: BaseViewController {
|
||||
return PunchPointImageState(data: data, fileName: fileName)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func handleMessage(_ message: String) {
|
||||
guard message.contains("定位权限未授予") else {
|
||||
showToast(message)
|
||||
return
|
||||
}
|
||||
let alert = UIAlertController(title: "无法定位", message: message, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: "取消", style: .cancel))
|
||||
alert.addAction(UIAlertAction(title: "去设置", style: .default) { _ in
|
||||
guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
|
||||
UIApplication.shared.open(url)
|
||||
})
|
||||
present(alert, animated: true)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func applyMapCoordinate(_ coordinate: CLLocationCoordinate2D) {
|
||||
if let initialDetail, let original = initialDetail.coordinate {
|
||||
mapView.updatePunchPointMarker(
|
||||
coordinate: original,
|
||||
imageURL: initialDetail.guideImages.first
|
||||
)
|
||||
let isOriginal = abs(original.latitude - coordinate.latitude) < 0.000_001
|
||||
&& abs(original.longitude - coordinate.longitude) < 0.000_001
|
||||
mapView.updateSelectedMarker(coordinate: isOriginal ? nil : coordinate)
|
||||
mapView.fitAllMarkers()
|
||||
} else {
|
||||
mapView.updatePunchPointMarker(coordinate: nil)
|
||||
mapView.updateSelectedMarker(coordinate: coordinate)
|
||||
mapView.setCenter(coordinate, zoomLevel: 17)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateUploadDialog(_ state: PunchPointUploadDialogState?) {
|
||||
guard let state else {
|
||||
progressAlert?.dismiss(animated: true)
|
||||
@ -329,13 +361,13 @@ private final class PunchPointTextFieldView: UIView {
|
||||
super.init(frame: .zero)
|
||||
titleLabel.attributedText = Self.requiredTitle(title)
|
||||
textField.placeholder = placeholder
|
||||
textField.font = .systemFont(ofSize: 14)
|
||||
textField.font = .systemFont(ofSize: 15)
|
||||
textField.textColor = AppColor.textPrimary
|
||||
textField.backgroundColor = .white
|
||||
textField.layer.cornerRadius = 8
|
||||
textField.layer.borderColor = AppColor.border.cgColor
|
||||
textField.layer.borderWidth = 1
|
||||
textField.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 12, height: 44))
|
||||
textField.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 12, height: 46))
|
||||
textField.leftViewMode = .always
|
||||
addSubview(titleLabel)
|
||||
addSubview(textField)
|
||||
@ -345,7 +377,7 @@ private final class PunchPointTextFieldView: UIView {
|
||||
textField.snp.makeConstraints { make in
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(8)
|
||||
make.leading.trailing.bottom.equalToSuperview()
|
||||
make.height.equalTo(44)
|
||||
make.height.equalTo(46)
|
||||
}
|
||||
textField.addTarget(self, action: #selector(textChanged), for: .editingChanged)
|
||||
}
|
||||
@ -395,10 +427,11 @@ private final class PunchPointCoordinateFieldView: UIView {
|
||||
container.layer.borderWidth = 1
|
||||
container.layer.borderColor = AppColor.border.cgColor
|
||||
valueLabel.text = placeholder
|
||||
valueLabel.font = .systemFont(ofSize: 14)
|
||||
valueLabel.font = .systemFont(ofSize: 15)
|
||||
valueLabel.textColor = UIColor(hex: 0x999999)
|
||||
locateButton.setImage(UIImage(systemName: "location.fill"), for: .normal)
|
||||
locateButton.tintColor = AppColor.textPrimary
|
||||
locateButton.setImage(UIImage(named: "punch_point_location"), for: .normal)
|
||||
locateButton.imageView?.contentMode = .scaleAspectFit
|
||||
locateButton.accessibilityLabel = "定位打卡点坐标"
|
||||
addSubview(titleLabel)
|
||||
addSubview(container)
|
||||
container.addSubview(valueLabel)
|
||||
@ -409,7 +442,7 @@ private final class PunchPointCoordinateFieldView: UIView {
|
||||
container.snp.makeConstraints { make in
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(8)
|
||||
make.leading.trailing.bottom.equalToSuperview()
|
||||
make.height.equalTo(44)
|
||||
make.height.equalTo(46)
|
||||
}
|
||||
valueLabel.snp.makeConstraints { make in
|
||||
make.leading.equalToSuperview().offset(12)
|
||||
@ -457,7 +490,7 @@ private final class PunchPointTextViewFieldView: UIView, UITextViewDelegate {
|
||||
titleLabel.text = title
|
||||
titleLabel.font = .systemFont(ofSize: 14, weight: .medium)
|
||||
titleLabel.textColor = UIColor(hex: 0x333333)
|
||||
textView.font = .systemFont(ofSize: 14)
|
||||
textView.font = .systemFont(ofSize: 15)
|
||||
textView.textColor = AppColor.textPrimary
|
||||
textView.layer.cornerRadius = 8
|
||||
textView.layer.borderWidth = 1
|
||||
@ -476,7 +509,7 @@ private final class PunchPointTextViewFieldView: UIView, UITextViewDelegate {
|
||||
textView.snp.makeConstraints { make in
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(8)
|
||||
make.leading.trailing.bottom.equalToSuperview()
|
||||
make.height.equalTo(92)
|
||||
make.height.equalTo(100)
|
||||
}
|
||||
placeholderLabel.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview().offset(10)
|
||||
@ -575,7 +608,8 @@ private final class PunchPointImageGridView: UIView {
|
||||
/// 打卡点图片缩略图。
|
||||
private final class PunchPointImageThumbView: UIControl {
|
||||
private let imageView = UIImageView()
|
||||
private let addIcon = UIImageView(image: UIImage(systemName: "plus"))
|
||||
private let addIcon = UIImageView(image: UIImage(named: "punch_point_image_add"))
|
||||
private let addLabel = UILabel()
|
||||
private let deleteButton = UIButton(type: .system)
|
||||
private let overlayLabel = UILabel()
|
||||
var onAdd: (() -> Void)?
|
||||
@ -586,26 +620,35 @@ private final class PunchPointImageThumbView: UIControl {
|
||||
super.init(frame: frame)
|
||||
layer.cornerRadius = 8
|
||||
clipsToBounds = true
|
||||
backgroundColor = .white
|
||||
backgroundColor = UIColor(hex: 0xF4F4F4)
|
||||
imageView.contentMode = .scaleAspectFill
|
||||
imageView.clipsToBounds = true
|
||||
addIcon.tintColor = AppColor.primary
|
||||
deleteButton.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal)
|
||||
deleteButton.tintColor = .white
|
||||
addLabel.text = "点击上传"
|
||||
addLabel.font = .systemFont(ofSize: 12)
|
||||
addLabel.textColor = UIColor(hex: 0xB6BECA)
|
||||
addLabel.textAlignment = .center
|
||||
deleteButton.setImage(UIImage(named: "punch_point_image_delete"), for: .normal)
|
||||
deleteButton.accessibilityLabel = "删除图片"
|
||||
overlayLabel.font = .systemFont(ofSize: 14, weight: .medium)
|
||||
overlayLabel.textColor = .white
|
||||
overlayLabel.textAlignment = .center
|
||||
overlayLabel.backgroundColor = UIColor.black.withAlphaComponent(0.45)
|
||||
addSubview(imageView)
|
||||
addSubview(addIcon)
|
||||
addSubview(addLabel)
|
||||
addSubview(deleteButton)
|
||||
addSubview(overlayLabel)
|
||||
imageView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
addIcon.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
make.size.equalTo(28)
|
||||
make.centerX.equalToSuperview()
|
||||
make.centerY.equalToSuperview().offset(-8)
|
||||
make.size.equalTo(24)
|
||||
}
|
||||
addLabel.snp.makeConstraints { make in
|
||||
make.top.equalTo(addIcon.snp.bottom).offset(2)
|
||||
make.centerX.equalToSuperview()
|
||||
}
|
||||
deleteButton.snp.makeConstraints { make in
|
||||
make.top.trailing.equalToSuperview().inset(4)
|
||||
@ -624,18 +667,22 @@ private final class PunchPointImageThumbView: UIControl {
|
||||
}
|
||||
|
||||
func applyAdd() {
|
||||
accessibilityLabel = "点击上传图片"
|
||||
layer.borderColor = UIColor(hex: 0xE5E7EB).cgColor
|
||||
layer.borderWidth = 1
|
||||
imageView.image = nil
|
||||
imageView.kf.cancelDownloadTask()
|
||||
addIcon.isHidden = false
|
||||
addLabel.isHidden = false
|
||||
deleteButton.isHidden = true
|
||||
overlayLabel.isHidden = true
|
||||
}
|
||||
|
||||
func apply(item: PunchPointImageState) {
|
||||
accessibilityLabel = item.errorMessage == nil ? "打卡点图片" : "图片上传失败,点击重试"
|
||||
layer.borderWidth = 0
|
||||
addIcon.isHidden = true
|
||||
addLabel.isHidden = true
|
||||
deleteButton.isHidden = item.isUploading
|
||||
if let urlText = item.previewURL, let url = URL(string: urlText), !urlText.isEmpty {
|
||||
imageView.kf.setImage(with: url)
|
||||
|
||||
Reference in New Issue
Block a user