refactor: 白板从画笔画板改为文本记事本

原实现是 Canvas 画笔画板,与「文字白板/记事本」需求不符。重做为纯文本实时协作:
- model:strokes JSON -> content TEXT + version INT(乐观锁)+ edit_count;
  schema/dao/service 同步重构,append_stroke/replace_strokes -> update_content。
- WS 协议:stroke -> edit(发完整文本,debounce 400ms);init 下发 content/version。
  update 帧广播给他人,cleared 广播给所有人。
- 前端:canvas -> textarea;收到远端 update 用最长公共前后缀算变更区间,
  仅替换该区间并保留光标(区间前不动/后平移/内移末尾);清空/复制文本按钮。
- schema.sql 更新 whiteboard 表 DDL;DB 旧表 DROP 重建(开发环境)。
- 测试脚本与 README 同步更新。
This commit is contained in:
zikai
2026-07-21 15:00:25 +00:00
parent 7bacc33679
commit 655e039aad
13 changed files with 240 additions and 271 deletions

View File

@@ -1,13 +1,11 @@
"""Whiteboard 的 DAO。
"""Whiteboard 的 DAO(文本记事本)
所有写操作均在该层 commitservice 不直接操作 session。
get_or_create 用于「访问即新建」语义(路由 GET /whiteboard/{id} 不存在则建)。
get_or_create 用于「访问即新建」语义(路由 GET /api/wb/{id} 不存在则建)。
"""
from __future__ import annotations
from typing import Any
from sqlalchemy import func, select
from sqlalchemy.orm import Session
@@ -33,7 +31,7 @@ class WhiteboardDAO:
board = self.get(board_id)
if board is not None:
return board
board = Whiteboard(board_id=board_id, strokes=[], stroke_count=0)
board = Whiteboard(board_id=board_id, content="", version=0, edit_count=0)
try:
return self.create(board)
except Exception:
@@ -41,24 +39,14 @@ class WhiteboardDAO:
self.db.rollback()
return self.get(board_id) # type: ignore[return-value]
def append_strokes(self, board_id: str, new_strokes: list[Any]) -> Whiteboard | None:
"""把新笔画追加到 strokes 数组尾部stroke_count 自增"""
def update_content(self, board_id: str, content: str) -> Whiteboard | None:
"""整体替换文本内容version +1、edit_count +1"""
board = self.get(board_id)
if board is None:
return None
board.strokes = [*board.strokes, *new_strokes]
board.stroke_count = (board.stroke_count or 0) + len(new_strokes)
self.db.commit()
self.db.refresh(board)
return board
def replace_strokes(self, board_id: str, strokes: list[Any]) -> Whiteboard | None:
"""整体替换 strokes清空时传 []stroke_count 自增 1。"""
board = self.get(board_id)
if board is None:
return None
board.strokes = list(strokes)
board.stroke_count = (board.stroke_count or 0) + 1
board.content = content
board.version = (board.version or 0) + 1
board.edit_count = (board.edit_count or 0) + 1
self.db.commit()
self.db.refresh(board)
return board