restore: 恢复橙色逍遥梦UI版本(2ea2860)到主分支

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-09 00:17:03 +08:00
parent 267de7c780
commit 566aeaa3b7
228 changed files with 22076 additions and 11864 deletions

View File

@@ -1,73 +1,119 @@
// components/chenghao-tag/chenghao-tag.js
const app = getApp();
const PILL_SHAPES = ['pill', 'rectangle', 'rounded'];
Component({
properties: {
mingcheng: { type: String, value: '' },
texiaoJson: { type: Object, value: {} }
texiaoJson: { type: null, value: null },
},
data: {
// 默认值宽152高52六边形无背景图无动画白色字
width: 152,
height: 52,
shapeClass: 'liubianxing', // 保证至少不是矩形
inlineStyle: '',
shapeClass: 'tag-pill',
animationClass: '',
bgStyle: '',
textColor: '#FFFFFF',
textSize: 22,
imageUrl: ''
imageUrl: '',
isPill: true,
},
observers: {
'texiaoJson, mingcheng': function () {
this._applyConfig(this.properties.texiaoJson);
},
},
lifetimes: {
attached() {
const cfg = this.properties.texiaoJson || {};
// 1. 尺寸稍大一些一行能放3~4个
const width = cfg.width || 152;
const height = cfg.height || 52;
this._applyConfig(this.properties.texiaoJson);
},
},
methods: {
_applyConfig(raw) {
let cfg = raw || {};
if (typeof cfg === 'string') {
try {
cfg = JSON.parse(cfg);
} catch (e) {
cfg = {};
}
}
if (Array.isArray(cfg)) {
cfg = cfg[0] || {};
}
if (!cfg || typeof cfg !== 'object') {
cfg = {};
}
const ossImageUrl = app.globalData.ossImageUrl || '';
// 2. 背景处理:优先背景图,否则用渐变/纯色
// 无 shape身份装饰标签 / 自定义色圆角标;有 shape考核称号等特殊形状
const isPill = !cfg.shape || PILL_SHAPES.includes(cfg.shape);
if (isPill) {
const height = Number(cfg.height) || 44;
const minWidth = Number(cfg.width) || 72;
const solidColor = cfg.bg_color || cfg.background || cfg.color;
let bgStyle = '';
if (cfg.bg_gradient) {
bgStyle = `background: ${cfg.bg_gradient};`;
} else if (solidColor) {
bgStyle = `background: ${solidColor};`;
} else {
bgStyle = 'background: linear-gradient(135deg, #FFD700, #FF8C00);';
}
const flash = cfg.flash || cfg.animation === 'shine' || cfg.animation === 'glow';
let animationClass = cfg.animation || '';
if (flash && !animationClass) {
animationClass = 'pill-flash';
}
const borderColor = cfg.borderColor || cfg.border_color;
const borderStyle = borderColor ? `border: 2rpx solid ${borderColor};` : '';
const textColor = cfg.text_color || cfg.textColor || '#FFFFFF';
this.setData({
isPill: true,
shapeClass: 'tag-pill',
animationClass,
inlineStyle: `min-width: ${minWidth}rpx; height: ${height}rpx; padding: 0 18rpx; ${bgStyle} ${borderStyle}`,
textColor,
textSize: cfg.text_size || 22,
imageUrl: '',
});
return;
}
const width = Number(cfg.width) || 152;
const height = Number(cfg.height) || 52;
let bgStyle = '';
let imageUrl = '';
if (cfg.image_url) {
const ossImageUrl = app.globalData.ossImageUrl || '';
imageUrl = cfg.image_url.startsWith('http')
? cfg.image_url
imageUrl = cfg.image_url.startsWith('http')
? cfg.image_url
: ossImageUrl + cfg.image_url;
} else if (cfg.bg_gradient) {
bgStyle = `background: ${cfg.bg_gradient};`;
} else if (cfg.bg_color) {
bgStyle = `background: ${cfg.bg_color};`;
} else {
// 默认紫色渐变
bgStyle = `background: linear-gradient(135deg, #c4b5fd, #9333ea);`;
bgStyle = 'background: linear-gradient(135deg, #FFD700, #FF8C00);';
}
// 3. 形状(后端传入 shape 字段,默认 liubianxing
const shapeClass = cfg.shape || 'liubianxing';
// 4. 动画
const animationClass = cfg.animation || '';
// 5. 文字
const textColor = cfg.text_color || '#FFFFFF';
const textSize = cfg.text_size || 22;
this.setData({
width, height,
bgStyle, imageUrl,
shapeClass, animationClass,
textColor, textSize
isPill: false,
inlineStyle: `width: ${width}rpx; height: ${height}rpx; ${bgStyle}`,
shapeClass: cfg.shape || 'liubianxing',
animationClass: cfg.animation || '',
textColor: cfg.text_color || '#FFFFFF',
textSize: cfg.text_size || 22,
imageUrl,
});
}
},
methods: {
// 背景图加载失败时回退为纯色背景
},
onImageError() {
this.setData({ imageUrl: '' });
// 如果 bgStyle 为空,给个默认背景
if (!this.data.bgStyle) {
this.setData({ bgStyle: 'background: linear-gradient(135deg, #c4b5fd, #9333ea);' });
if (!this.data.inlineStyle.includes('background')) {
this.setData({
inlineStyle: this.data.inlineStyle + ' background: linear-gradient(135deg, #FFD700, #FF8C00);',
});
}
}
}
});
},
},
});

