!105 czh-20260717-优化-测试页面增加linkTitle和data支持
* czh-20260717-优化-测试页面增加linkTitle和data支持 * czh-20260717-修正测试页面默认Mock端口为19010 * czh-20260717-新增即时通推送测试页面
This commit is contained in:
@@ -0,0 +1,301 @@
|
||||
<template>
|
||||
<div class="ksim-test-container">
|
||||
<a-card title="即时通消息推送测试" style="margin-bottom: 16px">
|
||||
<a-form :label-col="{ span: 4 }" :wrapper-col="{ span: 18 }">
|
||||
<a-divider orientation="left">即时通连接配置</a-divider>
|
||||
<a-form-item label="API 地址(host)">
|
||||
<a-input v-model:value="formData.host" placeholder="http://localhost:17072" />
|
||||
<span style="color: #8c8c8c; font-size: 12px; margin-left: 8px">即时通服务器地址,含端口号</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="应用ID(appId)">
|
||||
<a-input v-model:value="formData.appId" placeholder="test-app" />
|
||||
</a-form-item>
|
||||
<a-form-item label="应用密钥(appSecret)">
|
||||
<a-input-password v-model:value="formData.appSecret" placeholder="test-secret" />
|
||||
</a-form-item>
|
||||
|
||||
<a-divider orientation="left">消息内容</a-divider>
|
||||
<a-form-item label="用户标识类型">
|
||||
<a-input v-model:value="formData.toUserKeyType" placeholder="Email" />
|
||||
<span style="color: #8c8c8c; font-size: 12px; margin-left: 8px">如 Email、Phone 等,对应即时通用户关联类型</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="用户标识值">
|
||||
<a-input v-model:value="formData.toUserValue" placeholder="user@example.com" />
|
||||
<span style="color: #8c8c8c; font-size: 12px; margin-left: 8px">接收人的具体标识值</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="消息标题">
|
||||
<a-input v-model:value="formData.title" placeholder="测试消息标题" />
|
||||
</a-form-item>
|
||||
<a-form-item label="消息内容">
|
||||
<a-textarea v-model:value="formData.content" placeholder="测试消息正文" :rows="3" />
|
||||
</a-form-item>
|
||||
<a-form-item label="链接地址(可选)">
|
||||
<a-input v-model:value="formData.linkUrl" placeholder="http://localhost:3100/semri/task" />
|
||||
<span style="color: #8c8c8c; font-size: 12px; margin-left: 8px">点击消息后跳转的链接</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="链接标题(可选)">
|
||||
<a-input v-model:value="formData.linkTitle" placeholder="查看详情" />
|
||||
<span style="color: #8c8c8c; font-size: 12px; margin-left: 8px">链接显示的文字</span>
|
||||
</a-form-item>
|
||||
<a-form-item label="业务数据 data(可选)">
|
||||
<a-textarea v-model:value="formData.dataJson" placeholder='{"id":"123","name":"zhangsan"}' :rows="3" />
|
||||
<span style="color: #8c8c8c; font-size: 12px; margin-left: 8px">JSON 格式,发送给即时通的业务数据</span>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item :wrapper-col="{ offset: 4, span: 18 }">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="handleSend" :loading="sending">
|
||||
{{ sending ? '发送中...' : '发送消息' }}
|
||||
</a-button>
|
||||
<a-button @click="handleReset">重置</a-button>
|
||||
<a-button @click="handleFillMock">填充 Mock 默认值</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-card>
|
||||
|
||||
<a-card title="完整请求(Request)" style="margin-bottom: 16px">
|
||||
<a-descriptions :column="1" size="small" bordered>
|
||||
<a-descriptions-item label="Token 请求 URL">
|
||||
<code>{{ requestInfo.tokenRequestUrl || '(未发送)' }}</code>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="Token 请求体">
|
||||
<pre class="json-block">{{ formatJson(requestInfo.tokenRequestBody) }}</pre>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="消息请求 URL">
|
||||
<code>{{ requestInfo.msgRequestUrl || '(未发送)' }}</code>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="消息请求体">
|
||||
<pre class="json-block">{{ formatJson(requestInfo.msgRequestBody) }}</pre>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
|
||||
<a-card title="完整响应(Response)" style="margin-bottom: 16px">
|
||||
<a-space direction="vertical" style="width: 100%">
|
||||
<div v-if="responseInfo.success === true" style="margin-bottom: 8px">
|
||||
<a-tag color="green">发送成功</a-tag>
|
||||
<span v-if="responseInfo.messageId"> messageId: {{ responseInfo.messageId }}</span>
|
||||
</div>
|
||||
<div v-else-if="responseInfo.success === false" style="margin-bottom: 8px">
|
||||
<a-tag color="red">发送失败</a-tag>
|
||||
<span v-if="responseInfo.errorMessage"> {{ responseInfo.errorMessage }}</span>
|
||||
</div>
|
||||
<a-descriptions :column="1" size="small" bordered>
|
||||
<a-descriptions-item label="Token 响应">
|
||||
<pre class="json-block">{{ formatJson(responseInfo.tokenResponse) }}</pre>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="消息响应">
|
||||
<pre class="json-block">{{ formatJson(responseInfo.msgResponse) }}</pre>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="状态码">
|
||||
<a-tag :color="responseInfo.responseCode === 0 || responseInfo.responseCode === 200 ? 'green' : 'red'">
|
||||
{{ responseInfo.responseCode !== undefined ? responseInfo.responseCode : '-' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-space>
|
||||
</a-card>
|
||||
|
||||
<a-card title="事件日志">
|
||||
<div class="event-log-wrapper">
|
||||
<a-button size="small" @click="eventLogs = []" style="margin-bottom: 8px">清空日志</a-button>
|
||||
<div class="event-log-list">
|
||||
<div v-for="(log, idx) in eventLogs" :key="idx" class="event-log-item">
|
||||
<a-tag :color="log.type === 'success' ? 'green' : log.type === 'error' ? 'red' : 'blue'" size="small">
|
||||
{{ log.type }}
|
||||
</a-tag>
|
||||
<span class="log-time">{{ log.time }}</span>
|
||||
<span class="log-msg">{{ log.message }}</span>
|
||||
</div>
|
||||
<div v-if="eventLogs.length === 0" class="empty-log">暂无日志</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
const sending = ref(false);
|
||||
const eventLogs = ref<any[]>([]);
|
||||
|
||||
const formData = reactive({
|
||||
host: 'http://localhost:19010',
|
||||
appId: 'test-app',
|
||||
appSecret: 'test-secret',
|
||||
toUserKeyType: 'Email',
|
||||
toUserValue: 'test@example.com',
|
||||
title: '测试消息',
|
||||
content: '这是一条来自督办系统的测试消息',
|
||||
linkUrl: '',
|
||||
linkTitle: '',
|
||||
dataJson: '',
|
||||
});
|
||||
|
||||
const requestInfo = reactive<Record<string, any>>({});
|
||||
const responseInfo = reactive<Record<string, any>>({});
|
||||
|
||||
function addLog(type: string, message: string) {
|
||||
const now = new Date();
|
||||
const time = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
|
||||
eventLogs.value.unshift({ type, message, time });
|
||||
if (eventLogs.value.length > 100) eventLogs.value.pop();
|
||||
}
|
||||
|
||||
function formatJson(obj: any): string {
|
||||
if (!obj) return '(空)';
|
||||
try {
|
||||
return JSON.stringify(obj, null, 2);
|
||||
} catch {
|
||||
return String(obj);
|
||||
}
|
||||
}
|
||||
|
||||
function handleFillMock() {
|
||||
formData.host = 'http://localhost:19010';
|
||||
formData.appId = 'test-app';
|
||||
formData.appSecret = 'test-secret';
|
||||
formData.toUserKeyType = 'Email';
|
||||
formData.toUserValue = 'test@example.com';
|
||||
formData.title = '测试消息';
|
||||
formData.content = '这是一条来自督办系统的测试消息';
|
||||
formData.linkUrl = '';
|
||||
formData.linkTitle = '';
|
||||
formData.dataJson = '';
|
||||
addLog('info', '已填充 Mock 默认值');
|
||||
}
|
||||
|
||||
async function handleSend() {
|
||||
if (!formData.host) {
|
||||
addLog('error', '请填写 API 地址(host)');
|
||||
return;
|
||||
}
|
||||
if (!formData.toUserKeyType || !formData.toUserValue) {
|
||||
addLog('error', '请填写用户标识类型和值');
|
||||
return;
|
||||
}
|
||||
|
||||
sending.value = true;
|
||||
addLog('info', `开始发送消息 → ${formData.host}`);
|
||||
|
||||
// 清空上次结果
|
||||
Object.keys(requestInfo).forEach(k => delete requestInfo[k]);
|
||||
Object.keys(responseInfo).forEach(k => delete responseInfo[k]);
|
||||
|
||||
try {
|
||||
const res = await defHttp.post({
|
||||
url: '/ksim/test/send',
|
||||
data: {
|
||||
...formData,
|
||||
data: formData.dataJson ? JSON.parse(formData.dataJson) : null,
|
||||
},
|
||||
});
|
||||
|
||||
if (res?.request) {
|
||||
Object.assign(requestInfo, res.request);
|
||||
}
|
||||
if (res?.tokenResponse) {
|
||||
responseInfo.tokenResponse = res.tokenResponse;
|
||||
}
|
||||
if (res?.msgResponse) {
|
||||
responseInfo.msgResponse = res.msgResponse;
|
||||
}
|
||||
responseInfo.success = res?.success;
|
||||
responseInfo.messageId = res?.messageId;
|
||||
responseInfo.errorMessage = res?.errorMessage;
|
||||
responseInfo.responseCode = res?.responseCode;
|
||||
|
||||
if (res?.success) {
|
||||
addLog('success', `发送成功!messageId: ${res?.messageId || '-'}`);
|
||||
} else {
|
||||
addLog('error', `发送失败: ${res?.errorMessage || '未知错误'}`);
|
||||
}
|
||||
} catch (e: any) {
|
||||
addLog('error', `请求异常: ${e?.message || e}`);
|
||||
responseInfo.success = false;
|
||||
responseInfo.errorMessage = e?.message || '网络请求异常';
|
||||
} finally {
|
||||
sending.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
formData.host = 'http://localhost:19010';
|
||||
formData.appId = 'test-app';
|
||||
formData.appSecret = 'test-secret';
|
||||
formData.toUserKeyType = 'Email';
|
||||
formData.toUserValue = 'test@example.com';
|
||||
formData.title = '测试消息';
|
||||
formData.content = '这是一条来自督办系统的测试消息';
|
||||
formData.linkUrl = '';
|
||||
formData.linkTitle = '';
|
||||
formData.dataJson = '';
|
||||
Object.keys(requestInfo).forEach(k => delete requestInfo[k]);
|
||||
Object.keys(responseInfo).forEach(k => delete responseInfo[k]);
|
||||
eventLogs.value = [];
|
||||
addLog('info', '表单已重置');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ksim-test-container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.json-block {
|
||||
background: #f5f5f5;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.event-log-wrapper {
|
||||
.event-log-list {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
background: #fafafa;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.event-log-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 4px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.log-time {
|
||||
font-size: 12px;
|
||||
color: #8c8c8c;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.log-msg {
|
||||
font-size: 13px;
|
||||
color: #262626;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-log {
|
||||
text-align: center;
|
||||
color: #8c8c8c;
|
||||
font-size: 13px;
|
||||
padding: 16px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user