merge(sj_dev): 合并 sj_1.0.0_beta3

This commit is contained in:
xlsea 2024-05-31 11:08:08 +08:00
commit 9341f5345c
17 changed files with 180 additions and 269 deletions

1
.gitignore vendored
View File

@ -36,3 +36,4 @@ yarn.lock
src/typings/elegant-router.d.ts
src/typings/components.d.ts
src/router/elegant/transform.ts

View File

@ -41,6 +41,9 @@ importers:
'@sa/utils':
specifier: workspace:*
version: link:packages/utils
'@sa/workflow':
specifier: workspace:*
version: link:packages/work-flow
'@vueuse/core':
specifier: 10.9.0
version: 10.9.0(vue@3.4.27(typescript@5.4.5))
@ -291,6 +294,8 @@ importers:
specifier: 4.2.2
version: 4.2.2
packages/work-flow: {}
packages:
'@ampproject/remapping@2.3.0':
@ -4746,6 +4751,17 @@ packages:
'@vue/composition-api':
optional: true
vue-demi@0.14.8:
resolution: {integrity: sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==}
engines: {node: '>=12'}
hasBin: true
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
vue: ^3.0.0-0 || ^2.6.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
vue-draggable-plus@0.4.1:
resolution: {integrity: sha512-KNi+c482OQUZTZ2kXIGc41fEwknkNF+LlngjBr5TVtBLNvpX2dmwRJJ3J7dy5dGcijXb7V1j+mhqce4iHOoi6Q==}
peerDependencies:
@ -9963,7 +9979,7 @@ snapshots:
dependencies:
codemirror: 6.0.1(@lezer/common@1.2.1)
vue: 3.4.27(typescript@5.4.5)
vue-demi: 0.14.7(vue@3.4.27(typescript@5.4.5))
vue-demi: 0.14.8(vue@3.4.27(typescript@5.4.5))
transitivePeerDependencies:
- '@lezer/common'
- '@vue/composition-api'
@ -9976,6 +9992,10 @@ snapshots:
dependencies:
vue: 3.4.27(typescript@5.4.5)
vue-demi@0.14.8(vue@3.4.27(typescript@5.4.5)):
dependencies:
vue: 3.4.27(typescript@5.4.5)
vue-draggable-plus@0.4.1(@types/sortablejs@1.15.8):
dependencies:
'@types/sortablejs': 1.15.8

14
public/iconify/cbi.json Normal file
View File

@ -0,0 +1,14 @@
{
"prefix": "cbi",
"lastModified": 1715922185,
"aliases": {},
"width": 24,
"height": 24,
"icons": {
"scene-dynamic": {
"body": "<path fill=\"currentColor\" d=\"M17 21h-6c-.551 0-1-.45-1-1s.449-1 1-1h6c.55 0 1 .45 1 1s-.45 1-1 1m5-4h-8c-.551 0-1-.45-1-1s.449-1 1-1h8c.55 0 1 .45 1 1s-.45 1-1 1m-3-4h-8c-.551 0-1-.45-1-1s.449-1 1-1h8c.55 0 1 .45 1 1s-.45 1-1 1m-3-9C9.372 4 4 9.373 4 16s5.372 12 12 12c6.627 0 12-5.373 12-12S22.627 4 16 4\"/>",
"width": 32,
"height": 32
}
}
}

View File

@ -0,0 +1,12 @@
{
"prefix": "fluent",
"lastModified": 1716181326,
"aliases": {},
"width": 20,
"height": 20,
"icons": {
"people-call-20-filled": {
"body": "<path fill=\"currentColor\" d=\"M6.75 2.5a3.25 3.25 0 1 0 0 6.5a3.25 3.25 0 0 0 0-6.5M1.5 12a2 2 0 0 1 2-2H10a2 2 0 0 1 2 2v.084l-.002.04l-.01.135a3.95 3.95 0 0 1-.67 1.806C10.617 15.08 9.263 16 6.75 16s-3.867-.92-4.568-1.934a3.95 3.95 0 0 1-.67-1.807a3 3 0 0 1-.012-.175zm13-8a2.5 2.5 0 1 0 0 5a2.5 2.5 0 0 0 0-5m1.084 7.582l.283-.75c.258-.681 1.062-1.017 1.74-.728l.388.166c.473.202.864.568.947 1.06c.457 2.725-1.908 6.601-4.63 7.59c-.492.178-1.023.04-1.445-.246l-.346-.235a1.184 1.184 0 0 1-.204-1.79l.545-.607a1.07 1.07 0 0 1 1.034-.323l1.225.29q1.457-.91 1.562-2.56l-.878-.859a.94.94 0 0 1-.221-1.008\"/>"
}
}
}