View File

@@ -1,20 +1,17 @@
<!-- components/chenghao-tag/chenghao-tag.wxml -->
<view
class="tag-root {{shapeClass}} {{animationClass}}"
style="width: {{width}}rpx; height: {{height}}rpx; {{bgStyle}}"
<view
class="tag-root {{shapeClass}} {{animationClass}}"
style="{{inlineStyle}}"
>
<!-- 背景图(如果有) -->
<image
wx:if="{{imageUrl}}"
class="tag-bg-image"
src="{{imageUrl}}"
<image
wx:if="{{imageUrl && !isPill}}"
class="tag-bg-image"
src="{{imageUrl}}"
mode="aspectFill"
binderror="onImageError"
></image>
<!-- 文字层 -->
<text
class="tag-text"
/>
<text
class="tag-text"
style="color: {{textColor}}; font-size: {{textSize}}rpx;"
>{{mingcheng}}</text>
</view>
</view>

View File

@@ -12,6 +12,18 @@
margin: 4rpx;
box-sizing: border-box;
}
/* 身份装饰 / 自定义色:圆角标 */
.tag-root.tag-pill {
border-radius: 20rpx;
clip-path: none;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.12);
}
.tag-pill .tag-text {
padding: 0;
text-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.25);
}
/* ========== 背景图 ========== */
.tag-bg-image {
@@ -85,6 +97,21 @@
animation: glow-anim 2s ease-in-out infinite;
}
@keyframes glow-anim {
0%, 100% { box-shadow: 0 0 8rpx rgba(196, 181, 253, 0.4); }
50% { box-shadow: 0 0 20rpx rgba(196, 181, 253, 0.8), 0 0 40rpx rgba(196, 181, 253, 0.4); }
0%, 100% { box-shadow: 0 0 8rpx rgba(255, 215, 0, 0.4); }
50% { box-shadow: 0 0 20rpx rgba(255, 215, 0, 0.8), 0 0 40rpx rgba(255, 215, 0, 0.4); }
}
/* 身份标签闪光 */
.tag-root.pill-flash::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 60%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.55), transparent);
transform: skewX(-20deg);
animation: shine-anim 2.2s infinite;
z-index: 1;
pointer-events: none;
}

View File

