diff --git a/suixinkan/Features/TravelAlbum/OTG/Models/WiredCameraTransferHelpDocument.swift b/suixinkan/Features/TravelAlbum/OTG/Models/WiredCameraTransferHelpDocument.swift
new file mode 100644
index 0000000..c364752
--- /dev/null
+++ b/suixinkan/Features/TravelAlbum/OTG/Models/WiredCameraTransferHelpDocument.swift
@@ -0,0 +1,20 @@
+//
+// WiredCameraTransferHelpDocument.swift
+// suixinkan
+//
+
+import Foundation
+
+/// 有线相机传输帮助文档(App 内置 HTML),供传输页与历史导入页打开。
+enum WiredCameraTransferHelpDocument {
+ /// 导航栏标题。
+ static let pageTitle = "帮助文档"
+
+ /// Bundle 内资源名(不含扩展名)。
+ static let resourceName = "WiredCameraTransferHelp"
+
+ /// 返回内置帮助页文件 URL;资源缺失时返回 `nil`。
+ static func bundledURL(in bundle: Bundle = .main) -> URL? {
+ bundle.url(forResource: resourceName, withExtension: "html")
+ }
+}
diff --git a/suixinkan/Resources/WiredCameraTransferHelp.html b/suixinkan/Resources/WiredCameraTransferHelp.html
new file mode 100644
index 0000000..99ac32a
--- /dev/null
+++ b/suixinkan/Resources/WiredCameraTransferHelp.html
@@ -0,0 +1,208 @@
+
+
+
+
+
+ 有线相机传输帮助
+
+
+
+ 有线相机传输帮助
+ 本说明适用于「随心瞰商家版」iPhone 端旅拍相册的有线相机传输功能,帮助你快速连接相机、导入照片并上传到相册。
+
+ 功能简介
+ 通过 USB 线将相机连接到 iPhone 后,可在当前旅拍相册中:
+
+ - 边拍边传:拍摄后自动传入 App,并可按设置自动上传
+ - 拍后传输:先把照片传入 App,再手动选择上传
+ - 历史导入:从相机内已有照片中挑选导入
+ - 相册导入:从手机系统相册导入照片
+
+
+
支持品牌
+
当前支持佳能、索尼、尼康等主流相机(具体机型以实际识别结果为准)。连接成功后,状态区会显示相机名称。
+
+
+ 使用前准备
+
+ - 使用 iPhone(仅竖屏使用),并确保手机有足够剩余存储空间。
+ - 准备原装或质量可靠的 USB 数据线,以及必要的转接头(Lightning / USB-C 按手机接口选择)。
+ - 相机开机,并确认电量充足;建议使用相机原厂供电或满电电池。
+ - 如需上传,请保持网络畅通(Wi‑Fi 或蜂窝数据)。
+
+
+ 连接相机
+
+ - 打开旅拍相册,进入有线传输页面。
+ - 用数据线将相机连接到 iPhone。
+ - 若系统弹出「是否允许访问相机 / USB 配件」等授权提示,请选择允许。
+ - 页面状态变为「xxx 已连接」即表示连接成功;若长时间停留在搜索或未连接,可点击重新连接,或拔插数据线后重试。
+
+
+
注意
+
连接过程中请勿频繁拔插数据线,也不要同时打开电脑读卡软件或其他占用相机 USB 的应用。
+
+
+ 传输模式
+
+
边拍边传
+
相机处于可实时传输状态时,新拍照片会自动写入当前相册;若开启对应上传逻辑,则会继续上传到云端。
+
+
+
拍后传输
+
照片会先进入 App 本地列表,不会自动上传。你可使用「批量上传」或「指定上传」按需上传。
+
+ 可在页面设置区切换传输模式;切换后对后续新传入的照片生效。
+
+ 页面常用操作
+
+ - 重新连接 / 刷新:未连接时用于重新搜索;已连接时用于刷新当前已传入列表。
+ - 历史导入:相机连接成功后可用,从相机存储中挑选历史照片导入当前相册。
+ - 批量上传:进入多选模式,勾选照片后上传选中项。
+ - 指定上传:可一键上传「所有未上传照片」或「今日拍摄照片」。
+ - 相册导入:从手机系统相册选择图片导入当前旅拍相册。
+ - 时间轴:左侧时间导航可快速定位到某一时间段的照片。
+
+ 列表支持「全部 / 已上传 / 失败」筛选,失败项可按提示重试。
+
+ 索尼相机说明
+ 索尼相机在不同 USB 模式下,行为和列表内容会有差异:
+
+ - 边拍边传:通常需要进入相机支持的远程/PC Remote 类连接模式,以便拍摄后及时传到手机。
+ - 历史导入:若提示无照片或列表为空,请将相机 USB 连接模式切换为 MTP(或「仅传照片 / Mass Storage / MTP」等类似选项,以机身为准),然后重新插拔连接并再次进入历史导入。
+
+
+
切换提示
+
多数索尼机身路径类似:菜单 → 网络/连接 → USB 连接 → 选择 MTP。具体名称因机型而异,请以相机说明书为准。
+
+
+ 常见问题
+ 1. 一直显示「未连接 USB」或「正在搜索」?
+
+ - 检查数据线与转接头是否支持数据传输(仅充电线无法识别相机)。
+ - 确认相机已开机,并处于可被电脑/手机识别的 USB 模式。
+ - 尝试拔掉重插,或点击「重新连接」。
+ - 重启相机与 App 后再试。
+
+
+ 2. 已连接但看不到新拍照片?
+
+ - 确认当前传输出入的是正确的旅拍相册。
+ - 边拍边传模式下,请保持本页在前台,并避免同时进行历史导入。
+ - 索尼机型请核对 USB/远程模式是否匹配当前用途。
+
+
+ 3. 上传失败怎么办?
+
+ - 检查网络是否稳定,必要时切换 Wi‑Fi。
+ - 确认手机存储空间充足。
+ - 在「失败」Tab 中查看失败照片,并重试上传。
+
+
+ 4. 历史导入打开后没有照片?
+
+ - 相机存储卡中确实要有可识别的照片文件。
+ - 索尼请切换到 MTP 模式后重试。
+ - 关闭历史导入页,回到传输页重新连接后再进入。
+
+
+ 5. 连接中提示没有权限?
+
+ - 请在系统弹窗中允许访问相机或相关配件。
+ - 若曾点过拒绝,可到 iPhone「设置」中为「随心瞰商家版」重新开启相关权限,或重新插拔设备触发授权。
+
+
+
+
+
+
diff --git a/suixinkan/UI/Setting/AgreementWebViewController.swift b/suixinkan/UI/Setting/AgreementWebViewController.swift
index 1ac7dea..03c0dd6 100644
--- a/suixinkan/UI/Setting/AgreementWebViewController.swift
+++ b/suixinkan/UI/Setting/AgreementWebViewController.swift
@@ -7,7 +7,7 @@ import SnapKit
import UIKit
import WebKit
-/// 协议 H5 页面,使用应用内 WebView 展示关于我们、用户协议和隐私政策。
+/// 应用内 WebView 页面,用于展示协议 H5、内置帮助 HTML 等文档内容。
final class AgreementWebViewController: BaseViewController {
private let pageTitle: String
private let url: URL
@@ -37,7 +37,15 @@ final class AgreementWebViewController: BaseViewController {
view.addSubview(loadingIndicator)
loadingIndicator.hidesWhenStopped = true
loadingIndicator.startAnimating()
- webView.load(URLRequest(url: url))
+ loadContent()
+ }
+
+ private func loadContent() {
+ if url.isFileURL {
+ webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
+ } else {
+ webView.load(URLRequest(url: url))
+ }
}
override func setupConstraints() {
diff --git a/suixinkan/UI/TravelAlbum/TravelAlbumCameraImportViewController.swift b/suixinkan/UI/TravelAlbum/TravelAlbumCameraImportViewController.swift
index 7225c5e..0343273 100644
--- a/suixinkan/UI/TravelAlbum/TravelAlbumCameraImportViewController.swift
+++ b/suixinkan/UI/TravelAlbum/TravelAlbumCameraImportViewController.swift
@@ -293,8 +293,11 @@ final class TravelAlbumCameraImportViewController: UIViewController {
}
@objc private func helpTapped() {
- guard let url = URL(string: "https://sharesky.feishu.cn/wiki/CaAhwl3Gnin4Kqk0BVocK3SGnab?from=from_copylink") else { return }
- UIApplication.shared.open(url)
+ guard let url = WiredCameraTransferHelpDocument.bundledURL() else { return }
+ navigationController?.pushViewController(
+ AgreementWebViewController(title: WiredCameraTransferHelpDocument.pageTitle, url: url),
+ animated: true
+ )
}
}
diff --git a/suixinkan/UI/TravelAlbum/WiredCameraTransferViewController.swift b/suixinkan/UI/TravelAlbum/WiredCameraTransferViewController.swift
index ac9ed3e..e6c2f68 100644
--- a/suixinkan/UI/TravelAlbum/WiredCameraTransferViewController.swift
+++ b/suixinkan/UI/TravelAlbum/WiredCameraTransferViewController.swift
@@ -777,8 +777,14 @@ final class WiredCameraTransferViewController: BaseViewController {
}
@objc private func helpTapped() {
- guard let url = URL(string: "https://sharesky.feishu.cn/wiki/CaAhwl3Gnin4Kqk0BVocK3SGnab?from=from_copylink") else { return }
- UIApplication.shared.open(url)
+ guard let url = WiredCameraTransferHelpDocument.bundledURL() else {
+ showToast("帮助文档暂不可用")
+ return
+ }
+ navigationController?.pushViewController(
+ AgreementWebViewController(title: WiredCameraTransferHelpDocument.pageTitle, url: url),
+ animated: true
+ )
}
private func presentPhotoPreview(_ item: TravelAlbumOTGPhotoItem) {
diff --git a/suixinkanTests/WiredCameraTransferHelpDocumentTests.swift b/suixinkanTests/WiredCameraTransferHelpDocumentTests.swift
new file mode 100644
index 0000000..70abd23
--- /dev/null
+++ b/suixinkanTests/WiredCameraTransferHelpDocumentTests.swift
@@ -0,0 +1,33 @@
+//
+// WiredCameraTransferHelpDocumentTests.swift
+// suixinkanTests
+//
+
+import XCTest
+@testable import suixinkan
+
+/// 有线相机传输内置帮助文档资源测试。
+final class WiredCameraTransferHelpDocumentTests: XCTestCase {
+ func testBundledHelpHTMLExists() {
+ let url = WiredCameraTransferHelpDocument.bundledURL()
+ XCTAssertNotNil(url)
+ XCTAssertEqual(url?.pathExtension, "html")
+ XCTAssertTrue(url?.lastPathComponent.hasPrefix(WiredCameraTransferHelpDocument.resourceName) == true)
+ }
+
+ func testBundledHelpHTMLContainsCoreSections() throws {
+ let url = try XCTUnwrap(WiredCameraTransferHelpDocument.bundledURL())
+ let html = try String(contentsOf: url, encoding: .utf8)
+ XCTAssertTrue(html.contains("有线相机传输帮助"))
+ XCTAssertTrue(html.contains("连接相机"))
+ XCTAssertTrue(html.contains("边拍边传"))
+ XCTAssertTrue(html.contains("拍后传输"))
+ XCTAssertTrue(html.contains("历史导入"))
+ XCTAssertTrue(html.contains("索尼相机说明"))
+ XCTAssertTrue(html.contains("常见问题"))
+ }
+
+ func testPageTitle() {
+ XCTAssertEqual(WiredCameraTransferHelpDocument.pageTitle, "帮助文档")
+ }
+}