18 KiB
TaxerInfo 模块改写为 Tauri v1(单窗口 + Vue)设计文档
1. 文档目标
将 CallClient/WPF/TaxerInfo.xaml.cs + CallClient/WPF/TaxerInfo.xaml 对应功能迁移到 Tauri v1 + Vue(单窗口) 架构,确保:
- 业务行为与现有 WPF 一致(取号、开始办理、办结、实名信息、企业列表、网页加载、复制、查询)。
- 桌面能力由 Tauri(Rust)提供,界面由 Vue 负责。
- 后续可以逐步替换原
WebBrowser内嵌业务页,最终统一为前端组件化实现。
2. 现有模块功能盘点(WPF)
2.1 核心职责
TaxerInfo 窗口当前承担:
- 展示办税员实名信息(身份证图、头像、姓名、手机号、采集状态)。
- 展示当前取号下的企业/票据列表,支持“开始”“办结”“选择企业”。
- 根据当前票据拼接 URL 并加载纳税人页面(
WebBrowser)。 - 提供操作按钮:复制税号、复制号码、刷新、一户式查询。
- 展示“代理人办理企业清单”(通过 HTTP 接口获取)。
2.2 主要数据模型
ticket:票据/办理对象(状态、企业信息、号票信息等)。Enterprise:代理人办理企业清单项。SerialNumberEnterpriseNameTaxpayerId
ApiResponse / DataItem:today-enterprises接口返回结构。- 外部响应:
SmzJhxtGetBsyxxByqhhmResponseSmzJhxtGetSmzcjxxResponseSmzJhxtGetBdNsrxxResponse
2.3 关键流程
LoadInfo(comparecode)触发加载:- 调实名接口、绑定纳税人接口、绑定企业接口;
- 查询当日关联票据列表;
- 填充 UI。
- 票据切换(
SelectedSubTicket):- 更新“当前办理文案”;
- 刷新纳税人页面 URL。
- 开始办理(
StartCommand):- 更新票据状态为办理中;
- 记录窗口/员工信息;
- 刷新右侧页面。
- 办结(
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 -> SerialNumberserviceTarget -> EnterpriseNameserviceTargetCode -> 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。SelectedSubTicketsetter:切换企业 -> 重算currentCompanyText与nsrUrl。LoadInfo:初始化 ->taxer_load_info一次加载。
7. 页面交互细节(Vue)
- 页面
onMounted调taxer_load_info。 - 左侧列表点击行 => 更新
selectedSubTicket,调用taxer_build_nsr_url。 - 列表项按钮显示规则(与现有一致):
- 显示“开始”:
isStarted && (status == 0 || status == 2) - 显示“办结”:
isStarted && status == 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.BaishuiModelSmzJhxtGetBsyxxByqhhm(取号号 -> 办税员信息)SmzGetSmzcjxx(身份证号 -> 采集信息)SmzJhxtGetBdNsrxx(身份证号 -> 绑定纳税人)
QueuingSystemSDK.ticketUpdate()、Stop()、Abandon()、GetList(...)
QueuingSystemSDK.businessnew business((int)t.BIZ_UID)用于补全业务名称
QueuingSystemSDK.SystemControlGet("REALNAME_CHECK_API")、Get("BS_NSR_URL")、Get("BS_YHSCX_URL")、Get("BS_TAX_AUTHORITY_NUM")、Get("ZIYUN_SERVICE_URL")
QueuingSystemSDK.HttpHelperhttpGet("{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]表并映射对象
- 直接拼 SQL 查
这意味着 Tauri 改写时有两个实现路径:
- 兼容优先:继续复用现有 .NET 服务层(本地中间服务)操作数据库;Tauri 仅调用中间层 API。
- 重写优先:Rust 直接连库并重建
ticketSQL 逻辑(工作量和风险更高)。
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 -> SerialNumberserviceTarget -> EnterpriseNameserviceTargetCode -> TaxpayerId
- 否则清空列表
13.7 Tauri v1 落地时的“接口保持一致”建议
A. 百税接口适配器(Rust)必须做到
- 保持相同
bid与请求字段名 - 保持 form 参数名:
domain.ywId、domain.parmJson - 保持 UTF-8 + URL 编码行为(百分号大写)
- 保持错误语义:
SmzJhxtGetBsyxxByqhhm:code != "00"视为失败SmzGetSmzcjxx:允许"00"和"01"SmzJhxtGetBdNsrxx:当前 SDK 对非 00 未强拦截(按原行为兼容)
B. 队列票据能力建议
- 第一阶段不要在 Rust 侧直连数据库重写
ticket全量逻辑; - 建议先将
Start/Stop/GetList封成可调用服务(HTTP/IPC),Tauri 调该服务; - 等功能回归稳定后再考虑 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_windowclose_ticket_windowfocus_windowopen_main_windowopen_login_window
- 当前窗口形态:
main窗口:500x100、always_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/caller(JSON 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 主窗:
- 保留
main作为呼叫条形控制台(最小侵入)。 - 在“更多菜单 -> 办税员窗口”中打开/聚焦
taxerInfo。 taxerInfo使用新路由页面(建议/taxerInfo)承载原 WPF 界面。
这样做的原因
- 与现有多窗口架构一致(已有
ticketList模式可复用)。 - 不影响当前呼叫链路稳定性。
- 便于逐步迁移
TaxerInfo而非一次性替换MainView。
14.5 与现项目文件的映射建议
- 前端:
- 新增
src/views/TaxerInfoView.vue src/router/index.ts增加/taxerInfosrc/host/window.ts增加openTaxerInfoWindow()src/views/MainView.vue的handleMoreCommand("main")改为打开/聚焦taxerInfo
- 新增
- Rust:
src-tauri/src/commands/window.rs增加open_taxer_info_windowclose_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:
- 现有
API_QUEUE_CALLER_PATH - 百税 API 专用 baseURL(
REALNAME_CHECK_API)+ form 编码适配
14.7 文档结论更新(针对你的目标)
结合当前 Tauri 项目,TaxerInfo 改写最可行路径是:
- 先新增
taxerInfo独立窗口(由MainView的“办税员窗口”按钮打开) - 再迁移 C#
TaxerInfo的 UI 与接口编排 - 最后再评估是否把条形主窗与办税员窗合并
这样既满足“在 Tauri 主流程中打开办税员窗口”,又不会破坏现有呼叫台功能。