背景
线下抽奖现有链路:
apps/web/src/views/lottery.vue:lottery_mode === 'offline' 时需管理员登录,调用 POST /lottery/activities/:id/offline-draw
- 后端
apps/service/src/routes/lottery.js 创建 lottery_records(含 operator_id),返回中奖结果
- 前端弹出结果 Dialog,5 秒后自动关闭
- 活动详情
activityDetail.vue 展示抽奖记录,目前没有签字字段
系统设置页 settings.vue、superSettings.vue 目前几乎是空壳。GET /system/config 是硬编码,config/system.json 只存安装元数据,没有 COS 配置,也没有写配置接口。
目标
- 仅线下抽奖:抽奖完成后弹出签字弹窗,是否开启在抽奖配置中决定
- 签字图片由后端上传到腾讯云 COS,不要把
SecretKey 下发到浏览器
- 未配置 COS 时,组织在抽奖配置中勾选打开签字功能
- 将 COS 对象键 / 访问信息写回对应
lottery_records
- 超级管理员可在系统设置中配置 COS:
SecretId、SecretKey、Bucket(bucketname-appid)、Region,可选自定义域名 / 对象前缀
- 活动详情的抽奖记录可查看签字状态和预览## 建议流程
管理员输入抽奖码 → offline-draw 成功
→ 展示抽奖结果
→ 打开签字弹窗(取消现有 5 秒自动关闭,避免打断签字)
→ Canvas 导出 PNG
→ POST 到后端(record_id + 图片)
→ 后端 putObject 到 COS
→ 更新 lottery_records.signature_*
→ 记录页可预览
签字必须走后端上传。COS 官方也建议密钥只放服务端,并优先子账号最小权限。
签字库依赖
这里不做强制指定,但如果你没做过,可以看看!
| 方案 |
包 |
说明 |
| 推荐 A |
* signature_pad(szimek/signature_pad) |
行业标准 Canvas 库,星标多、TypeScript 友好,可包一层 Vue 组件,和现有 shadcn-vue Dialog 最贴合 |
| 推荐 B |
@selemondev/vue3-signature-pad |
Vue 3 + TS 封装,2026 仍在维护,底层同样是 signature_pad |
| 推荐 C |
vue3-signature |
中文社区常用封装,底层 signature_pad 5.x |
不建议 vue-signature-pad(偏 Vue 2)。项目已有 @vueuse/core、reka-ui Dialog,没有现成签字能力,需要新增依赖。
签字信息存储
腾讯云 COS:
- 官方包:
cos-nodejs-sdk-v5(要求 Node.js ≥ 9,本仓库 Node ≥ 20 满足)
- 文档:快速入门、接口文档
- 签字图很小,用
putObject + Body: Buffer 即可,不必上分块上传
- 配置项:
SecretId、SecretKey、Bucket(格式 name-appid)、Region(如 ap-guangzhou)
- 对象键建议:
lottery-signatures/{activityId}/{recordId}/{timestamp}.png
可能的改造点
以下内容为 AI 根据项目已有情况进行整理,具体请根据实际改造需求进行改造,
前端改造点
-
新建签字组件(如 SignatureDialog.vue)
复用现有 Dialog:画布、清空、撤销、确认。触摸屏要可用(线下现场常见平板)。
-
lottery.vue
- 仅
offline 模式、抽奖成功后弹出签字
- 去掉或延长结果 Dialog 的 5 秒自动关闭
offlineDraw 返回的 lottery_record.id 作为上传关联 ID
- 处理未配置 COS、上传失败、用户拒签
-
系统设置
- 建议做在
superSettings.vue(超级管理员),settings.vue 也可入口但需鉴权
- 表单:SecretId / SecretKey / Bucket / Region,可选 Path Prefix、自定义域名
- SecretKey 回显脱敏,留空表示不修改
- 可选「测试连接」按钮
-
API / 类型
apps/web/src/api.ts:上传签字、读写 COS 配置
types/api.ts 的 LotteryRecord 增加 signature_url / signed_at 等
-
activityDetail.vue 记录表
增加「签字」列:未签 / 已签预览(Dialog 或新窗口)。DataTable 已支持自定义 render。
-
i18n:apps/web/src/i18n/locales/zh.json 补文案。
后端改造点
-
数据表 lottery_records(scripts/install.js + 已有库的迁移)建议字段:
signature_key VARCHAR:COS Object Key
signature_url VARCHAR:访问 URL(或只存 key,读取时再签临时链)
signed_at DATETIME
- 可选
signature_status:unsigned / signed
-
Model:LotteryRecord.js 的 createRecord、findByActivity;activities.js 里 GET /admin/activities/:id/records 的精简返回要带上签字字段。
-
签字上传接口(需管理员鉴权)
建议:POST /lottery/activities/:id/records/:recordId/signature
- 校验记录属于该活动、是线下抽奖、调用者有权限
- 接收
multipart 或 PNG base64,限制大小(如 1–2MB)和 MIME
- 上传 COS 成功后再写库
- COS 未配置时返回明确错误
-
COS 系统配置接口(requireSuperAdmin)
GET /system/cos-config:SecretKey 脱敏
PUT /system/cos-config:更新;SecretKey 空则保留原值
- 可选
POST /system/cos-config/test:getService 或对测试 key 做 headObject/putObject
- 存储位置实施者自定:扩展
config/system.json,或独立配置文件 / 表。密钥不要进 git,不要明文打日志。
-
COS 客户端封装
例如 apps/service/src/utils/cosClient.js,按 官方示例 初始化,统一 putObject / getObjectUrl。存储桶建议私有,预览用预签名 URL。
-
测试
扩展 tests/routes/lottery.test.js 的 offline-draw:上传成功、未配置 COS、非线下记录、无权限。配置接口测超级管理员权限和脱敏。
-
OpenAPI:同步 apps/service/openapi.json。
验收
背景
线下抽奖现有链路:
apps/web/src/views/lottery.vue:lottery_mode === 'offline'时需管理员登录,调用POST /lottery/activities/:id/offline-drawapps/service/src/routes/lottery.js创建lottery_records(含operator_id),返回中奖结果activityDetail.vue展示抽奖记录,目前没有签字字段系统设置页
settings.vue、superSettings.vue目前几乎是空壳。GET /system/config是硬编码,config/system.json只存安装元数据,没有 COS 配置,也没有写配置接口。目标
SecretKey下发到浏览器lottery_recordsSecretId、SecretKey、Bucket(bucketname-appid)、Region,可选自定义域名 / 对象前缀签字必须走后端上传。COS 官方也建议密钥只放服务端,并优先子账号最小权限。
签字库依赖
这里不做强制指定,但如果你没做过,可以看看!
signature_pad(szimek/signature_pad)@selemondev/vue3-signature-padsignature_padvue3-signaturesignature_pad5.x不建议
vue-signature-pad(偏 Vue 2)。项目已有@vueuse/core、reka-uiDialog,没有现成签字能力,需要新增依赖。签字信息存储
腾讯云 COS:
cos-nodejs-sdk-v5(要求 Node.js ≥ 9,本仓库 Node ≥ 20 满足)putObject+Body: Buffer即可,不必上分块上传SecretId、SecretKey、Bucket(格式name-appid)、Region(如ap-guangzhou)lottery-signatures/{activityId}/{recordId}/{timestamp}.png可能的改造点
以下内容为 AI 根据项目已有情况进行整理,具体请根据实际改造需求进行改造,
前端改造点
新建签字组件(如
SignatureDialog.vue)复用现有 Dialog:画布、清空、撤销、确认。触摸屏要可用(线下现场常见平板)。
lottery.vueoffline模式、抽奖成功后弹出签字offlineDraw返回的lottery_record.id作为上传关联 ID系统设置
superSettings.vue(超级管理员),settings.vue也可入口但需鉴权API / 类型
apps/web/src/api.ts:上传签字、读写 COS 配置types/api.ts的LotteryRecord增加signature_url/signed_at等activityDetail.vue记录表增加「签字」列:未签 / 已签预览(Dialog 或新窗口)。
DataTable已支持自定义render。i18n:
apps/web/src/i18n/locales/zh.json补文案。后端改造点
数据表
lottery_records(scripts/install.js+ 已有库的迁移)建议字段:signature_keyVARCHAR:COS Object Keysignature_urlVARCHAR:访问 URL(或只存 key,读取时再签临时链)signed_atDATETIMEsignature_status:unsigned/signedModel:
LotteryRecord.js的createRecord、findByActivity;activities.js里GET /admin/activities/:id/records的精简返回要带上签字字段。签字上传接口(需管理员鉴权)
建议:
POST /lottery/activities/:id/records/:recordId/signaturemultipart或 PNG base64,限制大小(如 1–2MB)和 MIMECOS 系统配置接口(
requireSuperAdmin)GET /system/cos-config:SecretKey 脱敏PUT /system/cos-config:更新;SecretKey 空则保留原值POST /system/cos-config/test:getService或对测试 key 做headObject/putObjectconfig/system.json,或独立配置文件 / 表。密钥不要进 git,不要明文打日志。COS 客户端封装
例如
apps/service/src/utils/cosClient.js,按 官方示例 初始化,统一putObject/getObjectUrl。存储桶建议私有,预览用预签名 URL。测试
扩展
tests/routes/lottery.test.js的offline-draw:上传成功、未配置 COS、非线下记录、无权限。配置接口测超级管理员权限和脱敏。OpenAPI:同步
apps/service/openapi.json。验收