105 lines
4.6 KiB
JavaScript
105 lines
4.6 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { readFileSync } from 'node:fs'
|
|
import test from 'node:test'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
import { normalizeDigitalEmployeeDashboardPayload } from '../src/services/analytics.js'
|
|
|
|
const topBar = readFileSync(
|
|
fileURLToPath(new URL('../src/components/layout/TopBar.vue', import.meta.url)),
|
|
'utf8'
|
|
)
|
|
const overviewView = readFileSync(
|
|
fileURLToPath(new URL('../src/views/OverviewView.vue', import.meta.url)),
|
|
'utf8'
|
|
)
|
|
const overviewViewModel = readFileSync(
|
|
fileURLToPath(new URL('../src/composables/useOverviewView.js', import.meta.url)),
|
|
'utf8'
|
|
)
|
|
const analyticsService = readFileSync(
|
|
fileURLToPath(new URL('../src/services/analytics.js', import.meta.url)),
|
|
'utf8'
|
|
)
|
|
const dashboardComponent = readFileSync(
|
|
fileURLToPath(new URL('../src/components/dashboard/DigitalEmployeeDashboard.vue', import.meta.url)),
|
|
'utf8'
|
|
)
|
|
const dailyChartComponent = readFileSync(
|
|
fileURLToPath(new URL('../src/components/charts/DigitalEmployeeDailyWorkChart.vue', import.meta.url)),
|
|
'utf8'
|
|
)
|
|
const dashboardModel = readFileSync(
|
|
fileURLToPath(new URL('../src/views/scripts/overviewDigitalEmployeeDashboardModel.js', import.meta.url)),
|
|
'utf8'
|
|
)
|
|
|
|
test('digital employee dashboard normalizes backend payload fields', () => {
|
|
const dashboard = normalizeDigitalEmployeeDashboardPayload({
|
|
window_days: 7,
|
|
generated_at: '2026-06-01T08:00:00Z',
|
|
has_real_data: true,
|
|
totals: {
|
|
totalRuns: 3,
|
|
successRuns: 2,
|
|
failedRuns: 1,
|
|
businessOutputs: 8
|
|
},
|
|
daily_work: [{ date: '06-01', total: 3, businessOutputs: 8 }],
|
|
task_distribution: [{ name: '知识制度整理', count: 2 }],
|
|
category_distribution: [{ name: '整理', count: 2 }],
|
|
recent_runs: [{ runId: 'run-001', taskLabel: '知识制度整理' }]
|
|
})
|
|
|
|
assert.equal(dashboard.windowDays, 7)
|
|
assert.equal(dashboard.generatedAt, '2026-06-01T08:00:00Z')
|
|
assert.equal(dashboard.hasRealData, true)
|
|
assert.equal(dashboard.totals.totalRuns, 3)
|
|
assert.equal(dashboard.dailyWork[0].businessOutputs, 8)
|
|
assert.equal(dashboard.taskDistribution[0].name, '知识制度整理')
|
|
assert.equal(dashboard.categoryDistribution[0].name, '整理')
|
|
assert.equal(dashboard.recentRuns[0].runId, 'run-001')
|
|
})
|
|
|
|
test('digital employee dashboard is wired into overview dashboard switch', () => {
|
|
assert.match(topBar, /label: '数字员工看板', value: 'digitalEmployee'/)
|
|
assert.match(overviewView, /<DigitalEmployeeDashboard/)
|
|
assert.match(overviewView, /activeDashboard === 'digitalEmployee'/)
|
|
assert.match(overviewView, /digitalEmployeeKpiMetrics/)
|
|
assert.match(overviewViewModel, /fetchDigitalEmployeeDashboard/)
|
|
assert.match(overviewViewModel, /const digitalEmployeeKpiMetrics = computed/)
|
|
assert.match(dashboardModel, /label: '工作总数'/)
|
|
assert.match(dashboardModel, /label: '成功数量'/)
|
|
assert.match(dashboardModel, /label: '失败数量'/)
|
|
assert.match(dashboardModel, /categoryDistribution/)
|
|
assert.match(analyticsService, /\/analytics\/digital-employee-dashboard/)
|
|
})
|
|
|
|
test('digital employee dashboard renders enterprise dashboard panels with chart components', () => {
|
|
assert.match(dashboardComponent, /每日工作趋势/)
|
|
assert.match(dashboardComponent, /每日工作摘要/)
|
|
assert.match(dashboardComponent, /技能类型分布/)
|
|
assert.match(dashboardComponent, /工作模块排行/)
|
|
assert.match(dashboardComponent, /最近工作记录/)
|
|
assert.match(dashboardComponent, /DigitalEmployeeDailyWorkChart/)
|
|
assert.match(dashboardComponent, /DonutChart/)
|
|
assert.match(dashboardComponent, /BarChart/)
|
|
assert.match(dailyChartComponent, /echarts\/charts/)
|
|
assert.match(dailyChartComponent, /name: '工作次数'/)
|
|
assert.match(dailyChartComponent, /name: '业务产出'/)
|
|
assert.doesNotMatch(dashboardComponent, /hermes/i)
|
|
})
|
|
|
|
test('digital employee dashboard uses filled card layout for charts and rows', () => {
|
|
assert.match(dashboardComponent, /digital-chart-fill digital-trend-fill/)
|
|
assert.match(dashboardComponent, /digital-chart-fill digital-donut-fill/)
|
|
assert.match(dashboardComponent, /digital-chart-fill digital-bar-fill/)
|
|
assert.match(dashboardComponent, /digital-output-grid digital-card-fill/)
|
|
assert.match(dashboardComponent, /grid-auto-rows: minmax\(300px, auto\)/)
|
|
assert.match(dashboardComponent, /\.digital-work-trend-panel \{\s*grid-column: span 7/s)
|
|
assert.match(dashboardComponent, /\.digital-work-day-panel \{\s*grid-column: span 5/s)
|
|
assert.match(dashboardComponent, /\.digital-recent-panel \{\s*grid-column: span 12/s)
|
|
assert.match(dailyChartComponent, /height: 100%/)
|
|
assert.match(dailyChartComponent, /min-height: 280px/)
|
|
})
|