mirror of
https://github.com/hpd840321/craftlabs-authorization-sdk.git
synced 2026-06-09 10:00:30 +08:00
feat(m5): add simulated callback event delivery for testing
This commit is contained in:
+17
-2
@@ -1,6 +1,9 @@
|
|||||||
package cn.craftlabs.platform.api.callback;
|
package cn.craftlabs.platform.api.callback;
|
||||||
|
|
||||||
|
import cn.craftlabs.platform.api.service.CallbackEventIngestService;
|
||||||
import cn.craftlabs.platform.api.service.CallbackInboxService;
|
import cn.craftlabs.platform.api.service.CallbackInboxService;
|
||||||
|
import cn.craftlabs.platform.api.web.dto.CallbackEventIngestRequest;
|
||||||
|
import cn.craftlabs.platform.api.web.dto.CallbackEventIngestResponse;
|
||||||
import cn.craftlabs.platform.api.web.dto.CallbackInboxLinkPatchRequest;
|
import cn.craftlabs.platform.api.web.dto.CallbackInboxLinkPatchRequest;
|
||||||
import cn.craftlabs.platform.api.web.dto.CallbackInboxResponse;
|
import cn.craftlabs.platform.api.web.dto.CallbackInboxResponse;
|
||||||
import cn.craftlabs.platform.api.web.dto.CallbackInboxStatusPatchRequest;
|
import cn.craftlabs.platform.api.web.dto.CallbackInboxStatusPatchRequest;
|
||||||
@@ -10,15 +13,17 @@ import cn.craftlabs.platform.api.web.dto.PageResponse;
|
|||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.Max;
|
import jakarta.validation.constraints.Max;
|
||||||
import jakarta.validation.constraints.Min;
|
import jakarta.validation.constraints.Min;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PatchMapping;
|
import org.springframework.web.bind.annotation.PatchMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestHeader;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
@@ -30,9 +35,11 @@ import java.time.OffsetDateTime;
|
|||||||
public class CallbackInboxController {
|
public class CallbackInboxController {
|
||||||
|
|
||||||
private final CallbackInboxService callbackInboxService;
|
private final CallbackInboxService callbackInboxService;
|
||||||
|
private final CallbackEventIngestService callbackEventIngestService;
|
||||||
|
|
||||||
public CallbackInboxController(CallbackInboxService callbackInboxService) {
|
public CallbackInboxController(CallbackInboxService callbackInboxService, CallbackEventIngestService callbackEventIngestService) {
|
||||||
this.callbackInboxService = callbackInboxService;
|
this.callbackInboxService = callbackInboxService;
|
||||||
|
this.callbackEventIngestService = callbackEventIngestService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
@@ -77,6 +84,14 @@ public class CallbackInboxController {
|
|||||||
return callbackInboxService.patchLink(id, request);
|
return callbackInboxService.patchLink(id, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** M5-F10:模拟投递(仅测试环境),手动 POST 模拟 Callback 事件。 */
|
||||||
|
@PostMapping("/simulate")
|
||||||
|
public CallbackEventIngestResponse simulate(
|
||||||
|
@Valid @RequestBody CallbackEventIngestRequest request,
|
||||||
|
@RequestHeader(value = "Idempotency-Key", required = false) String idempotencyKey) {
|
||||||
|
return callbackEventIngestService.ingest(request, idempotencyKey);
|
||||||
|
}
|
||||||
|
|
||||||
/** I8:代理 OPS 调用 Webhook,将关联收据的 {@code DEAD} 出库重新入队。 */
|
/** I8:代理 OPS 调用 Webhook,将关联收据的 {@code DEAD} 出库重新入队。 */
|
||||||
@PostMapping("/{id}/replay-webhook-delivery")
|
@PostMapping("/{id}/replay-webhook-delivery")
|
||||||
public CallbackWebhookReplayResponse replayWebhookDelivery(@PathVariable("id") long id) {
|
public CallbackWebhookReplayResponse replayWebhookDelivery(@PathVariable("id") long id) {
|
||||||
|
|||||||
@@ -280,6 +280,14 @@ export function patchCallbackInboxLink(id, body) {
|
|||||||
return axios.patch(`/api/v1/callback-inbox/${id}/link`, body);
|
return axios.patch(`/api/v1/callback-inbox/${id}/link`, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* M5-F10:模拟投递(仅测试环境)。
|
||||||
|
* @param {Record<string, unknown>} body
|
||||||
|
*/
|
||||||
|
export function simulateCallback(body) {
|
||||||
|
return axios.post('/api/v1/callback-inbox/simulate', body);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I8:将 Webhook 侧 DEAD 出库按收据 ID 重新入队(需平台配置 LICENSE_WEBHOOK_*)。
|
* I8:将 Webhook 侧 DEAD 出库按收据 ID 重新入队(需平台配置 LICENSE_WEBHOOK_*)。
|
||||||
* @param {string | number} id — callback inbox id
|
* @param {string | number} id — callback inbox id
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
<el-input v-model="filterProjectId" clearable placeholder="项目 ID" class="filter" style="width: 120px" @keyup.enter="load" />
|
<el-input v-model="filterProjectId" clearable placeholder="项目 ID" class="filter" style="width: 120px" @keyup.enter="load" />
|
||||||
<el-button type="primary" :loading="loading" @click="load">查询</el-button>
|
<el-button type="primary" :loading="loading" @click="load">查询</el-button>
|
||||||
<el-button @click="handleBatchRetry" :disabled="selectedCallbacks.length === 0">批量重试</el-button>
|
<el-button @click="handleBatchRetry" :disabled="selectedCallbacks.length === 0">批量重试</el-button>
|
||||||
|
<el-button @click="simDialogVisible = true">模拟投递</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -52,6 +53,29 @@
|
|||||||
@size-change="onSizeChange"
|
@size-change="onSizeChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<el-dialog v-model="simDialogVisible" title="模拟 Callback 投递" width="560px">
|
||||||
|
<el-form label-width="120px">
|
||||||
|
<el-form-item label="事件类型" required>
|
||||||
|
<el-select v-model="simForm.eventType" style="width:100%">
|
||||||
|
<el-option label="sn:post_activate" value="sn:post_activate" />
|
||||||
|
<el-option label="sn:pre_activate" value="sn:pre_activate" />
|
||||||
|
<el-option label="device:post_activate" value="device:post_activate" />
|
||||||
|
<el-option label="yunbaobao:session_logout" value="yunbaobao:session_logout" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="SN 编码">
|
||||||
|
<el-input v-model="simForm.snCode" placeholder="选填" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="Payload (JSON)">
|
||||||
|
<el-input v-model="simForm.rawPayload" type="textarea" :rows="6" placeholder='{"key": "value"}' />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="simDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="simulating" @click="handleSimulate">投递</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</el-card>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -60,7 +84,7 @@ import { ref, onMounted } from "vue";
|
|||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { useAuthStore } from "../stores/auth";
|
import { useAuthStore } from "../stores/auth";
|
||||||
import { listCallbackInbox, replayCallbackWebhookDelivery } from "../api/platform";
|
import { listCallbackInbox, replayCallbackWebhookDelivery, simulateCallback } from "../api/platform";
|
||||||
import { apiErrorMessage } from "../utils/apiErrorMessage";
|
import { apiErrorMessage } from "../utils/apiErrorMessage";
|
||||||
|
|
||||||
const auth = useAuthStore();
|
const auth = useAuthStore();
|
||||||
@@ -76,6 +100,9 @@ const filterEventType = ref("");
|
|||||||
const filterSnCode = ref("");
|
const filterSnCode = ref("");
|
||||||
const filterProjectId = ref("");
|
const filterProjectId = ref("");
|
||||||
const selectedCallbacks = ref([]);
|
const selectedCallbacks = ref([]);
|
||||||
|
const simDialogVisible = ref(false);
|
||||||
|
const simulating = ref(false);
|
||||||
|
const simForm = ref({ eventType: 'sn:post_activate', snCode: '', rawPayload: '{}' });
|
||||||
|
|
||||||
function handleSelectionChange(val) {
|
function handleSelectionChange(val) {
|
||||||
selectedCallbacks.value = val;
|
selectedCallbacks.value = val;
|
||||||
@@ -150,6 +177,27 @@ async function load() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleSimulate() {
|
||||||
|
simulating.value = true;
|
||||||
|
try {
|
||||||
|
await simulateCallback({
|
||||||
|
sourceSystem: 'SIMULATOR',
|
||||||
|
externalMessageId: `sim-${Date.now()}`,
|
||||||
|
schemaVersion: '1.0',
|
||||||
|
eventType: simForm.value.eventType,
|
||||||
|
rawPayload: JSON.parse(simForm.value.rawPayload),
|
||||||
|
receivedAt: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
ElMessage.success('模拟事件已投递');
|
||||||
|
simDialogVisible.value = false;
|
||||||
|
load();
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error(apiErrorMessage(e, '模拟投递失败'));
|
||||||
|
} finally {
|
||||||
|
simulating.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function goDetail(id) {
|
function goDetail(id) {
|
||||||
router.push({ name: "callback-inbox-detail", params: { id: String(id) } });
|
router.push({ name: "callback-inbox-detail", params: { id: String(id) } });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user