feat(sj_1.0.0): 死信任务详情完成

This commit is contained in:
opensnail 2024-04-30 12:28:11 +08:00
parent 22e2c22b43
commit 2705e22f52
9 changed files with 167 additions and 178 deletions

View File

@ -53,6 +53,7 @@ function refresh() {
</template>
{{ $t('common.add') }}
</NButton>
<slot name="addAfter"></slot>
<NPopconfirm v-if="showDelete" @positive-click="batchDelete">
<template #trigger>
<NButton size="small" ghost type="error" :disabled="disabledDelete">

View File

@ -18,7 +18,9 @@ const local: App.I18n.Schema = {
confirm: 'Confirm',
save: 'Save',
delete: 'Delete',
rollback: 'RollBACK',
rollback: 'Rollback',
batchRollback: 'Batch Rollback',
rollbackSuccess: 'Rollback Success',
deleteSuccess: 'Delete Success',
confirmDelete: 'Are you sure you want to delete?',
edit: 'Edit',
@ -735,6 +737,7 @@ const local: App.I18n.Schema = {
},
retryDeadLetter: {
title: 'RetryDeadLetter List',
detail: 'RetryDeadLetter Detail',
uniqueId: 'UniqueId',
groupName: 'Group name',
sceneName: 'Scene name',

View File

@ -19,6 +19,8 @@ const local: App.I18n.Schema = {
save: '保存',
delete: '删除',
rollback: '回滚',
batchRollback: '批量回滚',
rollbackSuccess: '回滚成功',
deleteSuccess: '删除成功',
confirmDelete: '确认删除吗?',
edit: '编辑',
@ -731,6 +733,7 @@ const local: App.I18n.Schema = {
},
retryDeadLetter: {
title: '死信任务列表',
detail: '死信任务详情',
uniqueId: 'UniqueId',
groupName: '组名',
sceneName: '场景名称',

View File

@ -9,8 +9,15 @@ export function fetchGetRetryDeadLetterPageList(params?: Api.RetryDeadLetter.Ret
});
}
export function fetchGetRetryDeadLetterById(id: string, groupName: string) {
return request({
url: `/retry-dead-letter/${id}?groupName=${groupName}`,
method: 'get'
});
}
/** add retry scene */
export function fetchRollbackRetryDeadLetter(data: { id: string | undefined | null }) {
export function fetchRollbackRetryDeadLetter(data: Api.RetryDeadLetter.BatchDeadLetter) {
return request<boolean>({
url: '/retry-dead-letter/batch/rollback',
method: 'post',
@ -19,7 +26,7 @@ export function fetchRollbackRetryDeadLetter(data: { id: string | undefined | nu
}
/** edit retry scene */
export function fetchDeleteRetryDeadLetter(data: { id: string | undefined | null }) {
export function fetchDeleteRetryDeadLetter(data: Api.RetryDeadLetter.BatchDeadLetter) {
return request<boolean>({
url: '/retry-dead-letter/batch',
method: 'delete',

11
src/typings/api.d.ts vendored
View File

@ -655,7 +655,7 @@ declare namespace Api {
/** deadLetter */
type DeadLetter = Common.CommonRecord<{
/** id */
id?: string;
id?: number;
/** UniqueId */
uniqueId?: string;
/** 组名称 */
@ -670,6 +670,10 @@ declare namespace Api {
taskType?: TaskType;
/** 创建时间 * */
createDt?: string;
/** 执行器名称 */
executorName: string;
/** 执行方法参数 */
argsStr: string;
}>;
/** deadLetter search params */
@ -683,6 +687,11 @@ declare namespace Api {
/** DeadLetter list */
type RetryDeadLetterList = Common.PaginatingQueryRecord<DeadLetter>;
type BatchDeadLetter = Common.CommonRecord<{
groupName?: string;
ids: number[];
}>;
}
/**

View File

@ -265,6 +265,8 @@ declare namespace App {
save: string;
delete: string;
rollback: string;
batchRollback: string;
rollbackSuccess: string;
deleteSuccess: string;
confirmDelete: string;
edit: string;
@ -879,6 +881,7 @@ declare namespace App {
};
retryDeadLetter: {
title: string;
detail: string;
uniqueId: string;
groupName: string;
sceneName: string;

View File

@ -1,13 +1,25 @@
<script setup lang="tsx">
import { NButton, NPopconfirm } from 'naive-ui';
import { fetchGetRetryDeadLetterPageList } from '@/service/api';
import { NButton, NPopconfirm, NTag } from 'naive-ui';
import { ref } from 'vue';
import {
fetchDeleteRetryDeadLetter,
fetchGetRetryDeadLetterById,
fetchGetRetryDeadLetterPageList,
fetchRollbackRetryDeadLetter
} from '@/service/api';
import { $t } from '@/locales';
import { useAppStore } from '@/store/modules/app';
import { useTable, useTableOperate } from '@/hooks/common/table';
import RetryDeadLetterOperateDrawer from './modules/dead-letter-operate-drawer.vue';
import { retryTaskTypeRecord } from '@/constants/business';
import { tagColor } from '@/utils/common';
import RetryDeadLetterSearch from './modules/dead-letter-search.vue';
import RetryDeadLetterDetailDrawer from './modules/retry-letter-detail-drawer.vue';
const appStore = useAppStore();
const detailData = ref();
const detailVisible = defineModel<boolean>('detailVisible', {
default: false
});
const { columns, columnChecks, data, getData, loading, mobilePagination, searchParams, resetSearchParams } = useTable({
apiFn: fetchGetRetryDeadLetterPageList,
@ -33,7 +45,19 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
key: 'uniqueId',
title: $t('page.retryDeadLetter.uniqueId'),
align: 'left',
minWidth: 120
minWidth: 120,
render: row => {
async function showDetailDrawer() {
await loadRetryInfo(row);
detailVisible.value = true;
}
return (
<n-button text tag="a" type="primary" onClick={showDetailDrawer} class="ws-normal">
{row.uniqueId}
</n-button>
);
}
},
{
key: 'groupName',
@ -63,7 +87,15 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
key: 'taskType',
title: $t('page.retryDeadLetter.taskType'),
align: 'left',
minWidth: 120
minWidth: 120,
render: row => {
if (row.taskType === null) {
return null;
}
const label = $t(retryTaskTypeRecord[row.taskType!]);
return <NTag type={tagColor(row.taskType!)}>{label}</NTag>;
}
},
{
key: 'createDt',
@ -78,10 +110,10 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
width: 130,
render: row => (
<div class="flex-center gap-8px">
<NButton type="primary" ghost size="small" onClick={() => rollback(row.id!)}>
<NButton type="primary" ghost size="small" onClick={() => rollback(row)}>
{$t('common.rollback')}
</NButton>
<NPopconfirm onPositiveClick={() => handleDelete(row.id!)}>
<NPopconfirm onPositiveClick={() => handleDelete(row)}>
{{
default: () => $t('common.confirmDelete'),
trigger: () => (
@ -97,34 +129,47 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
]
});
const {
drawerVisible,
operateType,
editingData,
handleAdd,
handleEdit,
checkedRowKeys,
onBatchDeleted,
onDeleted
// closeDrawer
} = useTableOperate(data, getData);
const { handleAdd, checkedRowKeys } = useTableOperate(data, getData);
async function handleBatchDelete() {
// request
console.log(checkedRowKeys.value);
onBatchDeleted();
const { error } = await fetchDeleteRetryDeadLetter({
ids: checkedRowKeys.value as any[],
groupName: searchParams.groupName!
});
if (error) return;
window.$message?.success($t('common.deleteSuccess'));
getData();
}
function handleDelete(id: string) {
async function handleBatchRollback() {
// request
console.log(id);
onDeleted();
const { error } = await fetchRollbackRetryDeadLetter({
ids: checkedRowKeys.value as any[],
groupName: searchParams.groupName!
});
if (error) return;
window.$message?.success($t('common.rollbackSuccess'));
getData();
}
function rollback(id: string) {
handleEdit(id);
async function handleDelete(row: Api.RetryDeadLetter.DeadLetter) {
const { error } = await fetchDeleteRetryDeadLetter({ ids: [row.id!], groupName: row.groupName! });
if (error) return;
window.$message?.success($t('common.deleteSuccess'));
getData();
}
async function loadRetryInfo(row: Api.RetryDeadLetter.DeadLetter) {
const res = await fetchGetRetryDeadLetterById(row.id!, row.groupName!);
detailData.value = (res.data as Api.RetryDeadLetter.DeadLetter) || null;
}
async function rollback(row: Api.RetryDeadLetter.DeadLetter) {
const { error } = await fetchRollbackRetryDeadLetter({ ids: [row.id!], groupName: row.groupName! });
if (error) return;
window.$message?.success($t('common.rollbackSuccess'));
getData();
}
</script>
@ -146,7 +191,16 @@ function rollback(id: string) {
@add="handleAdd"
@delete="handleBatchDelete"
@refresh="getData"
/>
>
<template #addAfter>
<NButton size="small" ghost type="primary" @click="handleBatchRollback">
<template #icon>
<IconTdesignRollback class="text-icon" />
</template>
{{ $t('common.batchRollback') }}
</NButton>
</template>
</TableHeaderOperation>
</template>
<NDataTable
v-model:checked-row-keys="checkedRowKeys"
@ -160,12 +214,7 @@ function rollback(id: string) {
:pagination="mobilePagination"
class="sm:h-full"
/>
<RetryDeadLetterOperateDrawer
v-model:visible="drawerVisible"
:operate-type="operateType"
:row-data="editingData"
@submitted="getData"
/>
<RetryDeadLetterDetailDrawer v-model:visible="detailVisible" :row-data="detailData" />
</NCard>
</div>
</template>

View File

@ -1,140 +0,0 @@
<script setup lang="ts">
import { computed, reactive, watch } from 'vue';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import OperateDrawer from '@/components/common/operate-drawer.vue';
import { $t } from '@/locales';
import { fetchDeleteRetryDeadLetter, fetchRollbackRetryDeadLetter } from '@/service/api';
defineOptions({
name: 'RetryDeadLetterOperateDrawer'
});
interface Props {
/** the type of operation */
operateType: NaiveUI.TableOperateType;
/** the edit row data */
rowData?: Api.RetryDeadLetter.DeadLetter | null;
}
const props = defineProps<Props>();
interface Emits {
(e: 'submitted'): void;
}
const emit = defineEmits<Emits>();
const visible = defineModel<boolean>('visible', {
default: false
});
const { formRef, validate, restoreValidation } = useNaiveForm();
const { defaultRequiredRule } = useFormRules();
const title = computed(() => {
const titles: Record<NaiveUI.TableOperateType, string> = {
add: $t('page.retryScene.addScene'),
edit: $t('page.retryScene.editScene')
};
return titles[props.operateType];
});
type Model = Pick<
Api.RetryDeadLetter.RetryDeadLetterSearchParams,
'id' | 'uniqueId' | 'groupName' | 'sceneName' | 'idempotentId' | 'bizNo' | 'taskType' | 'createDt'
>;
const model: Model = reactive(createDefaultModel());
function createDefaultModel(): Model {
return {
id: '',
uniqueId: '',
groupName: '',
sceneName: '',
idempotentId: '',
bizNo: '',
taskType: 1,
createDt: ''
};
}
type RuleKey = Extract<
keyof Model,
'id' | 'groupName' | 'sceneName' | 'idempotentId' | 'bizNo' | 'taskType' | 'createDt'
>;
const rules = {
id: [defaultRequiredRule],
groupName: [defaultRequiredRule],
sceneName: [
defaultRequiredRule,
{
required: true,
pattern: /^[A-Za-z0-9_]{1,64}$/,
trigger: 'change',
message: $t('page.retryScene.form.sceneName2')
}
],
idempotentId: [defaultRequiredRule],
bizNo: [defaultRequiredRule],
taskType: [defaultRequiredRule],
createDt: [defaultRequiredRule]
} satisfies Record<RuleKey, App.Global.FormRule[]>;
function handleUpdateModelWhenEdit() {
if (props.operateType === 'add') {
Object.assign(model, createDefaultModel());
return;
}
if (props.operateType === 'edit' && props.rowData) {
Object.assign(model, props.rowData);
}
}
function closeDrawer() {
visible.value = false;
}
async function handleSubmit() {
await validate();
// request
if (props.operateType === 'edit') {
const { id } = model;
const { error } = await fetchRollbackRetryDeadLetter({ id });
if (error) return;
}
if (props.operateType === 'add') {
const { id } = model;
const { error } = await fetchDeleteRetryDeadLetter({ id });
if (error) return;
}
window.$message?.success($t('common.updateSuccess'));
closeDrawer();
emit('submitted');
}
watch(visible, () => {
if (visible.value) {
handleUpdateModelWhenEdit();
restoreValidation();
}
});
</script>
<template>
<OperateDrawer v-model="visible" :title="title" @handle-submit="handleSubmit">
<NForm ref="formRef" :model="model" :rules="rules"></NForm>
<template #footer>
<NSpace :size="16">
<NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
<NButton type="primary" @click="handleSubmit">{{ $t('common.save') }}</NButton>
</NSpace>
</template>
</OperateDrawer>
</template>
<style scoped></style>

View File

@ -0,0 +1,54 @@
<script setup lang="ts">
import { watch } from 'vue';
import { $t } from '@/locales';
import { tagColor } from '@/utils/common';
import { retryTaskTypeRecord } from '@/constants/business';
defineOptions({
name: 'RetryDeadLetterDetailDrawer'
});
interface Props {
/** row data */
rowData?: Api.RetryDeadLetter.DeadLetter | null;
}
const visible = defineModel<boolean>('visible', {
default: false
});
const props = defineProps<Props>();
watch(
() => props.rowData,
() => {
console.log(props.rowData);
},
{ immediate: true }
);
</script>
<template>
<OperateDrawer v-model="visible" :title="$t('page.retryDeadLetter.detail')">
<NDescriptions label-placement="top" bordered :column="3">
<NDescriptionsItem :label="$t('page.retryTask.uniqueId')" :span="3">
{{ rowData?.uniqueId }}
</NDescriptionsItem>
<NDescriptionsItem :label="$t('page.retryTask.groupName')" :span="3">{{ rowData?.groupName }}</NDescriptionsItem>
<NDescriptionsItem :label="$t('page.retryTask.sceneName')" :span="3">{{ rowData?.sceneName }}</NDescriptionsItem>
<NDescriptionsItem :label="$t('page.retryTask.taskType')" :span="1">
<NTag :type="tagColor(rowData?.taskType!)">{{ $t(retryTaskTypeRecord[rowData?.taskType!]) }}</NTag>
</NDescriptionsItem>
<NDescriptionsItem :label="$t('page.retryTask.bizNo')" :span="2">{{ rowData?.bizNo }}</NDescriptionsItem>
<NDescriptionsItem :label="$t('page.retryTask.idempotentId')" :span="3">
{{ rowData?.idempotentId }}
</NDescriptionsItem>
<NDescriptionsItem :label="$t('page.retryTask.executorName')" :span="3">
{{ rowData?.executorName }}
</NDescriptionsItem>
<NDescriptionsItem :label="$t('page.retryTask.argsStr')" :span="3">{{ rowData?.argsStr }}</NDescriptionsItem>
<NDescriptionsItem :label="$t('common.createDt')" :span="3">{{ rowData?.createDt }}</NDescriptionsItem>
</NDescriptions>
</OperateDrawer>
</template>
<style scoped></style>