diff --git a/shierfeng-fastapi-frontend/scripts/verify-business-contract.mjs b/shierfeng-fastapi-frontend/scripts/verify-business-contract.mjs
index c053738..a6d42f0 100644
--- a/shierfeng-fastapi-frontend/scripts/verify-business-contract.mjs
+++ b/shierfeng-fastapi-frontend/scripts/verify-business-contract.mjs
@@ -834,6 +834,35 @@ function hasExpectedRequest(expectedRequest) {
)
}
+const source = (relativePath) => readFile(path.join(frontendRoot, relativePath), 'utf8')
+
+test('Web 测试模式统一附加请求头并通过路由重建清空页面状态', async () => {
+ const requestSource = await source('src/utils/request.js')
+ const appMainSource = await source('src/layout/components/AppMain.vue')
+ const navbarSource = await source('src/layout/components/Navbar.vue')
+
+ assert.match(requestSource, /X-Test-Batch-Id/)
+ assert.match(requestSource, /TEST_BATCH_UNAVAILABLE/)
+ assert.match(appMainSource, /scopeVersion/)
+ assert.match(navbarSource, /TestBatchModeSwitch/)
+ assert.match(navbarSource, /测试数据/)
+})
+
+test('Web 测试批次上下文仅持久化 ID,登出清除 ID 且管理员标记严格来自后端布尔值', async () => {
+ const contextSource = await source('src/utils/testBatchContext.js')
+ const storeSource = await source('src/store/modules/testBatch.js')
+ const userSource = await source('src/store/modules/user.js')
+
+ assert.match(contextSource, /sessionStorage/)
+ assert.doesNotMatch(contextSource, /batchName|status|admin|permission/i)
+ assert.match(storeSource, /getStoredTestBatchId/)
+ assert.match(storeSource, /setStoredTestBatchId/)
+ assert.match(storeSource, /clearStoredTestBatchId/)
+ assert.match(userSource, /admin:\s*false/)
+ assert.match(userSource, /this\.admin\s*=\s*user\.admin\s*===\s*true/)
+ assert.match(userSource, /clearStoredTestBatchId\(\)/)
+})
+
test('17 个页面的真实权限门禁逐项匹配独立硬编码契约', async () => {
assert.equal(expectedPagePermissions.length, 17)
assert.equal(expectedButtonPermissions.length, 44)
diff --git a/shierfeng-fastapi-frontend/src/api/system/testBatch.js b/shierfeng-fastapi-frontend/src/api/system/testBatch.js
new file mode 100644
index 0000000..5035aab
--- /dev/null
+++ b/shierfeng-fastapi-frontend/src/api/system/testBatch.js
@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+// 查询当前用户可用的测试数据批次。
+export function listAvailableTestBatches() {
+ return request({
+ url: '/system/test-batch/options',
+ method: 'get'
+ })
+}
diff --git a/shierfeng-fastapi-frontend/src/components/TestBatchModeSwitch/index.vue b/shierfeng-fastapi-frontend/src/components/TestBatchModeSwitch/index.vue
new file mode 100644
index 0000000..e6390fc
--- /dev/null
+++ b/shierfeng-fastapi-frontend/src/components/TestBatchModeSwitch/index.vue
@@ -0,0 +1,185 @@
+
+