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) |
| 并发打印 | 任务队列、打印机组 |