feat: update app workflows and permissions
This commit is contained in:
@ -125,7 +125,7 @@ final class WildPhotographerReportListViewController: BaseViewController {
|
||||
reports.forEach { record in
|
||||
let card = WildReportListCardView(record: record)
|
||||
card.onOpen = { [weak self] in self?.openDetail(record) }
|
||||
card.onShare = { [weak self] in self?.viewModel.shareReport(record) }
|
||||
card.onShare = { [weak self] in self?.shareReport(record) }
|
||||
stack.addArrangedSubview(card)
|
||||
}
|
||||
}
|
||||
@ -148,6 +148,21 @@ final class WildPhotographerReportListViewController: BaseViewController {
|
||||
)
|
||||
}
|
||||
|
||||
private func shareReport(_ record: WildReportRecord) {
|
||||
showLoading()
|
||||
Task { [weak self] in
|
||||
guard let self else { return }
|
||||
let payload = await self.viewModel.shareReport(record, api: self.api)
|
||||
await MainActor.run {
|
||||
self.hideLoading()
|
||||
guard let payload else { return }
|
||||
WeChatShareService.shareMiniProgram(payload) { [weak self] result in
|
||||
self?.showWildReportShareResult(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var currentScenicId: Int? {
|
||||
let scenicId = AppStore.shared.currentScenicId
|
||||
return scenicId > 0 ? scenicId : nil
|
||||
@ -736,7 +751,7 @@ final class WildPhotographerReportDetailViewController: BaseViewController {
|
||||
card.stack.addArrangedSubview(WildReportDetailInfoRowView(title: "举报说明", value: viewModel.descriptionText, multiline: true))
|
||||
card.stack.addArrangedSubview(makeInsetDivider())
|
||||
card.stack.addArrangedSubview(WildReportDetailInfoRowView(title: "微信号/手机号", value: viewModel.contactText))
|
||||
if !viewModel.handleRemarkText.isEmpty {
|
||||
if !viewModel.handleRemarkText.isEmpty, !viewModel.showHandlerInfo {
|
||||
card.stack.addArrangedSubview(makeInsetDivider())
|
||||
card.stack.addArrangedSubview(WildReportDetailInfoRowView(title: "处理备注", value: viewModel.handleRemarkText, multiline: true))
|
||||
}
|
||||
@ -768,13 +783,16 @@ final class WildPhotographerReportDetailViewController: BaseViewController {
|
||||
make.edges.equalToSuperview().inset(UIEdgeInsets(top: 18, left: 18, bottom: 10, right: 18))
|
||||
}
|
||||
card.stack.addArrangedSubview(titleWrap)
|
||||
card.stack.addArrangedSubview(WildReportDetailInfoRowView(title: "处理人", value: info.handlerName))
|
||||
card.stack.addArrangedSubview(WildReportHandlerInfoRowView(title: "处理人", value: info.handlerName))
|
||||
card.stack.addArrangedSubview(makeInsetDivider())
|
||||
card.stack.addArrangedSubview(WildReportDetailInfoRowView(title: "处理人电话", value: info.maskedHandlerPhone, trailingIconName: "phone.fill"))
|
||||
let phoneRow = WildReportHandlerInfoRowView(title: "处理人电话", value: info.maskedHandlerPhone, trailingIconName: "phone.fill")
|
||||
phoneRow.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handlerPhoneTapped)))
|
||||
phoneRow.accessibilityTraits.insert(.button)
|
||||
card.stack.addArrangedSubview(phoneRow)
|
||||
card.stack.addArrangedSubview(makeInsetDivider())
|
||||
card.stack.addArrangedSubview(WildReportDetailInfoRowView(title: "处理时间", value: info.processingAt))
|
||||
card.stack.addArrangedSubview(WildReportHandlerInfoRowView(title: "处理时间", value: info.processingAt))
|
||||
card.stack.addArrangedSubview(makeInsetDivider())
|
||||
card.stack.addArrangedSubview(WildReportDetailInfoRowView(title: "处理完成时间", value: info.processedAt))
|
||||
card.stack.addArrangedSubview(WildReportHandlerInfoRowView(title: "处理完成时间", value: info.processedAt))
|
||||
card.stack.addArrangedSubview(makeInsetDivider())
|
||||
card.stack.addArrangedSubview(WildReportDetailInfoRowView(title: "处理意见", value: info.processOpinion, multiline: true))
|
||||
|
||||
@ -800,7 +818,11 @@ final class WildPhotographerReportDetailViewController: BaseViewController {
|
||||
header.alignment = .center
|
||||
header.addArrangedSubview(WildReportUI.label(item.submitTime, font: .app(.captionMedium), color: AppColor.textSecondary))
|
||||
header.addArrangedSubview(UIView())
|
||||
header.addArrangedSubview(WildReportUI.label("第\(items.count - index)次补充", font: .app(.captionMedium), color: AppColor.primary))
|
||||
header.addArrangedSubview(WildReportUI.label(
|
||||
WildReportSupplementDisplayFormatter.sequenceTitle(forDisplayIndex: index),
|
||||
font: .app(.captionMedium),
|
||||
color: AppColor.primary
|
||||
))
|
||||
itemStack.addArrangedSubview(header)
|
||||
itemStack.addArrangedSubview(WildReportUI.label(item.summaryText, font: .app(.bodyMedium), color: AppColor.textPrimary, lines: 0))
|
||||
card.stack.addArrangedSubview(itemStack)
|
||||
@ -948,12 +970,11 @@ final class WildPhotographerReportDetailViewController: BaseViewController {
|
||||
section.spacing = 12
|
||||
section.layoutMargins = UIEdgeInsets(top: 14, left: 18, bottom: 16, right: 18)
|
||||
section.isLayoutMarginsRelativeArrangement = true
|
||||
section.addArrangedSubview(makeSectionHeader(
|
||||
section.addArrangedSubview(makeCompactMediaSectionHeader(
|
||||
iconName: "photo.on.rectangle.angled",
|
||||
title: "处理凭证",
|
||||
subtitle: info.completionMediaSummary,
|
||||
chevron: false,
|
||||
action: nil
|
||||
summary: info.completionMediaSummary,
|
||||
action: #selector(completionPreviewTapped)
|
||||
))
|
||||
|
||||
let mediaScroll = UIScrollView()
|
||||
@ -1199,10 +1220,33 @@ final class WildPhotographerReportDetailViewController: BaseViewController {
|
||||
return wrapper
|
||||
}
|
||||
|
||||
@objc private func shareTapped() { viewModel.shareReport() }
|
||||
@objc private func shareTapped() {
|
||||
showLoading()
|
||||
Task { [weak self] in
|
||||
guard let self else { return }
|
||||
let payload = await self.viewModel.shareReport(api: self.api)
|
||||
await MainActor.run {
|
||||
self.hideLoading()
|
||||
guard let payload else { return }
|
||||
WeChatShareService.shareMiniProgram(payload) { [weak self] result in
|
||||
self?.showWildReportShareResult(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@objc private func previewTapped() { presentReporterMediaPreview(selectedKey: nil) }
|
||||
@objc private func paymentPreviewTapped() { presentPaymentMediaPreview(selectedKey: nil) }
|
||||
@objc private func completionPreviewTapped() { presentCompletionMediaPreview(selectedKey: nil) }
|
||||
@objc private func locationTapped() { viewModel.showLocationPreview() }
|
||||
@objc private func handlerPhoneTapped() {
|
||||
guard let phone = viewModel.handlerInfo?.handlerPhone.trimmingCharacters(in: .whitespacesAndNewlines),
|
||||
!phone.isEmpty,
|
||||
let url = URL(string: "tel://\(phone)") else {
|
||||
showToast("暂无处理人电话")
|
||||
return
|
||||
}
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
|
||||
@objc private func reporterMediaTapped(_ recognizer: UITapGestureRecognizer) {
|
||||
guard let tile = recognizer.view as? WildReportDetailMediaThumbnailView else { return }
|
||||
@ -1367,6 +1411,60 @@ private final class WildReportDetailInfoRowView: UIView {
|
||||
}
|
||||
}
|
||||
|
||||
/// 举报详情页处理信息单行,左侧字段名、右侧内容。
|
||||
private final class WildReportHandlerInfoRowView: UIView {
|
||||
init(title: String, value: String, trailingIconName: String? = nil) {
|
||||
super.init(frame: .zero)
|
||||
|
||||
let titleLabel = WildReportUI.label(title, font: .app(.captionMedium), color: AppColor.textSecondary)
|
||||
titleLabel.setContentHuggingPriority(.required, for: .horizontal)
|
||||
titleLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
|
||||
let valueLabel = WildReportUI.label(value, font: .app(.subtitle), color: AppColor.textPrimary, lines: 1)
|
||||
valueLabel.textAlignment = .right
|
||||
valueLabel.lineBreakMode = .byTruncatingTail
|
||||
valueLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||
|
||||
addSubview(titleLabel)
|
||||
addSubview(valueLabel)
|
||||
|
||||
if let trailingIconName {
|
||||
let icon = UIImageView(image: UIImage(systemName: trailingIconName))
|
||||
icon.tintColor = AppColor.primary
|
||||
icon.contentMode = .scaleAspectFit
|
||||
addSubview(icon)
|
||||
icon.snp.makeConstraints { make in
|
||||
make.trailing.equalToSuperview().inset(18)
|
||||
make.centerY.equalToSuperview()
|
||||
make.size.equalTo(16)
|
||||
}
|
||||
valueLabel.snp.makeConstraints { make in
|
||||
make.trailing.equalTo(icon.snp.leading).offset(-6)
|
||||
}
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.leading.equalToSuperview().offset(18)
|
||||
make.centerY.equalToSuperview()
|
||||
}
|
||||
valueLabel.snp.makeConstraints { make in
|
||||
make.leading.greaterThanOrEqualTo(titleLabel.snp.trailing).offset(14)
|
||||
make.centerY.equalToSuperview()
|
||||
if trailingIconName == nil {
|
||||
make.trailing.equalToSuperview().inset(18)
|
||||
}
|
||||
}
|
||||
snp.makeConstraints { make in
|
||||
make.height.equalTo(48)
|
||||
}
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
private extension MediaPreviewItem {
|
||||
init?(wildReportReporterItem item: WildReportReporterMediaItem) {
|
||||
guard let urlText = item.previewKey else { return nil }
|
||||
@ -1393,6 +1491,28 @@ private extension MediaPreviewItem {
|
||||
}
|
||||
}
|
||||
|
||||
private extension BaseViewController {
|
||||
@MainActor
|
||||
func showWildReportShareResult(_ result: WeChatShareResult) {
|
||||
switch result {
|
||||
case .success:
|
||||
showToast("分享成功")
|
||||
case .cancelled:
|
||||
showToast("已取消分享")
|
||||
case .notInstalled:
|
||||
showToast("请先安装微信")
|
||||
case .unsupported:
|
||||
showToast("当前微信版本不支持分享")
|
||||
case .invalidPayload(let message):
|
||||
showToast(message)
|
||||
case .sendFailed:
|
||||
showToast("微信分享发送失败")
|
||||
case .unknown:
|
||||
showToast("微信分享失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension WildReportReporterMediaItem {
|
||||
var previewKey: String? {
|
||||
guard let text = fileURL?.trimmingCharacters(in: .whitespacesAndNewlines), !text.isEmpty else { return nil }
|
||||
|
||||
Reference in New Issue
Block a user