99# 云印享 - 付费打印服务系统架构设计 ## 1. 项目概述 ### 1.1 项目背景 构建一个提供付费打印服务的微信小程序系统,用户可通过小程序上传文档/图片/压缩包,选择打印机并完成打印。系统包含用户端小程序、管理员端(Windows客户端)和后端服务。 ### 1.2 核心功能需求 | 模块 | 功能点 | |------|--------| | 用户端小程序 | 上传文件(文档/图片/压缩包)、价目表展示、选择打印机、文件编辑(预览/水印/合并)、聊天记录选择文件、打印订单管理 | | 管理员端 | 文库管理(上传资料供用户打印)、订单处理、打印机管理、用户管理 | | 后端服务 | 用户认证、文件存储、订单处理、API网关 | | Windows客户端 | 调用Windows API连接打印机、执行打印任务、文件预处理 | ### 1.3 技术栈 - **小程序端**:Taro(跨平台框架)+ React技术栈 - **后端**:Go + gRPC + MySQL + go-pay(微信支付) - **Windows客户端**:C# (.NET 8) + WPF - **管理后台**:React + Ant Design(网页端) - **文件存储**:本地存储 + MinIO(可选) - **通信**:gRPC + WebSocket --- ## 2. 系统架构 ### 2.1 整体架构图 ```mermaid flowchart TB subgraph Client["客户端层"] MiniApp["Taro微信小程序
用户端"] AdminWeb["React管理后台
网页端"] end subgraph Backend["后端服务层"] GRPC["gRPC Gateway
:8080"] Auth["认证服务"] File["文件服务"] Order["订单服务"] Print["打印服务"] Pay["支付服务
go-pay"] end subgraph Data["数据层"] MySQL["MySQL
数据库"] Redis["Redis
缓存"] MinIO["MinIO
文件存储"] end subgraph PrintShop["打印店内部署"] WinClient["C# WPF客户端
打印管理程序"] Printers["打印机列表"] LocalFiles["本地文库"] end MiniApp -->|"HTTPS/gRPC"| GRPC AdminWeb -->|"HTTPS/gRPC"| GRPC WinClient -->|"gRPC| WebSocket"| GRPC GRPC --> Auth GRPC --> File GRPC --> Order GRPC --> Print GRPC --> Pay Auth --> Redis Order --> MySQL File --> MinIO File --> MySQL Pay --> WeChat["微信支付"] WinClient --> Printers WinClient --> LocalFiles ``` ### 2.2 部署架构 ```mermaid flowchart LR subgraph Internet["互联网"] User["用户
微信小程序"] end subgraph Cloud["云服务器"] API_Server["Go API Server"] DB["MySQL + Redis"] File_Storage["文件存储服务"] end subgraph Local["打印店本地"] PC["Windows电脑
C# WPF客户端"] Printer["打印机"] end User -->|"上传文件/下单"| Cloud Cloud -->|"转发打印任务"| PC PC -->|"执行打印"| Printer ``` --- ## 3. 模块详细设计 ### 3.1 微信小程序端 #### 3.1.1 页面结构 ``` pages/ ├── index/ # 首页 │ ├──价目表展示 │ ├──快捷上传入口 │ └──最近的打印历史 ├── upload/ # 文件上传 │ ├──文件选择(支持聊天记录) │ ├──上传进度 │ └──文件预览 ├── editor/ # 文件编辑 │ ├──PDF预览 │ ├──水印设置 │ ├──页面合并 │ └──打印参数设置 ├── printer/ # 打印机选择 │ ├──打印机列表 │ ├──打印机状态 │ └──价格显示 ├── order/ # 订单管理 │ ├──订单列表 │ ├──订单详情 │ └──支付 ├── library/ # 文库(用户浏览) │ ├──分类列表 │ ├──文件搜索 │ └──文件详情 └── my/ # 个人中心 ├──打印记录 ├──账户余额 └──设置 ``` #### 3.1.2 核心页面流程 ```mermaid flowchart TD Start["首页"] --> Upload{"选择上传方式"} Upload -->|"本地上传"| SelectFile["选择文件"] Upload -->|"聊天记录"| ChatFile["从聊天选择"] SelectFile --> Preview["文件预览"] ChatFile --> Preview Preview --> Edit{"需要编辑?"} Edit -->|"是"| Editor["编辑页面"] Edit -->|"否"| SelectPrinter["选择打印机"] Editor --> SelectPrinter SelectPrinter --> Confirm["确认订单"] Confirm --> Pay["支付"] Pay --> Success["下单成功"] Success --> Notify["通知打印店"] ``` #### 3.1.3 文件编辑功能设计 | 功能 | 实现方式 | 说明 | |------|----------|------| | PDF预览 | pdf.js | 轻量级PDF预览,支持缩放、翻页 | | 添加水印 | 前端Canvas + 后端PDF处理 | 支持文字水印、位置、透明度 | | 页面合并 | pdf-lib | 合并多个PDF页面 | | 打印参数 | 份数、纸张大小、单双面、彩色/黑白 | 传递给Windows客户端 | ### 3.2 C# WPF打印客户端 #### 3.2.1 核心模块 ```csharp // 项目结构 CloudPrint.Client/ ├── App.xaml # 应用程序入口 ├── Services/ │ ├── PrintService.cs # 打印服务(调用Windows API) │ ├── FileService.cs # 文件处理服务 │ ├── GrpcService.cs # gRPC通信服务 │ └── WebSocketService.cs # WebSocket备用通信 ├── ViewModels/ │ ├── MainViewModel.cs # 主窗口 │ ├── PrintQueueViewModel.cs # 打印队列 │ ├── LibraryViewModel.cs # 文库管理 │ └── SettingsViewModel.cs # 设置 ├── Views/ │ ├── MainWindow.xaml │ ├── PrintQueueView.xaml │ ├── LibraryView.xaml │ └── SettingsView.xaml ├── Models/ │ ├── PrintJob.cs │ ├── Printer.cs │ └── Document.cs └── Helpers/ ├── WindowsPrintApi.cs # Windows打印API封装 └── PdfProcessor.cs # PDF处理 ``` #### 3.2.2 Windows打印API集成 使用 P/Invoke 调用 Windows Print Spooler API: - `OpenPrinter` - `StartDocPrinter` - `StartPagePrinter` - `WritePrinter` - `EndPagePrinter` - `EndDocPrinter` - `ClosePrinter` ```csharp // 核心打印服务类 public class PrintService { // 获取系统打印机列表 public List GetPrinters(); // 获取打印机状态 public PrinterStatus GetPrinterStatus(string printerName); // 提交打印任务 public string SubmitPrintJob(PrintJob job); // 取消打印任务 public bool CancelPrintJob(string jobId); // 获取打印任务状态 public PrintJobStatus GetJobStatus(string jobId); } ``` #### 3.2.3 gRPC通信 ```csharp // 与后端gRPC服务通信 public class GrpcService { // 连接gRPC服务器 public async Task ConnectAsync(string address); // 订阅打印任务流 public async Task SubscribePrintJobsAsync(string printerName); // 发送状态更新 public async Task SendStatusUpdateAsync(PrintJobStatus status); } ``` ### 3.3 后端服务(Go + gRPC + go-pay) #### 3.3.1 项目结构 ```text cloudprint-backend/ ├── cmd/ │ └── server/ │ └── main.go # 入口 ├── config/ │ └── config.go # 配置 ├── internal/ │ ├── grpc/ # gRPC服务 │ │ ├── server.go # gRPC服务器入口 │ │ ├── interceptor/ # 拦截器 │ │ └── service/ # 服务实现 │ │ ├── auth.go │ │ ├── file.go │ │ ├── order.go │ │ ├── print.go │ │ └── library.go │ ├── model/ # 数据模型 │ ├── repository/ # 数据访问 │ └── service/ # 业务逻辑 ├── pkg/ │ ├── jwt/ # JWT认证 │ ├── pay/ # 支付服务 (go-pay) │ └── upload/ # 文件上传 ├── proto/ # Protobuf定义 │ ├── cloudprint.proto │ └── generated/ # 生成的代码 ├── scripts/ │ └── db.sql # 数据库脚本 └── go.mod ``` #### 3.3.2 gRPC 服务设计 **认证服务 (AuthService)** ```protobuf service AuthService { rpc Login(LoginRequest) returns (LoginResponse); rpc RefreshToken(RefreshRequest) returns (RefreshResponse); rpc Logout(LogoutRequest) returns (Empty); } ``` **文件服务 (FileService)** ```protobuf service FileService { rpc Upload(stream UploadRequest) returns (UploadResponse); rpc GetFile(GetFileRequest) returns (stream FileData); rpc DeleteFile(DeleteRequest) returns (Empty); rpc AddWatermark(WatermarkRequest) returns (WatermarkResponse); } ``` **订单服务 (OrderService)** ```protobuf service OrderService { rpc CreateOrder(CreateOrderRequest) returns (OrderResponse); rpc GetOrderList(GetOrderListRequest) returns (OrderListResponse); rpc GetOrder(GetOrderRequest) returns (OrderResponse); rpc UpdateOrderStatus(UpdateStatusRequest) returns (Empty); rpc PayOrder(PayRequest) returns (PayResponse); } ``` **打印服务 (PrintService)** ```protobuf service PrintService { rpc GetPrinters(Empty) returns (PrinterListResponse); rpc GetPrinterStatus(PrinterRequest) returns (PrinterStatusResponse); rpc SubmitPrintJob(PrintJobRequest) returns (PrintJobResponse); rpc CancelPrintJob(CancelRequest) returns (Empty); rpc SubscribeJobs(SubscriberRequest) returns (stream PrintJob); rpc ReportJobStatus(JobStatusReport) returns (Empty); } ``` **文库服务 (LibraryService)** ```protobuf service LibraryService { rpc GetCategories(Empty) returns (CategoryListResponse); rpc GetFiles(GetFilesRequest) returns (FileListResponse); rpc UploadFile(stream UploadRequest) returns (UploadResponse); rpc DeleteFile(DeleteRequest) returns (Empty); } ``` **支付服务 (PayService)** ```protobuf service PayService { rpc CreateWxPayOrder(WxPayRequest) returns (WxPayResponse); rpc QueryWxPayStatus(QueryRequest) returns (PayStatusResponse); rpc HandleWxPayCallback(CallbackRequest) returns (CallbackResponse); } ``` #### 3.3.3 gRPC 通信流程 ```mermaid sequenceDiagram participant CSharp as C# WPF客户端 participant Go as Go gRPC服务器 participant DB as MySQL/Redis CSharp->>Go: 连接gRPC服务 (认证) Go-->>CSharp: 连接成功 CSharp->>Go: 注册打印机 (SubscribeJobs) Go->>DB: 查询待打印任务 DB-->>Go: 任务列表 loop 等待新任务 Go-->>CSharp: 推送新打印任务 (stream) CSharp->>CSharp: 处理文件/调用打印API CSharp->>Go: 上报状态 (ReportJobStatus) Go->>DB: 更新任务状态 end ``` ### 3.4 数据库设计 #### 3.4.1 ER 图 ```mermaid erDiagram User ||--o{ Order : places User { int id PK string openid UK string nickname decimal balance datetime created_at } Order ||--|{ OrderItem : contains Order ||--o{ Payment : has Order { int id PK string order_no UK int user_id FK int status decimal total_amount datetime created_at } OrderItem { int id PK int order_id FK int file_id FK string printer_name int copies bool color bool duplex string page_range decimal price } Payment { int id PK string order_no UK int pay_status string transaction_id datetime paid_at } File { int id PK string file_name string file_path string file_type int file_size string uploader_type int uploader_id datetime created_at } Library |||--|{ LibraryFile : contains Library { int id PK string name string description int sort_order } LibraryFile ||--o{ File : references LibraryFile { int id PK int library_id FK int file_id FK string title string description } Printer |||--o{ PrintJob : receives Printer { int id PK string name UK string display_name bool is_active string api_key UK } PrintJob { int id PK string job_no UK int printer_id FK int order_item_id FK string status int progress datetime started_at datetime completed_at } PriceList { int id PK string name string type decimal price string unit bool is_active } ``` #### 3.4.2 主要表结构 ```sql -- 用户表 CREATE TABLE `user` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `openid` VARCHAR(64) UNIQUE NOT NULL COMMENT '微信OpenID', `nickname` VARCHAR(128) DEFAULT '', `avatar` VARCHAR(512) DEFAULT '', `balance` DECIMAL(10,2) DEFAULT 0.00 COMMENT '余额', `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); -- 管理员表 CREATE TABLE `admin` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `username` VARCHAR(64) UNIQUE NOT NULL, `password_hash` VARCHAR(256) NOT NULL, `nickname` VARCHAR(128) DEFAULT '', `role` TINYINT DEFAULT 1 COMMENT '1:普通管理员 2:超级管理员', `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 打印机表 CREATE TABLE `printer` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(128) UNIQUE NOT NULL COMMENT '系统打印机名', `display_name` VARCHAR(128) NOT NULL COMMENT '显示名称', `api_key` VARCHAR(64) UNIQUE NOT NULL COMMENT '客户端认证Key', `is_active` TINYINT DEFAULT 1, `status` TINYINT DEFAULT 0 COMMENT '0:空闲 1:打印中 2:离线', `last_heartbeat` DATETIME, `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 订单表 CREATE TABLE `order` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `order_no` VARCHAR(32) UNIQUE NOT NULL COMMENT '订单号', `user_id` INT NOT NULL, `status` TINYINT DEFAULT 0 COMMENT '0:待支付 1:已支付 2:打印中 3:已完成 4:已取消', `total_amount` DECIMAL(10,2) NOT NULL, `remark` VARCHAR(512) DEFAULT '', `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, `paid_at` DATETIME, FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ); -- 订单明细表 CREATE TABLE `order_item` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `order_id` INT NOT NULL, `file_id` INT NOT NULL, `printer_id` INT, `copies` INT DEFAULT 1, `color` TINYINT DEFAULT 0, `duplex` TINYINT DEFAULT 0, `page_range` VARCHAR(64) DEFAULT 'all', `price` DECIMAL(10,2) NOT NULL, FOREIGN KEY (`order_id`) REFERENCES `order`(`id`), FOREIGN KEY (`file_id`) REFERENCES `file`(`id`) ); -- 文件表 CREATE TABLE `file` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `file_name` VARCHAR(256) NOT NULL, `file_path` VARCHAR(512) NOT NULL, `file_type` VARCHAR(32) NOT NULL COMMENT 'pdf/doc/docx/xls/xlsx/ppt/pptx/txt/jpg/png/zip', `file_size` BIGINT NOT NULL COMMENT '字节', `uploader_type` VARCHAR(16) NOT NULL COMMENT 'user/admin/system', `uploader_id` INT NOT NULL, `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 文库分类表 CREATE TABLE `library_category` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(128) NOT NULL, `icon` VARCHAR(128) DEFAULT '', `sort_order` INT DEFAULT 0, `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 文库文件表 CREATE TABLE `library_file` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `category_id` INT NOT NULL, `file_id` INT NOT NULL, `title` VARCHAR(256) NOT NULL, `description` VARCHAR(512) DEFAULT '', `page_count` INT DEFAULT 0, `download_count` INT DEFAULT 0, `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (`category_id`) REFERENCES `library_category`(`id`), FOREIGN KEY (`file_id`) REFERENCES `file`(`id`) ); -- 打印任务表 CREATE TABLE `print_job` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `job_no` VARCHAR(32) UNIQUE NOT NULL, `printer_id` INT NOT NULL, `order_item_id` INT NOT NULL, `status` VARCHAR(16) DEFAULT 'pending' COMMENT 'pending/printing/completed/failed/cancelled', `progress` INT DEFAULT 0, `error_msg` VARCHAR(512) DEFAULT '', `started_at` DATETIME, `completed_at` DATETIME, FOREIGN KEY (`printer_id`) REFERENCES `printer`(`id`) ); -- 价目表 CREATE TABLE `price_list` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(128) NOT NULL COMMENT '项目名称', `type` VARCHAR(32) NOT NULL COMMENT '纸张类型: A4/A3/照片纸', `price` DECIMAL(10,2) NOT NULL COMMENT '单价', `unit` VARCHAR(16) NOT NULL COMMENT '单位: 页/张/份', `color_enabled` TINYINT DEFAULT 1 COMMENT '是否支持彩色', `is_active` TINYINT DEFAULT 1, `sort_order` INT DEFAULT 0, `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 支付记录表 CREATE TABLE `payment` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `order_no` VARCHAR(32) UNIQUE NOT NULL, `pay_type` VARCHAR(16) DEFAULT 'wechat' COMMENT 'wechat/balance', `pay_status` TINYINT DEFAULT 0 COMMENT '0:待支付 1:支付中 2:成功 3:失败', `transaction_id` VARCHAR(64) DEFAULT '', `paid_at` DATETIME, `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP ); ``` --- ## 4. 核心流程 ### 4.1 用户打印流程 ```mermaid sequenceDiagram participant User as 用户 participant MiniApp as 微信小程序 participant Backend as Go后端 participant Windows as Windows客户端 participant Printer as 打印机 User->>MiniApp: 选择文件上传 MiniApp->>MiniApp: 文件预览/编辑 User->>MiniApp: 确认打印参数 MiniApp->>Backend: 创建订单 Backend-->>MiniApp: 订单信息 User->>MiniApp: 支付订单 MiniApp->>Backend: 支付回调 Backend->>Windows: WebSocket推送打印任务 Windows->>Backend: 下载文件 Windows->>Windows: PDF预处理 Windows->>Printer: 发送打印指令 Printer-->>Windows: 打印中 Windows->>Backend: 更新任务状态 Backend->>MiniApp: 推送状态更新 Printer-->>User: 输出打印件 ``` ### 4.2 管理员上传文库流程 ```mermaid flowchart TD Admin["管理员登录Windows客户端"] --> Navigate["进入文库管理"] Navigate --> SelectCategory["选择分类"] SelectCategory --> Upload["上传文件"] Upload --> SetInfo["设置文件标题描述"] SetInfo --> Confirm["确认上传"] Confirm --> Save["保存到数据库"] Save --> Sync["同步到云端"] Sync --> Success["上传成功"] ``` --- ## 5. 文件处理 ### 5.1 支持的文件格式 | 类型 | 格式 | 处理方式 | |------|------|----------| | 文档 | doc, docx, txt | 转为PDF后打印 | | 表格 | xls, xlsx | 转为PDF后打印 | | 演示 | ppt, pptx | 转为PDF后打印 | | 图片 | jpg, png, bmp, gif | 直接打印或转PDF | | 压缩包 | zip, rar | 解压后处理内部文件 | | PDF | pdf | 直接打印 | ### 5.2 C#端文件转换 使用以下库/工具进行文件转换: - **Word/Excel/PowerPoint**: Microsoft Office COM Automation 或 LibreOffice Headless - **图片**: System.Drawing - **压缩包**: SharpCompress - **PDF合并/水印**: PDFsharp 或 iTextSharp --- ## 6. 安全设计 ### 6.1 认证授权 - **用户端**: 微信 OAuth2.0 获取 OpenID - **管理后台**: 用户名密码 + JWT Token - **打印客户端**: API Key 认证 + gRPC TLS加密连接 ### 6.2 数据安全 - 文件上传: 大小限制 (单文件 50MB) - 文件类型白名单验证 - SQL注入防护: 使用参数化查询 - XSS防护: 输出编码 - gRPC传输加密: TLS 1.3 ### 6.3 打印客户端认证 gRPC认证流程: 1. 客户端使用API Key获取临时凭证 2. 使用凭证建立gRPC TLS连接 3. 服务端验证客户端身份 4. 建立长连接后订阅打印任务流 --- ## 7. 开发计划 ### 7.1 项目模块划分 1. **cloudprint-miniapp** - Taro微信小程序用户端 2. **cloudprint-backend** - Go + gRPC 后端服务 3. **cloudprint-client** - C# (.NET 8) + WPF 打印客户端 4. **cloudprint-admin** - React 管理后台网页端 5. **cloudprint-proto** - Protobuf 定义共享库 ### 7.2 开发顺序 ``` 1. cloudprint-proto (公共协议定义) ├── 定义所有 gRPC 服务和消息类型 ├── 生成 Go、C#、TypeScript 代码 2. cloudprint-backend (Go + gRPC + go-pay) ├── 数据库设计与初始化 ├── 基础框架搭建 ├── 认证模块 (JWT) ├── 文件服务 ├── 订单服务 ├── 打印服务 ├── 文库服务 └── 微信支付集成 (go-pay) 3. cloudprint-client (C# WPF) ├── 项目初始化 (.NET 8) ├── 打印服务开发 (P/Invoke Windows API) ├── gRPC 通信 (Grpc.Net) ├── WebSocket 通信 (用于推送) ├── 文件处理 └── 文库管理 4. cloudprint-admin (React + Ant Design) ├── 项目初始化 ├── 登录认证 ├── 订单管理 ├── 用户管理 ├── 价目表管理 └── 数据统计 5. cloudprint-miniapp (Taro) ├── 项目初始化 (@tarojs/cli) ├── 用户端页面开发 ├── 文件上传与编辑 ├── 订单流程 └── 与后端 gRPC 对接 ``` --- ## 8. 部署方案 ### 8.1 云服务器要求 - **配置**: 2核4G起步 - **系统**: Ubuntu 22.04 / CentOS 8 - **数据库**: MySQL 8.0 - **缓存**: Redis 6.0 - **文件存储**: 本地磁盘或 MinIO ### 8.2 打印店客户端部署 1. 在打印店电脑安装 Windows 10/11 + .NET 8 Runtime 2. 运行 C# WPF 客户端程序,配置服务器地址 3. 登录管理员账号 4. 配置打印机 5. 保持客户端在线 --- ## 9. 风险与注意事项 | 风险 | 应对措施 | |------|----------| | 文件格式兼容 | C#客户端集成LibreOffice转换 | | 打印质量差异 | 客户端提供打印参数调试 | | 大文件传输 | 分片上传、断点续传 | | 客户端掉线 | gRPC心跳检测、自动重连 | | 支付安全 | 微信支付官方SDK (go-pay) | | 并发打印 | 任务队列、打印机组 |