@@ -1,4 +1,4 @@
const { resolveAvatarUrl } = require('../../utils/avatar.js');
const { resolveAvatarUrl, getDefaultAvatarUrl } = require('../../utils/avatar.js');
Component({
properties: {
@@ -53,7 +53,8 @@ Component({
// 静音状态
isMuted: false,
formattedTime: '',
// 自动隐藏计时器
autoHideTimeout: null
},
@@ -123,7 +124,7 @@ Component({
let avatar = resolveAvatarUrl(
data.avatar || data.message?.senderData?.avatar,
app
);
) || getDefaultAvatarUrl(app);
this.setData({
show: true,
@@ -131,6 +132,7 @@ Component({
message: data.content || '[消息内容]',
avatar: avatar,
notificationData: data,
formattedTime: this.formatTime(data.timestamp),
progress: 100,
swipingClass: '',
swipeStyle: ''
@@ -149,6 +151,7 @@ Component({
this.clearTimers();
this.setData({
show: false,
formattedTime: '',
progress: 100,
swipingClass: '',
swipeStyle: ''
@@ -265,6 +268,13 @@ Component({
this.triggerEvent('close');
this.hideNotification();
},
onAvatarError() {
const def = getDefaultAvatarUrl(getApp());
if (def && this.data.avatar !== def) {
this.setData({ avatar: def });
}
},
onMute(e) {
e.stopPropagation();

View File

@@ -15,14 +15,15 @@
<!-- 通知内容 -->
<view class="notification-content">
<!-- 左侧头像 -->
<image class="notification-avatar" src="{{avatar}}" mode="aspectFill"></image>
<image class="notification-avatar" src="{{avatar}}" mode="aspectFill" binderror="onAvatarError"></image>
<!-- 中间内容区域 -->
<view class="notification-body">
<view class="notification-tag">新消息</view>
<view class="notification-title">{{title}}</view>
<view class="notification-message">{{message}}</view>
<view class="notification-time" wx:if="{{showTime}}">
{{formatTime(notificationData ? notificationData.timestamp : '')}}
<view class="notification-time" wx:if="{{show && showTime && formattedTime}}">
{{formattedTime}}
</view>
</view>

View File

@@ -1,29 +1,40 @@
.global-notification {
position: fixed;
left: 20rpx;
right: 20rpx;
top: 0rpx;
left: 24rpx;
right: 24rpx;
top: calc(env(safe-area-inset-top) + 108rpx);
z-index: 99999;
opacity: 0;
transform: translateY(-120%);
transition: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
transform: translateY(-160%);
transition: all 0.42s cubic-bezier(0.34, 1.2, 0.64, 1);
pointer-events: none;
overflow: hidden;
border-radius: 24rpx;
background: linear-gradient(135deg,
rgba(41, 47, 61, 0.98) 0%,
rgba(31, 36, 48, 0.98) 100%);
backdrop-filter: blur(30rpx) saturate(180%);
-webkit-backdrop-filter: blur(30rpx) saturate(180%);
border: 1rpx solid rgba(255, 255, 255, 0.08);
box-shadow:
0 20rpx 60rpx rgba(0, 0, 0, 0.4),
0 0 0 1rpx rgba(255, 255, 255, 0.03),
inset 0 1rpx 0 rgba(255, 255, 255, 0.1);
min-height: 140rpx;
border-radius: 28rpx;
background: linear-gradient(145deg,
rgba(28, 32, 42, 0.97) 0%,
rgba(22, 26, 36, 0.98) 100%);
backdrop-filter: blur(40rpx) saturate(180%);
-webkit-backdrop-filter: blur(40rpx) saturate(180%);
border: 1rpx solid rgba(255, 255, 255, 0.1);
box-shadow:
0 24rpx 64rpx rgba(0, 0, 0, 0.45),
0 0 0 1rpx rgba(255, 255, 255, 0.04),
inset 0 1rpx 0 rgba(255, 255, 255, 0.12);
min-height: 148rpx;
touch-action: pan-y;
}
.global-notification::before {
content: '';
position: absolute;
left: 0;
top: 24rpx;
bottom: 24rpx;
width: 6rpx;
border-radius: 0 6rpx 6rpx 0;
background: linear-gradient(180deg, #07c160 0%, #D4AF37 100%);
}
.global-notification.show {
opacity: 1;
transform: translateY(0);
@@ -58,8 +69,8 @@
.notification-content {
display: flex;
align-items: center;
padding: 32rpx;
min-height: 140rpx;
padding: 28rpx 28rpx 28rpx 36rpx;
min-height: 148rpx;
position: relative;
}
@@ -84,6 +95,18 @@
justify-content: center;
}
.notification-tag {
display: inline-block;
align-self: flex-start;
font-size: 20rpx;
color: #07c160;
background: rgba(7, 193, 96, 0.15);
padding: 4rpx 14rpx;
border-radius: 20rpx;
margin-bottom: 8rpx;
font-weight: 500;
}
.notification-title {
font-size: 34rpx;
font-weight: 600;

View File

@@ -0,0 +1,170 @@
import { openCustomerServiceChat, resolveKefuIconUrl } from '../../utils/kefu-nav.js';
const CS_HOUR_START = 8;
const CS_HOUR_END = 23;
function getCsOnlineStatus() {
const hour = new Date().getHours();
const online = hour >= CS_HOUR_START && hour < CS_HOUR_END;
return {
csOnline: online,
csHoursText: '8:00-23:00',
csStatusText: online ? '在线' : '在线时间',
};
}
Component({
properties: {
bottom: { type: String, value: '200rpx' },
},
data: {
mode: 'full',
sessionHidden: false,
csUnread: 0,
floatY: 520,
iconUrl: '',
csOnline: false,
csHoursText: '8:00-23:00',
csStatusText: '在线时间',
},
lifetimes: {
attached() {
const app = getApp();
this._syncIcon();
this._syncFromGlobal();
this._initFloatY();
this._convHandler = () => this.syncCsUnread();
this._configHandler = () => this._syncIcon();
if (app.on) {
app.on('conversationsUpdated', this._convHandler);
app.on('unreadCountChanged', this._convHandler);
app.on('configApplied', this._configHandler);
}
this.syncCsUnread();
this._syncOnlineStatus();
},
detached() {
const app = getApp();
if (app.off) {
if (this._convHandler) {
app.off('conversationsUpdated', this._convHandler);
app.off('unreadCountChanged', this._convHandler);
}
if (this._configHandler) {
app.off('configApplied', this._configHandler);
}
}
},
},
pageLifetimes: {
show() {
this._syncIcon();
this._syncFromGlobal();
this.syncCsUnread();
this._syncOnlineStatus();
},
},
methods: {
_syncOnlineStatus() {
this.setData(getCsOnlineStatus());
},
_syncIcon() {
const url = resolveKefuIconUrl(getApp());
if (url && url !== this.data.iconUrl) {
this.setData({ iconUrl: url });
}
},
_initFloatY() {
const app = getApp();
if (app.globalData.kefuFloatY != null) {
this.setData({ floatY: app.globalData.kefuFloatY });
return;
}
try {
const sys = wx.getSystemInfoSync();
const defaultY = Math.floor((sys.windowHeight || 600) * 0.55);
this.setData({ floatY: defaultY });
} catch (e) {
this.setData({ floatY: 520 });
}
},
_syncFromGlobal() {
const app = getApp();
const sessionHidden = !!app.globalData.kefuFloatSessionHidden;
const mode = app.globalData.kefuFloatMode || 'full';
this.setData({ sessionHidden, mode });
},
onFloatMove(e) {
const y = e.detail && e.detail.y;
if (y == null) return;
const app = getApp();
app.globalData.kefuFloatY = y;
},
syncCsUnread() {
if (this.data.sessionHidden) return;
if (!wx.goEasy?.im?.latestConversations) return;
wx.goEasy.im.latestConversations({
onSuccess: (res) => {
const list = res.content?.conversations || res.conversations || [];
let unread = 0;
list.forEach((c) => {
if (c.type === 'cs' || c.teamId === 'support_team') {
unread += c.unread || 0;
}
});
if (unread !== this.data.csUnread) {
this.setData({ csUnread: unread });
}
},
onFailed: () => {},
});
},
onIconError() {
this._syncIcon();
},
onContact() {
openCustomerServiceChat();
},
onHideTap(e) {
if (e && e.stopPropagation) e.stopPropagation();
const app = getApp();
app.globalData.kefuFloatMode = 'mini';
this.setData({ mode: 'mini' });
},
onExpand(e) {
if (e && e.stopPropagation) e.stopPropagation();
const app = getApp();
app.globalData.kefuFloatMode = 'full';
this.setData({ mode: 'full' });
},
onSessionDismiss(e) {
if (e && e.stopPropagation) e.stopPropagation();
wx.showModal({
title: '隐藏联系客服',
content: '本次使用期间不再显示此按钮。清空后台重新进入小程序后会再次出现。',
confirmText: '确定隐藏',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
const app = getApp();
app.globalData.kefuFloatSessionHidden = true;
this.setData({ sessionHidden: true });
}
},
});
},
},
});

View File

@@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@@ -0,0 +1,44 @@
<movable-area class="kefu-movable-area" wx:if="{{!sessionHidden}}">
<movable-view
class="kefu-movable-view"
direction="vertical"
y="{{floatY}}"
damping="40"
friction="2"
bindchange="onFloatMove"
>
<block wx:if="{{mode === 'full'}}">
<view class="kefu-wrap">
<view class="kefu-float kefu-float--full">
<view class="kefu-unread-badge" wx:if="{{csUnread > 0}}">{{csUnread > 99 ? '99+' : csUnread}}</view>
<view class="kefu-float-main" catchtap="onContact">
<image class="kefu-float-icon-img" src="{{iconUrl}}" mode="aspectFit" binderror="onIconError"/>
<view class="kefu-text-col">
<text class="kefu-float-text">联系客服</text>
<text class="kefu-float-sub kefu-float-sub--warn" wx:if="{{csUnread > 0}}">有新消息</text>
<text class="kefu-float-sub {{csOnline ? 'kefu-float-sub--online' : ''}}" wx:else>{{csStatusText}} {{csHoursText}}</text>
</view>
</view>
<view class="kefu-float-close" catchtap="onHideTap">
<text>×</text>
</view>
</view>
<view class="kefu-permanent-row" catchtap="onSessionDismiss">
<text class="kefu-permanent-label">本次不再显示</text>
</view>
</view>
</block>
<block wx:else>
<view class="kefu-wrap kefu-wrap--mini">
<view class="kefu-float kefu-float--mini" catchtap="onContact" bindlongpress="onExpand">
<view class="kefu-unread-badge kefu-unread-badge--mini" wx:if="{{csUnread > 0}}">{{csUnread > 99 ? '99+' : csUnread}}</view>
<image class="kefu-float-mini-icon-img" src="{{iconUrl}}" mode="aspectFit" binderror="onIconError"/>
</view>
<view class="kefu-permanent-row kefu-permanent-row--mini" catchtap="onSessionDismiss">
<text class="kefu-permanent-label">隐藏</text>
</view>
</view>
</block>
</movable-view>
</movable-area>

View File

@@ -0,0 +1,186 @@
.kefu-movable-area {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 900;
}
.kefu-movable-view {
width: auto;
height: auto;
pointer-events: auto;
position: absolute;
right: 20rpx;
top: 0;
}
.kefu-wrap {
display: flex;
flex-direction: column;
align-items: flex-end;
pointer-events: auto;
}
.kefu-float {
position: relative;
}
.kefu-float--full {
display: flex;
align-items: stretch;
background: linear-gradient(135deg, #07c160 0%, #06ad56 100%);
border-radius: 999rpx;
box-shadow: 0 8rpx 28rpx rgba(7, 193, 96, 0.45);
border: 2rpx solid rgba(255, 255, 255, 0.85);
overflow: visible;
animation: kefu-pulse 2.4s ease-in-out infinite;
}
@keyframes kefu-pulse {
0%, 100% { box-shadow: 0 8rpx 28rpx rgba(7, 193, 96, 0.45); }
50% { box-shadow: 0 8rpx 36rpx rgba(7, 193, 96, 0.65), 0 0 0 8rpx rgba(7, 193, 96, 0.12); }
}
.kefu-unread-badge {
position: absolute;
top: -10rpx;
right: -6rpx;
min-width: 36rpx;
height: 36rpx;
line-height: 36rpx;
padding: 0 8rpx;
background: #fa5151;
color: #fff;
font-size: 20rpx;
font-weight: 700;
text-align: center;
border-radius: 18rpx;
border: 3rpx solid #fff;
z-index: 2;
}
.kefu-unread-badge--mini {
top: -6rpx;
right: -4rpx;
}
.kefu-float-main {
display: flex;
align-items: center;
padding: 18rpx 24rpx;
flex: 1;
}
.kefu-float-main:active {
opacity: 0.88;
}
.kefu-float-icon-img {
width: 44rpx;
height: 44rpx;
margin-right: 12rpx;
flex-shrink: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.95);
padding: 4rpx;
}
.kefu-text-col {
display: flex;
flex-direction: column;
min-width: 0;
}
.kefu-float-text {
font-size: 28rpx;
color: #fff;
font-weight: 700;
white-space: nowrap;
}
.kefu-float-sub {
font-size: 20rpx;
color: rgba(255, 255, 255, 0.92);
margin-top: 2rpx;
font-weight: 600;
}
.kefu-float-sub--online {
color: #e8ffe8;
}
.kefu-float-sub--warn {
color: #fff3e0;
}
.kefu-float-close {
width: 52rpx;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.12);
color: rgba(255, 255, 255, 0.9);
font-size: 34rpx;
line-height: 1;
border-left: 1rpx solid rgba(255, 255, 255, 0.25);
border-radius: 0 999rpx 999rpx 0;
}
.kefu-float-close:active {
background: rgba(0, 0, 0, 0.2);
}
.kefu-permanent-row {
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 6rpx;
padding: 4rpx 10rpx;
}
.kefu-permanent-row:active {
opacity: 0.75;
}
.kefu-permanent-row--mini {
margin-top: 4rpx;
padding: 2rpx 8rpx;
}
.kefu-permanent-label {
font-size: 20rpx;
color: #888;
}
.kefu-wrap--mini {
align-items: flex-end;
}
.kefu-float--mini {
width: 96rpx;
height: 96rpx;
padding: 0;
border-radius: 50%;
background: linear-gradient(135deg, #07c160 0%, #06ad56 100%);
box-shadow: 0 8rpx 24rpx rgba(7, 193, 96, 0.45);
border: 3rpx solid #fff;
display: flex;
align-items: center;
justify-content: center;
animation: kefu-pulse 2.4s ease-in-out infinite;
}
.kefu-float--mini:active {
transform: scale(0.96);
}
.kefu-float-mini-icon-img {
width: 48rpx;
height: 48rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.95);
padding: 4rpx;
}

View File

@@ -15,7 +15,7 @@
.card-id { font-size: 24rpx; color: #999; margin-left: 15rpx; }
.cross-tag {
margin-left: auto;
background: #8b5cf6;
background: #ff9900;
color: #fff;
font-size: 20rpx;
padding: 2rpx 12rpx;

View File

@@ -1,16 +1,87 @@
import request from '../../utils/request';
const app = getApp();
function mapIdentityForApi() {
const role = app.globalData.currentRole || wx.getStorageSync('currentRole') || 'normal';
if (role === 'dashou') return 'dashou';
if (role === 'shangjia') return 'shangjia';
return 'normal';
}
Component({
properties: {
visible: Boolean,
showDetail: { type: Boolean, value: false }
visible: { type: Boolean, value: false },
groupId: { type: String, value: '' },
orderId: { type: String, value: '' },
},
data: {},
data: {
keyword: '',
loading: false,
orders: [],
filteredOrders: [],
},
observers: {
visible(v) {
if (v) {
this.setData({ keyword: '' });
this.loadOrders('');
}
},
},
methods: {
close() {
this.triggerEvent('close');
}
}
});
},
onSearchInput(e) {
const keyword = (e.detail.value || '').trim();
this.setData({ keyword });
if (this._searchTimer) clearTimeout(this._searchTimer);
this._searchTimer = setTimeout(() => {
this.loadOrders(keyword);
}, 350);
},
async loadOrders(keyword) {
const { groupId, orderId } = this.properties;
if (!groupId && !orderId) return;
this.setData({ loading: true });
try {
const res = await request({
url: '/dingdan/ltpddd',
method: 'POST',
data: {
groupId,
dingdan_id: orderId,
keyword: keyword || '',
identityType: mapIdentityForApi(),
},
});
const body = res?.data || {};
const list = body.data?.list || [];
this.setData({
orders: list,
filteredOrders: list,
loading: false,
});
} catch (e) {
console.warn('加载历史订单失败', e);
this.setData({ loading: false, orders: [], filteredOrders: [] });
wx.showToast({ title: '加载订单失败', icon: 'none' });
}
},
onSelectOrder(e) {
const index = e.currentTarget.dataset.index;
const order = this.data.filteredOrders[index];
if (!order) return;
this.triggerEvent('send', { order });
this.close();
},
},
});

View File

@@ -1,12 +1,28 @@
<view class="order-sender-mask" wx:if="{{visible}}" catchtap="close"></view>
<view class="order-sender {{visible ? 'show' : ''}}">
<view class="header">
<text class="title">提示</text>
<text class="title">选择订单发送</text>
<text class="close" bindtap="close">✕</text>
</view>
<view class="content">
<view class="icon">📋</view>
<text class="notice">此功能暂未开放</text>
<text class="sub">敬请期待</text>
<view class="search-row">
<input class="search-input" placeholder="搜索订单号/内容" value="{{keyword}}" bindinput="onSearchInput" confirm-type="search" />
</view>
</view>
<scroll-view scroll-y class="order-list" enable-flex>
<view class="loading-tip" wx:if="{{loading}}">加载中...</view>
<block wx:for="{{filteredOrders}}" wx:key="dingdan_id">
<view class="order-item" data-index="{{index}}" bindtap="onSelectOrder">
<view class="order-item-top">
<text class="order-id">{{item.dingdan_id}}</text>
<text class="order-status">{{item.zhuangtaiText}}</text>
</view>
<text class="order-desc">{{item.jieshao || '暂无介绍'}}</text>
<view class="order-item-bottom">
<text class="order-price">¥{{item.jine || '0'}}</text>
<text class="order-time">{{item.create_time}}</text>
</view>
<text class="order-send-hint">点击发送订单卡片</text>
</view>
</block>
<view class="empty-tip" wx:if="{{!loading && !filteredOrders.length}}">暂无相关订单</view>
</scroll-view>
</view>

View File

@@ -1,45 +1,140 @@
.order-sender-mask {
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.5);
z-index: 2000;
}
.order-sender {
position: fixed; bottom: 0; left: 0; right: 0;
height: 360rpx;
background: #fff;
border-radius: 24rpx 24rpx 0 0;
z-index: 2001;
transform: translateY(100%);
transition: 0.25s;
display: flex;
flex-direction: column;
}
.order-sender.show { transform: translateY(0); }
.header {
display: flex; justify-content: space-between;
padding: 24rpx 30rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.title { font-size: 32rpx; font-weight: 600; }
.close { font-size: 44rpx; color: #999; padding: 0 12rpx; }
.content {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-bottom: 40rpx;
}
.icon { font-size: 80rpx; margin-bottom: 20rpx; }
.notice {
font-size: 34rpx;
font-weight: 600;
color: #333;
margin-bottom: 10rpx;
}
.sub {
font-size: 24rpx;
color: #999;
}
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 2000;
}
.order-sender {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 72vh;
max-height: 900rpx;
background: #fff;
border-radius: 24rpx 24rpx 0 0;
z-index: 2001;
transform: translateY(100%);
transition: transform 0.25s;
display: flex;
flex-direction: column;
}
.order-sender.show {
transform: translateY(0);
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx 30rpx;
border-bottom: 1rpx solid #f0f0f0;
flex-shrink: 0;
}
.title {
font-size: 32rpx;
font-weight: 600;
}
.close {
font-size: 44rpx;
color: #999;
padding: 0 12rpx;
}
.search-row {
padding: 16rpx 24rpx;
flex-shrink: 0;
}
.search-input {
background: #f5f5f5;
border-radius: 32rpx;
padding: 16rpx 28rpx;
font-size: 28rpx;
}
.order-list {
flex: 1;
height: 0;
padding: 0 24rpx 24rpx;
box-sizing: border-box;
}
.loading-tip,
.empty-tip {
text-align: center;
color: #999;
font-size: 28rpx;
padding: 60rpx 0;
}
.order-item {
background: #fafafa;
border-radius: 16rpx;
padding: 20rpx 24rpx;
margin-bottom: 16rpx;
border: 1rpx solid #eee;
}
.order-item:active {
background: #f0f7ff;
}
.order-item-top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8rpx;
}
.order-id {
font-size: 26rpx;
font-weight: 600;
color: #333;
}
.order-status {
font-size: 22rpx;
color: #07c160;
background: #e8f8ee;
padding: 4rpx 14rpx;
border-radius: 20rpx;
}
.order-desc {
font-size: 26rpx;
color: #666;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-bottom: 8rpx;
}
.order-item-bottom {
display: flex;
justify-content: space-between;
align-items: center;
}
.order-price {
font-size: 28rpx;
color: #ff6b00;
font-weight: 600;
}
.order-time {
font-size: 22rpx;
color: #aaa;
}
.order-send-hint {
display: block;
font-size: 22rpx;
color: #007aff;
margin-top: 10rpx;
}

View File

@@ -0,0 +1,15 @@
Component({
properties: {
visible: { type: Boolean, value: false },
title: { type: String, value: '频道' },
channelNo: { type: String, value: '' },
images: { type: Array, value: [] },
},
methods: {
preventMove() {},
onClose() {
this.triggerEvent('close');
},
},
});

View File

@@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@@ -0,0 +1,24 @@
<view class="pindao-mask" wx:if="{{visible}}" catchtouchmove="preventMove">
<view class="pindao-panel" catchtap="preventMove">
<view class="pindao-head flexb">
<text class="pindao-title">{{title}}</text>
<view class="pindao-close" bindtap="onClose">×</view>
</view>
<view class="pindao-channel" wx:if="{{channelNo}}">
<text class="pindao-channel-label">频道号</text>
<text class="pindao-channel-no">{{channelNo}}</text>
</view>
<scroll-view class="pindao-scroll" scroll-y enhanced show-scrollbar="{{false}}">
<view wx:if="{{!images || images.length === 0}}" class="pindao-empty">暂无频道内容</view>
<image
wx:for="{{images}}"
wx:key="index"
class="pindao-img"
src="{{item}}"
mode="widthFix"
lazy-load="{{false}}"
show-menu-by-longpress
/>
</scroll-view>
</view>
</view>

View File

@@ -0,0 +1,88 @@
.pindao-mask {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.55);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx;
box-sizing: border-box;
}
.pindao-panel {
width: 100%;
max-height: 80vh;
background: #fff;
border-radius: 24rpx;
overflow: hidden;
display: flex;
flex-direction: column;
}
.pindao-head {
padding: 28rpx 32rpx 16rpx;
align-items: center;
}
.pindao-title {
font-size: 32rpx;
font-weight: 600;
color: #222;
}
.pindao-close {
width: 56rpx;
height: 56rpx;
line-height: 52rpx;
text-align: center;
font-size: 40rpx;
color: #999;
}
.pindao-channel {
padding: 0 32rpx 20rpx;
text-align: center;
}
.pindao-channel-label {
display: block;
font-size: 24rpx;
color: #999;
margin-bottom: 8rpx;
}
.pindao-channel-no {
font-size: 36rpx;
font-weight: 700;
color: #c9a962;
}
.pindao-scroll {
flex: 1;
max-height: 60vh;
padding: 0 24rpx 24rpx;
box-sizing: border-box;
}
.pindao-img {
width: 100%;
display: block;
margin-bottom: 16rpx;
border-radius: 12rpx;
}
.pindao-empty {
text-align: center;
color: #999;
padding: 48rpx 0;
font-size: 28rpx;
}
.flexb {
display: flex;
justify-content: space-between;
}

View File

@@ -138,7 +138,7 @@
.countdown-tip {
text-align: center;
font-size: 28rpx;
color: #9333ea;
color: #ff6600;
margin-bottom: 20rpx;
}
@@ -223,7 +223,7 @@
height: 120rpx;
border-radius: 50%;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.3);
border: 2rpx solid rgba(196, 181, 253, 0.6);
border: 2rpx solid rgba(255, 215, 0, 0.6);
background: #f0f0f0;
display: block;
transform: translateZ(0);