diff --git a/yunkes/src/components/management/EmployeeCompareDrawer.vue b/yunkes/src/components/management/EmployeeCompareDrawer.vue new file mode 100644 index 0000000..6dbe89e --- /dev/null +++ b/yunkes/src/components/management/EmployeeCompareDrawer.vue @@ -0,0 +1,169 @@ + + + + + diff --git a/yunkes/src/layouts/MainLayout.vue b/yunkes/src/layouts/MainLayout.vue index f6dd5f4..6f1c496 100644 --- a/yunkes/src/layouts/MainLayout.vue +++ b/yunkes/src/layouts/MainLayout.vue @@ -107,6 +107,9 @@ function logout(): void { 管理驾驶舱 + + 员工分析 + diff --git a/yunkes/src/router/index.ts b/yunkes/src/router/index.ts index 0befb89..27888d6 100644 --- a/yunkes/src/router/index.ts +++ b/yunkes/src/router/index.ts @@ -99,6 +99,14 @@ const routes: RouteRecordRaw[] = [ component: () => import('@/views/management/ManagementDashboardView.vue'), meta: { title: '管理驾驶舱' }, }, + { + // 员工分析(批次D):四视图总览;详情路由 /management/employees/{user_id} + // 由批次D后续任务补挂(D2) + path: '/management/employees', + name: 'management-employees', + component: () => import('@/views/management/EmployeeAnalyticsView.vue'), + meta: { title: '员工分析' }, + }, { path: '/chat/:channel/:ownerId/:talkerId?', name: 'chat', diff --git a/yunkes/src/utils/csvExport.ts b/yunkes/src/utils/csvExport.ts index 8bc92f0..434ce4f 100644 --- a/yunkes/src/utils/csvExport.ts +++ b/yunkes/src/utils/csvExport.ts @@ -10,6 +10,9 @@ * ], * filename: '微信客户列表', * }) + * + * Optional `preamble: string[]` writes comment lines (口径/窗口注释等) before + * the header — each line occupies the first column of its own row. */ export interface CsvColumn { @@ -30,6 +33,12 @@ export interface ExportOptions { pageSize?: number /** Max rows to export (safety cap, default 10000) */ maxRows?: number + /** + * Optional comment lines written before the header row (batch D: management + * employee CSV carries caliber/window notes so the export is self-describing + * outside the app). Each line becomes a single-cell row in the first column. + */ + preamble?: string[] } function escapeCsv(value: string | number | null | undefined): string { @@ -43,7 +52,7 @@ function escapeCsv(value: string | number | null | undefined): string { } export async function exportListToCsv(options: ExportOptions): Promise<{ rows: number; filename: string }> { - const { fetchPage, columns, filename, pageSize = 100, maxRows = 10000 } = options + const { fetchPage, columns, filename, pageSize = 100, maxRows = 10000, preamble } = options // Fetch all pages const allRows: T[] = [] @@ -68,7 +77,7 @@ export async function exportListToCsv(options: ExportOptions): Promise<{ r return escapeCsv(val as string | number | null | undefined) }).join(',') ) - const csv = '' + header + '\n' + lines.join('\n') // BOM for Excel Chinese support + const csv = '' + [...(preamble ?? []).map((p) => escapeCsv(p)), header, ...lines].join('\n') // BOM for Excel Chinese support // Trigger download const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' }) diff --git a/yunkes/src/views/management/EmployeeAnalyticsView.vue b/yunkes/src/views/management/EmployeeAnalyticsView.vue new file mode 100644 index 0000000..3bdad1f --- /dev/null +++ b/yunkes/src/views/management/EmployeeAnalyticsView.vue @@ -0,0 +1,718 @@ + + + + +