fix: 修复管理端前端 lint 与构建问题

- 收敛 easyflow-ui-admin 的 lint、格式和类型问题

- 修正 demo 页面与管理端前端构建失败点

- 验证 pnpm lint 与 pnpm build 均已通过
This commit is contained in:
2026-04-05 21:39:13 +08:00
parent bb72e19c84
commit 7e7c236c2a
240 changed files with 5151 additions and 4701 deletions

View File

@@ -15,10 +15,10 @@
<link rel="icon" href="/favicon.svg" /> <link rel="icon" href="/favicon.svg" />
<script> <script>
var _hmt = _hmt || []; var _hmt = _hmt || [];
(function() { (function () {
var hm = document.createElement("script"); var hm = document.createElement('script');
hm.src = "https://hm.baidu.com/hm.js?42639a1503843c26bc4d8b35185616d9"; hm.src = 'https://hm.baidu.com/hm.js?42639a1503843c26bc4d8b35185616d9';
var s = document.getElementsByTagName("script")[0]; var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(hm, s); s.parentNode.insertBefore(hm, s);
})(); })();
</script> </script>

View File

@@ -29,10 +29,10 @@
"@easyflow/types": "workspace:*", "@easyflow/types": "workspace:*",
"@easyflow/utils": "workspace:*", "@easyflow/utils": "workspace:*",
"@element-plus/icons-vue": "^2.3.2", "@element-plus/icons-vue": "^2.3.2",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"@tinyflow-ai/vue": "workspace:*", "@tinyflow-ai/vue": "workspace:*",
"@vueuse/core": "catalog:", "@vueuse/core": "catalog:",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"dayjs": "catalog:", "dayjs": "catalog:",
"dompurify": "^3.3.1", "dompurify": "^3.3.1",
"element-plus": "catalog:", "element-plus": "catalog:",

View File

@@ -10,7 +10,11 @@ import type { Recordable } from '@easyflow/types';
import { defineAsyncComponent, defineComponent, h, ref } from 'vue'; import { defineAsyncComponent, defineComponent, h, ref } from 'vue';
import { ApiComponent, globalShareState, IconPicker } from '@easyflow/common-ui'; import {
ApiComponent,
globalShareState,
IconPicker,
} from '@easyflow/common-ui';
import { $t } from '@easyflow/locales'; import { $t } from '@easyflow/locales';
import { ElNotification } from 'element-plus'; import { ElNotification } from 'element-plus';

View File

