7 changed files with 270 additions and 2 deletions
@ -0,0 +1,34 @@ |
|||||||
|
<script lang="ts" setup> |
||||||
|
import { getOnlineClientList } from '@/api/subscription/consumer' |
||||||
|
import { BasicTable, useTable } from '@/components/Table' |
||||||
|
|
||||||
|
const props = defineProps<{ |
||||||
|
consumerToken: string |
||||||
|
}>() |
||||||
|
|
||||||
|
const [register] = useTable({ |
||||||
|
api: () => getOnlineClientList(props.consumerToken), |
||||||
|
columns: [ |
||||||
|
{ |
||||||
|
title: '客户端 ID', |
||||||
|
dataIndex: 'uuid', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '客户端 IP', |
||||||
|
dataIndex: 'address', |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '最后上线时间', |
||||||
|
dataIndex: 'onlineDate', |
||||||
|
}, |
||||||
|
], |
||||||
|
bordered: true, |
||||||
|
inset: true, |
||||||
|
canResize: false, |
||||||
|
pagination: false, |
||||||
|
}) |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<BasicTable @register="register" /> |
||||||
|
</template> |
@ -0,0 +1,91 @@ |
|||||||
|
<script lang="ts" setup> |
||||||
|
import { h, ref } from 'vue' |
||||||
|
import { Popconfirm, Space, Tag } from 'ant-design-vue' |
||||||
|
import { DisconnectOutlined } from '@ant-design/icons-vue' |
||||||
|
import { useAsyncState } from '@vueuse/core' |
||||||
|
import { disSubscription, getSubscribeList } from '@/api/subscription/consumer' |
||||||
|
import { BasicTable, useTable } from '@/components/Table' |
||||||
|
import { useSystemEnumStore } from '@/store/modules/systemEnum' |
||||||
|
import { getAllProducts } from '@/api/product' |
||||||
|
import type { Product } from '@/api/subscription/consumer/types' |
||||||
|
import { noop } from '@/utils' |
||||||
|
|
||||||
|
const props = defineProps<{ consumerId: string }>() |
||||||
|
|
||||||
|
const { getSystemEnums } = useSystemEnumStore() |
||||||
|
|
||||||
|
const { state: products } = useAsyncState(getAllProducts, []) |
||||||
|
|
||||||
|
const [register, { reload }] = useTable({ |
||||||
|
api: () => getSubscribeList(props.consumerId), |
||||||
|
columns: [ |
||||||
|
{ |
||||||
|
title: '产品名称', |
||||||
|
dataIndex: 'productId', |
||||||
|
customRender({ value }) { |
||||||
|
const product = products.value.find(item => item.id === value) |
||||||
|
return product && product.productName |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: '推送消息类型', |
||||||
|
dataIndex: 'messageType', |
||||||
|
customRender({ value }) { |
||||||
|
const values = value.split(',') |
||||||
|
const types = getSystemEnums('eSubscribeMessageType') |
||||||
|
return h( |
||||||
|
Space, |
||||||
|
() => types |
||||||
|
.map(item => values.includes(item.value.toString()) ? item.label : null) |
||||||
|
.filter(Boolean) |
||||||
|
.map(name => h(Tag, () => name)), |
||||||
|
) |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
bordered: true, |
||||||
|
inset: true, |
||||||
|
canResize: false, |
||||||
|
pagination: false, |
||||||
|
actionColumn: { |
||||||
|
width: 200, |
||||||
|
title: '操作', |
||||||
|
dataIndex: 'action', |
||||||
|
fixed: 'right', |
||||||
|
}, |
||||||
|
}) |
||||||
|
|
||||||
|
const loading = ref(false) |
||||||
|
function handleDisconnect(serverSubscribeId: string) { |
||||||
|
loading.value = true |
||||||
|
disSubscription(props.consumerId, serverSubscribeId) |
||||||
|
.then(() => { |
||||||
|
reload() |
||||||
|
}) |
||||||
|
.catch(noop) |
||||||
|
.finally(() => { |
||||||
|
loading.value = false |
||||||
|
}) |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<BasicTable :api="async () => ([] as Product[])" @register="register"> |
||||||
|
<template #bodyCell="{ column, record }"> |
||||||
|
<template v-if="column.key === 'action'"> |
||||||
|
<Popconfirm |
||||||
|
title="删除消费组后,该组内的消费者都将立即停止接收消息,并会清除所有相关资源,您确定要删除吗?" |
||||||
|
ok-text="确定" |
||||||
|
cancel-text="取消" |
||||||
|
placement="left" |
||||||
|
@confirm="() => handleDisconnect(record.id)" |
||||||
|
> |
||||||
|
<a-button type="link" size="small" danger :loading="loading"> |
||||||
|
<DisconnectOutlined /> |
||||||
|
解除订阅 |
||||||
|
</a-button> |
||||||
|
</Popconfirm> |
||||||
|
</template> |
||||||
|
</template> |
||||||
|
</BasicTable> |
||||||
|
</template> |
@ -0,0 +1,2 @@ |
|||||||
|
export { default as OnlineClient } from './OnlineClient.vue' |
||||||
|
export { default as Product } from './Product.vue' |
@ -0,0 +1,96 @@ |
|||||||
|
<script lang="ts" setup> |
||||||
|
import { useAsyncState } from '@vueuse/core' |
||||||
|
import { Button, Card, Tabs } from 'ant-design-vue' |
||||||
|
import { CopyOutlined } from '@ant-design/icons-vue' |
||||||
|
import { useRoute } from 'vue-router' |
||||||
|
import { h } from 'vue' |
||||||
|
import { OnlineClient, Product } from './components' |
||||||
|
import { getConsumerDetail } from '@/api/subscription/consumer' |
||||||
|
import type { DescItem } from '@/components/Description' |
||||||
|
import { Description } from '@/components/Description' |
||||||
|
import { copyText } from '@/utils/copyTextToClipboard' |
||||||
|
|
||||||
|
const route = useRoute() |
||||||
|
const { state } = useAsyncState(() => getConsumerDetail(route.params.id as string), undefined) |
||||||
|
const schema: DescItem[] = [ |
||||||
|
{ |
||||||
|
field: 'consumerToken', |
||||||
|
label: '消费组 Token', |
||||||
|
render(value) { |
||||||
|
return h('div', [ |
||||||
|
value, |
||||||
|
h(Button, { |
||||||
|
size: 'small', |
||||||
|
type: 'link', |
||||||
|
style: { |
||||||
|
marginLeft: '5px', |
||||||
|
}, |
||||||
|
onClick: () => copyText(value), |
||||||
|
}, () => [h(CopyOutlined), '复制']), |
||||||
|
]) |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
field: 'consumerName', |
||||||
|
label: '消费组名称', |
||||||
|
}, |
||||||
|
{ |
||||||
|
field: 'tenantId', |
||||||
|
label: '企业编号', |
||||||
|
render(value) { |
||||||
|
return h('div', [ |
||||||
|
value, |
||||||
|
h(Button, { |
||||||
|
size: 'small', |
||||||
|
type: 'link', |
||||||
|
style: { |
||||||
|
marginLeft: '5px', |
||||||
|
}, |
||||||
|
onClick: () => copyText(value), |
||||||
|
}, () => [h(CopyOutlined), '复制']), |
||||||
|
]) |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
field: 'Topic', |
||||||
|
label: 'Topic', |
||||||
|
render(_, data) { |
||||||
|
const value = `$SYS/${data.tenantId}/${data.consumerToken}/status ` |
||||||
|
return h('div', [ |
||||||
|
value, |
||||||
|
h(Button, { |
||||||
|
size: 'small', |
||||||
|
type: 'link', |
||||||
|
style: { |
||||||
|
marginLeft: '5px', |
||||||
|
}, |
||||||
|
onClick: () => copyText(value), |
||||||
|
}, () => [h(CopyOutlined), '复制']), |
||||||
|
]) |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
field: 'createTime', |
||||||
|
label: '创建时间', |
||||||
|
}, |
||||||
|
] |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<div p="12px"> |
||||||
|
<Card title="基础信息"> |
||||||
|
<Description :data="state" :schema="schema" :column="1" :label-style="{ width: '140px' }" /> |
||||||
|
</Card> |
||||||
|
|
||||||
|
<Card mt="12px"> |
||||||
|
<Tabs> |
||||||
|
<Tabs.TabPane key="1" tab="在线客户端"> |
||||||
|
<OnlineClient v-if="state" :consumer-token="state.consumerToken" /> |
||||||
|
</Tabs.TabPane> |
||||||
|
<Tabs.TabPane key="2" tab="订阅产品"> |
||||||
|
<Product v-if="state" :consumer-id="state.id" /> |
||||||
|
</Tabs.TabPane> |
||||||
|
</Tabs> |
||||||
|
</Card> |
||||||
|
</div> |
||||||
|
</template> |
Loading…
Reference in new issue