You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tauri-client/call-client/TaxerInfo-tauri-v1-migratio...

18 KiB

TaxerInfo 模块改写为 Tauri v1单窗口 + Vue设计文档

1. 文档目标

CallClient/WPF/TaxerInfo.xaml.cs + CallClient/WPF/TaxerInfo.xaml 对应功能迁移到 Tauri v1 + Vue单窗口 架构,确保:

  • 业务行为与现有 WPF 一致(取号、开始办理、办结、实名信息、企业列表、网页加载、复制、查询)。
  • 桌面能力由 TauriRust提供界面由 Vue 负责。
  • 后续可以逐步替换原 WebBrowser 内嵌业务页,最终统一为前端组件化实现。

2. 现有模块功能盘点WPF

2.1 核心职责

TaxerInfo 窗口当前承担:

  1. 展示办税员实名信息(身份证图、头像、姓名、手机号、采集状态)。
  2. 展示当前取号下的企业/票据列表,支持“开始”“办结”“选择企业”。
  3. 根据当前票据拼接 URL 并加载纳税人页面(WebBrowser)。
  4. 提供操作按钮:复制税号、复制号码、刷新、一户式查询。
  5. 展示“代理人办理企业清单”(通过 HTTP 接口获取)。

2.2 主要数据模型

  • ticket:票据/办理对象(状态、企业信息、号票信息等)。
  • Enterprise:代理人办理企业清单项。
    • SerialNumber
    • EnterpriseName
    • TaxpayerId
  • ApiResponse / DataItemtoday-enterprises 接口返回结构。
  • 外部响应:
    • SmzJhxtGetBsyxxByqhhmResponse
    • SmzJhxtGetSmzcjxxResponse
    • SmzJhxtGetBdNsrxxResponse