12
public/iconify/oui.json Normal file
View File

@ -0,0 +1,12 @@
{
"prefix": "oui",
"lastModified": 1714628006,
"aliases": {},
"icons": {
"app-spaces": {
"body": "<path fill=\"currentColor\" d=\"M4 4h6v2H4zm18 0h6v2h-6zM4 22h6v2H4z\" class=\"ouiIcon__fillSecondary\"/><path fill=\"currentColor\" d=\"M0 14h14V0H0zM2 2h10v10H2zm16-2v14h14V0zm12 12H20V2h10zM0 32h14V18H0zm2-12h10v10H2zm16 12h14V18H18zm2-12h10v10H20z\"/><path fill=\"currentColor\" d=\"M22 22h6v2h-6z\" class=\"ouiIcon__fillSecondary\"/>",
"width": 32,
"height": 32
}
}
}

View File

@ -0,0 +1,17 @@
{
"prefix": "streamline",
"lastModified": 1702314084,
"aliases": {},
"width": 14,
"height": 14,
"icons": {
"interface-arrows-synchronize-warning-arrow-fail-notification-sync-warning-failure-synchronize-error": {
"body": "<g fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m11 9l2-.5l.5 2\"/><path d=\"M13 8.5A6.6 6.6 0 0 1 7 13h0a6 6 0 0 1-5.64-3.95M3 5l-2 .5l-.5-2\"/><path d=\"M1 5.5A6.79 6.79 0 0 1 7 1h0a6 6 0 0 1 5.64 4M7 3.5v4\"/><circle cx=\"7\" cy=\"10\" r=\".5\"/></g>",
"hidden": true
},
"interface-user-multiple-close-geometric-human-multiple-person-up-user": {
"body": "<g fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"5\" cy=\"3.75\" r=\"2.25\"/><path d=\"M9.5 13.5h-9v-1a4.5 4.5 0 0 1 9 0ZM9 1.5A2.25 2.25 0 0 1 9 6m1.6 2.19a4.5 4.5 0 0 1 2.9 4.2v1.11H12\"/></g>",
"hidden": true
}
}
}

View File

@ -0,0 +1,12 @@
{
"prefix": "tabler",
"lastModified": 1716442914,
"aliases": {},
"width": 24,
"height": 24,
"icons": {
"logs": {
"body": "<path fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 12h.01M4 6h.01M4 18h.01M8 18h2m-2-6h2M8 6h2m4 0h6m-6 6h6m-6 6h6\"/>"
}
}
}

View File

@ -7,6 +7,12 @@ defineOptions({
name: 'FileUpload'
});
const emit = defineEmits<Emits>();
interface Emits {
(e: 'refresh'): void;
}
interface Props {
accept?: string;
action?: string;
@ -51,6 +57,7 @@ const handleImport = ({
})
.then(() => {
onFinish();
emit('refresh');
})
.catch(() => onError());
};

View File

