feat:修改铸造相关报错
This commit is contained in:
parent
ba44041e55
commit
d279976822
@ -203,6 +203,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/castlove/create",
|
||||
"style": {
|
||||
"navigationStyle": "custom",
|
||||
"app-plus": {
|
||||
"bounce": "none"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/castlove/craft-select",
|
||||
"style": {
|
||||
|
||||
@ -112,11 +112,19 @@ isErrorProcessing: false // 防止错误重复触发
|
||||
},
|
||||
onLoad() {
|
||||
this.initSession()
|
||||
this.initWebSocket()
|
||||
},
|
||||
onReady() {
|
||||
console.log('[AI Chat] onReady called')
|
||||
},
|
||||
onShow() {
|
||||
// 页面可见时连接 WebSocket(包括首次进入和从其他页面返回)
|
||||
this.initWebSocket()
|
||||
},
|
||||
onHide() {
|
||||
// 页面不可见时断开,不再占用连接
|
||||
this.clearStreamTimeout()
|
||||
this.closeWebSocket()
|
||||
},
|
||||
onUnload() {
|
||||
this.clearStreamTimeout()
|
||||
this.closeWebSocket()
|
||||
@ -196,11 +204,10 @@ isErrorProcessing: false // 防止错误重复触发
|
||||
})
|
||||
|
||||
// 设置断开回调 - 在对话框提示用户
|
||||
socket.off('disconnect', this._disconnectHandler)
|
||||
const prevDisconnect = this._disconnectHandler
|
||||
this._disconnectHandler = () => {
|
||||
console.log('[AI Chat] WebSocket disconnected')
|
||||
if (this.isTyping) {
|
||||
// 先保存已收到的部分回复
|
||||
if (this.currentAssistantMessage) {
|
||||
this.messages.push({
|
||||
role: 'assistant',
|
||||
@ -217,6 +224,7 @@ isErrorProcessing: false // 防止错误重复触发
|
||||
this.scrollToBottom()
|
||||
}
|
||||
}
|
||||
socket.off('disconnect', prevDisconnect)
|
||||
socket.on('disconnect', this._disconnectHandler)
|
||||
|
||||
// 设置连接成功回调
|
||||
|
||||
@ -410,7 +410,7 @@ export default {
|
||||
fail: (err) => {
|
||||
// 路径写错 / pages.json 未注册 → 兜底 toast,不闪退
|
||||
console.error("[castlove] navigateTo fail", card.route_path, err);
|
||||
uni.showToast({ title: "页面不存在", icon: "none" });
|
||||
uni.showToast({ title: "功能待开发", icon: "none" });
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
117
frontend/pages/castlove/create-laser-upload.css
Normal file
117
frontend/pages/castlove/create-laser-upload.css
Normal file
@ -0,0 +1,117 @@
|
||||
/**
|
||||
* 铸爱 create 页 — 镭射卡上传区样式(独立 CSS,由 create.vue import,确保各端构建必进包)
|
||||
* 根类 castlove-laser-upload-root 全局唯一,避免 scoped / 第二 style 块在部分端未生效
|
||||
*/
|
||||
.castlove-laser-upload-root {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
/* 略偏竖版小卡比例,接近设计稿「大卡 + 内虚线」观感 */
|
||||
height: 520rpx;
|
||||
box-sizing: border-box;
|
||||
border-radius: 32rpx;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.38);
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
backdrop-filter: blur(22rpx);
|
||||
-webkit-backdrop-filter: blur(22rpx);
|
||||
overflow: hidden;
|
||||
box-shadow:
|
||||
0 22rpx 56rpx rgba(40, 22, 80, 0.36),
|
||||
inset 0 0 0 1rpx rgba(255, 255, 255, 0.22);
|
||||
}
|
||||
|
||||
.castlove-laser-upload-root .uploaded-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 24rpx;
|
||||
box-shadow: inset 0 0 0 1rpx rgba(255, 255, 255, 0.22);
|
||||
}
|
||||
|
||||
.castlove-laser-upload-root .upload-laser-stack {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 与设计稿一致:卡内淡色「卡面 / 人像」底图(与工艺选择同款素材) */
|
||||
.castlove-laser-upload-root .upload-laser-photo-bg {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
opacity: 0.22;
|
||||
pointer-events: none;
|
||||
filter: saturate(1.15) contrast(0.92);
|
||||
}
|
||||
|
||||
.castlove-laser-upload-root .upload-laser-watermark {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
opacity: 1;
|
||||
pointer-events: none;
|
||||
/* 叠在底图上:压暗边缘 + 轻微幻彩,避免只剩「灰蒙一块」 */
|
||||
background:
|
||||
linear-gradient(
|
||||
118deg,
|
||||
rgba(255, 170, 220, 0.12) 0%,
|
||||
transparent 40%,
|
||||
rgba(170, 210, 255, 0.1) 62%,
|
||||
transparent 82%,
|
||||
rgba(255, 210, 190, 0.08) 100%
|
||||
),
|
||||
radial-gradient(ellipse 55% 75% at 50% 100%, rgba(35, 22, 70, 0.45), transparent 58%),
|
||||
radial-gradient(ellipse 40% 48% at 50% 32%, rgba(100, 75, 150, 0.28), transparent 55%),
|
||||
linear-gradient(185deg, rgba(255, 220, 245, 0.08) 0%, rgba(55, 35, 95, 0.25) 100%);
|
||||
}
|
||||
|
||||
.castlove-laser-upload-root .upload-laser-inset {
|
||||
position: absolute;
|
||||
/* 收紧留白:虚线框更贴外框,接近设计稿「整卡即相框」 */
|
||||
left: 14rpx;
|
||||
right: 14rpx;
|
||||
top: 14rpx;
|
||||
bottom: 14rpx;
|
||||
z-index: 2;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.castlove-laser-upload-root .upload-laser-dashed-inner {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
border: 2rpx dashed rgba(255, 255, 255, 0.95);
|
||||
border-radius: 26rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 20rpx;
|
||||
padding: 24rpx 16rpx;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
}
|
||||
|
||||
.castlove-laser-upload-root .upload-plus--laser {
|
||||
font-size: 96rpx;
|
||||
line-height: 0.88;
|
||||
color: #ffffff;
|
||||
font-weight: 100;
|
||||
text-shadow: 0 2rpx 18rpx rgba(60, 30, 100, 0.35);
|
||||
}
|
||||
|
||||
.castlove-laser-upload-root .upload-text--laser {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.96);
|
||||
font-weight: 500;
|
||||
letter-spacing: 1rpx;
|
||||
text-shadow: 0 2rpx 12rpx rgba(40, 20, 80, 0.4);
|
||||
}
|
||||
1560
frontend/pages/castlove/create.vue
Normal file
1560
frontend/pages/castlove/create.vue
Normal file
File diff suppressed because it is too large
Load Diff
@ -106,7 +106,8 @@ const handleSelect = (idx) => {
|
||||
}
|
||||
|
||||
const handleBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
// uni.navigateBack({ delta: 1 })
|
||||
uni.redirectTo({ url: `/pages/castlove/create?name=${encodeURIComponent('镭射卡')}` })
|
||||
}
|
||||
|
||||
// 礼盒打开后:白光扫光 → 选中默认卡(克制,无彩虹过曝)
|
||||
|
||||
@ -821,10 +821,10 @@ const fetchUserInfo = async (forceRefresh = false) => {
|
||||
}
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: error.message || "获取用户信息失败",
|
||||
icon: "none",
|
||||
});
|
||||
// uni.showToast({
|
||||
// title: error.message || "获取用户信息失败",
|
||||
// icon: "none",
|
||||
// });
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
@ -106,7 +106,8 @@ export function useContributionRealtime(activityId, isPageActive) {
|
||||
// contribution channel 也能用新 token 重新订阅,而不是复用上一个用户的 WS。
|
||||
const token = uni.getStorageSync('access_token')
|
||||
if (token) {
|
||||
socket.connect(token).catch(err => console.warn('[useContributionRealtime] connect error:', err))
|
||||
// 连接统一由页面 onShow 管理
|
||||
// socket.connect(token).catch(err => console.warn('[useContributionRealtime] connect error:', err))
|
||||
}
|
||||
// 同步分支:如果 WS 已连接(单例复用导致 'connect' 事件不会再次触发)且 pubsub 可用,
|
||||
// 必须直接调 onWsConnect 停轮询,否则 polling 会一直跑。
|
||||
|
||||
@ -92,7 +92,8 @@ export function useMessageRealtime(activityId) {
|
||||
// 解决"另一个账户没有接收到实时推送"的问题。
|
||||
const token = uni.getStorageSync('access_token')
|
||||
if (token) {
|
||||
socket.connect(token).catch(err => console.warn('[useMessageRealtime] connect error:', err))
|
||||
// 连接统一由页面 onShow 管理
|
||||
// socket.connect(token).catch(err => console.warn('[useMessageRealtime] connect error:', err))
|
||||
}
|
||||
// 同步分支:如果 WS 已连接(单例复用,另一个 composable 可能先连上了),
|
||||
// subscribe 会直接发送;否则缓存到 _topics,等待 connect 事件触发 resubscribeAll
|
||||
|
||||
@ -208,7 +208,7 @@ import TopRanking from "./components/TopRanking.vue";
|
||||
import MessageBoard from "./components/MessageBoard.vue";
|
||||
import MessageInput from "./components/MessageInput.vue";
|
||||
import { getEarningsSummaryApi } from "@/utils/api.js";
|
||||
import { closeActivitySocket } from "@/utils/socket/ActivitySocket.js";
|
||||
import { getActivitySocket, closeActivitySocket } from "@/utils/socket/ActivitySocket.js";
|
||||
import { useMessageRealtime } from "./composables/useMessageRealtime.js";
|
||||
import { useContributionRealtime } from "./composables/useContributionRealtime.js";
|
||||
|
||||
@ -551,7 +551,6 @@ async function preloadCriticalAssets() {
|
||||
return new Promise((resolve) => {
|
||||
const startTime = Date.now();
|
||||
let isResolved = false;
|
||||
const img = new Image();
|
||||
|
||||
// 超时定时器
|
||||
const timeoutId = setTimeout(() => {
|
||||
@ -562,27 +561,28 @@ async function preloadCriticalAssets() {
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
img.onload = () => {
|
||||
if (!isResolved) {
|
||||
isResolved = true;
|
||||
clearTimeout(timeoutId);
|
||||
const loadTime = Date.now() - startTime;
|
||||
performanceMonitor.recordImageLoad(true, loadTime);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
img.onerror = () => {
|
||||
if (!isResolved) {
|
||||
isResolved = true;
|
||||
clearTimeout(timeoutId);
|
||||
const loadTime = Date.now() - startTime;
|
||||
performanceMonitor.recordImageLoad(false, loadTime);
|
||||
resolve(); // 即使失败也继续
|
||||
}
|
||||
};
|
||||
|
||||
img.src = src;
|
||||
// uni-app 环境使用 uni.getImageInfo 代替 new Image(),兼容 App/iOS/Android
|
||||
uni.getImageInfo({
|
||||
src,
|
||||
success: () => {
|
||||
if (!isResolved) {
|
||||
isResolved = true;
|
||||
clearTimeout(timeoutId);
|
||||
const loadTime = Date.now() - startTime;
|
||||
performanceMonitor.recordImageLoad(true, loadTime);
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
if (!isResolved) {
|
||||
isResolved = true;
|
||||
clearTimeout(timeoutId);
|
||||
const loadTime = Date.now() - startTime;
|
||||
performanceMonitor.recordImageLoad(false, loadTime);
|
||||
resolve(); // 即使失败也继续
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -609,19 +609,18 @@ function preloadNonCriticalAssets() {
|
||||
nonCriticalImages.forEach((src) => {
|
||||
if (src) {
|
||||
const startTime = Date.now();
|
||||
const img = new Image();
|
||||
|
||||
img.onload = () => {
|
||||
const loadTime = Date.now() - startTime;
|
||||
performanceMonitor.recordImageLoad(true, loadTime);
|
||||
};
|
||||
|
||||
img.onerror = () => {
|
||||
const loadTime = Date.now() - startTime;
|
||||
performanceMonitor.recordImageLoad(false, loadTime);
|
||||
};
|
||||
|
||||
img.src = src;
|
||||
// uni-app 环境使用 uni.getImageInfo 代替 new Image(),兼容 App/iOS/Android
|
||||
uni.getImageInfo({
|
||||
src,
|
||||
success: () => {
|
||||
const loadTime = Date.now() - startTime;
|
||||
performanceMonitor.recordImageLoad(true, loadTime);
|
||||
},
|
||||
fail: () => {
|
||||
const loadTime = Date.now() - startTime;
|
||||
performanceMonitor.recordImageLoad(false, loadTime);
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
}, 1000); // 延迟1秒后开始加载
|
||||
@ -652,8 +651,13 @@ onLoad(async (options) => {
|
||||
onShow(() => {
|
||||
isPageActive.value = true;
|
||||
|
||||
// 进入活动页面时连接 Activity socket
|
||||
const token = uni.getStorageSync("access_token");
|
||||
if (token) {
|
||||
getActivitySocket().connect(token);
|
||||
}
|
||||
|
||||
if (!isLoading.value && !errorMessage.value && progressManager) {
|
||||
// 使用 resumePolling 而不是 startPolling,避免重复启动
|
||||
progressManager.resumePolling();
|
||||
}
|
||||
|
||||
@ -661,6 +665,9 @@ onShow(() => {
|
||||
});
|
||||
|
||||
onHide(() => {
|
||||
// 离开活动页面时断开 Activity socket
|
||||
closeActivitySocket();
|
||||
|
||||
isPageActive.value = false;
|
||||
|
||||
// 使用 pausePolling 暂停轮询,而不是完全停止
|
||||
|
||||
@ -486,6 +486,33 @@ export function loadTextureImage(src, canvasForCreateImage) {
|
||||
/* fall through */
|
||||
}
|
||||
}
|
||||
// uni-app 环境使用 uni.getImageInfo 代替 new Image(),兼容 App/iOS/Android
|
||||
if (typeof uni !== 'undefined' && typeof uni.getImageInfo === 'function') {
|
||||
try {
|
||||
uni.getImageInfo({
|
||||
src,
|
||||
success: (res) => {
|
||||
const localPath = res.path || src
|
||||
const offC = typeof uni.createOffscreenCanvas === 'function'
|
||||
? uni.createOffscreenCanvas({ type: '2d', width: 1, height: 1 })
|
||||
: null
|
||||
if (offC && typeof offC.createImage === 'function') {
|
||||
const img = offC.createImage()
|
||||
img.onload = () => resolve(img)
|
||||
img.onerror = () => reject(new Error('createImage load'))
|
||||
img.src = localPath
|
||||
} else {
|
||||
reject(new Error('createOffscreenCanvas failed'))
|
||||
}
|
||||
},
|
||||
fail: (err) => reject(new Error('getImageInfo: ' + JSON.stringify(err)))
|
||||
})
|
||||
return
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
return
|
||||
}
|
||||
}
|
||||
if (typeof Image !== 'undefined') {
|
||||
try {
|
||||
const img = new Image()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user