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",
|
"path": "pages/castlove/craft-select",
|
||||||
"style": {
|
"style": {
|
||||||
|
|||||||
@ -112,11 +112,19 @@ isErrorProcessing: false // 防止错误重复触发
|
|||||||
},
|
},
|
||||||
onLoad() {
|
onLoad() {
|
||||||
this.initSession()
|
this.initSession()
|
||||||
this.initWebSocket()
|
|
||||||
},
|
},
|
||||||
onReady() {
|
onReady() {
|
||||||
console.log('[AI Chat] onReady called')
|
console.log('[AI Chat] onReady called')
|
||||||
},
|
},
|
||||||
|
onShow() {
|
||||||
|
// 页面可见时连接 WebSocket(包括首次进入和从其他页面返回)
|
||||||
|
this.initWebSocket()
|
||||||
|
},
|
||||||
|
onHide() {
|
||||||
|
// 页面不可见时断开,不再占用连接
|
||||||
|
this.clearStreamTimeout()
|
||||||
|
this.closeWebSocket()
|
||||||
|
},
|
||||||
onUnload() {
|
onUnload() {
|
||||||
this.clearStreamTimeout()
|
this.clearStreamTimeout()
|
||||||
this.closeWebSocket()
|
this.closeWebSocket()
|
||||||
@ -196,11 +204,10 @@ isErrorProcessing: false // 防止错误重复触发
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 设置断开回调 - 在对话框提示用户
|
// 设置断开回调 - 在对话框提示用户
|
||||||
socket.off('disconnect', this._disconnectHandler)
|
const prevDisconnect = this._disconnectHandler
|
||||||
this._disconnectHandler = () => {
|
this._disconnectHandler = () => {
|
||||||
console.log('[AI Chat] WebSocket disconnected')
|
console.log('[AI Chat] WebSocket disconnected')
|
||||||
if (this.isTyping) {
|
if (this.isTyping) {
|
||||||
// 先保存已收到的部分回复
|
|
||||||
if (this.currentAssistantMessage) {
|
if (this.currentAssistantMessage) {
|
||||||
this.messages.push({
|
this.messages.push({
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
@ -217,6 +224,7 @@ isErrorProcessing: false // 防止错误重复触发
|
|||||||
this.scrollToBottom()
|
this.scrollToBottom()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
socket.off('disconnect', prevDisconnect)
|
||||||
socket.on('disconnect', this._disconnectHandler)
|
socket.on('disconnect', this._disconnectHandler)
|
||||||
|
|
||||||
// 设置连接成功回调
|
// 设置连接成功回调
|
||||||
|
|||||||
@ -410,7 +410,7 @@ export default {
|
|||||||
fail: (err) => {
|
fail: (err) => {
|
||||||
// 路径写错 / pages.json 未注册 → 兜底 toast,不闪退
|
// 路径写错 / pages.json 未注册 → 兜底 toast,不闪退
|
||||||
console.error("[castlove] navigateTo fail", card.route_path, err);
|
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 = () => {
|
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({
|
// uni.showToast({
|
||||||
title: error.message || "获取用户信息失败",
|
// title: error.message || "获取用户信息失败",
|
||||||
icon: "none",
|
// icon: "none",
|
||||||
});
|
// });
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -106,7 +106,8 @@ export function useContributionRealtime(activityId, isPageActive) {
|
|||||||
// contribution channel 也能用新 token 重新订阅,而不是复用上一个用户的 WS。
|
// contribution channel 也能用新 token 重新订阅,而不是复用上一个用户的 WS。
|
||||||
const token = uni.getStorageSync('access_token')
|
const token = uni.getStorageSync('access_token')
|
||||||
if (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 可用,
|
// 同步分支:如果 WS 已连接(单例复用导致 'connect' 事件不会再次触发)且 pubsub 可用,
|
||||||
// 必须直接调 onWsConnect 停轮询,否则 polling 会一直跑。
|
// 必须直接调 onWsConnect 停轮询,否则 polling 会一直跑。
|
||||||
|
|||||||
@ -92,7 +92,8 @@ export function useMessageRealtime(activityId) {
|
|||||||
// 解决"另一个账户没有接收到实时推送"的问题。
|
// 解决"另一个账户没有接收到实时推送"的问题。
|
||||||
const token = uni.getStorageSync('access_token')
|
const token = uni.getStorageSync('access_token')
|
||||||
if (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 可能先连上了),
|
// 同步分支:如果 WS 已连接(单例复用,另一个 composable 可能先连上了),
|
||||||
// subscribe 会直接发送;否则缓存到 _topics,等待 connect 事件触发 resubscribeAll
|
// subscribe 会直接发送;否则缓存到 _topics,等待 connect 事件触发 resubscribeAll
|
||||||
|
|||||||
@ -208,7 +208,7 @@ import TopRanking from "./components/TopRanking.vue";
|
|||||||
import MessageBoard from "./components/MessageBoard.vue";
|
import MessageBoard from "./components/MessageBoard.vue";
|
||||||
import MessageInput from "./components/MessageInput.vue";
|
import MessageInput from "./components/MessageInput.vue";
|
||||||
import { getEarningsSummaryApi } from "@/utils/api.js";
|
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 { useMessageRealtime } from "./composables/useMessageRealtime.js";
|
||||||
import { useContributionRealtime } from "./composables/useContributionRealtime.js";
|
import { useContributionRealtime } from "./composables/useContributionRealtime.js";
|
||||||
|
|
||||||
@ -551,7 +551,6 @@ async function preloadCriticalAssets() {
|
|||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
let isResolved = false;
|
let isResolved = false;
|
||||||
const img = new Image();
|
|
||||||
|
|
||||||
// 超时定时器
|
// 超时定时器
|
||||||
const timeoutId = setTimeout(() => {
|
const timeoutId = setTimeout(() => {
|
||||||
@ -562,7 +561,10 @@ async function preloadCriticalAssets() {
|
|||||||
}
|
}
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
|
||||||
img.onload = () => {
|
// uni-app 环境使用 uni.getImageInfo 代替 new Image(),兼容 App/iOS/Android
|
||||||
|
uni.getImageInfo({
|
||||||
|
src,
|
||||||
|
success: () => {
|
||||||
if (!isResolved) {
|
if (!isResolved) {
|
||||||
isResolved = true;
|
isResolved = true;
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
@ -570,9 +572,8 @@ async function preloadCriticalAssets() {
|
|||||||
performanceMonitor.recordImageLoad(true, loadTime);
|
performanceMonitor.recordImageLoad(true, loadTime);
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
fail: () => {
|
||||||
img.onerror = () => {
|
|
||||||
if (!isResolved) {
|
if (!isResolved) {
|
||||||
isResolved = true;
|
isResolved = true;
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
@ -580,9 +581,8 @@ async function preloadCriticalAssets() {
|
|||||||
performanceMonitor.recordImageLoad(false, loadTime);
|
performanceMonitor.recordImageLoad(false, loadTime);
|
||||||
resolve(); // 即使失败也继续
|
resolve(); // 即使失败也继续
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
});
|
||||||
img.src = src;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -609,19 +609,18 @@ function preloadNonCriticalAssets() {
|
|||||||
nonCriticalImages.forEach((src) => {
|
nonCriticalImages.forEach((src) => {
|
||||||
if (src) {
|
if (src) {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const img = new Image();
|
// uni-app 环境使用 uni.getImageInfo 代替 new Image(),兼容 App/iOS/Android
|
||||||
|
uni.getImageInfo({
|
||||||
img.onload = () => {
|
src,
|
||||||
|
success: () => {
|
||||||
const loadTime = Date.now() - startTime;
|
const loadTime = Date.now() - startTime;
|
||||||
performanceMonitor.recordImageLoad(true, loadTime);
|
performanceMonitor.recordImageLoad(true, loadTime);
|
||||||
};
|
},
|
||||||
|
fail: () => {
|
||||||
img.onerror = () => {
|
|
||||||
const loadTime = Date.now() - startTime;
|
const loadTime = Date.now() - startTime;
|
||||||
performanceMonitor.recordImageLoad(false, loadTime);
|
performanceMonitor.recordImageLoad(false, loadTime);
|
||||||
};
|
},
|
||||||
|
});
|
||||||
img.src = src;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, 1000); // 延迟1秒后开始加载
|
}, 1000); // 延迟1秒后开始加载
|
||||||
@ -652,8 +651,13 @@ onLoad(async (options) => {
|
|||||||
onShow(() => {
|
onShow(() => {
|
||||||
isPageActive.value = true;
|
isPageActive.value = true;
|
||||||
|
|
||||||
|
// 进入活动页面时连接 Activity socket
|
||||||
|
const token = uni.getStorageSync("access_token");
|
||||||
|
if (token) {
|
||||||
|
getActivitySocket().connect(token);
|
||||||
|
}
|
||||||
|
|
||||||
if (!isLoading.value && !errorMessage.value && progressManager) {
|
if (!isLoading.value && !errorMessage.value && progressManager) {
|
||||||
// 使用 resumePolling 而不是 startPolling,避免重复启动
|
|
||||||
progressManager.resumePolling();
|
progressManager.resumePolling();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -661,6 +665,9 @@ onShow(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onHide(() => {
|
onHide(() => {
|
||||||
|
// 离开活动页面时断开 Activity socket
|
||||||
|
closeActivitySocket();
|
||||||
|
|
||||||
isPageActive.value = false;
|
isPageActive.value = false;
|
||||||
|
|
||||||
// 使用 pausePolling 暂停轮询,而不是完全停止
|
// 使用 pausePolling 暂停轮询,而不是完全停止
|
||||||
|
|||||||
@ -486,6 +486,33 @@ export function loadTextureImage(src, canvasForCreateImage) {
|
|||||||
/* fall through */
|
/* 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') {
|
if (typeof Image !== 'undefined') {
|
||||||
try {
|
try {
|
||||||
const img = new Image()
|
const img = new Image()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user