|
@@ -298,6 +298,101 @@
|
|
|
pointer-events: none;
|
|
pointer-events: none;
|
|
|
word-break: break-all;
|
|
word-break: break-all;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ .api-debug-overlay {
|
|
|
|
|
+ display: none;
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ inset: 0;
|
|
|
|
|
+ z-index: 10050;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ padding: 16px;
|
|
|
|
|
+ background: rgba(0, 0, 0, 0.62);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .api-debug-overlay.is-visible {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .api-debug-modal {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ width: min(100%, 720px);
|
|
|
|
|
+ max-height: min(88vh, 900px);
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.28);
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .api-debug-modal__header {
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ padding: 14px 16px 10px;
|
|
|
|
|
+ border-bottom: 1px solid rgba(170, 170, 170, 0.25);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .api-debug-modal__title {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ line-height: 1.4;
|
|
|
|
|
+ color: var(--text);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .api-debug-modal__meta {
|
|
|
|
|
+ margin-top: 6px;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ line-height: 1.5;
|
|
|
|
|
+ color: var(--muted);
|
|
|
|
|
+ word-break: break-all;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .api-debug-modal__body {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ min-height: 0;
|
|
|
|
|
+ overflow: auto;
|
|
|
|
|
+ -webkit-overflow-scrolling: touch;
|
|
|
|
|
+ padding: 12px 16px;
|
|
|
|
|
+ background: #f8f9fc;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .api-debug-modal__pre {
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ line-height: 1.55;
|
|
|
|
|
+ white-space: pre-wrap;
|
|
|
|
|
+ word-break: break-word;
|
|
|
|
|
+ color: #222;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .api-debug-modal__footer {
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ padding: 12px 16px calc(12px + var(--safe-bottom));
|
|
|
|
|
+ border-top: 1px solid rgba(170, 170, 170, 0.25);
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .api-debug-modal__btn {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 44px;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ font-size: 15px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .api-debug-modal__btn--primary {
|
|
|
|
|
+ background: var(--orange);
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .api-debug-modal__btn--ghost {
|
|
|
|
|
+ background: #eef1f7;
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ }
|
|
|
</style>
|
|
</style>
|
|
|
</head>
|
|
</head>
|
|
|
<body>
|
|
<body>
|
|
@@ -307,6 +402,22 @@
|
|
|
|
|
|
|
|
<div id="openAppToast" role="status" aria-live="polite"></div>
|
|
<div id="openAppToast" role="status" aria-live="polite"></div>
|
|
|
|
|
|
|
|
|
|
+ <div id="apiDebugOverlay" class="api-debug-overlay" aria-hidden="true">
|
|
|
|
|
+ <div class="api-debug-modal" role="dialog" aria-modal="true" aria-labelledby="apiDebugTitle">
|
|
|
|
|
+ <div class="api-debug-modal__header">
|
|
|
|
|
+ <div id="apiDebugTitle" class="api-debug-modal__title">会话记录接口返回</div>
|
|
|
|
|
+ <div id="apiDebugMeta" class="api-debug-modal__meta"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="api-debug-modal__body">
|
|
|
|
|
+ <pre id="apiDebugContent" class="api-debug-modal__pre"></pre>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="api-debug-modal__footer">
|
|
|
|
|
+ <button type="button" id="apiDebugCopyBtn" class="api-debug-modal__btn api-debug-modal__btn--ghost">复制 JSON</button>
|
|
|
|
|
+ <button type="button" id="apiDebugCloseBtn" class="api-debug-modal__btn api-debug-modal__btn--primary">关闭</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
<div class="fab-wrap">
|
|
<div class="fab-wrap">
|
|
|
<div class="fab-dock__slot">
|
|
<div class="fab-dock__slot">
|
|
|
<!-- 与 secondShareGoods 相同顺序:openApp 在下,launch-btn 在上,避免挡住点击 -->
|
|
<!-- 与 secondShareGoods 相同顺序:openApp 在下,launch-btn 在上,避免挡住点击 -->
|
|
@@ -565,6 +676,86 @@
|
|
|
return getConversationApiBase(type) + "?" + params.toString();
|
|
return getConversationApiBase(type) + "?" + params.toString();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ var apiDebugModalText = "";
|
|
|
|
|
+
|
|
|
|
|
+ function formatApiDebugJson(value) {
|
|
|
|
|
+ if (value == null) return "";
|
|
|
|
|
+ if (typeof value === "string") return value;
|
|
|
|
|
+ try {
|
|
|
|
|
+ return JSON.stringify(value, null, 2);
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ return String(value);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function showConversationApiDebugModal(info) {
|
|
|
|
|
+ var overlay = document.getElementById("apiDebugOverlay");
|
|
|
|
|
+ var metaEl = document.getElementById("apiDebugMeta");
|
|
|
|
|
+ var contentEl = document.getElementById("apiDebugContent");
|
|
|
|
|
+ if (!overlay || !metaEl || !contentEl) return;
|
|
|
|
|
+
|
|
|
|
|
+ var requestUrl = info && info.requestUrl ? String(info.requestUrl) : "";
|
|
|
|
|
+ var statusText = info && info.status ? String(info.status) : "unknown";
|
|
|
|
|
+ var metaParts = ["状态:" + statusText];
|
|
|
|
|
+ if (requestUrl) metaParts.push("请求:" + requestUrl);
|
|
|
|
|
+ metaEl.textContent = metaParts.join("\n");
|
|
|
|
|
+
|
|
|
|
|
+ var sections = [];
|
|
|
|
|
+ if (info && info.error) {
|
|
|
|
|
+ sections.push("【错误信息】\n" + String(info.error));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (info && info.rawResponse != null) {
|
|
|
|
|
+ sections.push("【接口原始返回】\n" + formatApiDebugJson(info.rawResponse));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (info && info.normalized != null) {
|
|
|
|
|
+ sections.push("【解析后的数据】\n" + formatApiDebugJson(info.normalized));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!sections.length) {
|
|
|
|
|
+ sections.push("(无返回数据)");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ apiDebugModalText = sections.join("\n\n");
|
|
|
|
|
+ contentEl.textContent = apiDebugModalText;
|
|
|
|
|
+ overlay.classList.add("is-visible");
|
|
|
|
|
+ overlay.setAttribute("aria-hidden", "false");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function hideConversationApiDebugModal() {
|
|
|
|
|
+ var overlay = document.getElementById("apiDebugOverlay");
|
|
|
|
|
+ if (!overlay) return;
|
|
|
|
|
+ overlay.classList.remove("is-visible");
|
|
|
|
|
+ overlay.setAttribute("aria-hidden", "true");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function bindConversationApiDebugModalEvents() {
|
|
|
|
|
+ var overlay = document.getElementById("apiDebugOverlay");
|
|
|
|
|
+ var closeBtn = document.getElementById("apiDebugCloseBtn");
|
|
|
|
|
+ var copyBtn = document.getElementById("apiDebugCopyBtn");
|
|
|
|
|
+ if (closeBtn) {
|
|
|
|
|
+ closeBtn.addEventListener("click", hideConversationApiDebugModal);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (overlay) {
|
|
|
|
|
+ overlay.addEventListener("click", function (e) {
|
|
|
|
|
+ if (e.target === overlay) hideConversationApiDebugModal();
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ if (copyBtn) {
|
|
|
|
|
+ copyBtn.addEventListener("click", function () {
|
|
|
|
|
+ var text = apiDebugModalText || "";
|
|
|
|
|
+ if (!text) return;
|
|
|
|
|
+ if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
|
|
|
+ navigator.clipboard.writeText(text).then(function () {
|
|
|
|
|
+ showFabToast("已复制到剪贴板");
|
|
|
|
|
+ }).catch(function () {
|
|
|
|
|
+ showFabToast("复制失败,请手动选择文本复制");
|
|
|
|
|
+ });
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ showFabToast("当前环境不支持自动复制,请手动选择文本复制");
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
function normalizeConversationRole(raw) {
|
|
function normalizeConversationRole(raw) {
|
|
|
var role = String(raw || "").trim().toLowerCase();
|
|
var role = String(raw || "").trim().toLowerCase();
|
|
|
if (
|
|
if (
|
|
@@ -697,6 +888,12 @@
|
|
|
|
|
|
|
|
function fetchConversationHistory(sessionId, userId, type) {
|
|
function fetchConversationHistory(sessionId, userId, type) {
|
|
|
var requestUrl = buildConversationApiUrl(sessionId, userId, type);
|
|
var requestUrl = buildConversationApiUrl(sessionId, userId, type);
|
|
|
|
|
+ var debugShown = false;
|
|
|
|
|
+ function showDebug(info) {
|
|
|
|
|
+ if (debugShown) return;
|
|
|
|
|
+ debugShown = true;
|
|
|
|
|
+ showConversationApiDebugModal(info);
|
|
|
|
|
+ }
|
|
|
console.log("[conversation-api] GET", requestUrl);
|
|
console.log("[conversation-api] GET", requestUrl);
|
|
|
return fetch(requestUrl, {
|
|
return fetch(requestUrl, {
|
|
|
method: "GET",
|
|
method: "GET",
|
|
@@ -713,21 +910,57 @@
|
|
|
})
|
|
})
|
|
|
.then(function (text) {
|
|
.then(function (text) {
|
|
|
var hint = "";
|
|
var hint = "";
|
|
|
|
|
+ var parsed = null;
|
|
|
try {
|
|
try {
|
|
|
- var j = JSON.parse(text);
|
|
|
|
|
- hint = j.msg || j.message || "";
|
|
|
|
|
|
|
+ parsed = JSON.parse(text);
|
|
|
|
|
+ hint = parsed.msg || parsed.message || "";
|
|
|
} catch (eP) {
|
|
} catch (eP) {
|
|
|
if (text) hint = text.slice(0, 120);
|
|
if (text) hint = text.slice(0, 120);
|
|
|
}
|
|
}
|
|
|
- throw new Error("对话接口 HTTP " + r.status + (hint ? ":" + hint : ""));
|
|
|
|
|
|
|
+ var errMsg = "对话接口 HTTP " + r.status + (hint ? ":" + hint : "");
|
|
|
|
|
+ showDebug({
|
|
|
|
|
+ requestUrl: requestUrl,
|
|
|
|
|
+ status: "HTTP " + r.status,
|
|
|
|
|
+ rawResponse: parsed != null ? parsed : text,
|
|
|
|
|
+ error: errMsg,
|
|
|
|
|
+ });
|
|
|
|
|
+ throw new Error(errMsg);
|
|
|
});
|
|
});
|
|
|
})
|
|
})
|
|
|
.then(function (res) {
|
|
.then(function (res) {
|
|
|
- var data = normalizeConversationApiPayload(res);
|
|
|
|
|
- if (!data) {
|
|
|
|
|
- throw new Error("对话接口返回数据为空或格式无法解析");
|
|
|
|
|
|
|
+ var data = null;
|
|
|
|
|
+ var parseError = "";
|
|
|
|
|
+ try {
|
|
|
|
|
+ data = normalizeConversationApiPayload(res);
|
|
|
|
|
+ if (!data) {
|
|
|
|
|
+ parseError = "对话接口返回数据为空或格式无法解析";
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (eNorm) {
|
|
|
|
|
+ parseError = eNorm && eNorm.message ? eNorm.message : "对话数据解析失败";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ showDebug({
|
|
|
|
|
+ requestUrl: requestUrl,
|
|
|
|
|
+ status: parseError ? "解析失败" : "成功",
|
|
|
|
|
+ rawResponse: res,
|
|
|
|
|
+ normalized: data,
|
|
|
|
|
+ error: parseError,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (parseError) {
|
|
|
|
|
+ throw new Error(parseError);
|
|
|
}
|
|
}
|
|
|
return data;
|
|
return data;
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(function (e) {
|
|
|
|
|
+ if (!debugShown) {
|
|
|
|
|
+ showDebug({
|
|
|
|
|
+ requestUrl: requestUrl,
|
|
|
|
|
+ status: "请求失败",
|
|
|
|
|
+ error: e && e.message ? e.message : String(e || "未知错误"),
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ throw e;
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1579,6 +1812,7 @@
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function boot() {
|
|
function boot() {
|
|
|
|
|
+ bindConversationApiDebugModalEvents();
|
|
|
var launchTag = document.getElementById("launch-btn");
|
|
var launchTag = document.getElementById("launch-btn");
|
|
|
if (launchTag) launchTag.setAttribute("appid", WECHAT_OPEN_APP_ID);
|
|
if (launchTag) launchTag.setAttribute("appid", WECHAT_OPEN_APP_ID);
|
|
|
bindWeChatLaunchTagEvents();
|
|
bindWeChatLaunchTagEvents();
|