diff --git a/components.d.ts b/components.d.ts index 8124057..409ef40 100644 --- a/components.d.ts +++ b/components.d.ts @@ -11,9 +11,7 @@ export {} /* prettier-ignore */ declare module 'vue' { export interface GlobalComponents { - 2: typeof import('./src/components/virtual-scroller/VirtualScroller copy 2.vue')['default'] Canvas: typeof import('./src/components/canvas/index.vue')['default'] - copy: typeof import('./src/components/virtual-scroller/VirtualScroller copy.vue')['default'] DialogBox: typeof import('./src/components/dialogBox/index.vue')['default'] ElButton: typeof import('element-plus/es')['ElButton'] ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] diff --git a/src/components/dialogBox/index.vue b/src/components/dialogBox/index.vue index 5bdc329..20a896e 100644 --- a/src/components/dialogBox/index.vue +++ b/src/components/dialogBox/index.vue @@ -83,7 +83,6 @@ const isgerenate = ref(false) const model = ref('flux') const modelType = ref('text') -// 公用参数 const prompt = ref('一个女孩在树下吃苹果') const promptPlaceholder = '描述你想生成的画面和动作。' const proportion = ref('16:9') @@ -106,8 +105,10 @@ const autoSizeConfig = computed(() => { }) const handleStart = async () => { + const currentType = props.type + if (!props.isGenerate) { - router.push({ name: 'home', query: { loading: false, Generate: true } }) + router.push({ name: 'home', query: { loading: false, Generate: true, type: currentType } }) } if (!prompt.value) { // eslint-disable-next-line no-undef @@ -122,8 +123,7 @@ const handleStart = async () => { }) console.log('imgs', imgs) - const result = { - type: props.type, + const generateData = { model: model.value, modelType: modelType.value, prompt: prompt.value, @@ -147,15 +147,15 @@ const handleStart = async () => { { name: 'resolution', data: resolution.value}, ], imgs, - result + result: JSON.stringify(generateData) } - await generate(modelType.value, data) + await generate(modelType.value, data, generateData, props.type) console.log('生成中', isgerenate.value) } const fillParamsFromResult = (resultData) => { if (!resultData) return - + if (resultData.model !== undefined) model.value = resultData.model if (resultData.modelType !== undefined) modelType.value = resultData.modelType if (resultData.prompt !== undefined) prompt.value = resultData.prompt @@ -196,6 +196,15 @@ watch(() => useDisplay.isSubGerenate, (newValue) => { watch(() => modelType.value, (newValue) => { console.log('modelType.value', newValue) }) + +watch(() => props.type, (newType) => { + if (newType === 'video') { + model.value = 'Vidu Q3-T2V' + } else { + model.value = 'flux' + } +}) + onMounted(() => { if(props.type === 'video'){ model.value = 'Vidu Q3-T2V' diff --git a/src/components/virtual-scroller/VirtualScroller.vue b/src/components/virtual-scroller/VirtualScroller.vue index 52b0d7e..85f8a37 100644 --- a/src/components/virtual-scroller/VirtualScroller.vue +++ b/src/components/virtual-scroller/VirtualScroller.vue @@ -1,379 +1,613 @@ - - diff --git a/src/stores/display.js b/src/stores/display.js index 9ae44f4..f6caf3e 100644 --- a/src/stores/display.js +++ b/src/stores/display.js @@ -18,12 +18,10 @@ const DisplayStoreSetup = () => { const newItem = { id: item.taskId || crypto.randomUUID(), status: 'generate', - text: item.text || '生成中...', - name: item.name || '生成中...', type: item.type || 'image', time: item.time || new Date().toLocaleString(), files: [], - ...item + generateData: item.generateData || {} } tempList.value.unshift(newItem) return newItem diff --git a/src/utils/createTask.js b/src/utils/createTask.js index 2f4c612..b9ed95c 100644 --- a/src/utils/createTask.js +++ b/src/utils/createTask.js @@ -13,7 +13,8 @@ export async function createTask(data, type, taskId, token) { modelName: data.modelName, payload, taskId, - token + token, + result: data.result } } diff --git a/src/utils/websocket.js b/src/utils/websocket.js index f34c172..097f30f 100644 --- a/src/utils/websocket.js +++ b/src/utils/websocket.js @@ -10,7 +10,7 @@ export function getChargeType(chargeType) { case 'painting': return 1 case 'video': - return 2 + return 4 default: return 2 } @@ -58,7 +58,7 @@ export function websocketSuccess() { }) } -export async function generate(type, data) { +export async function generate(modelType, data, generateData, type) { const progress_text = ref('') const message = ref('') const useDisplay = useDisplayStore() @@ -68,7 +68,7 @@ export async function generate(type, data) { useDisplay.isSubGerenate = true - const result = await createTask(data, type, taskId, token) + const result = await createTask(data, modelType, taskId, token) console.log(result) // const token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOjY0NDEwODAyMjk1OTgzNzIzMCwicm5TdHIiOiJiWkVwS2JLWFJyZmRIaFFHWXZKTkdzOGdGM0JSRmxQOCJ9.5eQ2GtVdrDntQDe2tnF8vl_DhTfd2uW-KNqzvl1imc0' const wsURL = `${import.meta.env.VITE_API_WORKFLOW_WS}/?token=Bearer ${token}` @@ -102,10 +102,8 @@ export async function generate(type, data) { useDisplay.addGeneratingItem({ taskId: taskId, - text: data.prompt || '生成中...', - name: data.prompt || '生成中...', type: type, - result: data.result + generateData: generateData }) setTimeout(() => { useDisplay.scrollToBottom() diff --git a/src/views/home/display/components/set.vue b/src/views/home/display/components/set.vue index c03c77a..7f35782 100644 --- a/src/views/home/display/components/set.vue +++ b/src/views/home/display/components/set.vue @@ -2,25 +2,14 @@
-
-
-
{{ props.item.text }}
-
-
{{ props.item.model }}
- -
{{ props.item.proportion }}
-
{{ props.item.resolution }}
-
{{ props.item.quantity }}张
- +
+
+
{{ props.item.generateData.prompt || '生成图片' }}
+
+
{{ props.item.generateData.model }}
+
{{ props.item.generateData.proportion }}
-
- 源自 {{ props.item.parentTime }} -
- 源自 {{ props.item.parentTime }} -
- 第 {{ props.item.parentIndex }} 张图片 -
@@ -49,8 +38,8 @@
- -
+ +
index @@ -74,7 +63,21 @@
-
+ +
+
+ +
+
+ +
{{ item.name }} @@ -102,7 +105,6 @@ const props = defineProps({ default: () => ({}) } }) - const emit = defineEmits(['open-canvas', 'delete-success']) const useDisplay = useDisplayStore() @@ -111,6 +113,76 @@ const useUser = useUserStore() const localCollectStatus = ref({ ...props.item.collectStatus }) const hoverIndex = ref(-1) +const isHovering = ref(false) +const shouldShowOnSecondLine = ref(false) +const nameRef = ref(null) +const titleRef = ref(null) +const generateDataRef = ref(null) +const wrapperHeight = ref(38.5) + +const checkTextOverflow = () => { + nextTick(() => { + if (nameRef.value && titleRef.value && generateDataRef.value) { + const lineHeight = 22.5 + const padding = 8 + const twoLineHeight = 55 + const generateDataWidth = generateDataRef.value.offsetWidth + 20 + + nameRef.value.style.maxHeight = 'none' + nameRef.value.style.overflow = 'visible' + + const actualHeight = nameRef.value.scrollHeight + const lineCount = Math.ceil((actualHeight - padding * 2) / lineHeight) + + if (!isHovering.value) { + nameRef.value.style.maxHeight = '55px' + nameRef.value.style.overflow = 'hidden' + } + + if (lineCount > 1) { + shouldShowOnSecondLine.value = true + wrapperHeight.value = twoLineHeight + } else { + const containerWidth = titleRef.value.offsetWidth + const promptWidth = nameRef.value.scrollWidth + const firstLineRemaining = containerWidth - promptWidth + + if (firstLineRemaining < generateDataWidth) { + shouldShowOnSecondLine.value = true + wrapperHeight.value = twoLineHeight + } else { + shouldShowOnSecondLine.value = false + wrapperHeight.value = Math.max(lineHeight + padding * 2, actualHeight) + } + } + } + }) +} + +watch(isHovering, (newVal) => { + if (nameRef.value) { + if (newVal) { + nameRef.value.style.maxHeight = 'none' + nameRef.value.style.overflow = 'visible' + } else { + nameRef.value.style.maxHeight = '55px' + nameRef.value.style.overflow = 'hidden' + } + } +}) + +watch(() => props.item.generateData.prompt, () => { + checkTextOverflow() +}, { immediate: true }) + +onMounted(() => { + checkTextOverflow() + window.addEventListener('resize', checkTextOverflow) +}) + +onUnmounted(() => { + window.removeEventListener('resize', checkTextOverflow) +}) const isCollected = (url) => { return localCollectStatus.value[url] === true @@ -132,12 +204,12 @@ const AIbrush = (file, index) => { } const reEdit = () => { - useDisplay.setResultData(props.item.result) + useDisplay.setResultData(props.item.generateData) useDisplay.fillParamsForEdit() } const againGenerate = () => { - useDisplay.setResultData(props.item.result) + useDisplay.setResultData(props.item.generateData) useDisplay.triggerGenerateWithResult() } @@ -214,40 +286,62 @@ const addCollection = async (url) => { display: flex; flex-direction: column; flex: 1; - gap: 20px; - padding-bottom: 20px; + gap: 12px; + padding-bottom: 40px; } .none-primary-box{ height: 350px; } .title{ - // height: 25px; width: 100%; - display: flex; - align-items: center; - gap: 20px; + position: relative; - .style{ - width: 100%; - display: inline; + .prompt-wrapper{ + position: relative; + min-height: 28.5px; + overflow: visible; } - .name{ + .prompt{ + position: absolute; + left: 0; + top: 0; color: #333; font-family: "Microsoft YaHei"; - font-size: 15px; + font-size: 14px; font-style: normal; - font-weight: 700; - line-height: 1.5; + font-weight: 400; + line-height: 22.5px; word-break: break-all; - display: inline; - margin-right: 20px; + max-height: 60px; + overflow: hidden; + z-index: 10; + padding: 8px; + background-color: #fff; + + &.expanded{ + max-height: none; + overflow: visible; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + border-radius: 4px; + } } .generate-data{ + position: absolute; + right: 0; + top: 0; display: inline-flex; align-items: center; + z-index: 2; + background-color: #fff; + padding-right: 20px; + + &.second-line{ + top: auto; + bottom: 0; + } } .detailed-data{ @@ -270,28 +364,6 @@ const addCollection = async (url) => { border-left: none; padding-left: 0; } - - .time{ - color: #333; - font-family: "Microsoft YaHei"; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: normal; - } - - .dividing-line{ - height: 100%; - border: 1px solid #ccc; - } - - .delete-btn{ - cursor: pointer; - } - - .delete-btn:hover{ - color: #ff4949; - } } .box{ @@ -399,6 +471,13 @@ const addCollection = async (url) => { object-fit: contain; /* 确保图片完整显示,不被裁剪 */ border-radius: 8px; /* 可选:给图片添加圆角 */ } + + .video{ + width: 380px; + height: auto; /* 保持宽高比 */ + object-fit: contain; /* 确保图片完整显示,不被裁剪 */ + border-radius: 8px; /* 可选:给图片添加圆角 */ + } } .left-top,.bottom-brush{ diff --git a/src/views/home/display/index.vue b/src/views/home/display/index.vue index 74096b1..cc7a126 100644 --- a/src/views/home/display/index.vue +++ b/src/views/home/display/index.vue @@ -50,6 +50,7 @@ :estimated-height="300" :buffer-size="3" direction="reverse" + :bottom-placeholder-height="350" class="scroller" @scroll="handleScroll" @visible-change="handleVisibleChange" @@ -103,7 +104,7 @@ const isInitializing = ref(true) const { canvasVisible, canvasImage, canvasReferenceImages, canvasSource } = storeToRefs(useDisplay) const chargeType = computed(() => getChargeType(props.type)) -console.log(chargeType.value) +// console.log(chargeType.value) const timeOptions = [ { label: '全部', value: 'all' }, @@ -135,42 +136,25 @@ const toggleDisplay = (newValue, oldValue) => { } const conversion = (newlist) => { - const temp = newlist.list.map((item) => { + const temp = newlist.map((item) => { const files = item.fileUrl ? item.fileUrl.split(',').filter(url => url.trim()) : [] + const generateData = JSON.parse(item.result || '{}') return { id: item.id, taskId: item.taskId, + type: props.type, collection: item.collection, status: 'success', - prompt: item.prompt, - params: item.params, - result: item.result, + generateData: generateData, time: item.createTime, files: files, - collectStatus: item.collectStatus || {}, - model: item.model || '', - proportion: item.proportion || '', - resolution: item.resolution || '', - quantity: item.quantity || 1 + collectStatus: item.collectStatus || {} } }) + console.log(temp) return temp } -const adaptDataList = (dataList) => { - const convertedList = conversion({ list: dataList }) - return convertedList.map((item, index) => { - const originalItem = dataList[index] - return { - ...item, - text: originalItem?.title || item.prompt || '生成图片', - name: originalItem?.title || item.prompt || '生成图片', - type: 'image', - title: originalItem?.title || '生成图片' - } - }) -} - const fetchHistory = async (isLoadMore = false) => { if (isLoading.value || (!isLoadMore && !hasMoreData.value)) return @@ -200,7 +184,7 @@ const fetchHistory = async (isLoadMore = false) => { return } - const adaptedList = adaptDataList(dataList) + const adaptedList = conversion(dataList) if (isLoadMore) { useDisplay.appendHistoryList(adaptedList) @@ -244,13 +228,13 @@ const fetchHistory = async (isLoadMore = false) => { } } -const handleScroll = (scrollTop, scrollInfo) => { +const handleScroll = (scrollInfo) => { if (isInitializing.value) return if (!scrollInfo) return - const { isAtTop, isAtBottom, distanceToTop, distanceToBottom } = scrollInfo - - if (isAtTop && !isLoading.value && !isLoadingMoreLocked.value && hasMoreData.value) { + const { isAtPageTop, isAtPageBottom, distanceToPageTop, distanceToPageBottom } = scrollInfo + + if (isAtPageTop && !isLoading.value && !isLoadingMoreLocked.value && hasMoreData.value) { isLoadingMoreLocked.value = true fetchHistory(true) setTimeout(() => { @@ -258,9 +242,9 @@ const handleScroll = (scrollTop, scrollInfo) => { }, 3000) } - if (isAtBottom) { + if (isAtPageBottom) { useDisplay.Sender_variant = 'updown' - } else if (distanceToTop >= 350) { + } else if (distanceToPageTop >= 350) { useDisplay.Sender_variant = 'default' } } diff --git a/src/views/home/index.vue b/src/views/home/index.vue index 8000649..e876752 100644 --- a/src/views/home/index.vue +++ b/src/views/home/index.vue @@ -1,5 +1,5 @@