Browse Source

feat: 消费组详情

main
刘凯 1 year ago
parent
commit
1f9f510f3f
  1. 35
      src/api/subscription/consumer/index.ts
  2. 7
      src/api/subscription/consumer/types.ts
  3. 34
      src/views/subscription/consumer/components/OnlineClient.vue
  4. 91
      src/views/subscription/consumer/components/Product.vue
  5. 2
      src/views/subscription/consumer/components/index.ts
  6. 96
      src/views/subscription/consumer/detail.vue
  7. 7
      src/views/subscription/consumer/index.vue

35
src/api/subscription/consumer/index.ts

@ -1,4 +1,4 @@
import type { Consumer, GetConsumerListParams } from './types'
import type { Consumer, GetConsumerListParams, Product } from './types'
import { defHttp } from '@/utils/http/axios'
export function getConsumerList(params: GetConsumerListParams) {
@ -27,3 +27,36 @@ export function deleteConsumer(id: string) {
url: `/server/consumer/remove?id=${id}`,
})
}
export function getConsumerDetail(id: string) {
return defHttp.get<Consumer>({
url: '/server/consumer/detail',
params: {
id,
},
})
}
export function getOnlineClientList(consumerToken: string) {
return defHttp.get({
url: '/server/client/list',
params: {
consumerToken,
},
})
}
export function getSubscribeList(consumerId: string) {
return defHttp.get<Product[]>({
url: '/server/consumer/subscribeList',
params: {
consumerId,
},
})
}
export function disSubscription(consumerId: string, serverSubscribeId: string) {
return defHttp.post({
url: `/server/consumer/unsubscription?consumerId=${consumerId}&serverSubscribeId=${serverSubscribeId}`,
})
}

7
src/api/subscription/consumer/types.ts

@ -9,3 +9,10 @@ export interface Consumer {
createTime: string
subscribes: string
}
export interface Product {
id: string
messageType: string
productId: string
tenantId: string
}

34
src/views/subscription/consumer/components/OnlineClient.vue

@ -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>

91
src/views/subscription/consumer/components/Product.vue

@ -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>

2
src/views/subscription/consumer/components/index.ts

@ -0,0 +1,2 @@
export { default as OnlineClient } from './OnlineClient.vue'
export { default as Product } from './Product.vue'

96
src/views/subscription/consumer/detail.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>

7
src/views/subscription/consumer/index.vue

@ -24,7 +24,7 @@ const [register, { reload }] = useTable({
isTreeTable: true,
useSearchForm: true,
actionColumn: {
width: 160,
width: 220,
title: '操作',
dataIndex: 'action',
fixed: 'right',
@ -55,6 +55,11 @@ async function handleDelete(id: string) {
<template v-if="column.key === 'action'">
<TableAction
:actions="[
{
icon: 'i-ant-design:file-search-outlined',
label: '详情',
onClick: () => $router.push(`/subscription/consumer/detail/${record.id}`),
},
{
icon: 'i-ant-design:edit-outlined',
label: '修改',

Loading…
Cancel
Save