diff --git a/web/src/views/goauto/ai-matching-settings/index.vue b/web/src/views/goauto/ai-matching-settings/index.vue index acd9278..109c621 100644 --- a/web/src/views/goauto/ai-matching-settings/index.vue +++ b/web/src/views/goauto/ai-matching-settings/index.vue @@ -10,17 +10,13 @@ {{ form.enabled ? '已启用' : '未启用' }} - + + + {{ form.autoConfirmMinConfidence.toFixed(2) }} + + 达到阈值才自动预填建议;范围 0~1。自动预填不等于自动确认或自动采购。 @@ -74,6 +71,7 @@ export default { } catch (_) { return callback(new Error('请输入有效的 HTTP 或 HTTPS 服务地址')) } return callback() } + const validConfidence = (_, value, callback) => { if (Number.isFinite(value) && value >= 0 && value <= 1) callback(); else callback(new Error('置信度阈值必须在 0 与 1 之间')) } return { loading: false, saving: false, @@ -83,7 +81,8 @@ export default { rules: { baseUrl: [{ validator: validHttps, trigger: 'blur' }], model: [{ validator: (_, value, callback) => { if (!this.form.enabled || value) callback(); else callback(new Error('请输入模型名称')) }, trigger: 'blur' }], - apiKey: [{ validator: (_, value, callback) => { if (!this.form.enabled || value) callback(); else callback(new Error('请输入 API Key')) }, trigger: 'blur' }] + apiKey: [{ validator: (_, value, callback) => { if (!this.form.enabled || value) callback(); else callback(new Error('请输入 API Key')) }, trigger: 'blur' }], + autoConfirmMinConfidence: [{ validator: validConfidence, trigger: 'change' }] } } }, @@ -93,7 +92,7 @@ export default { }, created() { this.load() }, methods: { - emptyForm() { return { enabled: false, provider: 'openai_compatible', baseUrl: '', model: '', timeoutSeconds: 15, apiKey: '' } }, + emptyForm() { return { enabled: false, provider: 'openai_compatible', baseUrl: '', model: '', timeoutSeconds: 15, autoConfirmMinConfidence: 0.9, apiKey: '' } }, async load() { this.loading = true try { @@ -106,7 +105,7 @@ export default { if (!valid) return this.saving = true try { - const response = await saveAiMatchingSettings({ enabled: this.form.enabled, baseUrl: this.form.baseUrl, model: this.form.model, timeoutSeconds: this.form.timeoutSeconds, apiKey: this.form.apiKey }) + const response = await saveAiMatchingSettings({ enabled: this.form.enabled, baseUrl: this.form.baseUrl, model: this.form.model, timeoutSeconds: this.form.timeoutSeconds, autoConfirmMinConfidence: this.form.autoConfirmMinConfidence, apiKey: this.form.apiKey }) this.form = { ...this.emptyForm(), ...response.data } ElMessage.success('AI 规格匹配设置已保存') } finally { this.saving = false } diff --git a/web/tests/e2e/ai-matching-confidence.spec.ts b/web/tests/e2e/ai-matching-confidence.spec.ts new file mode 100644 index 0000000..c9b3186 --- /dev/null +++ b/web/tests/e2e/ai-matching-confidence.spec.ts @@ -0,0 +1,42 @@ +import { expect, test } from '@playwright/test' + +const routeFor = (path: string) => [{ path: '/goauto-management', component: 'Layout', menuName: 'GoAutoManagement', title: '采采管理', visible: '0', children: [{ path, component: '/goauto/ai-matching-settings/index', menuName: 'GoAutoAiMatchingSettings', title: 'AI 规格匹配', visible: '0' }] }] + +test('管理员可保存 AI 建议置信度阈值', async({ page, context }) => { + await context.addCookies([{ name: 'Admin-Token', value: 'prototype-test-token', domain: 'localhost', path: '/' }]) + let saved: { autoConfirmMinConfidence?: number } = {} + await page.route('**/api/**', async route => { + const url = new URL(route.request().url()) + if (url.pathname.startsWith('/src/api/')) return route.continue() + if (url.pathname.endsWith('/api/v1/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['admin'], name: '管理员', avatar: '', introduction: '', permissions: [] }}}) + if (url.pathname.endsWith('/api/v1/menurole')) return route.fulfill({ json: { code: 200, data: routeFor('/ai-matching-settings') }}) + if (url.pathname.endsWith('/api/admin/v1/ai-matching-settings') && route.request().method() === 'PUT') { saved = route.request().postDataJSON(); return route.fulfill({ json: { code: 200, data: { enabled: true, provider: 'openai_compatible', baseUrl: 'http://provider/v1', model: 'test', timeoutSeconds: 180, autoConfirmMinConfidence: saved.autoConfirmMinConfidence, apiKey: 'secret' }}}) } + if (url.pathname.endsWith('/api/admin/v1/ai-matching-settings')) return route.fulfill({ json: { code: 200, data: { enabled: true, provider: 'openai_compatible', baseUrl: 'http://provider/v1', model: 'test', timeoutSeconds: 180, autoConfirmMinConfidence: 0.85, apiKey: 'secret' }}}) + return route.fulfill({ json: { code: 200, data: [] }}) + }) + await page.goto('/#/ai-matching-settings') + const threshold = page.getByLabel('AI 建议置信度阈值') + await expect(threshold).toHaveValue('0.85') + const thresholdField = page.locator('.el-form-item').filter({ hasText: 'AI 建议置信度阈值' }) + for (let index = 0; index < 10; index += 1) await thresholdField.getByRole('button', { name: '减少数值' }).click() + await expect(threshold).toHaveValue('0.75') + await page.getByRole('button', { name: '保存设置', exact: true }).click() + await expect.poll(() => saved.autoConfirmMinConfidence).toBe(0.75) + await expect(page.getByText('达到阈值才自动预填建议;范围 0~1。自动预填不等于自动确认或自动采购。', { exact: true })).toBeVisible() +}) + +test('非管理员只读查看 AI 建议置信度阈值', async({ page, context }) => { + await context.addCookies([{ name: 'Admin-Token', value: 'prototype-test-token', domain: 'localhost', path: '/' }]) + await page.route('**/api/**', async route => { + const url = new URL(route.request().url()) + if (url.pathname.startsWith('/src/api/')) return route.continue() + if (url.pathname.endsWith('/api/v1/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['purchaser'], name: '采购员', avatar: '', introduction: '', permissions: [] }}}) + if (url.pathname.endsWith('/api/v1/menurole')) return route.fulfill({ json: { code: 200, data: routeFor('/ai-matching-settings') }}) + if (url.pathname.endsWith('/api/admin/v1/ai-matching-settings')) return route.fulfill({ json: { code: 200, data: { enabled: true, autoConfirmMinConfidence: 0.85 }}}) + return route.fulfill({ json: { code: 200, data: [] }}) + }) + await page.goto('/#/ai-matching-settings') + await expect(page.getByText('0.85', { exact: true })).toBeVisible() + await expect(page.getByLabel('AI 建议置信度阈值')).toHaveCount(0) + await expect(page.getByRole('button', { name: '保存设置', exact: true })).toHaveCount(0) +})
达到阈值才自动预填建议;范围 0~1。自动预填不等于自动确认或自动采购。