@ -1,250 +0,0 @@
/* eslint-disable */
/* prettier-ignore */
// Generated by elegant-router
// Read more: https://github.com/soybeanjs/elegant-router
import type { RouteRecordRaw, RouteComponent } from 'vue-router';
import type { ElegantConstRoute } from '@elegant-router/vue';
import type { RouteMap, RouteKey, RoutePath } from '@elegant-router/types';
/**
* transform elegant const routes to vue routes
* @param routes elegant const routes
* @param layouts layout components
* @param views view components
*/
export function transformElegantRoutesToVueRoutes(
routes: ElegantConstRoute[],
layouts: Record<string, RouteComponent | (() => Promise<RouteComponent>)>,
views: Record<string, RouteComponent | (() => Promise<RouteComponent>)>
) {
return routes.flatMap(route => transformElegantRouteToVueRoute(route, layouts, views));
}
/**
* transform elegant route to vue route
* @param route elegant const route
* @param layouts layout components
* @param views view components
*/
function transformElegantRouteToVueRoute(
route: ElegantConstRoute,
layouts: Record<string, RouteComponent | (() => Promise<RouteComponent>)>,
views: Record<string, RouteComponent | (() => Promise<RouteComponent>)>
) {
const LAYOUT_PREFIX = 'layout.';
const VIEW_PREFIX = 'view.';
const ROUTE_DEGREE_SPLITTER = '_';
const FIRST_LEVEL_ROUTE_COMPONENT_SPLIT = '$';
function isLayout(component: string) {
return component.startsWith(LAYOUT_PREFIX);
}
function getLayoutName(component: string) {
const layout = component.replace(LAYOUT_PREFIX, '');
if(!layouts[layout]) {
throw new Error(`Layout component "${layout}" not found`);
}
return layout;
}
function isView(component: string) {
return component.startsWith(VIEW_PREFIX);
}
function getViewName(component: string) {
const view = component.replace(VIEW_PREFIX, '');
if(!views[view]) {
throw new Error(`View component "${view}" not found`);
}
return view;
}
function isFirstLevelRoute(item: ElegantConstRoute) {
return !item.name.includes(ROUTE_DEGREE_SPLITTER);
}
function isSingleLevelRoute(item: ElegantConstRoute) {
return isFirstLevelRoute(item) && !item.children?.length;
}
function getSingleLevelRouteComponent(component: string) {
const [layout, view] = component.split(FIRST_LEVEL_ROUTE_COMPONENT_SPLIT);
return {
layout: getLayoutName(layout),
view: getViewName(view)
};
}
const vueRoutes: RouteRecordRaw[] = [];
// add props: true to route
if (route.path.includes(':') && !route.props) {
route.props = true;
}
const { name, path, component, children, ...rest } = route;
const vueRoute = { name, path, ...rest } as RouteRecordRaw;
try {
if (component) {
if (isSingleLevelRoute(route)) {
const { layout, view } = getSingleLevelRouteComponent(component);
const singleLevelRoute: RouteRecordRaw = {
path,
component: layouts[layout],
children: [
{
name,
path: '',
component: views[view],
...rest
} as RouteRecordRaw
]
};
return [singleLevelRoute];
}
if (isLayout(component)) {
const layoutName = getLayoutName(component);
vueRoute.component = layouts[layoutName];
}
if (isView(component)) {
const viewName = getViewName(component);
vueRoute.component = views[viewName];
}
}
} catch (error: any) {
console.error(`Error transforming route "${route.name}": ${error.toString()}`);
return [];
}
// add redirect to child
if (children?.length && !vueRoute.redirect) {
vueRoute.redirect = {
name: children[0].name
};
}
if (children?.length) {
const childRoutes = children.flatMap(child => transformElegantRouteToVueRoute(child, layouts, views));
if(isFirstLevelRoute(route)) {
vueRoute.children = childRoutes;
} else {
vueRoutes.push(...childRoutes);
}
}
vueRoutes.unshift(vueRoute);
return vueRoutes;
}
/**
* map of route name and route path
*/
const routeMap: RouteMap = {
"root": "/",
"not-found": "/:pathMatch(.*)*",
"exception": "/exception",
"exception_403": "/exception/403",
"exception_404": "/exception/404",
"exception_500": "/exception/500",
"document": "/document",
"document_project": "/document/project",
"document_project-link": "/document/project-link",
"document_vue": "/document/vue",
"document_vite": "/document/vite",
"document_unocss": "/document/unocss",
"document_naive": "/document/naive",
"document_antd": "/document/antd",
"403": "/403",
"404": "/404",
"500": "/500",
"about": "/about",
"function": "/function",
"function_hide-child": "/function/hide-child",
"function_hide-child_one": "/function/hide-child/one",
"function_hide-child_three": "/function/hide-child/three",
"function_hide-child_two": "/function/hide-child/two",
"function_multi-tab": "/function/multi-tab",
"function_request": "/function/request",
"function_super-page": "/function/super-page",
"function_tab": "/function/tab",
"function_toggle-auth": "/function/toggle-auth",
"group": "/group",
"home": "/home",
"iframe-page": "/iframe-page/:url",
"job": "/job",
"job_batch": "/job/batch",
"job_task": "/job/task",
"login": "/login/:module(pwd-login)?",
"manage": "/manage",
"manage_menu": "/manage/menu",
"manage_role": "/manage/role",
"manage_user": "/manage/user",
"manage_user-detail": "/manage/user-detail/:id",
"multi-menu": "/multi-menu",
"multi-menu_first": "/multi-menu/first",
"multi-menu_first_child": "/multi-menu/first/child",
"multi-menu_second": "/multi-menu/second",
"multi-menu_second_child": "/multi-menu/second/child",
"multi-menu_second_child_home": "/multi-menu/second/child/home",
"namespace": "/namespace",
"notify": "/notify",
"notify_recipient": "/notify/recipient",
"notify_scene": "/notify/scene",
"pods": "/pods",
"retry": "/retry",
"retry_dead-letter": "/retry/dead-letter",
"retry_log": "/retry/log",
"retry_scene": "/retry/scene",
"retry_task": "/retry/task",
"user": "/user",
"user_manager": "/user/manager",
"user-center": "/user-center",
"workflow": "/workflow",
"workflow_batch": "/workflow/batch",
"workflow_form": "/workflow/form",
"workflow_form_add": "/workflow/form/add",
"workflow_form_batch": "/workflow/form/batch",
"workflow_form_copy": "/workflow/form/copy",
"workflow_form_detail": "/workflow/form/detail",
"workflow_form_edit": "/workflow/form/edit",
"workflow_task": "/workflow/task"
};
/**
* get route path by route name
* @param name route name
*/
export function getRoutePath<T extends RouteKey>(name: T) {
return routeMap[name];
}
/**
* get route name by route path
* @param path route path
*/
export function getRouteName(path: RoutePath) {
const routeEntries = Object.entries(routeMap) as [RouteKey, RoutePath][];
const routeName: RouteKey | null = routeEntries.find(([, routePath]) => routePath === path)?.[0] || null;
return routeName;
}

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

