Merge branch 'master' into preview

This commit is contained in:
xlsea 2024-11-18 09:30:13 +08:00
commit 32c324df5f
6 changed files with 100 additions and 9 deletions

2
.env
View File

@ -4,7 +4,7 @@ VITE_APP_TITLE=Snail Job
VITE_APP_DESC=A flexible, reliable, and fast platform for distributed task retry and distributed task scheduling. VITE_APP_DESC=A flexible, reliable, and fast platform for distributed task retry and distributed task scheduling.
VITE_APP_VERSION=1.2.0-beta2 VITE_APP_VERSION=1.2.0
VITE_APP_DEFAULT_TOKEN=SJ_Wyz3dmsdbDOkDujOTSSoBjGQP1BMsVnj VITE_APP_DEFAULT_TOKEN=SJ_Wyz3dmsdbDOkDujOTSSoBjGQP1BMsVnj

View File

@ -4,6 +4,7 @@ import { NButton, NCode, NTag } from 'naive-ui';
import hljs from 'highlight.js/lib/core'; import hljs from 'highlight.js/lib/core';
import json from 'highlight.js/lib/languages/json'; import json from 'highlight.js/lib/languages/json';
import { ref, render } from 'vue'; import { ref, render } from 'vue';
import dayjs from 'dayjs';
import { taskStatusRecord, taskStatusRecordOptions } from '@/constants/business'; import { taskStatusRecord, taskStatusRecordOptions } from '@/constants/business';
import { $t } from '@/locales'; import { $t } from '@/locales';
import { isNotNull, parseArgsJson, translateOptions } from '@/utils/common'; import { isNotNull, parseArgsJson, translateOptions } from '@/utils/common';
@ -251,6 +252,18 @@ const { columns, searchParams, columnChecks, data, getData, loading, mobilePagin
title: $t('page.jobBatch.jobTask.createDt'), title: $t('page.jobBatch.jobTask.createDt'),
align: 'left', align: 'left',
minWidth: 130 minWidth: 130
},
{
key: 'duration',
title: $t('page.jobBatch.duration'),
align: 'center',
width: 120,
render: row => {
if (row.taskStatus === 3) {
return Math.round(dayjs(row.updateDt).diff(dayjs(row.createDt)) / 1000);
}
return null;
}
} }
] ]
}); });

View File

