发布 v1.10 #5

Merged
czm merged 147 commits from develop into main 2026-08-20 11:36:27 +08:00
8 changed files with 128 additions and 44 deletions
Showing only changes of commit f92707dac8 - Show all commits

View File

@@ -51,6 +51,8 @@
"submitPublishApproval": "Submit Publish Approval", "submitPublishApproval": "Submit Publish Approval",
"viewSegmentation": "View Segments", "viewSegmentation": "View Segments",
"continueProcess": "Continue", "continueProcess": "Continue",
"backToTop": "Back to top",
"goToBottom": "Go to bottom",
"startIndex": "Start Indexing", "startIndex": "Start Indexing",
"retryParse": "Retry Parse", "retryParse": "Retry Parse",
"retryIndex": "Retry Index" "retryIndex": "Retry Index"

View File

@@ -51,6 +51,8 @@
"submitPublishApproval": "提交发布审批", "submitPublishApproval": "提交发布审批",
"viewSegmentation": "查看分段", "viewSegmentation": "查看分段",
"continueProcess": "继续处理", "continueProcess": "继续处理",
"backToTop": "回到页顶",
"goToBottom": "到达页末",
"startIndex": "开始向量化", "startIndex": "开始向量化",
"retryParse": "重试解析", "retryParse": "重试解析",
"retryIndex": "重试向量化" "retryIndex": "重试向量化"

View File

@@ -432,19 +432,7 @@ watch(
</div> </div>
</ElForm> </ElForm>
<section class="workbench__content"> <div class="workbench__actions">
<SplitterDocPreview
:loading="previewLoading"
:preview-items="previewItems"
@preview-session-change="handlePreviewSessionChange"
/>
</section>
<div v-if="previewError" class="workbench__error">
{{ previewError }}
</div>
<div class="workbench__footer">
<ElButton :disabled="startLoading" @click="handleCancel"> <ElButton :disabled="startLoading" @click="handleCancel">
{{ $t('button.cancel') }} {{ $t('button.cancel') }}
</ElButton> </ElButton>
@@ -457,6 +445,18 @@ watch(
{{ $t('button.startIndex') }} {{ $t('button.startIndex') }}
</ElButton> </ElButton>
</div> </div>
<section class="workbench__content">
<SplitterDocPreview
:loading="previewLoading"
:preview-items="previewItems"
@preview-session-change="handlePreviewSessionChange"
/>
</section>
<div v-if="previewError" class="workbench__error">
{{ previewError }}
</div>
</div> </div>
</template> </template>
@@ -484,6 +484,15 @@ watch(
grid-column: 1 / -1; 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 { .workbench__content {
min-height: 620px; min-height: 620px;
} }
@@ -500,22 +509,6 @@ watch(
border-radius: 16px; 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) { :deep(.el-form-item__label) {
padding-bottom: 6px; padding-bottom: 6px;
font-size: 13px; font-size: 13px;

View File

@@ -1,5 +1,6 @@
export { export {
ArrowDown, ArrowDown,
ArrowDownToLine,
ArrowLeft, ArrowLeft,
ArrowLeftToLine, ArrowLeftToLine,
ArrowRightLeft, ArrowRightLeft,

View File

@@ -3,7 +3,7 @@ import type { BacktopProps } from './backtop';
import { computed } from 'vue'; import { computed } from 'vue';
import { ArrowUpToLine } from '@easyflow-core/icons'; import { ArrowDownToLine, ArrowUpToLine } from '@easyflow-core/icons';
import { EasyFlowButton } from '../button'; import { EasyFlowButton } from '../button';
import { useBackTop } from './use-backtop'; import { useBackTop } from './use-backtop';
@@ -14,9 +14,11 @@ defineOptions({ name: 'BackTop' });
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
bottom: 20, bottom: 20,
bottomLabel: 'Scroll to bottom',
isGroup: false, isGroup: false,
right: 24, right: 24,
target: '', target: '',
topLabel: 'Back to top',
visibilityHeight: 200, visibilityHeight: 200,
}); });
@@ -25,19 +27,45 @@ const backTopStyle = computed(() => ({
right: `${props.right}px`, right: `${props.right}px`,
})); }));
const { handleClick, visible } = useBackTop(props); const {
canScrollDown,
canScrollUp,
handleBottomClick,
handleClick,
scrollable,
visible,
} = useBackTop(props);
</script> </script>
<template> <template>
<transition name="fade-down"> <transition name="fade-down">
<EasyFlowButton <div
v-if="visible" v-if="isGroup ? scrollable : visible"
:style="backTopStyle" :style="backTopStyle"
class="dark:bg-accent dark:hover:bg-heavy bg-background hover:bg-heavy data shadow-float z-popup fixed bottom-10 size-10 rounded-full duration-500" class="z-popup fixed flex flex-col gap-2"
>
<EasyFlowButton
:aria-label="topLabel"
:disabled="isGroup && !canScrollUp"
:title="topLabel"
class="dark:bg-accent dark:hover:bg-heavy bg-background hover:bg-heavy shadow-float size-10 rounded-full duration-150"
size="icon" size="icon"
variant="icon" variant="icon"
@click="handleClick" @click="handleClick"
> >
<ArrowUpToLine class="size-4" /> <ArrowUpToLine class="size-4" />
</EasyFlowButton> </EasyFlowButton>
<EasyFlowButton
v-if="isGroup"
:aria-label="bottomLabel"
:disabled="!canScrollDown"
:title="bottomLabel"
class="dark:bg-accent dark:hover:bg-heavy bg-background hover:bg-heavy shadow-float size-10 rounded-full duration-150"
size="icon"
variant="icon"
@click="handleBottomClick"
>
<ArrowDownToLine class="size-4" />
</EasyFlowButton>
</div>
</transition> </transition>
</template> </template>

