Commit Graph

7 Commits

Author SHA1 Message Date
浅念 d08255696c fix(ui): 进场动画改纯opacity(transform残留值把fixed抽屉裁成半截)
transform:translateY(0)结束后仍是非none transform→创建containing block
→position:fixed的抽屉相对列表卡片定位被裁剪;opacity动画无此副作用

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-22 16:21:12 +08:00
浅念 01842a0abf feat(ui): 可点击元素统一玉绿示意(链接悬停下划线+行悬停首列染玉绿+会话侧栏玉绿激活;修StaffList灰色覆盖把link按钮染灰的bug)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-22 15:54:05 +08:00
浅念 12097df9f1 feat(ui): 墨玉控制台主题(深墨侧栏+玉绿主色+暖纸内容区,组件零改动)
- 侧栏:深墨渐变底+品牌玉点+玉绿激活竖条(微光)+右缘渐隐线
- 主色:Element 全系覆写为玉绿(#0d9f6e,微信血统精炼)
- 内容区:暖纸底+极淡点阵纹理;页面进场微上浮动画
- 卡片:10px圆角+双层阴影+jade hover;表格:精致表头+玉绿行hover+tabular数字
- 聊天流:纸面质感底;细滚动条;输入/按钮圆角统一

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-22 15:38:03 +08:00
浅念 ff73c056e9 feat(chat): 聊天排版升级微信标准(左右分侧+头像+绿气泡)+is_send数据修复
- is_send 根因:云客消息方向在 mine 字段(isSend 全 null),归一化加 fallback
  +存量回填 60.7 万行(51万收/16万发)——分侧数据首次完整
- MessageBubble:头像(对方=raw headUrl 在左/自己=默认在右)、自己侧隐藏昵称、
  接收白底描边/发送微信绿 #95ec69、气泡列 max-width 78%
- 实测混合对话:13发(绿+头像右)/7收(白+头像左)全部正确

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-20 15:26:04 +08:00
浅念 8fde1d8597 fix: render chat media by URL (images/video/voice) instead of unknown-type placeholder
MessageBubble.vue was keys off the (incomplete) type code, so many messages
with real OSS media URLs (https://wx.oss.yunkecn.com/.../*.webp|*.mp4) showed
as '[未知消息]'. Rendering is now URL-driven: pick the best http URL from
file_url > file_hd_url > file_th_url, then render by extension
(image/video/audio/file). Type code is only used as a last-resort label.

- MessageBubble.vue: URL-driven cascade (URL by ext → duration →
  transcription → text → structured-type placeholder → localized tag).
  Image/video/audio/file children @click.stop so the all-fields drawer
  still opens on bubble click but not on media interactions.
- format.ts: wechatTypeLabel(type_raw) maps known codes (3→图片, 34→语音,
  43→图片/表情, 49→文件/名片, 42→名片, 9→表情, 20→红包/转账).
- ChatTimeline.vue drawer type tag uses wechatTypeLabel for WeChat msgs.
- style.css: compact .yk-msg__audio player for voice-with-URL messages.

Verified against smoke.db: 25 type-3 images + 3 type-43 videos that
previously showed '[未知消息]' now render as images/video. Build clean.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-05 10:23:01 +08:00
浅念 6ac47a1203 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>
2026-08-01 17:47:50 +08:00
浅念 6c4cd92ae6 feat: vue3 frontend scaffold + org tree + customer list + chat timeline
M5b viewing frontend for the yunke data-mirror, under yunkes/.

- Scaffold: Vite + Vue 3 + TS, with element-plus, @element-plus/icons-vue,
  pinia, vue-router@4, axios. Dev server on :5173 with /api and /api/media
  proxied to the FastAPI backend on :8000.
- API client (src/api/): axios instance (baseURL '/api') whose response
  interceptor unwraps the axios envelope; typed wrappers (getCustomers,
  getMessages, getDepartments, getStaff) returning Page<T> / arrays; types
  mirroring the backend *Out schemas (Message typed as a permissive superset
  so file_th_url/duration/transcription_text degrade gracefully today and
  light up once MessageOut exposes them).
- Layout: el-header top bar (title + channel switch) + el-aside department
  tree (built from the flat parent_id list via useOrgStore, with search
  filter) + el-main router-view.
- CustomerList (/customers): el-table with channel filter, department filter
  driven by the tree selection (route query), pagination, and row-click into
  the chat timeline (channel + owner_account_id + talker_id).
- ChatTimeline (/chat/:channel/:ownerId/:talkerId): asc-ordered message
  bubbles keyed by is_send (direction) and type (text/image/video/voice/file/
  divider/system/unknown); lands on the most-recent page and prepends older
  pages via load-more with scroll anchoring.
- Home '/' redirects to '/customers'.

npm run build (vue-tsc -b + vite build) is clean.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-01 16:27:22 +08:00