修复bug

This commit is contained in:
2026-05-11 22:22:18 +08:00
parent 03bc46df29
commit 7d891c9f7b
22 changed files with 2198 additions and 181 deletions
+178
View File
@@ -0,0 +1,178 @@
/* eslint-disable */
// @ts-ignore
import type { CustomRequestOptions } from '@/http/types';
type AnyRecord = Record<string, any>;
type StreamCallbacks = {
onToken?: (text: string) => void;
onDone?: () => void;
onError?: (err: unknown) => void;
onStart?: (payload: Record<string, any>) => void;
onTool?: (payload: Record<string, any>) => void;
onChunk?: (payload: Record<string, any>) => void;
onEnd?: (payload: Record<string, any>) => void;
};
export type AiChatStreamQuery = {
content: string;
conversationId?: string;
};
function decodeChunk(data: ArrayBuffer | string): string {
if (typeof data === 'string') return data;
try {
return new TextDecoder('utf-8').decode(data);
} catch (e) {
const arr = new Uint8Array(data);
let str = '';
for (let i = 0; i < arr.length; i += 1) str += String.fromCharCode(arr[i]);
return decodeURIComponent(escape(str));
}
}
function parseSsePayload(raw: string): string {
const line = raw.trim();
if (!line) return '';
if (!line.startsWith('data:')) return line;
const payload = line.slice(5).trim();
if (!payload || payload === '[DONE]') return '';
try {
const json = JSON.parse(payload);
return (
json?.content ??
json?.delta?.content ??
json?.message ??
json?.data?.content ??
''
);
} catch (e) {
return payload;
}
}
function parseSseEventBlock(block: string): { event: string; payload: Record<string, any> | null } | null {
const lines = block
.split('\n')
.map((line) => line.trim())
.filter(Boolean);
if (!lines.length) return null;
let eventName = 'message';
const dataLines: string[] = [];
lines.forEach((line) => {
if (line.startsWith('event:')) {
eventName = line.slice(6).trim() || 'message';
} else if (line.startsWith('data:')) {
dataLines.push(line.slice(5).trim());
}
});
if (!dataLines.length) return { event: eventName, payload: null };
const raw = dataLines.join('\n');
try {
return { event: eventName, payload: JSON.parse(raw) };
} catch (e) {
return { event: eventName, payload: { text: raw } };
}
}
function dispatchSseEvent(
parsed: { event: string; payload: Record<string, any> | null } | null,
callbacks?: StreamCallbacks,
) {
if (!parsed) return;
const payload = parsed.payload || {};
switch (parsed.event) {
case 'start':
callbacks?.onStart?.(payload);
break;
case 'tool':
callbacks?.onTool?.(payload);
break;
case 'chunk':
callbacks?.onChunk?.(payload);
if (!callbacks?.onChunk && typeof payload.text === 'string' && payload.text) {
callbacks?.onToken?.(payload.text);
}
break;
case 'end':
callbacks?.onEnd?.(payload);
callbacks?.onDone?.();
break;
default:
// 兼容未知 event 或普通 message
if (typeof payload.text === 'string' && payload.text) {
callbacks?.onToken?.(payload.text);
}
break;
}
}
/**
* AI 流式对话 GET /app/ai/chat/stream
* 注意:不同端对 chunk 支持程度不同,不支持时会在 success 中返回完整文本。
*/
export function appAiChatStreamGet({
query,
callbacks,
options,
}: {
query: AiChatStreamQuery;
callbacks?: StreamCallbacks;
options?: CustomRequestOptions;
}) {
let buffer = '';
let gotChunk = false;
const task = uni.request({
url: '/app/ai/chat/stream',
method: 'GET',
data: query,
enableChunked: true as any,
responseType: 'text',
timeout: options?.timeout ?? 60000,
header: {
...(options?.header || {}),
},
success(res) {
// 部分端不支持 chunk 回调,这里兜底按整段文本处理
if (gotChunk) {
return;
}
const raw = typeof res.data === 'string' ? res.data : JSON.stringify(res.data || '');
const normalized = raw.replace(/\r\n/g, '\n');
const blocks = normalized.split('\n\n').filter(Boolean);
if (!blocks.length) {
if (raw) callbacks?.onToken?.(raw);
callbacks?.onDone?.();
return;
}
blocks.forEach((block) => {
dispatchSseEvent(parseSseEventBlock(block), callbacks);
});
},
fail(err) {
callbacks?.onError?.(err);
},
});
const taskAny = task as any;
if (taskAny && typeof taskAny.onChunkReceived === 'function') {
taskAny.onChunkReceived((chunk: { data: ArrayBuffer | string }) => {
gotChunk = true;
buffer += decodeChunk(chunk.data).replace(/\r\n/g, '\n');
const blocks = buffer.split('\n\n');
buffer = blocks.pop() || '';
blocks.forEach((block) => {
dispatchSseEvent(parseSseEventBlock(block), callbacks);
});
});
}
return task;
}
// 兼容旧调用名,避免其他页面引用报错
export const appAiChatStreamPost = appAiChatStreamGet;
+70
View File
@@ -0,0 +1,70 @@
/* eslint-disable */
// @ts-ignore
import request from '@/http/vue-query';
import type { CustomRequestOptions } from '@/http/types';
type AnyRecord = Record<string, any>;
export type DiningProfileFields = Record<string, unknown>;
export type DiningProfileConfigItem = {
groupKey: string;
groupName: string;
fieldKey: string;
fieldName: string;
optionsJson: string;
sortNum: number;
isRequired: number | null;
multiSelect: number;
};
/** 查询当前可用画像配置 GET /app/diningProfile/config */
export async function appDiningProfileConfigGet({
options,
}: {
options?: CustomRequestOptions;
}) {
return request<{ code: number; data: DiningProfileConfigItem[]; msg?: string }>(
'/app/diningProfile/config',
{
method: 'GET',
...(options || {}),
}
);
}
/** 查询当前登录用户画像 GET /app/diningProfile */
export async function appDiningProfileGet({
options,
}: {
options?: CustomRequestOptions;
}) {
return request<{ code: number; data: DiningProfileFields | null; msg?: string }>(
'/app/diningProfile',
{
method: 'GET',
...(options || {}),
}
);
}
/** 保存画像配置 POST /app/diningProfile/save */
export async function appDiningProfileSavePost({
body,
options,
}: {
body: { fields: DiningProfileFields };
options?: CustomRequestOptions;
}) {
return request<{ code: number; data: AnyRecord | null; msg?: string }>(
'/app/diningProfile/save',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
}
);
}
+2
View File
@@ -4,6 +4,8 @@ export * from './types';
export * from './displayEnumLabel';
export * from './filtersConfig';
export * from './aiChat';
export * from './diningProfile';
export * from './merchant';
export * from './agreement';
export * from './version';