@ -212,7 +212,7 @@ declare namespace Api {
type DashboardLineJob = {
createDt: string;
total: number;
failNum: number;
fail: number;
stop: number;
cancel: number;
success: number;
@ -649,8 +649,7 @@ declare namespace Api {
/** notifyRecipient search params */
type NotifyRecipientParams = CommonType.RecordNullable<
Pick<Api.NotifyRecipient.NotifyRecipient, 'recipientName' | 'notifyType' | 'notifyAttribute' | 'description'> &
CommonSearchParams
Pick<Api.NotifyRecipient.NotifyRecipient, 'recipientName' | 'notifyType'> & CommonSearchParams
>;
/** notifyRecipient list */
@ -659,6 +658,11 @@ declare namespace Api {
/** 1: 钉钉通知 2: 邮件通知 3: 企业通知 4: 飞书 5: Webhook */
type AlarmType = 1 | 2 | 3 | 4 | 5;
type ExportNotifyRecipient = Common.CommonRecord<{
notifyRecipientIds: string[];
}> &
NotifyRecipientParams;
/* 1: application/json 2application/x-www-form-urlencoded */
type AlarmTypeWebhook = 1 | 2;
}
@ -894,6 +898,11 @@ declare namespace Api {
Pick<Api.Workflow.Workflow, 'workflowName' | 'groupName' | 'workflowStatus'> & CommonSearchParams
>;
type ExportWorkflow = Common.CommonRecord<{
workflowIds: String[];
}> &
WorkflowSearchParams;
/** workflow list */
type WorkflowList = Common.PaginatingQueryRecord<Workflow>;
}
@ -982,6 +991,11 @@ declare namespace Api {
/** JobTask list */
type JobList = Common.PaginatingQueryRecord<Job>;
type ExportJob = Common.CommonRecord<{
jobIds: string[];
}> &
JobSearchParams;
/** 2、固定时间 3、CRON表达式 99、工作流 */
type TriggerType = 2 | 3 | 99;

View File

@ -195,7 +195,7 @@ function handleExport() {
@refresh="getData"
>
<template #addAfter>
<FileUpload v-if="hasAuth('R_ADMIN')" action="/group/import" accept="application/json" />
<FileUpload v-if="hasAuth('R_ADMIN')" action="/group/import" accept="application/json" @refresh="getData" />
<NPopconfirm @positive-click="handleExport">
<template #trigger>
<NButton size="small" ghost type="primary" :disabled="checkedRowKeys.length === 0 && hasAuth('R_USER')">

View File

@ -193,7 +193,7 @@ const getData = () => {
opts.tabIndex === 'RETRY' ? x.successNum : x.success
);
opts.series[1].data = props.modelValue?.dashboardLineResponseDOList.map(x =>
opts.tabIndex === 'RETRY' ? x.runningNum : x.failNum
opts.tabIndex === 'RETRY' ? x.runningNum : x.fail
);
opts.series[2].data = props.modelValue?.dashboardLineResponseDOList.map(x =>
opts.tabIndex === 'RETRY' ? x.maxCountNum : x.stop

View File

@ -253,8 +253,17 @@ function goToBatch(jobId: string) {
routerPushByKey('job_batch', { query: { jobId } });
}
function body(): Api.Job.ExportJob {
return {
jobIds: checkedRowKeys.value,
groupName: searchParams.groupName,
jobName: searchParams.jobName,
jobStatus: searchParams.jobStatus
};
}
function handleExport() {
downloadFetch('/job/export', checkedRowKeys.value, $t('page.jobTask.title'));
downloadFetch('/job/export', body(), $t('page.jobTask.title'));
}
</script>
@ -277,7 +286,7 @@ function handleExport() {
@refresh="getData"
>
<template #addAfter>
<FileUpload action="/job/import" accept="application/json" />
<FileUpload action="/job/import" accept="application/json" @refresh="getData" />
<NPopconfirm @positive-click="handleExport">
<template #trigger>
<NButton size="small" ghost type="primary" :disabled="checkedRowKeys.length === 0 && hasAuth('R_USER')">

View File

@ -9,6 +9,7 @@ import { useTable, useTableOperate } from '@/hooks/common/table';
import { alarmTypeRecord } from '@/constants/business';
import { tagColor } from '@/utils/common';
import { useAuth } from '@/hooks/business/auth';
import { downloadFetch } from '@/utils/download';
import NotifyRecipientOperateDrawer from './modules/notify-recipient-operate-drawer.vue';
import NotifyRecipientSearch from './modules/notify-recipient-search.vue';
import NotifyRecipientDetailDrawer from './modules/notify-recipient-detail-drawer.vue';
@ -28,7 +29,7 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
size: 10,
// if you want to use the searchParams in Form, you need to define the following properties, and the value is null
// the value can not be undefined, otherwise the property in Form will not be reactive
recipientName: '',
recipientName: null,
notifyType: null
},
columns: () => [
@ -137,6 +138,18 @@ async function handleDelete(id: string) {
function edit(id: string) {
handleEdit(id);
}
function body(): Api.NotifyRecipient.ExportNotifyRecipient {
return {
notifyRecipientIds: checkedRowKeys.value,
notifyType: searchParams.notifyType,
recipientName: searchParams.recipientName
};
}
function handleExport() {
downloadFetch('/notify-recipient/export', body(), $t('page.notifyRecipient.title'));
}
</script>
<template>
@ -157,7 +170,28 @@ function edit(id: string) {
@add="handleAdd"
@delete="handleBatchDelete"
@refresh="getData"
/>
>
<template #addAfter>
<FileUpload action="/job/import" accept="application/json" @refresh="getData" />
<NPopconfirm @positive-click="handleExport">
<template #trigger>
<NButton size="small" ghost type="primary" :disabled="checkedRowKeys.length === 0 && hasAuth('R_USER')">
<template #icon>
<IconPajamasExport class="text-icon" />
</template>
{{ $t('common.export') }}
</NButton>
</template>
<template #default>
{{
checkedRowKeys.length === 0
? $t('common.exportAll')
: $t('common.exportPar', { num: checkedRowKeys.length })
}}
</template>
</NPopconfirm>
</template>
</TableHeaderOperation>
</template>
<NDataTable
v-model:checked-row-keys="checkedRowKeys"

View File

@ -222,7 +222,7 @@ function handleExport() {
@refresh="getData"
>
<template #addAfter>
<FileUpload action="/scene-config/import" accept="application/json" />
<FileUpload action="/scene-config/import" accept="application/json" @refresh="getData" />
<NPopconfirm @positive-click="handleExport">
<template #trigger>
<NButton size="small" ghost type="primary" :disabled="checkedRowKeys.length === 0 && hasAuth('R_USER')">

View File

@ -33,11 +33,11 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
workflowStatus: null
},
columns: () => [
// {
// type: 'selection',
// align: 'center',
// width: 48
// },
{
type: 'selection',
align: 'center',
width: 48
},
{
key: 'id',
title: $t('common.index'),
@ -249,8 +249,17 @@ async function execute(id: string) {
}
}
function body(): Api.Workflow.ExportWorkflow {
return {
workflowIds: checkedRowKeys.value,
groupName: searchParams.groupName,
workflowName: searchParams.workflowName,
workflowStatus: searchParams.workflowStatus
};
}
function handleExport() {
downloadFetch('/workflow/export', checkedRowKeys.value, $t('page.workflow.title'));
downloadFetch('/workflow/export', body(), $t('page.workflow.title'));
}
</script>
@ -275,7 +284,7 @@ function handleExport() {
@refresh="getData"
>
<template #addAfter>
<FileUpload action="/workflow/import" accept="application/json" />
<FileUpload action="/workflow/import" accept="application/json" @refresh="getData" />
<NPopconfirm @positive-click="handleExport">
<template #trigger>
<NButton size="small" ghost type="primary" :disabled="checkedRowKeys.length === 0 && hasAuth('R_USER')">

View File

@ -29,7 +29,7 @@ function search() {
<template>
<SearchForm :model="model" @search="search" @reset="reset">
<NFormItemGi span="24 s:12 m:6" :label="$t('page.workflow.groupName')" path="groupName" class="pr-24px">
<SelectGroup v-model="model.groupName" />
<SelectGroup v-model:value="model.groupName" />
</NFormItemGi>
<NFormItemGi
span="24 s:12 m:6"