feat 消息通知流水记录

This commit is contained in:
bootx
2024-02-25 01:43:43 +08:00
parent 5dd2a8a3ec
commit 0aba9ca504
5 changed files with 514 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
<template>
<basic-modal
title="查看记录"
v-bind="$attrs"
:loading="confirmLoading"
:width="modalWidth"
:visible="visible"
:mask-closable="showable"
@cancel="handleCancel"
>
<a-spin :spinning="confirmLoading">
<a-descriptions bordered title="" :column="{ md: 1, sm: 1, xs: 1 }">
<a-descriptions-item label="主键">
{{ info.id }}
</a-descriptions-item>
<a-descriptions-item label="请求次数">
{{ info.reqCount }}
</a-descriptions-item>
<a-descriptions-item label="发送类型">
<a-tag>{{ dictConvert('ClientNoticeSendType', info.type) }}</a-tag>
</a-descriptions-item>
<a-descriptions-item label="是否发送成功">
<a-tag v-if="info.success" color="green"></a-tag>
<a-tag v-else color="red"></a-tag>
</a-descriptions-item>
<a-descriptions-item label="错误信息">
{{ info.errorMsg }}
</a-descriptions-item>
<a-descriptions-item label="发送时间">
{{ info.createTime }}
</a-descriptions-item>
</a-descriptions>
</a-spin>
<template #footer>
<a-space>
<a-button key="cancel" @click="handleCancel">取消</a-button>
</a-space>
</template>
</basic-modal>
</template>
<script lang="ts" setup>
import { $ref } from 'vue/macros'
import useFormEdit from '/@/hooks/bootx/useFormEdit'
import { ClientNoticeRecord, getRecord } from './ClientNoticeTask.api'
import { BasicModal } from '/@/components/Modal'
import { useDict } from '/@/hooks/bootx/useDict'
const {
initFormEditType,
handleCancel,
search,
labelCol,
wrapperCol,
modalWidth,
title,
confirmLoading,
visible,
editable,
showable,
formEditType,
} = useFormEdit()
const { dictConvert } = useDict()
let info = $ref<ClientNoticeRecord>({})
/**
*
*/
async function init(record: ClientNoticeRecord) {
info = record
visible.value = true
confirmLoading.value = true
await getRecord(record.id).then(({ data }) => {
info = data
})
confirmLoading.value = false
}
// 获取信息
defineExpose({
init,
})
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,106 @@
<template>
<basic-drawer forceRender v-bind="$attrs" title="通道订单列表" width="60%" :visible="visible" @close="visible = false">
<vxe-toolbar ref="xToolbar" custom :refresh="{ queryMethod: queryPage }" />
<vxe-table
row-id="id"
ref="xTable"
:data="pagination.records"
:loading="loading"
:sort-config="{ remote: true, trigger: 'cell' }"
@sort-change="sortChange"
>
<vxe-column type="seq" width="60" />
<vxe-column field="reqCount" title="请求次数" />
<vxe-column field="channel" title="是否成功">
<template #default="{ row }">
<a-tag v-if="row.success" color="green"></a-tag>
<a-tag v-else color="red"></a-tag>
</template>
</vxe-column>
<vxe-column field="type" title="发送类型">
<template #default="{ row }">
<a-tag>{{ dictConvert('ClientNoticeSendType', row.type) }}</a-tag>
</template>
</vxe-column>
<vxe-column field="errorMsg" title="错误信息" max-width="200" />
<vxe-column field="createTime" title="发送时间" />
<vxe-column fixed="right" width="60" :showOverflow="false" title="操作">
<template #default="{ row }">
<span>
<a href="javascript:" @click="show(row)">查看</a>
</span>
</template>
</vxe-column>
</vxe-table>
<vxe-pager
size="medium"
:loading="loading"
:current-page="pagination.current"
:page-size="pagination.size"
:total="pagination.total"
@page-change="handleTableChange"
/>
<client-notice-record-info ref="clientNoticeRecordInfo" />
</basic-drawer>
</template>
<script setup lang="ts">
import { nextTick } from 'vue'
import { $ref } from 'vue/macros'
import useTablePage from '/@/hooks/bootx/useTablePage'
import { VxePager, VxeTable, VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
import { useMessage } from '/@/hooks/web/useMessage'
import BasicDrawer from '/@/components/Drawer/src/BasicDrawer.vue'
import { useDict } from '/@/hooks/bootx/useDict'
import { pageRecord, ClientNoticeTask } from './ClientNoticeTask.api'
import ClientNoticeRecordInfo from './ClientNoticeRecordInfo.vue'
// 使用hooks
const { handleTableChange, pageQueryResHandel, sortChange, resetQueryParams, pagination, pages, sortParam, model, loading } =
useTablePage(queryPage)
const { notification, createMessage } = useMessage()
const { dictDropDown, dictConvert } = useDict()
let visible = $ref(false)
let task = $ref<ClientNoticeTask>({})
let clientNoticeRecordInfo = $ref<any>()
const xTable = $ref<VxeTableInstance>()
const xToolbar = $ref<VxeToolbarInstance>()
nextTick(() => {
xTable?.connect(xToolbar as VxeToolbarInstance)
})
/**
* 入口
*/
function init(record: ClientNoticeTask) {
visible = true
task = record
queryPage()
}
/**
* 分页查询
*/
function queryPage() {
loading.value = true
pageRecord({
taskId: task.id,
...sortParam,
}).then(({ data }) => {
pageQueryResHandel(data)
})
}
/**
* 查看
*/
function show(record) {
clientNoticeRecordInfo.init(record)
}
defineExpose({
init,
})
</script>
<style scoped lang="less"></style>

View File

@@ -0,0 +1,90 @@
import { defHttp } from '/@/utils/http/axios'
import { PageResult, Result } from '/#/axios'
import { BaseEntity } from '/#/web'
/**
* 重新发送消息通知
*/
export function resetSendNotice(taskId){
return defHttp.post<Result>({
url: '/task/notice/resetSend',
method: 'post',
params: { taskId },
})
}
/**
* 任务分页
*/
export function page(params) {
return defHttp.get<Result<PageResult<ClientNoticeTask[]>>>({
url: '/task/notice/page',
method: 'get',
params,
})
}
/**
* 获取单条
*/
export function get(id) {
return defHttp.get<Result<ClientNoticeTask>>({
url: '/task/notice/findById',
params: { id },
})
}
/**
* 记录分页
*/
export function pageRecord(params) {
return defHttp.get<Result<PageResult<ClientNoticeRecord[]>>>({
url: '/task/notice/record/page',
method: 'get',
params,
})
}
/**
* 记录单条
*/
export function getRecord(id) {
return defHttp.get<Result<ClientNoticeRecord>>({
url: '/task/notice/record/findById',
params: { id },
})
}
/**
* 消息通知任务
*/
export interface ClientNoticeTask extends BaseEntity {
// 本地订单ID
orderId?: number
// 回调类型
type?: string
// 消息内容
content?: string
// 是否发送成功
success?: boolean
// 发送次数
sendCount?: number
// 发送地址
url?: string
// 最后发送时间
latestTime?: string
}
/**
* 消息通知记录
*/
export interface ClientNoticeRecord extends BaseEntity {
// 任务ID
taskId?: string
// 请求次数
reqCount?: number
// 发送是否成功
success?: boolean
// 错误信息
errorMsg?: string
}

View File

@@ -0,0 +1,93 @@
<template>
<basic-modal
title="查看通知任务"
v-bind="$attrs"
:loading="confirmLoading"
:width="modalWidth"
:visible="visible"
:mask-closable="showable"
@cancel="handleCancel"
>
<a-spin :spinning="confirmLoading">
<a-descriptions title="" :column="{ md: 1, sm: 1, xs: 1 }">
<a-descriptions-item label="主键">
<a-tag>{{ task.id }}</a-tag>
</a-descriptions-item>
<a-descriptions-item label="本地订单ID">
<a-tag>{{ task.orderId }}</a-tag>
</a-descriptions-item>
<a-descriptions-item label="回调类型">
<a-tag>{{ dictConvert('ClientNoticeType', task.type) }}</a-tag>
</a-descriptions-item>
<a-descriptions-item label="消息内容">
<json-preview :data="JSON.parse(task.content || '{}')" />
</a-descriptions-item>
<a-descriptions-item label="是否发送成功">
<a-tag v-if="task.success" color="green"></a-tag>
<a-tag v-else color="red"></a-tag>
</a-descriptions-item>
<a-descriptions-item label="发送次数">
{{ task.sendCount }}
</a-descriptions-item>
<a-descriptions-item label="发送地址">
{{ task.url }}
</a-descriptions-item>
<a-descriptions-item label="最后发送时间">
{{ task.latestTime }}
</a-descriptions-item>
<a-descriptions-item label="创建时间">
{{ task.createTime }}
</a-descriptions-item>
</a-descriptions>
</a-spin>
<template #footer>
<a-space>
<a-button key="cancel" @click="handleCancel">取消</a-button>
</a-space>
</template>
</basic-modal>
</template>
<script lang="ts" setup>
import { $ref } from 'vue/macros'
import useFormEdit from '/@/hooks/bootx/useFormEdit'
import { get, ClientNoticeTask } from './ClientNoticeTask.api'
import { BasicModal } from '/@/components/Modal'
import { useDict } from '/@/hooks/bootx/useDict'
import JsonPreview from '/@/components/CodeEditor/src/json-preview/JsonPreview.vue'
const {
initFormEditType,
handleCancel,
search,
labelCol,
wrapperCol,
modalWidth,
title,
confirmLoading,
visible,
editable,
showable,
formEditType,
} = useFormEdit()
const { dictConvert } = useDict()
let task = $ref<ClientNoticeTask>({})
/**
*
*/
async function init(record: ClientNoticeTask) {
task = record
visible.value = true
confirmLoading.value = true
await get(record.id).then(({ data }) => {
task = data
})
confirmLoading.value = false
}
// 获取信息
defineExpose({
init,
})
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,141 @@
<template>
<div>
<div class="m-3 p-3 pt-5 bg-white">
<b-query :query-params="model.queryParam" :fields="fields" @query="queryPage" @reset="resetQueryParams" />
</div>
<div class="m-3 p-3 bg-white">
<vxe-toolbar ref="xToolbar" custom :refresh="{ queryMethod: queryPage }" />
<vxe-table
row-id="id"
ref="xTable"
:data="pagination.records"
:loading="loading"
:sort-config="{ remote: true, trigger: 'cell' }"
@sort-change="sortChange"
>
<vxe-column type="seq" title="序号" width="60" />
<vxe-column field="orderId" title="本地订单ID" width="170" />
<vxe-column field="type" title="消息类型">
<template #default="{ row }">
<a-tag>{{ dictConvert('ClientNoticeType', row.type) }}</a-tag>
</template>
</vxe-column>
<vxe-column field="success" title="发送成功">
<template #default="{ row }">
<a-tag v-if="row.success" color="green"></a-tag>
<a-tag v-else color="red"></a-tag>
</template>
</vxe-column>
<vxe-column field="sendCount" title="发送次数" sortable />
<vxe-column field="latestTime" title="最后发送时间" sortable />
<vxe-column field="url" title="发送地址" />
<vxe-column field="createTime" title="创建时间" sortable />
<vxe-column fixed="right" width="180" :showOverflow="false" title="操作">
<template #default="{ row }">
<a-link @click="show(row)">查看</a-link>
<a-divider type="vertical" />
<a-link @click="showRecord(row)">记录列表</a-link>
<a-divider type="vertical" />
<a-link @click="resetSend(row)">重发</a-link>
</template>
</vxe-column>
</vxe-table>
<vxe-pager
size="medium"
:loading="loading"
:current-page="pagination.current"
:page-size="pagination.size"
:total="pagination.total"
@page-change="handleTableChange"
/>
</div>
<client-notice-task-info ref="clientNoticeTaskInfo" />
<client-notice-record-list ref="clientNoticeRecordList" />
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted } from 'vue'
import { $ref } from 'vue/macros'
import { ClientNoticeTask, page, resetSendNotice } from './ClientNoticeTask.api'
import useTablePage from '/@/hooks/bootx/useTablePage'
import BQuery from '/@/components/Bootx/Query/BQuery.vue'
import { useMessage } from '/@/hooks/web/useMessage'
import { LIST, QueryField, STRING } from '/@/components/Bootx/Query/Query'
import { useDict } from '/@/hooks/bootx/useDict'
import { VxeTableInstance, VxeToolbarInstance, VxePager, VxeTable, VxeToolbar } from 'vxe-table'
import ALink from '/@/components/Link/Link.vue'
import ClientNoticeRecordList from './ClientNoticeRecordList.vue'
import ClientNoticeTaskInfo from '/@/views/payment/task/notice/ClientNoticeTaskInfo.vue'
// 使用hooks
const { handleTableChange, pageQueryResHandel, sortChange, resetQueryParams, pagination, pages, sortParam, model, loading } =
useTablePage(queryPage)
const { notification, createMessage, createConfirm } = useMessage()
const { dictConvert, dictDropDown } = useDict()
// 查询条件
const fields = computed(() => {
return [{ field: 'orderId', type: STRING, name: '本地订单ID', placeholder: '请输入完整本地订单ID' }] as QueryField[]
})
const clientNoticeRecordList = $ref<any>()
const clientNoticeTaskInfo = $ref<any>()
const xTable = $ref<VxeTableInstance>()
const xToolbar = $ref<VxeToolbarInstance>()
onMounted(() => {
vxeBind()
queryPage()
})
function vxeBind() {
xTable?.connect(xToolbar as VxeToolbarInstance)
}
/**
* 分页查询
*/
function queryPage() {
loading.value = true
page({
...model.queryParam,
...pages,
...sortParam,
}).then(({ data }) => {
pageQueryResHandel(data)
})
}
/**
* 重新发送消息
*/
function resetSend(record: ClientNoticeTask) {
createConfirm({
iconType: 'warning',
title: '警告',
content: '是否重新发送通知消息?',
onOk: () => {
loading.value = true
resetSendNotice(record.id).then(({ data }) => {
createMessage.success('请求已发送')
queryPage()
})
},
})
}
/**
* 查看
*/
function show(record) {
clientNoticeTaskInfo.init(record)
}
/**
* 查看记录
*/
function showRecord(record) {
clientNoticeRecordList.init(record)
}
</script>
<style lang="less" scoped></style>