发布 v1.10 #5
@@ -0,0 +1,75 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, watch } from 'vue';
|
||||||
|
|
||||||
|
import { AuthenticationLoginExpiredModal } from '@easyflow/common-ui';
|
||||||
|
import { useWatermark } from '@easyflow/hooks';
|
||||||
|
import { LockScreen } from '@easyflow/layouts';
|
||||||
|
import { preferences } from '@easyflow/preferences';
|
||||||
|
import { useAccessStore, useUserStore } from '@easyflow/stores';
|
||||||
|
|
||||||
|
import { useAuthStore } from '#/store';
|
||||||
|
import LoginForm from '#/views/_core/authentication/login.vue';
|
||||||
|
|
||||||
|
const accessStore = useAccessStore();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
const { destroyWatermark, updateWatermark } = useWatermark();
|
||||||
|
|
||||||
|
const avatar = computed(
|
||||||
|
() => userStore.userInfo?.avatar ?? preferences.app.defaultAvatar,
|
||||||
|
);
|
||||||
|
|
||||||
|
async function handleLogout() {
|
||||||
|
await authStore.logout(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => ({
|
||||||
|
enable: preferences.app.watermark,
|
||||||
|
content: preferences.app.watermarkContent,
|
||||||
|
}),
|
||||||
|
async ({ enable, content }) => {
|
||||||
|
if (enable) {
|
||||||
|
await updateWatermark({
|
||||||
|
content:
|
||||||
|
content ||
|
||||||
|
`${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
destroyWatermark();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="authenticated-standalone-layout">
|
||||||
|
<slot></slot>
|
||||||
|
<AuthenticationLoginExpiredModal
|
||||||
|
v-model:open="accessStore.loginExpired"
|
||||||
|
:avatar
|
||||||
|
>
|
||||||
|
<LoginForm />
|
||||||
|
</AuthenticationLoginExpiredModal>
|
||||||
|
<Transition v-if="preferences.widget.lockScreen" name="slide-up">
|
||||||
|
<LockScreen
|
||||||
|
v-if="accessStore.isLockScreen"
|
||||||
|
:avatar
|
||||||
|
@to-login="handleLogout"
|
||||||
|
/>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.authenticated-standalone-layout {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: var(--el-bg-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
import agentDesignRoutes from '../routes/external/agent-design';
|
||||||
|
import agentRoutes from '../routes/modules/agent';
|
||||||
|
|
||||||
|
describe('agent design route', () => {
|
||||||
|
it('keeps the standalone designer outside dynamic menu routes', () => {
|
||||||
|
const designRoute = agentDesignRoutes.find(
|
||||||
|
(route) => route.name === 'AgentDesigner',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(agentRoutes.some((route) => route.name === 'AgentDesigner')).toBe(
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(designRoute).toBeDefined();
|
||||||
|
expect(designRoute?.path).toBe('/ai/agents/designer/:id');
|
||||||
|
expect(designRoute?.meta).toMatchObject({
|
||||||
|
activePath: '/ai/agents',
|
||||||
|
hideInBreadcrumb: true,
|
||||||
|
hideInMenu: true,
|
||||||
|
hideInTab: true,
|
||||||
|
noBasicLayout: true,
|
||||||
|
openInNewWindow: true,
|
||||||
|
});
|
||||||
|
expect(designRoute?.meta?.ignoreAccess).not.toBe(true);
|
||||||
|
expect(designRoute?.component).toBeTypeOf('function');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
import workflowRoutes from '../routes/modules/workflow';
|
||||||
|
|
||||||
|
describe('workflow design route', () => {
|
||||||
|
it('uses the authenticated standalone shell without exposing a menu or tab', () => {
|
||||||
|
const designRoute = workflowRoutes.find(
|
||||||
|
(route) => route.name === 'WorkflowDesign',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(designRoute).toBeDefined();
|
||||||
|
expect(designRoute?.path).toBe('/ai/workflow/design');
|
||||||
|
expect(designRoute?.meta).toMatchObject({
|
||||||
|
activePath: '/ai/workflow',
|
||||||
|
hideInBreadcrumb: true,
|
||||||
|
hideInMenu: true,
|
||||||
|
hideInTab: true,
|
||||||
|
noBasicLayout: true,
|
||||||
|
});
|
||||||
|
expect(designRoute?.meta?.ignoreAccess).not.toBe(true);
|
||||||
|
expect(designRoute?.component).toBeTypeOf('function');
|
||||||
|
});
|
||||||
|
});
|
||||||
23
easyflow-ui-admin/app/src/router/routes/external/agent-design.ts
vendored
Normal file
23
easyflow-ui-admin/app/src/router/routes/external/agent-design.ts
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import type { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
|
const routes: RouteRecordRaw[] = [
|
||||||
|
{
|
||||||
|
name: 'AgentDesigner',
|
||||||
|
path: '/ai/agents/designer/:id',
|
||||||
|
component: () =>
|
||||||
|
import('#/views/ai/agents/AgentDesignerStandaloneView.vue'),
|
||||||
|
meta: {
|
||||||
|
title: $t('menus.ai.agents'),
|
||||||
|
openInNewWindow: true,
|
||||||
|
hideInMenu: true,
|
||||||
|
hideInTab: true,
|
||||||
|
hideInBreadcrumb: true,
|
||||||
|
noBasicLayout: true,
|
||||||
|
activePath: '/ai/agents',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default routes;
|
||||||
@@ -1,19 +1,6 @@
|
|||||||
import type {RouteRecordRaw} from 'vue-router';
|
import type { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
import {$t} from '#/locales';
|
|
||||||
|
|
||||||
const routes: RouteRecordRaw[] = [
|
const routes: RouteRecordRaw[] = [
|
||||||
{
|
|
||||||
name: 'AgentDesigner',
|
|
||||||
path: '/ai/agents/designer/:id',
|
|
||||||
component: () => import('#/views/ai/agents/AgentDesigner.vue'),
|
|
||||||
meta: {
|
|
||||||
title: $t('menus.ai.agents'),
|
|
||||||
openInNewWindow: true,
|
|
||||||
hideInMenu: true,
|
|
||||||
activePath: '/ai/agents',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'AgentChat',
|
name: 'AgentChat',
|
||||||
path: '/ai/agent-chat',
|
path: '/ai/agent-chat',
|
||||||
|
|||||||
@@ -8,11 +8,15 @@ const routes: RouteRecordRaw[] = [
|
|||||||
icon: 'ant-design:apartment-outlined',
|
icon: 'ant-design:apartment-outlined',
|
||||||
title: '工作流设计',
|
title: '工作流设计',
|
||||||
hideInMenu: true,
|
hideInMenu: true,
|
||||||
|
hideInTab: true,
|
||||||
|
hideInBreadcrumb: true,
|
||||||
|
noBasicLayout: true,
|
||||||
activePath: '/ai/workflow',
|
activePath: '/ai/workflow',
|
||||||
},
|
},
|
||||||
name: 'WorkflowDesign',
|
name: 'WorkflowDesign',
|
||||||
path: '/ai/workflow/design',
|
path: '/ai/workflow/design',
|
||||||
component: () => import('#/views/ai/workflow/WorkflowDesign.vue'),
|
component: () =>
|
||||||
|
import('#/views/ai/workflow/WorkflowDesignStandaloneView.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
meta: {
|
meta: {
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import AuthenticatedStandaloneLayout from '#/layouts/AuthenticatedStandaloneLayout.vue';
|
||||||
|
|
||||||
|
import AgentDesigner from './AgentDesigner.vue';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AuthenticatedStandaloneLayout>
|
||||||
|
<AgentDesigner />
|
||||||
|
</AuthenticatedStandaloneLayout>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import AuthenticatedStandaloneLayout from '#/layouts/AuthenticatedStandaloneLayout.vue';
|
||||||
|
|
||||||
|
import WorkflowDesign from './WorkflowDesign.vue';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AuthenticatedStandaloneLayout class="workflow-design-standalone">
|
||||||
|
<WorkflowDesign />
|
||||||
|
</AuthenticatedStandaloneLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.workflow-design-standalone :deep(.head-div) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-design-standalone :deep(.agentsflow) {
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-design-standalone :deep(.tiny-flow-container) {
|
||||||
|
flex: 1;
|
||||||
|
height: auto;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user