alipay-emulator/pages/shopping/jingdong/list-index.vue

811 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="top-fixed">
<nav-bar title="京东" bgColor="#F0F4F9" :buttonGroup="buttonGroup" @button-click="util.clickTitlePopupButton">
<template v-slot:center>
<view class="search-box">
<image class="search-icon" src="/static/image/shopping/jingdong/search-icon.png" mode="aspectFit">
</image>
<input class="input" type="text" placeholder="搜索我的订单" />
</view>
</template>
<template v-slot:right>
<view class="right-box">
<image class="gift icon" src="/static/image/shopping/jingdong/gift.png" mode="aspectFit">
</image>
<image class="more icon" src="/static/image/shopping/jingdong/more.png" mode="aspectFit">
</image>
</view>
</template>
</nav-bar>
<view class="tab-list">
<view class="tab-item" v-for="(item, index) in tabList" :key="index"
:class="{ active: currentTab === index }" @click="switchTab(index)">
<text class="title">{{ item.name }}</text>
<view class="line" v-if="currentTab === index"></view>
<image v-if="item.icon" class="badge-icon" :src="item.icon" mode="heightFix"></image>
</view>
</view>
<view class="filter-wrapper">
<scroll-view class="filter-scroll" scroll-x="true" :show-scrollbar="false">
<view class="filter-list">
<view class="filter-item" v-for="(item, index) in filterList" :key="index"
:class="{ active: currentFilter === index, disabled: item.disabled }"
@click="switchFilter(index)">
<text class="text">{{ item.name }}</text>
<text class="close-icon" v-if="currentFilter === index">×</text>
</view>
</view>
</scroll-view>
<view class="filter-btn">
<image class="filter-icon" src="/static/image/shopping/jingdong/shaixuan.png" mode="aspectFit"></image>
<text class="filter-text">筛选</text>
</view>
</view>
</view>
<view class="content" :style="{ paddingTop: contentPaddingTop }">
<shopping-card v-for="(item, index) in filteredOrderList" :key="index" :item="item" @longpress="handleLongPress"
@click="handleCardClick(item)"></shopping-card>
<view class="empty-state" v-if="filteredOrderList.length === 0">
<image class="empty-icon" src="/static/image/shopping/jingdong/null.png" mode="heightFix"></image>
<text class="empty-text">您还没有相关订单</text>
</view>
</view>
<view class="bottom-fixed" :style="{ height: bottomBoxHeight }">
<view class="bottom-item">
<image class="like-icon" src="/static/image/shopping/jingdong/weinituijian.png" mode="aspectFit"></image>
<text>为你推荐</text>
</view>
<view class="upload-screenshot-box">
<view class="upload-screenshot-content">
<image class="upload-screenshot" src="/static/image/common/upload-screenshot.png" mode="aspectFit">
</image>
<view class="upload-screenshot-text">长按替换截图</view>
</view>
</view>
</view>
<!-- 长按操作气泡菜单 -->
<view v-if="showActionMenu" class="action-menu-mask" @click="showActionMenu = false">
<view class="action-menu-bubble" :style="{ left: actionMenuState.x + 'px', top: actionMenuState.y + 'px' }"
@click.stop>
<view class="menu-item" @click.stop="editOrder">修改</view>
<view class="menu-line"></view>
<view class="menu-item" @click.stop="handleDeleteOrder">删除</view>
<view class="bubble-arrow"></view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted, getCurrentInstance } from 'vue';
import ShoppingCard from '@/components/shopping/jingdong/shopping-card.vue';
import { util } from '@/utils/common.js';
const showActionMenu = ref(false);
const actionMenuState = ref({ x: 0, y: 0, item: null });
//导航栏菜单按钮
const buttonGroup = [
{
name: "新增购物",
click: () => {
uni.navigateTo({
url: '/pages/shopping/jingdong/add-order/add-order'
});
}
},
]
/**
* 长按弹出气泡菜单
* @param data
*/
const handleLongPress = (data) => {
console.log("长按", data);
const event = data.event;
let x = 0;
let y = 0;
// 兼容不同平台的坐标获取
if (event.touches && event.touches.length > 0) {
x = event.touches[0].clientX;
y = event.touches[0].clientY;
} else if (event.changedTouches && event.changedTouches.length > 0) {
x = event.changedTouches[0].clientX;
y = event.changedTouches[0].clientY;
} else {
// 兜底处理 (如模拟器点击或 detail 携带)
x = event.clientX || (event.detail && event.detail.x) || 0;
y = event.clientY || (event.detail && event.detail.y) || 0;
}
if (x || y) {
actionMenuState.value = {
x: x,
y: y,
item: data.item
};
showActionMenu.value = true;
} else {
console.warn("无法获取长按坐标");
}
};
/**
* 修改订单
*/
const editOrder = () => {
const item = actionMenuState.value.item;
if (!item) return;
showActionMenu.value = false;
uni.navigateTo({
url: '/pages/shopping/jingdong/add-order/add-order?id=' + item.id + '&type=' + item.shopType
});
};
/**
* 点击订单卡片
* @param item 订单项
*/
const handleCardClick = (item) => {
if (item.shopType !== "waimai") {
uni.navigateTo({
url: '/pages/shopping/jingdong/order-detail/order-detail?id=' + item.id
});
} else {
}
};
/**
* 删除订单
*/
const handleDeleteOrder = () => {
const itemToDel = actionMenuState.value.item;
const realIndex = mockOrderList.value.findIndex(item => item === itemToDel);
if (realIndex > -1) {
mockOrderList.value.splice(realIndex, 1);
}
showActionMenu.value = false;
uni.showToast({ title: '已删除', icon: 'none' });
};
const contentPaddingTop = ref('0px');
const instance = getCurrentInstance();
/**
* 底部盒子高度
*/
const bottomBoxHeight = computed(() => {
const { windowHeight } = uni.getSystemInfoSync();
return `calc(${windowHeight}px - ${contentPaddingTop.value} - 324rpx)`;
});
/**
* 初始化
*/
onMounted(() => {
setTimeout(() => {
const query = uni.createSelectorQuery().in(instance.proxy);
query.select('.top-fixed').boundingClientRect(data => {
if (data) {
contentPaddingTop.value = data.height + 'px';
}
}).exec();
}, 100);
});
const currentTab = ref(0);
const tabList = ref([
{ name: '全部' },
{ name: '购物' },
{ name: '秒送', icon: '/static/image/shopping/jingdong/waimai.png' },
{ name: '服务', icon: '/static/image/shopping/jingdong/jiazheng.png', disabled: true }
]);
/**
* 切换tab
* @param index
*/
const switchTab = (index) => {
if (tabList.value[index].disabled) return;
currentTab.value = index;
};
const currentFilter = ref(-1);
const filterList = ref([
{ name: '待付款' },
{ name: '待收货' },
{ name: '待使用', disabled: false },
{ name: '已完成' },
{ name: '待评价' },
{ name: '已取消' }
]);
/**
* 切换筛选
* @param index 索引
*/
const switchFilter = (index) => {
if (filterList.value[index].disabled) return;
if (currentFilter.value === index) {
currentFilter.value = -1;
} else {
currentFilter.value = index;
}
};
/**
* 筛选订单列表
*/
const filteredOrderList = computed(() => {
const tabName = tabList.value[currentTab.value].name;
let baseList = mockOrderList.value;
if (tabName === '购物') {
baseList = mockOrderList.value.filter(item => item.shopType !== 'waimai');
} else if (tabName === '秒送') {
baseList = mockOrderList.value.filter(item => item.shopType === 'waimai');
}
if (currentFilter.value === -1) {
return baseList;
}
const filterName = filterList.value[currentFilter.value].name;
return baseList.filter(item => {
if (filterName === '待付款') return item.status === '等待付款';
if (filterName === '待收货') return item.status === '正在出库' || item.status === '待收货' || item.status === '运输中' || item.status === '已发货' || item.status === '商家备餐中' || item.status === '骑手到店取餐中';
if (filterName === '待使用') return item.status === '待使用';
if (filterName === '已完成') return item.status === '完成' || item.status === '已完成' || item.status === '已签收';
if (filterName === '待评价') return item.status === '待评价' || item.status === '完成' || item.status === '已完成';
if (filterName === '已取消') return item.status === '已取消';
return true;
});
});
/**
* 模拟订单列表
*/
const mockOrderList = ref([
{
id: 123211111,
shopType: 'waimai',
shopName: '安野屋 (AARYE) 京...',
status: '等待付款',
statusDesc: '29分钟',
products: [
{
image: '/static/image/shopping/jingdong/product1.png',
title: '超值哈哈哈哈哈哈哈哈哈哈哈哈哈哈好一人份',
desc: '不支持7天无理由退货',
service: "",
price: '69.00',
count: 1,
}
],
promoType: 'text',
promoHighlight: '近90天600+人回购',
},
{
id: 9632554,
shopType: 'waimai',
shopName: '安野屋 (AARYE) 京...',
status: '骑手到店取餐中',
trackingTitle: '10:22-10:55',
trackingDesc: '骑手已到店,大王',
trackingTime: '2026-03-10 15:14:30',
products: [
{
image: '/static/image/shopping/jingdong/product1.png',
title: '超值哈哈哈哈哈哈哈哈哈哈哈哈哈哈好热 少糖',
desc: '不支持7天无理由退货',
service: "",
tags: [],
price: '69.00',
count: 1,
}
]
},
{
id: 63254112,
shopType: 'waimai',
shopName: '安野屋 (AARYE) 京...',
status: '商家备餐中',
trackingTitle: '10:22-10:55',
trackingDesc: '商家已接单,商品备餐中',
trackingTime: '2026-03-10 15:14:30',
products: [
{
image: '/static/image/shopping/jingdong/product1.png',
title: '超值哈哈哈哈哈哈哈哈哈哈哈哈哈哈好热 少糖',
desc: '不支持7天无理由退货',
service: "",
tags: [],
price: '69.00',
count: 1,
}
]
},
{
id: 78456211,
shopType: 'waimai',
shopName: '瑞幸咖啡',
status: '完成',
statusColor: 'gray',
products: [
{
image: '/static/image/shopping/jingdong/product1.png',
title: '多肉桃桃哈哈哈哈哈哈哈哈哈哈好和和好',
desc: '不支持7天无理由退货',
service: "",
tags: [],
price: '69.00',
count: 1,
}
],
promoType: 'coupon',
promoText: '恭喜您获得3元京东购物券',
promoAction: '去领券'
},
{
id: 56322115,
shopType: 'waimai',
shopName: '瑞幸咖啡',
status: '完成',
statusColor: 'gray',
products: [
{
image: '/static/image/shopping/jingdong/product1.png',
},
{
image: '/static/image/shopping/jingdong/product1.png',
},
{
image: '/static/image/shopping/jingdong/product1.png',
}
],
price: '17.00',
count: 2,
},
{
id: 52322221,
shopType: 'waimai',
shopName: '瑞幸咖啡',
status: '已取消',
statusColor: 'gray',
products: [
{
image: '/static/image/shopping/jingdong/product1.png',
title: '多肉桃桃哈哈哈哈哈哈哈哈哈哈好和和好',
desc: '不支持7天无理由退货',
tags: [],
service: "",
price: '69.00',
count: 1,
}
]
},
{
id: 8562245551,
shopType: 'self',
shopName: '安野屋 (AARYE) 京联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
status: '等待付款',
statusDesc: '20小时11分钟',
products: [
{
image: '/static/image/shopping/jingdong/product1.png',
title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
tags: ['无理由退货政策'],
service: "无理由退货政策",
price: '69.00',
count: 1,
}
],
promoType: 'text',
promoHighlight: '白条支付券0.5元优惠券',
},
{
id: 5504455,
shopType: 'none',
shopName: '甜小南旗舰店',
status: '正在出库',
trackingTitle: '仓库处理中',
trackingDesc: '预计 3月12日24:00 前发货3月15日 24:00 前送达',
trackingTime: '2026-03-10 15:14:30',
products: [
{
image: '/static/image/shopping/jingdong/product1.png',
title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
tags: ['无理由退货政策'],
service: "无理由退货政策",
price: '69.00',
count: 1,
}
],
promoType: 'plus',
promoText: '告别凑单, 享免运优惠',
},
{
id: 585552,
shopType: 'self',
shopName: '甜小南旗舰店',
status: '完成',
statusColor: 'gray',
trackingTitle: '已签收',
trackingDesc: '您的订单已签收,可对快递员的服务进行评价或打赏哦~',
trackingTime: '2026-03-10 15:14:30',
products: [
{
image: '/static/image/shopping/jingdong/product1.png',
title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
tags: ['无理由退货政策'],
service: "无理由退货政策",
price: '69.00',
count: 1,
}
],
promoType: 'plus',
promoText: '告别凑单, 享免运优惠',
hasMore: true,
},
{
id: 4545451,
shopType: 'jd',
shopName: '甜小南旗舰店',
status: '完成',
statusColor: 'gray',
products: [
{
image: '/static/image/shopping/jingdong/product1.png',
title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
tags: ['无理由退货政策'],
service: "无理由退货政策",
price: '1669.00',
count: 1,
}
],
hasMore: true,
},
{
id: 1236524,
shopType: 'self',
shopName: '甜小南旗舰店',
status: '已取消',
statusColor: 'gray',
products: [
{
image: '/static/image/shopping/jingdong/product1.png',
title: '安野哈哈哈哈哈哈哈哈哈哈哈哈好好',
desc: '联名哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈好梦',
tags: ['无理由退货政策'],
service: "无理由退货政策",
price: '1669.00',
count: 1,
}
]
}
]);
</script>
<style lang="less">
.top-fixed {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 999;
background-color: #F0F4F9;
}
::v-deep .uni-navbar__header-btns {
width: auto !important;
}
::v-deep .uni-navbar__header-container {
padding-right: 0 !important;
}
.search-box {
width: 100%;
background-color: #fff;
border-radius: 12rpx;
padding: 0 16rpx;
height: 60rpx;
display: flex;
align-items: center;
border: 1rpx solid #E5E5E5;
.search-icon {
width: 36rpx;
height: 36rpx;
flex-shrink: 0;
margin-right: 14rpx;
}
::v-deep .input-placeholder {
font-size: 26rpx;
line-height: 26rpx;
color: #CCCCCC;
}
}
.right-box {
display: flex;
align-items: center;
.icon {
width: 40rpx;
height: 40rpx;
margin-left: 22rpx;
}
}
.tab-list {
display: flex;
align-items: center;
padding: 16rpx 36rpx 10rpx;
background-color: #F0F4F9;
.tab-item {
position: relative;
display: flex;
align-items: center;
margin-right: 58rpx;
.title {
font-size: 28rpx;
color: #1A1A1A;
font-weight: 700;
line-height: 28rpx;
}
&.active {
.title {
font-size: 28rpx;
color: #F51919;
font-weight: 700;
}
}
.line {
position: absolute;
bottom: -10rpx;
left: -5%;
transform: translateX(50%);
width: 30rpx;
height: 4rpx;
background-color: #F51919;
border-radius: 4rpx;
}
.badge-icon {
position: relative;
top: 0;
margin-left: 2rpx;
height: 32rpx;
}
}
}
.filter-wrapper {
display: flex;
align-items: center;
height: 64rpx;
padding: 0 0 0 24rpx;
background-color: #F0F4F9;
margin-top: 10rpx;
margin-bottom: 26rpx;
.filter-scroll {
flex: 1;
width: 0;
white-space: nowrap;
.filter-list {
height: 88rpx;
line-height: 88rpx;
padding-right: 24rpx;
}
.filter-item {
display: inline-flex;
align-items: center;
justify-content: center;
vertical-align: middle;
height: 56rpx;
padding: 0 24rpx;
background-color: #FFFFFF;
border-radius: 8rpx;
margin-right: 16rpx;
border: 2rpx solid transparent;
box-sizing: border-box;
.text {
font-size: 26rpx;
color: #1A1A1A;
}
.close-icon {
font-size: 18px;
color: #E40C24;
margin-top: -10rpx;
line-height: 14px;
margin-left: 6rpx;
font-weight: 400;
}
&.active {
background-color: #FFECF5;
border-color: #E40C24;
.text {
color: #E40C24;
}
}
// &.disabled {
// background-color: #F8F8F8;
// border-color: transparent;
// .text {
// color: #CCCCCC;
// }
// }
}
}
.filter-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 82rpx;
height: 64rpx;
background-color: #F0F4F9;
position: relative;
z-index: 10;
box-shadow: -10rpx 0 10rpx -10rpx rgba(0, 0, 0, 0.1);
.filter-icon {
width: 28rpx;
height: 28rpx;
margin-bottom: 4rpx;
}
.filter-text {
font-size: 20rpx;
line-height: 20rpx;
color: #575757;
}
}
}
.content {
padding: 0 20rpx;
}
.bottom-fixed {
display: flex;
flex-direction: column;
}
.bottom-item {
display: flex;
align-items: center;
justify-content: center;
color: #1A1A1A;
font-size: 28rpx;
line-height: 26rpx;
font-weight: 500;
margin-bottom: 22rpx;
}
.like-icon {
width: 32rpx;
height: 32rpx;
margin-right: 8rpx;
}
.upload-screenshot-box {
width: 100%;
flex: 1;
min-height: 540rpx;
background-color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
.upload-screenshot {
width: 92rpx;
height: 92rpx;
}
.upload-screenshot-content {
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
.upload-screenshot-text {
font-size: 36rpx;
color: #1777FF;
line-height: 50rpx;
margin-top: 16rpx;
}
}
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40rpx 0 64rpx;
.empty-icon {
height: 220rpx;
margin-bottom: 12rpx;
}
.empty-text {
font-size: 22rpx;
color: #999A9E;
line-height: 24rpx;
}
}
.action-menu-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
}
.action-menu-bubble {
position: fixed;
background-color: #3B3C3E;
border-radius: 12rpx;
width: 200rpx;
transform: translate(-50%, calc(-100% - 15px));
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.2);
display: flex;
flex-direction: column;
.menu-item {
color: #FFFFFF;
font-size: 26rpx;
text-align: center;
padding: 24rpx 0;
line-height: 26rpx;
}
.menu-line {
height: 1rpx;
background-color: rgba(255, 255, 255, 0.1);
margin: 0 24rpx;
}
.bubble-arrow {
position: absolute;
bottom: -12rpx;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 12rpx solid transparent;
border-right: 12rpx solid transparent;
border-top: 14rpx solid #3B3C3E;
}
}
</style>