diff --git a/easyflow-ui-admin/app/src/locales/langs/en-US/button.json b/easyflow-ui-admin/app/src/locales/langs/en-US/button.json index ebb6527f..e4a3440e 100644 --- a/easyflow-ui-admin/app/src/locales/langs/en-US/button.json +++ b/easyflow-ui-admin/app/src/locales/langs/en-US/button.json @@ -51,6 +51,8 @@ "submitPublishApproval": "Submit Publish Approval", "viewSegmentation": "View Segments", "continueProcess": "Continue", + "backToTop": "Back to top", + "goToBottom": "Go to bottom", "startIndex": "Start Indexing", "retryParse": "Retry Parse", "retryIndex": "Retry Index" diff --git a/easyflow-ui-admin/app/src/locales/langs/zh-CN/button.json b/easyflow-ui-admin/app/src/locales/langs/zh-CN/button.json index 2b6bee1f..f10413ba 100644 --- a/easyflow-ui-admin/app/src/locales/langs/zh-CN/button.json +++ b/easyflow-ui-admin/app/src/locales/langs/zh-CN/button.json @@ -51,6 +51,8 @@ "submitPublishApproval": "提交发布审批", "viewSegmentation": "查看分段", "continueProcess": "继续处理", + "backToTop": "回到页顶", + "goToBottom": "到达页末", "startIndex": "开始向量化", "retryParse": "重试解析", "retryIndex": "重试向量化" diff --git a/easyflow-ui-admin/app/src/views/ai/documentCollection/SegmenterDoc.vue b/easyflow-ui-admin/app/src/views/ai/documentCollection/SegmenterDoc.vue index 3b1bf2bc..eee08992 100644 --- a/easyflow-ui-admin/app/src/views/ai/documentCollection/SegmenterDoc.vue +++ b/easyflow-ui-admin/app/src/views/ai/documentCollection/SegmenterDoc.vue @@ -432,19 +432,7 @@ watch( -
- -
- -
- {{ previewError }} -
- - @@ -484,6 +484,15 @@ watch( grid-column: 1 / -1; } +.workbench__actions { + display: flex; + flex-wrap: wrap; + gap: 8px; + justify-content: flex-end; + padding-bottom: 16px; + border-bottom: 1px solid var(--el-border-color-lighter); +} + .workbench__content { min-height: 620px; } @@ -500,22 +509,6 @@ watch( border-radius: 16px; } -.workbench__footer { - position: sticky; - bottom: 0; - display: flex; - justify-content: flex-end; - gap: 12px; - padding: 16px 0 8px; - margin-top: auto; - background: linear-gradient( - 180deg, - rgb(246 248 251 / 0%) 0%, - rgb(246 248 251 / 82%) 30%, - rgb(246 248 251 / 100%) 100% - ); -} - :deep(.el-form-item__label) { padding-bottom: 6px; font-size: 13px; diff --git a/easyflow-ui-admin/packages/@core/base/icons/src/lucide.ts b/easyflow-ui-admin/packages/@core/base/icons/src/lucide.ts index 0a79f773..c0ea9cd5 100644 --- a/easyflow-ui-admin/packages/@core/base/icons/src/lucide.ts +++ b/easyflow-ui-admin/packages/@core/base/icons/src/lucide.ts @@ -1,5 +1,6 @@ export { ArrowDown, + ArrowDownToLine, ArrowLeft, ArrowLeftToLine, ArrowRightLeft, diff --git a/easyflow-ui-admin/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue b/easyflow-ui-admin/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue index 2838d090..8ce3fe97 100644 --- a/easyflow-ui-admin/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue +++ b/easyflow-ui-admin/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue @@ -3,7 +3,7 @@ import type { BacktopProps } from './backtop'; import { computed } from 'vue'; -import { ArrowUpToLine } from '@easyflow-core/icons'; +import { ArrowDownToLine, ArrowUpToLine } from '@easyflow-core/icons'; import { EasyFlowButton } from '../button'; import { useBackTop } from './use-backtop'; @@ -14,9 +14,11 @@ defineOptions({ name: 'BackTop' }); const props = withDefaults(defineProps(), { bottom: 20, + bottomLabel: 'Scroll to bottom', isGroup: false, right: 24, target: '', + topLabel: 'Back to top', visibilityHeight: 200, }); @@ -25,19 +27,45 @@ const backTopStyle = computed(() => ({ right: `${props.right}px`, })); -const { handleClick, visible } = useBackTop(props); +const { + canScrollDown, + canScrollUp, + handleBottomClick, + handleClick, + scrollable, + visible, +} = useBackTop(props); diff --git a/easyflow-ui-admin/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts b/easyflow-ui-admin/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts index de422c0c..74a53366 100644 --- a/easyflow-ui-admin/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts +++ b/easyflow-ui-admin/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts @@ -6,6 +6,20 @@ export const backtopProps = { default: 40, type: Number, }, + /** + * @zh_CN scroll-to-bottom button label. + */ + bottomLabel: { + default: 'Scroll to bottom', + type: String, + }, + /** + * @zh_CN whether to show top and bottom controls as a group. + */ + isGroup: { + default: false, + type: Boolean, + }, /** * @zh_CN right distance. */ @@ -20,6 +34,13 @@ export const backtopProps = { default: '', type: String, }, + /** + * @zh_CN back-to-top button label. + */ + topLabel: { + default: 'Back to top', + type: String, + }, /** * @zh_CN the button will not show until the scroll height reaches this value. */ @@ -31,8 +52,10 @@ export const backtopProps = { export interface BacktopProps { bottom?: number; + bottomLabel?: string; isGroup?: boolean; right?: number; target?: string; + topLabel?: string; visibilityHeight?: number; } diff --git a/easyflow-ui-admin/packages/@core/ui-kit/shadcn-ui/src/components/back-top/use-backtop.ts b/easyflow-ui-admin/packages/@core/ui-kit/shadcn-ui/src/components/back-top/use-backtop.ts index 6a51a95a..a64278a9 100644 --- a/easyflow-ui-admin/packages/@core/ui-kit/shadcn-ui/src/components/back-top/use-backtop.ts +++ b/easyflow-ui-admin/packages/@core/ui-kit/shadcn-ui/src/components/back-top/use-backtop.ts @@ -1,16 +1,31 @@ import type { BacktopProps } from './backtop'; -import { onMounted, ref, shallowRef } from 'vue'; +import { nextTick, onMounted, ref, shallowRef } from 'vue'; -import { useEventListener, useThrottleFn } from '@vueuse/core'; +import { + useEventListener, + useResizeObserver, + useThrottleFn, +} from '@vueuse/core'; export const useBackTop = (props: BacktopProps) => { const el = shallowRef(); const container = shallowRef(); + const resizeTarget = shallowRef(); + const canScrollDown = ref(false); + const canScrollUp = ref(false); + const scrollable = ref(false); const visible = ref(false); const handleScroll = () => { if (el.value) { + const maxScrollTop = Math.max( + el.value.scrollHeight - el.value.clientHeight, + 0, + ); + scrollable.value = maxScrollTop > 1; + canScrollUp.value = el.value.scrollTop > 1; + canScrollDown.value = el.value.scrollTop < maxScrollTop - 1; visible.value = el.value.scrollTop >= (props?.visibilityHeight ?? 0); } }; @@ -19,12 +34,24 @@ export const useBackTop = (props: BacktopProps) => { el.value?.scrollTo({ behavior: 'smooth', top: 0 }); }; + const handleBottomClick = () => { + if (!el.value) { + return; + } + el.value.scrollTo({ + behavior: 'smooth', + top: Math.max(el.value.scrollHeight - el.value.clientHeight, 0), + }); + }; + const handleScrollThrottled = useThrottleFn(handleScroll, 300, true); useEventListener(container, 'scroll', handleScrollThrottled); + useResizeObserver(resizeTarget, handleScrollThrottled); onMounted(() => { container.value = document; el.value = document.documentElement; + resizeTarget.value = document.body; if (props.target) { el.value = document.querySelector(props.target) ?? undefined; @@ -33,13 +60,17 @@ export const useBackTop = (props: BacktopProps) => { throw new Error(`target does not exist: ${props.target}`); } container.value = el.value; + resizeTarget.value = el.value; } - // Give visible an initial value, fix #13066 - handleScroll(); + void nextTick(handleScroll); }); return { + canScrollDown, + canScrollUp, + handleBottomClick, handleClick, + scrollable, visible, }; }; diff --git a/easyflow-ui-admin/packages/effects/layouts/src/basic/layout.vue b/easyflow-ui-admin/packages/effects/layouts/src/basic/layout.vue index 21822f91..9d072c01 100644 --- a/easyflow-ui-admin/packages/effects/layouts/src/basic/layout.vue +++ b/easyflow-ui-admin/packages/effects/layouts/src/basic/layout.vue @@ -425,7 +425,11 @@ const headerSlots = computed(() => { @clear-preferences-and-logout="clearPreferencesAndLogout" /> - +