feat: full-field display for message/staff/accounts (raw_json + drawers)
Replicates the Customer all-fields pattern across the remaining three entities. Backend now exposes `raw_json` on MessageOut / StaffOut / AccountOut so the frontend can render every 云客 source field without a second endpoint. Each entity gains a Chinese-label field utility + an el-drawer surfacing all fields (structured-first, raw_json fallback, unknown keys under 其他). Backend: - schemas.py: add `raw_json: dict | None` to MessageOut / StaffOut / AccountOut. MessageOut/StaffOut pick the column up via from_attributes; AccountOut is built explicitly in the router, which now threads `raw_json` through from both WechatAccount and WhatsappAccount rows. - tests: new raw_json serialization tests for messages, staff, accounts (assert populated dict round-trips verbatim + NULL serializes as null). Frontend (yunkes/): - New utils: messageFields.ts, staffFields.ts, accountFields.ts — each with a 中文 label map, ordered groups, structured-column preference, and an 其他 fallback for unknown raw_json keys. - Message: clicking a chat bubble opens an all-fields drawer (referMsg renders as pretty-printed JSON). Image preview + file download links stopPropagation so their own interactions still work. - Staff: row click → drawer; columns relabeled (员工ID, 销售手机). - Accounts: new AccountList.vue at /accounts with a 账号 nav item, unified WeChat/WhatsApp table (渠道/账号ID/昵称/微信号/归属员工/好友数/ 群数/收发/在职/最后更新), channel filter, pagination, row-click drawer. - api: add Account type + getAccounts(); add raw_json to Message/Staff. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -68,7 +68,12 @@ class DepartmentOut(BaseModel):
|
||||
|
||||
|
||||
class StaffOut(BaseModel):
|
||||
"""Staff member (employee) row."""
|
||||
"""Staff member (employee) row.
|
||||
|
||||
The structured columns power the list table; the verbatim upstream record
|
||||
is exposed as ``raw_json`` so the frontend can render the all-fields drawer
|
||||
without a second endpoint. Picked up automatically via ``from_attributes``.
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
@@ -78,6 +83,7 @@ class StaffOut(BaseModel):
|
||||
sale_phone: str | None = None
|
||||
dept_id: str | None = None
|
||||
is_on_job: bool | None = None
|
||||
raw_json: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class AccountOut(BaseModel):
|
||||
@@ -87,7 +93,9 @@ class AccountOut(BaseModel):
|
||||
have different PK / column names; this view projects both onto a single
|
||||
shape keyed by ``channel`` + ``account_id`` so the frontend can render one
|
||||
list. Built explicitly in the route handler (not via ``from_attributes``)
|
||||
because no single ORM row carries this schema.
|
||||
because no single ORM row carries this schema. ``raw_json`` carries the
|
||||
verbatim upstream record (wechatId/alias/sendNum/receiveNum/dbSize/...) so
|
||||
the all-fields drawer can render every column the 云客 微信号管理 page shows.
|
||||
"""
|
||||
|
||||
channel: str
|
||||
@@ -99,6 +107,7 @@ class AccountOut(BaseModel):
|
||||
contacts_num: int | None = None
|
||||
group_num: int | None = None
|
||||
is_on_job: bool | None = None
|
||||
raw_json: dict[str, Any] | None = None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -107,7 +116,14 @@ class AccountOut(BaseModel):
|
||||
|
||||
|
||||
class MessageOut(BaseModel):
|
||||
"""Chat timeline row — a single message (text/media/voice/...)."""
|
||||
"""Chat timeline row — a single message (text/media/voice/...).
|
||||
|
||||
The structured columns power the bubble rendering; the verbatim upstream
|
||||
record is exposed as ``raw_json`` so the frontend can render the all-fields
|
||||
drawer (msgSvrId/keyId, file/fileTh/fileHd, md5/md5Th/md5Hd, paymsgid,
|
||||
referMsg, imgPath, ...) without a second endpoint. Picked up automatically
|
||||
via ``from_attributes``.
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
@@ -132,6 +148,7 @@ class MessageOut(BaseModel):
|
||||
sender_name: str | None = None
|
||||
sender_head_url: str | None = None
|
||||
timestamp: int | None = None
|
||||
raw_json: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class GroupOut(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user