工单管理服务,负责客户支持工单的全生命周期管理。支持创建工单、状态流转、处理人分配和回复(含内部备注)。Admin 用户可管理所有工单,Customer 用户只能查看和操作自己的工单。
| RPC | 描述 | 权限 |
| CreateTicket | 创建工单 | 已认证 |
| ListTickets | 工单列表(分页+筛选) | admin 全量 / customer 自身 |
| GetTicket | 获取工单详情(含回复列表) | admin 全量 / customer 自身 |
| UpdateTicket | 更新工单状态/优先级/处理人/描述 | admin |
| CreateReply | 添加工单回复 | 已认证 |
| DeleteTicket | 删除工单 | admin |
创建新工单。Admin 创建时可指定 customer_id 为特定客户创建;Customer 用户创建时自动绑定自身客户。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| customer_id | string | 1 | 是 | 客户 ID(admin 指定,customer 自动设置) |
| title | string | 2 | 是 | 工单标题 |
| description | string | 3 | 是 | 问题描述 |
| priority | string | 4 | 是 | 优先级:"low" / "medium" / "high" / "urgent"(默认 "medium") |
| 字段 | 类型 | 编号 | 描述 |
| ticket | TicketInfo | 1 | 创建的工单信息 |
| 错误 | 说明 |
| InvalidArgument | 标题为空或优先级无效 |
| NotFound | 指定客户不存在 |
| Unauthenticated | 未登录 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"customer_id":"0192a123-...","title":"服务器无法连接","description":"VPS 无法通过 SSH 连接,已尝试重启无效","priority":"high"}' \
localhost:50051 rustbill.ticket.TicketService/CreateTicket
const resp = await api.createTicket({
customer_id: "0192a123-...",
title: "服务器无法连接",
description: "VPS 无法通过 SSH 连接,已尝试重启无效",
priority: "high"
});
分页查询工单列表。Admin 可查看所有工单,Customer 自动限定为自身工单。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| pagination | PageRequest | 1 | 是 | 分页参数 |
| customer_id | string? | 2 | 否 | 按客户过滤(admin 可用) |
| status | string? | 3 | 否 | 按状态过滤:"pending" / "processing" / "resolved" / "closed" |
| priority | string? | 4 | 否 | 按优先级过滤:"low" / "medium" / "high" / "urgent" |
| assignee_user_id | string? | 5 | 否 | 按处理人过滤 |
| 字段 | 类型 | 编号 | 描述 |
| tickets | repeated TicketInfo | 1 | 工单列表 |
| meta | PageMeta | 2 | 分页元数据 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"pagination":{"page":1,"page_size":20},"status":"pending","priority":"high"}' \
localhost:50051 rustbill.ticket.TicketService/ListTickets
获取单个工单详情,包含完整回复列表。is_internal=true 的回复仅对 admin 可见,customer 请求中自动过滤。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| id | string | 1 | 是 | 工单 ID(UUID) |
| 字段 | 类型 | 编号 | 描述 |
| ticket | TicketInfo | 1 | 工单信息(含回复列表) |
| 错误 | 说明 |
| NotFound | 工单不存在 |
| PermissionDenied | customer 用户无权查看他人工单 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"id":"0192a123-4567-7890-abcd-ef0123456789"}' \
localhost:50051 rustbill.ticket.TicketService/GetTicket
更新工单状态、优先级、处理人或描述。更改处理人时会触发通知系统向新旧处理人发送工单分配通知。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| id | string | 1 | 是 | 工单 ID |
| status | string? | 2 | 否 | 新状态:"pending" / "processing" / "resolved" / "closed" |
| priority | string? | 3 | 否 | 新优先级 |
| assignee_user_id | string? | 4 | 否 | 新处理人用户 ID(变更时触发通知) |
| description | string? | 5 | 否 | 更新的问题描述 |
| 字段 | 类型 | 编号 | 描述 |
| ticket | TicketInfo | 1 | 更新后的工单信息 |
| 错误 | 说明 |
| NotFound | 工单不存在 |
| InvalidArgument | 状态流转不合法 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"id":"0192a123-...","status":"processing","assignee_user_id":"0192b456-..."}' \
localhost:50051 rustbill.ticket.TicketService/UpdateTicket
添加工单回复。is_internal=true 的回复为内部备注,仅 admin 可见。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| ticket_id | string | 1 | 是 | 工单 ID(UUID) |
| content | string | 2 | 是 | 回复内容 |
| is_internal | bool | 3 | 是 | 是否为内部备注 |
| 字段 | 类型 | 编号 | 描述 |
| reply | TicketReplyInfo | 1 | 创建的回复信息 |
| 错误 | 说明 |
| NotFound | 工单不存在 |
| InvalidArgument | 回复内容为空 |
| Unauthenticated | 未登录 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"ticket_id":"0192a123-...","content":"已定位问题,正在修复","is_internal":false}' \
localhost:50051 rustbill.ticket.TicketService/CreateReply
const resp = await api.createReply({
ticket_id: "0192a123-...",
content: "请提供更多信息",
is_internal: false
});
删除指定工单及其所有回复。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| id | string | 1 | 是 | 工单 ID(UUID) |
无字段。
| 错误 | 说明 |
| NotFound | 工单不存在 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"id":"0192a123-4567-7890-abcd-ef0123456789"}' \
localhost:50051 rustbill.ticket.TicketService/DeleteTicket
| 字段 | 类型 | 编号 | 描述 |
| id | string | 1 | 工单 UUID |
| customer_id | string | 2 | 关联客户 ID |
| title | string | 3 | 工单标题 |
| description | string | 4 | 问题描述 |
| status | string | 5 | 状态:"pending" / "processing" / "resolved" / "closed" |
| priority | string | 6 | 优先级:"low" / "medium" / "high" / "urgent" |
| assignee_user_id | string | 7 | 处理人用户 ID |
| creator_user_id | string | 8 | 创建人用户 ID(admin 创建时设置) |
| created_at | string | 9 | 创建时间(RFC3339) |
| updated_at | string | 10 | 更新时间(RFC3339) |
| replies | repeated TicketReplyInfo | 11 | 回复列表 |
| 字段 | 类型 | 编号 | 描述 |
| id | string | 1 | 回复 UUID |
| ticket_id | string | 2 | 关联工单 ID |
| user_id | string | 3 | 回复人 admin 用户 ID(customer 回复时为空) |
| customer_id | string | 4 | 回复人客户 ID(admin 回复时为空) |
| content | string | 5 | 回复内容 |
| is_internal | bool | 6 | 是否为内部备注(customer 不可见) |
| created_at | string | 7 | 创建时间(RFC3339) |
pending → processing → resolved → closed
| 状态 | 说明 |
| pending | 待处理 |
| processing | 处理中 |
| resolved | 已解决 |
| closed | 已关闭 |
| 优先级 | 值 | 说明 |
| low | 低 | 非紧急问题 |
| medium | 中 | 一般问题(默认) |
| high | 高 | 影响业务但可等待 |
| urgent | 紧急 | 业务完全中断 |