feat: add project-scoped work assistant results

This commit is contained in:
2026-07-21 04:44:15 +08:00
parent 53b15e506c
commit 4536d607e3
75 changed files with 3281 additions and 507 deletions
+26
View File
@@ -29,3 +29,29 @@ test('问师傅支持显式新对话、版本回写和受控原文件或视频
assert.match(page, /msg\.result\.rewrittenQuery !== msg\.result\.queryText/);
assert.match(page, /已结合本次对话理解/);
});
test('工作助手按项目名称选择并为文字、媒体和工具请求携带项目上下文', async () => {
const [page, service, auth] = await Promise.all([
read('../src/pages/user/sop/index.vue'),
read('../src/services/knowledge.ts'),
read('../src/services/auth.ts')
]);
assert.match(page, />当前项目</);
assert.match(page, /选择当前项目/);
assert.match(page, /搜索项目名称/);
assert.match(page, /saveCurrentProject\(project\)/);
assert.match(page, /resetConversation\(false\)/);
assert.match(page, /currentProject\.value\?\.projectCode/);
assert.match(service, /projectCode/);
assert.match(auth, /aihr_mobile_current_project:\$\{tenantId/);
assert.match(auth, /reconcileCurrentProject/);
});
test('项目选择面板避开底栏且确认卡内容增长后重新滚到底部', async () => {
const page = await read('../src/pages/user/sop/index.vue');
assert.match(page, /inset:\s*0 0 var\(--window-bottom, 0px\)/);
assert.match(page, /let scrollSeq = 0/);
assert.match(page, /threadScrollTop\.value = 100000 \+ \(\+\+scrollSeq \* 200\)/);
});
+20
View File
@@ -25,6 +25,8 @@ after(async () => {
});
const { createPageRequestScope } = await vite.ssrLoadModule('/src/services/request-scope.ts');
const { getCurrentProject, reconcileCurrentProject, saveAuth, saveCurrentProject } =
await vite.ssrLoadModule('/src/services/auth.ts');
const loginAs = (phone, token) => {
storage.set('aihr_mobile_phone', phone);
@@ -89,3 +91,21 @@ test('五个账号敏感页在显示时捕获账号并在隐藏和卸载时失
assert.match(source, /requests\.isCurrent\(/);
}
});
test('当前项目按租户和登录账号隔离并在权限变化后重新校验', () => {
saveAuth({ access_token: 'token-a', client_id: 'mobile-client' }, '13800138000', '000000');
saveCurrentProject({ projectCode: 'P1', projectName: '星河湾一期' });
assert.equal(getCurrentProject()?.projectCode, 'P1');
saveAuth({ access_token: 'token-b', client_id: 'mobile-client' }, '13900139000', '000000');
assert.equal(getCurrentProject(), null);
assert.equal(reconcileCurrentProject([
{ projectCode: 'P2', projectName: '星河湾二期' }
])?.projectCode, 'P2');
assert.equal(reconcileCurrentProject([
{ projectCode: 'P3', projectName: '星河湾三期' },
{ projectCode: 'P4', projectName: '星河湾四期' }
]), null);
assert.equal(getCurrentProject(), null);
});
+46
View File
@@ -0,0 +1,46 @@
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import test from 'node:test';
const read = (path) => readFile(new URL(path, import.meta.url), 'utf8');
test('员工与主管成果页只允许推进待跟进或处理中记录', async () => {
const [employeePage, supervisorPage] = await Promise.all([
read('../src/pages/user/work-results/index.vue'),
read('../src/pages/supervisor/work-results/index.vue')
]);
const actionableStatuses = /\['PENDING',\s*'IN_PROGRESS'\]\.includes\(item\.businessStatus\)/;
assert.match(employeePage, actionableStatuses);
assert.match(supervisorPage, /\['PENDING','IN_PROGRESS'\]\.includes\(item\.businessStatus\)/);
assert.doesNotMatch(employeePage, /!\['COMPLETED',\s*'VOID'\]\.includes\(item\.businessStatus\)/);
assert.doesNotMatch(supervisorPage, /!\['COMPLETED','VOID'\]\.includes\(item\.businessStatus\)/);
});
test('员工成果页与主管成果页复用真实项目成果接口', async () => {
const [employeePage, supervisorPage, service] = await Promise.all([
read('../src/pages/user/work-results/index.vue'),
read('../src/pages/supervisor/work-results/index.vue'),
read('../src/services/work-results.ts')
]);
assert.match(employeePage, /generateMyWorkResult/);
assert.match(supervisorPage, /getProjectWorkResult/);
assert.match(service, /\/api\/aihr\/work-results\/mine\/generate/);
assert.match(service, /\/api\/aihr\/work-results\/project/);
});
test('员工与主管成果页都能追溯非文字原始来源', async () => {
const [employeePage, supervisorPage, preview] = await Promise.all([
read('../src/pages/user/work-results/index.vue'),
read('../src/pages/supervisor/work-results/index.vue'),
read('../src/services/source-preview.ts')
]);
assert.match(employeePage, /openProtectedSource/);
assert.match(supervisorPage, /原始来源/);
assert.match(supervisorPage, /openProtectedSource/);
assert.match(preview, /createInnerAudioContext/);
assert.match(preview, /previewMedia/);
assert.doesNotMatch(employeePage, /openDocument/);
});