2.3 关键流程

  1. LoadInfo(comparecode) 触发加载:
    • 调实名接口、绑定纳税人接口、绑定企业接口;
    • 查询当日关联票据列表;
    • 填充 UI。
  2. 票据切换(SelectedSubTicket
    • 更新“当前办理文案”;
    • 刷新纳税人页面 URL。
  3. 开始办理(StartCommand
    • 更新票据状态为办理中;
    • 记录窗口/员工信息;
    • 刷新右侧页面。
  4. 办结(EndCommand
    • 结束当前票据;
    • 浏览器跳转 about:blank

3. 迁移目标架构Tauri v1

3.1 技术分层

  • 前端Vue
    • 单窗口页面:TaxerInfoView.vue
    • 状态管理Pinia推荐或 Vue reactive store
    • UI 组件Element Plus / Ant Design Vue任选
  • Tauri 后端Rust
    • #[tauri::command] 提供桌面能力与系统访问
    • 封装对旧服务接口调用(可直接 HTTP 调用)
    • 封装票据数据库/SDK 调用(通过 Rust 侧 adapter
  • 桥接
    • invoke():前端调用命令
    • event:推送异步状态(可选)

3.2 单窗口布局建议(与 WPF 对齐)

  • 左侧(固定宽度)
    • 办税员实名信息卡片(身份证图 + 头像 + 姓名 + 手机 + 采集状态)
    • 企业/票据列表(开始、办结按钮)
    • “选择企业”按钮
  • 右侧(自适应)
    • 顶部操作栏(当前办理文案 + 四个按钮)
    • Tabs
      • 纳税人信息iframe/webview 或前端重构页
      • 代理人办理企业清单:表格展示 EnterpriseList

4. 接口设计Tauri Command + 业务 HTTP

以下为建议接口(前端调用 Rust command

4.1 初始化与加载

taxer_load_info(compareCode: String, currentTicketId: String) -> TaxerLoadInfoDto

聚合返回:

  • 办税员实名信息(姓名、性别、身份证、地址、头像、身份证底图)
  • 实名采集结果(手机号、备注、是否已采集)
  • 绑定纳税人列表(用于税号映射)
  • 当日票据列表(TicketDto[]
  • 默认选中票据
  • 代理人办理企业清单(EnterpriseDto[]

说明WPF 中由 BackgroundWorker + 多次接口请求 + 本地票据查询 完成,迁移后建议统一为一个“聚合命令”,减少前端编排复杂度。

4.2 票据动作

taxer_start_ticket(ticketId: String, windowUid: i64, employeeUid: i64) -> TicketDto

  • 更新开始时间、状态dealing、窗口/员工绑定。
  • 返回更新后的票据数据。

taxer_end_ticket(ticketId: String) -> TicketDto

  • 标记办结(对应原 t.Stop(DateTime.Now))。
  • 返回更新后的票据数据。

taxer_batch_end_or_abandon(ticketIds: Vec<String>) -> ()

  • 对应原 End() 的兜底逻辑(办理中停止、待办废弃)。

4.3 URL 与外部查询

taxer_build_nsr_url(ticketId: String, phoneNo: String, compareCode: String) -> String

根据模板参数替换生成 URL等价 Analize_URL

  • {djxh} ENTERPRISE_ID
  • {sfzhm} 身份证号
  • {sflb} 企业/个人标识
  • {swjgDm} 税务机关代码
  • {qhhm} 取号号码
  • {sjhm} 手机号

taxer_build_yhscx_url(ticketId: String) -> String

生成“一户式查询”URL。

4.4 代理人企业清单

taxer_get_today_enterprises(ticketId: String) -> Vec<EnterpriseDto>

调用:

  • GET {ZIYUN_SERVICE_URL}/agentInfo/today-enterprises/{ticketId}

返回字段映射:

  • serialNumber -> SerialNumber
  • serviceTarget -> EnterpriseName
  • serviceTargetCode -> TaxpayerId

4.5 系统能力

system_copy_text(text: String) -> ()

  • 复制号码、复制税号统一复用。

system_open_external(url: String) -> ()

  • 一户式查询可在系统默认浏览器打开(可选)。

5. 前端 Vue 数据结构建议

export interface TaxerState {
  compareCode: string
  currentTicketId: string
  currentTicket?: TicketDto
  selectedSubTicket?: TicketDto
  ticketList: TicketDto[]
  enterpriseList: EnterpriseDto[]

  name: string
  phoneNo: string
  memo: string
  idCardImageBase64?: string
  headImageBase64?: string
  caijiRegistered: boolean

  isLoading: boolean
  isStarted: boolean
  currentCompanyText: string
  nsrUrl: string
}

6. 功能映射表WPF -> Tauri + Vue

  • Caiji_Click:打开实名采集弹窗 -> Vue Dialog + taxer_submit_realname(若后续迁移)。
  • Copy_Click:复制 TKT_ID -> system_copy_text(currentTicket.tktId)
  • Copy_Tax_Click:复制税号 -> 先映射税号,再 system_copy_text
  • Reflesh_Click:浏览器刷新 -> iframe 重新赋值 src 或 key 强制重渲染。
  • YHSCX_Click:一户式查询 -> taxer_build_yhscx_url + 新标签页/外部浏览器。
  • StartCommand:开始办理 -> taxer_start_ticket 后更新列表和当前文案。
  • EndCommand:办结 -> taxer_end_ticket 后更新状态并清空 nsrUrl
  • SelectedSubTicket setter切换企业 -> 重算 currentCompanyTextnsrUrl
  • LoadInfo:初始化 -> taxer_load_info 一次加载。

7. 页面交互细节Vue

  1. 页面 onMountedtaxer_load_info
  2. 左侧列表点击行 => 更新 selectedSubTicket,调用 taxer_build_nsr_url
  3. 列表项按钮显示规则(与现有一致):
    • 显示“开始”:isStarted && (status == 0 || status == 2)
    • 显示“办结”:isStarted && status == 4
  4. 采集状态图标:
    • 已采集:绿色(对应 Registerd.png
    • 未采集:灰/红(对应 UnRegisterd.png

8. 迁移实施步骤(建议)

第 1 阶段:壳迁移(低风险)

  • 建立 Tauri v1 + Vue 单窗口工程。
  • 先做 UI 结构 1:1 迁移。
  • 右侧“纳税人信息”先保留 iframe/webview 加载原 URL不改业务页

第 2 阶段:命令层落地

  • 实现 taxer_load_info / start / end / build_url / get_today_enterprises
  • 前端改为只依赖 command不再直接拼接/请求。

第 3 阶段:体验与稳定性

  • 增加错误提示、重试、超时处理。
  • 增加日志链路(前端行为日志 + Rust 命令日志)。
  • 补充 E2E 场景测试(见第 10 节)。

9. 关键风险与处理

  • 旧 SDK 依赖迁移风险ticket/business 等可能强依赖 .NET。
    • 方案:先通过 HTTP/本地服务桥接,逐步替换为 Rust 实现。
  • WebBrowser 行为差异WPF WebBrowser 与 Tauri webview 对 cookie/session 行为不同。
    • 方案:先验证登录态与跨域;必要时改外部浏览器打开。
  • 线程模型差异WPF Dispatcher/BackgroundWorker 到 Vue 异步模型要重构。
    • 方案:统一在 command 层串行/并行编排,前端只维护状态。

10. 测试清单(迁移验收)

  • 初始化后实名信息完整展示(姓名、头像、身份证图、手机号)。
  • 票据列表状态渲染正确(待办/办理中/已完成)。
  • 开始办理后状态切换为办理中,当前办理文案正确。
  • 办结后状态切换为已完成,页面清空/切换逻辑正确。
  • 复制号码、复制税号可在系统剪贴板拿到正确值。
  • 一户式查询 URL 参数替换正确(djxh/sfzhm/sflb/swjgDm/qhhm/sjhm)。
  • 代理人办理企业清单可正确加载并展示。
  • 网络异常时有可感知报错,不出现页面卡死。

11. 建议目录结构Tauri

src-tauri/
  src/
    commands/
      taxer.rs
      system.rs
    services/
      baishui_service.rs
      ziyun_service.rs
      ticket_service.rs
    models/
      taxer.rs
      ticket.rs

src/
  views/
    TaxerInfoView.vue
  stores/
    taxer.ts
  services/
    tauri-taxer.ts
  components/
    taxer/
      TaxerProfileCard.vue
      TicketList.vue
      TaxerToolbar.vue
      EnterpriseTable.vue

12. 结论

TaxerInfo 模块适合按“UI 先迁移、命令聚合、再逐步替换内嵌网页”的路径落地。
在 Tauri v1 中建议将现有 ViewModel 的业务入口收敛为 5~7 个 command由 Vue 负责渲染与交互,可在保持业务一致的前提下提升后续可维护性。


13. 深挖:BaiShuiSDK / QueuingSystemSDK 真实依赖行为

本节用于回答“改写后是否还能调用相同后端接口”的关键问题。

13.1 TaxerInfo 实际依赖清单(代码级)

  • BaiShuiSDK.Model.BaishuiModel
    • SmzJhxtGetBsyxxByqhhm(取号号 -> 办税员信息)
    • SmzGetSmzcjxx(身份证号 -> 采集信息)
    • SmzJhxtGetBdNsrxx(身份证号 -> 绑定纳税人)
  • QueuingSystemSDK.ticket
    • Update()Stop()Abandon()GetList(...)
  • QueuingSystemSDK.business
    • new business((int)t.BIZ_UID) 用于补全业务名称
  • QueuingSystemSDK.SystemControl
    • Get("REALNAME_CHECK_API")Get("BS_NSR_URL")Get("BS_YHSCX_URL")Get("BS_TAX_AUTHORITY_NUM")Get("ZIYUN_SERVICE_URL")
  • QueuingSystemSDK.HttpHelper
    • httpGet("{ZIYUN_SERVICE_URL}/agentInfo/today-enterprises/{tktId}")
  • DbHelperSQL.GetServerTime()(开始办理时落库时间)

13.2 百税接口协议(必须保持兼容)

TaxerInfo 间接通过 BaishuiModel -> BsDefaultClient.execute 调后端。真实请求格式不是纯 JSON而是

  • POST {REALNAME_CHECK_API}
  • Content-Type: application/x-www-form-urlencoded
  • body 参数:
    • domain.ywId={bid}
    • domain.parmJson={UrlEncode(Json(request))}

其中 UrlEncode 使用 SDK 自定义逻辑:逐字符编码,并将 %xx 转为大写(%2f -> %2F)。
这在某些网关上会影响签名或解析结果,建议 Rust 侧保持一致实现。

13.3 TaxerInfo 使用的 3 个百税 bid

  • smz.jhxtGetBsyxxByqhhm
    • 请求字段:qhhm
    • 来源:compareCode(取号号码)
  • smz.getSmzcjxx
    • 请求字段:sfzhm
    • 来源:上一步返回 result.sfzhm
  • smz.jhxtGetBdNsrxx
    • 请求字段:sfzhm
    • 来源:同上

返回字段依赖(前端展示必须保留):

  • 办税员:xm/xb/mz/sfzhm/zz/csrq/sfzzmPic/headPic
  • 采集信息:sjhm/bz/code
  • 绑定纳税人:dataList[].djxh/nsrsbh/nsrmc

13.4 队列票据本地数据行为(非 HTTP

ticket 属于本地数据库实体SQL Server不是远端 REST

  • Update()
    • 更新 WIN_ID/BIZ_UID/EMP_UID/START_TIME/END_TIME/RANK/STATUS
  • Stop(DateTime)
    • 更新 END_TIME=GETDATE()STATUS=complete(5)
  • Abandon()
    • 更新 END_TIME=GETDATE()STATUS=abandoned(6)
  • GetList(where, ..., hideLinkTicket)
    • 直接拼 SQL 查 [ticket] 表并映射对象

这意味着 Tauri 改写时有两个实现路径:

  1. 兼容优先:继续复用现有 .NET 服务层本地中间服务操作数据库Tauri 仅调用中间层 API。
  2. 重写优先Rust 直接连库并重建 ticket SQL 逻辑(工作量和风险更高)。

13.5 配置来源(SystemControl.Get

SystemControl 在静态构造时会把 system 表配置加载进内存缓存,然后 Get(key) 直接读缓存。
TaxerInfo 迁移最关键的配置项如下:

  • REALNAME_CHECK_API:百税 API 入口地址
  • BS_NSR_URL:纳税人信息页模板(含 {djxh} 等占位符)
  • BS_YHSCX_URL:一户式查询 URL 模板
  • BS_TAX_AUTHORITY_NUM{swjgDm} 参数
  • ZIYUN_SERVICE_URL:紫云服务入口

默认值(由 DBUpdateManager 初始化)显示 BS_NSR_URL/BS_YHSCX_URL 为同一模板,迁移后可沿用同策略。

13.6 直接 HTTP 接口(紫云)

GetDelegaterInfo() 使用:

  • GET {ZIYUN_SERVICE_URL}/agentInfo/today-enterprises/{CurrentTicket.TKT_ID}

解析规则:

  • 响应 code == 200 && data != null 才展示
  • 字段映射:
    • serialNumber -> SerialNumber
    • serviceTarget -> EnterpriseName
    • serviceTargetCode -> TaxpayerId
  • 否则清空列表

13.7 Tauri v1 落地时的“接口保持一致”建议

A. 百税接口适配器Rust必须做到

  • 保持相同 bid 与请求字段名
  • 保持 form 参数名:domain.ywIddomain.parmJson
  • 保持 UTF-8 + URL 编码行为(百分号大写)
  • 保持错误语义:
    • SmzJhxtGetBsyxxByqhhmcode != "00" 视为失败
    • SmzGetSmzcjxx:允许 "00""01"
    • SmzJhxtGetBdNsrxx:当前 SDK 对非 00 未强拦截(按原行为兼容)

B. 队列票据能力建议

  • 第一阶段不要在 Rust 侧直连数据库重写 ticket 全量逻辑;
  • 建议先将 Start/Stop/GetList 封成可调用服务HTTP/IPCTauri 调该服务;
  • 等功能回归稳定后再考虑 Rust 直连库替换。

C. URL 模板能力

  • Analize_URL 的 6 个占位符替换规则必须逐字兼容:
    • {djxh}{sfzhm}{sflb}{swjgDm}{qhhm}{sjhm}

13.8 额外注意点(代码库现状)

  • SmzJhxtGetBdNsrxxRequest 类定义在 SmzJhxtGetBsyGlqyxxRequest.cs 文件中(文件名与类名不一致),迁移时建议统一命名避免维护歧义。
  • HttpHelper.httpGet 未设置超时与异常细化Tauri 迁移时建议新增超时、重试与可观测日志。

14. 基于现有 Tauri 项目(F:\workspace\zyclient_linux\TauriClient\call-client)的落位分析

本节基于当前 Tauri v1 代码现状补充,目的是将 TaxerInfo 改写方案落到“现项目可实施”的路径,而非抽象设计。

14.1 当前 Tauri 主结构(已实现)

  • 前端路由:
    • /main -> MainView.vue
    • /ticketList -> TicketListView.vue
    • /login -> LoginView.vue
    • /setup -> ServerSetupView.vue
  • Rust 窗口命令(已实现):
    • open_ticket_window
    • close_ticket_window
    • focus_window
    • open_main_window
    • open_login_window
  • 当前窗口形态:
    • main 窗口:500x100always_on_top、无边框(条形呼叫台)
    • ticketList 窗口:1024x720、无边框、独立路由页

14.2 “办税员窗口”当前行为(关键结论)

MainView.vue 的“更多菜单”里确有 办税员窗口 按钮,但目前逻辑是:

  • handleMoreCommand("main") 仅提示“当前已在办税员窗口”
  • 并不会打开新的 TaxerInfo 页面/窗口

这说明:现项目尚未承载 C# TaxerInfo 的完整 UI 与业务,仅有一个呼叫控制条主窗。

14.3 与 TaxerInfo 的差距(按能力分层)

A. 窗口与页面承载差距

  • main 尺寸为 500x100,不具备 TaxerInfo(约 1200x600)承载条件。
  • 当前仅有一个次窗口 ticketList,尚无 taxerInfo 路由/窗口定义。

B. 接口协议差距

  • 现有 src/api/index.ts 全部走 API_QUEUE_CALLER_PATH=/api/queue/callerJSON REST
  • TaxerInfo 依赖的百税接口协议是 form-url-encoded + domain.ywId/domain.parmJson,目前项目中尚未实现该适配器。

C. 数据源差距

  • MainView/TicketListView 主要消费 call-terminal/* 接口(呼叫、票池、评价)。
  • TaxerInfo 需要额外数据源:
    • 百税 9.2.2 / 9.2.12 / 9.2.3
    • 紫云 today-enterprises
    • 本地票据扩展信息(企业名、税号映射等)

14.4 在现项目中建议的落位方案(不改代码阶段的设计结论)

方案选型

推荐新增独立窗口 taxerInfo(与 ticketList 同级),而不是直接塞入当前 500x100 主窗:

  1. 保留 main 作为呼叫条形控制台(最小侵入)。
  2. 在“更多菜单 -> 办税员窗口”中打开/聚焦 taxerInfo
  3. taxerInfo 使用新路由页面(建议 /taxerInfo)承载原 WPF 界面。

这样做的原因

  • 与现有多窗口架构一致(已有 ticketList 模式可复用)。
  • 不影响当前呼叫链路稳定性。
  • 便于逐步迁移 TaxerInfo 而非一次性替换 MainView

14.5 与现项目文件的映射建议

  • 前端:
    • 新增 src/views/TaxerInfoView.vue
    • src/router/index.ts 增加 /taxerInfo
    • src/host/window.ts 增加 openTaxerInfoWindow()
    • src/views/MainView.vuehandleMoreCommand("main") 改为打开/聚焦 taxerInfo
  • Rust
    • src-tauri/src/commands/window.rs 增加
      • open_taxer_info_window
      • close_taxer_info_window(可选)
    • src-tauri/src/lib.rs 注册上述命令

14.6 TaxerInfo 接口在现项目中的接入位置建议

前端 API 层

src/api 下新增 taxer.ts,避免和 call-terminal 混杂:

  • loadTaxerInfo(compareCode, currentTicketId)
  • startTaxerTicket(...)
  • endTaxerTicket(...)
  • getTodayEnterprises(ticketId)
  • buildNsrUrl(...) / buildYhscxUrl(...)(可前后端任选)

HTTP 传输层

沿用 src/utils/service.ts 的 axios + Tauri HTTP adapter 机制,但需要区分两类 baseURL

  1. 现有 API_QUEUE_CALLER_PATH
  2. 百税 API 专用 baseURLREALNAME_CHECK_API+ form 编码适配

14.7 文档结论更新(针对你的目标)

结合当前 Tauri 项目,TaxerInfo 改写最可行路径是:

  • 先新增 taxerInfo 独立窗口(由 MainView 的“办税员窗口”按钮打开)
  • 再迁移 C# TaxerInfo 的 UI 与接口编排
  • 最后再评估是否把条形主窗与办税员窗合并

这样既满足“在 Tauri 主流程中打开办税员窗口”,又不会破坏现有呼叫台功能。