@@ -1,11 +1,15 @@
import type { import type {
EasyFlowFormSchema as FormSchema,
EasyFlowFormProps, EasyFlowFormProps,
EasyFlowFormSchema as FormSchema,
} from '@easyflow/common-ui'; } from '@easyflow/common-ui';
import type { ComponentType } from './component'; import type { ComponentType } from './component';
import { setupEasyFlowForm, useEasyFlowForm as useForm, z } from '@easyflow/common-ui'; import {
setupEasyFlowForm,
useEasyFlowForm as useForm,
z,
} from '@easyflow/common-ui';
import { $t } from '@easyflow/locales'; import { $t } from '@easyflow/locales';
async function initSetupEasyFlowForm() { async function initSetupEasyFlowForm() {

View File

@@ -2,7 +2,10 @@ import type { VxeTableGridOptions } from '@easyflow/plugins/vxe-table';
import { h } from 'vue'; import { h } from 'vue';
import { setupEasyFlowVxeTable, useEasyFlowVxeGrid } from '@easyflow/plugins/vxe-table'; import {
setupEasyFlowVxeTable,
useEasyFlowVxeGrid,
} from '@easyflow/plugins/vxe-table';
import { ElButton, ElImage } from 'element-plus'; import { ElButton, ElImage } from 'element-plus';

View File

@@ -0,0 +1 @@
export {};

View File

@@ -144,143 +144,8 @@ const filteredActions = computed(() => {
</template> </template>
<style scoped> <style scoped>
.card-list-container {
width: 100%;
height: 100%;
}
.card-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 20px;
}
:deep(.el-card__body) {
padding: 20px 0 0 0;
}
.card-item {
transition: all 0.3s ease;
border-radius: 8px;
flex-shrink: 0;
height: 165px;
min-width: 0;
}
:deep(.delete-dropdown-item) {
color: #ff4d4f !important;
}
:deep(.delete-dropdown-item:hover) {
color: #ff7875 !important;
}
:deep(.delete-dropdown-item .el-icon) {
color: inherit !important;
}
.card-item:hover {
transform: translateY(-5px);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
.card-content {
display: flex;
flex-direction: column;
height: 100%;
background-color: var(--el-bg-color);
border-radius: 8px;
}
.card-header {
display: flex;
align-items: flex-start;
gap: 15px;
margin-bottom: 15px;
flex: 1;
padding: 0 20px 0 20px;
}
.card-info {
flex: 1;
min-width: 0;
max-width: 100%;
}
.card-title {
margin: 0 0 8px 0;
font-size: 16px;
font-weight: 600;
color: var(--el-text-color-primary);
line-height: 1.4;
}
.card-desc {
margin: 0;
width: 100%;
font-size: 14px;
color: #606266;
line-height: 1.5;
height: 42px;
min-height: 42px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
.card-actions {
display: flex;
align-items: center;
height: 48px;
background:
linear-gradient(
180deg,
var(--el-color-primary-light-9),
var(--el-bg-color)
),
var(--el-bg-color);
}
.action-btn {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
min-width: 0;
color: #acb7c6;
position: relative;
&:hover {
color: var(--el-color-primary);
}
}
.more-btn {
width: 100%;
justify-content: center;
}
.divider {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 1px;
height: 20px;
background-color: #e0e0e0;
}
/* 确保按钮内容不换行 */
.action-btn .el-button {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
justify-content: center;
}
.empty-state {
padding: 40px 0;
text-align: center;
}
/* 响应式设计 */ /* 响应式设计 */
/* 超大屏幕 */ /* 超大屏幕 */
@media (min-width: 1920px) { @media (min-width: 1920px) {
.card-list { .card-list {
@@ -305,8 +170,8 @@ const filteredActions = computed(() => {
} }
.card-header { .card-header {
padding: 0 16px 0 16px;
gap: 12px; gap: 12px;
padding: 0 16px;
} }
.card-title { .card-title {
@@ -314,9 +179,9 @@ const filteredActions = computed(() => {
} }
.card-desc { .card-desc {
font-size: 13px;
height: 36px; height: 36px;
min-height: 36px; min-height: 36px;
font-size: 13px;
} }
} }
@@ -326,21 +191,22 @@ const filteredActions = computed(() => {
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 16px; gap: 16px;
} }
.card-header { .card-header {
padding: 0 12px 0 12px;
gap: 10px; gap: 10px;
padding: 0 12px;
} }
.card-title { .card-title {
font-size: 14px;
margin-bottom: 6px; margin-bottom: 6px;
font-size: 14px;
} }
.card-desc { .card-desc {
font-size: 12px;
height: 32px; height: 32px;
min-height: 32px; min-height: 32px;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
font-size: 12px;
} }
.card-actions { .card-actions {
@@ -351,4 +217,147 @@ const filteredActions = computed(() => {
font-size: 11px; font-size: 11px;
} }
} }
.card-list-container {
width: 100%;
height: 100%;
}
.card-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 20px;
}
:deep(.el-card__body) {
padding: 20px 0 0;
}
.card-item {
flex-shrink: 0;
min-width: 0;
height: 165px;
border-radius: 8px;
transition: all 0.3s ease;
}
:deep(.delete-dropdown-item) {
color: #ff4d4f !important;
}
:deep(.delete-dropdown-item:hover) {
color: #ff7875 !important;
}
:deep(.delete-dropdown-item .el-icon) {
color: inherit !important;
}
.card-item:hover {
box-shadow: 0 4px 20px rgb(0 0 0 / 10%);
transform: translateY(-5px);
}
.card-content {
display: flex;
flex-direction: column;
height: 100%;
background-color: var(--el-bg-color);
border-radius: 8px;
}
.card-header {
display: flex;
flex: 1;
gap: 15px;
align-items: flex-start;
padding: 0 20px;
margin-bottom: 15px;
}
.card-info {
flex: 1;
min-width: 0;
max-width: 100%;
}
.card-title {
margin: 0 0 8px;
font-size: 16px;
font-weight: 600;
line-height: 1.4;
color: var(--el-text-color-primary);
}
.card-desc {
display: -webkit-box;
width: 100%;
height: 42px;
min-height: 42px;
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
font-size: 14px;
line-height: 1.5;
color: #606266;
-webkit-box-orient: vertical;
}
.card-actions {
display: flex;
align-items: center;
height: 48px;
background:
linear-gradient(
180deg,
var(--el-color-primary-light-9),
var(--el-bg-color)
),
var(--el-bg-color);
}
.action-btn {
position: relative;
display: flex;
flex: 1;
align-items: center;
justify-content: center;
min-width: 0;
color: #acb7c6;
&:hover {
color: var(--el-color-primary);
}
}
.more-btn {
justify-content: center;
width: 100%;
}
.divider {
position: absolute;
top: 50%;
right: 0;
width: 1px;
height: 20px;
background-color: #e0e0e0;
transform: translateY(-50%);
}
/* 确保按钮内容不换行 */
.action-btn .el-button {
justify-content: center;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.empty-state {
padding: 40px 0;
text-align: center;
}
</style> </style>

View File

@@ -283,28 +283,28 @@ const handleDeleteClick = (event: any, item: any) => {
<style scoped> <style scoped>
.crud-category-item:hover { .crud-category-item:hover {
background-color: var(--el-color-primary-light-9);
cursor: pointer; cursor: pointer;
background-color: var(--el-color-primary-light-9);
} }
.crud-category-item.selected { .crud-category-item.selected {
background-color: var(--el-color-primary-light-9);
color: var(--el-color-primary); color: var(--el-color-primary);
background-color: var(--el-color-primary-light-9);
} }
.no-data { .no-data {
text-align: center;
padding: 40px 0; padding: 40px 0;
text-align: center;
} }
.crud-category-item { .crud-category-item {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 8px 12px;
height: 40px; height: 40px;
border-radius: 8px; padding: 8px 12px;
font-size: 14px; font-size: 14px;
border-radius: 8px;
} }
.crud-category-item :deep(.el-icon) { .crud-category-item :deep(.el-icon) {
@@ -316,8 +316,8 @@ const handleDeleteClick = (event: any, item: any) => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 4px; padding: 4px;
border-radius: 4px;
cursor: pointer; cursor: pointer;
border-radius: 4px;
transition: background-color 0.3s; transition: background-color 0.3s;
} }

View File

@@ -10,7 +10,6 @@ const props = defineProps({
categories: { categories: {
type: Array, type: Array,
default: () => [], default: () => [],
required: true,
}, },
valueKey: { valueKey: {
type: String, type: String,
@@ -125,6 +124,14 @@ const panelWidth = computed(() => {
} }
}); });
const categoryIconStyle = computed(() => ({
'--category-icon-color': props.iconColor,
'--category-icon-size':
typeof props.iconSize === 'number'
? `${props.iconSize}px`
: `${props.iconSize}`,
}));
// 切换面板收缩状态 // 切换面板收缩状态
const togglePanel = () => { const togglePanel = () => {
isCollapsed.value = !isCollapsed.value; isCollapsed.value = !isCollapsed.value;
@@ -177,18 +184,24 @@ onMounted(() => {
@click="handleCategoryClick(category)" @click="handleCategoryClick(category)"
> >
<!-- 图标 --> <!-- 图标 -->
<div v-if="category[iconKey]" class="category-icon"> <div
v-if="category[iconKey]"
class="category-icon"
:style="categoryIconStyle"
>
<!-- 1. 组件类型图标Element Plus / 自定义 SVG 组件 --> <!-- 1. 组件类型图标Element Plus / 自定义 SVG 组件 -->
<ElIcon v-if="isComponent(category[iconKey])"> <ElIcon v-if="isComponent(category[iconKey])">
<component :is="category[iconKey]" /> <component :is="category[iconKey]" />
</ElIcon> </ElIcon>
<!-- 2. SVG 字符串支持 v-html img 两种渲染方式 --> <!-- 2. SVG 字符串支持 v-html img 两种渲染方式 -->
<template v-else-if="isSvgString(category[iconKey])"> <template v-else-if="isSvgString(category[iconKey])">
<!-- eslint-disable vue/no-v-html -->
<div <div
v-if="!useImgForSvg" v-if="!useImgForSvg"
v-html="category[iconKey]" v-html="category[iconKey]"
class="custom-svg" class="custom-svg"
></div> ></div>
<!-- eslint-enable vue/no-v-html -->
<img <img
v-else v-else
:src="svgToDataUrl(category[iconKey])" :src="svgToDataUrl(category[iconKey])"
@@ -221,14 +234,14 @@ onMounted(() => {
<style scoped> <style scoped>
.category-panel { .category-panel {
position: relative; /* 相对定位,用于按钮绝对定位 */ position: relative; /* 相对定位,用于按钮绝对定位 */
overflow: hidden;
height: 100%;
transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1); /* 平滑宽度过渡 */
box-sizing: border-box; box-sizing: border-box;
background: #ffffff; height: 100%;
border-radius: 8px;
border: 1px solid #f0f0f0;
padding: 20px; padding: 20px;
overflow: hidden;
background: #fff;
border: 1px solid #f0f0f0;
border-radius: 8px;
transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1); /* 平滑宽度过渡 */
} }
/* 右上角收缩/展开按钮 */ /* 右上角收缩/展开按钮 */
@@ -242,18 +255,19 @@ onMounted(() => {
justify-content: center; justify-content: center;
width: 32px; width: 32px;
height: 32px; height: 32px;
border-radius: 50%; cursor: pointer;
background-color: var(--el-color-white); background-color: var(--el-color-white);
border: 1px solid #e5e7eb; border: 1px solid #e5e7eb;
cursor: pointer; border-radius: 50%;
transition: all 0.2s;
/* 按钮不随面板收缩移动 */ /* 按钮不随面板收缩移动 */
transform: translateX(0); transform: translateX(0);
transition: all 0.2s;
} }
.toggle-panel-btn:hover { .toggle-panel-btn:hover {
background-color: #f3f4f6; background-color: #f3f4f6;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 8px rgb(0 0 0 / 10%);
} }
.toggle-panel-btn .el-icon { .toggle-panel-btn .el-icon {
@@ -264,15 +278,12 @@ onMounted(() => {
/* 分类列表容器 */ /* 分类列表容器 */
.category-list { .category-list {
overflow: hidden;
height: 100%;
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1px; gap: 1px;
} height: 100%;
overflow: hidden;
.category-item {
} }
.category-item:last-child { .category-item:last-child {
@@ -281,15 +292,15 @@ onMounted(() => {
.category-item-content { .category-item-content {
display: flex; display: flex;
gap: 12px;
align-items: center; align-items: center;
padding: 6px 0 6px 14px;
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
color: #333; color: #333;
cursor: pointer; cursor: pointer;
transition: background-color 0.2s;
gap: 12px;
padding: 6px 0 6px 14px;
border-radius: 4px; border-radius: 4px;
transition: background-color 0.2s;
} }
.category-item-content:hover { .category-item-content:hover {
@@ -297,49 +308,36 @@ onMounted(() => {
} }
.category-icon { .category-icon {
width: v-bind(iconSize);
height: v-bind(iconSize);
color: v-bind(iconColor);
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: var(--category-icon-size);
height: var(--category-icon-size);
vertical-align: middle; vertical-align: middle;
color: var(--category-icon-color);
} }
.category-icon .el-icon { .category-icon .el-icon {
width: 100%;
height: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} width: 100%;
height: 100%;
.category-item-content {
display: flex;
align-items: center;
font-size: 14px;
font-weight: 500;
color: #333;
cursor: pointer;
transition: background-color 0.2s;
gap: 12px;
} }
.category-name { .category-name {
overflow: hidden;
text-overflow: ellipsis;
font-family: PingFangSC, 'PingFang SC';
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px;
text-align: left;
white-space: nowrap;
transition: transition:
opacity 0.2s, opacity 0.2s,
transform 0.2s; transform 0.2s;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-family:
PingFangSC,
PingFang SC;
font-weight: 400;
font-size: 14px;
line-height: 20px;
text-align: left;
font-style: normal;
} }
/* 收缩状态样式 */ /* 收缩状态样式 */
@@ -360,11 +358,11 @@ onMounted(() => {
/* 新增:选中态样式 */ /* 新增:选中态样式 */
.category-item-content.selected { .category-item-content.selected {
font-weight: 600; font-weight: 600;
background: rgba(0, 102, 255, 0.06); color: #06f;
color: #0066ff; background: rgb(0 102 255 / 6%);
} }
.category-item-content.selected:hover { .category-item-content.selected:hover {
background: rgba(0, 102, 255, 0.06); background: rgb(0 102 255 / 6%);
} }
</style> </style>

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ChatThinkingBlock } from '@easyflow/common-ui';
import ElXMarkdown from 'vue-element-plus-x/es/XMarkdown/index.js'; import ElXMarkdown from 'vue-element-plus-x/es/XMarkdown/index.js';
import { ChatThinkingBlock } from '@easyflow/common-ui';
import { IconifyIcon } from '@easyflow/icons'; import { IconifyIcon } from '@easyflow/icons';
import { CircleCheck, Close } from '@element-plus/icons-vue'; import { CircleCheck, Close } from '@element-plus/icons-vue';
@@ -22,7 +22,7 @@ interface ChatHistoryDetailDrawerProps {
session?: any; session?: any;
messages?: any[]; messages?: any[];
hasMore?: boolean; hasMore?: boolean;
onLoadMore?: (() => void | Promise<void>) | undefined; onLoadMore?: (() => Promise<void> | void) | undefined;
} }
const props = withDefaults(defineProps<ChatHistoryDetailDrawerProps>(), { const props = withDefaults(defineProps<ChatHistoryDetailDrawerProps>(), {
@@ -128,12 +128,7 @@ async function handleLoadMore() {
<div class="chat-history-detail__stream"> <div class="chat-history-detail__stream">
<div class="chat-history-detail__stream-toolbar"> <div class="chat-history-detail__stream-toolbar">
<ElButton <ElButton v-if="hasMore" text type="primary" @click="handleLoadMore">
v-if="hasMore"
text
type="primary"
@click="handleLoadMore"
>
加载更早消息 加载更早消息
</ElButton> </ElButton>
</div> </div>
@@ -233,48 +228,48 @@ async function handleLoadMore() {
<style scoped> <style scoped>
.chat-history-detail { .chat-history-detail {
display: flex; display: flex;
flex-direction: column;
height: 100%; height: 100%;
min-height: 0; min-height: 0;
flex-direction: column;
background: background:
radial-gradient( radial-gradient(
circle at top right, circle at top right,
hsl(var(--nav-ambient) / 0.1), hsl(var(--nav-ambient) / 10%),
transparent 26% transparent 26%
), ),
linear-gradient( linear-gradient(
180deg, 180deg,
hsl(var(--glass-border) / 0.18) 0%, hsl(var(--glass-border) / 18%) 0%,
hsl(var(--glass-tint) / 0.34) 10%, hsl(var(--glass-tint) / 34%) 10%,
hsl(var(--surface-panel) / 0.88) 28%, hsl(var(--surface-panel) / 88%) 28%,
hsl(var(--surface-panel) / 0.96) 100% hsl(var(--surface-panel) / 96%) 100%
); );
} }
.chat-history-detail__summary { .chat-history-detail__summary {
display: flex; display: flex;
gap: 16px;
align-items: flex-start; align-items: flex-start;
justify-content: space-between; justify-content: space-between;
gap: 16px;
padding: 20px 24px 12px; padding: 20px 24px 12px;
border-bottom: 1px solid hsl(var(--divider-faint) / 0.16); border-bottom: 1px solid hsl(var(--divider-faint) / 16%);
} }
.chat-history-detail__summary-main { .chat-history-detail__summary-main {
min-width: 0;
flex: 1; flex: 1;
min-width: 0;
} }
.chat-history-detail__title-row { .chat-history-detail__title-row {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center;
gap: 12px; gap: 12px;
align-items: center;
} }
.chat-history-detail__title { .chat-history-detail__title {
margin: 0;
min-width: 0; min-width: 0;
margin: 0;
font-size: 18px; font-size: 18px;
font-weight: 600; font-weight: 600;
color: hsl(var(--text-strong)); color: hsl(var(--text-strong));
@@ -285,19 +280,19 @@ async function handleLoadMore() {
align-items: center; align-items: center;
min-height: 26px; min-height: 26px;
padding: 0 10px; padding: 0 10px;
border: 1px solid hsl(var(--glass-border) / 0.38);
border-radius: 999px;
background: hsl(var(--glass-tint) / 0.54);
font-size: 12px; font-size: 12px;
font-weight: 600; font-weight: 600;
color: hsl(var(--nav-item-active-foreground)); color: hsl(var(--nav-item-active-foreground));
background: hsl(var(--glass-tint) / 54%);
border: 1px solid hsl(var(--glass-border) / 38%);
border-radius: 999px;
} }
.chat-history-detail__meta-row { .chat-history-detail__meta-row {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center;
gap: 10px; gap: 10px;
align-items: center;
margin-top: 10px; margin-top: 10px;
} }
@@ -316,28 +311,28 @@ async function handleLoadMore() {
.chat-history-detail__meta-inline { .chat-history-detail__meta-inline {
display: inline-flex; display: inline-flex;
min-width: 0;
align-items: center;
gap: 6px; gap: 6px;
align-items: center;
min-width: 0;
} }
.chat-history-detail__meta-divider { .chat-history-detail__meta-divider {
display: inline-flex; display: inline-flex;
height: 12px;
width: 1px; width: 1px;
background: hsl(var(--divider-faint) / 0.42); height: 12px;
background: hsl(var(--divider-faint) / 42%);
} }
.chat-history-detail__close { .chat-history-detail__close {
display: inline-flex; display: inline-flex;
height: 36px;
width: 36px;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
border: 1px solid hsl(var(--divider-faint) / 0.24); width: 36px;
border-radius: 999px; height: 36px;
background: hsl(var(--glass-tint) / 0.46);
color: hsl(var(--text-muted)); color: hsl(var(--text-muted));
background: hsl(var(--glass-tint) / 46%);
border: 1px solid hsl(var(--divider-faint) / 24%);
border-radius: 999px;
transition: transition:
transform 0.18s ease, transform 0.18s ease,
background-color 0.18s ease, background-color 0.18s ease,
@@ -346,15 +341,15 @@ async function handleLoadMore() {
.chat-history-detail__close:hover { .chat-history-detail__close:hover {
color: hsl(var(--text-strong)); color: hsl(var(--text-strong));
background: hsl(var(--surface-contrast-soft) / 0.92); background: hsl(var(--surface-contrast-soft) / 92%);
transform: translateY(-1px); transform: translateY(-1px);
} }
.chat-history-detail__stream { .chat-history-detail__stream {
display: flex; display: flex;
min-height: 0;
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
min-height: 0;
padding: 14px 24px 20px; padding: 14px 24px 20px;
} }
@@ -365,8 +360,8 @@ async function handleLoadMore() {
} }
.chat-history-detail__scrollbar { .chat-history-detail__scrollbar {
min-height: 0;
flex: 1; flex: 1;
min-height: 0;
} }
.chat-history-detail__message-list { .chat-history-detail__message-list {
@@ -391,9 +386,9 @@ async function handleLoadMore() {
.chat-history-detail__message-meta { .chat-history-detail__message-meta {
display: inline-flex; display: inline-flex;
max-width: 88%;
align-items: center;
gap: 10px; gap: 10px;
align-items: center;
max-width: 88%;
font-size: 11px; font-size: 11px;
color: hsl(var(--text-muted)); color: hsl(var(--text-muted));
} }
@@ -409,30 +404,30 @@ async function handleLoadMore() {
.chat-history-detail__message-bubble { .chat-history-detail__message-bubble {
width: min(88%, 760px); width: min(88%, 760px);
border: 1px solid hsl(var(--divider-faint) / 0.34);
border-radius: 22px;
padding: 14px 16px; padding: 14px 16px;
font-size: 14px; font-size: 14px;
line-height: 1.72; line-height: 1.72;
border: 1px solid hsl(var(--divider-faint) / 34%);
border-radius: 22px;
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
} }
.chat-history-detail__message-bubble.is-assistant { .chat-history-detail__message-bubble.is-assistant {
background: hsl(var(--glass-tint) / 0.88); background: hsl(var(--glass-tint) / 88%);
box-shadow: box-shadow:
inset 0 1px 0 hsl(var(--glass-border) / 0.48), inset 0 1px 0 hsl(var(--glass-border) / 48%),
0 12px 26px -24px hsl(var(--foreground) / 0.18); 0 12px 26px -24px hsl(var(--foreground) / 18%);
} }
.chat-history-detail__message-bubble.is-user { .chat-history-detail__message-bubble.is-user {
background: linear-gradient( background: linear-gradient(
180deg, 180deg,
hsl(var(--primary) / 0.14) 0%, hsl(var(--primary) / 14%) 0%,
hsl(var(--surface-panel) / 0.96) 100% hsl(var(--surface-panel) / 96%) 100%
); );
box-shadow: box-shadow:
inset 0 1px 0 hsl(var(--glass-border) / 0.42), inset 0 1px 0 hsl(var(--glass-border) / 42%),
0 16px 30px -26px hsl(var(--primary) / 0.24); 0 16px 30px -26px hsl(var(--primary) / 24%);
} }
.chat-history-detail__message-chains { .chat-history-detail__message-chains {
@@ -448,23 +443,23 @@ async function handleLoadMore() {
.chat-history-detail__tool-panel { .chat-history-detail__tool-panel {
overflow: hidden; overflow: hidden;
border: 1px solid hsl(var(--divider-faint) / 0.24); background: hsl(var(--surface-panel) / 68%);
border: 1px solid hsl(var(--divider-faint) / 24%);
border-radius: 14px; border-radius: 14px;
background: hsl(var(--surface-panel) / 0.68); box-shadow: inset 0 1px 0 hsl(var(--glass-border) / 18%);
box-shadow: inset 0 1px 0 hsl(var(--glass-border) / 0.18);
} }
.chat-history-detail__tool-title { .chat-history-detail__tool-title {
display: flex; display: flex;
min-width: 0;
align-items: center;
gap: 8px; gap: 8px;
align-items: center;
min-width: 0;
padding-left: 6px; padding-left: 6px;
} }
.chat-history-detail__tool-name { .chat-history-detail__tool-name {
min-width: 0;
flex: 1; flex: 1;
min-width: 0;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@@ -472,13 +467,13 @@ async function handleLoadMore() {
.chat-history-detail__tool-status { .chat-history-detail__tool-status {
display: inline-flex; display: inline-flex;
align-items: center;
gap: 6px; gap: 6px;
align-items: center;
padding: 4px 8px; padding: 4px 8px;
border-radius: 999px;
background: hsl(var(--surface-contrast-soft) / 0.92);
font-size: 12px; font-size: 12px;
color: hsl(var(--text-muted)); color: hsl(var(--text-muted));
background: hsl(var(--surface-contrast-soft) / 92%);
border-radius: 999px;
} }
.chat-history-detail__markdown { .chat-history-detail__markdown {
@@ -488,9 +483,9 @@ async function handleLoadMore() {
} }
.chat-history-detail__markdown :deep(.markdown-body) { .chat-history-detail__markdown :deep(.markdown-body) {
background: transparent;
font-size: inherit; font-size: inherit;
line-height: inherit; line-height: inherit;
background: transparent;
} }
.chat-history-detail__markdown :deep(.markdown-body > :first-child) { .chat-history-detail__markdown :deep(.markdown-body > :first-child) {
@@ -508,8 +503,8 @@ async function handleLoadMore() {
.chat-history-detail__markdown :deep(pre) { .chat-history-detail__markdown :deep(pre) {
max-width: 100%; max-width: 100%;
overflow: auto;
margin-top: 0; margin-top: 0;
overflow: auto;
} }
.chat-history-detail__tool-panel :deep(.el-collapse-item__wrap) { .chat-history-detail__tool-panel :deep(.el-collapse-item__wrap) {
@@ -520,7 +515,7 @@ async function handleLoadMore() {
min-height: 44px; min-height: 44px;
padding-right: 14px; padding-right: 14px;
background: transparent; background: transparent;
border-bottom-color: hsl(var(--divider-faint) / 0.16); border-bottom-color: hsl(var(--divider-faint) / 16%);
} }
.chat-history-detail__message-bubble :deep(.el-collapse-item__content) { .chat-history-detail__message-bubble :deep(.el-collapse-item__content) {
@@ -550,8 +545,8 @@ async function handleLoadMore() {
.chat-history-detail__message-bubble, .chat-history-detail__message-bubble,
.chat-history-detail__message-meta { .chat-history-detail__message-meta {
max-width: 100%;
width: 100%; width: 100%;
max-width: 100%;
} }
} }
</style> </style>

View File

@@ -5,18 +5,23 @@ import type {
} from 'vue-element-plus-x/types/BubbleList'; } from 'vue-element-plus-x/types/BubbleList';
import type { TypewriterInstance } from 'vue-element-plus-x/types/Typewriter'; import type { TypewriterInstance } from 'vue-element-plus-x/types/Typewriter';
import { import type { ChatThinkingBlockStatus } from '@easyflow/common-ui';
ChatThinkingBlock,
type ChatThinkingBlockStatus,
} from '@easyflow/common-ui';
import type { BotInfo, ChatMessage } from '@easyflow/types'; import type { BotInfo, ChatMessage } from '@easyflow/types';
import { nextTick, onBeforeUnmount, onMounted, ref, watch, watchEffect } from 'vue'; import {
import { useRoute, useRouter } from 'vue-router'; nextTick,
onBeforeUnmount,
onMounted,
ref,
watch,
watchEffect,
} from 'vue';
import ElBubbleList from 'vue-element-plus-x/es/BubbleList/index.js'; import ElBubbleList from 'vue-element-plus-x/es/BubbleList/index.js';
import ElSender from 'vue-element-plus-x/es/Sender/index.js'; import ElSender from 'vue-element-plus-x/es/Sender/index.js';
import ElXMarkdown from 'vue-element-plus-x/es/XMarkdown/index.js'; import ElXMarkdown from 'vue-element-plus-x/es/XMarkdown/index.js';
import { useRoute, useRouter } from 'vue-router';
import { ChatThinkingBlock } from '@easyflow/common-ui';
import { IconifyIcon } from '@easyflow/icons'; import { IconifyIcon } from '@easyflow/icons';
import { $t } from '@easyflow/locales'; import { $t } from '@easyflow/locales';
import { useBotStore } from '@easyflow/stores'; import { useBotStore } from '@easyflow/stores';
@@ -51,8 +56,8 @@ import SendingIcon from '../icons/SendingIcon.vue';
type Think = { type Think = {
reasoning_content?: string; reasoning_content?: string;
thinkingStatus?: ChatThinkingBlockStatus;
thinkingExpanded?: boolean; thinkingExpanded?: boolean;
thinkingStatus?: ChatThinkingBlockStatus;
}; };
type Tool = { type Tool = {
@@ -168,7 +173,8 @@ const updateBackToBottomButtonVisible = () => {
showBackToBottomButton.value = false; showBackToBottomButton.value = false;
return; return;
} }
const { scrollTop, scrollHeight, clientHeight } = bubbleListScrollElement.value; const { scrollTop, scrollHeight, clientHeight } =
bubbleListScrollElement.value;
showBackToBottomButton.value = showBackToBottomButton.value =
scrollHeight - (scrollTop + clientHeight) > BACK_TO_BOTTOM_THRESHOLD; scrollHeight - (scrollTop + clientHeight) > BACK_TO_BOTTOM_THRESHOLD;
}; };
@@ -571,7 +577,6 @@ onBeforeUnmount(() => {
</ElCollapse> </ElCollapse>
</template> </template>
</template> </template>
</div> </div>
</template> </template>
<!-- 自定义头像 --> <!-- 自定义头像 -->
@@ -725,7 +730,7 @@ onBeforeUnmount(() => {
background: var(--el-bg-color-overlay); background: var(--el-bg-color-overlay);
border: 1px solid var(--el-border-color-light); border: 1px solid var(--el-border-color-light);
border-radius: 999px; border-radius: 999px;
box-shadow: 0 6px 10px rgba(0, 0, 0, 0.08); box-shadow: 0 6px 10px rgb(0 0 0 / 8%);
transition: all 0.2s ease; transition: all 0.2s ease;
} }
@@ -775,10 +780,10 @@ onBeforeUnmount(() => {
} }
:deep(.chat-tool-panel.el-collapse) { :deep(.chat-tool-panel.el-collapse) {
border: 1px solid hsl(var(--divider-faint) / 0.26); background: hsl(var(--surface-panel) / 70%);
border: 1px solid hsl(var(--divider-faint) / 26%);
border-radius: 14px; border-radius: 14px;
background: hsl(var(--surface-panel) / 0.7); box-shadow: inset 0 1px 0 hsl(var(--glass-border) / 20%);
box-shadow: inset 0 1px 0 hsl(var(--glass-border) / 0.2);
} }
:deep(.chat-tool-panel .el-collapse-item) { :deep(.chat-tool-panel .el-collapse-item) {
@@ -794,7 +799,7 @@ onBeforeUnmount(() => {
min-height: 44px; min-height: 44px;
padding-right: 14px; padding-right: 14px;
background: transparent; background: transparent;
border-bottom-color: hsl(var(--divider-faint) / 0.16); border-bottom-color: hsl(var(--divider-faint) / 16%);
} }
:deep(.chat-tool-panel .el-collapse-item__content) { :deep(.chat-tool-panel .el-collapse-item__content) {

View File

@@ -122,162 +122,6 @@ const collapseAll = () => {
</template> </template>
<style scoped> <style scoped>
.accordion-container {
max-width: 100%;
margin: 0 auto;
padding: 20px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.title {
text-align: center;
color: var(--el-text-color-secondary);
margin-bottom: 8px;
font-size: 2rem;
font-weight: 600;
}
.subtitle {
text-align: center;
color: var(--el-text-color-secondary);
margin-bottom: 30px;
font-size: 1.1rem;
}
/* 控制面板样式 */
.controls {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
padding: 20px;
background: var(--el-bg-color);
border-radius: 8px;
border: 1px solid #e9ecef;
}
.control-group {
display: flex;
align-items: center;
gap: 15px;
}
.checkbox-label {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: var(--el-text-color-secondary);
cursor: pointer;
}
.checkbox {
width: 16px;
height: 16px;
}
.control-btn {
padding: 8px 16px;
border: 1px solid #3498db;
background: var(--el-bg-color);
color: var(--el-text-color-secondary);
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s ease;
}
.control-btn:hover {
background: #3498db;
background: var(--el-color-primary-light-9);
}
/* 折叠面板列表 */
.accordion-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.accordion-item {
border: 1px solid #e1e5e9;
border-radius: 8px;
overflow: hidden;
background: var(--el-bg-color);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
}
.accordion-item:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.accordion-item--active {
border-color: #3498db;
}
/* 面板头部 */
.accordion-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 20px;
background: var(--el-bg-color);
cursor: pointer;
transition: background-color 0.3s ease;
user-select: none;
}
.accordion-header:hover {
background: var(--el-color-primary-light-9);
}
.accordion-title {
margin: 0;
font-size: 1.1rem;
font-weight: 500;
color: var(--el-text-color-secondary);
padding-left: 12px;
}
.accordion-icon {
transition: transform 0.3s ease;
color: #7f8c8d;
font-size: 12px;
}
.accordion-icon--rotated {
transform: rotate(180deg);
color: #3498db;
}
.accordion-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.4s ease;
background: var(--el-bg-color);
}
.accordion-content--open {
max-height: 200px;
}
.accordion-content-inner {
padding: 20px;
border-top: 1px solid #e1e5e9;
}
.accordion-content-inner p {
margin: 0;
line-height: 1.6;
color: var(--el-text-color-secondary);
font-size: 14px;
}
.column-header-container {
display: flex;
justify-content: space-between;
align-items: center;
}
/* 响应式设计 */ /* 响应式设计 */
@media (max-width: 768px) { @media (max-width: 768px) {
.accordion-container { .accordion-container {
@@ -306,4 +150,162 @@ const collapseAll = () => {
font-size: 1rem; font-size: 1rem;
} }
} }
.accordion-container {
max-width: 100%;
padding: 20px;
margin: 0 auto;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.title {
margin-bottom: 8px;
font-size: 2rem;
font-weight: 600;
color: var(--el-text-color-secondary);
text-align: center;
}
.subtitle {
margin-bottom: 30px;
font-size: 1.1rem;
color: var(--el-text-color-secondary);
text-align: center;
}
/* 控制面板样式 */
.controls {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px;
margin-bottom: 30px;
background: var(--el-bg-color);
border: 1px solid #e9ecef;
border-radius: 8px;
}
.control-group {
display: flex;
gap: 15px;
align-items: center;
}
.checkbox-label {
display: flex;
gap: 8px;
align-items: center;
font-size: 14px;
color: var(--el-text-color-secondary);
cursor: pointer;
}
.checkbox {
width: 16px;
height: 16px;
}
.control-btn {
padding: 8px 16px;
font-size: 14px;
color: var(--el-text-color-secondary);
cursor: pointer;
background: var(--el-bg-color);
border: 1px solid #3498db;
border-radius: 4px;
transition: all 0.3s ease;
}
.control-btn:hover {
background: #3498db;
background: var(--el-color-primary-light-9);
}
/* 折叠面板列表 */
.accordion-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.accordion-item {
overflow: hidden;
background: var(--el-bg-color);
border: 1px solid #e1e5e9;
border-radius: 8px;
box-shadow: 0 2px 8px rgb(0 0 0 / 5%);
transition: all 0.3s ease;
}
.accordion-item:hover {
box-shadow: 0 4px 12px rgb(0 0 0 / 10%);
}
.accordion-item--active {
border-color: #3498db;
}
/* 面板头部 */
.accordion-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
cursor: pointer;
user-select: none;
background: var(--el-bg-color);
transition: background-color 0.3s ease;
}
.accordion-header:hover {
background: var(--el-color-primary-light-9);
}
.accordion-title {
padding-left: 12px;
margin: 0;
font-size: 1.1rem;
font-weight: 500;
color: var(--el-text-color-secondary);
}
.accordion-icon {
font-size: 12px;
color: #7f8c8d;
transition: transform 0.3s ease;
}
.accordion-icon--rotated {
color: #3498db;
transform: rotate(180deg);
}
.accordion-content {
max-height: 0;
overflow: hidden;
background: var(--el-bg-color);
transition: max-height 0.4s ease;
}
.accordion-content--open {
max-height: 200px;
}
.accordion-content-inner {
padding: 20px;
border-top: 1px solid #e1e5e9;
}
.accordion-content-inner p {
margin: 0;
font-size: 14px;
line-height: 1.6;
color: var(--el-text-color-secondary);
}
.column-header-container {
display: flex;
align-items: center;
justify-content: space-between;
}
</style> </style>

View File

@@ -171,9 +171,9 @@ const handleDropdownClick = (button) => {
<style scoped> <style scoped>
.custom-header { .custom-header {
display: flex; display: flex;
gap: 16px;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 16px;
width: 100%; width: 100%;
} }
@@ -192,8 +192,8 @@ const handleDropdownClick = (button) => {
display: flex; display: flex;
flex: 1; flex: 1;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center;
gap: 12px; gap: 12px;
align-items: center;
} }
.search-middle { .search-middle {
@@ -208,20 +208,20 @@ const handleDropdownClick = (button) => {
.search-input :deep(.el-input__wrapper) { .search-input :deep(.el-input__wrapper) {
min-height: 40px; min-height: 40px;
background: hsl(var(--surface-contrast-soft) / 0.92); background: hsl(var(--surface-contrast-soft) / 92%);
border-radius: 14px; border-radius: 14px;
box-shadow: box-shadow:
inset 0 1px 0 hsl(var(--glass-border) / 0.44), inset 0 1px 0 hsl(var(--glass-border) / 44%),
0 10px 24px -24px hsl(var(--foreground) / 0.24); 0 10px 24px -24px hsl(var(--foreground) / 24%);
} }
.search-input :deep(.el-input__wrapper:hover), .search-input :deep(.el-input__wrapper:hover),
.search-input :deep(.el-input__wrapper.is-focus) { .search-input :deep(.el-input__wrapper.is-focus) {
background: hsl(var(--surface-subtle) / 0.98); background: hsl(var(--surface-subtle) / 98%);
box-shadow: box-shadow:
inset 0 1px 0 hsl(var(--glass-border) / 0.56), inset 0 1px 0 hsl(var(--glass-border) / 56%),
0 0 0 3px hsl(var(--primary) / 0.08), 0 0 0 3px hsl(var(--primary) / 8%),
0 12px 24px -24px hsl(var(--foreground) / 0.24); 0 12px 24px -24px hsl(var(--foreground) / 24%);
} }
.search-prefix { .search-prefix {
@@ -231,8 +231,8 @@ const handleDropdownClick = (button) => {
.header-right { .header-right {
flex-shrink: 0; flex-shrink: 0;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: flex-end;
gap: 12px; gap: 12px;
justify-content: flex-end;
} }
.header-right :deep(.el-button), .header-right :deep(.el-button),
@@ -241,24 +241,24 @@ const handleDropdownClick = (button) => {
height: 32px; height: 32px;
min-height: 32px; min-height: 32px;
padding-inline: 18px; padding-inline: 18px;
border-radius: 10px;
border-color: transparent; border-color: transparent;
border-radius: 10px;
box-shadow: none; box-shadow: none;
} }
.header-right :deep(.el-button:not(.el-button--primary)), .header-right :deep(.el-button:not(.el-button--primary)),
.search-group :deep(.el-button:not(.el-button--primary)) { .search-group :deep(.el-button:not(.el-button--primary)) {
color: hsl(var(--text-strong)); color: hsl(var(--text-strong));
background: hsl(var(--surface-contrast-soft) / 0.86); background: hsl(var(--surface-contrast-soft) / 86%);
border-color: transparent; border-color: transparent;
box-shadow: box-shadow:
inset 0 1px 0 hsl(var(--glass-border) / 0.34), inset 0 1px 0 hsl(var(--glass-border) / 34%),
0 10px 24px -24px hsl(var(--foreground) / 0.2); 0 10px 24px -24px hsl(var(--foreground) / 20%);
} }
.header-right :deep(.el-button--primary), .header-right :deep(.el-button--primary),
.search-group :deep(.el-button--primary) { .search-group :deep(.el-button--primary) {
box-shadow: 0 16px 28px -22px hsl(var(--primary) / 0.48); box-shadow: 0 16px 28px -22px hsl(var(--primary) / 48%);
} }
.dropdown-label { .dropdown-label {
@@ -268,8 +268,8 @@ const handleDropdownClick = (button) => {
@media (max-width: 768px) { @media (max-width: 768px) {
.custom-header { .custom-header {
flex-direction: column; flex-direction: column;
align-items: stretch;
gap: 12px; gap: 12px;
align-items: stretch;
} }
.header-right { .header-right {

View File

@@ -6,9 +6,10 @@ import { preferences } from '@easyflow/preferences';
import { ElEmpty } from 'element-plus'; import { ElEmpty } from 'element-plus';
import { JsonViewer } from 'vue3-json-viewer'; import { JsonViewer } from 'vue3-json-viewer';
import 'vue3-json-viewer/dist/vue3-json-viewer.css';
import { getEmptyStateImageUrl } from '#/utils/assets'; import { getEmptyStateImageUrl } from '#/utils/assets';
import 'vue3-json-viewer/dist/vue3-json-viewer.css';
defineProps({ defineProps({
value: { value: {
required: true, required: true,

View File

@@ -84,14 +84,25 @@ const resolvedPrimaryAction = computed(() => {
return props.primaryAction; return props.primaryAction;
}); });
function resolveActionPlacement(
action: ActionButton,
index: number,
): ActionPlacement {
if (action.placement) {
return action.placement;
}
if (resolvedPrimaryAction.value) {
return 'menu';
}
return index < 3 ? 'inline' : 'menu';
}
const resolvedActions = computed<ResolvedActionButton[]>(() => { const resolvedActions = computed<ResolvedActionButton[]>(() => {
return props.actions return props.actions
.filter((action) => hasPermission(action.permission)) .filter((action) => hasPermission(action.permission))
.map((action, index) => ({ .map((action, index) => ({
...action, ...action,
placement: placement: resolveActionPlacement(action, index),
action.placement ||
(resolvedPrimaryAction.value ? 'menu' : index < 3 ? 'inline' : 'menu'),
tone: tone:
action.tone || action.tone ||
(action.className?.includes('danger') ? 'danger' : 'default'), (action.className?.includes('danger') ? 'danger' : 'default'),
@@ -111,8 +122,8 @@ const menuActions = computed(() => {
const showFooter = computed(() => { const showFooter = computed(() => {
return Boolean( return Boolean(
resolvedPrimaryAction.value || resolvedPrimaryAction.value ||
inlineActions.value.length || inlineActions.value.length > 0 ||
menuActions.value.length, menuActions.value.length > 0,
); );
}); });
@@ -132,10 +143,8 @@ function handleActionClick(event: Event, action: ActionButton, item: any) {
v-for="(item, index) in props.data" v-for="(item, index) in props.data"
:key="item.id ?? index" :key="item.id ?? index"
shadow="never" shadow="never"
:class="[ class="card-item"
'card-item', :class="[{ 'card-item--interactive': resolvedPrimaryAction }]"
{ 'card-item--interactive': resolvedPrimaryAction },
]"
:role="resolvedPrimaryAction ? 'button' : undefined" :role="resolvedPrimaryAction ? 'button' : undefined"
:tabindex="resolvedPrimaryAction ? 0 : undefined" :tabindex="resolvedPrimaryAction ? 0 : undefined"
@click="handlePrimaryAction(item)" @click="handlePrimaryAction(item)"
@@ -201,7 +210,7 @@ function handleActionClick(event: Event, action: ActionButton, item: any) {
</div> </div>
<div <div
v-if="inlineActions.length || menuActions.length" v-if="inlineActions.length > 0 || menuActions.length > 0"
class="card-actions" class="card-actions"
@click.stop @click.stop
> >

View File

@@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type {CSSProperties} from 'vue'; import type { CSSProperties } from 'vue';
import {computed, useSlots} from 'vue';
import { computed, useSlots } from 'vue';
interface Props { interface Props {
contentPadding?: number | string; contentPadding?: number | string;
@@ -67,8 +68,8 @@ const contentStyle = computed((): CSSProperties => {
display: flex; display: flex;
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
min-height: 0;
gap: 16px; gap: 16px;
min-height: 0;
} }
.list-page-shell.is-dense { .list-page-shell.is-dense {
@@ -78,9 +79,9 @@ const contentStyle = computed((): CSSProperties => {
.list-page-shell__toolbar { .list-page-shell__toolbar {
position: relative; position: relative;
display: flex; display: flex;
gap: 16px;
align-items: flex-start; align-items: flex-start;
justify-content: space-between; justify-content: space-between;
gap: 16px;
padding: 8px 6px 2px; padding: 8px 6px 2px;
background: transparent; background: transparent;
border: none; border: none;
@@ -92,8 +93,8 @@ const contentStyle = computed((): CSSProperties => {
top: 12px; top: 12px;
z-index: 5; z-index: 5;
padding: 10px 10px 6px; padding: 10px 10px 6px;
background: hsl(var(--glass-tint) / 0.7); background: hsl(var(--glass-tint) / 70%);
border: 1px solid hsl(var(--glass-border) / 0.44); border: 1px solid hsl(var(--glass-border) / 44%);
border-radius: 20px; border-radius: 20px;
box-shadow: var(--shadow-toolbar); box-shadow: var(--shadow-toolbar);
backdrop-filter: blur(var(--glass-blur)) saturate(155%); backdrop-filter: blur(var(--glass-blur)) saturate(155%);
@@ -110,40 +111,41 @@ const contentStyle = computed((): CSSProperties => {
.list-page-shell__content { .list-page-shell__content {
--list-page-shell-content-padding: 0px; --list-page-shell-content-padding: 0px;
position: relative;
display: flex; display: flex;
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
min-height: 0; min-height: 0;
position: relative;
overflow: hidden;
padding: var(--list-page-shell-content-padding); padding: var(--list-page-shell-content-padding);
overflow: hidden;
background: linear-gradient( background: linear-gradient(
180deg, 180deg,
hsl(var(--glass-border) / 0.84) 0%, hsl(var(--glass-border) / 84%) 0%,
hsl(var(--surface-panel) / 0.94) 28%, hsl(var(--surface-panel) / 94%) 28%,
hsl(var(--surface-panel) / 0.97) 100% hsl(var(--surface-panel) / 97%) 100%
); );
border: 1px solid hsl(var(--glass-border) / 0.58); border: 1px solid hsl(var(--glass-border) / 58%);
border-radius: 24px; border-radius: 24px;
box-shadow: box-shadow:
inset 0 1px 0 hsl(var(--glass-border) / 0.72), inset 0 1px 0 hsl(var(--glass-border) / 72%),
0 24px 54px -42px hsl(var(--primary) / 0.22), 0 24px 54px -42px hsl(var(--primary) / 22%),
0 18px 42px -34px hsl(var(--foreground) / 0.1); 0 18px 42px -34px hsl(var(--foreground) / 10%);
backdrop-filter: blur(calc(var(--glass-blur) * 0.7)) saturate(145%); backdrop-filter: blur(calc(var(--glass-blur) * 0.7)) saturate(145%);
} }
.list-page-shell.is-subtle .list-page-shell__content { .list-page-shell.is-subtle .list-page-shell__content {
background: linear-gradient( background: linear-gradient(
180deg, 180deg,
hsl(var(--glass-tint) / 0.84) 0%, hsl(var(--glass-tint) / 84%) 0%,
hsl(var(--surface-contrast-soft) / 0.94) 100% hsl(var(--surface-contrast-soft) / 94%) 100%
); );
box-shadow: none; box-shadow: none;
} }
.list-page-shell.is-plain .list-page-shell__content { .list-page-shell.is-plain .list-page-shell__content {
background: hsl(var(--surface-panel) / 0.96); background: hsl(var(--surface-panel) / 96%);
border: 1px solid hsl(var(--divider-faint) / 0.58); border: 1px solid hsl(var(--divider-faint) / 58%);
border-radius: 20px; border-radius: 20px;
box-shadow: none; box-shadow: none;
backdrop-filter: none; backdrop-filter: none;
@@ -162,14 +164,10 @@ const contentStyle = computed((): CSSProperties => {
background: background:
radial-gradient( radial-gradient(
ellipse 84% 72% at 10% 0%, ellipse 84% 72% at 10% 0%,
hsl(var(--nav-ambient) / 0.18) 0%, hsl(var(--nav-ambient) / 18%) 0%,
transparent 68% transparent 68%
), ),
linear-gradient( linear-gradient(180deg, hsl(var(--nav-flow-trace) / 8%) 0%, transparent 78%);
180deg,
hsl(var(--nav-flow-trace) / 0.08) 0%,
transparent 78%
);
} }
.list-page-shell__content > * { .list-page-shell__content > * {
@@ -195,6 +193,7 @@ const contentStyle = computed((): CSSProperties => {
--el-table-border-color: hsl(var(--table-row-border)); --el-table-border-color: hsl(var(--table-row-border));
--el-table-current-row-bg-color: hsl(var(--table-row-hover)); --el-table-current-row-bg-color: hsl(var(--table-row-hover));
--el-fill-color-blank: transparent; --el-fill-color-blank: transparent;
background: transparent; background: transparent;
} }
@@ -216,8 +215,8 @@ const contentStyle = computed((): CSSProperties => {
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
color: hsl(var(--text-strong)); color: hsl(var(--text-strong));
background: hsl(var(--table-header-bg) / 0.86); background: hsl(var(--table-header-bg) / 86%);
border-bottom: 1px solid hsl(var(--divider-faint) / 0.38); border-bottom: 1px solid hsl(var(--divider-faint) / 38%);
} }
.list-page-shell__content :deep(.el-table th.el-table__cell:first-child) { .list-page-shell__content :deep(.el-table th.el-table__cell:first-child) {
@@ -232,7 +231,7 @@ const contentStyle = computed((): CSSProperties => {
.list-page-shell__content :deep(.el-table--border .el-table__cell) { .list-page-shell__content :deep(.el-table--border .el-table__cell) {
padding: 14px 0; padding: 14px 0;
border-right: none; border-right: none;
border-bottom: 1px solid hsl(var(--divider-faint) / 0.46); border-bottom: 1px solid hsl(var(--divider-faint) / 46%);
} }
.list-page-shell__content :deep(.el-table__row:hover > td.el-table__cell) { .list-page-shell__content :deep(.el-table__row:hover > td.el-table__cell) {

View File

@@ -138,7 +138,7 @@ onMounted(() => {
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
min-height: 0; min-height: 0;
padding: 18px 20px 18px; padding: 18px 20px;
} }
.page-data-container__body { .page-data-container__body {

View File

@@ -114,6 +114,7 @@ const isSvgString = (icon: any) => {
v-if="item.icon" v-if="item.icon"
class="ml-[-3px] flex items-center justify-center" class="ml-[-3px] flex items-center justify-center"
> >
<!-- eslint-disable vue/no-v-html -->
<div <div
v-if="isSvgString(item.icon)" v-if="isSvgString(item.icon)"
v-html="item.icon" v-html="item.icon"
@@ -127,6 +128,7 @@ const isSvgString = (icon: any) => {
}" }"
class="svg-container" class="svg-container"
></div> ></div>
<!-- eslint-enable vue/no-v-html -->
<img <img
v-else-if=" v-else-if="
typeof item.icon === 'string' && !isComponent(item.icon) typeof item.icon === 'string' && !isComponent(item.icon)

View File

@@ -1,6 +1,7 @@
import {mount} from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { describe, expect, it, vi } from 'vitest';
import {describe, expect, it, vi} from 'vitest';
import CardList from '../CardList.vue'; import CardList from '../CardList.vue';
const { hasAccessByCodes } = vi.hoisted(() => ({ const { hasAccessByCodes } = vi.hoisted(() => ({
@@ -13,7 +14,7 @@ vi.mock('@easyflow/access', () => ({
}), }),
})); }));
describe('CardList', () => { describe('cardList', () => {
function mountCardList(props: Record<string, unknown>) { function mountCardList(props: Record<string, unknown>) {
return mount(CardList, { return mount(CardList, {
props: { props: {

View File

@@ -233,14 +233,14 @@ onMounted(() => {
v-loading="loading" v-loading="loading"
:element-loading-text="loadingText" :element-loading-text="loadingText"
> >
<template #default="{ node, data }"> <template #default="{ node, data: itemData }">
<span class="tree-node"> <span class="tree-node">
<span class="node-label">{{ $t(node.label) }}</span> <span class="node-label">{{ $t(node.label) }}</span>
<span <span
v-if="showCount && data[defaultProps.children]" v-if="showCount && itemData[defaultProps.children]"
class="node-count" class="node-count"
> >
({{ data[defaultProps.children].length }}) ({{ itemData[defaultProps.children].length }})
</span> </span>
</span> </span>
</template> </template>
@@ -278,17 +278,17 @@ onMounted(() => {
.tree-node { .tree-node {
display: flex; display: flex;
align-items: center;
gap: 8px; gap: 8px;
align-items: center;
min-width: 0; min-width: 0;
} }
.node-label { .node-label {
overflow: hidden; overflow: hidden;
color: var(--el-text-color-primary); text-overflow: ellipsis;
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
text-overflow: ellipsis; color: var(--el-text-color-primary);
white-space: nowrap; white-space: nowrap;
} }
@@ -299,22 +299,22 @@ onMounted(() => {
min-width: 22px; min-width: 22px;
height: 20px; height: 20px;
padding: 0 6px; padding: 0 6px;
color: var(--el-text-color-secondary);
font-size: 12px; font-size: 12px;
line-height: 1; line-height: 1;
color: var(--el-text-color-secondary);
background: var(--el-fill-color); background: var(--el-fill-color);
border-radius: 999px; border-radius: 999px;
} }
:deep(.el-tree) { :deep(.el-tree) {
background: transparent;
color: inherit; color: inherit;
background: transparent;
} }
:deep(.el-tree-node__content) { :deep(.el-tree-node__content) {
height: 38px; height: 38px;
margin-bottom: 4px;
padding: 0 10px; padding: 0 10px;
margin-bottom: 4px;
border-radius: 10px; border-radius: 10px;
transition: transition:
background-color 0.18s ease, background-color 0.18s ease,

View File

@@ -9,7 +9,10 @@ import { useAccessStore } from '@easyflow/stores';
import { UploadFilled } from '@element-plus/icons-vue'; import { UploadFilled } from '@element-plus/icons-vue';
import { ElIcon, ElMessage, ElUpload } from 'element-plus'; import { ElIcon, ElMessage, ElUpload } from 'element-plus';
import { normalizeUploadError, resolveUploadPath } from '#/utils/upload-response'; import {
normalizeUploadError,
resolveUploadPath,
} from '#/utils/upload-response';
const props = defineProps({ const props = defineProps({
action: { action: {

View File

@@ -8,8 +8,11 @@ import { useAccessStore } from '@easyflow/stores';
import { ElButton, ElMessage, ElUpload } from 'element-plus'; import { ElButton, ElMessage, ElUpload } from 'element-plus';
import { normalizeUploadError, resolveUploadPath } from '#/utils/upload-response';
import { $t } from '#/locales'; import { $t } from '#/locales';
import {
normalizeUploadError,
resolveUploadPath,
} from '#/utils/upload-response';
const props = defineProps({ const props = defineProps({
action: { action: {

View File

@@ -10,7 +10,10 @@ import { Plus } from '@element-plus/icons-vue';
import { ElIcon, ElImage, ElMessage, ElUpload } from 'element-plus'; import { ElIcon, ElImage, ElMessage, ElUpload } from 'element-plus';
import { $t } from '#/locales'; import { $t } from '#/locales';
import { normalizeUploadError, resolveUploadPath } from '#/utils/upload-response'; import {
normalizeUploadError,
resolveUploadPath,
} from '#/utils/upload-response';
const props = defineProps({ const props = defineProps({
action: { action: {
@@ -134,20 +137,20 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
<style> <style>
.avatar-uploader .el-upload { .avatar-uploader .el-upload {
width: var(--avatar-size); position: relative;
height: var(--avatar-size);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
position: relative; width: var(--avatar-size);
height: var(--avatar-size);
overflow: hidden; overflow: hidden;
cursor: pointer; cursor: pointer;
border: 1px solid hsl(var(--input) / 0.92); background: hsl(var(--modal-surface-strong) / 92%);
border: 1px solid hsl(var(--input) / 92%);
border-radius: 50%; border-radius: 50%;
background: hsl(var(--modal-surface-strong) / 0.92);
box-shadow: box-shadow:
inset 0 1px 0 hsl(0 0% 100% / 0.72), inset 0 1px 0 hsl(0deg 0% 100% / 72%),
0 16px 28px -24px hsl(var(--foreground) / 0.24); 0 16px 28px -24px hsl(var(--foreground) / 24%);
transition: transition:
transform var(--el-transition-duration-fast), transform var(--el-transition-duration-fast),
border-color var(--el-transition-duration-fast), border-color var(--el-transition-duration-fast),
@@ -155,26 +158,26 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
} }
.avatar-uploader .el-upload:hover { .avatar-uploader .el-upload:hover {
border-color: hsl(var(--primary) / 0.52); border-color: hsl(var(--primary) / 52%);
transform: translateY(-1px);
box-shadow: box-shadow:
inset 0 1px 0 hsl(0 0% 100% / 0.76), inset 0 1px 0 hsl(0deg 0% 100% / 76%),
0 20px 36px -26px hsl(var(--modal-preview-glow) / 0.3); 0 20px 36px -26px hsl(var(--modal-preview-glow) / 30%);
transform: translateY(-1px);
} }
.avatar-uploader--soft-panel .el-upload { .avatar-uploader--soft-panel .el-upload {
background: background:
radial-gradient( radial-gradient(
circle at top, circle at top,
hsl(var(--modal-preview-glow) / 0.14), hsl(var(--modal-preview-glow) / 14%),
transparent 60% transparent 60%
), ),
linear-gradient( linear-gradient(
145deg, 145deg,
hsl(var(--modal-preview-surface) / 0.98), hsl(var(--modal-preview-surface) / 98%),
hsl(var(--modal-preview-surface-strong) / 0.9) hsl(var(--modal-preview-surface-strong) / 90%)
); );
border-color: hsl(var(--modal-preview-border) / 0.9); border-color: hsl(var(--modal-preview-border) / 90%);
} }
.avatar-uploader--rounded .el-upload { .avatar-uploader--rounded .el-upload {

View File

@@ -2,7 +2,10 @@ import type { Language } from 'element-plus/es/locale';
import type { App } from 'vue'; import type { App } from 'vue';
import type { LocaleSetupOptions, SupportedLanguagesType } from '@easyflow/locales'; import type {
LocaleSetupOptions,
SupportedLanguagesType,
} from '@easyflow/locales';
import { ref } from 'vue'; import { ref } from 'vue';

View File

@@ -1,20 +1,20 @@
{ {
"id": "Id", "id": "Id",
"deptId": "DeptId", "deptId": "DeptId",
"tenantId": "TenantId", "tenantId": "TenantId",
"resourceType": "ResourceType", "resourceType": "ResourceType",
"resourceName": "ResourceName", "resourceName": "ResourceName",
"suffix": "Suffix", "suffix": "Suffix",
"resourceUrl": "ResourceUrl", "resourceUrl": "ResourceUrl",
"origin": "Origin", "origin": "Origin",
"status": "Status", "status": "Status",
"created": "Created", "created": "Created",
"createdBy": "CreatedBy", "createdBy": "CreatedBy",
"modified": "Modified", "modified": "Modified",
"modifiedBy": "ModifiedBy", "modifiedBy": "ModifiedBy",
"options": "Options", "options": "Options",
"isDeleted": "IsDeleted", "isDeleted": "IsDeleted",
"fileSize": "FileSize", "fileSize": "FileSize",
"categoryId": "Category", "categoryId": "Category",
"choose": "Choose" "choose": "Choose"
} }

View File

@@ -1,10 +1,10 @@
{ {
"id": "Id", "id": "Id",
"categoryName": "CategoryName", "categoryName": "CategoryName",
"sortNo": "SortNo", "sortNo": "SortNo",
"created": "Created", "created": "Created",
"createdBy": "CreatedBy", "createdBy": "CreatedBy",
"modified": "Modified", "modified": "Modified",
"modifiedBy": "ModifiedBy", "modifiedBy": "ModifiedBy",
"status": "Status" "status": "Status"
} }

View File

@@ -1,25 +1,25 @@
{ {
"id": "Id", "id": "Id",
"execKey": "ExecKey", "execKey": "ExecKey",
"workflowId": "WorkflowId", "workflowId": "WorkflowId",
"title": "Title", "title": "Title",
"description": "Description", "description": "Description",
"input": "Input", "input": "Input",
"output": "Output", "output": "Output",
"workflowJson": "WorkflowJson", "workflowJson": "WorkflowJson",
"startTime": "StartTime", "startTime": "StartTime",
"endTime": "EndTime", "endTime": "EndTime",
"tokens": "Tokens", "tokens": "Tokens",
"status": "Status", "status": "Status",
"createdKey": "CreatedKey", "createdKey": "CreatedKey",
"createdBy": "CreatedBy", "createdBy": "CreatedBy",
"errorInfo": "ErrorInfo", "errorInfo": "ErrorInfo",
"moduleName": "ExecuteRecords", "moduleName": "ExecuteRecords",
"execTime": "TimeConsuming", "execTime": "TimeConsuming",
"status1": "Running", "status1": "Running",
"status5": "Suspend", "status5": "Suspend",
"status10": "Error", "status10": "Error",
"status20": "Success", "status20": "Success",
"status21": "Failed", "status21": "Failed",
"status22": "Cancel" "status22": "Cancel"
} }

View File

@@ -1,22 +1,22 @@
{ {
"id": "Id", "id": "Id",
"recordId": "RecordId", "recordId": "RecordId",
"execKey": "ExecKey", "execKey": "ExecKey",
"nodeId": "NodeId", "nodeId": "NodeId",
"nodeName": "NodeName", "nodeName": "NodeName",
"input": "Input", "input": "Input",
"output": "Output", "output": "Output",
"nodeData": "NodeData", "nodeData": "NodeData",
"startTime": "StartTime", "startTime": "StartTime",
"endTime": "EndTime", "endTime": "EndTime",
"tokens": "Tokens", "tokens": "Tokens",
"status": "Status", "status": "Status",
"errorInfo": "ErrorInfo", "errorInfo": "ErrorInfo",
"moduleName": "Steps", "moduleName": "Steps",
"execTime": "TimeConsuming", "execTime": "TimeConsuming",
"status1": "Running", "status1": "Running",
"status6": "Suspend", "status6": "Suspend",
"status10": "Error", "status10": "Error",
"status20": "Success", "status20": "Success",
"status21": "Failed" "status21": "Failed"
} }

View File

@@ -1,33 +1,33 @@
{ {
"title": "DataCenter", "title": "DataCenter",
"id": "Id", "id": "Id",
"deptId": "DeptId", "deptId": "DeptId",
"tenantId": "TenantId", "tenantId": "TenantId",
"tableName": "TableName", "tableName": "TableName",
"tableDesc": "TableDesc", "tableDesc": "TableDesc",
"actualTable": "ActualTable", "actualTable": "ActualTable",
"status": "Status", "status": "Status",
"created": "Created", "created": "Created",
"createdBy": "CreatedBy", "createdBy": "CreatedBy",
"modified": "Modified", "modified": "Modified",
"modifiedBy": "ModifiedBy", "modifiedBy": "ModifiedBy",
"options": "Options", "options": "Options",
"fields": "Fields", "fields": "Fields",
"fieldName": "FiledName", "fieldName": "FiledName",
"fieldDesc": "Description", "fieldDesc": "Description",
"fieldType": "Type", "fieldType": "Type",
"required": "Required", "required": "Required",
"noFieldError": "At least one field is required", "noFieldError": "At least one field is required",
"fieldInfoError": "Field info is not completed", "fieldInfoError": "Field info is not completed",
"nameRegx": "It can only contain lowercase letters, numbers, and underscores, and must start with a lowercase letter", "nameRegx": "It can only contain lowercase letters, numbers, and underscores, and must start with a lowercase letter",
"structure": "TableStructure", "structure": "TableStructure",
"data": "Data", "data": "Data",
"uploadTitle": "Click to upload", "uploadTitle": "Click to upload",
"uploadDesc": "Choose an excel file to upload, file size limit 10MB.", "uploadDesc": "Choose an excel file to upload, file size limit 10MB.",
"downloadTemplate": "Download template", "downloadTemplate": "Download template",
"importComplete": "Import is completed", "importComplete": "Import is completed",
"totalNum": "Total Count", "totalNum": "Total Count",
"successNum": "Success Count", "successNum": "Success Count",
"failNum": "Fail Count", "failNum": "Fail Count",
"failList": "Fail List" "failList": "Fail List"
} }

View File

@@ -1,13 +1,13 @@
{ {
"id": "Id", "id": "Id",
"tableId": "TableId", "tableId": "TableId",
"fieldName": "FieldName", "fieldName": "FieldName",
"fieldDesc": "FieldDesc", "fieldDesc": "FieldDesc",
"fieldType": "FieldType", "fieldType": "FieldType",
"required": "Required", "required": "Required",
"created": "Created", "created": "Created",
"createdBy": "CreatedBy", "createdBy": "CreatedBy",
"modified": "Modified", "modified": "Modified",
"modifiedBy": "ModifiedBy", "modifiedBy": "ModifiedBy",
"options": "Options" "options": "Options"
} }

View File

@@ -1,6 +1,6 @@
{ {
"id": "Id", "id": "Id",
"requestInterface": "RequestInterface", "requestInterface": "RequestInterface",
"title": "Title", "title": "Title",
"addPermission": "AddRequestInterface" "addPermission": "AddRequestInterface"
} }

View File

@@ -1,17 +1,17 @@
{ {
"root": "Root", "root": "Root",
"id": "Id", "id": "Id",
"tenantId": "TenantId", "tenantId": "TenantId",
"parentId": "Parent", "parentId": "Parent",
"ancestors": "Ancestors", "ancestors": "Ancestors",
"deptName": "DeptName", "deptName": "DeptName",
"deptCode": "DeptCode", "deptCode": "DeptCode",
"sortNo": "SortNo", "sortNo": "SortNo",
"status": "Status", "status": "Status",
"created": "Created", "created": "Created",
"createdBy": "CreatedBy", "createdBy": "CreatedBy",
"modified": "Modified", "modified": "Modified",
"modifiedBy": "ModifiedBy", "modifiedBy": "ModifiedBy",
"remark": "Remark", "remark": "Remark",
"isDeleted": "IsDeleted" "isDeleted": "IsDeleted"
} }

View File

@@ -1,12 +1,12 @@
{ {
"id": "Id", "id": "Id",
"name": "Name", "name": "Name",
"code": "Code", "code": "Code",
"description": "Description", "description": "Description",
"dictType": "DictType", "dictType": "DictType",
"sortNo": "SortNo", "sortNo": "SortNo",
"status": "Status", "status": "Status",
"options": "Options", "options": "Options",
"created": "Created", "created": "Created",
"modified": "Modified" "modified": "Modified"
} }

View File

@@ -1,23 +1,23 @@
{ {
"id": "Id", "id": "Id",
"deptId": "DeptId", "deptId": "DeptId",
"tenantId": "TenantId", "tenantId": "TenantId",
"jobName": "JobName", "jobName": "JobName",
"jobType": "JobType", "jobType": "JobType",
"jobParams": "JobParams", "jobParams": "JobParams",
"cronExpression": "CronExpression", "cronExpression": "CronExpression",
"allowConcurrent": "AllowConcurrent", "allowConcurrent": "AllowConcurrent",
"misfirePolicy": "MisfirePolicy", "misfirePolicy": "MisfirePolicy",
"options": "Options", "options": "Options",
"status": "Status", "status": "Status",
"created": "Created", "created": "Created",
"createdBy": "CreatedBy", "createdBy": "CreatedBy",
"modified": "Modified", "modified": "Modified",
"modifiedBy": "ModifiedBy", "modifiedBy": "ModifiedBy",
"remark": "Remark", "remark": "Remark",
"isDeleted": "IsDeleted", "isDeleted": "IsDeleted",
"workflow": "Workflow", "workflow": "Workflow",
"beanMethod": "BeanMethod", "beanMethod": "BeanMethod",
"javaMethod": "JavaMethod", "javaMethod": "JavaMethod",
"example": "example" "example": "example"
} }

View File

@@ -1,14 +1,14 @@
{ {
"id": "Id", "id": "Id",
"accountId": "AccountId", "accountId": "AccountId",
"actionName": "ActionName", "actionName": "ActionName",
"actionType": "ActionType", "actionType": "ActionType",
"actionClass": "ActionClass", "actionClass": "ActionClass",
"actionMethod": "ActionMethod", "actionMethod": "ActionMethod",
"actionUrl": "ActionUrl", "actionUrl": "ActionUrl",
"actionIp": "ActionIp", "actionIp": "ActionIp",
"actionParams": "ActionParams", "actionParams": "ActionParams",
"actionBody": "ActionBody", "actionBody": "ActionBody",
"status": "Status", "status": "Status",
"created": "Created" "created": "Created"
} }

View File

@@ -1,20 +1,20 @@
{ {
"root":"Top", "root": "Top",
"id": "Id", "id": "Id",
"parentId": "Parent", "parentId": "Parent",
"menuType": "MenuType", "menuType": "MenuType",
"menuTitle": "MenuTitle", "menuTitle": "MenuTitle",
"menuUrl": "MenuUrl", "menuUrl": "MenuUrl",
"component": "Component", "component": "Component",
"menuIcon": "MenuIcon", "menuIcon": "MenuIcon",
"isShow": "IsShow", "isShow": "IsShow",
"permissionTag": "PermissionTag", "permissionTag": "PermissionTag",
"sortNo": "SortNo", "sortNo": "SortNo",
"status": "Status", "status": "Status",
"created": "Created", "created": "Created",
"createdBy": "CreatedBy", "createdBy": "CreatedBy",
"modified": "Modified", "modified": "Modified",
"modifiedBy": "ModifiedBy", "modifiedBy": "ModifiedBy",
"remark": "Remark", "remark": "Remark",
"isDeleted": "IsDeleted" "isDeleted": "IsDeleted"
} }

View File

@@ -1,22 +1,22 @@
{ {
"id": "Id", "id": "Id",
"tenantId": "TenantId", "tenantId": "TenantId",
"roleName": "RoleName", "roleName": "RoleName",
"roleKey": "RoleKey", "roleKey": "RoleKey",
"status": "Status", "status": "Status",
"created": "Created", "created": "Created",
"createdBy": "CreatedBy", "createdBy": "CreatedBy",
"modified": "Modified", "modified": "Modified",
"modifiedBy": "ModifiedBy", "modifiedBy": "ModifiedBy",
"remark": "Remark", "remark": "Remark",
"isDeleted": "IsDeleted", "isDeleted": "IsDeleted",
"menuPermission": "MenuPermission", "menuPermission": "MenuPermission",
"dataPermission": "DataPermission", "dataPermission": "DataPermission",
"categoryPermission": "CategoryPermission", "categoryPermission": "CategoryPermission",
"categoryPermissionHint": "Deny by default. Applies to resource visibility and selectors/binders only.", "categoryPermissionHint": "Deny by default. Applies to resource visibility and selectors/binders only.",
"categoryScopeAll": "AllCategories", "categoryScopeAll": "AllCategories",
"categoryScopeCustom": "CustomCategories", "categoryScopeCustom": "CustomCategories",
"categoryScopePlaceholder": "Select categories", "categoryScopePlaceholder": "Select categories",
"checkStrictlyTrue": "Linked", "checkStrictlyTrue": "Linked",
"checkStrictlyFalse": "NotLinked" "checkStrictlyFalse": "NotLinked"
} }

View File

@@ -1,20 +1,20 @@
{ {
"id": "主键", "id": "主键",
"deptId": "部门ID", "deptId": "部门ID",
"tenantId": "租户ID", "tenantId": "租户ID",
"resourceType": "素材类型", "resourceType": "素材类型",
"resourceName": "素材名称", "resourceName": "素材名称",
"suffix": "后缀", "suffix": "后缀",
"resourceUrl": "素材地址", "resourceUrl": "素材地址",
"origin": "素材来源", "origin": "素材来源",
"status": "数据状态", "status": "数据状态",
"created": "创建时间", "created": "创建时间",
"createdBy": "创建者", "createdBy": "创建者",
"modified": "修改时间", "modified": "修改时间",
"modifiedBy": "修改者", "modifiedBy": "修改者",
"options": "扩展项", "options": "扩展项",
"isDeleted": "删除标识", "isDeleted": "删除标识",
"fileSize": "文件大小", "fileSize": "文件大小",
"categoryId": "分类", "categoryId": "分类",
"choose": "选择素材" "choose": "选择素材"
} }

View File

@@ -1,10 +1,10 @@
{ {
"id": "主键", "id": "主键",
"categoryName": "分类名称", "categoryName": "分类名称",
"sortNo": "排序", "sortNo": "排序",
"created": "创建时间", "created": "创建时间",
"createdBy": "创建者", "createdBy": "创建者",
"modified": "修改时间", "modified": "修改时间",
"modifiedBy": "修改者", "modifiedBy": "修改者",
"status": "数据状态" "status": "数据状态"
} }

View File

@@ -1,25 +1,25 @@
{ {
"id": "主键", "id": "主键",
"execKey": "执行标识", "execKey": "执行标识",
"workflowId": "工作流ID", "workflowId": "工作流ID",
"title": "标题", "title": "标题",
"description": "描述", "description": "描述",
"input": "输入", "input": "输入",
"output": "输出", "output": "输出",
"workflowJson": "工作流执行时的配置", "workflowJson": "工作流执行时的配置",
"startTime": "开始时间", "startTime": "开始时间",
"endTime": "结束时间", "endTime": "结束时间",
"tokens": "消耗总token", "tokens": "消耗总token",
"status": "状态", "status": "状态",
"createdKey": "执行人标识[有可能是用户|外部|定时任务等情况]", "createdKey": "执行人标识[有可能是用户|外部|定时任务等情况]",
"createdBy": "执行人", "createdBy": "执行人",
"errorInfo": "错误信息", "errorInfo": "错误信息",
"moduleName": "执行记录", "moduleName": "执行记录",
"execTime": "耗时", "execTime": "耗时",
"status1": "运行中", "status1": "运行中",
"status5": "挂起", "status5": "挂起",
"status10": "错误", "status10": "错误",
"status20": "成功", "status20": "成功",
"status21": "失败", "status21": "失败",
"status22": "取消" "status22": "取消"
} }

View File

@@ -1,22 +1,22 @@
{ {
"id": "主键", "id": "主键",
"recordId": "执行记录ID", "recordId": "执行记录ID",
"execKey": "执行标识", "execKey": "执行标识",
"nodeId": "节点ID", "nodeId": "节点ID",
"nodeName": "节点名称", "nodeName": "节点名称",
"input": "输入", "input": "输入",
"output": "输出", "output": "输出",
"nodeData": "节点信息", "nodeData": "节点信息",
"startTime": "开始时间", "startTime": "开始时间",
"endTime": "结束时间", "endTime": "结束时间",
"tokens": "消耗总token", "tokens": "消耗总token",
"status": "状态", "status": "状态",
"errorInfo": "错误信息", "errorInfo": "错误信息",
"moduleName": "步骤信息", "moduleName": "步骤信息",
"execTime": "耗时", "execTime": "耗时",
"status1": "运行中", "status1": "运行中",
"status6": "挂起", "status6": "挂起",
"status10": "错误", "status10": "错误",
"status20": "成功", "status20": "成功",
"status21": "失败" "status21": "失败"
} }

View File

@@ -1,33 +1,33 @@
{ {
"title": "数据中枢", "title": "数据中枢",
"id": "主键", "id": "主键",
"deptId": "部门ID", "deptId": "部门ID",
"tenantId": "租户ID", "tenantId": "租户ID",
"tableName": "数据表名", "tableName": "数据表名",
"tableDesc": "数据表描述", "tableDesc": "数据表描述",
"actualTable": "物理表名", "actualTable": "物理表名",
"status": "数据状态", "status": "数据状态",
"created": "创建时间", "created": "创建时间",
"createdBy": "创建者", "createdBy": "创建者",
"modified": "修改时间", "modified": "修改时间",
"modifiedBy": "修改者", "modifiedBy": "修改者",
"options": "扩展项", "options": "扩展项",
"fields": "字段", "fields": "字段",
"fieldName": "字段名", "fieldName": "字段名",
"fieldDesc": "字段描述", "fieldDesc": "字段描述",
"fieldType": "字段类型", "fieldType": "字段类型",
"required": "是否必填", "required": "是否必填",
"noFieldError": "至少包含一个字段", "noFieldError": "至少包含一个字段",
"fieldInfoError": "字段信息不完善", "fieldInfoError": "字段信息不完善",
"nameRegx": "只能包含小写字母、数字和下划线,且必须以小写字母开头", "nameRegx": "只能包含小写字母、数字和下划线,且必须以小写字母开头",
"structure": "表结构", "structure": "表结构",
"data": "数据", "data": "数据",
"uploadTitle": "点击或将文件拖拽到这里上传", "uploadTitle": "点击或将文件拖拽到这里上传",
"uploadDesc": "上传一份Excel文档文件大小限制10MB以内。", "uploadDesc": "上传一份Excel文档文件大小限制10MB以内。",
"downloadTemplate": "下载模板", "downloadTemplate": "下载模板",
"importComplete": "导入完成", "importComplete": "导入完成",
"totalNum": "总数", "totalNum": "总数",
"successNum": "成功数", "successNum": "成功数",
"failNum": "失败数", "failNum": "失败数",
"failList": "失败记录" "failList": "失败记录"
} }

View File

@@ -1,13 +1,13 @@
{ {
"id": "主键", "id": "主键",
"tableId": "数据表ID", "tableId": "数据表ID",
"fieldName": "字段名称", "fieldName": "字段名称",
"fieldDesc": "字段描述", "fieldDesc": "字段描述",
"fieldType": "字段类型", "fieldType": "字段类型",
"required": "是否必填", "required": "是否必填",
"created": "创建时间", "created": "创建时间",
"createdBy": "创建者", "createdBy": "创建者",
"modified": "修改时间", "modified": "修改时间",
"modifiedBy": "修改者", "modifiedBy": "修改者",
"options": "扩展项" "options": "扩展项"
} }

View File

@@ -1,17 +1,17 @@
{ {
"root": "根部门", "root": "根部门",
"id": "主键", "id": "主键",
"tenantId": "租户ID", "tenantId": "租户ID",
"parentId": "父级", "parentId": "父级",
"ancestors": "父级部门ID集合", "ancestors": "父级部门ID集合",
"deptName": "部门名称", "deptName": "部门名称",
"deptCode": "部门编码", "deptCode": "部门编码",
"sortNo": "排序", "sortNo": "排序",
"status": "数据状态", "status": "数据状态",
"created": "创建时间", "created": "创建时间",
"createdBy": "创建者", "createdBy": "创建者",
"modified": "修改时间", "modified": "修改时间",
"modifiedBy": "修改者", "modifiedBy": "修改者",
"remark": "备注", "remark": "备注",
"isDeleted": "删除标识" "isDeleted": "删除标识"
} }

View File

@@ -1,12 +1,12 @@
{ {
"id": "主键", "id": "主键",
"name": "数据字典名称", "name": "数据字典名称",
"code": "字典编码", "code": "字典编码",
"description": "字典描述或备注", "description": "字典描述或备注",
"dictType": "字典类型 1 自定义字典、2 数据表字典、 3 枚举类字典、 4 系统字典(自定义 DictLoader", "dictType": "字典类型 1 自定义字典、2 数据表字典、 3 枚举类字典、 4 系统字典(自定义 DictLoader",
"sortNo": "排序编号", "sortNo": "排序编号",
"status": "是否启用", "status": "是否启用",
"options": "扩展字典 存放 json", "options": "扩展字典 存放 json",
"created": "创建时间", "created": "创建时间",
"modified": "修改时间" "modified": "修改时间"
} }

View File

@@ -1,23 +1,23 @@
{ {
"id": "主键", "id": "主键",
"deptId": "部门ID", "deptId": "部门ID",
"tenantId": "租户ID", "tenantId": "租户ID",
"jobName": "任务名称", "jobName": "任务名称",
"jobType": "任务类型", "jobType": "任务类型",
"jobParams": "任务参数", "jobParams": "任务参数",
"cronExpression": "cron表达式", "cronExpression": "cron表达式",
"allowConcurrent": "是否并发执行", "allowConcurrent": "是否并发执行",
"misfirePolicy": "错过策略", "misfirePolicy": "错过策略",
"options": "其他配置", "options": "其他配置",
"status": "任务状态", "status": "任务状态",
"created": "创建时间", "created": "创建时间",
"createdBy": "创建者", "createdBy": "创建者",
"modified": "修改时间", "modified": "修改时间",
"modifiedBy": "修改者", "modifiedBy": "修改者",
"remark": "备注", "remark": "备注",
"isDeleted": "删除标识", "isDeleted": "删除标识",
"workflow": "工作流", "workflow": "工作流",
"beanMethod": "bean方法", "beanMethod": "bean方法",
"javaMethod": "java方法", "javaMethod": "java方法",
"example": "示例" "example": "示例"
} }

View File

@@ -1,14 +1,14 @@
{ {
"id": "ID", "id": "ID",
"accountId": "操作人", "accountId": "操作人",
"actionName": "操作名称", "actionName": "操作名称",
"actionType": "操作的类型", "actionType": "操作的类型",
"actionClass": "操作涉及的类", "actionClass": "操作涉及的类",
"actionMethod": "操作涉及的方法", "actionMethod": "操作涉及的方法",
"actionUrl": "操作涉及的 URL 地址", "actionUrl": "操作涉及的 URL 地址",
"actionIp": "操作涉及的用户 IP 地址", "actionIp": "操作涉及的用户 IP 地址",
"actionParams": "操作请求参数", "actionParams": "操作请求参数",
"actionBody": "操作请求body", "actionBody": "操作请求body",
"status": "操作状态 1 成功 9 失败", "status": "操作状态 1 成功 9 失败",
"created": "操作时间" "created": "操作时间"
} }

View File

@@ -1,20 +1,20 @@
{ {
"root":"顶级", "root": "顶级",
"id": "主键", "id": "主键",
"parentId": "父菜单", "parentId": "父菜单",
"menuType": "菜单类型", "menuType": "菜单类型",
"menuTitle": "菜单标题", "menuTitle": "菜单标题",
"menuUrl": "菜单url", "menuUrl": "菜单url",
"component": "组件路径", "component": "组件路径",
"menuIcon": "图标", "menuIcon": "图标",
"isShow": "是否显示", "isShow": "是否显示",
"permissionTag": "权限标识", "permissionTag": "权限标识",
"sortNo": "排序", "sortNo": "排序",
"status": "数据状态", "status": "数据状态",
"created": "创建时间", "created": "创建时间",
"createdBy": "创建者", "createdBy": "创建者",
"modified": "修改时间", "modified": "修改时间",
"modifiedBy": "修改者", "modifiedBy": "修改者",
"remark": "备注", "remark": "备注",
"isDeleted": "删除标识" "isDeleted": "删除标识"
} }

View File

@@ -1,22 +1,22 @@
{ {
"id": "主键", "id": "主键",
"tenantId": "租户ID", "tenantId": "租户ID",
"roleName": "角色名称", "roleName": "角色名称",
"roleKey": "角色标识", "roleKey": "角色标识",
"status": "是否启用", "status": "是否启用",
"created": "创建时间", "created": "创建时间",
"createdBy": "创建者", "createdBy": "创建者",
"modified": "修改时间", "modified": "修改时间",
"modifiedBy": "修改者", "modifiedBy": "修改者",
"remark": "备注", "remark": "备注",
"isDeleted": "删除标识", "isDeleted": "删除标识",
"menuPermission": "菜单权限", "menuPermission": "菜单权限",
"dataPermission": "数据权限", "dataPermission": "数据权限",
"categoryPermission": "分类权限", "categoryPermission": "分类权限",
"categoryPermissionHint": "未配置即拒绝,仅控制资源可见性与选择器/绑定器。", "categoryPermissionHint": "未配置即拒绝,仅控制资源可见性与选择器/绑定器。",
"categoryScopeAll": "全部分类", "categoryScopeAll": "全部分类",
"categoryScopeCustom": "自定义分类", "categoryScopeCustom": "自定义分类",
"categoryScopePlaceholder": "请选择分类", "categoryScopePlaceholder": "请选择分类",
"checkStrictlyTrue": "联动", "checkStrictlyTrue": "联动",
"checkStrictlyFalse": "不联动" "checkStrictlyFalse": "不联动"
} }

View File

@@ -1,4 +1,8 @@
import { initPreferences, preferences, updatePreferences } from '@easyflow/preferences'; import {
initPreferences,
preferences,
updatePreferences,
} from '@easyflow/preferences';
import { unmountGlobalLoading } from '@easyflow/utils'; import { unmountGlobalLoading } from '@easyflow/utils';
import { import {

View File

@@ -7,6 +7,12 @@ import { startProgress, stopProgress } from '@easyflow/utils';
import { accessRoutes, coreRouteNames } from '#/router/routes'; import { accessRoutes, coreRouteNames } from '#/router/routes';
import { useAuthStore } from '#/store'; import { useAuthStore } from '#/store';
import {
buildForcePasswordRoute,
isForcePasswordRoute,
notifyForcePasswordChange,
shouldForcePasswordChange,
} from '#/utils/password-reset';
import { generateAccess } from './access'; import { generateAccess } from './access';
import { import {
@@ -14,12 +20,6 @@ import {
removeDevLoginQuery, removeDevLoginQuery,
shouldAttemptDevLogin, shouldAttemptDevLogin,
} from './dev-login'; } from './dev-login';
import {
buildForcePasswordRoute,
isForcePasswordRoute,
notifyForcePasswordChange,
shouldForcePasswordChange,
} from '#/utils/password-reset';
interface NetworkConnectionLike { interface NetworkConnectionLike {
effectiveType?: string; effectiveType?: string;
@@ -189,7 +189,8 @@ function setupAccessGuard(router: Router) {
// 基本路由,这些路由不需要进入权限拦截 // 基本路由,这些路由不需要进入权限拦截
if (coreRouteNames.includes(to.name as string)) { if (coreRouteNames.includes(to.name as string)) {
if (to.path === LOGIN_PATH && accessStore.accessToken) { if (to.path === LOGIN_PATH && accessStore.accessToken) {
const currentUser = userStore.userInfo || (await authStore.fetchUserInfo()); const currentUser =
userStore.userInfo || (await authStore.fetchUserInfo());
if (shouldForcePasswordChange(currentUser)) { if (shouldForcePasswordChange(currentUser)) {
return buildForcePasswordRoute(); return buildForcePasswordRoute();
} }

View File

@@ -1,9 +1,9 @@
import type {RouteRecordRaw} from 'vue-router'; import type { RouteRecordRaw } from 'vue-router';
import {LOGIN_PATH} from '@easyflow/constants'; import { LOGIN_PATH } from '@easyflow/constants';
import {preferences} from '@easyflow/preferences'; import { preferences } from '@easyflow/preferences';
import {$t} from '#/locales'; import { $t } from '#/locales';
const BasicLayout = () => import('#/layouts/basic.vue'); const BasicLayout = () => import('#/layouts/basic.vue');
const AuthPageLayout = () => import('#/layouts/auth.vue'); const AuthPageLayout = () => import('#/layouts/auth.vue');

View File

@@ -50,3 +50,5 @@
// ]; // ];
// //
// export default routes; // export default routes;
export {};

View File

@@ -95,7 +95,8 @@ export const useAuthStore = defineStore('auth', () => {
) { ) {
try { try {
loginLoading.value = true; loginLoading.value = true;
const { forceChangePassword, token: accessToken } = await loginApi(params); const { forceChangePassword, token: accessToken } =
await loginApi(params);
if (accessToken) { if (accessToken) {
return await finalizeLogin(accessToken, forceChangePassword, { return await finalizeLogin(accessToken, forceChangePassword, {

View File

@@ -1,5 +1,9 @@
declare module '@tinyflow-ai/vue' { declare module '@tinyflow-ai/vue' {
import type { DefineComponent } from 'vue'; import type { DefineComponent } from 'vue';
export const Tinyflow: DefineComponent<Record<string, any>, Record<string, any>, any>; export const Tinyflow: DefineComponent<
Record<string, any>,
Record<string, any>,
any
>;
} }

View File

@@ -1,6 +1,10 @@
declare module 'vue-element-plus-x/es/*/index.js' { declare module 'vue-element-plus-x/es/*/index.js' {
import type { DefineComponent } from 'vue'; import type { DefineComponent } from 'vue';
const component: DefineComponent<Record<string, any>, Record<string, any>, any>; const component: DefineComponent<
Record<string, any>,
Record<string, any>,
any
>;
export default component; export default component;
} }

View File

@@ -1,5 +1,5 @@
declare module '@wangeditor/editor-for-vue' { declare module '@wangeditor/editor-for-vue' {
import type {DefineComponent} from 'vue'; import type { DefineComponent } from 'vue';
export const Editor: DefineComponent<any, any, any>; export const Editor: DefineComponent<any, any, any>;
export const Toolbar: DefineComponent<any, any, any>; export const Toolbar: DefineComponent<any, any, any>;

View File

@@ -19,7 +19,10 @@ export function buildForcePasswordRoute() {
} }
export function isForcePasswordRoute( export function isForcePasswordRoute(
route: Pick<{ name?: string | symbol | null; query?: Record<string, any> }, 'name' | 'query'>, route: Pick<
{ name?: null | string | symbol; query?: Record<string, any> },
'name' | 'query'
>,
) { ) {
return route.name === 'Profile' && route.query?.tab === 'password'; return route.name === 'Profile' && route.query?.tab === 'password';
} }

View File

@@ -1,11 +1,13 @@
<script lang="ts" setup> <script lang="ts" setup>
import type {EasyFlowFormSchema} from '@easyflow/common-ui'; import type { EasyFlowFormSchema } from '@easyflow/common-ui';
import {AuthenticationLogin, z} from '@easyflow/common-ui';
import {computed, onMounted} from 'vue'; import { computed, onMounted } from 'vue';
import {useAppConfig} from '@easyflow/hooks';
import {$t} from '@easyflow/locales'; import { AuthenticationLogin, z } from '@easyflow/common-ui';
import {useAuthStore} from '#/store'; import { useAppConfig } from '@easyflow/hooks';
import { $t } from '@easyflow/locales';
import { useAuthStore } from '#/store';
defineOptions({ name: 'Login' }); defineOptions({ name: 'Login' });
onMounted(() => {}); onMounted(() => {});
@@ -109,10 +111,10 @@ function onSubmit(values: any) {
} }
.captcha-anchor { .captcha-anchor {
inset: 0;
pointer-events: none;
position: absolute; position: absolute;
inset: 0;
z-index: 30; z-index: 30;
pointer-events: none;
} }
.captcha-anchor:empty { .captcha-anchor:empty {

View File

@@ -18,7 +18,9 @@ const userStore = useUserStore();
const tabsValue = ref<string>('basic'); const tabsValue = ref<string>('basic');
const forcePasswordChange = computed(() => { const forcePasswordChange = computed(() => {
return !!userStore.userInfo?.passwordResetRequired || route.query.force === '1'; return (
!!userStore.userInfo?.passwordResetRequired || route.query.force === '1'
);
}); });
const tabs = computed(() => { const tabs = computed(() => {
@@ -43,7 +45,11 @@ const tabs = computed(() => {
}); });
watch( watch(
() => [route.query.force, route.query.tab, userStore.userInfo?.passwordResetRequired], () => [
route.query.force,
route.query.tab,
userStore.userInfo?.passwordResetRequired,
],
() => { () => {
if (forcePasswordChange.value) { if (forcePasswordChange.value) {
tabsValue.value = 'password'; tabsValue.value = 'password';

View File

@@ -22,7 +22,9 @@ const router = useRouter();
const userStore = useUserStore(); const userStore = useUserStore();
const isForcedPasswordChange = computed(() => { const isForcedPasswordChange = computed(() => {
return !!userStore.userInfo?.passwordResetRequired || route.query.force === '1'; return (
!!userStore.userInfo?.passwordResetRequired || route.query.force === '1'
);
}); });
const formSchema = computed((): EasyFlowFormSchema[] => { const formSchema = computed((): EasyFlowFormSchema[] => {
@@ -49,7 +51,9 @@ const formSchema = computed((): EasyFlowFormSchema[] => {
}; };
}, },
rules: z rules: z
.string({ required_error: $t('sysAccount.newPwd') + $t('common.isRequired') }) .string({
required_error: $t('sysAccount.newPwd') + $t('common.isRequired'),
})
.min(1, { message: $t('sysAccount.newPwd') + $t('common.isRequired') }) .min(1, { message: $t('sysAccount.newPwd') + $t('common.isRequired') })
.refine((value) => isStrongPassword(value), { .refine((value) => isStrongPassword(value), {
message: $t('sysAccount.passwordStrongTip'), message: $t('sysAccount.passwordStrongTip'),

View File

@@ -210,11 +210,11 @@ defineExpose({
} }
.bot-modal-section { .bot-modal-section {
border-radius: 14px;
border: 1px solid hsl(var(--modal-divider));
background: hsl(var(--modal-content-surface-strong));
box-shadow: none;
padding: 14px; padding: 14px;
background: hsl(var(--modal-content-surface-strong));
border: 1px solid hsl(var(--modal-divider));
border-radius: 14px;
box-shadow: none;
} }
.bot-modal-section--compact { .bot-modal-section--compact {
@@ -227,17 +227,17 @@ defineExpose({
.bot-modal-section__title { .bot-modal-section__title {
margin: 0; margin: 0;
color: hsl(var(--text-strong));
font-size: 14px; font-size: 14px;
font-weight: 700; font-weight: 700;
line-height: 1.4; line-height: 1.4;
color: hsl(var(--text-strong));
} }
.bot-modal-section__description { .bot-modal-section__description {
margin: 3px 0 0; margin: 3px 0 0;
color: hsl(var(--text-muted));
font-size: 11px; font-size: 11px;
line-height: 1.45; line-height: 1.45;
color: hsl(var(--text-muted));
} }
.bot-modal-appearance-grid { .bot-modal-appearance-grid {
@@ -279,9 +279,9 @@ defineExpose({
.bot-modal-field-tip { .bot-modal-field-tip {
margin-top: 4px; margin-top: 4px;
color: hsl(var(--text-muted));
font-size: 11px; font-size: 11px;
line-height: 1.5; line-height: 1.5;
color: hsl(var(--text-muted));
} }
.bot-modal-form :deep(.el-form-item) { .bot-modal-form :deep(.el-form-item) {
@@ -290,18 +290,18 @@ defineExpose({
.bot-modal-form :deep(.el-form-item__label) { .bot-modal-form :deep(.el-form-item__label) {
padding-bottom: 6px; padding-bottom: 6px;
color: hsl(var(--text-strong));
font-size: 12px; font-size: 12px;
font-weight: 600; font-weight: 600;
line-height: 1.4; line-height: 1.4;
color: hsl(var(--text-strong));
} }
.bot-modal-form :deep(.el-input__wrapper), .bot-modal-form :deep(.el-input__wrapper),
.bot-modal-form :deep(.el-select__wrapper), .bot-modal-form :deep(.el-select__wrapper),
.bot-modal-form :deep(.el-textarea__inner) { .bot-modal-form :deep(.el-textarea__inner) {
border-radius: 12px;
background: hsl(var(--input-background)); background: hsl(var(--input-background));
box-shadow: inset 0 0 0 1px hsl(var(--input) / 0.92); border-radius: 12px;
box-shadow: inset 0 0 0 1px hsl(var(--input) / 92%);
transition: transition:
box-shadow 0.2s ease, box-shadow 0.2s ease,
transform 0.2s ease, transform 0.2s ease,
@@ -316,15 +316,15 @@ defineExpose({
.bot-modal-form :deep(.el-input__wrapper:hover), .bot-modal-form :deep(.el-input__wrapper:hover),
.bot-modal-form :deep(.el-select__wrapper:hover), .bot-modal-form :deep(.el-select__wrapper:hover),
.bot-modal-form :deep(.el-textarea__inner:hover) { .bot-modal-form :deep(.el-textarea__inner:hover) {
box-shadow: inset 0 0 0 1px hsl(var(--primary) / 0.18); box-shadow: inset 0 0 0 1px hsl(var(--primary) / 18%);
} }
.bot-modal-form :deep(.el-input__wrapper.is-focus), .bot-modal-form :deep(.el-input__wrapper.is-focus),
.bot-modal-form :deep(.el-select__wrapper.is-focused), .bot-modal-form :deep(.el-select__wrapper.is-focused),
.bot-modal-form :deep(.el-textarea__inner:focus) { .bot-modal-form :deep(.el-textarea__inner:focus) {
box-shadow: box-shadow:
inset 0 0 0 1px hsl(var(--primary) / 0.72), inset 0 0 0 1px hsl(var(--primary) / 72%),
0 0 0 4px hsl(var(--primary) / 0.12); 0 0 0 4px hsl(var(--primary) / 12%);
} }
.bot-modal-form :deep(.el-textarea__inner) { .bot-modal-form :deep(.el-textarea__inner) {
@@ -336,8 +336,8 @@ defineExpose({
.bot-modal-form :deep(.el-form-item.is-error .el-select__wrapper), .bot-modal-form :deep(.el-form-item.is-error .el-select__wrapper),
.bot-modal-form :deep(.el-form-item.is-error .el-textarea__inner) { .bot-modal-form :deep(.el-form-item.is-error .el-textarea__inner) {
box-shadow: box-shadow:
inset 0 0 0 1px hsl(var(--destructive) / 0.8), inset 0 0 0 1px hsl(var(--destructive) / 80%),
0 0 0 4px hsl(var(--destructive) / 0.08); 0 0 0 4px hsl(var(--destructive) / 8%);
} }
@media (max-width: 768px) { @media (max-width: 768px) {

View File

@@ -2,8 +2,8 @@
import type { BotInfo, Session } from '@easyflow/types'; import type { BotInfo, Session } from '@easyflow/types';
import { onMounted, ref, watchEffect } from 'vue'; import { onMounted, ref, watchEffect } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import ElConversations from 'vue-element-plus-x/es/Conversations/index.js'; import ElConversations from 'vue-element-plus-x/es/Conversations/index.js';
import { useRoute, useRouter } from 'vue-router';
import { IconifyIcon } from '@easyflow/icons'; import { IconifyIcon } from '@easyflow/icons';
import { preferences } from '@easyflow/preferences'; import { preferences } from '@easyflow/preferences';

View File

@@ -1466,10 +1466,12 @@ const handleBasicInfoChange = async (
</label> </label>
<div class="publish-external-code-preview"> <div class="publish-external-code-preview">
<div class="publish-external-code-topbar">HTML</div> <div class="publish-external-code-topbar">HTML</div>
<!-- eslint-disable vue/no-v-html -->
<pre class="publish-external-code-block"><code <pre class="publish-external-code-block"><code
class="hljs language-xml" class="hljs language-xml"
v-html="iframeCodeHighlighted" v-html="iframeCodeHighlighted"
></code></pre> ></code></pre>
<!-- eslint-enable vue/no-v-html -->
</div> </div>
<div class="publish-external-actions"> <div class="publish-external-actions">
<ElButton <ElButton

View File

@@ -1,13 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import type {BotInfo} from '@easyflow/types'; import type { BotInfo } from '@easyflow/types';
import {computed, onMounted, ref} from 'vue'; import { computed, onMounted, ref } from 'vue';
import {useRoute, useRouter} from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import {tryit} from 'radash'; import { tryit } from 'radash';
import {getBotDetails} from '#/api'; import { getBotDetails } from '#/api';
import {hasPermission} from '#/api/common/hasPermission'; import { hasPermission } from '#/api/common/hasPermission';
import Config from './config.vue'; import Config from './config.vue';
import Preview from './preview.vue'; import Preview from './preview.vue';
@@ -77,14 +77,16 @@ const fetchBotDetail = async (id: string) => {
height: calc(100vh - 90px); height: calc(100vh - 90px);
padding: 20px; padding: 20px;
} }
.row-container { .row-container {
height: 100%;
display: flex; display: flex;
gap: 20px; gap: 20px;
}
.row-item {
height: 100%; height: 100%;
}
.row-item {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
height: 100%;
} }
</style> </style>

View File

@@ -442,8 +442,8 @@ function closeDetail() {
.chat-history-page__filters { .chat-history-page__filters {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center;
gap: 12px; gap: 12px;
align-items: center;
} }
.chat-history-page__filter-control { .chat-history-page__filter-control {
@@ -471,26 +471,26 @@ function closeDetail() {
.chat-history-page__content { .chat-history-page__content {
display: flex; display: flex;
min-height: 0;
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
min-height: 0;
} }
.chat-history-page__table-shell { .chat-history-page__table-shell {
min-height: 0;
flex: 1; flex: 1;
min-height: 0;
overflow: hidden; overflow: hidden;
border: 1px solid hsl(var(--glass-border) / 0.42);
border-radius: 24px;
background: linear-gradient( background: linear-gradient(
180deg, 180deg,
hsl(var(--glass-border) / 0.28) 0%, hsl(var(--glass-border) / 28%) 0%,
hsl(var(--glass-tint) / 0.4) 14%, hsl(var(--glass-tint) / 40%) 14%,
hsl(var(--surface-panel) / 0.94) 100% hsl(var(--surface-panel) / 94%) 100%
); );
border: 1px solid hsl(var(--glass-border) / 42%);
border-radius: 24px;
box-shadow: box-shadow:
inset 0 1px 0 hsl(var(--glass-border) / 0.54), inset 0 1px 0 hsl(var(--glass-border) / 54%),
0 24px 42px -36px hsl(var(--foreground) / 0.16); 0 24px 42px -36px hsl(var(--foreground) / 16%);
} }
.chat-history-page__table { .chat-history-page__table {
@@ -500,30 +500,30 @@ function closeDetail() {
.chat-history-page__session-cell { .chat-history-page__session-cell {
display: flex; display: flex;
min-width: 0;
flex-direction: column; flex-direction: column;
gap: 6px; gap: 6px;
min-width: 0;
padding: 2px 0; padding: 2px 0;
} }
.chat-history-page__session-title { .chat-history-page__session-title {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis;
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
color: hsl(var(--text-strong)); color: hsl(var(--text-strong));
text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.chat-history-page__session-preview { .chat-history-page__session-preview {
display: -webkit-box; display: -webkit-box;
overflow: hidden; overflow: hidden;
-webkit-line-clamp: 1;
font-size: 12px; font-size: 12px;
line-height: 1.5; line-height: 1.5;
color: hsl(var(--text-muted)); color: hsl(var(--text-muted));
word-break: break-word; overflow-wrap: anywhere;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
-webkit-line-clamp: 1;
} }
.chat-history-page__assistant-chip { .chat-history-page__assistant-chip {
@@ -532,15 +532,15 @@ function closeDetail() {
max-width: 100%; max-width: 100%;
min-height: 28px; min-height: 28px;
padding: 0 12px; padding: 0 12px;
border: 1px solid hsl(var(--glass-border) / 0.48); overflow: hidden;
border-radius: 999px; text-overflow: ellipsis;
background: hsl(var(--glass-tint) / 0.76);
font-size: 12px; font-size: 12px;
font-weight: 600; font-weight: 600;
color: hsl(var(--nav-item-active-foreground)); color: hsl(var(--nav-item-active-foreground));
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
background: hsl(var(--glass-tint) / 76%);
border: 1px solid hsl(var(--glass-border) / 48%);
border-radius: 999px;
} }
.chat-history-page__user-cell, .chat-history-page__user-cell,
@@ -551,15 +551,15 @@ function closeDetail() {
.chat-history-page__count-pill { .chat-history-page__count-pill {
display: inline-flex; display: inline-flex;
min-width: 42px;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
min-width: 42px;
padding: 4px 10px; padding: 4px 10px;
border-radius: 999px;
background: hsl(var(--surface-contrast-soft) / 0.88);
font-size: 12px; font-size: 12px;
font-weight: 600; font-weight: 600;
color: hsl(var(--text-strong)); color: hsl(var(--text-strong));
background: hsl(var(--surface-contrast-soft) / 88%);
border-radius: 999px;
} }
.chat-history-page__detail-action { .chat-history-page__detail-action {
@@ -568,10 +568,10 @@ function closeDetail() {
.chat-history-page__empty { .chat-history-page__empty {
display: flex; display: flex;
min-height: 360px;
flex: 1; flex: 1;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
min-height: 360px;
} }
.chat-history-page__pagination { .chat-history-page__pagination {
@@ -599,27 +599,27 @@ function closeDetail() {
.chat-history-page__content :deep(.el-table th.el-table__cell) { .chat-history-page__content :deep(.el-table th.el-table__cell) {
height: 48px; height: 48px;
background: hsl(var(--surface-contrast-soft) / 0.54);
border-bottom-color: hsl(var(--divider-faint) / 0.28);
font-size: 12px; font-size: 12px;
font-weight: 600; font-weight: 600;
color: hsl(var(--text-muted)); color: hsl(var(--text-muted));
background: hsl(var(--surface-contrast-soft) / 54%);
border-bottom-color: hsl(var(--divider-faint) / 28%);
} }
.chat-history-page__content :deep(.el-table td.el-table__cell) { .chat-history-page__content :deep(.el-table td.el-table__cell) {
padding: 14px 0; padding: 14px 0;
background: transparent; background: transparent;
border-bottom-color: hsl(var(--divider-faint) / 0.22); border-bottom-color: hsl(var(--divider-faint) / 22%);
} }
.chat-history-page__content .chat-history-page__content
:deep(.el-table__body tr:hover > td.el-table__cell) { :deep(.el-table__body tr:hover > td.el-table__cell) {
background: hsl(var(--primary) / 0.04); background: hsl(var(--primary) / 4%);
} }
.chat-history-page__content .chat-history-page__content
:deep(.el-table__body tr.current-row > td.el-table__cell) { :deep(.el-table__body tr.current-row > td.el-table__cell) {
background: hsl(var(--primary) / 0.08); background: hsl(var(--primary) / 8%);
} }
@media (max-width: 1024px) { @media (max-width: 1024px) {

View File

@@ -268,76 +268,85 @@ const backDoc = () => {
<style scoped> <style scoped>
.document-container { .document-container {
width: 100%;
display: flex; display: flex;
height: 100%;
padding: 24px 24px 30px 24px;
}
.doc-container {
height: 100%;
width: 100%; width: 100%;
height: 100%;
padding: 24px 24px 30px;
}
.doc-container {
box-sizing: border-box;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
box-sizing: border-box;
}
.doc-table-content {
border-radius: 8px;
width: 100%; width: 100%;
box-sizing: border-box; height: 100%;
padding: 20px 14px 0 14px;
background-color: var(--el-bg-color);
flex: 1;
} }
.doc-table-content {
box-sizing: border-box;
flex: 1;
width: 100%;
padding: 20px 14px 0;
background-color: var(--el-bg-color);
border-radius: 8px;
}
.doc-header { .doc-header {
width: 100%; width: 100%;
margin: 0 auto;
padding-bottom: 21px; padding-bottom: 21px;
margin: 0 auto;
} }
.doc-content { .doc-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%;
width: 100%;
gap: 12px; gap: 12px;
width: 100%;
height: 100%;
} }
.doc-top-menu { .doc-top-menu {
flex: 1;
width: auto;
border-radius: 0;
background-color: transparent;
padding: 0;
display: flex; display: flex;
flex: 1;
flex-wrap: wrap; flex-wrap: wrap;
gap: 6px; gap: 6px;
min-height: 32px;
align-items: center; align-items: center;
width: auto;
min-height: 32px;
padding: 0;
background-color: transparent;
border-radius: 0;
} }
.doc-menu-item { .doc-menu-item {
border: 1px solid transparent;
background: transparent;
padding: 7px 14px; padding: 7px 14px;
border-radius: 8px;
font-size: 14px; font-size: 14px;
color: var(--el-text-color-secondary);
font-weight: 500; font-weight: 500;
color: var(--el-text-color-secondary);
cursor: pointer; cursor: pointer;
background: transparent;
border: 1px solid transparent;
border-radius: 8px;
transition: transition:
background-color 0.2s, background-color 0.2s,
color 0.2s, color 0.2s,
border-color 0.2s, border-color 0.2s,
box-shadow 0.2s; box-shadow 0.2s;
} }
.doc-menu-item:hover { .doc-menu-item:hover {
background-color: var(--el-fill-color-light);
color: var(--el-text-color-primary); color: var(--el-text-color-primary);
background-color: var(--el-fill-color-light);
} }
.doc-menu-item.active { .doc-menu-item.active {
font-weight: 600;
color: var(--el-color-primary); color: var(--el-color-primary);
background-color: var(--el-color-primary-light-9); background-color: var(--el-color-primary-light-9);
border-color: var(--el-color-primary-light-7); border-color: var(--el-color-primary-light-7);
box-shadow: 0 2px 10px rgb(64 158 255 / 16%); box-shadow: 0 2px 10px rgb(64 158 255 / 16%);
font-weight: 600;
} }
.doc-menu-item:focus-visible { .doc-menu-item:focus-visible {
outline: 2px solid var(--el-color-primary-light-5); outline: 2px solid var(--el-color-primary-light-5);
outline-offset: 1px; outline-offset: 1px;
@@ -353,52 +362,59 @@ const backDoc = () => {
.doc-table { .doc-table {
background-color: var(--el-bg-color); background-color: var(--el-bg-color);
} }
.doc-imp-container { .doc-imp-container {
box-sizing: border-box;
flex: 1; flex: 1;
width: 100%; width: 100%;
box-sizing: border-box;
} }
.doc-header-container { .doc-header-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
} }
.doc-knowledge-container { .doc-knowledge-container {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: 8px;
align-items: center; align-items: center;
margin-bottom: 20px; margin-bottom: 20px;
gap: 8px;
} }
.knowledge-info-container { .knowledge-info-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 4px; gap: 4px;
min-width: 160px; min-width: 160px;
} }
.title { .title {
font-weight: 500;
font-size: 16px; font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 24px; line-height: 24px;
text-align: left; text-align: left;
font-style: normal;
text-transform: none; text-transform: none;
} }
.description { .description {
font-weight: 400;
font-size: 14px; font-size: 14px;
color: #75808d;
line-height: 22px;
text-align: left;
font-style: normal; font-style: normal;
font-weight: 400;
line-height: 22px;
color: #75808d;
text-align: left;
text-transform: none; text-transform: none;
} }
.doc-search-container { .doc-search-container {
display: flex;
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex;
} }
.menu-container { .menu-container {
flex: 1; flex: 1;
} }

View File

@@ -601,9 +601,9 @@ function changeCategory(category: any) {
<style scoped> <style scoped>
h1 { h1 {
text-align: center;
margin-bottom: 30px; margin-bottom: 30px;
color: #303133; color: #303133;
text-align: center;
} }
.knowledge-scope-chip { .knowledge-scope-chip {
@@ -616,7 +616,7 @@ h1 {
font-weight: 600; font-weight: 600;
line-height: 1; line-height: 1;
color: hsl(var(--text-strong)); color: hsl(var(--text-strong));
background: hsl(var(--surface-subtle) / 0.92); background: hsl(var(--surface-subtle) / 92%);
border: 1px solid hsl(var(--line-subtle)); border: 1px solid hsl(var(--line-subtle));
border-radius: 999px; border-radius: 999px;
transition: transition:
@@ -632,15 +632,15 @@ button.knowledge-scope-chip {
} }
button.knowledge-scope-chip:hover { button.knowledge-scope-chip:hover {
box-shadow: 0 10px 22px -18px hsl(var(--foreground) / 32%);
transform: translateY(-1px); transform: translateY(-1px);
box-shadow: 0 10px 22px -18px hsl(var(--foreground) / 0.32);
} }
button.knowledge-scope-chip:focus-visible { button.knowledge-scope-chip:focus-visible {
outline: none; outline: none;
box-shadow: box-shadow:
0 0 0 4px hsl(var(--primary) / 0.12), 0 0 0 4px hsl(var(--primary) / 12%),
0 10px 22px -18px hsl(var(--foreground) / 0.32); 0 10px 22px -18px hsl(var(--foreground) / 32%);
} }
button.knowledge-scope-chip:disabled { button.knowledge-scope-chip:disabled {
@@ -663,20 +663,20 @@ button.knowledge-scope-chip:disabled {
.knowledge-scope-chip--private { .knowledge-scope-chip--private {
color: hsl(var(--primary)); color: hsl(var(--primary));
background: hsl(var(--primary) / 0.09); background: hsl(var(--primary) / 9%);
border-color: hsl(var(--primary) / 0.2); border-color: hsl(var(--primary) / 20%);
} }
.knowledge-scope-chip--dept { .knowledge-scope-chip--dept {
color: hsl(var(--warning)); color: hsl(var(--warning));
background: hsl(var(--warning) / 0.12); background: hsl(var(--warning) / 12%);
border-color: hsl(var(--warning) / 0.2); border-color: hsl(var(--warning) / 20%);
} }
.knowledge-scope-chip--public { .knowledge-scope-chip--public {
color: hsl(var(--success)); color: hsl(var(--success));
background: hsl(var(--success) / 0.12); background: hsl(var(--success) / 12%);
border-color: hsl(var(--success) / 0.2); border-color: hsl(var(--success) / 20%);
} }
.knowledge-scope-panel { .knowledge-scope-panel {
@@ -687,9 +687,9 @@ button.knowledge-scope-chip:disabled {
.knowledge-scope-option { .knowledge-scope-option {
display: flex; display: flex;
gap: 10px;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 10px;
width: 100%; width: 100%;
padding: 10px 8px; padding: 10px 8px;
text-align: left; text-align: left;
@@ -703,12 +703,12 @@ button.knowledge-scope-chip:disabled {
} }
.knowledge-scope-option:hover { .knowledge-scope-option:hover {
background: hsl(var(--foreground) / 0.04); background: hsl(var(--foreground) / 4%);
} }
.knowledge-scope-option:focus-visible { .knowledge-scope-option:focus-visible {
outline: none; outline: none;
box-shadow: 0 0 0 4px hsl(var(--primary) / 0.12); box-shadow: 0 0 0 4px hsl(var(--primary) / 12%);
} }
.knowledge-scope-option:disabled { .knowledge-scope-option:disabled {
@@ -729,8 +729,8 @@ button.knowledge-scope-chip:disabled {
justify-content: center; justify-content: center;
width: 30px; width: 30px;
height: 30px; height: 30px;
border-radius: 9px;
background: transparent; background: transparent;
border-radius: 9px;
} }
.knowledge-scope-option__icon { .knowledge-scope-option__icon {
@@ -764,29 +764,29 @@ button.knowledge-scope-chip:disabled {
.knowledge-scope-option--private .knowledge-scope-option__icon-wrap { .knowledge-scope-option--private .knowledge-scope-option__icon-wrap {
color: hsl(var(--primary)); color: hsl(var(--primary));
background: hsl(var(--primary) / 0.1); background: hsl(var(--primary) / 10%);
} }
.knowledge-scope-option--dept .knowledge-scope-option__icon-wrap { .knowledge-scope-option--dept .knowledge-scope-option__icon-wrap {
color: hsl(var(--warning)); color: hsl(var(--warning));
background: hsl(var(--warning) / 0.12); background: hsl(var(--warning) / 12%);
} }
.knowledge-scope-option--public .knowledge-scope-option__icon-wrap { .knowledge-scope-option--public .knowledge-scope-option__icon-wrap {
color: hsl(var(--success)); color: hsl(var(--success));
background: hsl(var(--success) / 0.12); background: hsl(var(--success) / 12%);
} }
.knowledge-scope-option--private.knowledge-scope-option--active { .knowledge-scope-option--private.knowledge-scope-option--active {
background: hsl(var(--primary) / 0.08); background: hsl(var(--primary) / 8%);
} }
.knowledge-scope-option--dept.knowledge-scope-option--active { .knowledge-scope-option--dept.knowledge-scope-option--active {
background: hsl(var(--warning) / 0.08); background: hsl(var(--warning) / 8%);
} }
.knowledge-scope-option--public.knowledge-scope-option--active { .knowledge-scope-option--public.knowledge-scope-option--active {
background: hsl(var(--success) / 0.08); background: hsl(var(--success) / 8%);
} }
.knowledge-scope-option--private .knowledge-scope-option__check { .knowledge-scope-option--private .knowledge-scope-option__check {
@@ -803,8 +803,8 @@ button.knowledge-scope-chip:disabled {
:global(.knowledge-visibility-popover.el-popover.el-popper) { :global(.knowledge-visibility-popover.el-popover.el-popper) {
padding: 8px; padding: 8px;
border-radius: 16px;
border-color: hsl(var(--line-subtle)); border-color: hsl(var(--line-subtle));
box-shadow: 0 18px 34px -28px hsl(var(--foreground) / 0.2); border-radius: 16px;
box-shadow: 0 18px 34px -28px hsl(var(--foreground) / 20%);
} }
</style> </style>

View File

@@ -162,17 +162,19 @@ const handleDelete = (row: any) => {
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
} }
.file-name-container { .file-name-container {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.title { .title {
font-weight: 500;
font-size: 14px; font-size: 14px;
color: #1a1a1a;
line-height: 20px;
text-align: left;
font-style: normal; font-style: normal;
font-weight: 500;
line-height: 20px;
color: #1a1a1a;
text-align: left;
text-transform: none; text-transform: none;
} }
</style> </style>

View File

@@ -252,8 +252,8 @@ onBeforeUnmount(() => {
.faq-form :deep(.el-input__wrapper), .faq-form :deep(.el-input__wrapper),
.faq-form :deep(.el-select__wrapper) { .faq-form :deep(.el-select__wrapper) {
border-radius: 10px;
min-height: 42px; min-height: 42px;
border-radius: 10px;
transition: box-shadow 0.2s ease; transition: box-shadow 0.2s ease;
} }
@@ -264,17 +264,17 @@ onBeforeUnmount(() => {
.field-tip { .field-tip {
margin-top: 6px; margin-top: 6px;
color: var(--el-text-color-secondary);
font-size: 12px; font-size: 12px;
line-height: 18px; line-height: 18px;
color: var(--el-text-color-secondary);
} }
.editor-wrapper { .editor-wrapper {
width: 100%; width: 100%;
overflow: hidden;
background: var(--el-fill-color-blank);
border: 1px solid var(--el-border-color-lighter); border: 1px solid var(--el-border-color-lighter);
border-radius: 12px; border-radius: 12px;
background: var(--el-fill-color-blank);
overflow: hidden;
box-shadow: 0 8px 24px rgb(15 23 42 / 4%); box-shadow: 0 8px 24px rgb(15 23 42 / 4%);
transition: transition:
border-color 0.2s ease, border-color 0.2s ease,
@@ -287,16 +287,16 @@ onBeforeUnmount(() => {
} }
:deep(.w-e-toolbar) { :deep(.w-e-toolbar) {
border-bottom: 1px solid var(--el-border-color-light);
background: var(--el-fill-color-blank);
padding: 8px 10px; padding: 8px 10px;
background: var(--el-fill-color-blank);
border-bottom: 1px solid var(--el-border-color-light);
} }
:deep(.w-e-text-container) { :deep(.w-e-text-container) {
height: 340px; height: 340px;
min-height: 340px; min-height: 340px;
background: var(--el-fill-color-blank);
cursor: text; cursor: text;
background: var(--el-fill-color-blank);
} }
:deep(.w-e-text-container .w-e-scroll) { :deep(.w-e-text-container .w-e-scroll) {
@@ -315,8 +315,8 @@ onBeforeUnmount(() => {
.dialog-footer { .dialog-footer {
display: flex; display: flex;
justify-content: flex-end;
gap: 12px; gap: 12px;
justify-content: flex-end;
} }
.footer-btn { .footer-btn {
@@ -324,13 +324,13 @@ onBeforeUnmount(() => {
} }
:deep(.faq-edit-dialog .el-dialog) { :deep(.faq-edit-dialog .el-dialog) {
border-radius: 14px;
overflow: hidden; overflow: hidden;
border-radius: 14px;
} }
:deep(.faq-edit-dialog .el-dialog__header) { :deep(.faq-edit-dialog .el-dialog__header) {
margin-right: 0;
padding: 18px 22px; padding: 18px 22px;
margin-right: 0;
border-bottom: 1px solid var(--el-border-color-lighter); border-bottom: 1px solid var(--el-border-color-lighter);
} }

View File

@@ -298,31 +298,31 @@ const handleImport = async () => {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 10px 12px;
background: var(--el-fill-color-blank);
border: 1px solid var(--el-border-color-light); border: 1px solid var(--el-border-color-light);
border-radius: 10px; border-radius: 10px;
background: var(--el-fill-color-blank);
padding: 10px 12px;
} }
.selected-file-main { .selected-file-main {
display: flex; display: flex;
align-items: center;
gap: 10px;
min-width: 0;
flex: 1; flex: 1;
gap: 10px;
align-items: center;
min-width: 0;
} }
.selected-file-icon { .selected-file-icon {
color: var(--el-text-color-secondary);
font-size: 18px; font-size: 18px;
color: var(--el-text-color-secondary);
} }
.selected-file-name { .selected-file-name {
color: var(--el-text-color-primary);
font-size: 14px;
font-weight: 500;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
font-size: 14px;
font-weight: 500;
color: var(--el-text-color-primary);
white-space: nowrap; white-space: nowrap;
} }
@@ -335,10 +335,10 @@ const handleImport = async () => {
} }
.result-wrap { .result-wrap {
border: 1px solid var(--el-border-color-light);
border-radius: 12px;
padding: 14px; padding: 14px;
background: var(--el-fill-color-light); background: var(--el-fill-color-light);
border: 1px solid var(--el-border-color-light);
border-radius: 12px;
} }
.result-head { .result-head {
@@ -350,8 +350,8 @@ const handleImport = async () => {
.result-title-wrap { .result-title-wrap {
display: flex; display: flex;
align-items: center;
gap: 8px; gap: 8px;
align-items: center;
} }
.result-state-icon { .result-state-icon {
@@ -371,24 +371,24 @@ const handleImport = async () => {
} }
.stat-item { .stat-item {
padding: 10px 12px;
background: var(--el-fill-color-blank); background: var(--el-fill-color-blank);
border: 1px solid var(--el-border-color-lighter); border: 1px solid var(--el-border-color-lighter);
border-radius: 8px; border-radius: 8px;
padding: 10px 12px;
} }
.stat-label { .stat-label {
color: var(--el-text-color-secondary); margin-bottom: 8px;
font-size: 12px; font-size: 12px;
line-height: 1; line-height: 1;
margin-bottom: 8px; color: var(--el-text-color-secondary);
} }
.stat-value { .stat-value {
color: var(--el-text-color-primary);
font-size: 22px; font-size: 22px;
font-weight: 600; font-weight: 600;
line-height: 1; line-height: 1;
color: var(--el-text-color-primary);
} }
.success-text { .success-text {
@@ -414,14 +414,14 @@ const handleImport = async () => {
:deep(.faq-upload-area .el-upload-dragger) { :deep(.faq-upload-area .el-upload-dragger) {
padding: 0; padding: 0;
border-radius: 10px;
background-color: var(--el-fill-color-blank); background-color: var(--el-fill-color-blank);
border-radius: 10px;
transition: all 0.3s; transition: all 0.3s;
} }
:deep(.faq-upload-area .el-upload-dragger:hover) { :deep(.faq-upload-area .el-upload-dragger:hover) {
border-color: var(--el-color-primary);
background-color: var(--el-color-primary-light-9); background-color: var(--el-color-primary-light-9);
border-color: var(--el-color-primary);
} }
@media (max-width: 768px) { @media (max-width: 768px) {

View File

@@ -1000,37 +1000,37 @@ onMounted(() => {
} }
.faq-category-pane { .faq-category-pane {
width: 236px;
min-width: 236px;
border: 1px solid var(--el-border-color-lighter);
border-radius: 12px;
background: var(--el-fill-color-blank);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 236px;
min-width: 236px;
overflow: hidden; overflow: hidden;
background: var(--el-fill-color-blank);
border: 1px solid var(--el-border-color-lighter);
border-radius: 12px;
} }
.faq-category-header { .faq-category-header {
display: flex; display: flex;
justify-content: space-between;
align-items: center; align-items: center;
justify-content: space-between;
padding: 10px; padding: 10px;
border-bottom: 1px solid var(--el-border-color-lighter);
font-weight: 600; font-weight: 600;
border-bottom: 1px solid var(--el-border-color-lighter);
} }
.faq-category-tree { .faq-category-tree {
flex: 1;
padding: 6px; padding: 6px;
overflow: auto; overflow: auto;
flex: 1;
} }
.faq-category-node { .faq-category-node {
display: flex;
gap: 6px;
align-items: center;
width: 100%; width: 100%;
min-width: 0; min-width: 0;
display: flex;
align-items: center;
gap: 6px;
} }
.faq-category-node.is-all-node .faq-category-node-label { .faq-category-node.is-all-node .faq-category-node-label {
@@ -1053,12 +1053,12 @@ onMounted(() => {
} }
.faq-content-pane { .faq-content-pane {
flex: 1;
padding: 14px 16px 8px;
overflow: auto;
background: var(--el-fill-color-blank);
border: 1px solid var(--el-border-color-lighter); border: 1px solid var(--el-border-color-lighter);
border-radius: 12px; border-radius: 12px;
padding: 14px 16px 8px;
background: var(--el-fill-color-blank);
flex: 1;
overflow: auto;
} }
.faq-header { .faq-header {
@@ -1074,18 +1074,18 @@ onMounted(() => {
.faq-toolbar { .faq-toolbar {
display: flex; display: flex;
gap: 14px;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 14px;
padding: 2px 0; padding: 2px 0;
} }
.faq-search-actions { .faq-search-actions {
flex: 1;
min-width: 260px;
display: flex; display: flex;
align-items: center; flex: 1;
gap: 10px; gap: 10px;
align-items: center;
min-width: 260px;
} }
.faq-search-input { .faq-search-input {
@@ -1095,15 +1095,15 @@ onMounted(() => {
.faq-primary-actions { .faq-primary-actions {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: flex-end;
gap: 10px; gap: 10px;
justify-content: flex-end;
} }
:deep(.faq-toolbar .el-button) { :deep(.faq-toolbar .el-button) {
height: 38px; height: 38px;
padding: 0 16px; padding: 0 16px;
border-radius: 10px;
font-weight: 500; font-weight: 500;
border-radius: 10px;
transition: transition:
border-color 0.2s ease, border-color 0.2s ease,
background-color 0.2s ease, background-color 0.2s ease,
@@ -1112,15 +1112,15 @@ onMounted(() => {
:deep(.faq-toolbar .el-button:not(.el-button--primary):hover) { :deep(.faq-toolbar .el-button:not(.el-button--primary):hover) {
color: hsl(var(--primary)); color: hsl(var(--primary));
border-color: hsl(var(--primary) / 45%);
background: hsl(var(--primary) / 7%); background: hsl(var(--primary) / 7%);
border-color: hsl(var(--primary) / 45%);
} }
:deep(.faq-search-input .el-input__wrapper) { :deep(.faq-search-input .el-input__wrapper) {
padding-right: 12px;
padding-left: 12px;
border-radius: 10px; border-radius: 10px;
box-shadow: 0 0 0 1px var(--el-border-color) inset; box-shadow: 0 0 0 1px var(--el-border-color) inset;
padding-left: 12px;
padding-right: 12px;
} }
:deep(.faq-search-input .el-input__wrapper:hover) { :deep(.faq-search-input .el-input__wrapper:hover) {
@@ -1142,8 +1142,8 @@ onMounted(() => {
:deep(.faq-category-tree .el-tree-node__content) { :deep(.faq-category-tree .el-tree-node__content) {
height: 34px; height: 34px;
border-radius: 8px;
padding-right: 4px; padding-right: 4px;
border-radius: 8px;
} }
:deep(.faq-category-tree .el-tree-node__content:hover) { :deep(.faq-category-tree .el-tree-node__content:hover) {
@@ -1157,8 +1157,8 @@ onMounted(() => {
} }
:deep(.el-tree-node.is-current > .el-tree-node__content) { :deep(.el-tree-node.is-current > .el-tree-node__content) {
background-color: hsl(var(--primary) / 15%);
color: hsl(var(--primary)); color: hsl(var(--primary));
background-color: hsl(var(--primary) / 15%);
} }
:deep( :deep(
@@ -1168,8 +1168,8 @@ onMounted(() => {
} }
:deep(.el-table) { :deep(.el-table) {
border-radius: 10px;
overflow: hidden; overflow: hidden;
border-radius: 10px;
} }
:deep(.el-table th.el-table__cell) { :deep(.el-table th.el-table__cell) {
@@ -1183,8 +1183,8 @@ onMounted(() => {
@media (max-width: 1360px) { @media (max-width: 1360px) {
.faq-toolbar { .faq-toolbar {
align-items: flex-start;
flex-direction: column; flex-direction: column;
align-items: flex-start;
} }
.faq-search-actions, .faq-search-actions,

View File

@@ -221,11 +221,11 @@ async function confirmImport() {
.imp-doc-kno-container { .imp-doc-kno-container {
position: relative; position: relative;
display: flex; display: flex;
height: 100%;
flex-direction: column; flex-direction: column;
height: 100%;
padding: 24px; padding: 24px;
border-radius: 16px;
background: var(--el-bg-color); background: var(--el-bg-color);
border-radius: 16px;
} }
.imp-doc-kno-content { .imp-doc-kno-content {
@@ -239,9 +239,9 @@ async function confirmImport() {
.step-card { .step-card {
padding: 20px 24px; padding: 20px 24px;
background: var(--el-fill-color-blank);
border: 1px solid var(--el-border-color-light); border: 1px solid var(--el-border-color-light);
border-radius: 16px; border-radius: 16px;
background: var(--el-fill-color-blank);
} }
.step-body { .step-body {

View File

@@ -323,8 +323,8 @@ function showLengthSettings(strategyCode?: string) {
.strategy-card__header { .strategy-card__header {
display: flex; display: flex;
justify-content: space-between;
gap: 16px; gap: 16px;
justify-content: space-between;
padding-bottom: 16px; padding-bottom: 16px;
border-bottom: 1px solid var(--el-border-color-lighter); border-bottom: 1px solid var(--el-border-color-lighter);
} }
@@ -343,9 +343,9 @@ function showLengthSettings(strategyCode?: string) {
.strategy-card__badges { .strategy-card__badges {
display: flex; display: flex;
flex-wrap: wrap;
gap: 8px; gap: 8px;
align-items: flex-start; align-items: flex-start;
flex-wrap: wrap;
} }
.strategy-card__content { .strategy-card__content {
@@ -369,10 +369,10 @@ function showLengthSettings(strategyCode?: string) {
} }
.strategy-reason-list { .strategy-reason-list {
margin: 0;
padding-left: 18px; padding-left: 18px;
color: var(--el-text-color-regular); margin: 0;
line-height: 1.7; line-height: 1.7;
color: var(--el-text-color-regular);
} }
.strategy-reason-list__item { .strategy-reason-list__item {
@@ -387,7 +387,7 @@ function showLengthSettings(strategyCode?: string) {
.strategy-form { .strategy-form {
padding: 16px; padding: 16px;
border-radius: 12px;
background: var(--el-fill-color-light); background: var(--el-fill-color-light);
border-radius: 12px;
} }
</style> </style>

View File

@@ -193,9 +193,9 @@ watch(
.preview-panel { .preview-panel {
padding: 20px; padding: 20px;
background: var(--el-bg-color);
border: 1px solid var(--el-border-color-light); border: 1px solid var(--el-border-color-light);
border-radius: 16px; border-radius: 16px;
background: var(--el-bg-color);
} }
.preview-summary { .preview-summary {
@@ -212,16 +212,16 @@ watch(
.chunk-card { .chunk-card {
padding: 16px; padding: 16px;
background: var(--el-fill-color-blank);
border: 1px solid var(--el-border-color-lighter); border: 1px solid var(--el-border-color-lighter);
border-radius: 14px; border-radius: 14px;
background: var(--el-fill-color-blank);
} }
.chunk-card__header { .chunk-card__header {
display: flex; display: flex;
gap: 12px;
align-items: flex-start; align-items: flex-start;
justify-content: space-between; justify-content: space-between;
gap: 12px;
} }
.chunk-card__title { .chunk-card__title {
@@ -244,11 +244,11 @@ watch(
.chunk-card__content { .chunk-card__content {
margin: 16px 0 0; margin: 16px 0 0;
white-space: pre-wrap;
word-break: break-word;
font-family: inherit; font-family: inherit;
line-height: 1.7; line-height: 1.7;
color: var(--el-text-color-regular); color: var(--el-text-color-regular);
overflow-wrap: anywhere;
white-space: pre-wrap;
} }
.chunk-card__warnings { .chunk-card__warnings {
@@ -262,10 +262,10 @@ watch(
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 12px;
margin-top: 16px;
padding: 12px; padding: 12px;
border-radius: 12px; margin-top: 16px;
background: var(--el-fill-color-light); background: var(--el-fill-color-light);
border-radius: 12px;
} }
.qa-block__item { .qa-block__item {
@@ -276,11 +276,11 @@ watch(
.qa-block__label { .qa-block__label {
display: inline-flex; display: inline-flex;
width: 22px;
justify-content: center; justify-content: center;
border-radius: 999px; width: 22px;
background: var(--el-color-primary-light-9);
color: var(--el-color-primary);
font-weight: 600; font-weight: 600;
color: var(--el-color-primary);
background: var(--el-color-primary-light-9);
border-radius: 999px;
} }
</style> </style>

View File

@@ -262,50 +262,56 @@ const activeName = ref('config');
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.content-title { .content-title {
font-size: 12px;
font-style: normal;
font-weight: 500; font-weight: 500;
font-size: 12px;
color: rgba(0, 0, 0, 0.85);
line-height: 24px; line-height: 24px;
color: rgb(0 0 0 / 85%);
text-align: left; text-align: left;
font-style: normal;
text-transform: none; text-transform: none;
} }
.content-desc { .content-desc {
font-weight: 400;
font-size: 12px; font-size: 12px;
color: rgba(0, 0, 0, 0.45);
line-height: 22px;
text-align: left;
font-style: normal; font-style: normal;
font-weight: 400;
line-height: 22px;
color: rgb(0 0 0 / 45%);
text-align: left;
text-transform: none; text-transform: none;
} }
.params-name { .params-name {
flex: 1;
background-color: #fafafa;
display: flex; display: flex;
flex: 1;
align-items: center; align-items: center;
padding: 8px;
background-color: #fafafa;
border: 1px solid #e6e9ee; border: 1px solid #e6e9ee;
border-radius: 8px; border-radius: 8px;
padding: 8px;
} }
.params-content-container { .params-content-container {
display: flex; display: flex;
flex: 1;
flex-direction: row; flex-direction: row;
gap: 8px; gap: 8px;
flex: 1;
border-radius: 8px;
padding: 8px; padding: 8px;
border-radius: 8px;
} }
.params-desc-container { .params-desc-container {
display: flex; display: flex;
flex: 1;
flex-direction: column; flex-direction: column;
gap: 4px; gap: 4px;
flex: 1;
border-radius: 8px;
border: 1px solid #e6e9ee;
padding: 8px; padding: 8px;
border: 1px solid #e6e9ee;
border-radius: 8px;
} }
.params-list { .params-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -313,18 +319,19 @@ const activeName = ref('config');
.params-left-title-container { .params-left-title-container {
display: flex; display: flex;
flex-direction: row;
background-color: #fafafa;
gap: 8px;
flex: 1; flex: 1;
flex-direction: row;
gap: 8px;
align-items: center;
padding: 8px;
background-color: #fafafa;
border: 1px solid #e6e9ee; border: 1px solid #e6e9ee;
border-radius: 8px; border-radius: 8px;
padding: 8px;
align-items: center;
} }
.required-mark { .required-mark {
color: #f56c6c;
margin-left: 2px; margin-left: 2px;
font-size: 14px; font-size: 14px;
color: #f56c6c;
} }
</style> </style>

View File

@@ -408,8 +408,8 @@ const save = async () => {
} }
.model-modal__ability-panel { .model-modal__ability-panel {
overflow: hidden;
padding: 2px; padding: 2px;
overflow: hidden;
border-radius: 18px; border-radius: 18px;
} }
@@ -421,8 +421,8 @@ const save = async () => {
} }
.model-modal__ability-separator { .model-modal__ability-separator {
width: 1px;
align-self: stretch; align-self: stretch;
width: 1px;
min-height: 28px; min-height: 28px;
background: hsl(var(--divider-faint) / 62%); background: hsl(var(--divider-faint) / 62%);
border-radius: 999px; border-radius: 999px;
@@ -430,9 +430,9 @@ const save = async () => {
.model-modal__ability-chip { .model-modal__ability-chip {
display: inline-flex; display: inline-flex;
gap: 8px;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 8px;
min-height: 40px; min-height: 40px;
padding: 9px 18px; padding: 9px 18px;
font-size: 13px; font-size: 13px;
@@ -454,21 +454,21 @@ const save = async () => {
.model-modal__ability-chip:hover:not(:disabled), .model-modal__ability-chip:hover:not(:disabled),
.model-modal__ability-chip:focus-visible:not(:disabled) { .model-modal__ability-chip:focus-visible:not(:disabled) {
color: hsl(var(--text-strong)); color: hsl(var(--text-strong));
transform: translateY(-1px);
box-shadow: 0 10px 18px -14px hsl(var(--foreground) / 28%); box-shadow: 0 10px 18px -14px hsl(var(--foreground) / 28%);
transform: translateY(-1px);
} }
.model-modal__ability-chip.is-active { .model-modal__ability-chip.is-active {
color: hsl(var(--text-strong)); color: hsl(var(--text-strong));
border-color: hsl(var(--primary) / 18%);
background: hsl(var(--primary) / 10%); background: hsl(var(--primary) / 10%);
border-color: hsl(var(--primary) / 18%);
box-shadow: inset 0 0 0 1px hsl(var(--primary) / 14%); box-shadow: inset 0 0 0 1px hsl(var(--primary) / 14%);
} }
.model-modal__ability-chip.is-disabled { .model-modal__ability-chip.is-disabled {
cursor: not-allowed; cursor: not-allowed;
opacity: 0.56;
box-shadow: none; box-shadow: none;
opacity: 0.56;
transform: none; transform: none;
} }

View File

@@ -1,17 +1,28 @@
<script setup lang="ts"> <script setup lang="ts">
import {computed, reactive, ref} from 'vue'; import { computed, reactive, ref } from 'vue';
import {EasyFlowFormModal} from '@easyflow/common-ui'; import { EasyFlowFormModal } from '@easyflow/common-ui';
import {ArrowDown, ArrowUp} from '@element-plus/icons-vue'; import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
import {ElForm, ElFormItem, ElIcon, ElInput, ElMessage, ElOption, ElSelect,} from 'element-plus'; import {
ElForm,
ElFormItem,
ElIcon,
ElInput,
ElMessage,
ElOption,
ElSelect,
} from 'element-plus';
import {api} from '#/api/request'; import { api } from '#/api/request';
import UploadAvatar from '#/components/upload/UploadAvatar.vue'; import UploadAvatar from '#/components/upload/UploadAvatar.vue';
import {$t} from '#/locales'; import { $t } from '#/locales';
import {syncProgrammaticFieldValidation} from '#/utils/form-validation'; import { syncProgrammaticFieldValidation } from '#/utils/form-validation';
import ModelProviderBadge from '#/views/ai/model/ModelProviderBadge.vue'; import ModelProviderBadge from '#/views/ai/model/ModelProviderBadge.vue';
import {getProviderPresetByValue, providerPresets,} from '#/views/ai/model/modelUtils/defaultIcon'; import {
getProviderPresetByValue,
providerPresets,
} from '#/views/ai/model/modelUtils/defaultIcon';
const emit = defineEmits(['reload']); const emit = defineEmits(['reload']);

View File

@@ -1,13 +1,19 @@
<script setup lang="ts"> <script setup lang="ts">
import {computed, reactive, ref} from 'vue'; import { computed, reactive, ref } from 'vue';
import {EasyFlowFormModal} from '@easyflow/common-ui'; import { EasyFlowFormModal } from '@easyflow/common-ui';
import {CircleCheckFilled, WarningFilled} from '@element-plus/icons-vue'; import { CircleCheckFilled, WarningFilled } from '@element-plus/icons-vue';
import {ElForm, ElFormItem, ElMessage, ElOption, ElSelect,} from 'element-plus'; import {
ElForm,
ElFormItem,
ElMessage,
ElOption,
ElSelect,
} from 'element-plus';
import {api} from '#/api/request'; import { api } from '#/api/request';
import {$t} from '#/locales'; import { $t } from '#/locales';
type VerifyStatus = 'error' | 'idle' | 'success'; type VerifyStatus = 'error' | 'idle' | 'success';

View File

@@ -263,16 +263,13 @@ const getSelectedAbilityTagsForLlm = (llm: llmType): ModelAbilityItem[] => {
} }
.llm-item__description { .llm-item__description {
display: -webkit-box;
margin: 0; margin: 0;
overflow: hidden;
-webkit-line-clamp: 2;
font-size: 13px; font-size: 13px;
line-height: 1.5; line-height: 1.5;
color: hsl(var(--text-muted)); color: hsl(var(--text-muted));
}
.llm-item__description {
display: -webkit-box;
overflow: hidden;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }

View File

@@ -503,7 +503,7 @@ const handleToggleVisibleChecked = (checked: boolean | number | string) => {
checkedModelIds.value = [...next]; checkedModelIds.value = [...next];
}; };
const handlePublishToggle = async (nextValue: string | number | boolean) => { const handlePublishToggle = async (nextValue: boolean | number | string) => {
if (!draft.id || !selectedModel.value || isPublishing.value) { if (!draft.id || !selectedModel.value || isPublishing.value) {
return; return;
} }
@@ -978,9 +978,9 @@ defineExpose({
.gateway-workspace__batch { .gateway-workspace__batch {
display: flex; display: flex;
gap: 12px;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 12px;
padding: 10px 12px; padding: 10px 12px;
background: hsl(var(--surface-contrast-soft) / 48%); background: hsl(var(--surface-contrast-soft) / 48%);
border: 1px solid hsl(var(--divider-faint) / 40%); border: 1px solid hsl(var(--divider-faint) / 40%);
@@ -1019,8 +1019,8 @@ defineExpose({
} }
.gateway-model-item.is-active { .gateway-model-item.is-active {
border-color: hsl(var(--primary) / 42%);
background: hsl(var(--primary) / 7%); background: hsl(var(--primary) / 7%);
border-color: hsl(var(--primary) / 42%);
} }
.gateway-model-item__content { .gateway-model-item__content {
@@ -1148,9 +1148,9 @@ defineExpose({
.gateway-form__actions { .gateway-form__actions {
display: flex; display: flex;
flex-shrink: 0;
gap: 12px; gap: 12px;
justify-content: flex-end; justify-content: flex-end;
flex-shrink: 0;
} }
.gateway-info-grid { .gateway-info-grid {
@@ -1189,8 +1189,8 @@ defineExpose({
} }
.gateway-example-item pre { .gateway-example-item pre {
margin: 0;
padding: 14px; padding: 14px;
margin: 0;
overflow: auto; overflow: auto;
font-size: 12px; font-size: 12px;
line-height: 1.7; line-height: 1.7;
@@ -1240,18 +1240,18 @@ defineExpose({
} }
.gateway-form__switch-row { .gateway-form__switch-row {
align-items: flex-start;
flex-direction: column; flex-direction: column;
align-items: flex-start;
} }
.gateway-form__invoke-row { .gateway-form__invoke-row {
align-items: stretch;
flex-direction: column; flex-direction: column;
align-items: stretch;
} }
.gateway-publish-inline { .gateway-publish-inline {
align-items: flex-start;
flex-direction: column; flex-direction: column;
align-items: flex-start;
} }
.gateway-hero__title { .gateway-hero__title {

View File

@@ -1,4 +1,4 @@
import {describe, expect, it} from 'vitest'; import { describe, expect, it } from 'vitest';
import { import {
createProviderDraft, createProviderDraft,

View File

@@ -1,4 +1,4 @@
import type {ProviderPreset} from './defaultIcon'; import type { ProviderPreset } from './defaultIcon';
export const PROVIDER_EDITABLE_FIELDS = [ export const PROVIDER_EDITABLE_FIELDS = [
'apiKey', 'apiKey',

View File

@@ -1,5 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import type {FormInstance} from 'element-plus'; import type { FormInstance } from 'element-plus';
import { onMounted, ref } from 'vue';
import { EasyFlowFormModal } from '@easyflow/common-ui';
import { Plus, Remove } from '@element-plus/icons-vue';
import { import {
ElForm, ElForm,
ElFormItem, ElFormItem,
@@ -12,15 +18,9 @@ import {
ElSelect, ElSelect,
} from 'element-plus'; } from 'element-plus';
import {onMounted, ref} from 'vue'; import { api } from '#/api/request';
import {EasyFlowFormModal} from '@easyflow/common-ui';
import {Plus, Remove} from '@element-plus/icons-vue';
import {api} from '#/api/request';
import UploadAvatar from '#/components/upload/UploadAvatar.vue'; import UploadAvatar from '#/components/upload/UploadAvatar.vue';
import {$t} from '#/locales'; import { $t } from '#/locales';
const emit = defineEmits(['reload']); const emit = defineEmits(['reload']);
const embeddingLlmList = ref<any>([]); const embeddingLlmList = ref<any>([]);
@@ -44,9 +44,11 @@ onMounted(() => {
api.get('/api/v1/plugin/modelList?supportEmbed=true').then((res) => { api.get('/api/v1/plugin/modelList?supportEmbed=true').then((res) => {
embeddingLlmList.value = res.data; embeddingLlmList.value = res.data;
}); });
api.get('/api/v1/plugin/modelList?supportRerankerLlmList=true').then((res) => { api
rerankerLlmList.value = res.data; .get('/api/v1/plugin/modelList?supportRerankerLlmList=true')
}); .then((res) => {
rerankerLlmList.value = res.data;
});
api.get('/api/v1/pluginCategory/list').then((res) => { api.get('/api/v1/pluginCategory/list').then((res) => {
if (res.errorCode === 0) { if (res.errorCode === 0) {
categoryList.value = res.data; categoryList.value = res.data;
@@ -145,7 +147,8 @@ function save() {
}) })
.then(async (res) => { .then(async (res) => {
if (res.errorCode === 0) { if (res.errorCode === 0) {
const pluginId = res.data?.id || plainEntity.id || entity.value.id; const pluginId =
res.data?.id || plainEntity.id || entity.value.id;
if (!pluginId) { if (!pluginId) {
throw new Error('插件保存成功但未返回插件ID'); throw new Error('插件保存成功但未返回插件ID');
} }
@@ -330,15 +333,17 @@ function removeHeader(index: number) {
.headers-container-reduce { .headers-container-reduce {
align-items: center; align-items: center;
} }
.addHeadersBtn { .addHeadersBtn {
width: 100%; width: 100%;
border-style: dashed;
border-color: var(--el-color-primary);
border-radius: 8px;
margin-top: 8px; margin-top: 8px;
border-color: var(--el-color-primary);
border-style: dashed;
border-radius: 8px;
} }
.head-con-content { .head-con-content {
margin-bottom: 8px;
align-items: center; align-items: center;
margin-bottom: 8px;
} }
</style> </style>

View File

@@ -82,7 +82,6 @@ function handleSubmitRun() {
v-model:open="dialogVisible" v-model:open="dialogVisible"
width="80%" width="80%"
align-center align-center
class="run-test-dialog"
:title="$t('pluginItem.pluginToolEdit.trialRun')" :title="$t('pluginItem.pluginToolEdit.trialRun')"
:before-close="() => (dialogVisible = false)" :before-close="() => (dialogVisible = false)"
> >
@@ -157,32 +156,36 @@ function handleSubmitRun() {
width: 100%; width: 100%;
height: calc(100vh - 161px); height: calc(100vh - 161px);
} }
.run-test-dialog {
}
.run-test-params { .run-test-params {
flex: 1;
width: 100%; width: 100%;
overflow: auto; overflow: auto;
flex: 1;
} }
.run-res-json { .run-res-json {
width: 100%;
flex: 1; flex: 1;
width: 100%;
overflow: auto; overflow: auto;
} }
.run-test-result { .run-test-result {
flex: 1;
display: flex; display: flex;
flex: 1;
flex-direction: column; flex-direction: column;
} }
.name-cell { .name-cell {
position: relative; position: relative;
min-width: 100%; min-width: 100%;
} }
.run-title-style { .run-title-style {
margin-bottom: 8px;
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
margin-bottom: 8px;
} }
.editable-name { .editable-name {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -201,15 +204,15 @@ function handleSubmitRun() {
} }
.error-message { .error-message {
color: #ff4d4f;
font-size: 12px;
margin-top: 2px; margin-top: 2px;
font-size: 12px;
line-height: 1.2; line-height: 1.2;
color: #ff4d4f;
} }
:deep(.el-table td.el-table__cell.first-column div) { :deep(.el-table td.el-table__cell.first-column div) {
display: flex; display: flex;
align-items: center;
gap: 2px; gap: 2px;
align-items: center;
} }
</style> </style>

View File

@@ -1,5 +1,7 @@
<script setup lang="ts"></script> <script setup lang="ts"></script>
<template></template> <template>
<div></div>
</template>
<style scoped></style> <style scoped></style>

View File

@@ -4,7 +4,6 @@ import { useRoute } from 'vue-router';
import { usePreferences } from '@easyflow/preferences'; import { usePreferences } from '@easyflow/preferences';
import { getOptions, sortNodes } from '@easyflow/utils'; import { getOptions, sortNodes } from '@easyflow/utils';
import { getIconByValue } from '#/views/ai/model/modelUtils/defaultIcon';
import { ArrowLeft, CircleCheck, Close } from '@element-plus/icons-vue'; import { ArrowLeft, CircleCheck, Close } from '@element-plus/icons-vue';
import { Tinyflow } from '@tinyflow-ai/vue'; import { Tinyflow } from '@tinyflow-ai/vue';
@@ -14,6 +13,7 @@ import { api } from '#/api/request';
import CommonSelectDataModal from '#/components/commonSelectModal/CommonSelectDataModal.vue'; import CommonSelectDataModal from '#/components/commonSelectModal/CommonSelectDataModal.vue';
import { $t } from '#/locales'; import { $t } from '#/locales';
import { router } from '#/router'; import { router } from '#/router';
import { getIconByValue } from '#/views/ai/model/modelUtils/defaultIcon';
import ExecResult from '#/views/ai/workflow/components/ExecResult.vue'; import ExecResult from '#/views/ai/workflow/components/ExecResult.vue';
import SingleRun from '#/views/ai/workflow/components/SingleRun.vue'; import SingleRun from '#/views/ai/workflow/components/SingleRun.vue';
import WorkflowForm from '#/views/ai/workflow/components/WorkflowForm.vue'; import WorkflowForm from '#/views/ai/workflow/components/WorkflowForm.vue';
@@ -143,7 +143,7 @@ const issueFocusActive = ref(false);
const focusedIssueKey = ref(''); const focusedIssueKey = ref('');
let focusPulseTimer: ReturnType<typeof setTimeout> | undefined; let focusPulseTimer: ReturnType<typeof setTimeout> | undefined;
type WorkflowCheckStage = 'SAVE' | 'PRE_EXECUTE'; type WorkflowCheckStage = 'PRE_EXECUTE' | 'SAVE';
const builtInNodeIconMap: Record<string, string> = { const builtInNodeIconMap: Record<string, string> = {
startNode: startNode:
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM12 15C10.3431 15 9 13.6569 9 12C9 10.3431 10.3431 9 12 9C13.6569 9 15 10.3431 15 12C15 13.6569 13.6569 15 12 15Z"></path></svg>', '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM12 15C10.3431 15 9 13.6569 9 12C9 10.3431 10.3431 9 12 9C13.6569 9 15 10.3431 15 12C15 13.6569 13.6569 15 12 15Z"></path></svg>',
@@ -395,6 +395,15 @@ function checkStageText(stage?: string) {
} }
return '-'; return '-';
} }
function checkStageSummaryText(stage?: string) {
return `${$t('aiWorkflow.checkStageLabel')}${checkStageText(stage)}`;
}
function checkIssueCountText(count?: number) {
return `${$t('aiWorkflow.issueCount')}${count || 0}`;
}
function issueKey(issue: any, index: number) { function issueKey(issue: any, index: number) {
return `${issue.code || '-'}-${issue.nodeId || '-'}-${issue.edgeId || '-'}-${index}`; return `${issue.code || '-'}-${issue.nodeId || '-'}-${issue.edgeId || '-'}-${index}`;
} }
@@ -616,16 +625,8 @@ function onAsyncExecute(info: any) {
/> />
</div> </div>
<div class="check-summary"> <div class="check-summary">
<span <span v-text="checkStageSummaryText(checkResult?.stage)"></span>
>{{ $t('aiWorkflow.checkStageLabel') }}{{ <span v-text="checkIssueCountText(checkResult?.issueCount)"></span>
checkStageText(checkResult?.stage)
}}</span
>
<span
>{{ $t('aiWorkflow.issueCount') }}{{
checkResult?.issueCount || 0
}}</span
>
</div> </div>
<div class="checklist-body"> <div class="checklist-body">
<button <button
@@ -645,14 +646,16 @@ function onAsyncExecute(info: any) {
<span <span
class="check-level" class="check-level"
:class="issueLevelClass(item.issue.level)" :class="issueLevelClass(item.issue.level)"
>{{ item.issue.level || '-' }}</span v-text="item.issue.level || '-'"
> ></span>
<span class="check-node-display"> <span class="check-node-display">
<!-- eslint-disable vue/no-v-html -->
<span <span
v-if="item.nodeDisplay.icon" v-if="item.nodeDisplay.icon"
class="check-node-icon" class="check-node-icon"
v-html="item.nodeDisplay.icon" v-html="item.nodeDisplay.icon"
/> ></span>
<!-- eslint-enable vue/no-v-html -->
<span v-else class="check-node-icon-fallback">N</span> <span v-else class="check-node-icon-fallback">N</span>
<span class="check-node-title">{{ <span class="check-node-title">{{
item.nodeDisplay.title item.nodeDisplay.title
@@ -676,23 +679,24 @@ function onAsyncExecute(info: any) {
} }
:deep(.tf-bottom-dock) { :deep(.tf-bottom-dock) {
left: 50% !important;
bottom: 16px !important; bottom: 16px !important;
transform: translateX(-50%) !important; left: 50% !important;
z-index: 46 !important; z-index: 46 !important;
transform: translateX(-50%) !important;
} }
.head-div { .head-div {
--workflow-bottom-dock-height: 56px; --workflow-bottom-dock-height: 56px;
--workflow-checklist-offset: calc(var(--workflow-bottom-dock-height) + 24px); --workflow-checklist-offset: calc(var(--workflow-bottom-dock-height) + 24px);
position: relative; position: relative;
background-color: var(--el-bg-color); background-color: var(--el-bg-color);
} }
.workflow-head-actions { .workflow-head-actions {
display: flex; display: flex;
align-items: center;
gap: 8px; gap: 8px;
align-items: center;
} }
.tiny-flow-container { .tiny-flow-container {
@@ -706,18 +710,18 @@ function onAsyncExecute(info: any) {
.checklist-panel { .checklist-panel {
position: absolute; position: absolute;
left: 20px;
right: 20px; right: 20px;
bottom: var(--workflow-checklist-offset); bottom: var(--workflow-checklist-offset);
left: 20px;
z-index: 60; z-index: 60;
max-height: min(320px, 42vh);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
max-height: min(320px, 42vh);
padding: 12px; padding: 12px;
background: var(--el-bg-color-overlay);
border: 1px solid var(--el-border-color); border: 1px solid var(--el-border-color);
border-radius: 12px; border-radius: 12px;
background: var(--el-bg-color-overlay); box-shadow: 0 10px 28px rgb(0 0 0 / 12%);
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.12);
} }
.checklist-header { .checklist-header {
@@ -742,18 +746,18 @@ function onAsyncExecute(info: any) {
} }
.checklist-body { .checklist-body {
overflow: auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px; gap: 8px;
overflow: auto;
} }
.check-item { .check-item {
padding: 10px 12px;
text-align: left; text-align: left;
background: var(--el-fill-color-lighter);
border: 1px solid var(--el-border-color-lighter); border: 1px solid var(--el-border-color-lighter);
border-radius: 10px; border-radius: 10px;
background: var(--el-fill-color-lighter);
padding: 10px 12px;
transition: transition:
border-color 0.2s ease, border-color 0.2s ease,
box-shadow 0.2s ease, box-shadow 0.2s ease,
@@ -765,8 +769,8 @@ function onAsyncExecute(info: any) {
} }
.check-item.is-clickable:hover { .check-item.is-clickable:hover {
border-color: var(--el-color-primary-light-5);
background: var(--el-fill-color-light); background: var(--el-fill-color-light);
border-color: var(--el-color-primary-light-5);
} }
.check-item.is-active { .check-item.is-active {
@@ -781,11 +785,11 @@ function onAsyncExecute(info: any) {
.check-item-meta { .check-item-meta {
display: flex; display: flex;
align-items: center;
gap: 10px; gap: 10px;
align-items: center;
margin-bottom: 6px;
font-size: 12px; font-size: 12px;
line-height: 1.2; line-height: 1.2;
margin-bottom: 6px;
} }
.check-level { .check-level {
@@ -795,10 +799,10 @@ function onAsyncExecute(info: any) {
min-width: 56px; min-width: 56px;
height: 20px; height: 20px;
padding: 0 8px; padding: 0 8px;
border-radius: 999px;
font-weight: 600; font-weight: 600;
color: var(--el-text-color-primary); color: var(--el-text-color-primary);
background: var(--el-fill-color-dark); background: var(--el-fill-color-dark);
border-radius: 999px;
} }
.check-level.is-error { .check-level.is-error {
@@ -818,8 +822,8 @@ function onAsyncExecute(info: any) {
.check-node-display { .check-node-display {
display: inline-flex; display: inline-flex;
align-items: center;
gap: 8px; gap: 8px;
align-items: center;
min-width: 0; min-width: 0;
} }
@@ -843,24 +847,24 @@ function onAsyncExecute(info: any) {
justify-content: center; justify-content: center;
width: 18px; width: 18px;
height: 18px; height: 18px;
border-radius: 50%;
font-size: 10px; font-size: 10px;
font-weight: 700; font-weight: 700;
color: var(--el-color-primary); color: var(--el-color-primary);
background: var(--el-color-primary-light-9); background: var(--el-color-primary-light-9);
border-radius: 50%;
} }
.check-node-title { .check-node-title {
font-size: 14px; font-size: 14px;
color: var(--el-text-color-primary);
font-weight: 500; font-weight: 500;
color: var(--el-text-color-primary);
} }
.check-item-message { .check-item-message {
font-size: 13px; font-size: 13px;
line-height: 1.45; line-height: 1.45;
color: var(--el-color-danger); color: var(--el-color-danger);
word-break: break-word; overflow-wrap: anywhere;
} }
.checklist-slide-enter-active, .checklist-slide-enter-active,
@@ -876,14 +880,15 @@ function onAsyncExecute(info: any) {
.workflow-issue-focus :deep(.svelte-flow__node.selected) { .workflow-issue-focus :deep(.svelte-flow__node.selected) {
border-color: var(--el-color-danger) !important; border-color: var(--el-color-danger) !important;
box-shadow: 0 0 0 3px rgba(245, 108, 108, 0.26); box-shadow: 0 0 0 3px rgb(245 108 108 / 26%);
animation: issue-node-pulse 1.2s ease-out 1; animation: issue-node-pulse 1.2s ease-out 1;
} }
@keyframes issue-node-pulse { @keyframes issue-node-pulse {
0% { 0% {
box-shadow: 0 0 0 0 rgba(245, 108, 108, 0.42); box-shadow: 0 0 0 0 rgb(245 108 108 / 42%);
} }
100% { 100% {
box-shadow: 0 0 0 10px transparent; box-shadow: 0 0 0 10px transparent;
} }

View File

@@ -1,23 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
import type {FormInstance} from 'element-plus'; import type { FormInstance } from 'element-plus';
import {
ElForm,
ElFormItem,
ElIcon,
ElInput,
ElInputNumber,
ElMessage,
ElMessageBox,
ElPopover,
} from 'element-plus';
import type {ActionButton, CardPrimaryAction,} from '#/components/page/CardList.vue'; import type {
import CardList from '#/components/page/CardList.vue'; ActionButton,
CardPrimaryAction,
} from '#/components/page/CardList.vue';
import {computed, markRaw, onMounted, ref} from 'vue'; import { computed, markRaw, onMounted, ref } from 'vue';
import {useAccess} from '@easyflow/access'; import { useAccess } from '@easyflow/access';
import {EasyFlowFormModal} from '@easyflow/common-ui'; import { EasyFlowFormModal } from '@easyflow/common-ui';
import { import {
Check, Check,
@@ -33,18 +25,29 @@ import {
Upload, Upload,
VideoPlay, VideoPlay,
} from '@element-plus/icons-vue'; } from '@element-plus/icons-vue';
import {tryit} from 'radash'; import {
ElForm,
ElFormItem,
ElIcon,
ElInput,
ElInputNumber,
ElMessage,
ElMessageBox,
ElPopover,
} from 'element-plus';
import { tryit } from 'radash';
import {api} from '#/api/request'; import { api } from '#/api/request';
import workflowIcon from '#/assets/ai/workflow/workflowIcon.png'; import workflowIcon from '#/assets/ai/workflow/workflowIcon.png';
// import workflowSvg from '#/assets/workflow.svg'; // import workflowSvg from '#/assets/workflow.svg';
import HeaderSearch from '#/components/headerSearch/HeaderSearch.vue'; import HeaderSearch from '#/components/headerSearch/HeaderSearch.vue';
import DesignIcon from '#/components/icons/DesignIcon.vue'; import DesignIcon from '#/components/icons/DesignIcon.vue';
import CardList from '#/components/page/CardList.vue';
import PageData from '#/components/page/PageData.vue'; import PageData from '#/components/page/PageData.vue';
import PageSide from '#/components/page/PageSide.vue'; import PageSide from '#/components/page/PageSide.vue';
import {$t} from '#/locales'; import { $t } from '#/locales';
import {router} from '#/router'; import { router } from '#/router';
import {useDictStore} from '#/store'; import { useDictStore } from '#/store';
import WorkflowModal from './WorkflowModal.vue'; import WorkflowModal from './WorkflowModal.vue';
@@ -61,7 +64,7 @@ interface FieldDefinition {
placeholder?: string; placeholder?: string;
} }
type VisibilityScope = 'PRIVATE' | 'DEPT' | 'PUBLIC'; type VisibilityScope = 'DEPT' | 'PRIVATE' | 'PUBLIC';
const primaryAction: CardPrimaryAction = { const primaryAction: CardPrimaryAction = {
icon: DesignIcon, icon: DesignIcon,
@@ -72,11 +75,11 @@ const primaryAction: CardPrimaryAction = {
}, },
}; };
const {hasAccessByCodes} = useAccess(); const { hasAccessByCodes } = useAccess();
const canManageWorkflow = computed(() => const canManageWorkflow = computed(() =>
hasAccessByCodes(['/api/v1/workflow/save']), hasAccessByCodes(['/api/v1/workflow/save']),
); );
const updatingScopeId = ref<string | number | null>(null); const updatingScopeId = ref<null | number | string>(null);
const visibilityScopePopoverRefs = ref<Record<string, any>>({}); const visibilityScopePopoverRefs = ref<Record<string, any>>({});
const visibilityScopeMeta = computed(() => ({ const visibilityScopeMeta = computed(() => ({
PRIVATE: { PRIVATE: {
@@ -203,10 +206,12 @@ function initDict() {
dictStore.fetchDictionary('dataStatus'); dictStore.fetchDictionary('dataStatus');
} }
function resolveVisibilityScopeMeta(scope?: string) { function resolveVisibilityScopeMeta(scope?: string) {
return visibilityScopeMeta.value[(scope || 'PRIVATE') as VisibilityScope] || return (
visibilityScopeMeta.value.PRIVATE; visibilityScopeMeta.value[(scope || 'PRIVATE') as VisibilityScope] ||
visibilityScopeMeta.value.PRIVATE
);
} }
function setVisibilityScopePopoverRef(id: string | number, el: any) { function setVisibilityScopePopoverRef(id: number | string, el: any) {
const cacheKey = String(id); const cacheKey = String(id);
if (el) { if (el) {
visibilityScopePopoverRefs.value[cacheKey] = el; visibilityScopePopoverRefs.value[cacheKey] = el;
@@ -214,7 +219,7 @@ function setVisibilityScopePopoverRef(id: string | number, el: any) {
} }
delete visibilityScopePopoverRefs.value[cacheKey]; delete visibilityScopePopoverRefs.value[cacheKey];
} }
function closeVisibilityScopePopover(id: string | number) { function closeVisibilityScopePopover(id: number | string) {
visibilityScopePopoverRefs.value[String(id)]?.hide?.(); visibilityScopePopoverRefs.value[String(id)]?.hide?.();
} }
async function updateVisibilityScope( async function updateVisibilityScope(
@@ -509,11 +514,16 @@ function handleHeaderButtonClick(data: any) {
> >
<ElIcon class="workflow-scope-chip__icon"> <ElIcon class="workflow-scope-chip__icon">
<component <component
:is="resolveVisibilityScopeMeta(item.visibilityScope).icon" :is="
resolveVisibilityScopeMeta(item.visibilityScope)
.icon
"
/> />
</ElIcon> </ElIcon>
<span class="workflow-scope-chip__label"> <span class="workflow-scope-chip__label">
{{ resolveVisibilityScopeMeta(item.visibilityScope).label }} {{
resolveVisibilityScopeMeta(item.visibilityScope).label
}}
</span> </span>
</button> </button>
</template> </template>
@@ -564,7 +574,9 @@ function handleHeaderButtonClick(data: any) {
> >
<ElIcon class="workflow-scope-chip__icon"> <ElIcon class="workflow-scope-chip__icon">
<component <component
:is="resolveVisibilityScopeMeta(item.visibilityScope).icon" :is="
resolveVisibilityScopeMeta(item.visibilityScope).icon
"
/> />
</ElIcon> </ElIcon>
<span class="workflow-scope-chip__label"> <span class="workflow-scope-chip__label">
@@ -629,7 +641,7 @@ function handleHeaderButtonClick(data: any) {
font-weight: 600; font-weight: 600;
line-height: 1; line-height: 1;
color: hsl(var(--text-strong)); color: hsl(var(--text-strong));
background: hsl(var(--surface-subtle) / 0.92); background: hsl(var(--surface-subtle) / 92%);
border: 1px solid hsl(var(--line-subtle)); border: 1px solid hsl(var(--line-subtle));
border-radius: 999px; border-radius: 999px;
transition: transition:
@@ -645,15 +657,15 @@ button.workflow-scope-chip {
} }
button.workflow-scope-chip:hover { button.workflow-scope-chip:hover {
box-shadow: 0 10px 22px -18px hsl(var(--foreground) / 32%);
transform: translateY(-1px); transform: translateY(-1px);
box-shadow: 0 10px 22px -18px hsl(var(--foreground) / 0.32);
} }
button.workflow-scope-chip:focus-visible { button.workflow-scope-chip:focus-visible {
outline: none; outline: none;
box-shadow: box-shadow:
0 0 0 4px hsl(var(--primary) / 0.12), 0 0 0 4px hsl(var(--primary) / 12%),
0 10px 22px -18px hsl(var(--foreground) / 0.32); 0 10px 22px -18px hsl(var(--foreground) / 32%);
} }
button.workflow-scope-chip:disabled { button.workflow-scope-chip:disabled {
@@ -676,20 +688,20 @@ button.workflow-scope-chip:disabled {
.workflow-scope-chip--private { .workflow-scope-chip--private {
color: hsl(var(--primary)); color: hsl(var(--primary));
background: hsl(var(--primary) / 0.09); background: hsl(var(--primary) / 9%);
border-color: hsl(var(--primary) / 0.2); border-color: hsl(var(--primary) / 20%);
} }
.workflow-scope-chip--dept { .workflow-scope-chip--dept {
color: hsl(var(--warning)); color: hsl(var(--warning));
background: hsl(var(--warning) / 0.12); background: hsl(var(--warning) / 12%);
border-color: hsl(var(--warning) / 0.2); border-color: hsl(var(--warning) / 20%);
} }
.workflow-scope-chip--public { .workflow-scope-chip--public {
color: hsl(var(--success)); color: hsl(var(--success));
background: hsl(var(--success) / 0.12); background: hsl(var(--success) / 12%);
border-color: hsl(var(--success) / 0.2); border-color: hsl(var(--success) / 20%);
} }
.workflow-scope-panel { .workflow-scope-panel {
@@ -700,9 +712,9 @@ button.workflow-scope-chip:disabled {
.workflow-scope-option { .workflow-scope-option {
display: flex; display: flex;
gap: 10px;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 10px;
width: 100%; width: 100%;
padding: 10px 8px; padding: 10px 8px;
text-align: left; text-align: left;
@@ -716,12 +728,12 @@ button.workflow-scope-chip:disabled {
} }
.workflow-scope-option:hover { .workflow-scope-option:hover {
background: hsl(var(--foreground) / 0.04); background: hsl(var(--foreground) / 4%);
} }
.workflow-scope-option:focus-visible { .workflow-scope-option:focus-visible {
outline: none; outline: none;
box-shadow: 0 0 0 4px hsl(var(--primary) / 0.12); box-shadow: 0 0 0 4px hsl(var(--primary) / 12%);
} }
.workflow-scope-option:disabled { .workflow-scope-option:disabled {
@@ -742,8 +754,8 @@ button.workflow-scope-chip:disabled {
justify-content: center; justify-content: center;
width: 30px; width: 30px;
height: 30px; height: 30px;
border-radius: 9px;
background: transparent; background: transparent;
border-radius: 9px;
} }
.workflow-scope-option__icon { .workflow-scope-option__icon {
@@ -776,29 +788,29 @@ button.workflow-scope-chip:disabled {
.workflow-scope-option--private .workflow-scope-option__icon-wrap { .workflow-scope-option--private .workflow-scope-option__icon-wrap {
color: hsl(var(--primary)); color: hsl(var(--primary));
background: hsl(var(--primary) / 0.1); background: hsl(var(--primary) / 10%);
} }
.workflow-scope-option--dept .workflow-scope-option__icon-wrap { .workflow-scope-option--dept .workflow-scope-option__icon-wrap {
color: hsl(var(--warning)); color: hsl(var(--warning));
background: hsl(var(--warning) / 0.12); background: hsl(var(--warning) / 12%);
} }
.workflow-scope-option--public .workflow-scope-option__icon-wrap { .workflow-scope-option--public .workflow-scope-option__icon-wrap {
color: hsl(var(--success)); color: hsl(var(--success));
background: hsl(var(--success) / 0.12); background: hsl(var(--success) / 12%);
} }
.workflow-scope-option--private.workflow-scope-option--active { .workflow-scope-option--private.workflow-scope-option--active {
background: hsl(var(--primary) / 0.08); background: hsl(var(--primary) / 8%);
} }
.workflow-scope-option--dept.workflow-scope-option--active { .workflow-scope-option--dept.workflow-scope-option--active {
background: hsl(var(--warning) / 0.08); background: hsl(var(--warning) / 8%);
} }
.workflow-scope-option--public.workflow-scope-option--active { .workflow-scope-option--public.workflow-scope-option--active {
background: hsl(var(--success) / 0.08); background: hsl(var(--success) / 8%);
} }
.workflow-scope-option--private .workflow-scope-option__check { .workflow-scope-option--private .workflow-scope-option__check {
@@ -815,8 +827,8 @@ button.workflow-scope-chip:disabled {
:global(.workflow-visibility-popover.el-popover.el-popper) { :global(.workflow-visibility-popover.el-popover.el-popper) {
padding: 8px; padding: 8px;
border-radius: 16px;
border-color: hsl(var(--line-subtle)); border-color: hsl(var(--line-subtle));
box-shadow: 0 18px 34px -28px hsl(var(--foreground) / 0.2); border-radius: 16px;
box-shadow: 0 18px 34px -28px hsl(var(--foreground) / 20%);
} }
</style> </style>

View File

@@ -84,7 +84,7 @@ function openDialog(row: any, importMode = false) {
isAdd.value = !row?.id; isAdd.value = !row?.id;
entity.value = { entity.value = {
...createDefaultEntity(), ...createDefaultEntity(),
...(row || {}), ...row,
}; };
dialogVisible.value = true; dialogVisible.value = true;
} }

View File

@@ -65,7 +65,7 @@ const handleDownload = (url: string) => {
v-if="selectionDataType === 'text'" v-if="selectionDataType === 'text'"
class="custom-radio-option" class="custom-radio-option"
:class="{ selected: isSelected(item) }" :class="{ selected: isSelected(item) }"
style="width: 100%; flex-shrink: 0" style="flex-shrink: 0; width: 100%"
@click="changeValue(item)" @click="changeValue(item)"
> >
{{ item }} {{ item }}
@@ -82,7 +82,7 @@ const handleDownload = (url: string) => {
<img <img
:src="item" :src="item"
alt="" alt=""
style="width: 80px; height: 80px; border-radius: 8px; display: block" style="display: block; width: 80px; height: 80px; border-radius: 8px"
/> />
</div> </div>
@@ -101,7 +101,7 @@ const handleDownload = (url: string) => {
v-else-if="selectionDataType === 'audio'" v-else-if="selectionDataType === 'audio'"
class="custom-radio-option" class="custom-radio-option"
:class="{ selected: isSelected(item) }" :class="{ selected: isSelected(item) }"
style="width: 100%; flex-shrink: 0" style="flex-shrink: 0; width: 100%"
@click="changeValue(item)" @click="changeValue(item)"
> >
<audio <audio
@@ -118,17 +118,17 @@ const handleDownload = (url: string) => {
" "
class="custom-radio-option" class="custom-radio-option"
:class="{ selected: isSelected(item) }" :class="{ selected: isSelected(item) }"
style="width: 100%; flex-shrink: 0" style="flex-shrink: 0; width: 100%"
@click="changeValue(item)" @click="changeValue(item)"
> >
<div <div
style=" style="
display: flex; display: flex;
justify-content: space-between;
align-items: center; align-items: center;
justify-content: space-between;
" "
> >
<div style="width: 92%; display: flex; align-items: center"> <div style="display: flex; align-items: center; width: 92%">
<img <img
style="width: 20px; height: 20px; margin-right: 8px" style="width: 20px; height: 20px; margin-right: 8px"
alt="" alt=""
@@ -151,19 +151,19 @@ const handleDownload = (url: string) => {
<style scoped> <style scoped>
.custom-radio-group { .custom-radio-group {
display: flex; display: flex;
gap: 12px;
flex-wrap: wrap; flex-wrap: wrap;
gap: 12px;
} }
.custom-radio-option { .custom-radio-option {
background-color: var(--el-bg-color);
padding: 8px;
border-radius: 8px;
cursor: pointer;
position: relative; position: relative;
box-sizing: border-box; /* 确保 padding 不会撑大宽度 */
padding: 8px;
cursor: pointer;
background-color: var(--el-bg-color);
border-radius: 8px;
box-shadow: 0 0 0 1px var(--el-border-color); box-shadow: 0 0 0 1px var(--el-border-color);
transition: all 0.2s; transition: all 0.2s;
box-sizing: border-box; /* 确保 padding 不会撑大宽度 */
} }
.custom-radio-option:hover { .custom-radio-option:hover {
@@ -171,41 +171,41 @@ const handleDownload = (url: string) => {
} }
.custom-radio-option.selected { .custom-radio-option.selected {
box-shadow: 0 0 0 1px var(--el-color-primary-light-3);
padding: 8px; padding: 8px;
background: var(--el-color-primary-light-9); background: var(--el-color-primary-light-9);
box-shadow: 0 0 0 1px var(--el-color-primary-light-3);
} }
.custom-radio-option.selected::after { .custom-radio-option.selected::after {
content: '';
position: absolute; position: absolute;
right: 0; right: 0;
bottom: 0; bottom: 0;
box-sizing: border-box;
width: 16px; width: 16px;
height: 16px; height: 16px;
content: '';
background-color: var(--el-color-primary); background-color: var(--el-color-primary);
border-radius: 6px 2px; border-radius: 6px 2px;
box-sizing: border-box;
} }
.custom-radio-option.selected::before { .custom-radio-option.selected::before {
content: '';
position: absolute; position: absolute;
right: 3px; right: 3px;
bottom: 7px; bottom: 7px;
z-index: 1;
width: 9px; width: 9px;
height: 4px; height: 4px;
border-left: 1px solid white; content: '';
border-bottom: 1px solid white; border-bottom: 1px solid white;
border-left: 1px solid white;
transform: rotate(-45deg); transform: rotate(-45deg);
z-index: 1;
} }
.download-icon-btn { .download-icon-btn {
font-size: 18px;
cursor: pointer;
margin-right: 10px;
display: flex; /* 为了对齐图标 */ display: flex; /* 为了对齐图标 */
align-items: center; align-items: center;
margin-right: 10px;
font-size: 18px;
cursor: pointer;
} }
</style> </style>

View File

@@ -73,7 +73,7 @@ const handleDownload = (url: string) => {
v-if="selectionDataType === 'text'" v-if="selectionDataType === 'text'"
class="custom-radio-option" class="custom-radio-option"
:class="{ selected: isSelected(item) }" :class="{ selected: isSelected(item) }"
style="width: 100%; flex-shrink: 0" style="flex-shrink: 0; width: 100%"
@click="changeValue(item)" @click="changeValue(item)"
> >
{{ item }} {{ item }}
@@ -90,7 +90,7 @@ const handleDownload = (url: string) => {
<img <img
:src="item" :src="item"
alt="" alt=""
style="width: 80px; height: 80px; border-radius: 8px; display: block" style="display: block; width: 80px; height: 80px; border-radius: 8px"
/> />
</div> </div>
@@ -109,7 +109,7 @@ const handleDownload = (url: string) => {
v-else-if="selectionDataType === 'audio'" v-else-if="selectionDataType === 'audio'"
class="custom-radio-option" class="custom-radio-option"
:class="{ selected: isSelected(item) }" :class="{ selected: isSelected(item) }"
style="width: 300px; flex-shrink: 0" style="flex-shrink: 0; width: 300px"
@click="changeValue(item)" @click="changeValue(item)"
> >
<audio controls :src="item" style="width: 100%; height: 40px"></audio> <audio controls :src="item" style="width: 100%; height: 40px"></audio>
@@ -122,17 +122,17 @@ const handleDownload = (url: string) => {
" "
class="custom-radio-option" class="custom-radio-option"
:class="{ selected: isSelected(item) }" :class="{ selected: isSelected(item) }"
style="width: 100%; flex-shrink: 0" style="flex-shrink: 0; width: 100%"
@click="changeValue(item)" @click="changeValue(item)"
> >
<div <div
style=" style="
display: flex; display: flex;
justify-content: space-between;
align-items: center; align-items: center;
justify-content: space-between;
" "
> >
<div style="width: 92%; display: flex; align-items: center"> <div style="display: flex; align-items: center; width: 92%">
<img <img
style="width: 20px; height: 20px; margin-right: 8px" style="width: 20px; height: 20px; margin-right: 8px"
alt="" alt=""
@@ -156,19 +156,19 @@ const handleDownload = (url: string) => {
/* 这里复用之前的 CSS样式完全一致 */ /* 这里复用之前的 CSS样式完全一致 */
.custom-radio-group { .custom-radio-group {
display: flex; display: flex;
gap: 12px;
flex-wrap: wrap; flex-wrap: wrap;
gap: 12px;
} }
.custom-radio-option { .custom-radio-option {
background-color: var(--el-bg-color);
padding: 8px;
border-radius: 8px;
cursor: pointer;
position: relative; position: relative;
box-sizing: border-box;
padding: 8px;
cursor: pointer;
background-color: var(--el-bg-color);
border-radius: 8px;
box-shadow: 0 0 0 1px var(--el-border-color); box-shadow: 0 0 0 1px var(--el-border-color);
transition: all 0.2s; transition: all 0.2s;
box-sizing: border-box;
} }
.custom-radio-option:hover { .custom-radio-option:hover {
@@ -176,41 +176,41 @@ const handleDownload = (url: string) => {
} }
.custom-radio-option.selected { .custom-radio-option.selected {
box-shadow: 0 0 0 1px var(--el-color-primary-light-3);
padding: 8px; padding: 8px;
background: var(--el-color-primary-light-9); background: var(--el-color-primary-light-9);
box-shadow: 0 0 0 1px var(--el-color-primary-light-3);
} }
.custom-radio-option.selected::after { .custom-radio-option.selected::after {
content: '';
position: absolute; position: absolute;
right: 0; right: 0;
bottom: 0; bottom: 0;
box-sizing: border-box;
width: 16px; width: 16px;
height: 16px; height: 16px;
content: '';
background-color: var(--el-color-primary); background-color: var(--el-color-primary);
border-radius: 6px 2px; border-radius: 6px 2px;
box-sizing: border-box;
} }
.custom-radio-option.selected::before { .custom-radio-option.selected::before {
content: '';
position: absolute; position: absolute;
right: 3px; right: 3px;
bottom: 7px; bottom: 7px;
z-index: 1;
width: 9px; width: 9px;
height: 5px; height: 5px;
border-left: 1px solid white; content: '';
border-bottom: 1px solid white; border-bottom: 1px solid white;
border-left: 1px solid white;
transform: rotate(-45deg); transform: rotate(-45deg);
z-index: 1;
} }
.download-icon-btn { .download-icon-btn {
font-size: 18px;
cursor: pointer;
margin-right: 10px;
display: flex; display: flex;
align-items: center; align-items: center;
margin-right: 10px;
font-size: 18px;
cursor: pointer;
} }
</style> </style>

View File

@@ -71,9 +71,7 @@ function submit() {
</ElButton> </ElButton>
</ElFormItem> </ElFormItem>
</ElForm> </ElForm>
<div class="mb-2.5 mt-2.5 font-semibold"> <div class="mb-2.5 mt-2.5 font-semibold">{{ $t('workflow.result') }}</div>
{{ $t('workflow.result') }}
</div>
<ShowJson :value="result" /> <ShowJson :value="result" />
</div> </div>
</template> </template>

View File

@@ -3,9 +3,11 @@ import type {
ManagedDatasetOption, ManagedDatasetOption,
ManagedDatasetSourceOption, ManagedDatasetSourceOption,
} from './datasetOptions'; } from './datasetOptions';
import huaweiIcon from '#/assets/datacenter/huawei-icon.svg'; import huaweiIcon from '#/assets/datacenter/huawei-icon.svg';
import mysqlIcon from '#/assets/datacenter/mysql-icon.svg'; import mysqlIcon from '#/assets/datacenter/mysql-icon.svg';
import postgresqlIcon from '#/assets/datacenter/postgresql-icon.svg'; import postgresqlIcon from '#/assets/datacenter/postgresql-icon.svg';
import { import {
groupManagedDatasetOptions, groupManagedDatasetOptions,
loadManagedDatasetOptions, loadManagedDatasetOptions,
@@ -24,15 +26,15 @@ const SOURCE_LOGO_MAP: Record<string, string> = {
}; };
type NodeLike = { type NodeLike = {
id: string;
data?: Record<string, any>; data?: Record<string, any>;
id: string;
}; };
type UpdateNodeData = ( type UpdateNodeData = (
nodeId: string, nodeId: string,
data: data:
| Record<string, any> | ((node: Record<string, any>) => Record<string, any>)
| ((node: Record<string, any>) => Record<string, any>), | Record<string, any>,
) => void; ) => void;
type FlowInstance = { type FlowInstance = {
@@ -42,10 +44,10 @@ type FlowInstance = {
type RenderContext = FlowInstance | undefined; type RenderContext = FlowInstance | undefined;
type RendererState = { type RendererState = {
pickerOpen: boolean;
loadingOptions: boolean; loadingOptions: boolean;
optionsLoaded: boolean;
options: ManagedDatasetOption[]; options: ManagedDatasetOption[];
optionsLoaded: boolean;
pickerOpen: boolean;
sources: ManagedDatasetSourceOption[]; sources: ManagedDatasetSourceOption[];
tableSearchText: string; tableSearchText: string;
updateNodeData?: UpdateNodeData; updateNodeData?: UpdateNodeData;
@@ -75,11 +77,13 @@ function getUpdateNodeData(parent: HTMLElement, flowInstance?: RenderContext) {
} }
function getDatasetKey(datasetRef?: DatasetRefPayload | null) { function getDatasetKey(datasetRef?: DatasetRefPayload | null) {
return datasetRef?.tableId == null ? '' : String(datasetRef.tableId); const tableId = datasetRef?.tableId;
return tableId === null || tableId === undefined ? '' : String(tableId);
} }
function getSourceKey(datasetRef?: DatasetRefPayload | null) { function getSourceKey(datasetRef?: DatasetRefPayload | null) {
return datasetRef?.sourceId == null ? '' : String(datasetRef.sourceId); const sourceId = datasetRef?.sourceId;
return sourceId === null || sourceId === undefined ? '' : String(sourceId);
} }
function createSourceOnlyDatasetRef( function createSourceOnlyDatasetRef(
@@ -95,7 +99,7 @@ function createSourceOnlyDatasetRef(
}; };
} }
function escapeHtml(value?: string | number | null) { function escapeHtml(value?: null | number | string) {
return String(value ?? '') return String(value ?? '')
.replaceAll('&', '&amp;') .replaceAll('&', '&amp;')
.replaceAll('<', '&lt;') .replaceAll('<', '&lt;')
@@ -410,7 +414,7 @@ function buildSourceList(
activeKey: string, activeKey: string,
emptyText: string, emptyText: string,
) { ) {
if (!options.length) { if (options.length === 0) {
return `<div class="dataset-node-empty">${emptyText}</div>`; return `<div class="dataset-node-empty">${emptyText}</div>`;
} }
return options return options
@@ -432,7 +436,7 @@ function buildTableList(
activeKey: string, activeKey: string,
emptyText: string, emptyText: string,
) { ) {
if (!options.length) { if (options.length === 0) {
return `<div class="dataset-node-empty">${emptyText}</div>`; return `<div class="dataset-node-empty">${emptyText}</div>`;
} }
return options return options
@@ -465,8 +469,10 @@ function bindInteractiveElements(parent: HTMLElement) {
parent parent
.querySelectorAll<HTMLElement>('button, input, select, textarea') .querySelectorAll<HTMLElement>('button, input, select, textarea')
.forEach((element) => { .forEach((element) => {
element.onpointerdown = (event) => event.stopPropagation(); element.addEventListener('pointerdown', (event) =>
element.onmousedown = (event) => event.stopPropagation(); event.stopPropagation(),
);
element.addEventListener('mousedown', (event) => event.stopPropagation());
}); });
} }
@@ -539,7 +545,7 @@ export function rerenderSearchNode(
state.pickerOpen = false; state.pickerOpen = false;
const nextDatasetRef = createSourceOnlyDatasetRef(source); const nextDatasetRef = createSourceOnlyDatasetRef(source);
node.data = { node.data = {
...(node.data || {}), ...node.data,
datasetRef: nextDatasetRef, datasetRef: nextDatasetRef,
sourceName: source.sourceName, sourceName: source.sourceName,
sourceType: source.sourceType, sourceType: source.sourceType,
@@ -606,7 +612,7 @@ export function rerenderSaveNode(
return; return;
} }
node.data = { node.data = {
...(node.data || {}), ...node.data,
datasetRef: option.datasetRef, datasetRef: option.datasetRef,
sourceName: option.sourceName, sourceName: option.sourceName,
sourceType: option.sourceType, sourceType: option.sourceType,

View File

@@ -1,12 +1,12 @@
import { api } from '#/api/request'; import { api } from '#/api/request';
export interface DatasetRefPayload { export interface DatasetRefPayload {
sourceId: number | string | null; sourceId: null | number | string;
catalogId?: number | string | null; catalogId?: null | number | string;
catalogName?: string; catalogName?: string;
tableId: number | string | null; tableId: null | number | string;
tableName: string; tableName: string;
versionId?: number | string | null; versionId?: null | number | string;
} }
export interface ManagedDatasetFieldOption { export interface ManagedDatasetFieldOption {
@@ -57,21 +57,25 @@ function shouldSkipSourceError(error: any) {
function dedupeManagedDatasetOptions(options: ManagedDatasetOption[]) { function dedupeManagedDatasetOptions(options: ManagedDatasetOption[]) {
const uniqueOptions = new Map<string, ManagedDatasetOption>(); const uniqueOptions = new Map<string, ManagedDatasetOption>();
for (const option of options || []) { for (const option of options || []) {
const key = option.datasetRef?.tableId != null const tableId = option.datasetRef?.tableId;
? String(option.datasetRef.tableId) const key =
: [ tableId === null || tableId === undefined
option.datasetRef?.sourceId ?? '', ? [
option.datasetRef?.catalogId ?? '', option.datasetRef?.sourceId ?? '',
option.tableName ?? '', option.datasetRef?.catalogId ?? '',
].join(':'); option.tableName ?? '',
].join(':')
: String(tableId);
if (!uniqueOptions.has(key)) { if (!uniqueOptions.has(key)) {
uniqueOptions.set(key, option); uniqueOptions.set(key, option);
} }
} }
return Array.from(uniqueOptions.values()); return [...uniqueOptions.values()];
} }
export async function loadManagedDatasetOptions(): Promise<ManagedDatasetOption[]> { export async function loadManagedDatasetOptions(): Promise<
ManagedDatasetOption[]
> {
const sourceRes = await api.get('/api/v1/datacenterSource/page', { const sourceRes = await api.get('/api/v1/datacenterSource/page', {
params: { params: {
pageNumber: 1, pageNumber: 1,
@@ -89,19 +93,23 @@ export async function loadManagedDatasetOptions(): Promise<ManagedDatasetOption[
}); });
const catalogs = catalogRes.data || []; const catalogs = catalogRes.data || [];
for (const catalog of catalogs) { for (const catalog of catalogs) {
const tableRes = await api.get('/api/v1/datacenterDataset/managedTables', { const tableRes = await api.get(
params: { '/api/v1/datacenterDataset/managedTables',
sourceId: source.id, {
catalogId: catalog.id, params: {
sourceId: source.id,
catalogId: catalog.id,
},
}, },
}); );
const tables = tableRes.data || []; const tables = tableRes.data || [];
for (const table of tables) { for (const table of tables) {
const label = `${source.sourceName} / ${catalog.catalogName} / ${table.tableName}`; const label = `${source.sourceName} / ${catalog.catalogName} / ${table.tableName}`;
options.push({ options.push({
label, label,
value: table.id, value: table.id,
keywords: `${source.sourceName} ${catalog.catalogName} ${table.tableName}`.toLowerCase(), keywords:
`${source.sourceName} ${catalog.catalogName} ${table.tableName}`.toLowerCase(),
sourceName: source.sourceName, sourceName: source.sourceName,
sourceType: source.sourceType, sourceType: source.sourceType,
catalogName: catalog.catalogName, catalogName: catalog.catalogName,
@@ -132,7 +140,7 @@ export function groupManagedDatasetOptions(
const grouped = new Map<number | string, ManagedDatasetSourceOption>(); const grouped = new Map<number | string, ManagedDatasetSourceOption>();
for (const option of dedupeManagedDatasetOptions(options || [])) { for (const option of dedupeManagedDatasetOptions(options || [])) {
const sourceId = option.datasetRef?.sourceId; const sourceId = option.datasetRef?.sourceId;
if (sourceId == null) { if (sourceId === null || sourceId === undefined) {
continue; continue;
} }
if (!grouped.has(sourceId)) { if (!grouped.has(sourceId)) {
@@ -145,9 +153,12 @@ export function groupManagedDatasetOptions(
tables: [], tables: [],
}); });
} }
grouped.get(sourceId)!.tables.push(option); const group = grouped.get(sourceId);
if (group) {
group.tables.push(option);
}
} }
return Array.from(grouped.values()).map((item) => ({ return [...grouped.values()].map((item) => ({
...item, ...item,
keywords: `${item.sourceName} ${item.tables keywords: `${item.sourceName} ${item.tables
.map((table) => `${table.catalogName} ${table.tableName}`) .map((table) => `${table.catalogName} ${table.tableName}`)

View File

@@ -25,7 +25,7 @@ const dialogVisible = ref(false);
<style scoped> <style scoped>
.sys-apikey-container { .sys-apikey-container {
height: 100%;
width: 100%; width: 100%;
height: 100%;
} }
</style> </style>

View File

@@ -128,7 +128,11 @@ function remove(row: any) {
{{ row.title }} {{ row.title }}
</template> </template>
</ElTableColumn> </ElTableColumn>
<ElTableColumn :label="$t('common.handle')" width="90" align="right"> <ElTableColumn
:label="$t('common.handle')"
width="90"
align="right"
>
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<ElButton link type="primary" @click="showDialog(row)"> <ElButton link type="primary" @click="showDialog(row)">

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import {onMounted, ref} from 'vue'; import { onMounted, ref } from 'vue';
import {$t} from '@easyflow/locales'; import { $t } from '@easyflow/locales';
import { import {
ElAlert, ElAlert,
@@ -14,7 +14,7 @@ import {
ElSelect, ElSelect,
} from 'element-plus'; } from 'element-plus';
import {api} from '#/api/request.js'; import { api } from '#/api/request.js';
import providerList from '#/views/ai/model/modelUtils/providerList.json'; import providerList from '#/views/ai/model/modelUtils/providerList.json';
interface ProviderOptionExtra { interface ProviderOptionExtra {

View File

@@ -475,24 +475,24 @@ onBeforeUnmount(() => {
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
min-height: 0; min-height: 0;
margin-top: 0;
padding-top: 12px; padding-top: 12px;
background: transparent; margin-top: 0;
overflow: hidden; overflow: hidden;
background: transparent;
} }
.workspace-toolbar { .workspace-toolbar {
display: flex; display: flex;
gap: 12px;
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
gap: 12px;
padding: 0 0 12px; padding: 0 0 12px;
} }
.toolbar-left { .toolbar-left {
display: flex; display: flex;
align-items: center;
gap: 8px; gap: 8px;
align-items: center;
} }
.toolbar-button { .toolbar-button {
@@ -501,8 +501,8 @@ onBeforeUnmount(() => {
} }
.workspace-body { .workspace-body {
width: 100%;
flex: 1; flex: 1;
width: 100%;
min-height: 0; min-height: 0;
overflow: hidden; overflow: hidden;
background: transparent; background: transparent;
@@ -519,13 +519,13 @@ onBeforeUnmount(() => {
} }
.workspace-body :deep([data-panel-resize-handle-enabled]::before) { .workspace-body :deep([data-panel-resize-handle-enabled]::before) {
content: '';
position: absolute; position: absolute;
top: 20px; top: 20px;
bottom: 20px; bottom: 20px;
left: 50%; left: 50%;
width: 1px; width: 1px;
background: hsl(var(--border) / 0.32); content: '';
background: hsl(var(--border) / 32%);
transform: translateX(-50%); transform: translateX(-50%);
} }

View File

@@ -237,8 +237,8 @@ onBeforeUnmount(() => {
.search-actions { .search-actions {
display: flex; display: flex;
align-items: center;
gap: 6px; gap: 6px;
align-items: center;
} }
.search-row :deep(.el-input) { .search-row :deep(.el-input) {
@@ -250,9 +250,9 @@ onBeforeUnmount(() => {
} }
.action-icon { .action-icon {
flex-shrink: 0;
width: 14px; width: 14px;
height: 14px; height: 14px;
flex-shrink: 0;
} }
.create-action { .create-action {
@@ -266,22 +266,22 @@ onBeforeUnmount(() => {
min-width: 36px; min-width: 36px;
height: 36px; height: 36px;
padding-inline: 0; padding-inline: 0;
border-color: hsl(var(--border) / 0.9);
background: hsl(var(--card));
color: hsl(var(--text-strong)); color: hsl(var(--text-strong));
background: hsl(var(--card));
border-color: hsl(var(--border) / 90%);
box-shadow: none; box-shadow: none;
} }
.refresh-action:hover { .refresh-action:hover {
background: hsl(var(--surface-subtle));
color: hsl(var(--foreground)); color: hsl(var(--foreground));
background: hsl(var(--surface-subtle));
} }
.tree-scroll { .tree-scroll {
flex: 1; flex: 1;
min-height: 0; min-height: 0;
overflow: auto;
padding-right: 4px; padding-right: 4px;
overflow: auto;
} }
.tree-list { .tree-list {
@@ -293,17 +293,17 @@ onBeforeUnmount(() => {
.tree-node { .tree-node {
display: flex; display: flex;
align-items: center;
gap: 12px; gap: 12px;
align-items: center;
min-height: 62px; min-height: 62px;
padding: 12px 14px; padding: 12px 14px;
border: 1px solid hsl(var(--border) / 0.52); color: hsl(var(--foreground));
border-radius: 14px;
background: hsl(var(--card) / 0.92);
box-shadow: 0 10px 22px -22px hsl(var(--foreground) / 0.22);
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
color: hsl(var(--foreground)); background: hsl(var(--card) / 92%);
border: 1px solid hsl(var(--border) / 52%);
border-radius: 14px;
box-shadow: 0 10px 22px -22px hsl(var(--foreground) / 22%);
transition: transition:
transform 0.16s, transform 0.16s,
background-color 0.16s, background-color 0.16s,
@@ -313,19 +313,19 @@ onBeforeUnmount(() => {
} }
.tree-node:hover { .tree-node:hover {
transform: translateY(-1px);
border-color: hsl(var(--border) / 0.74);
background: hsl(var(--card)); background: hsl(var(--card));
box-shadow: 0 16px 30px -24px hsl(var(--foreground) / 0.22); border-color: hsl(var(--border) / 74%);
box-shadow: 0 16px 30px -24px hsl(var(--foreground) / 22%);
transform: translateY(-1px);
} }
.tree-node.is-selected { .tree-node.is-selected {
border-color: hsl(var(--primary) / 0.24);
background: hsl(var(--primary) / 0.08);
color: hsl(var(--foreground)); color: hsl(var(--foreground));
background: hsl(var(--primary) / 8%);
border-color: hsl(var(--primary) / 24%);
box-shadow: box-shadow:
inset 0 0 0 1px hsl(var(--primary) / 0.12), inset 0 0 0 1px hsl(var(--primary) / 12%),
0 18px 34px -28px hsl(var(--primary) / 0.24); 0 18px 34px -28px hsl(var(--primary) / 24%);
} }
.tree-node--source { .tree-node--source {
@@ -333,17 +333,17 @@ onBeforeUnmount(() => {
} }
.tree-node--table { .tree-node--table {
margin-left: 20px;
align-items: center; align-items: center;
margin-left: 20px;
} }
.node-arrow { .node-arrow {
display: inline-flex; display: inline-flex;
flex-shrink: 0;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 16px; width: 16px;
height: 16px; height: 16px;
flex-shrink: 0;
transition: transform 0.15s; transition: transform 0.15s;
} }
@@ -359,18 +359,18 @@ onBeforeUnmount(() => {
.node-media { .node-media {
display: inline-flex; display: inline-flex;
flex-shrink: 0;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 34px; width: 34px;
height: 34px; height: 34px;
flex-shrink: 0;
margin-top: 1px; margin-top: 1px;
background: hsl(var(--surface-subtle) / 92%);
border-radius: 11px; border-radius: 11px;
background: hsl(var(--surface-subtle) / 0.92);
} }
.tree-node.is-selected .node-media { .tree-node.is-selected .node-media {
background: hsl(var(--primary) / 0.12); background: hsl(var(--primary) / 12%);
} }
.node-media :deep(svg) { .node-media :deep(svg) {
@@ -379,9 +379,9 @@ onBeforeUnmount(() => {
} }
.node-icon { .node-icon {
flex-shrink: 0;
width: 17px; width: 17px;
height: 17px; height: 17px;
flex-shrink: 0;
color: hsl(var(--text-muted)); color: hsl(var(--text-muted));
} }
@@ -391,46 +391,46 @@ onBeforeUnmount(() => {
.node-content { .node-content {
display: flex; display: flex;
flex-direction: column;
flex: 1; flex: 1;
min-width: 0; flex-direction: column;
align-items: flex-start;
gap: 4px; gap: 4px;
align-items: flex-start;
min-width: 0;
} }
.node-label { .node-label {
display: -webkit-box; display: -webkit-box;
overflow: hidden; overflow: hidden;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical;
white-space: normal;
font-size: 14px; font-size: 14px;
line-height: 1.3; line-height: 1.3;
letter-spacing: 0.01em; letter-spacing: 0.01em;
white-space: normal;
-webkit-box-orient: vertical;
} }
.node-meta { .node-meta {
font-size: 12px; font-size: 12px;
line-height: 1.2;
font-weight: 500; font-weight: 500;
line-height: 1.2;
color: hsl(var(--text-muted)); color: hsl(var(--text-muted));
} }
.node-status-dot { .node-status-dot {
flex-shrink: 0;
width: 8px; width: 8px;
height: 8px; height: 8px;
flex-shrink: 0;
margin-left: auto; margin-left: auto;
border-radius: 999px;
background: hsl(var(--destructive)); background: hsl(var(--destructive));
box-shadow: 0 0 0 3px hsl(var(--destructive) / 0.12); border-radius: 999px;
box-shadow: 0 0 0 3px hsl(var(--destructive) / 12%);
} }
.tree-empty { .tree-empty {
padding: 32px 16px; padding: 32px 16px;
text-align: center;
font-size: 13px; font-size: 13px;
color: hsl(var(--text-muted)); color: hsl(var(--text-muted));
text-align: center;
} }
.connection-context-menu { .connection-context-menu {
@@ -438,10 +438,10 @@ onBeforeUnmount(() => {
z-index: 30; z-index: 30;
min-width: 136px; min-width: 136px;
padding: 6px; padding: 6px;
border: 1px solid hsl(var(--border) / 0.7);
border-radius: 12px;
background: hsl(var(--popover)); background: hsl(var(--popover));
box-shadow: 0 18px 34px -28px hsl(var(--foreground) / 0.26); border: 1px solid hsl(var(--border) / 70%);
border-radius: 12px;
box-shadow: 0 18px 34px -28px hsl(var(--foreground) / 26%);
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
} }
@@ -451,17 +451,17 @@ onBeforeUnmount(() => {
width: 100%; width: 100%;
min-height: 34px; min-height: 34px;
padding: 0 10px; padding: 0 10px;
border: 0;
border-radius: 8px;
background: transparent;
color: hsl(var(--foreground));
font-size: 13px; font-size: 13px;
color: hsl(var(--foreground));
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
background: transparent;
border: 0;
border-radius: 8px;
} }
.context-menu-item:hover { .context-menu-item:hover {
background: hsl(var(--accent) / 0.86); background: hsl(var(--accent) / 86%);
} }
.context-menu-item--danger { .context-menu-item--danger {
@@ -469,6 +469,6 @@ onBeforeUnmount(() => {
} }
.context-menu-item--danger:hover { .context-menu-item--danger:hover {
background: hsl(var(--destructive) / 0.1); background: hsl(var(--destructive) / 10%);
} }
</style> </style>

View File

@@ -14,8 +14,8 @@ import {
defineProps<{ defineProps<{
actionLoading: boolean; actionLoading: boolean;
managedTables: any[];
fieldOptions: { label: string; value: string }[]; fieldOptions: { label: string; value: string }[];
managedTables: any[];
pendingUploadFile: File | null; pendingUploadFile: File | null;
}>(); }>();
@@ -29,7 +29,9 @@ const emit = defineEmits<{
}>(); }>();
const visible = defineModel<boolean>('visible', { default: false }); const visible = defineModel<boolean>('visible', { default: false });
const activeAction = ref<'derive' | 'export' | 'import' | 'merge' | 'split'>('import'); const activeAction = ref<'derive' | 'export' | 'import' | 'merge' | 'split'>(
'import',
);
const splitForm = defineModel<any>('splitForm', { required: true }); const splitForm = defineModel<any>('splitForm', { required: true });
const mergeForm = defineModel<any>('mergeForm', { required: true }); const mergeForm = defineModel<any>('mergeForm', { required: true });
@@ -47,6 +49,10 @@ const drawerTitle = computed(() => {
return titles[activeAction.value] || '数据操作'; return titles[activeAction.value] || '数据操作';
}); });
const deriveRenamePlaceholder = '字段重命名 JSON例如 {"old":"new"}';
const deriveFilterPlaceholder =
'筛选条件 JSON例如 [{"column":"status","operator":"EQ","value":"OPEN"}]';
function open(action: 'derive' | 'export' | 'import' | 'merge' | 'split') { function open(action: 'derive' | 'export' | 'import' | 'merge' | 'split') {
activeAction.value = action; activeAction.value = action;
visible.value = true; visible.value = true;
@@ -58,11 +64,28 @@ function handleUploadChange(file: UploadUserFile) {
function handleConfirm() { function handleConfirm() {
const action = activeAction.value; const action = activeAction.value;
if (action === 'import') emit('import'); switch (action) {
else if (action === 'split') emit('split'); case 'derive': {
else if (action === 'merge') emit('merge'); emit('derive');
else if (action === 'derive') emit('derive'); break;
else if (action === 'export') emit('export'); }
case 'export': {
emit('export');
break;
}
case 'import': {
emit('import');
break;
}
case 'merge': {
emit('merge');
break;
}
case 'split': {
emit('split');
break;
}
}
} }
defineExpose({ open }); defineExpose({ open });
@@ -96,7 +119,10 @@ defineExpose({ open });
<ElOption label="按字段值" value="BY_FIELD_VALUE" /> <ElOption label="按字段值" value="BY_FIELD_VALUE" />
<ElOption label="按工作表" value="BY_SHEET" /> <ElOption label="按工作表" value="BY_SHEET" />
</ElSelect> </ElSelect>
<ElInput v-model="splitForm.targetNamePrefix" placeholder="新表名前缀" /> <ElInput
v-model="splitForm.targetNamePrefix"
placeholder="新表名前缀"
/>
<ElInput <ElInput
v-if="splitForm.splitMode === 'BY_ROW_COUNT'" v-if="splitForm.splitMode === 'BY_ROW_COUNT'"
v-model="splitForm.rowBatchSize" v-model="splitForm.rowBatchSize"
@@ -154,13 +180,13 @@ defineExpose({ open });
v-model="deriveForm.renameMappingsText" v-model="deriveForm.renameMappingsText"
type="textarea" type="textarea"
:rows="4" :rows="4"
placeholder='字段重命名 JSON例如 {"old":"new"}' :placeholder="deriveRenamePlaceholder"
/> />
<ElInput <ElInput
v-model="deriveForm.filtersText" v-model="deriveForm.filtersText"
type="textarea" type="textarea"
:rows="5" :rows="5"
placeholder='筛选条件 JSON例如 [{"column":"status","operator":"EQ","value":"OPEN"}]' :placeholder="deriveFilterPlaceholder"
/> />
</template> </template>
@@ -177,12 +203,22 @@ defineExpose({ open });
<template #footer> <template #footer>
<div class="drawer-footer"> <div class="drawer-footer">
<ElButton @click="visible = false">取消</ElButton> <ElButton @click="visible = false">取消</ElButton>
<ElButton type="primary" :loading="actionLoading" @click="handleConfirm"> <ElButton
{{ activeAction === 'import' ? '开始导入' : type="primary"
activeAction === 'split' ? '开始拆分' : :loading="actionLoading"
activeAction === 'merge' ? '开始合并' : @click="handleConfirm"
activeAction === 'derive' ? '开始生成' : >
'生成并下载' }} {{
activeAction === 'import'
? '开始导入'
: activeAction === 'split'
? '开始拆分'
: activeAction === 'merge'
? '开始合并'
: activeAction === 'derive'
? '开始生成'
: '生成并下载'
}}
</ElButton> </ElButton>
</div> </div>
</template> </template>
@@ -198,13 +234,13 @@ defineExpose({ open });
.upload-hint { .upload-hint {
padding: 24px; padding: 24px;
color: hsl(var(--text-muted));
font-size: 14px; font-size: 14px;
color: hsl(var(--text-muted));
} }
.drawer-footer { .drawer-footer {
display: flex; display: flex;
align-items: center;
gap: 8px; gap: 8px;
align-items: center;
} }
</style> </style>

Some files were not shown because too many files have changed in this diff Show More