From 70529ccd47a9581a583c2a5aa564281127a1712e Mon Sep 17 00:00:00 2001 From: WangLeo <690854599@qq.com> Date: Thu, 26 Mar 2026 16:09:04 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components.d.ts | 4 +- out.txt | 371 +++++--- src/apis/display/index.js | 7 +- src/assets/dialog/time.svg | 4 + src/assets/dialog/videoPattern1.svg | 4 + src/assets/dialog/videoPattern2.svg | 4 + src/assets/dialog/videoPattern3.svg | 5 + src/assets/dialog/videoPattern4.svg | 4 + src/components/Select/index.vue | 36 +- src/components/canvas/index.vue | 58 +- src/components/dialogBox/Time/index.vue | 80 ++ .../dialogBox/imageUploader/index.vue | 23 +- src/components/dialogBox/index.vue | 52 +- src/components/dialogBox/model/index.vue | 91 +- src/components/dialogBox/pattern/index.vue | 93 ++ src/components/dialogBox/proportion/index.vue | 35 +- src/components/virtual-scroller/README.md | 273 +++--- .../virtual-scroller/VirtualScroller.vue | 800 +++++++++++++++--- .../virtual-scroller/VirtualScrollerItem.vue | 96 --- src/components/virtual-scroller/index.js | 9 +- .../virtual-scroller/useVirtualScroller.js | 246 ------ src/config/modelConfig/painting.json | 17 + src/config/modelConfig/video.json | 8 + src/stores/display.js | 38 +- src/utils/createTask.js | 5 +- src/utils/websocket.js | 15 +- src/views/home/display/components/set.vue | 50 +- src/views/home/display/index-list.vue | 350 -------- src/views/home/display/index.vue | 255 +++--- src/views/home/index.vue | 35 +- test/FlashHead.json | 10 + test/LTX2.3-T2V.json | 11 + test/Vidu Q3-I2V.json | 10 + test/Vidu Q3-T2V.json | 11 + 34 files changed, 1782 insertions(+), 1328 deletions(-) create mode 100644 src/assets/dialog/time.svg create mode 100644 src/assets/dialog/videoPattern1.svg create mode 100644 src/assets/dialog/videoPattern2.svg create mode 100644 src/assets/dialog/videoPattern3.svg create mode 100644 src/assets/dialog/videoPattern4.svg create mode 100644 src/components/dialogBox/Time/index.vue create mode 100644 src/components/dialogBox/pattern/index.vue delete mode 100644 src/components/virtual-scroller/VirtualScrollerItem.vue delete mode 100644 src/components/virtual-scroller/useVirtualScroller.js create mode 100644 src/config/modelConfig/painting.json create mode 100644 src/config/modelConfig/video.json delete mode 100644 src/views/home/display/index-list.vue create mode 100644 test/FlashHead.json create mode 100644 test/LTX2.3-T2V.json create mode 100644 test/Vidu Q3-I2V.json create mode 100644 test/Vidu Q3-T2V.json diff --git a/components.d.ts b/components.d.ts index 5aa1fbb..7c35fd4 100644 --- a/components.d.ts +++ b/components.d.ts @@ -15,7 +15,6 @@ declare module 'vue' { DialogBox: typeof import('./src/components/dialogBox/index.vue')['default'] ElButton: typeof import('element-plus/es')['ElButton'] ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] - ElPopover: typeof import('element-plus/es')['ElPopover'] ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElUpload: typeof import('element-plus/es')['ElUpload'] IEpCalendar: typeof import('~icons/ep/calendar')['default'] @@ -26,13 +25,14 @@ declare module 'vue' { ImageUploader: typeof import('./src/components/dialogBox/imageUploader/index.vue')['default'] Img: typeof import('./src/components/Img/index.vue')['default'] Model: typeof import('./src/components/dialogBox/model/index.vue')['default'] + Pattern: typeof import('./src/components/dialogBox/pattern/index.vue')['default'] Popover: typeof import('./src/components/Popover/index.vue')['default'] Proportion: typeof import('./src/components/dialogBox/proportion/index.vue')['default'] Quantity: typeof import('./src/components/dialogBox/quantity/index.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] Select: typeof import('./src/components/Select/index.vue')['default'] + Time: typeof import('./src/components/dialogBox/Time/index.vue')['default'] VirtualScroller: typeof import('./src/components/virtual-scroller/VirtualScroller.vue')['default'] - VirtualScrollerItem: typeof import('./src/components/virtual-scroller/VirtualScrollerItem.vue')['default'] } } diff --git a/out.txt b/out.txt index f01303b..3dda8ab 100644 --- a/out.txt +++ b/out.txt @@ -1,140 +1,231 @@ -2026-02-04 11:48:53 INFO [XNIO-1 task-2] t.c.starter.log.interceptor.handler.LogInterceptor - [0][1171053593383952384] [POST] /business/collect -2026-02-04 11:48:53 ERROR [XNIO-1 task-2] t.c.s.w.a.r.DefaultBeforeControllerAdviceProcessImpl - [0][1171053593383952384] [POST] /business/collect -org.springframework.dao.DataIntegrityViolationException: -### Error updating database. Cause: java.sql.SQLException: Field 'create_user' doesn't have a default value -### The error may exist in top/continew/admin/business/mapper/CollectMapper.java (best guess) -### The error may involve top.continew.admin.business.mapper.CollectMapper.insert-Inline -### The error occurred while setting parameters -### SQL: INSERT INTO t_collect ( user_id, url, clothes_id ) VALUES ( ?, ?, ? ) -### Cause: java.sql.SQLException: Field 'create_user' doesn't have a default value -; Field 'create_user' doesn't have a default value - at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:258) - at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:107) - at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:92) - at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:439) - at jdk.proxy2/jdk.proxy2.$Proxy153.insert(Unknown Source) - at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:272) - at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:59) - at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:152) - at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) - at jdk.proxy2/jdk.proxy2.$Proxy191.insert(Unknown Source) - at top.continew.starter.extension.crud.service.impl.BaseServiceImpl.add(BaseServiceImpl.java:156) - at jdk.internal.reflect.GeneratedMethodAccessor528.invoke(Unknown Source) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:569) - at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:354) - at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) - at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768) - at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) - at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:392) - at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) - at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:720) - at top.continew.admin.business.service.impl.CollectServiceImpl$$SpringCGLIB$$0.add() - at top.continew.admin.controller.business.CollectController.addCollect(CollectController.java:52) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:569) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) - at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:547) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) - at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614) - at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129) - at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at top.continew.starter.log.interceptor.handler.LogFilter.doFilterInternal(LogFilter.java:82) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at cn.dev33.satoken.filter.SaPathCheckFilterForJakartaServlet.doFilter(SaPathCheckFilterForJakartaServlet.java:55) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:107) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at top.continew.starter.web.autoconfigure.trace.TLogServletFilter.doFilter(TLogServletFilter.java:59) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84) - at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62) - at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68) - at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) - at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68) - at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117) - at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57) - at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) - at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) - at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64) - at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60) - at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77) - at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43) - at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) - at io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52) - at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) - at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:276) - at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135) - at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:132) - at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48) - at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43) - at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:256) - at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:101) - at io.undertow.server.Connectors.executeRootHandler(Connectors.java:393) - at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:859) - at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18) - at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513) - at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538) - at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282) - at java.base/java.lang.Thread.run(Thread.java:840) -Caused by: java.sql.SQLException: Field 'create_user' doesn't have a default value - at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:130) - at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) - at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:912) - at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:354) - at com.zaxxer.hikari.pool.ProxyPreparedStatement.execute(ProxyPreparedStatement.java:44) - at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.execute(HikariProxyPreparedStatement.java) - at com.p6spy.engine.wrapper.PreparedStatementWrapper.execute(PreparedStatementWrapper.java:362) - at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:48) - at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:75) - at jdk.internal.reflect.GeneratedMethodAccessor215.invoke(Unknown Source) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:569) - at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61) - at jdk.proxy2/jdk.proxy2.$Proxy260.update(Unknown Source) - at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50) - at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) - at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76) - at jdk.internal.reflect.GeneratedMethodAccessor214.invoke(Unknown Source) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:569) - at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:61) - at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:106) - at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:59) - at jdk.proxy2/jdk.proxy2.$Proxy258.update(Unknown Source) - at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197) - at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:184) - at jdk.internal.reflect.GeneratedMethodAccessor221.invoke(Unknown Source) - at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.base/java.lang.reflect.Method.invoke(Method.java:569) - at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:425) - ... 93 common frames omitted -2026-02-04 11:48:53 INFO [XNIO-1 task-2] t.c.starter.log.interceptor.handler.LogInterceptor - [0][1171053593383952384] [POST] /business/collect 200 3ms +{ + "code": "0", + "msg": "ok", + "success": true, + "timestamp": 1774247913094, + "data": { + "list": [ + { + "id": "793783789028385477", + "createUser": "779313132404212546", + "createTime": "2025-12-23 10:13:23", + "updateUser": null, + "updateTime": null, + "userId": "779313132404212546", + "platformId": 10000, + "taskId": "d7265fba-2a9c-4787-9212-0a543aa0079d", + "title": "生成图片", + "taskType": 1, + "chargeType": 1, + "type": null, + "fileType": null, + "modelName": "Flux", + "accountType": "sub_account_1", + "consumptionPoints": 1, + "fileUrl": "https://sxwz.xueai.art/file/2025/12/23/6949fac3e4b0ca6c273243e6.png", + "platformCode": "10000", + "result": null, + "tokens": null + }, + { + "id": "801756644529676772", + "createUser": "779313132404212546", + "createTime": "2026-01-14 10:14:40", + "updateUser": null, + "updateTime": null, + "userId": "779313132404212546", + "platformId": 10000, + "taskId": "be7fa32f-a64c-4502-9241-5b299aba3007", + "title": "生成图片", + "taskType": 1, + "chargeType": 1, + "type": null, + "fileType": null, + "modelName": "Flux", + "accountType": "sub_account_1", + "consumptionPoints": 1, + "fileUrl": "https://sxwz.xueai.art/file/2026/1/14/6966fc0fe4b0ca6c27324493.png", + "platformCode": "10000", + "result": null, + "tokens": null + }, + { + "id": "801757022436467181", + "createUser": "779313132404212546", + "createTime": "2026-01-14 10:16:10", + "updateUser": null, + "updateTime": null, + "userId": "779313132404212546", + "platformId": 10000, + "taskId": "a11eca7f-a974-40a5-9ba7-633e59c34203", + "title": "生成图片", + "taskType": 1, + "chargeType": 1, + "type": null, + "fileType": null, + "modelName": "Flux", + "accountType": "sub_account_1", + "consumptionPoints": 1, + "fileUrl": "https://sxwz.xueai.art/file/2026/1/14/6966fc6ae4b0ca6c27324494.png", + "platformCode": "10000", + "result": null, + "tokens": null + }, + { + "id": "808634443160891624", + "createUser": "779313132404212546", + "createTime": "2026-02-02 01:44:35", + "updateUser": null, + "updateTime": null, + "userId": "779313132404212546", + "platformId": 10000, + "taskId": "wKAM2KIQQ_riW0pTAAAL", + "title": "图片生成", + "taskType": 1, + "chargeType": 1, + "type": null, + "fileType": null, + "modelName": "Flux", + "accountType": "sub_account_1", + "consumptionPoints": 1, + "fileUrl": "https://sxwz.xueai.art/file/2026/2/2/69800182bd04d39e54d076dd.png", + "platformCode": "10000", + "result": null, + "tokens": null + }, + { + "id": "808634548240789744", + "createUser": "779313132404212546", + "createTime": "2026-02-02 01:45:00", + "updateUser": null, + "updateTime": null, + "userId": "779313132404212546", + "platformId": 10000, + "taskId": "ULX6qR65vnBzhx52AAAN", + "title": "图片生成", + "taskType": 1, + "chargeType": 1, + "type": null, + "fileType": null, + "modelName": "Flux", + "accountType": "sub_account_1", + "consumptionPoints": 1, + "fileUrl": "https://sxwz.xueai.art/file/2026/2/2/6980019bbd04d39e54d076de.png", + "platformCode": "10000", + "result": null, + "tokens": null + }, + { + "id": "808643919486136683", + "createUser": "779313132404212546", + "createTime": "2026-02-02 02:22:14", + "updateUser": null, + "updateTime": null, + "userId": "779313132404212546", + "platformId": 10000, + "taskId": "WiVJhf1U-CPFyyEiAAAb", + "title": "图片生成", + "taskType": 1, + "chargeType": 1, + "type": null, + "fileType": null, + "modelName": "Flux", + "accountType": "sub_account_1", + "consumptionPoints": 1, + "fileUrl": "https://sxwz.xueai.art/file/2026/2/2/69800a56bd04d39e54d076e7.png", + "platformCode": "10000", + "result": null, + "tokens": null + }, + { + "id": "808666588717789637", + "createUser": "779313132404212546", + "createTime": "2026-02-02 03:52:19", + "updateUser": null, + "updateTime": null, + "userId": "779313132404212546", + "platformId": 10000, + "taskId": "gH7baTTfPSfawbcUAAAf", + "title": "图片生成", + "taskType": 1, + "chargeType": 1, + "type": null, + "fileType": null, + "modelName": "Flux", + "accountType": "sub_account_1", + "consumptionPoints": 1, + "fileUrl": "https://sxwz.xueai.art/file/2026/2/2/69801f73bd04d39e54d076e9.png", + "platformCode": "10000", + "result": null, + "tokens": null + }, + { + "id": "808703764197290551", + "createUser": "779313132404212546", + "createTime": "2026-02-02 06:20:02", + "updateUser": null, + "updateTime": null, + "userId": "779313132404212546", + "platformId": 10000, + "taskId": "xpW7ykBix5s4b3j6AAAz", + "title": "图片生成", + "taskType": 1, + "chargeType": 1, + "type": null, + "fileType": null, + "modelName": "Flux", + "accountType": "main_account", + "consumptionPoints": 9, + "fileUrl": "https://sxwz.xueai.art/file/2026/2/2/69804212bd04d39e54d076f3.png", + "platformCode": "10000", + "result": null, + "tokens": null + }, + { + "id": "819160907316737522", + "createUser": "779313132404212546", + "createTime": "2026-03-03 02:53:00", + "updateUser": null, + "updateTime": null, + "userId": "779313132404212546", + "platformId": 10000, + "taskId": "LYLIzOdaCCBZ8qV-AACt", + "title": "图片生成", + "taskType": 1, + "chargeType": 1, + "type": null, + "fileType": null, + "modelName": "Flux", + "accountType": "main_account", + "consumptionPoints": 15, + "fileUrl": "https://sxwz.xueai.art/file/2026/3/3/69a64d0bbd04d39e54d0772b.png", + "platformCode": "10000", + "result": null, + "tokens": null + }, + { + "id": "821520405306029717", + "createUser": "779313132404212546", + "createTime": "2026-03-09 15:08:48", + "updateUser": null, + "updateTime": null, + "userId": "779313132404212546", + "platformId": 10000, + "taskId": "eIKMWxL9GzzeAfvsAAC_", + "title": "图片生成", + "taskType": 1, + "chargeType": 1, + "type": null, + "fileType": null, + "modelName": "Flux", + "accountType": "main_account", + "consumptionPoints": 8, + "fileUrl": "https://sxwz.xueai.art/file/2026/3/9/69aee27fbd04d39e54d07748.png", + "platformCode": "10000", + "result": null, + "tokens": null + } + ], + "total": 45 + } +} \ No newline at end of file diff --git a/src/apis/display/index.js b/src/apis/display/index.js index f43e4ff..d5061a5 100644 --- a/src/apis/display/index.js +++ b/src/apis/display/index.js @@ -2,5 +2,10 @@ import service from '@/utils/request' // 获取生成历史列表 export function getGenerateHistoryList(query) { - return service.get('/taskRecordHistory/list', { params: query }) + return service.get('/taskRecordHistory', { params: query }) } + +// 取消或收藏 +export function cancelOrCollect(query) { + return service.post('/collect/toggle', query) +} \ No newline at end of file diff --git a/src/assets/dialog/time.svg b/src/assets/dialog/time.svg new file mode 100644 index 0000000..6750b2a --- /dev/null +++ b/src/assets/dialog/time.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/dialog/videoPattern1.svg b/src/assets/dialog/videoPattern1.svg new file mode 100644 index 0000000..0541c40 --- /dev/null +++ b/src/assets/dialog/videoPattern1.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/dialog/videoPattern2.svg b/src/assets/dialog/videoPattern2.svg new file mode 100644 index 0000000..b617a7d --- /dev/null +++ b/src/assets/dialog/videoPattern2.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/dialog/videoPattern3.svg b/src/assets/dialog/videoPattern3.svg new file mode 100644 index 0000000..52b3289 --- /dev/null +++ b/src/assets/dialog/videoPattern3.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/dialog/videoPattern4.svg b/src/assets/dialog/videoPattern4.svg new file mode 100644 index 0000000..18619aa --- /dev/null +++ b/src/assets/dialog/videoPattern4.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/Select/index.vue b/src/components/Select/index.vue index 022e468..9bdbf38 100644 --- a/src/components/Select/index.vue +++ b/src/components/Select/index.vue @@ -62,8 +62,6 @@ + + diff --git a/src/components/dialogBox/imageUploader/index.vue b/src/components/dialogBox/imageUploader/index.vue index 01cf740..f4cd1c9 100644 --- a/src/components/dialogBox/imageUploader/index.vue +++ b/src/components/dialogBox/imageUploader/index.vue @@ -5,11 +5,11 @@ v-for="(item, index) in localPreviewList" :key="item.uid" class="image-item" - @click.stop + @click.stop="handleImageClick(index)" > 上传的图片
{{ index + 1 }}
-
+
@@ -46,7 +46,7 @@ const props = defineProps({ } }) -const emit = defineEmits(['update:modelValue']) +const emit = defineEmits(['update:modelValue', 'open-canvas']) const uploadurl = import.meta.env.VITE_API_WORKFLOW_UPLOAD const uploadRef = ref(null) @@ -116,6 +116,23 @@ const handleDelete = (index) => { emit('update:modelValue', [...imageList.value]) } +const handleImageClick = (clickedIndex) => { + const clickedImage = imageList.value[clickedIndex] + if (!clickedImage) return + + const otherImages = imageList.value + .filter((_, index) => index !== clickedIndex) + .map((img, index) => ({ + ...img, + displayIndex: index + 2 + })) + + emit('open-canvas', { + mainImage: clickedImage, + referenceImages: otherImages + }) +} + const handleSelect = async (url) => { const initialFile = await fetch(url) const blob = await initialFile.blob() diff --git a/src/components/dialogBox/index.vue b/src/components/dialogBox/index.vue index b07ddeb..d26ee94 100644 --- a/src/components/dialogBox/index.vue +++ b/src/components/dialogBox/index.vue @@ -7,9 +7,9 @@
回到底部
-
+
- +
@@ -17,15 +17,16 @@ @@ -50,8 +51,10 @@ @@ -262,7 +283,6 @@ watch(() => type.value, (newValue) => { :deep(.el-popover.el-popper){ border-radius: 20px; - } // 时间选择器 .select{ diff --git a/src/components/dialogBox/model/index.vue b/src/components/dialogBox/model/index.vue index 7c773be..58a1996 100644 --- a/src/components/dialogBox/model/index.vue +++ b/src/components/dialogBox/model/index.vue @@ -13,6 +13,8 @@ + + diff --git a/src/components/dialogBox/proportion/index.vue b/src/components/dialogBox/proportion/index.vue index d1ec65c..e91289b 100644 --- a/src/components/dialogBox/proportion/index.vue +++ b/src/components/dialogBox/proportion/index.vue @@ -3,7 +3,7 @@

选择比例

-
+
-
+

选择分辨率

-
+

尺寸(px)

@@ -68,6 +68,10 @@ const props = defineProps({ resolution: { type: String, default: '2k' + }, + type: { + type: String, + default: 'painting' } }) @@ -87,11 +91,11 @@ const proportionOptions = [ { value: '智能', label: '智能' }, { value: '21:9', label: '21:9' }, { value: '16:9', label: '16:9' }, - { value: '3:2', label: '3:2' }, + // { value: '3:2', label: '3:2' }, { value: '4:3', label: '4:3' }, { value: '1:1', label: '1:1' }, { value: '3:4', label: '3:4' }, - { value: '2:3', label: '2:3' }, + // { value: '2:3', label: '2:3' }, { value: '9:16', label: '9:16' } ] @@ -232,24 +236,25 @@ watch(() => [props.modelValue, props.resolution], () => { } .proportion-container{ - padding: 10px; + padding: 20px; } .section{ margin-bottom: 20px; + border-radius: 20px; &:last-child{ margin-bottom: 0; } h3{ - font-size: 14px; - font-weight: 500; + font-family: "Microsoft YaHei"; + font-size: 12px; + font-weight: 400; margin-bottom: 12px; - color: #666; + color: #999; } } - .proportion-options{ display: flex; flex-wrap: nowrap; @@ -257,6 +262,7 @@ watch(() => [props.modelValue, props.resolution], () => { margin-bottom: 16px; background-color: #F8F9FA; padding: 5px; + border-radius: 10px; } .proportion-item{ @@ -272,15 +278,16 @@ watch(() => [props.modelValue, props.resolution], () => { transition: all 0.2s ease; border-radius: 5px; text-align: bottom; - + color: #999; &::before{ content: ''; width: var(--width, 20px); height: var(--height, 20px); - background: #f0f0f0; + background: #F5F6F7; border-radius: 4px; transition: all 0.2s ease; + border: 2px solid #999; } &:hover{ @@ -288,8 +295,12 @@ watch(() => [props.modelValue, props.resolution], () => { } &.active{ + color: #000F33; background: #ffffff; } + &.active::before{ + border-color: #000F33; + } } .resolution-options{ diff --git a/src/components/virtual-scroller/README.md b/src/components/virtual-scroller/README.md index 7c3a63b..96618ac 100644 --- a/src/components/virtual-scroller/README.md +++ b/src/components/virtual-scroller/README.md @@ -1,45 +1,35 @@ -# 高性能虚拟滚动组件 +# VirtualScroller 虚拟滚动组件 -一个基于 Vue 3 Composition API 开发的高性能虚拟滚动组件,支持从底部开始渲染(容器向上增大),适用于聊天记录、历史列表等场景。 +一个高性能的虚拟滚动组件,支持未知高度子组件渲染和滚动方向反转功能。 ## 特性 -### 核心功能 -- ✅ 虚拟滚动核心,只渲染可视区域内容 -- ✅ 支持未知高度内容,自动测量和缓存高度 -- ✅ 插槽式组件插入,灵活易用 -- ✅ 两种渲染模式:顶部模式(向下滚动)和底部模式(向上滚动) -- ✅ 滚动触发加载更多事件 -- ✅ 性能优化,防止滚动抖动 - -### 补充功能 -- ✅ 自定义渲染函数 -- ✅ 动态数据更新 -- ✅ 滚动位置保存和恢复 -- ✅ 自定义滚动阈值 - -### 外部接口 -- ✅ 丰富的 Props 配置 -- ✅ 完整的方法暴露 +- 🚀 **高性能虚拟滚动** - 仅渲染可视区域内的元素,支持大数据量渲染 +- 🔄 **滚动方向反转** - 通过双重 CSS 旋转实现向上滚动效果 +- 📏 **未知高度支持** - 动态测量子组件高度,无需预设固定高度 +- 🎯 **精确滚动控制** - 提供滚动到指定索引、顶部、底部等 API +- 📱 **响应式设计** - 适配不同屏幕尺寸 +- ⚡ **60fps 流畅滚动** - 优化的渲染策略确保流畅体验 ## 安装 -组件位于 `@/components/virtual-scroller`,无需额外安装依赖。 +组件位于 `src/components/virtual-scroller/` 目录下,无需额外安装依赖。 -## 快速开始 - -### 基本使用 +## 基础用法 ```vue @@ -48,128 +38,185 @@ import { VirtualScroller } from '@/components/virtual-scroller' const list = ref([ - { id: 1, text: '消息 1' }, - { id: 2, text: '消息 2' } + { id: 1, name: 'Item 1' }, + { id: 2, name: 'Item 2' }, ]) + +const handleScroll = (event) => { + console.log('滚动事件', event) +} ``` -### Props 说明 +## Props -| 属性 | 类型 | 默认值 | 说明 | -|------|------|--------|------| -| data | Array | [] | 列表数据 | -| itemHeight | Number | 80 | 预估列表项高度 | -| estimatedHeight | Number | 80 | 未知高度内容的预估高度 | -| renderMode | String | 'bottom' | 渲染模式,'top' \| 'bottom' | -| scrollThreshold | Number | 100 | 滚动触发阈值 | -| onLoadMore | Function | null | 加载更多回调函数 | -| renderItem | Function | null | 自定义渲染函数 | -| keyExtractor | Function | (item, index) => index | 列表项 key 生成函数 | -| cacheHeight | Boolean | true | 是否缓存已测量的高度 | -| buffer | Number | 5 | 预渲染缓冲区数量 | +| 属性名 | 类型 | 默认值 | 说明 | +|--------|------|--------|------| +| `data` | `Array` | `[]` | 数据源数组(必填) | +| `itemKey` | `string \| Function` | `'id'` | 用于标识每个项目的键名或函数 | +| `estimatedHeight` | `number` | `100` | 预估的项目高度(像素) | +| `buffer` | `number` | `3` | 可视区域外预渲染的项目数量 | +| `height` | `string \| number` | `'100%'` | 滚动容器高度 | +| `width` | `string \| number` | `'100%'` | 滚动容器宽度 | +| `renderMode` | `'default' \| 'top'` | `'default'` | 渲染模式,`top` 模式会自动滚动到页面底部 | -### 事件说明 +## Events | 事件名 | 参数 | 说明 | |--------|------|------| -| scroll | event | 滚动事件 | -| load-more | - | 加载更多事件 | -| item-height-change | index, height | 列表项高度变化时触发 | +| `scroll` | `event: Event` | 滚动事件,包含 `distanceToPageTop`、`distanceToPageBottom`、`isAtPageTop`、`isAtPageBottom` 属性 | +| `scroll-start` | - | 滚动到**页面顶部**时触发 | +| `scroll-end` | - | 滚动到**页面底部**时触发 | -### 暴露方法 +## Expose Methods -通过 `ref` 可以调用以下方法: +通过 `ref` 可以访问以下方法: ```vue - - ``` -## 渲染模式说明 +| 方法名 | 参数 | 返回值 | 说明 | +|--------|------|--------|------| +| `scrollToIndex` | `index: number, behavior?: ScrollBehavior` | `void` | 滚动到指定索引的项目 | +| `scrollToBottom` | `behavior?: ScrollBehavior` | `void` | 滚动到**页面底部**(最新数据) | +| `scrollToTop` | `behavior?: ScrollBehavior` | `void` | 滚动到**页面顶部**(最旧数据) | +| `getScrollElement` | - | `HTMLElement \| null` | 获取滚动容器 DOM 元素 | +| `getVisibleIndices` | - | `number[]` | 获取当前可视项目的索引数组 | +| `resetMeasurements` | - | `void` | 重置所有高度测量缓存 | +| `isAtPageBottom` | - | `boolean` | 判断是否在页面底部 | +| `isAtPageTop` | - | `boolean` | 判断是否在页面顶部 | -### 顶部模式 (renderMode: 'top') +## 滚动方向反转原理 -内容从顶部开始显示,向下滚动加载更多。适用于普通列表。 +组件通过 CSS `transform: rotate(180deg)` 实现滚动方向反转: + +1. **容器旋转**:滚动容器应用 `transform: rotate(180deg)` +2. **内容反向旋转**:子组件内部应用 `transform: rotate(180deg)` 抵消旋转 + +### 坐标映射关系 + +由于容器旋转 180 度,坐标系统发生反转: + +| 页面概念 | 组件内部 scrollTop | +|----------|-------------------| +| 页面顶部(最旧数据) | `scrollTop = scrollHeight - clientHeight` | +| 页面底部(最新数据) | `scrollTop = 0` | + +### 滚轮方向处理 + +组件内部处理了滚轮方向映射: +- 用户**向上**滚动滚轮 → 页面内容**向上**滚动 +- 用户**向下**滚动滚轮 → 页面内容**向下**滚动 + +## 使用示例 ```vue - - - + + + ``` -### 底部模式 (renderMode: 'bottom') ⭐ 核心特性 +## 性能优化建议 -内容从底部开始显示,向上滚动加载更多,**容器垂直向上增大**。适用于聊天记录、历史列表等场景。 +1. **合理设置 `estimatedHeight`**:预估高度越接近实际高度,重排越少 +2. **适当调整 `buffer`**:较大的 buffer 会预渲染更多元素,减少白屏但增加内存占用 +3. **使用唯一的 `itemKey`**:确保每个项目有唯一标识,避免不必要的重渲染 +4. **避免复杂计算**:在插槽中避免复杂计算,使用计算属性或缓存 -```vue - - - -``` +## 常见问题 -## 性能优化 +### Q: 子组件显示倒置怎么办? -- 使用 `requestAnimationFrame` 优化渲染 -- 节流处理滚动事件(16ms) -- 高度缓存机制,避免重复测量 -- 使用 Intersection Observer 优化可见性检测 -- 只渲染可视区域 + 缓冲区内容 +A: 在子组件上添加 `style="transform: rotate(180deg)"` 来抵消容器的旋转。 -## 注意事项 +### Q: 如何判断是否滚动到页面底部? -1. `renderMode: 'bottom'` 模式下,数据建议按时间倒序排列(最新的在最后) -2. 列表项需要有明确的高度或能被正确测量 -3. 使用图片等异步内容时,建议设置 `min-height` 防止布局抖动 +A: 使用 `isAtPageBottom()` 方法或监听 `scroll-end` 事件。 -## 文件结构 +### Q: scrollToBottom 和 scrollToTop 的方向? -``` -virtual-scroller/ -├── index.js # 组件入口 -├── VirtualScroller.vue # 主组件 -├── VirtualScrollerItem.vue # 列表项组件 -├── useVirtualScroller.js # 组合式 API 钩子 -└── README.md # 本文档 -``` +A: +- `scrollToBottom()` - 滚动到**页面底部**(最新数据位置) +- `scrollToTop()` - 滚动到**页面顶部**(最旧数据位置) + +## 浏览器兼容性 + +- Chrome >= 64 +- Firefox >= 69 +- Safari >= 13.1 +- Edge >= 79 + +需要浏览器支持 `ResizeObserver` API。 diff --git a/src/components/virtual-scroller/VirtualScroller.vue b/src/components/virtual-scroller/VirtualScroller.vue index 3537b65..869bcfd 100644 --- a/src/components/virtual-scroller/VirtualScroller.vue +++ b/src/components/virtual-scroller/VirtualScroller.vue @@ -1,140 +1,690 @@ - - - diff --git a/src/components/virtual-scroller/VirtualScrollerItem.vue b/src/components/virtual-scroller/VirtualScrollerItem.vue deleted file mode 100644 index d75a660..0000000 --- a/src/components/virtual-scroller/VirtualScrollerItem.vue +++ /dev/null @@ -1,96 +0,0 @@ - - - - - diff --git a/src/components/virtual-scroller/index.js b/src/components/virtual-scroller/index.js index a12037f..991a9f7 100644 --- a/src/components/virtual-scroller/index.js +++ b/src/components/virtual-scroller/index.js @@ -1,11 +1,4 @@ import VirtualScroller from './VirtualScroller.vue' -import VirtualScrollerItem from './VirtualScrollerItem.vue' -import useVirtualScroller from './useVirtualScroller' - -export { - VirtualScroller, - VirtualScrollerItem, - useVirtualScroller -} +export { VirtualScroller } export default VirtualScroller diff --git a/src/components/virtual-scroller/useVirtualScroller.js b/src/components/virtual-scroller/useVirtualScroller.js deleted file mode 100644 index 1c5fdee..0000000 --- a/src/components/virtual-scroller/useVirtualScroller.js +++ /dev/null @@ -1,246 +0,0 @@ -import { ref, computed, watch, nextTick } from 'vue' - -export default function useVirtualScroller(props, emit, scrollerRef) { - const heights = ref(new Map()) - const positions = ref([]) - const scrollTop = ref(0) - const clientHeight = ref(0) - const isLoading = ref(false) - let lastScrollTime = 0 - let animationFrameId = null - const savedScrollPosition = ref(null) - - const getHeight = (index) => { - return heights.value.get(index) || props.estimatedHeight - } - - const initPositions = () => { - const data = props.data || [] - positions.value = [] - let top = 0 - for (let i = 0; i < data.length; i++) { - const height = getHeight(i) - positions.value.push({ - index: i, - top, - bottom: top + height, - height - }) - top += height - } - } - - const totalHeight = computed(() => { - if (positions.value.length === 0) return 0 - return positions.value[positions.value.length - 1].bottom - }) - - const getVisibleRange = () => { - const data = props.data || [] - if (data.length === 0) return { start: 0, end: 0 } - - let start = 0 - let end = data.length - - const currentScrollTop = scrollTop.value - const currentClientHeight = clientHeight.value - - for (let i = 0; i < positions.value.length; i++) { - if (positions.value[i].bottom > currentScrollTop) { - start = i - break - } - } - - for (let i = start; i < positions.value.length; i++) { - if (positions.value[i].top > currentScrollTop + currentClientHeight) { - end = i - break - } - } - - start = Math.max(0, start - props.buffer) - end = Math.min(data.length, end + props.buffer) - - return { start, end } - } - - const visibleData = computed(() => { - const { start, end } = getVisibleRange() - const data = props.data || [] - const result = [] - for (let i = start; i < end; i++) { - result.push({ - item: data[i], - index: i, - top: positions.value[i]?.top || 0 - }) - } - return result - }) - - const handleScroll = (event) => { - const now = Date.now() - const throttleTime = 16 - - if (now - lastScrollTime < throttleTime) return - lastScrollTime = now - - if (animationFrameId) { - cancelAnimationFrame(animationFrameId) - } - - animationFrameId = requestAnimationFrame(() => { - const target = event.target - scrollTop.value = target.scrollTop - clientHeight.value = target.clientHeight - - checkLoadMore(target) - }) - } - - const checkLoadMore = (target) => { - if (isLoading.value || !props.onLoadMore) return - - const { scrollTop: st, scrollHeight, clientHeight: ch } = target - const distanceToTop = st - const distanceToBottom = scrollHeight - st - ch - - if (props.renderMode === 'bottom') { - if (distanceToTop <= props.scrollThreshold) { - loadMore() - } - } else { - if (distanceToBottom <= props.scrollThreshold) { - loadMore() - } - } - } - - const loadMore = async () => { - if (isLoading.value || !props.onLoadMore) return - isLoading.value = true - emit('load-more') - try { - await props.onLoadMore() - } finally { - isLoading.value = false - } - } - - const scrollToBottom = () => { - nextTick(() => { - if (scrollerRef.value) { - scrollerRef.value.scrollTop = scrollerRef.value.scrollHeight - } - }) - } - - const scrollToTop = () => { - nextTick(() => { - if (scrollerRef.value) { - scrollerRef.value.scrollTop = 0 - } - }) - } - - const scrollToIndex = (index) => { - nextTick(() => { - if (scrollerRef.value && positions.value[index]) { - scrollerRef.value.scrollTop = positions.value[index].top - } - }) - } - - const updateData = (newData) => { - initPositions() - } - - const getScrollPosition = () => { - if (scrollerRef.value) { - return scrollerRef.value.scrollTop - } - return 0 - } - - const setScrollPosition = (position) => { - nextTick(() => { - if (scrollerRef.value) { - scrollerRef.value.scrollTop = position - } - }) - } - - const updateItemHeight = (index, height) => { - if (!props.cacheHeight) return - - const oldHeight = heights.value.get(index) || props.estimatedHeight - if (oldHeight === height) return - - heights.value.set(index, height) - - const oldScrollTop = scrollerRef.value?.scrollTop || 0 - const oldScrollHeight = scrollerRef.value?.scrollHeight || 0 - - initPositions() - - nextTick(() => { - if (scrollerRef.value && props.renderMode === 'bottom') { - const newScrollHeight = scrollerRef.value.scrollHeight - const heightDiff = newScrollHeight - oldScrollHeight - if (heightDiff > 0) { - scrollerRef.value.scrollTop = oldScrollTop + heightDiff - } - } - }) - } - - const clearHeightCache = () => { - heights.value.clear() - initPositions() - } - - const initScroll = () => { - initPositions() - nextTick(() => { - if (scrollerRef.value) { - clientHeight.value = scrollerRef.value.clientHeight - if (props.renderMode === 'bottom') { - scrollToBottom() - } - } - }) - } - - watch(() => props.data, () => { - const oldScrollTop = scrollerRef.value?.scrollTop || 0 - const oldScrollHeight = scrollerRef.value?.scrollHeight || 0 - - initPositions() - - nextTick(() => { - if (scrollerRef.value && props.renderMode === 'bottom') { - const newScrollHeight = scrollerRef.value.scrollHeight - const heightDiff = newScrollHeight - oldScrollHeight - if (heightDiff > 0) { - scrollerRef.value.scrollTop = oldScrollTop + heightDiff - } - } - }) - }, { deep: true, immediate: true }) - - return { - visibleData, - totalHeight, - scrollToBottom, - scrollToTop, - scrollToIndex, - updateData, - getScrollPosition, - setScrollPosition, - updateItemHeight, - clearHeightCache, - handleScroll, - initScroll - } -} diff --git a/src/config/modelConfig/painting.json b/src/config/modelConfig/painting.json new file mode 100644 index 0000000..17fe462 --- /dev/null +++ b/src/config/modelConfig/painting.json @@ -0,0 +1,17 @@ +{ + "generate": [ + { "value": "flux", "label": "flux" }, + { "value": "zImage", "label": "Z-image" }, + { "value": "jimeng", "label": "jimeng" }, + { "value": "QwenImage", "label": "QwenImage" } + ], + "edit": [ + { "value": "BananaPro", "label": "Banana-Pro" }, + { "value": "Qwen-image", "label": "Qwen-image" }, + { "value": "Kontext", "label": "Kontext" }, + { "value": "Jimeng_4.0", "label": "Jimeng.4.0" } + ], + "vision": [ + { "value": "Qwen3.5plus", "label": "Qwen3.5plus" } + ] +} diff --git a/src/config/modelConfig/video.json b/src/config/modelConfig/video.json new file mode 100644 index 0000000..174eeb3 --- /dev/null +++ b/src/config/modelConfig/video.json @@ -0,0 +1,8 @@ +{ + "video": [ + { "value": "FlashHead", "label": "FlashHead" }, + { "value": "LTX2.3-T2V", "label": "LTX 2.3-T2V" }, + { "value": "Vidu Q3-I2V", "label": "Vidu Q3-I2V" }, + { "value": "Vidu Q3-T2V", "label": "Vidu Q3-T2V" } + ] +} diff --git a/src/stores/display.js b/src/stores/display.js index 9352dfe..8016727 100644 --- a/src/stores/display.js +++ b/src/stores/display.js @@ -3,6 +3,9 @@ const DisplayStoreSetup = () => { const scrollerRef = ref(null) const tempList = ref([]) const isSubGerenate = ref(false) + const currentPage = ref(0) + const hasMoreData = ref(true) + const isLoading = ref(false) const addGeneratingItem = (item) => { const newItem = { @@ -15,34 +18,47 @@ const DisplayStoreSetup = () => { files: [], ...item } - tempList.value.push(newItem) + tempList.value.unshift(newItem) return newItem } - const updateItemToSuccess = (taskId, fileUrl) => { + const updateItemToSuccess = (taskId, fileUrls) => { const index = tempList.value.findIndex(item => item.id === taskId) if (index !== -1) { tempList.value[index].status = 'success' - tempList.value[index].files = [fileUrl] + tempList.value[index].files = Array.isArray(fileUrls) ? fileUrls : [fileUrls] } } const initHistoryList = (historyList) => { tempList.value = historyList + currentPage.value = 1 + hasMoreData.value = true + } + + const prependHistoryList = (historyList) => { + tempList.value = [...historyList, ...tempList.value] + } + + const appendHistoryList = (historyList) => { + tempList.value = [...tempList.value, ...historyList] + } + + const resetPagination = () => { + currentPage.value = 0 + hasMoreData.value = true + isLoading.value = false } const scrollToBottom = async () => { - console.log('store - 滚动到底部') const refValue = scrollerRef.value if (!refValue) { - console.log('store - scrollerRef 不存在') return } try { if (typeof refValue.scrollToBottom === 'function') { - console.log('store - 使用新组件 scrollToBottom') await nextTick() refValue.scrollToBottom() return @@ -52,18 +68,16 @@ const DisplayStoreSetup = () => { if (scrollerEl) { const viewport = scrollerEl.querySelector('.vue-recycle-scroller__viewport') if (viewport) { - console.log('store - 原生滚动, scrollHeight:', viewport.scrollHeight) viewport.scrollTop = viewport.scrollHeight } } if (typeof refValue.scrollToItem === 'function' && tempList.value && tempList.value.length > 0) { - console.log('store - scrollToItem, index:', tempList.value.length - 1) await nextTick() refValue.scrollToItem(tempList.value.length - 1) } } catch (error) { - console.error('store - 滚动出错:', error) + console.error('滚动出错:', error) } } @@ -72,9 +86,15 @@ const DisplayStoreSetup = () => { scrollerRef, tempList, isSubGerenate, + currentPage, + hasMoreData, + isLoading, addGeneratingItem, updateItemToSuccess, initHistoryList, + prependHistoryList, + appendHistoryList, + resetPagination, scrollToBottom } } diff --git a/src/utils/createTask.js b/src/utils/createTask.js index 003ca90..2f4c612 100644 --- a/src/utils/createTask.js +++ b/src/utils/createTask.js @@ -20,7 +20,8 @@ export async function createTask(data, type, taskId, token) { // 获取结果 export async function getTask(result) { if (result.code === 0 && result.msg === 'success' && Array.isArray(result.data) && result.data.length > 0) { - return { type: true, url: result.data[0].fileUrl } + const urls = result.data.map(item => item.fileUrl) + return { type: true, urls: urls } } return { type: false, message: result.data?.exception_message || '生成失败' } -} +} \ No newline at end of file diff --git a/src/utils/websocket.js b/src/utils/websocket.js index 4d2a564..73f6245 100644 --- a/src/utils/websocket.js +++ b/src/utils/websocket.js @@ -5,6 +5,17 @@ import { getToken } from '@/utils/auth' import { createTask, getTask } from '@/utils/createTask' import { userError } from '@/utils/tokenError' +export function getChargeType(chargeType) { + switch (chargeType) { + case 'painting': + return 1 + case 'video': + return 2 + default: + return 2 + } +} + export function websocketError(code, msg) { let message switch (code) { @@ -50,7 +61,6 @@ export function websocketSuccess() { export async function generate(type, data) { const progress_text = ref('') const message = ref('') - const previewUrl = ref('') const useDisplay = useDisplayStore() const token = getToken() const taskId = crypto.randomUUID() @@ -138,10 +148,9 @@ export async function generate(type, data) { console.log('收到服务器消息:', res) const result = await getTask(res) if (result.type) { - previewUrl.value = result.url if (currentTaskId) { - useDisplay.updateItemToSuccess(currentTaskId, result.url) + useDisplay.updateItemToSuccess(currentTaskId, result.urls) } websocketSuccess() diff --git a/src/views/home/display/components/set.vue b/src/views/home/display/components/set.vue index f8f48f2..1f890fa 100644 --- a/src/views/home/display/components/set.vue +++ b/src/views/home/display/components/set.vue @@ -1,5 +1,5 @@