@ -125,7 +125,7 @@ declare namespace Api {
interface LoginToken { interface LoginToken {
id: string; id: string;
mode: string; mode: string;
role: String; role: string;
token: string; token: string;
refreshToken: string; refreshToken: string;
createDt: string; createDt: string;
@ -934,7 +934,7 @@ declare namespace Api {
>; >;
type ExportWorkflow = Common.CommonRecord<{ type ExportWorkflow = Common.CommonRecord<{
workflowIds: String[]; workflowIds: string[];
}> & }> &
WorkflowSearchParams; WorkflowSearchParams;
@ -1072,6 +1072,8 @@ declare namespace Api {
children: JobTaskTree[]; children: JobTaskTree[];
/** 是否存在下级 */ /** 是否存在下级 */
isLeaf: boolean; isLeaf: boolean;
/** 执行时长(virtual) */
duration?: number;
}>; }>;
type JobTaskTree = { type JobTaskTree = {

View File

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue'; import { computed, reactive, ref, watch } from 'vue';
import { useClipboard } from '@vueuse/core';
import { useFormRules, useNaiveForm } from '@/hooks/common/form'; import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { $t } from '@/locales'; import { $t } from '@/locales';
import { translateOptions, translateOptions2 } from '@/utils/common'; import { translateOptions, translateOptions2 } from '@/utils/common';
@ -29,6 +30,7 @@ const visible = defineModel<boolean>('visible', {
default: false default: false
}); });
const { copy, isSupported } = useClipboard();
const { formRef, validate, restoreValidation } = useNaiveForm(); const { formRef, validate, restoreValidation } = useNaiveForm();
const { defaultRequiredRule } = useFormRules(); const { defaultRequiredRule } = useFormRules();
@ -160,6 +162,20 @@ watch(visible, () => {
restoreValidation(); restoreValidation();
} }
}); });
async function handleCopy(source: string) {
if (!isSupported) {
window.$message?.error('您的浏览器不支持 Clipboard API');
return;
}
if (!source) {
return;
}
await copy(source);
window.$message?.success('复制成功');
}
</script> </script>
<template> <template>
@ -196,9 +212,17 @@ watch(visible, () => {
:placeholder="$t('page.groupConfig.form.token')" :placeholder="$t('page.groupConfig.form.token')"
:disabled="props.operateType === 'edit'" :disabled="props.operateType === 'edit'"
/> />
<NTooltip trigger="hover"> <NTooltip v-if="props.operateType === 'edit'" trigger="hover">
<template #trigger> <template #trigger>
<NButton type="default" ghost :disabled="props.operateType === 'edit'" @click="setToken"> <NButton type="default" ghost @click="handleCopy(model.token)">
<icon-ic:round-content-copy class="text-icon" />
</NButton>
</template>
复制
</NTooltip>
<NTooltip v-else trigger="hover">
<template #trigger>
<NButton type="default" ghost @click="setToken">
<icon-ic-round-refresh class="text-icon" /> <icon-ic-round-refresh class="text-icon" />
</NButton> </NButton>
</template> </template>

View File

@ -1,6 +1,7 @@
<script setup lang="tsx"> <script setup lang="tsx">
import { NButton, NPopconfirm } from 'naive-ui'; import { NButton, NPopconfirm, NPopover } from 'naive-ui';
import { ref } from 'vue'; import { ref } from 'vue';
import { useClipboard } from '@vueuse/core';
import { fetchDeleteNamespace, fetchGetNamespaceList } from '@/service/api'; import { fetchDeleteNamespace, fetchGetNamespaceList } from '@/service/api';
import { $t } from '@/locales'; import { $t } from '@/locales';
import { useAppStore } from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
@ -14,12 +15,27 @@ import NamespaceSearch from './modules/namespace-search.vue';
const appStore = useAppStore(); const appStore = useAppStore();
const authStore = useAuthStore(); const authStore = useAuthStore();
const namespaceId = ref<string>(localStg.get('namespaceId')!); const namespaceId = ref<string>(localStg.get('namespaceId')!);
const { copy, isSupported } = useClipboard();
const handleChange = (uniqueId: string) => { const handleChange = (uniqueId: string) => {
namespaceId.value = uniqueId; namespaceId.value = uniqueId;
authStore.setNamespaceId(uniqueId); authStore.setNamespaceId(uniqueId);
}; };
async function handleCopy(source: string) {
if (!isSupported) {
window.$message?.error('您的浏览器不支持 Clipboard API');
return;
}
if (!source) {
return;
}
await copy(source);
window.$message?.success('复制成功');
}
const { columns, columnChecks, data, getData, loading, mobilePagination, searchParams, resetSearchParams } = useTable({ const { columns, columnChecks, data, getData, loading, mobilePagination, searchParams, resetSearchParams } = useTable({
apiFn: fetchGetNamespaceList, apiFn: fetchGetNamespaceList,
apiParams: { apiParams: {
@ -59,7 +75,19 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
key: 'uniqueId', key: 'uniqueId',
title: $t('page.namespace.uniqueId'), title: $t('page.namespace.uniqueId'),
align: 'left', align: 'left',
width: 180 width: 180,
render: row => (
<NPopover>
{{
trigger: () => (
<NButton text type="primary" onClick={() => handleCopy(row.uniqueId)}>
{row.uniqueId}
</NButton>
),
default: () => <span>点击复制</span>
}}
</NPopover>
)
}, },
{ {
key: 'createDt', key: 'createDt',

View File

@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, reactive, watch } from 'vue'; import { computed, reactive, watch } from 'vue';
import { nanoid } from '@sa/utils'; import { nanoid } from '@sa/utils';
import { useClipboard } from '@vueuse/core';
import { useFormRules, useNaiveForm } from '@/hooks/common/form'; import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import OperateDrawer from '@/components/common/operate-drawer.vue'; import OperateDrawer from '@/components/common/operate-drawer.vue';
import { $t } from '@/locales'; import { $t } from '@/locales';
@ -26,6 +27,7 @@ interface Emits {
const emit = defineEmits<Emits>(); const emit = defineEmits<Emits>();
const { copy, isSupported } = useClipboard();
const authStore = useAuthStore(); const authStore = useAuthStore();
const visible = defineModel<boolean>('visible', { const visible = defineModel<boolean>('visible', {
default: false default: false
@ -111,6 +113,20 @@ watch(visible, () => {
restoreValidation(); restoreValidation();
} }
}); });
async function handleCopy(source: string) {
if (!isSupported) {
window.$message?.error('您的浏览器不支持 Clipboard API');
return;
}
if (!source) {
return;
}
await copy(source);
window.$message?.success('复制成功');
}
</script> </script>
<template> <template>
@ -123,9 +139,17 @@ watch(visible, () => {
:disabled="props.operateType === 'edit'" :disabled="props.operateType === 'edit'"
:placeholder="$t('page.namespace.form.uniqueId')" :placeholder="$t('page.namespace.form.uniqueId')"
/> />
<NTooltip trigger="hover"> <NTooltip v-if="props.operateType === 'edit'" trigger="hover">
<template #trigger> <template #trigger>
<NButton type="default" ghost :disabled="props.operateType === 'edit'" @click="setUniqueId"> <NButton type="default" ghost @click="handleCopy(model.uniqueId)">
<icon-ic:round-content-copy class="text-icon" />
</NButton>
</template>
复制
</NTooltip>
<NTooltip v-else trigger="hover">
<template #trigger>
<NButton type="default" ghost @click="setUniqueId">
<icon-ic-round-refresh class="text-icon" /> <icon-ic-round-refresh class="text-icon" />
</NButton> </NButton>
</template> </template>