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>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
|
||||
|
||||
// `/` redirects to `/customers`. Chat timeline params are path segments so the
|
||||
// URL is shareable + survives refresh:
|
||||
// /chat/:channel/:ownerId/:talkerId
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: { name: 'customers' },
|
||||
},
|
||||
{
|
||||
path: '/customers',
|
||||
name: 'customers',
|
||||
component: () => import('@/views/CustomerList.vue'),
|
||||
meta: { title: '客户列表' },
|
||||
},
|
||||
{
|
||||
path: '/chat/:channel/:ownerId/:talkerId',
|
||||
name: 'chat',
|
||||
component: () => import('@/views/ChatTimeline.vue'),
|
||||
props: true,
|
||||
meta: { title: '聊天记录' },
|
||||
},
|
||||
{
|
||||
// Anything else → back to the list.
|
||||
path: '/:pathMatch(.*)*',
|
||||
redirect: { name: 'customers' },
|
||||
},
|
||||
]
|
||||
|
||||
export const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
scrollBehavior() {
|
||||
return { top: 0 }
|
||||
},
|
||||
})
|
||||
|
||||
router.afterEach((to) => {
|
||||
const title = (to.meta.title as string | undefined) ?? ''
|
||||
document.title = title ? `${title} · 云客数据镜像` : '云客数据镜像'
|
||||
})
|
||||
Reference in New Issue
Block a user