feat:添加桥宝
This commit is contained in:
@@ -0,0 +1,804 @@
|
||||
<template>
|
||||
<view v-if="visible" class="qiaobao-assistant" :class="{ 'is-collapsed': collapsed }">
|
||||
<view v-if="collapsed" class="qiaobao-edge-tab"
|
||||
:class="{ 'is-left': collapsedEdge === 'left', 'is-dragging': dockDragging }" :style="dockStyle" role="button"
|
||||
aria-label="桥宝已收起,点击展开" @click.stop="restoreFromDock" @touchstart.stop="handleDockDragStart"
|
||||
@touchmove.stop.prevent="handleDockDragMove" @touchend.stop="handleDockDragEnd"
|
||||
@touchcancel.stop="handleDockDragEnd" @mousedown.stop.prevent="handleDockMouseDragStart">
|
||||
<image class="qiaobao-edge-head" src="https://static.tbmall.xin/static/mine/qiaobao-edge-peek.png"
|
||||
mode="aspectFit" />
|
||||
</view>
|
||||
|
||||
<view v-else class="qiaobao-float" :class="{ 'is-scratching': action === 'scratch' }" :style="floatStyle"
|
||||
role="button" aria-label="桥宝,点击查看当前页面说明,长按可隐藏" @click.stop="openHelp" @longpress.stop="openHideMenu"
|
||||
@contextmenu.stop.prevent="openHideMenu" @touchstart.stop="handleDragStart"
|
||||
@touchmove.stop.prevent="handleDragMove" @touchend.stop="handleDragEnd" @touchcancel.stop="handleDragEnd"
|
||||
@mousedown.stop.prevent="handleMouseDragStart">
|
||||
<view v-if="showBubble" class="qiaobao-bubble">点我,了解这个页面</view>
|
||||
<image class="qiaobao-image" :src="actionImage" mode="aspectFit" />
|
||||
<view class="qiaobao-shadow" />
|
||||
</view>
|
||||
|
||||
<view v-if="panelVisible" class="qiaobao-mask" @click="closeHelp" @touchmove.stop.prevent>
|
||||
<view class="qiaobao-sheet" @click.stop>
|
||||
<view class="qiaobao-handle" />
|
||||
<view class="qiaobao-sheet-head">
|
||||
<view class="qiaobao-avatar-wrap">
|
||||
<image class="qiaobao-avatar" src="https://static.tbmall.xin/static/mine/qiaobao-idle.png"
|
||||
mode="aspectFit" />
|
||||
</view>
|
||||
<view class="qiaobao-title-wrap">
|
||||
<text class="qiaobao-kicker">桥宝 · 页面向导</text>
|
||||
<text class="qiaobao-title">{{ resolvedTitle }}</text>
|
||||
</view>
|
||||
<view class="qiaobao-close" aria-label="关闭" @click="closeHelp">×</view>
|
||||
</view>
|
||||
|
||||
<scroll-view class="qiaobao-content" scroll-y>
|
||||
<text class="qiaobao-summary">{{ resolvedSummary }}</text>
|
||||
<view v-if="resolvedTips.length" class="qiaobao-tips">
|
||||
<view v-for="(tip, index) in resolvedTips" :key="index" class="qiaobao-tip">
|
||||
<text class="qiaobao-tip-index">{{ index + 1 }}</text>
|
||||
<text class="qiaobao-tip-text">{{ tip }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<slot />
|
||||
</scroll-view>
|
||||
|
||||
<button class="qiaobao-confirm" @click="closeHelp">我知道了</button>
|
||||
<text class="qiaobao-hide-hint">长按桥宝,可以选择隐藏</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getCurrentPagePath,
|
||||
getQiaobaoDockEdge,
|
||||
getQiaobaoPosition,
|
||||
hideQiaobaoForPage,
|
||||
hideQiaobaoGlobally,
|
||||
isQiaobaoHidden,
|
||||
saveQiaobaoPosition,
|
||||
setQiaobaoDockEdge,
|
||||
showQiaobao,
|
||||
} from "@/utils/qiaobao.js";
|
||||
import { resolveQiaobaoPageHelp } from "@/utils/qiaobao-page-help.js";
|
||||
|
||||
const ACTION_IMAGES = {
|
||||
idle: "https://static.tbmall.xin/static/mine/qiaobao-idle.png",
|
||||
blink: "https://static.tbmall.xin/static/mine/qiaobao-blink.png",
|
||||
scratch: "https://static.tbmall.xin/static/mine/qiaobao-scratch.png",
|
||||
};
|
||||
|
||||
export default {
|
||||
name: "QiaobaoAssistant",
|
||||
props: {
|
||||
pageKey: { type: String, default: "" },
|
||||
title: { type: String, default: "" },
|
||||
summary: { type: String, default: "" },
|
||||
tips: { type: Array, default: () => [] },
|
||||
bubble: { type: Boolean, default: true },
|
||||
},
|
||||
emits: ["open", "close", "hide"],
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
collapsed: false,
|
||||
collapsedEdge: "right",
|
||||
panelVisible: false,
|
||||
showBubble: false,
|
||||
action: "idle",
|
||||
actionTimer: null,
|
||||
bubbleTimer: null,
|
||||
longPressTriggered: false,
|
||||
position: null,
|
||||
viewportWidth: 0,
|
||||
viewportHeight: 0,
|
||||
safeAreaTop: 0,
|
||||
safeAreaBottom: 0,
|
||||
petWidth: 82,
|
||||
petHeight: 88,
|
||||
dockHeight: 48,
|
||||
dockDragging: false,
|
||||
dockDragMoved: false,
|
||||
dockDragJustEnded: false,
|
||||
dockDragStartPoint: { x: 0, y: 0 },
|
||||
dockDragOriginY: 0,
|
||||
dockPointerX: 0,
|
||||
dragging: false,
|
||||
dragMoved: false,
|
||||
dragJustEnded: false,
|
||||
dragStartPoint: { x: 0, y: 0 },
|
||||
dragOrigin: { x: 0, y: 0 },
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
currentPageKey() {
|
||||
return this.pageKey || getCurrentPagePath();
|
||||
},
|
||||
actionImage() {
|
||||
return ACTION_IMAGES[this.action] || ACTION_IMAGES.idle;
|
||||
},
|
||||
floatStyle() {
|
||||
if (!this.position) return null;
|
||||
return {
|
||||
left: `${this.position.x}px`,
|
||||
top: `${this.position.y}px`,
|
||||
right: "auto",
|
||||
bottom: "auto",
|
||||
};
|
||||
},
|
||||
dockStyle() {
|
||||
if (!this.position) return null;
|
||||
const maxTop = Math.max(this.safeAreaTop + 8, this.viewportHeight - this.safeAreaBottom - this.dockHeight - 8);
|
||||
return {
|
||||
top: `${Math.min(maxTop, Math.max(this.safeAreaTop + 8, this.position.y + (this.petHeight - this.dockHeight) / 2))}px`,
|
||||
bottom: "auto",
|
||||
};
|
||||
},
|
||||
automaticHelp() {
|
||||
return resolveQiaobaoPageHelp(this.currentPageKey);
|
||||
},
|
||||
resolvedTitle() {
|
||||
return this.title || this.automaticHelp.title;
|
||||
},
|
||||
resolvedSummary() {
|
||||
return this.summary || this.automaticHelp.summary;
|
||||
},
|
||||
resolvedTips() {
|
||||
const customTips = Array.isArray(this.tips) ? this.tips.filter(Boolean) : [];
|
||||
return customTips.length ? customTips : this.automaticHelp.tips;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
uni.$on("qiaobao-visibility-change", this.handleVisibilityChange);
|
||||
this.initializeDragPosition();
|
||||
this.refreshVisibility();
|
||||
// #ifdef H5
|
||||
window.addEventListener("mousemove", this.handleMouseDragMove);
|
||||
window.addEventListener("mouseup", this.handleMouseDragEnd);
|
||||
// #endif
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.panelVisible) {
|
||||
try {
|
||||
uni.showTabBar({ animation: false });
|
||||
} catch (e) {}
|
||||
}
|
||||
uni.$off("qiaobao-visibility-change", this.handleVisibilityChange);
|
||||
// #ifdef H5
|
||||
window.removeEventListener("mousemove", this.handleMouseDragMove);
|
||||
window.removeEventListener("mouseup", this.handleMouseDragEnd);
|
||||
// #endif
|
||||
this.clearTimers();
|
||||
},
|
||||
methods: {
|
||||
initializeDragPosition() {
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
this.viewportWidth = Number(systemInfo.windowWidth) || 375;
|
||||
this.viewportHeight = Number(systemInfo.windowHeight) || 667;
|
||||
this.safeAreaTop = Number(systemInfo.safeAreaInsets?.top) || 0;
|
||||
this.safeAreaBottom = Number(systemInfo.safeAreaInsets?.bottom) || 0;
|
||||
const scale = this.viewportWidth / 750;
|
||||
this.petWidth = 164 * scale;
|
||||
this.petHeight = 176 * scale;
|
||||
this.dockHeight = 126 * scale;
|
||||
const storedPosition = getQiaobaoPosition();
|
||||
const defaultPosition = {
|
||||
x: this.viewportWidth - this.petWidth - 10,
|
||||
y: this.viewportHeight - this.safeAreaBottom - this.petHeight - 66,
|
||||
};
|
||||
this.position = this.clampPosition(storedPosition || defaultPosition);
|
||||
},
|
||||
clampPosition(position) {
|
||||
const minX = 0;
|
||||
const maxX = Math.max(0, this.viewportWidth - this.petWidth);
|
||||
const minY = this.safeAreaTop + 4;
|
||||
const maxY = Math.max(minY, this.viewportHeight - this.safeAreaBottom - this.petHeight - 4);
|
||||
return {
|
||||
x: Math.min(maxX, Math.max(minX, Number(position?.x) || 0)),
|
||||
y: Math.min(maxY, Math.max(minY, Number(position?.y) || minY)),
|
||||
};
|
||||
},
|
||||
getTouchPoint(event) {
|
||||
const touch = event?.touches?.[0] || event?.changedTouches?.[0];
|
||||
if (!touch) return null;
|
||||
return { x: Number(touch.clientX), y: Number(touch.clientY) };
|
||||
},
|
||||
getMousePoint(event) {
|
||||
if (!event || !Number.isFinite(Number(event.clientX))) return null;
|
||||
return { x: Number(event.clientX), y: Number(event.clientY) };
|
||||
},
|
||||
startDragging(point) {
|
||||
if (!point || this.panelVisible) return;
|
||||
this.dragging = true;
|
||||
this.dragMoved = false;
|
||||
this.dragStartPoint = point;
|
||||
this.dragOrigin = { ...(this.position || { x: 0, y: 0 }) };
|
||||
this.showBubble = false;
|
||||
},
|
||||
handleDragStart(event) {
|
||||
this.startDragging(this.getTouchPoint(event));
|
||||
},
|
||||
handleMouseDragStart(event) {
|
||||
this.startDragging(this.getMousePoint(event));
|
||||
},
|
||||
handleDragMove(event) {
|
||||
if (!this.dragging) return;
|
||||
const point = this.getTouchPoint(event);
|
||||
if (!point) return;
|
||||
const deltaX = point.x - this.dragStartPoint.x;
|
||||
const deltaY = point.y - this.dragStartPoint.y;
|
||||
if (!this.dragMoved && Math.hypot(deltaX, deltaY) > 6) {
|
||||
this.dragMoved = true;
|
||||
this.longPressTriggered = false;
|
||||
}
|
||||
this.position = this.clampPosition({
|
||||
x: this.dragOrigin.x + deltaX,
|
||||
y: this.dragOrigin.y + deltaY,
|
||||
});
|
||||
},
|
||||
handleMouseDragMove(event) {
|
||||
if (this.dockDragging) {
|
||||
this.moveDockDragging(this.getMousePoint(event));
|
||||
return;
|
||||
}
|
||||
if (!this.dragging) return;
|
||||
const point = this.getMousePoint(event);
|
||||
if (!point) return;
|
||||
const deltaX = point.x - this.dragStartPoint.x;
|
||||
const deltaY = point.y - this.dragStartPoint.y;
|
||||
if (!this.dragMoved && Math.hypot(deltaX, deltaY) > 6) this.dragMoved = true;
|
||||
this.position = this.clampPosition({
|
||||
x: this.dragOrigin.x + deltaX,
|
||||
y: this.dragOrigin.y + deltaY,
|
||||
});
|
||||
},
|
||||
handleMouseDragEnd() {
|
||||
if (this.dockDragging) {
|
||||
this.handleDockDragEnd();
|
||||
return;
|
||||
}
|
||||
this.handleDragEnd();
|
||||
},
|
||||
startDockDragging(point) {
|
||||
if (!point) return;
|
||||
this.dockDragging = true;
|
||||
this.dockDragMoved = false;
|
||||
this.dockDragStartPoint = point;
|
||||
this.dockDragOriginY = this.position ? this.position.y : this.safeAreaTop + 120;
|
||||
this.dockPointerX = point.x;
|
||||
},
|
||||
handleDockDragStart(event) {
|
||||
this.startDockDragging(this.getTouchPoint(event));
|
||||
},
|
||||
handleDockMouseDragStart(event) {
|
||||
this.startDockDragging(this.getMousePoint(event));
|
||||
},
|
||||
moveDockDragging(point) {
|
||||
if (!this.dockDragging || !point) return;
|
||||
const deltaX = point.x - this.dockDragStartPoint.x;
|
||||
const deltaY = point.y - this.dockDragStartPoint.y;
|
||||
if (!this.dockDragMoved && Math.hypot(deltaX, deltaY) > 5) {
|
||||
this.dockDragMoved = true;
|
||||
}
|
||||
this.dockPointerX = point.x;
|
||||
this.collapsedEdge = point.x < this.viewportWidth / 2 ? "left" : "right";
|
||||
this.position = this.clampPosition({
|
||||
x: this.position ? this.position.x : 0,
|
||||
y: this.dockDragOriginY + deltaY,
|
||||
});
|
||||
},
|
||||
handleDockDragMove(event) {
|
||||
this.moveDockDragging(this.getTouchPoint(event));
|
||||
},
|
||||
handleDockDragEnd() {
|
||||
if (!this.dockDragging) return;
|
||||
this.dockDragging = false;
|
||||
if (!this.dockDragMoved) return;
|
||||
setQiaobaoDockEdge(this.collapsedEdge);
|
||||
saveQiaobaoPosition(this.position);
|
||||
this.dockDragJustEnded = true;
|
||||
setTimeout(() => {
|
||||
this.dockDragJustEnded = false;
|
||||
this.dockDragMoved = false;
|
||||
}, 280);
|
||||
},
|
||||
handleDragEnd() {
|
||||
if (!this.dragging) return;
|
||||
this.dragging = false;
|
||||
if (!this.dragMoved) return;
|
||||
this.position = this.clampPosition(this.position);
|
||||
saveQiaobaoPosition(this.position);
|
||||
const edgeThreshold = Math.max(22, this.viewportWidth * 0.06);
|
||||
if (this.position.x <= edgeThreshold) {
|
||||
hideQiaobaoGlobally("left");
|
||||
} else if (this.position.x + this.petWidth >= this.viewportWidth - edgeThreshold) {
|
||||
hideQiaobaoGlobally("right");
|
||||
}
|
||||
this.dragJustEnded = true;
|
||||
setTimeout(() => {
|
||||
this.dragJustEnded = false;
|
||||
this.dragMoved = false;
|
||||
}, 280);
|
||||
},
|
||||
getNearestEdge() {
|
||||
if (!this.position) return "right";
|
||||
return this.position.x + this.petWidth / 2 < this.viewportWidth / 2 ? "left" : "right";
|
||||
},
|
||||
refreshVisibility() {
|
||||
this.visible = true;
|
||||
this.collapsed = isQiaobaoHidden(this.currentPageKey);
|
||||
this.collapsedEdge = getQiaobaoDockEdge();
|
||||
if (this.collapsed) {
|
||||
this.showBubble = false;
|
||||
this.clearTimers();
|
||||
return;
|
||||
}
|
||||
this.preloadImages();
|
||||
this.startMotion();
|
||||
if (this.bubble) {
|
||||
this.showBubble = true;
|
||||
this.bubbleTimer = setTimeout(() => {
|
||||
this.showBubble = false;
|
||||
}, 5000);
|
||||
}
|
||||
},
|
||||
handleVisibilityChange({ scope, pagePath, edge } = {}) {
|
||||
if (scope === "all") this.collapseToEdge(edge);
|
||||
if (scope === "page" && pagePath === this.currentPageKey) this.collapseToEdge(edge);
|
||||
if (scope === "show" && pagePath === this.currentPageKey) this.expandFromEdge();
|
||||
if (scope === "reset") this.refreshVisibility();
|
||||
},
|
||||
preloadImages() {
|
||||
// #ifdef H5
|
||||
Object.values(ACTION_IMAGES).forEach((src) => {
|
||||
const image = new Image();
|
||||
image.src = src;
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
startMotion() {
|
||||
this.clearActionTimer();
|
||||
const nextDelay = 3200 + Math.floor(Math.random() * 2600);
|
||||
this.actionTimer = setTimeout(() => {
|
||||
const shouldScratch = Math.random() > 0.72;
|
||||
this.action = shouldScratch ? "scratch" : "blink";
|
||||
const duration = shouldScratch ? 1450 : 180;
|
||||
this.actionTimer = setTimeout(() => {
|
||||
this.action = "idle";
|
||||
this.startMotion();
|
||||
}, duration);
|
||||
}, nextDelay);
|
||||
},
|
||||
openHelp() {
|
||||
if (this.dragJustEnded) return;
|
||||
if (this.longPressTriggered) {
|
||||
this.longPressTriggered = false;
|
||||
return;
|
||||
}
|
||||
this.showBubble = false;
|
||||
this.panelVisible = true;
|
||||
this.action = "blink";
|
||||
try {
|
||||
uni.hideTabBar({ animation: false });
|
||||
} catch (e) {}
|
||||
this.$emit("open", this.currentPageKey);
|
||||
},
|
||||
closeHelp() {
|
||||
this.panelVisible = false;
|
||||
this.action = "idle";
|
||||
try {
|
||||
uni.showTabBar({ animation: false });
|
||||
} catch (e) {}
|
||||
this.$emit("close", this.currentPageKey);
|
||||
},
|
||||
openHideMenu() {
|
||||
if (this.dragging || this.dragMoved) return;
|
||||
this.longPressTriggered = true;
|
||||
const edge = this.getNearestEdge();
|
||||
uni.showActionSheet({
|
||||
title: "桥宝收起设置",
|
||||
itemList: ["当前页面收起到边缘", "所有页面收起到边缘"],
|
||||
success: ({ tapIndex }) => {
|
||||
if (tapIndex === 0) hideQiaobaoForPage(this.currentPageKey, edge);
|
||||
if (tapIndex === 1) hideQiaobaoGlobally(edge);
|
||||
this.$emit("hide", tapIndex === 1 ? "all" : "page");
|
||||
},
|
||||
complete: () => {
|
||||
setTimeout(() => {
|
||||
this.longPressTriggered = false;
|
||||
}, 350);
|
||||
},
|
||||
});
|
||||
},
|
||||
collapseToEdge(edge = getQiaobaoDockEdge()) {
|
||||
this.collapsedEdge = edge === "left" ? "left" : "right";
|
||||
this.collapsed = true;
|
||||
if (this.panelVisible) {
|
||||
try {
|
||||
uni.showTabBar({ animation: false });
|
||||
} catch (e) {}
|
||||
}
|
||||
this.panelVisible = false;
|
||||
this.showBubble = false;
|
||||
this.action = "idle";
|
||||
this.clearTimers();
|
||||
},
|
||||
expandFromEdge() {
|
||||
this.collapsed = false;
|
||||
const edgeX = this.collapsedEdge === "left"
|
||||
? 12
|
||||
: Math.max(12, this.viewportWidth - this.petWidth - 12);
|
||||
const currentY = this.position ? this.position.y : this.safeAreaTop + 120;
|
||||
this.position = this.clampPosition({ x: edgeX, y: currentY });
|
||||
saveQiaobaoPosition(this.position);
|
||||
this.action = "blink";
|
||||
this.preloadImages();
|
||||
this.startMotion();
|
||||
setTimeout(() => {
|
||||
if (!this.collapsed) this.action = "idle";
|
||||
}, 180);
|
||||
},
|
||||
restoreFromDock() {
|
||||
if (this.dockDragJustEnded) return;
|
||||
showQiaobao(this.currentPageKey);
|
||||
},
|
||||
show() {
|
||||
this.visible = true;
|
||||
showQiaobao(this.currentPageKey);
|
||||
},
|
||||
clearActionTimer() {
|
||||
if (this.actionTimer) clearTimeout(this.actionTimer);
|
||||
this.actionTimer = null;
|
||||
},
|
||||
clearTimers() {
|
||||
this.clearActionTimer();
|
||||
if (this.bubbleTimer) clearTimeout(this.bubbleTimer);
|
||||
this.bubbleTimer = null;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.qiaobao-assistant {
|
||||
position: relative;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.qiaobao-edge-tab {
|
||||
position: fixed;
|
||||
right: -18rpx;
|
||||
bottom: calc(150rpx + constant(safe-area-inset-bottom));
|
||||
bottom: calc(150rpx + env(safe-area-inset-bottom));
|
||||
width: 132rpx;
|
||||
height: 126rpx;
|
||||
z-index: 99999;
|
||||
overflow: visible;
|
||||
animation: qiaobao-edge-in-right .22s cubic-bezier(.22, 1, .36, 1) both;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
.qiaobao-edge-tab.is-left {
|
||||
left: -18rpx;
|
||||
right: auto;
|
||||
animation-name: qiaobao-edge-in-left;
|
||||
}
|
||||
|
||||
.qiaobao-edge-tab.is-dragging {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
.qiaobao-edge-head {
|
||||
width: 132rpx;
|
||||
height: 132rpx;
|
||||
display: block;
|
||||
pointer-events: none;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.qiaobao-edge-tab.is-left .qiaobao-edge-head {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.qiaobao-float {
|
||||
position: fixed;
|
||||
right: 20rpx;
|
||||
bottom: calc(132rpx + constant(safe-area-inset-bottom));
|
||||
bottom: calc(132rpx + env(safe-area-inset-bottom));
|
||||
width: 164rpx;
|
||||
height: 176rpx;
|
||||
z-index: 99999;
|
||||
transform-origin: 50% 90%;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
.qiaobao-image {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
width: 164rpx;
|
||||
height: 164rpx;
|
||||
}
|
||||
|
||||
.qiaobao-shadow {
|
||||
position: absolute;
|
||||
left: 28rpx;
|
||||
right: 22rpx;
|
||||
bottom: 3rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(41, 21, 77, .2);
|
||||
filter: blur(6rpx);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.qiaobao-bubble {
|
||||
position: absolute;
|
||||
right: 132rpx;
|
||||
top: 26rpx;
|
||||
width: 250rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
border-radius: 24rpx 24rpx 6rpx 24rpx;
|
||||
color: #fff;
|
||||
background: #302645;
|
||||
box-shadow: 0 12rpx 32rpx rgba(27, 17, 51, .18);
|
||||
font-size: 24rpx;
|
||||
line-height: 1.45;
|
||||
white-space: nowrap;
|
||||
animation: qiaobao-bubble-in .2s ease-out both;
|
||||
}
|
||||
|
||||
.is-scratching {
|
||||
animation: qiaobao-curious 1.45s ease-in-out both;
|
||||
}
|
||||
|
||||
.qiaobao-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 999999;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
background: rgba(20, 16, 29, .52);
|
||||
animation: qiaobao-mask-in .2s ease-out both;
|
||||
}
|
||||
|
||||
.qiaobao-sheet {
|
||||
width: 100%;
|
||||
max-height: 80vh;
|
||||
padding: 12rpx 32rpx 32rpx;
|
||||
padding-bottom: calc(32rpx + constant(safe-area-inset-bottom));
|
||||
padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
border-radius: 36rpx 36rpx 0 0;
|
||||
background: #fff;
|
||||
box-shadow: 0 -16rpx 48rpx rgba(29, 17, 55, .14);
|
||||
animation: qiaobao-sheet-in .24s ease-out both;
|
||||
}
|
||||
|
||||
.qiaobao-handle {
|
||||
width: 72rpx;
|
||||
height: 8rpx;
|
||||
margin: 4rpx auto 22rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #ddd8e8;
|
||||
}
|
||||
|
||||
.qiaobao-sheet-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 116rpx;
|
||||
}
|
||||
|
||||
.qiaobao-avatar-wrap {
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background: #f1eaff;
|
||||
}
|
||||
|
||||
.qiaobao-avatar {
|
||||
width: 104rpx;
|
||||
height: 104rpx;
|
||||
}
|
||||
|
||||
.qiaobao-title-wrap {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
margin-left: 22rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.qiaobao-kicker {
|
||||
color: #7b2cff;
|
||||
font-size: 22rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.qiaobao-title {
|
||||
margin-top: 8rpx;
|
||||
color: #17131f;
|
||||
font-size: 36rpx;
|
||||
line-height: 1.25;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.qiaobao-close {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
margin-left: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
color: #6c6674;
|
||||
background: #f4f2f7;
|
||||
font-size: 46rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.qiaobao-content {
|
||||
max-height: 46vh;
|
||||
margin-top: 24rpx;
|
||||
}
|
||||
|
||||
.qiaobao-summary {
|
||||
display: block;
|
||||
color: #4b4653;
|
||||
font-size: 28rpx;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.qiaobao-tips {
|
||||
margin-top: 26rpx;
|
||||
}
|
||||
|
||||
.qiaobao-tip {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 22rpx;
|
||||
}
|
||||
|
||||
.qiaobao-tip-index {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
color: #6b24e8;
|
||||
background: #eee4ff;
|
||||
font-size: 22rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.qiaobao-tip-text {
|
||||
flex: 1;
|
||||
margin-left: 18rpx;
|
||||
color: #302b38;
|
||||
font-size: 27rpx;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.qiaobao-confirm {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
margin: 28rpx 0 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 24rpx;
|
||||
color: #fff;
|
||||
background: #7433f1;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
line-height: 88rpx;
|
||||
}
|
||||
|
||||
.qiaobao-confirm::after {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.qiaobao-hide-hint {
|
||||
display: block;
|
||||
margin-top: 18rpx;
|
||||
color: #9a94a3;
|
||||
text-align: center;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
@keyframes qiaobao-bubble-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(8rpx) scale(.96);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes qiaobao-mask-in {
|
||||
from {
|
||||
background: rgba(20, 16, 29, 0);
|
||||
}
|
||||
|
||||
to {
|
||||
background: rgba(20, 16, 29, .52);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes qiaobao-sheet-in {
|
||||
from {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes qiaobao-curious {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: rotate(0);
|
||||
}
|
||||
|
||||
32% {
|
||||
transform: rotate(2deg);
|
||||
}
|
||||
|
||||
68% {
|
||||
transform: rotate(-1deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes qiaobao-edge-in-right {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(54rpx);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes qiaobao-edge-in-left {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-54rpx);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
|
||||
.qiaobao-bubble,
|
||||
.qiaobao-mask,
|
||||
.qiaobao-sheet,
|
||||
.qiaobao-edge-tab,
|
||||
.is-scratching {
|
||||
animation: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,7 @@
|
||||
import App from './App'
|
||||
import messages from './locale/index'
|
||||
import uviewPlus from '@/uni_modules/uview-plus'
|
||||
import QiaobaoAssistant from '@/components/qiaobao-assistant/qiaobao-assistant.vue'
|
||||
// #ifndef MP-WEIXIN
|
||||
import VueClipboard from 'vue-clipboard2'
|
||||
// #endif
|
||||
@@ -22,6 +23,7 @@ Vue.use(VueClipboard);
|
||||
|
||||
Vue.use(uviewPlus)
|
||||
Vue.use(VueI18n)
|
||||
Vue.component('qiaobao-assistant', QiaobaoAssistant)
|
||||
const i18n = new VueI18n(i18nConfig)
|
||||
Vue.config.productionTip = false
|
||||
App.mpType = 'app'
|
||||
@@ -38,6 +40,7 @@ import { createI18n } from 'vue-i18n'
|
||||
const i18n = createI18n(i18nConfig)
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
app.component('qiaobao-assistant', QiaobaoAssistant)
|
||||
// #ifdef H5
|
||||
app.component('AsyncError', {
|
||||
props: ['error'],
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<template #indicator>
|
||||
<view class="indicator-num">
|
||||
<text class="indicator-num__text">{{ currentNum + 1 }}/{{ swiperList.length }}</text>
|
||||
<qiaobao-assistant page-key="pages/active/limited-time/limited-time" title="限时秒杀" />
|
||||
</view>
|
||||
</template>
|
||||
</up-swiper>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<template #indicator>
|
||||
<view class="indicator-num">
|
||||
<text class="indicator-num__text">{{ currentNum + 1 }}/{{ swiperList.length }}</text>
|
||||
<qiaobao-assistant page-key="pages/active/newcomer-exclusive/newcomer-exclusive" title="新人专享" />
|
||||
</view>
|
||||
</template>
|
||||
</up-swiper>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<template #indicator>
|
||||
<view class="indicator-num">
|
||||
<text class="indicator-num__text">{{ currentNum + 1 }}/{{ swiperList.length }}</text>
|
||||
<qiaobao-assistant page-key="pages/active/super-subsidy/super-subsidy" title="超级补贴" />
|
||||
</view>
|
||||
</template>
|
||||
</up-swiper>
|
||||
|
||||
@@ -210,6 +210,7 @@
|
||||
</view>
|
||||
</up-overlay>
|
||||
<HomePopup :show="homeShow" :dataObj="curData" @jumpShop="onJumpShop"></HomePopup>
|
||||
<qiaobao-assistant page-key="pages/home/home" title="商城首页" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
<view>最终解释权归商城所有!!!</view>
|
||||
</view>
|
||||
</view>
|
||||
<qiaobao-assistant page-key="pages/login_package/accelerate/accelerate" title="我的推广" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
</view>
|
||||
</view>
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<qiaobao-assistant page-key="pages/login_package/announcement/announcement" title="商城公告" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
</view>
|
||||
<view v-else @click="getMobileCode" class="code_msg">
|
||||
获取验证码
|
||||
<qiaobao-assistant page-key="pages/login_package/bind-phone/bind-phone" title="账户登录" />
|
||||
</view>
|
||||
</template>
|
||||
</up-input>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<view class="login_info_item">
|
||||
<up-input placeholder="请输入手机号/账户名称" border="surround" v-model="form.name" :customStyle="inputCss"
|
||||
:adjust-position="false" @change="checkNameParam"></up-input>
|
||||
<qiaobao-assistant page-key="pages/login_package/login/login" title="账户登录" />
|
||||
</view>
|
||||
<!-- 密码登录 -->
|
||||
<view class="login_info_item" v-if="loginWay === 'password'">
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<template #indicator>
|
||||
<view class="indicator-num">
|
||||
<text class="indicator-num__text">{{ currentNum + 1 }}/{{ swiperList.length }}</text>
|
||||
<qiaobao-assistant page-key="pages/login_package/news/news" title="商城公告" />
|
||||
</view>
|
||||
</template>
|
||||
</up-swiper>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
</view>
|
||||
<view v-else @click="getMobileCode" class="code_msg">
|
||||
获取验证码
|
||||
<qiaobao-assistant page-key="pages/login_package/register/register" title="账户登录" />
|
||||
</view>
|
||||
</template>
|
||||
</up-input>
|
||||
|
||||
@@ -224,6 +224,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</up-modal>
|
||||
<qiaobao-assistant page-key="pages/mine/mine" title="个人中心" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
@message="handlePostMessage"
|
||||
@onPostMessage="handlePostMessage"
|
||||
></web-view
|
||||
></view>
|
||||
> <qiaobao-assistant page-key="pages/mine_package/mild-shopping/mild-shopping" title="平价专区" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
<image src="/pages/other_package/static/not_search.png" class="empty_img" mode="aspectFit" />
|
||||
<text class="empty_text">暂无地址,快去添加吧~</text>
|
||||
</view>
|
||||
<qiaobao-assistant page-key="pages/mine_package/mine_address/mine_address" title="收货地址" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
></up-picker> -->
|
||||
<AddressPopup @ok="onOk"
|
||||
:show="regionShow" @itemSelect="onItemSelect" @select="onSelect" :curSelect="curSelect" :selectList="curSelectList" :dataList="addressList" @close="onClose"></AddressPopup>
|
||||
<qiaobao-assistant page-key="pages/mine_package/mine_address_add/mine_address_add" title="编辑收货地址" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
<up-picker :show="certShow" :columns="[CERT_OPTION]" keyName="value" itemHeight="34" @confirm="certConfirm"
|
||||
@cancel="certShow = false" @close="certShow = false"></up-picker>
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<qiaobao-assistant page-key="pages/mine_package/mine_authentication/mine_authentication" title="实名认证" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<qiaobao-assistant page-key="pages/mine_package/mine_coupon/mine_coupon" title="优惠券" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -188,6 +188,7 @@
|
||||
<up-input placeholder="输入邀请码" border="surround" v-model="bindValue"></up-input>
|
||||
</up-modal>
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<qiaobao-assistant page-key="pages/mine_package/mine_my_team/mine_my_team" title="我的推广" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -296,6 +296,7 @@
|
||||
|
||||
<u-modal class="sure_pay" :show="surePayShow" title="提示" showCancelButton @cancel="surePayShow = false"
|
||||
@confirm="cancelPay" confirmColor="#7934F6" content="确定取消支付吗?"></u-modal>
|
||||
<qiaobao-assistant page-key="pages/mine_package/mine_order/mine_order" title="我的订单" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -224,6 +224,7 @@
|
||||
</up-popup>
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<QrcodePreview ref="qrcodePreviewRef" :qrcodeVal="qrcodeVal" />
|
||||
<qiaobao-assistant page-key="pages/mine_package/mine_order_info/mine_order_info" title="订单详情" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -161,6 +161,7 @@
|
||||
开发者:信任桥(深圳)网络科技有限公司<br />
|
||||
</view>
|
||||
|
||||
<qiaobao-assistant page-key="pages/mine_package/mine_privacy_agreement/mine_privacy_agreement" title="协议与规则" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
|
||||
本协议最终解释权归 (信任桥) 所有。<br />
|
||||
</view>
|
||||
<qiaobao-assistant page-key="pages/mine_package/mine_product_agreement/mine_product_agreement" title="协议与规则" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</up-popup>
|
||||
<qiaobao-assistant page-key="pages/mine_package/mine_purse/mine_purse" title="钱包与账户" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
注销账号
|
||||
</view> -->
|
||||
</view>
|
||||
<qiaobao-assistant page-key="pages/mine_package/mine_settings/mine_settings" title="账户设置" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
10.4.本协议条款无论因何种原因部分无效或不可执行,其余条款仍有效,对双方具有约束力。<br />
|
||||
开发者:信任桥<br />
|
||||
</view>
|
||||
<qiaobao-assistant page-key="pages/mine_package/mine_user_agreement/mine_user_agreement" title="协议与规则" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<view class="mine_winning_record">
|
||||
<winningRecord />
|
||||
<qiaobao-assistant page-key="pages/mine_package/mine_winning_record/mine_winning_record" title="抽奖活动" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
</view>
|
||||
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<qiaobao-assistant page-key="pages/order_package/evaluate/evaluate" title="订单评价" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -294,6 +294,7 @@
|
||||
<!-- 优惠券选择弹框 -->
|
||||
<CouponDialog :show="couponShow" v-if="couponShow" @close="couponShow = false" @select="handleCouponSelect">
|
||||
</CouponDialog>
|
||||
<qiaobao-assistant page-key="pages/order_package/order_submit/order_submit" title="确认订单" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
</view>
|
||||
<view class="ok_but" @click="jumpHome">确认</view>
|
||||
</view>
|
||||
<qiaobao-assistant page-key="pages/order_package/order_submit_error/order_submit_error" title="订单状态与支付" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
</view>
|
||||
<view class="ok_but" @click="jumpHome">确认</view>
|
||||
</view>
|
||||
<qiaobao-assistant page-key="pages/order_package/order_submit_ok/order_submit_ok" title="订单状态与支付" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<view>
|
||||
<web-view :src="paymentLink"></web-view>
|
||||
<qiaobao-assistant page-key="pages/other_package/alipay_payment/alipay_payment" title="订单状态与支付" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
</view>
|
||||
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<qiaobao-assistant page-key="pages/other_package/coupon/coupon" title="优惠券" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</up-popup>
|
||||
<qiaobao-assistant page-key="pages/other_package/get_prize/get_prize" title="抽奖活动" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
</button>
|
||||
</view>
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<qiaobao-assistant page-key="pages/other_package/invite_friends/invite_friends" title="我的推广" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
<!-- 中奖结果弹窗 -->
|
||||
<ResultModal :visible="showResult" :prize="currentPrize" @close="showResult = false" />
|
||||
|
||||
<qiaobao-assistant page-key="pages/other_package/nine-grid/nine-grid" title="抽奖活动" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<qiaobao-assistant page-key="pages/other_package/pointsRedemption/pointsRedemption" title="平价专区" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -123,6 +123,7 @@
|
||||
</view>
|
||||
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<qiaobao-assistant page-key="pages/other_package/productInfo/evaluateDetail" title="评价详情" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<template #indicator>
|
||||
<view class="indicator-num">
|
||||
<text class="indicator-num__text">{{ currentNum + 1 }}/{{ swiperList.length }}</text>
|
||||
<qiaobao-assistant page-key="pages/other_package/productInfo/productInfo" title="商品详情" />
|
||||
</view>
|
||||
</template>
|
||||
</up-swiper>
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<qiaobao-assistant page-key="pages/other_package/search/search" title="商品搜索" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<up-image src="/static/common/left_b.png" width="22" height="22" bgColor="#f1f6ff00"></up-image>
|
||||
</view>
|
||||
<view class="title_">{{ prizesObj.title || '幸运转盘百亿补贴' }}</view>
|
||||
<qiaobao-assistant page-key="pages/other_package/turntable/turntable" title="抽奖活动" />
|
||||
</view>
|
||||
<view class="turntable_content_warp">
|
||||
<view class="frequency_warp">
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
</view>
|
||||
</view>
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<qiaobao-assistant page-key="pages/rwa_package/accountSafe/accountSafe" title="账户设置" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
</view>
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<!-- 腾讯电子签H5 → 集成到UniApp -->
|
||||
<qiaobao-assistant page-key="pages/rwa_package/express/express" title="物流详情" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
</view>
|
||||
<view v-else @click="getMobileCode" class="code_msg">
|
||||
获取验证码
|
||||
<qiaobao-assistant page-key="pages/rwa_package/forgotPass/forgotPass" title="账户登录" />
|
||||
</view>
|
||||
</template>
|
||||
</up-input>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<!-- 腾讯电子签H5 → 集成到UniApp -->
|
||||
<web-view v-if="signUrl" :src="signUrl" @message="handleMessage"></web-view>
|
||||
<qiaobao-assistant page-key="pages/rwa_package/insights/index" title="经营洞察" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<view class="customer-service-body">
|
||||
<hashmall-customer-service v-if="optionsReady" ref="customerService" :entry-options="entryOptions" />
|
||||
</view>
|
||||
<qiaobao-assistant page-key="pages/rwa_package/kefu/kefu" title="智能客服" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
提交
|
||||
</view>
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<qiaobao-assistant page-key="pages/rwa_package/merchant_settlement/merchant_settlement" title="商家入驻" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
</view>
|
||||
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<qiaobao-assistant page-key="pages/rwa_package/outAgreement/outAgreement" title="协议与规则" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
<qiaobao-assistant page-key="pages/rwa_package/rwa/rwa" title="账户服务" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<MyBtn text="保存" @ok="onSetName"></MyBtn>
|
||||
</view>
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<qiaobao-assistant page-key="pages/rwa_package/setName/setName" title="账户设置" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
<MyBtn class="mt-48" @ok="onOutLogin" text="退出登录"></MyBtn>
|
||||
</view>
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<qiaobao-assistant page-key="pages/rwa_package/setting/setting" title="账户设置" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
<!-- #ifndef H5 || MP-WEIXIN-->
|
||||
<CustomTabBar :tabIndex="3" />
|
||||
<!-- #endif -->
|
||||
<qiaobao-assistant page-key="pages/shopping_cart/shopping_cart" title="购物车" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -157,6 +157,7 @@
|
||||
<!-- #ifndef H5 || MP-WEIXIN-->
|
||||
<CustomTabBar :tabIndex="1" />
|
||||
<!-- #endif -->
|
||||
<qiaobao-assistant page-key="pages/sort/sort" title="商品分类" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
<CustomTabBar :tabIndex="2" />
|
||||
<!-- #endif -->
|
||||
<up-toast ref="uToastRef"></up-toast>
|
||||
<qiaobao-assistant page-key="pages/supply_chain/supply_chain" title="平价专区" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
const DEFAULT_HELP = {
|
||||
title: "当前页面",
|
||||
summary: "桥宝会介绍当前页面的主要功能,并提醒你常用的操作方式。",
|
||||
tips: [
|
||||
"先查看页面顶部的标题和筛选条件,再进行下一步操作。",
|
||||
"遇到订单、商品或账户问题时,可以进入智能客服咨询。",
|
||||
],
|
||||
};
|
||||
|
||||
const HELP_RULES = [
|
||||
{ match: /order_submit/, title: "确认订单", summary: "在这里核对收货地址、商品清单、优惠券抵扣及最终结算金额。", tips: ["请仔细核对收货地址和联系电话。", "选择合适的支付方式与优惠券后再提交。"] },
|
||||
{ match: /mine_address_add/, title: "编辑收货地址", summary: "填写收货人、手机号、所在地区和详细地址。", tips: ["请确认手机号和地区准确。", "保存前补充门牌号等详细信息。"] },
|
||||
{ match: /mine_address/, title: "收货地址", summary: "管理下单时使用的收货地址。", tips: ["可以新增、编辑或删除地址。", "常用地址可设为默认地址。"] },
|
||||
{ match: /evaluateDetail/, title: "评价详情", summary: "查看商品买家评价、晒图及买家真实使用反馈。", tips: ["可以查看其他买家的图片和文字评价。", "了解商品真实使用体验。"] },
|
||||
{ match: /order_package\/evaluate/, title: "订单评价", summary: "对已完成的订单商品和服务进行打分评价和心得分享。", tips: ["评分并填写使用体验。", "上传实物照片可帮助其他买家。"] },
|
||||
{ match: /mine_order_info/, title: "订单详情", summary: "查看订单商品、金额、收货信息和当前处理进度。", tips: ["根据订单状态进行付款、确认收货或申请售后。", "物流信息可在订单发货后查看。"] },
|
||||
{ match: /mine_order/, title: "我的订单", summary: "查看不同状态的商城订单及其处理进度。", tips: ["使用状态标签快速筛选订单。", "点击订单可查看商品、金额和物流详情。"] },
|
||||
{ match: /express/, title: "物流详情", summary: "查看订单包裹的实时物流动态与快递派送进度。", tips: ["可实时刷新快递轨迹。", "如遇到派送问题可联系快递员或客服。"] },
|
||||
{ match: /productInfo\/productInfo/, title: "商品详情", summary: "查看商品图片、规格、价格、库存和购买说明。", tips: ["购买前选择正确的商品规格和数量。", "详情页可联系智能客服咨询商品问题。"] },
|
||||
{ match: /other_package\/search/, title: "商品搜索", summary: "通过商品名称、关键词、简介和分类查找商品。", tips: ["输入更具体的关键词可缩小范围。", "搜索结果支持按销量和价格排序。"] },
|
||||
{ match: /insights/, title: "经营洞察", summary: "查看经营数据、收益概况、运营分析及数据检索。", tips: ["通过数据图表了解经营趋势。", "点击各子模块可查看细分数据。"] },
|
||||
{ match: /pages\/home\/home/, title: "商城首页", summary: "这里汇集商城活动、精选商品和常用购物入口。", tips: ["使用顶部搜索查找商品。", "活动入口可进入补贴、秒杀和新人专区。"] },
|
||||
{ match: /pages\/sort\/sort/, title: "商品分类", summary: "按商城分类浏览商品,左侧切换大类,右侧选择具体分类。", tips: ["点击分类名称查看对应商品。", "也可以使用顶部搜索直接查找。"] },
|
||||
{ match: /shopping_cart/, title: "购物车", summary: "在这里确认准备购买的商品、规格、数量和结算金额。", tips: ["勾选需要结算的商品。", "结算前请再次确认商品规格与数量。"] },
|
||||
{ match: /supply_chain|pointsRedemption|mild-shopping/, title: "平价专区", summary: "这里展示可使用数字积分或专区规则兑换的商品。", tips: ["进入商品详情查看兑换条件。", "实际可用积分和兑换比例以页面显示为准。"] },
|
||||
{ match: /pages\/mine\/mine/, title: "个人中心", summary: "这里可以管理订单、账户、地址、优惠券和个人资料。", tips: ["订单状态入口可快速查看对应订单。", "常用服务集中在页面下方。"] },
|
||||
{ match: /mine_coupon|other_package\/coupon/, title: "优惠券", summary: "查看待使用、已使用、已过期和已失效的优惠券。", tips: ["待使用优惠券可进入适用商品列表。", "下单时系统会按规则展示可用优惠券。"] },
|
||||
{ match: /mine_purse|recharge|withdraw|balance|wallet|mine_bank/, title: "钱包与账户", summary: "查看账户余额、明细以及相关资金操作。", tips: ["提交操作前核对金额和账户信息。", "资金记录可在明细页面查询。"] },
|
||||
{ match: /mine_authentication/, title: "实名认证", summary: "按照页面提示提交真实身份信息。", tips: ["请确保姓名和证件信息一致。", "认证结果以系统审核为准。"] },
|
||||
{ match: /mine_my_team|invite_friends|accelerate/, title: "我的推广", summary: "查看推广关系、团队信息和邀请入口。", tips: ["分享前确认自己的推荐信息。", "推荐关系及奖励按商城规则计算。"] },
|
||||
{ match: /merchant_settlement/, title: "商家入驻", summary: "提交商家资质及店铺信息,申请入驻商城。", tips: ["按照提示填写真实的营业执照与店铺信息。", "提交后等待系统审核通过。"] },
|
||||
{ match: /kefu/, title: "智能客服", summary: "在这里咨询商品、订单、物流和售后问题。", tips: ["尽量完整描述问题,客服能更快定位。", "需要人工帮助时可发送“人工客服”。"] },
|
||||
{ match: /limited-time/, title: "限时秒杀", summary: "查看当前和即将开始的限时秒杀商品。", tips: ["留意活动开始和结束时间。", "活动库存和价格以页面实时展示为准。"] },
|
||||
{ match: /super-subsidy/, title: "超级补贴", summary: "查看参与超级补贴的商品及贡献值奖励。", tips: ["不同商品的补贴比例可能不同。", "进入详情页确认价格、规格和奖励规则。"] },
|
||||
{ match: /newcomer-exclusive/, title: "新人专享", summary: "这里展示符合新人活动条件的商品。", tips: ["活动资格以账户状态为准。", "下单前确认活动价格和限购数量。"] },
|
||||
{ match: /turntable|nine-grid|get_prize|mine_winning_record/, title: "抽奖活动", summary: "使用可用抽奖次数参与商城活动并查看结果。", tips: ["抽奖次数和奖品以页面实时显示为准。", "中奖后按提示填写或确认领取信息。"] },
|
||||
{ match: /login|register|bind-phone|forgotPass/, title: "账户登录", summary: "登录、注册或找回商城账户。", tips: ["请妥善保管验证码和登录密码。", "无法登录时可检查手机号或重新获取验证码。"] },
|
||||
{ match: /news|announcement/, title: "商城公告", summary: "查看商城通知、活动说明和规则更新。", tips: ["重要规则请以公告正文为准。", "阅读后可返回继续浏览商城。"] },
|
||||
{ match: /agreement|Agreement|privacy/, title: "协议与规则", summary: "查看商城相关协议、隐私政策和业务规则。", tips: ["请完整阅读与当前操作相关的条款。", "继续操作表示按页面提示确认相关协议。"] },
|
||||
{ match: /mine_settings|setting|accountSafe|setName/, title: "账户设置", summary: "管理个人信息、交易密码、账号安全与偏好设置。", tips: ["可修改账户昵称和安全选项。", "涉及重要信息变更请仔细核对。"] },
|
||||
{ match: /alipay_payment|order_submit_ok|order_submit_error/, title: "订单状态与支付", summary: "完成订单支付或查看订单支付状态。", tips: ["确认支付金额无误后进行支付。", "支付成功后可在我的订单中查看进度。"] },
|
||||
{ match: /rwa/, title: "账户服务", summary: "这里提供账户资料、绑定、查询和相关业务操作。", tips: ["提交前确认填写的信息准确。", "涉及账户变更时请留意页面提示。"] },
|
||||
];
|
||||
|
||||
export function resolveQiaobaoPageHelp(pagePath = "") {
|
||||
const normalizedPath = String(pagePath).replace(/^\//, "");
|
||||
const rule = HELP_RULES.find((item) => item.match.test(normalizedPath));
|
||||
if (!rule) return { ...DEFAULT_HELP, tips: [...DEFAULT_HELP.tips] };
|
||||
return { title: rule.title, summary: rule.summary, tips: [...rule.tips] };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
const GLOBAL_HIDDEN_KEY = "tb_qiaobao_hidden_all";
|
||||
const PAGE_HIDDEN_KEY = "tb_qiaobao_hidden_pages";
|
||||
const DOCK_EDGE_KEY = "tb_qiaobao_dock_edge";
|
||||
const POSITION_KEY = "tb_qiaobao_position";
|
||||
|
||||
export function getQiaobaoDockEdge() {
|
||||
return uni.getStorageSync(DOCK_EDGE_KEY) === "left" ? "left" : "right";
|
||||
}
|
||||
|
||||
export function setQiaobaoDockEdge(edge) {
|
||||
uni.setStorageSync(DOCK_EDGE_KEY, edge === "left" ? "left" : "right");
|
||||
}
|
||||
|
||||
export function getQiaobaoPosition() {
|
||||
const position = uni.getStorageSync(POSITION_KEY);
|
||||
if (!position || typeof position !== "object") return null;
|
||||
const x = Number(position.x);
|
||||
const y = Number(position.y);
|
||||
return Number.isFinite(x) && Number.isFinite(y) ? { x, y } : null;
|
||||
}
|
||||
|
||||
export function saveQiaobaoPosition(position) {
|
||||
if (!position) return;
|
||||
const x = Number(position.x);
|
||||
const y = Number(position.y);
|
||||
if (Number.isFinite(x) && Number.isFinite(y)) {
|
||||
uni.setStorageSync(POSITION_KEY, { x, y });
|
||||
}
|
||||
}
|
||||
|
||||
export function getCurrentPagePath() {
|
||||
try {
|
||||
const pages = getCurrentPages();
|
||||
const current = pages[pages.length - 1];
|
||||
return current?.route || current?.$page?.fullPath?.split("?")[0] || "unknown";
|
||||
} catch (error) {
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
export function isQiaobaoHidden(pagePath = getCurrentPagePath()) {
|
||||
const hiddenAll = uni.getStorageSync(GLOBAL_HIDDEN_KEY);
|
||||
const hiddenPages = uni.getStorageSync(PAGE_HIDDEN_KEY);
|
||||
return hiddenAll === true || (Array.isArray(hiddenPages) && hiddenPages.includes(pagePath));
|
||||
}
|
||||
|
||||
export function hideQiaobaoForPage(pagePath = getCurrentPagePath(), edge = "right") {
|
||||
const hiddenPages = uni.getStorageSync(PAGE_HIDDEN_KEY);
|
||||
const nextPages = Array.isArray(hiddenPages) ? [...hiddenPages] : [];
|
||||
if (!nextPages.includes(pagePath)) nextPages.push(pagePath);
|
||||
uni.setStorageSync(PAGE_HIDDEN_KEY, nextPages);
|
||||
setQiaobaoDockEdge(edge);
|
||||
uni.$emit("qiaobao-visibility-change", { scope: "page", pagePath, edge });
|
||||
}
|
||||
|
||||
export function hideQiaobaoGlobally(edge = "right") {
|
||||
uni.setStorageSync(GLOBAL_HIDDEN_KEY, true);
|
||||
setQiaobaoDockEdge(edge);
|
||||
uni.$emit("qiaobao-visibility-change", { scope: "all", edge });
|
||||
}
|
||||
|
||||
export function showQiaobao(pagePath = getCurrentPagePath()) {
|
||||
uni.removeStorageSync(GLOBAL_HIDDEN_KEY);
|
||||
const hiddenPages = uni.getStorageSync(PAGE_HIDDEN_KEY);
|
||||
if (Array.isArray(hiddenPages)) {
|
||||
uni.setStorageSync(
|
||||
PAGE_HIDDEN_KEY,
|
||||
hiddenPages.filter((item) => item !== pagePath),
|
||||
);
|
||||
}
|
||||
uni.$emit("qiaobao-visibility-change", { scope: "show", pagePath });
|
||||
}
|
||||
|
||||
export function resetQiaobaoVisibility() {
|
||||
uni.removeStorageSync(GLOBAL_HIDDEN_KEY);
|
||||
uni.removeStorageSync(PAGE_HIDDEN_KEY);
|
||||
uni.$emit("qiaobao-visibility-change", { scope: "reset" });
|
||||
}
|
||||
Reference in New Issue
Block a user