feat: 优化差旅报销预审流程与个人工作台 UI 体系
- 完善 user_agent_application 申请差旅报销预审槽位与消息组装 - 增强预算助理报告与风险建议卡片交互 - 重构登录页视觉样式与移动端响应式适配 - 优化个人工作台、文档中心、政策中心、员工管理等页面布局 - 拆分 travelRequestDetailPreReviewModel 为 advice/submit 模型 - 补充报销草稿、风险复核、Item Sync 与模板执行器测试覆盖
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { readFileSync, statSync } from 'node:fs'
|
||||
import test from 'node:test'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
@@ -13,6 +13,32 @@ const workbench = readFileSync(
|
||||
fileURLToPath(new URL('../src/components/business/PersonalWorkbench.vue', import.meta.url)),
|
||||
'utf8'
|
||||
)
|
||||
const workbenchStyles = readFileSync(
|
||||
fileURLToPath(new URL('../src/assets/styles/components/personal-workbench.css', import.meta.url)),
|
||||
'utf8'
|
||||
)
|
||||
const workbenchGlassStyles = readFileSync(
|
||||
fileURLToPath(new URL('../src/assets/styles/components/personal-workbench-glass.css', import.meta.url)),
|
||||
'utf8'
|
||||
)
|
||||
const workbenchCardStyles = `${workbenchStyles}\n${workbenchGlassStyles}`
|
||||
const workbenchResponsiveStyles = readFileSync(
|
||||
fileURLToPath(new URL('../src/assets/styles/components/personal-workbench-responsive.css', import.meta.url)),
|
||||
'utf8'
|
||||
)
|
||||
const workbenchInsightStyles = readFileSync(
|
||||
fileURLToPath(new URL('../src/assets/styles/components/personal-workbench-insights.css', import.meta.url)),
|
||||
'utf8'
|
||||
)
|
||||
const heroBackgroundAsset = fileURLToPath(
|
||||
new URL('../src/assets/personal-workbench-hero-bg-theme-base.webp', import.meta.url)
|
||||
)
|
||||
const capabilityGlassAsset = fileURLToPath(
|
||||
new URL('../src/assets/personal-workbench-card-glass-capability.webp', import.meta.url)
|
||||
)
|
||||
const panelGlassAsset = fileURLToPath(
|
||||
new URL('../src/assets/personal-workbench-card-glass-panel.webp', import.meta.url)
|
||||
)
|
||||
|
||||
test('workbench assistant greets the current employee without the old helper tag', () => {
|
||||
assert.doesNotMatch(workbench, /assistant-tag/)
|
||||
@@ -56,6 +82,56 @@ test('workbench capability cards keep user-entered context only', () => {
|
||||
assert.equal(payload.files, files)
|
||||
})
|
||||
|
||||
test('workbench hero uses theme-tintable background image', () => {
|
||||
assert.match(workbench, /personal-workbench-hero-bg-theme-base\.webp/)
|
||||
assert.doesNotMatch(workbench, /personal-workbench-hero-bg-theme-base\.png/)
|
||||
assert.match(workbench, /--assistant-bg-image.*workbenchHeroBackground/)
|
||||
assert.match(workbenchStyles, /--assistant-theme-tint:[\s\S]*--theme-primary-rgb/)
|
||||
assert.match(workbenchStyles, /var\(--assistant-bg-image\) var\(--assistant-bg-position\) \/ var\(--assistant-bg-size\) no-repeat/)
|
||||
assert.match(workbenchStyles, /background-blend-mode:\s*normal,\s*color,\s*luminosity;/)
|
||||
assert.match(workbenchStyles, /\.assistant-hero::after\s*\{[\s\S]*content:\s*none;/)
|
||||
assert.match(workbenchResponsiveStyles, /--assistant-bg-position:\s*68% center;/)
|
||||
assert.doesNotMatch(workbenchResponsiveStyles, /homepage_backgraound/)
|
||||
assert.ok(statSync(heroBackgroundAsset).size < 120 * 1024)
|
||||
})
|
||||
|
||||
test('workbench cards use layered glass material instead of texture-led cards', () => {
|
||||
assert.match(workbench, /personal-workbench-glass\.css/)
|
||||
assert.match(workbenchGlassStyles, /--workbench-capability-bg-image:\s*url\("\.\.\/\.\.\/personal-workbench-card-glass-capability\.webp"\)/)
|
||||
assert.match(workbenchGlassStyles, /--workbench-panel-bg-image:\s*url\("\.\.\/\.\.\/personal-workbench-card-glass-panel\.webp"\)/)
|
||||
assert.match(workbenchGlassStyles, /--workbench-glass-base:/)
|
||||
assert.match(workbenchGlassStyles, /--workbench-glass-highlight:/)
|
||||
assert.match(workbenchGlassStyles, /--workbench-glass-noise-opacity:\s*0\.012;/)
|
||||
assert.match(workbenchGlassStyles, /--workbench-glass-blur:\s*blur\(18px\) saturate\(1\.28\);/)
|
||||
assert.match(workbenchGlassStyles, /\.capability-card\s*\{[\s\S]*background-color:\s*rgba\(255,\s*255,\s*255,\s*0\.64\);[\s\S]*backdrop-filter:\s*var\(--workbench-glass-blur\)/)
|
||||
assert.match(workbenchGlassStyles, /\.workbench-card\s*\{[\s\S]*background-color:\s*rgba\(255,\s*255,\s*255,\s*0\.66\);[\s\S]*backdrop-filter:\s*var\(--workbench-glass-blur\)/)
|
||||
assert.match(workbenchGlassStyles, /\.capability-card::before,[\s\S]*\.capability-card::after/)
|
||||
assert.match(workbenchGlassStyles, /\.capability-card::before\s*\{[\s\S]*var\(--workbench-capability-bg-image\) 0 0 \/ var\(--workbench-capability-tile-size\) repeat;[\s\S]*opacity:\s*var\(--workbench-glass-noise-opacity\);/)
|
||||
assert.match(workbenchGlassStyles, /\.workbench-card::before\s*\{[\s\S]*var\(--workbench-panel-bg-image\) 0 0 \/ var\(--workbench-panel-tile-size\) repeat;[\s\S]*opacity:\s*calc\(var\(--workbench-glass-noise-opacity\) \* 0\.8\);/)
|
||||
assert.match(workbenchGlassStyles, /\.capability-card::after\s*\{[\s\S]*var\(--workbench-glass-highlight\)/)
|
||||
assert.match(workbenchGlassStyles, /\.workbench-card::after\s*\{[\s\S]*var\(--workbench-glass-highlight\)/)
|
||||
assert.doesNotMatch(workbenchGlassStyles, /\.capability-card::after\s*\{[^}]*radial-gradient/)
|
||||
assert.doesNotMatch(workbenchGlassStyles, /\.workbench-card::after\s*\{[^}]*radial-gradient/)
|
||||
assert.match(workbenchGlassStyles, /\.workbench-card > \*\s*\{[\s\S]*z-index:\s*1;/)
|
||||
assert.match(workbenchGlassStyles, /--workbench-capability-tile-size:\s*384px 384px;/)
|
||||
assert.match(workbenchGlassStyles, /--workbench-panel-tile-size:\s*512px 512px;/)
|
||||
assert.doesNotMatch(workbenchCardStyles, /var\(--workbench-capability-bg-image\)[^;]*cover no-repeat/)
|
||||
assert.doesNotMatch(workbenchCardStyles, /var\(--workbench-panel-bg-image\)[^;]*cover no-repeat/)
|
||||
assert.match(workbenchGlassStyles, /--workbench-glass-theme-tint:[\s\S]*--theme-primary-rgb/)
|
||||
assert.doesNotMatch(workbenchCardStyles, /background-blend-mode:\s*normal,\s*color,\s*normal;/)
|
||||
assert.match(workbenchResponsiveStyles, /--workbench-glass-noise-opacity:\s*0\.008;/)
|
||||
assert.match(workbenchResponsiveStyles, /--workbench-glass-blur:\s*blur\(14px\) saturate\(1\.2\);/)
|
||||
assert.match(workbenchGlassStyles, /\.todo-row,[\s\S]*\.progress-row\s*\{[\s\S]*background:\s*transparent;[\s\S]*box-shadow:\s*inset 0 1px 0 rgba\(var\(--theme-primary-rgb/)
|
||||
assert.doesNotMatch(workbenchGlassStyles, /\.todo-row\s*\{[\s\S]*border-top:\s*1px solid var\(--workbench-line-soft\)/)
|
||||
assert.doesNotMatch(workbenchGlassStyles, /\.progress-row\s*\{[\s\S]*border-top:\s*1px solid var\(--workbench-line-soft\)/)
|
||||
assert.match(workbenchInsightStyles, /\.insight-metric-row,[\s\S]*\.insight-profile-card\s*\{[\s\S]*backdrop-filter:\s*blur\(10px\) saturate\(1\.16\)/)
|
||||
assert.doesNotMatch(workbenchInsightStyles, /background:\s*#ffffff;/)
|
||||
assert.ok(statSync(capabilityGlassAsset).size > 1024)
|
||||
assert.ok(statSync(panelGlassAsset).size > 1024)
|
||||
assert.ok(statSync(capabilityGlassAsset).size < 24 * 1024)
|
||||
assert.ok(statSync(panelGlassAsset).size < 24 * 1024)
|
||||
})
|
||||
|
||||
test('workbench submit shows intent recognition feedback before assistant opens', () => {
|
||||
assert.match(workbench, /class="assistant-intent-status"/)
|
||||
assert.match(workbench, /aria-live="polite"/)
|
||||
|
||||
Reference in New Issue
Block a user