From 6e227aa3775d2cccdeb8d10d8c90ef5a1851e1b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=87=AA=E8=BE=BE?= <980324341@qq.com> Date: Mon, 31 Aug 2026 19:18:21 +0800 Subject: [PATCH] =?UTF-8?q?task-3:=20callJava()=20=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E8=A7=A3=E5=8C=85=EF=BC=88JavaApiResponse/Le?= =?UTF-8?q?gacy=20=E5=85=BC=E5=AE=B9=E3=80=81success=3Dfalse=20=E6=8A=9B?= =?UTF-8?q?=E9=94=99=EF=BC=89=EF=BC=9B=E5=BC=80=E5=90=AF=20allowImportingT?= =?UTF-8?q?sExtensions=20=E6=94=AF=E6=8C=81=20node=20--test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend-vue/src/shared/api/call.ts | 35 +++++++++++++ frontend-vue/tests/call.test.ts | 77 +++++++++++++++++++++++++++++ frontend-vue/tsconfig.json | 1 + 3 files changed, 113 insertions(+) create mode 100644 frontend-vue/src/shared/api/call.ts create mode 100644 frontend-vue/tests/call.test.ts diff --git a/frontend-vue/src/shared/api/call.ts b/frontend-vue/src/shared/api/call.ts new file mode 100644 index 00000000..a4147e42 --- /dev/null +++ b/frontend-vue/src/shared/api/call.ts @@ -0,0 +1,35 @@ +import { http, type RequestOptions } from './http.ts' + +export interface JavaApiResponse { + success: boolean + message: string + data: T | null +} + +export interface LegacyApiSuccess { + success: true + msg?: string + data?: T +} + +export async function callJava( + config: RequestOptions, +): Promise { + const body = await http.request(config) + const data = (body as { data?: unknown }).data ?? body + + if ( + data && + typeof data === 'object' && + 'success' in data && + typeof (data as { success: unknown }).success === 'boolean' + ) { + const wrapped = data as { success: boolean; message?: string; msg?: string; error?: string; data?: T } + if (!wrapped.success) { + throw new Error(wrapped.message || wrapped.msg || wrapped.error || '请求失败') + } + return wrapped.data as T + } + + return data as T +} diff --git a/frontend-vue/tests/call.test.ts b/frontend-vue/tests/call.test.ts new file mode 100644 index 00000000..aa0e69c7 --- /dev/null +++ b/frontend-vue/tests/call.test.ts @@ -0,0 +1,77 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { http } from '../src/shared/api/http.ts' +import { callJava } from '../src/shared/api/call.ts' + +function mockResponse(t: Parameters[1] extends (t: infer T) => unknown ? T : never, body: unknown) { + t.mock.method(http, 'request', async () => ({ data: body }) as never) +} + +test('test_call_java_success_unwraps', async (t) => { + mockResponse(t, { success: true, message: 'ok', data: { taskId: 1, status: 'RUNNING' } }) + const result = await callJava<{ taskId: number; status: string }>({ + url: '/newApi/api/dedupe/run', + method: 'POST', + }) + assert.deepEqual(result, { taskId: 1, status: 'RUNNING' }) +}) + +test('test_call_java_legacy_msg_unwraps', async (t) => { + mockResponse(t, { success: true, msg: 'ok', data: [1, 2, 3] }) + const result = await callJava({ url: '/newApi/api/x', method: 'GET' }) + assert.deepEqual(result, [1, 2, 3]) +}) + +test('test_call_java_success_false_throws', async (t) => { + mockResponse(t, { success: false, message: '任务不存在' }) + await assert.rejects( + callJava({ url: '/newApi/api/x', method: 'GET' }), + /任务不存在/, + ) +}) + +test('test_call_java_message_precedence', async (t) => { + mockResponse(t, { success: false, message: 'm1', msg: 'm2', error: 'm3' }) + await assert.rejects(callJava({ url: '/newApi/api/x', method: 'GET' }), /m1/, 'message 应优先于 msg/error') + + mockResponse(t, { success: false, msg: 'm2', error: 'm3' }) + await assert.rejects(callJava({ url: '/newApi/api/x', method: 'GET' }), /m2/, '无 message 时 msg 优先于 error') + + mockResponse(t, { success: false, error: 'm3' }) + await assert.rejects(callJava({ url: '/newApi/api/x', method: 'GET' }), /m3/, '仅 error 时回退 error') +}) + +test('test_call_java_non_wrapped_passthrough', async (t) => { + mockResponse(t, { hello: 'world', count: 3 }) + const result = await callJava<{ hello: string; count: number }>({ + url: '/newApi/api/x', + method: 'GET', + }) + assert.deepEqual(result, { hello: 'world', count: 3 }) +}) + +test('test_call_java_null_data', async (t) => { + mockResponse(t, { success: true, message: 'ok', data: null }) + const result = await callJava({ url: '/newApi/api/x', method: 'GET' }) + assert.equal(result, null) +}) + +test('test_call_java_network_error', async (t) => { + t.mock.method(http, 'request', async () => { + throw new Error('Network Error') + }) + await assert.rejects( + callJava({ url: '/newApi/api/x', method: 'GET' }), + /Network Error/, + ) +}) + +test('test_call_java_http_error_status', async (t) => { + t.mock.method(http, 'request', async () => { + throw new Error('404 接口不存在') + }) + await assert.rejects( + callJava({ url: '/newApi/api/x', method: 'GET' }), + /404 接口不存在/, + ) +}) diff --git a/frontend-vue/tsconfig.json b/frontend-vue/tsconfig.json index 5fef477c..9e7bc765 100644 --- a/frontend-vue/tsconfig.json +++ b/frontend-vue/tsconfig.json @@ -8,6 +8,7 @@ "jsx": "preserve", "resolveJsonModule": true, "isolatedModules": true, + "allowImportingTsExtensions": true, "esModuleInterop": true, "lib": [ "ES2020",