1. 更新所有服务Dockerfile,切换到eclipse-temurin:17-jre-alpine镜像并调整服务端口 2. 配置前端项目基础路径与nginx代理 3. 新增数据库初始化编码设置与测试依赖 4. 添加部分服务的Servlet编码配置与JWT/LLM密钥配置 5. 完善话术实体类校验注解与Mapper接口 6. 新增密码生成工具类与部分测试文件配置
213 lines
7.9 KiB
HTML
213 lines
7.9 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>企微 JS-SDK 测试页</title>
|
||
<style>
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
body { font-family: -apple-system, sans-serif; background: #f5f5f5; padding: 16px; }
|
||
.card { background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
|
||
.title { font-size: 16px; font-weight: 600; margin-bottom: 12px; color: #333; }
|
||
.btn { display: block; width: 100%; padding: 12px; border: none; border-radius: 8px; background: #1677ff; color: #fff; font-size: 15px; margin-bottom: 8px; cursor: pointer; }
|
||
.btn:disabled { background: #ccc; }
|
||
.btn.secondary { background: #52c41a; }
|
||
.btn.danger { background: #ff4d4f; }
|
||
.log { background: #1e1e1e; color: #d4d4d4; padding: 12px; border-radius: 8px; font-family: monospace; font-size: 12px; line-height: 1.6; max-height: 300px; overflow-y: auto; white-space: pre-wrap; word-break: break-all; }
|
||
.ok { color: #7ee787; }
|
||
.err { color: #f85149; }
|
||
.info { color: #79c0ff; }
|
||
.status { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 12px; }
|
||
.status.ok { background: #f6ffed; color: #52c41a; }
|
||
.status.err { background: #fff2f0; color: #ff4d4f; }
|
||
.status.warn { background: #fffbe6; color: #faad14; }
|
||
.row { display: flex; gap: 8px; margin-bottom: 8px; align-items: center; }
|
||
input { flex: 1; padding: 8px 12px; border: 1px solid #d9d9d9; border-radius: 6px; font-size: 14px; }
|
||
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="card">
|
||
<div class="title">环境检测 <span id="env-status" class="status warn">检测中</span></div>
|
||
<div class="row"><span>wx 对象:</span><span id="wx-exists">--</span></div>
|
||
<div class="row"><span>当前 URL:</span><span id="current-url" style="font-size:12px;word-break:break-all;">--</span></div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="title">1. 签名接口测试</div>
|
||
<button class="btn" onclick="testSignature()">获取 JS-SDK 签名</button>
|
||
<div class="grid">
|
||
<button class="btn secondary" onclick="injectMockWx()">注入模拟 wx</button>
|
||
<button class="btn danger" onclick="injectErrorWx()">注入错误 wx</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="title">2. wx.config 测试</div>
|
||
<button class="btn" onclick="testWxConfig()">执行 wx.config</button>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="title">3. API 调用测试</div>
|
||
<div class="grid">
|
||
<button class="btn secondary" onclick="testGetContext()">getContext</button>
|
||
<button class="btn secondary" onclick="testGetCurExternalContact()">getCurExternalContact</button>
|
||
</div>
|
||
<div class="row" style="margin-top:8px;"><input type="text" id="send-text" value="这是一条测试消息"></div>
|
||
<button class="btn" onclick="testSendChatMessage()">sendChatMessage</button>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="title">4. OAuth 登录测试</div>
|
||
<button class="btn secondary" onclick="testOAuth()">模拟 OAuth 流程</button>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="title">日志输出</div>
|
||
<button class="btn" style="margin-bottom:8px;background:#666;" onclick="clearLog()">清空日志</button>
|
||
<div class="log" id="log"></div>
|
||
</div>
|
||
|
||
<script>
|
||
const logEl = document.getElementById('log');
|
||
function log(msg, type) {
|
||
const time = new Date().toLocaleTimeString();
|
||
const cls = type === 'ok' ? 'ok' : type === 'err' ? 'err' : 'info';
|
||
logEl.innerHTML += '<span class="' + cls + '">[' + time + '] ' + msg + '</span>\n';
|
||
logEl.scrollTop = logEl.scrollHeight;
|
||
}
|
||
function clearLog() { logEl.innerHTML = ''; }
|
||
|
||
function checkEnv() {
|
||
var wxExists = typeof wx !== 'undefined' && wx !== null;
|
||
document.getElementById('wx-exists').textContent = wxExists ? '存在' : '不存在';
|
||
document.getElementById('current-url').textContent = location.href;
|
||
var st = document.getElementById('env-status');
|
||
if (wxExists) { st.textContent = '企微环境'; st.className = 'status ok'; log('检测到企微环境', 'ok'); }
|
||
else { st.textContent = '浏览器环境'; st.className = 'status warn'; log('浏览器环境,wx 不存在', 'info'); }
|
||
}
|
||
|
||
async function testSignature() {
|
||
log('请求签名接口...');
|
||
try {
|
||
var url = location.href.split('#')[0];
|
||
var res = await fetch('/api/v1/auth/signature?url=' + encodeURIComponent(url));
|
||
var data = await res.json();
|
||
if (data.code === 0) {
|
||
log('签名获取成功', 'ok');
|
||
log(' corpId: ' + data.data.corpId);
|
||
log(' agentId: ' + data.data.agentId);
|
||
log(' timestamp: ' + data.data.timestamp);
|
||
log(' signature: ' + data.data.signature.substring(0, 20) + '...');
|
||
window._wxConfig = data.data;
|
||
} else {
|
||
log('签名失败: ' + data.message, 'err');
|
||
}
|
||
} catch (e) {
|
||
log('请求异常: ' + e.message, 'err');
|
||
}
|
||
}
|
||
|
||
function injectMockWx() {
|
||
window.wx = {
|
||
config: function(opts) {
|
||
log('[模拟] wx.config 调用', 'ok');
|
||
log(' jsApiList: ' + JSON.stringify(opts.jsApiList));
|
||
setTimeout(function() { if (opts.ready) opts.ready(); }, 100);
|
||
},
|
||
ready: function(fn) { this._ready = fn; },
|
||
error: function(fn) { this._error = fn; },
|
||
invoke: function(api, params, cb) {
|
||
log('[模拟] invoke: ' + api, 'info');
|
||
if (api === 'getCurExternalContact') {
|
||
cb({ err_msg: 'getCurExternalContact:ok', userId: 'mock_customer_001' });
|
||
} else if (api === 'sendChatMessage') {
|
||
cb({ err_msg: 'sendChatMessage:ok' });
|
||
} else if (api === 'getContext') {
|
||
cb({ err_msg: 'getContext:ok', entry: 'normal' });
|
||
}
|
||
}
|
||
};
|
||
log('已注入模拟 wx 对象', 'ok');
|
||
checkEnv();
|
||
}
|
||
|
||
function injectErrorWx() {
|
||
window.wx = {
|
||
config: function(opts) {
|
||
setTimeout(function() { if (opts.error) opts.error({ errMsg: 'invalid signature' }); }, 100);
|
||
},
|
||
ready: function(fn) {},
|
||
error: function(fn) { fn({ errMsg: 'invalid signature' }); }
|
||
};
|
||
log('已注入错误 wx 对象', 'err');
|
||
checkEnv();
|
||
}
|
||
|
||
async function testWxConfig() {
|
||
if (!window._wxConfig) {
|
||
log('请先获取签名', 'err'); return;
|
||
}
|
||
var wx = window.wx;
|
||
if (!wx || !wx.config) {
|
||
log('wx 对象不存在,请先注入模拟对象', 'err'); return;
|
||
}
|
||
log('执行 wx.config...');
|
||
var cfg = window._wxConfig;
|
||
wx.config({
|
||
beta: true,
|
||
debug: false,
|
||
appId: cfg.corpId,
|
||
timestamp: cfg.timestamp,
|
||
nonceStr: cfg.nonceStr,
|
||
signature: cfg.signature,
|
||
jsApiList: ['sendChatMessage', 'getContext', 'getCurExternalContact']
|
||
});
|
||
}
|
||
|
||
function testGetContext() {
|
||
var wx = window.wx;
|
||
if (!wx || !wx.invoke) { log('wx.invoke 不存在', 'err'); return; }
|
||
wx.invoke('getContext', {}, function(res) {
|
||
log('getContext 结果: ' + JSON.stringify(res), res.err_msg === 'getContext:ok' ? 'ok' : 'err');
|
||
});
|
||
}
|
||
|
||
function testGetCurExternalContact() {
|
||
var wx = window.wx;
|
||
if (!wx || !wx.invoke) { log('wx.invoke 不存在', 'err'); return; }
|
||
wx.invoke('getCurExternalContact', {}, function(res) {
|
||
log('getCurExternalContact 结果: ' + JSON.stringify(res), res.err_msg === 'getCurExternalContact:ok' ? 'ok' : 'err');
|
||
});
|
||
}
|
||
|
||
function testSendChatMessage() {
|
||
var wx = window.wx;
|
||
if (!wx || !wx.invoke) { log('wx.invoke 不存在', 'err'); return; }
|
||
var text = document.getElementById('send-text').value;
|
||
wx.invoke('sendChatMessage', {
|
||
msgtype: 'text',
|
||
text: { content: text }
|
||
}, function(res) {
|
||
log('sendChatMessage 结果: ' + JSON.stringify(res), res.err_msg === 'sendChatMessage:ok' ? 'ok' : 'err');
|
||
});
|
||
}
|
||
|
||
async function testOAuth() {
|
||
log('测试 OAuth 流程...');
|
||
var code = 'mock_code_' + Date.now();
|
||
try {
|
||
var res = await fetch('/api/v1/auth/login?code=' + code, { method: 'POST' });
|
||
var data = await res.json();
|
||
log('OAuth 登录结果: ' + JSON.stringify(data).substring(0, 200));
|
||
} catch (e) {
|
||
log('OAuth 请求异常: ' + e.message, 'err');
|
||
}
|
||
}
|
||
|
||
checkEnv();
|
||
</script>
|
||
</body>
|
||
</html>
|