View File

@@ -6,6 +6,20 @@ export const backtopProps = {
default: 40, default: 40,
type: Number, 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. * @zh_CN right distance.
*/ */
@@ -20,6 +34,13 @@ export const backtopProps = {
default: '', default: '',
type: String, 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. * @zh_CN the button will not show until the scroll height reaches this value.
*/ */
@@ -31,8 +52,10 @@ export const backtopProps = {
export interface BacktopProps { export interface BacktopProps {
bottom?: number; bottom?: number;
bottomLabel?: string;
isGroup?: boolean; isGroup?: boolean;
right?: number; right?: number;
target?: string; target?: string;
topLabel?: string;
visibilityHeight?: number; visibilityHeight?: number;
} }

View File

@@ -1,16 +1,31 @@
import type { BacktopProps } from './backtop'; 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) => { export const useBackTop = (props: BacktopProps) => {
const el = shallowRef<HTMLElement>(); const el = shallowRef<HTMLElement>();
const container = shallowRef<Document | HTMLElement>(); const container = shallowRef<Document | HTMLElement>();
const resizeTarget = shallowRef<HTMLElement>();
const canScrollDown = ref(false);
const canScrollUp = ref(false);
const scrollable = ref(false);
const visible = ref(false); const visible = ref(false);
const handleScroll = () => { const handleScroll = () => {
if (el.value) { 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); visible.value = el.value.scrollTop >= (props?.visibilityHeight ?? 0);
} }
}; };
@@ -19,12 +34,24 @@ export const useBackTop = (props: BacktopProps) => {
el.value?.scrollTo({ behavior: 'smooth', top: 0 }); 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); const handleScrollThrottled = useThrottleFn(handleScroll, 300, true);
useEventListener(container, 'scroll', handleScrollThrottled); useEventListener(container, 'scroll', handleScrollThrottled);
useResizeObserver(resizeTarget, handleScrollThrottled);
onMounted(() => { onMounted(() => {
container.value = document; container.value = document;
el.value = document.documentElement; el.value = document.documentElement;
resizeTarget.value = document.body;
if (props.target) { if (props.target) {
el.value = document.querySelector<HTMLElement>(props.target) ?? undefined; el.value = document.querySelector<HTMLElement>(props.target) ?? undefined;
@@ -33,13 +60,17 @@ export const useBackTop = (props: BacktopProps) => {
throw new Error(`target does not exist: ${props.target}`); throw new Error(`target does not exist: ${props.target}`);
} }
container.value = el.value; container.value = el.value;
resizeTarget.value = el.value;
} }
// Give visible an initial value, fix #13066 void nextTick(handleScroll);
handleScroll();
}); });
return { return {
canScrollDown,
canScrollUp,
handleBottomClick,
handleClick, handleClick,
scrollable,
visible, visible,
}; };
}; };

View File

@@ -425,7 +425,11 @@ const headerSlots = computed(() => {
@clear-preferences-and-logout="clearPreferencesAndLogout" @clear-preferences-and-logout="clearPreferencesAndLogout"
/> />
</template> </template>
<EasyFlowBackTop /> <EasyFlowBackTop
:bottom-label="$t('button.goToBottom')"
is-group
:top-label="$t('button.backToTop')"
/>
</template> </template>
</EasyFlowAdminLayout> </EasyFlowAdminLayout>
</template> </template>