完成淘宝购物模块

This commit is contained in:
tangxinyue 2026-05-15 09:36:12 +08:00
parent 55c624621d
commit 519c0f85d6
15 changed files with 2995 additions and 355 deletions

View File

@ -1,7 +1,8 @@
<template>
<view class="auto-width-input-container" :class="{ 'is-textarea': type === 'textarea' }">
<!-- 测量层用于计算宽度的影藏文本必须保持与 input 相同的字体样式 -->
<text v-if="type !== 'textarea'" class="measure-text" :style="[inputStyle, { visibility: 'hidden', position: 'absolute', whiteSpace: 'nowrap' }]">
<text v-if="type !== 'textarea'" class="measure-text"
:style="[inputStyle, { visibility: 'hidden', position: 'absolute', whiteSpace: 'nowrap' }]">
{{ modelValue || placeholder }}
</text>
@ -187,9 +188,10 @@ onMounted(() => {
vertical-align: middle;
max-width: 100%;
flex-wrap: nowrap;
// flex-1 width: 100% flex
&.flex-1, &.w100 {
&.flex-1,
&.w100 {
display: flex !important;
width: 100% !important;
}
@ -215,7 +217,7 @@ onMounted(() => {
height: 1.4em;
line-height: 1.4em;
flex-shrink: 0;
// input
& {
flex: 1;

View File

@ -94,6 +94,14 @@
"navigationBarTitleText": "淘宝购物详情页",
"navigationStyle": "custom"
}
},
{
"path" : "taobao/add-shopping-order/add-shopping-order",
"style" :
{
"navigationBarTitleText" : "新增淘宝购物订单",
"navigationStyle": "custom"
}
}
]
},

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
<template>
<view class="card-wrapper">
<view class="card-container" v-for="(item, index) in list" :key="index" @click.stop="clickItem(item)">
<view class="card-container" v-for="(item, index) in list" :key="index" @click.stop="clickItem(item)"
@touchstart="handleTouchStart($event, item)" @touchmove="handleTouchMove" @touchend="handleTouchEnd">
<!-- 顶部店铺和状态 -->
<view class="card-header">
<view class="shop-info">
@ -25,8 +26,8 @@
</image>
<view class="goods-info" :id="'goods-info-' + index + '-' + gIdx">
<view class="goods-title-row">
<view class="good-info-box">
<text class="goods-title">{{ goods.title }}</text>
<view class="good-info-box" :id="'title-box-' + index + '-' + gIdx">
<text class="goods-title">{{ getTruncatedTitle(item, index, goods, gIdx) }}</text>
<view class="goods-spec" v-if="goods.specs">{{ goods.specs }}</view>
</view>
@ -120,7 +121,7 @@
</template>
<script setup>
import { defineProps, defineEmits, ref, watch, nextTick, getCurrentInstance } from 'vue';
import { defineProps, defineEmits, ref, watch, nextTick, getCurrentInstance, onMounted } from 'vue';
const props = defineProps({
list: {
@ -129,32 +130,81 @@ const props = defineProps({
}
});
const emit = defineEmits(['action', 'detail', 'click-item']);
const emit = defineEmits(['action', 'detail', 'click-item', 'longpress']);
const instance = getCurrentInstance();
const imgHeights = ref({});
const titleMap = ref({}); // key: 'itemIdx-goodsIdx'
const longPressTimer = ref(null);
const touchStartPos = ref({ x: 0, y: 0 });
/**
* shopping-card.vue 对齐的字符权重截断算法
*/
const calcFitTitle = (originalTitle, containerWidth) => {
const fontSize = uni.upx2px(26);
let currentWidth = 0;
let cutIndex = 0;
let found = false;
for (let i = 0; i < originalTitle.length; i++) {
const char = originalTitle[i];
const charCode = char.charCodeAt(0);
let weight = 1;
if (charCode <= 255) {
if (/[A-Z]/.test(char)) weight = 0.7;
else if (/[a-z]/.test(char)) weight = 0.5;
else if (/[0-9]/.test(char)) weight = 0.55;
else if (char === ' ') weight = 0.25;
else weight = 0.5;
}
currentWidth += weight * fontSize;
if (currentWidth > containerWidth - uni.upx2px(4)) {
cutIndex = i;
found = true;
break;
}
}
return found ? originalTitle.slice(0, cutIndex - 1) : originalTitle;
};
/**
* 供模板调用返回截取后的标题
*/
const getTruncatedTitle = (item, index, goods, gIdx) => {
const key = index + '-' + gIdx;
return titleMap.value[key] !== undefined ? titleMap.value[key] : (goods.title || '');
};
const calculateHeights = () => {
nextTick(() => {
setTimeout(() => {
if (!instance || !instance.proxy) return;
const query = uni.createSelectorQuery().in(instance.proxy);
let keys = [];
if (!props.list || props.list.length === 0) return;
const heightQuery = uni.createSelectorQuery().in(instance.proxy);
const titleQuery = uni.createSelectorQuery().in(instance.proxy);
let keys = [];
props.list.forEach((item, index) => {
if (!item.goodsList) return;
item.goodsList.forEach((goods, gIdx) => {
const key = index + '-' + gIdx;
keys.push(key);
query.select('#goods-info-' + key).boundingClientRect();
heightQuery.select('#goods-info-' + key).boundingClientRect();
titleQuery.select('#title-box-' + key).boundingClientRect();
});
});
if (keys.length > 0) {
query.exec((res) => {
//
heightQuery.exec((res) => {
if (res && res.length > 0) {
res.forEach((data, i) => {
if (data && data.height) {
@ -163,8 +213,23 @@ const calculateHeights = () => {
});
}
});
//
titleQuery.exec((res) => {
if (res && res.length > 0) {
res.forEach((data, i) => {
if (data && data.width) {
const [li, gi] = keys[i].split('-').map(Number);
const goods = props.list[li]?.goodsList?.[gi];
if (goods && goods.title) {
titleMap.value[keys[i]] = calcFitTitle(goods.title, data.width);
}
}
});
}
});
}
}, 100); //
}, 300); //
});
};
@ -172,6 +237,12 @@ watch(() => props.list, () => {
calculateHeights();
}, { deep: true, immediate: true });
//
// shopping-card.vue onMounted
onMounted(() => {
setTimeout(calculateHeights, 500);
});
//
const getStatusText = (status) => {
const map = {
@ -268,6 +339,47 @@ const clickItem = (item) => {
emit('click-item', item);
}
const handleTouchStart = (e, item) => {
const touch = e.touches[0];
touchStartPos.value = { x: touch.clientX, y: touch.clientY };
//
if (longPressTimer.value) clearTimeout(longPressTimer.value);
// 800ms ()
longPressTimer.value = setTimeout(() => {
//
uni.vibrateShort();
emit('longpress', {
item,
x: touch.clientX,
y: touch.clientY
});
longPressTimer.value = null;
}, 800);
}
const handleTouchMove = (e) => {
const touch = e.touches[0];
const offsetX = Math.abs(touch.clientX - touchStartPos.value.x);
const offsetY = Math.abs(touch.clientY - touchStartPos.value.y);
// 10px
if (offsetX > 10 || offsetY > 10) {
if (longPressTimer.value) {
clearTimeout(longPressTimer.value);
longPressTimer.value = null;
}
}
}
const handleTouchEnd = () => {
if (longPressTimer.value) {
clearTimeout(longPressTimer.value);
longPressTimer.value = null;
}
}
const getTotalCount = (goodsList) => {
if (!goodsList || !goodsList.length) return 0;
return goodsList.reduce((sum, item) => sum + (Number(item.count) || 1), 0);
@ -335,6 +447,8 @@ const goToDetail = (item) => {
margin-bottom: 18rpx;
.goods-img {
height: 92px;
width: 92px;
min-width: 178rpx;
min-height: 178rpx;
border-radius: 12rpx;
@ -342,6 +456,8 @@ const goToDetail = (item) => {
flex-shrink: 0;
&.refunding {
width: 74px;
height: 74px;
min-width: 142rpx;
min-height: 142rpx;
}
@ -367,9 +483,7 @@ const goToDetail = (item) => {
font-size: 26rpx;
color: #00032A;
line-height: 36rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
white-space: nowrap;
overflow: hidden;
flex: 1;
margin-right: 18rpx;

View File

@ -18,11 +18,11 @@
"key": "refunding"
},
{
"label": "评价",
"label": "交易成功",
"key": "success"
},
{
"label": "已取消",
"label": "交易关闭",
"key": "closed"
}
],
@ -45,11 +45,11 @@
"coupons": "",
"goodsList": [
{
"image": "/static/image/shopping/jingdong/product/shopping/lv.png",
"title": "【官方正品】路易威登 经典老花手提包",
"specs": "经典老花;手提包",
"price": "23979.25",
"oriPrice": "23979.25",
"image": "",
"title": "",
"specs": "",
"price": "",
"oriPrice": "",
"count": 1,
"tags": "七天无理由退换"
}
@ -163,37 +163,37 @@
"title": "Apple iPhone 17 Pro Max",
"specs": "Apple/苹果 iPhone 17 Pro Max 1TB 星宇橙色",
"price": "10999.00",
"oriPrice": "12999.00",
"oriPrice": " ",
"count": 1,
"tags": "免费上门退换 七天无理由退货"
}
],
"totalPrice": "10999.00",
"platformDiscount": "200.00",
"platformDiscount": "",
"storeDiscount": "",
"orderId": "2026031121001039760581201016",
"orderInfo": [
{
"label": "发货时间",
"key": "deliveryTime",
"value": "2026-03-11 09:48:05",
"value": "",
"type": "time"
},
{
"label": "付款时间",
"key": "paymentTime",
"value": "2026-03-11 09:48:05",
"value": "",
"type": "time"
},
{
"label": "创建时间",
"key": "createTime",
"value": "2026-03-11 09:48:05",
"value": "",
"type": "time"
},
{
"label": "支付宝交易号",
"key": "alipayTransactionNum",
"value": "2026031121001039760581201016",
"value": "",
"type": "number"
},
{
@ -234,8 +234,8 @@
}
],
"totalPrice": "266.00",
"platformDiscount": "30.00",
"storeDiscount": "20.00",
"platformDiscount": "",
"storeDiscount": "",
"points": "10.00",
"coupons": "5.00",
"orderId": "2026031121001039760581201016",
@ -243,31 +243,31 @@
{
"label": "成交时间",
"key": "deliveryTime",
"value": "2026-03-11 09:48:05",
"value": "",
"type": "time"
},
{
"label": "发货时间",
"key": "deliveryTime",
"value": "2026-03-11 09:48:05",
"value": "",
"type": "time"
},
{
"label": "付款时间",
"key": "paymentTime",
"value": "2026-03-11 09:48:05",
"value": "",
"type": "time"
},
{
"label": "创建时间",
"key": "createTime",
"value": "2026-03-11 09:48:05",
"value": "",
"type": "time"
},
{
"label": "支付宝交易号",
"key": "alipayTransactionNum",
"value": "2026031121001039760581201016",
"value": "",
"type": "number"
},
{
@ -311,25 +311,26 @@
}
],
"totalPrice": "8999.00",
"platformDiscount": "1000.00",
"platformDiscount": "",
"storeDiscount": "",
"orderId": "2026031121001039760581201016",
"orderInfo": [
{
"label": "成交时间",
"key": "deliveryTime",
"value": "2026-03-11 09:48:05",
"value": "",
"type": "time"
},
{
"label": "创建时间",
"key": "createTime",
"value": "2026-03-11 09:48:05",
"value": "",
"type": "time"
},
{
"label": "支付宝交易号",
"key": "alipayTransactionNum",
"value": "2026031121001039760581201016",
"value": "",
"type": "number"
},
{
@ -354,6 +355,8 @@
"statusDesc": "平台支持退款",
"shopType": "taobao",
"refundMoney": "199.00",
"refundIcon": 1,
"productImgUrl": "/static/image/shopping/taobao/detail/refund/product1.png",
"goodsList": [
{
"image": "",
@ -371,36 +374,150 @@
{
"label": "退款原因",
"key": "refundReason",
"value": "不需要了",
"value": "七天无理由退货",
"type": "text"
},
{
"label": "退款金额",
"key": "refunMoney",
"value": "199.00",
"type": "money"
"value": "",
"type": "digit"
},
{
"label": "退款完结",
"key": "refunTime",
"value": "2026-3-11 10:48",
"type": "date"
"value": "",
"type": "time"
},
{
"label": "申请时间",
"key": "applyTime",
"value": "2026-3-11 10:48",
"type": "date"
"value": "",
"type": "time"
},
{
"label": "退款编号",
"key": "refundId",
"value": "2026031121001039760581201016",
"value": "",
"type": "number"
}
],
"statusDesc1": "退回支付宝",
"statusDesc2": "您已享受全额保障5.56元"
}
},
// "购物随机产品列表"
"shoppingProductList": [
{
"shopType": "taobao",
"shopName": "京东数码自营旗舰店",
"totalPrice": "0",
"carriage": "0.00",
"discount": "0",
"goodsList": [
{
"image": "/static/image/shopping/jingdong/product/shopping/xianka.png",
"name": "",
"title": "华硕 TUF 5090显卡",
"specs": "5090旗舰算力 水冷夜神OC",
"tags": "不支持7天无理由退货",
"price": "39849.00",
"count": "1"
}
]
},
{
"shopType": "tianmao",
"shopName": "Apple 产品京东自营旗舰店",
"totalPrice": "",
"platformDiscount": "10.00",
"storeDiscount": "20.00",
"goodsList": [
{
"image": "/static/image/shopping/jingdong/product/shopping/iphone.png",
"name": "Apple iPhone 17 Pro",
"title": "Apple/苹果 iPhone 17 Pro Max 1TB 星宇橙色",
"specs": "星宇橙色全网通5G",
"tags": "免费上门退换 七天无理由退货",
"price": "12999.00",
"count": "1"
}
]
},
{
"shopType": "taobao",
"shopName": "路易威登京东官方旗舰店",
"totalPrice": "",
"platformDiscount": "50.00",
"storeDiscount": "8.00",
"goodsList": [
{
"image": "/static/image/shopping/jingdong/product/shopping/lv.png",
"name": "LV",
"title": "路易威登 经典老花手提包",
"specs": "经典老花;手提包",
"tags": "次日达",
"price": "23979.25",
"count": "1"
}
]
},
{
"shopType": "tianmao",
"shopName": "索尼SONY数码京东官方旗舰店",
"totalPrice": "15499.00",
"platformDiscount": "1.32",
"storeDiscount": "2.3",
"goodsList": [
{
"image": "/static/image/shopping/jingdong/product/shopping/sony.png",
"name": "Sony",
"title": "索尼SONYAlpha 7 IV 全画幅微单数码相机",
"specs": "单机身不含镜头约3300万有效像素",
"tags": "厂家发货",
"price": "15499.00",
"count": "1"
}
]
},
{
"shopType": "tianmao",
"shopName": "京东超市-五粮液自营店",
"totalPrice": "2198.00",
"platformDiscount": "100.00",
"storeDiscount": "200.00",
"goodsList": [
{
"image": "/static/image/shopping/jingdong/product/shopping/wuliangye.png",
"name": "五粮液",
"title": "五粮液 普五 第八代 浓香型白酒 52度 500ml*2瓶",
"specs": "500ml*2礼盒装浓香型",
"tags": "211限时达",
"price": "1099.00",
"count": "2"
}
]
},
{
"shopType": "taobao",
"shopName": "戴森Dyson京东自营官方旗舰店",
"totalPrice": "3299.00",
"platformDiscount": "150.00",
"storeDiscount": "200.00",
"goodsList": [
{
"image": "/static/image/shopping/jingdong/product/shopping/dyson_v12.png",
"name": "戴森",
"title": "戴森(Dyson) V12 Detect Slim 无绳吸尘器",
"specs": "轻量版;激光探测;轻量吸尘器",
"tags": "次日达",
"price": "3299.00",
"count": "1"
}
]
}
},
],
//
"defualtData": [
{
"id": "202605110001",
@ -576,248 +693,7 @@
"statusDesc1": "已签收",
"statusDesc2": "【上海市】 您已在上海市浦东新区汤臣一品完成取件",
"confirmReceiptCountdown": "9天7小时"
},
{
"id": "202605110008",
"orderType": "shopping",
"shopName": "Apple 官方旗舰店",
"statusType": "wait_recv",
"address": "上海市浦东新区汤臣一品",
"userName": "张三",
"phone": "13812345678",
"isSignFor": false,
"shopType": "taobao",
"goodsList": [
{
"image": "/static/image/shopping/jingdong/product/shopping/iphone.png",
"title": "Apple iPhone 17 Pro Max",
"specs": "Apple/苹果 iPhone 17 Pro Max 1TB 星宇橙色",
"price": "10999.00",
"oriPrice": "12999.00",
"count": 1,
"tags": "免费上门退换 七天无理由退货"
}
],
"totalPrice": "10999.00",
"platformDiscount": "200.00",
"orderId": "2026031121001039760581201016",
"orderInfo": [
{
"label": "发货时间",
"key": "deliveryTime",
"value": "2026-03-11 09:48:05",
"type": "time"
},
{
"label": "付款时间",
"key": "paymentTime",
"value": "2026-03-11 09:48:05",
"type": "time"
},
{
"label": "创建时间",
"key": "createTime",
"value": "2026-03-11 09:48:05",
"type": "time"
},
{
"label": "支付宝交易号",
"key": "alipayTransactionNum",
"value": "2026031121001039760581201016"
},
{
"label": "交易快照",
"key": "transactionSnapshot",
"value": "发生交易争执时,可作为判断依据"
},
{
"label": "支付方式",
"key": "paymentMethod",
"value": "支付宝支付"
}
],
"statusDesc1": "预计明天送达",
"statusDesc2": "【上海市】 快件已发往 上海转运中心,下一站浦东新区"
},
{
"id": "202605110005",
"orderType": "shopping",
"shopName": "三只松鼠旗舰店",
"statusType": "success",
"shopType": "taobao",
"address": "上海市浦东新区汤臣一品",
"userName": "张三",
"phone": "13812345678",
"goodsList": [
{
"image": "",
"title": "三只松鼠 坚果大礼包 每日坚果 送礼佳品 1498g",
"specs": "颜色分类: 坚果礼盒1498g",
"price": "128.00",
"oriPrice": "158.00",
"count": 2,
"tags": "正品保障"
}
],
"totalPrice": "266.00",
"platformDiscount": "30.00",
"storeDiscount": "20.00",
"points": "10.00",
"coupons": "5.00",
"orderId": "2026031121001039760581201016",
"orderInfo": [
{
"label": "成交时间",
"key": "deliveryTime",
"value": "2026-03-11 09:48:05",
"type": "time"
},
{
"label": "发货时间",
"key": "deliveryTime",
"value": "2026-03-11 09:48:05",
"type": "time"
},
{
"label": "付款时间",
"key": "paymentTime",
"value": "2026-03-11 09:48:05",
"type": "time"
},
{
"label": "创建时间",
"key": "createTime",
"value": "2026-03-11 09:48:05",
"type": "time"
},
{
"label": "支付宝交易号",
"key": "alipayTransactionNum",
"value": "2026031121001039760581201016"
},
{
"label": "交易快照",
"key": "transactionSnapshot",
"value": "发生交易争执时,可作为判断依据"
},
{
"label": "收货信息",
"key": "shippingInfo",
"value": ""
},
{
"label": "支付方式",
"key": "paymentMethod",
"value": "支付宝支付"
}
]
},
{
"id": "202605110006",
"orderType": "shopping",
"shopName": "Apple Store 官方旗舰店",
"statusType": "closed",
"shopType": "tianmao",
"address": "上海市浦东新区汤臣一品",
"userName": "张三",
"phone": "13812345678",
"goodsList": [
{
"image": "",
"title": "Apple iPhone 15 Pro (A3104) 256GB 原色钛金属 5G手机",
"specs": "颜色分类: 原色钛金属; 内存容量: 256GB",
"price": "8999.00",
"oriPrice": "9999.00",
"count": 1,
"tags": "正品保障"
}
],
"totalPrice": "8999.00",
"platformDiscount": "1000.00",
"orderId": "2026031121001039760581201016",
"orderInfo": [
{
"label": "成交时间",
"key": "deliveryTime",
"value": "2026-03-11 09:48:05",
"type": "time"
},
{
"label": "创建时间",
"key": "createTime",
"value": "2026-03-11 09:48:05",
"type": "time"
},
{
"label": "支付宝交易号",
"key": "alipayTransactionNum",
"value": "2026031121001039760581201016"
},
{
"label": "交易快照",
"key": "transactionSnapshot",
"value": "发生交易争执时,可作为判断依据"
},
{
"label": "收货信息",
"key": "shippingInfo",
"value": ""
}
]
},
{
"id": "202605110007",
"orderType": "shopping",
"shopName": "优衣库官方旗舰店",
"statusType": "refunding",
"statusDesc": "平台支持退款",
"shopType": "taobao",
"refundMoney": "199.00",
"goodsList": [
{
"image": "",
"title": "UNIQLO 优衣库 男装/女装 摇粒绒拉链运动开衫(长袖) 463351",
"specs": "颜色分类: 藏青色; 尺码: L",
"price": "199.00",
"count": 1,
"tags": "正品保障",
"refundStatus": "退款成功"
}
],
"totalPrice": "199.00",
"orderId": "2026031121001039760581201016",
"orderInfo": [
{
"label": "退款原因",
"key": "refundReason",
"value": "不需要了",
"type": "text"
},
{
"label": "退款金额",
"key": "refunMoney",
"value": "199.00",
"type": "money"
},
{
"label": "退款完结",
"key": "refunTime",
"value": "2026-3-11 10:48",
"type": "date"
},
{
"label": "申请时间",
"key": "applyTime",
"value": "2026-3-11 10:48",
"type": "date"
},
{
"label": "退款编号",
"key": "refundId",
"value": "2026031121001039760581201016"
}
]
},
}
// {
// "id": "202605110008",
// "orderType": "waimai",

View File

@ -12,7 +12,7 @@
<image class="search-icon" src="/static/image/shopping/jingdong/search-icon.png"
mode="aspectFit">
</image>
<input class="input" type="text" placeholder="搜索我的订单" :disabled="true" />
<input class="input" type="text" placeholder="搜索我的订单" />
</view>
</template>
<template v-slot:right>
@ -32,6 +32,9 @@
</view>
</template>
</nav-bar>
<nav-bar v-else title="拼图" bgColor="#EFEFEF" noBack @back="closeImage" isRightButton
@right-click="confirmImage">
</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)">
@ -75,29 +78,141 @@
<uni-icons type="right" size="14" color="#5E6367"></uni-icons>
</view>
</view>
<listCard :list="displayList" @click-item="goDetail" />
<listCard v-if="displayList.length > 0" :list="displayList" @click-item="goDetail"
@longpress="onItemLongPress" />
<view v-else class="null-data-box flex-center flex-column">
<image style="width: 254rpx;height: 200rpx;" src="/static/image/shopping/taobao/null.png"></image>
<text
style="font-size: 28rpx;color: #7C8495;line-height: 28rpx;margin-top: 16rpx;font-weight: 500;">您还没有相关的订单</text>
</view>
<view class="bottom-fixed" style="height: 1000rpx;">
<view v-if="!selectedImage" class="upload-screenshot-box" @touchstart="handleTouchStart"
@touchend="handleTouchEnd">
<view v-if="!screenshotImage" 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 v-else class="screenshot-preview-box">
<image class="screenshot-preview" :src="screenshotImage" mode="widthFix"></image>
</view>
<!-- <image v-else class="w100 h100" :src="screenshotImage" mode="widthFix"></image> -->
</view>
<view v-else class="upload-screenshot-box scroll-image-box">
<scroll-view class="image-box" style="width: 100%;height: 100%;" scroll-y :show-scrollbar="false"
@scroll="onImageScroll">
<image class="crop-image-target" style="width:100%;" :src="selectedImage" mode="widthFix">
</image>
</scroll-view>
<view class="dashed-line-box">
<view class="dashed-line-text">我是分割线</view>
</view>
</view>
<canvas canvas-id="crop-canvas"
style="position: fixed; left: -9999px; width: 750rpx; height: 100vh; pointer-events: none;"></canvas>
</view>
</scroll-view>
</view>
<!-- 自定义长按上下文菜单 -->
<view v-if="menuState.show" class="menu-mask" @click="menuState.show = false" @touchmove.stop.prevent>
<view class="menu-content" :style="{ top: menuState.y + 'px', left: menuState.x + 'px' }">
<view class="menu-item" @click.stop="handleMenuAction('edit')">
<uni-icons type="compose" size="18" color="#1A1A1A"></uni-icons>
<text>编辑</text>
</view>
<view class="menu-line"></view>
<view class="menu-item" @click.stop="handleMenuAction('delete')">
<uni-icons type="trash" size="18" color="#FF4D4F"></uni-icons>
<text style="color: #FF4D4F;">删除</text>
</view>
</view>
</view>
<!-- 水印 -->
<!-- <view v-if="$isVip()">
<watermark dark="light" source="uni_alipay_shopping_taobao" />
<liu-drag-button :canDocking="false" @clickBtn="$goRechargePage('watermark', 'uni_alipay_shopping_taobao')">
<c-lottie ref="cLottieRef" :src='$watermark()' width="94px" height='74px' :loop="true"></c-lottie>
</liu-drag-button>
</view> -->
<!-- 切换底部图片弹窗 -->
<uni-popup ref="bottomImgPopup" type="center">
<view class="bottom-img-popup-card">
<view class="p-header">选择底部商品图</view>
<view class="p-content">
<view class="option-item" @click="selectBottomImg(1)">
<image class="preview-img" src="/static/image/shopping/taobao/bottom-bg-1.png" mode="aspectFill">
</image>
<view class="info">
<text class="name">商品图片 1</text>
<text class="desc">默认背景布局</text>
</view>
<uni-icons type="right" size="16" color="#C7C7CC"></uni-icons>
</view>
<view class="option-item" @click="selectBottomImg(2)">
<image class="preview-img" src="/static/image/shopping/taobao/bottom-bg-2.png" mode="aspectFill">
</image>
<view class="info">
<text class="name">商品图片 2</text>
<text class="desc">备选商品排列</text>
</view>
<uni-icons type="right" size="16" color="#C7C7CC"></uni-icons>
</view>
<text
style="color: #949494;font-size: 24rpx;text-align: center;display: block;">*长按底部商品图片区域可上传自定义图片*</text>
</view>
<view class="p-footer" @click="bottomImgPopup.close()">取消</view>
</view>
</uni-popup>
</template>
<script setup>
import { ref, computed, onMounted, getCurrentInstance } from 'vue';
import { ref, computed, onMounted, getCurrentInstance, reactive } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { util } from '@/utils/common.js';
import listCard from './components/list-card/list-card.vue';
import { defualtData } from './json/order.json'
const mockList = ref(defualtData);
const instance = getCurrentInstance();
const mockList = ref([]);
const menuState = reactive({
show: false,
x: 0,
y: 0,
target: null
});
const bottomImgPopup = ref(null);
const selectBottomImg = (type) => {
const path = `/static/image/shopping/taobao/bottom-bg-${type}.png`;
screenshotImage.value = path;
uni.setStorageSync('taobao_screenshot', path);
bottomImgPopup.value.close();
uni.showToast({
title: '切换成功',
icon: 'success'
});
};
onShow(() => {
//
let storageData = uni.getStorageSync('taobaoShopping');
//
if (!storageData || (Array.isArray(storageData) && storageData.length === 0)) {
console.log('检测到淘宝订单缓存为空,注入初始默认数据');
storageData = JSON.parse(JSON.stringify(defualtData));
uni.setStorageSync('taobaoShopping', storageData);
}
mockList.value = storageData || [];
// ()
let savedScreenshot = uni.getStorageSync('taobao_screenshot');
if (!savedScreenshot) {
savedScreenshot = '/static/image/shopping/taobao/bottom-bg-1.png';
uni.setStorageSync('taobao_screenshot', savedScreenshot);
}
screenshotImage.value = savedScreenshot;
});
//
const buttonGroup = [
@ -105,7 +220,7 @@ const buttonGroup = [
name: "新增购物订单",
click: () => {
uni.navigateTo({
url: '/pages/shopping/taobao/add-order/add-order'
url: '/pages/shopping/taobao/add-shopping-order/add-shopping-order'
});
}
}, {
@ -115,15 +230,17 @@ const buttonGroup = [
title: '开发中,敬请期待',
icon: 'none'
});
// uni.navigateTo({
// url: '/pages/shopping/jingdong/add-waimai/add-waimai'
// });
}
}, {
name: "切换底部商品图片",
click: () => {
bottomImgPopup.value.open();
}
},
]
const displayList = computed(() => {
let list = mockList.value;
let list = JSON.parse(JSON.stringify(mockList.value));
// 1. Tab (orderType)
if (currentTab.value === 1) { //
@ -135,15 +252,14 @@ const displayList = computed(() => {
// 2. (currentFilter)
if (currentFilter.value > 0) {
const filterName = filterList.value[currentFilter.value]?.name;
//
const statusMap = {
'待付款': ['wait_pay'],
'待发货': ['wait_send'],
'待收货': ['wait_recv'],
'退款/售后': ['refunding'],
'已关闭': ['closed'],
'待评价': ['success'] // success
'评价': ['success'],
'已关闭': ['closed']
};
const targetStatus = statusMap[filterName];
@ -152,6 +268,19 @@ const displayList = computed(() => {
}
}
// 3. ( || )
list.sort((a, b) => {
const getTime = (order) => {
if (!order.orderInfo) return '';
const create = order.orderInfo.find(i => i.key === 'createTime')?.value;
const apply = order.orderInfo.find(i => i.key === 'applyTime')?.value;
return create || apply || '';
};
const timeA = getTime(a);
const timeB = getTime(b);
return timeB.localeCompare(timeA); //
});
return list;
});
@ -162,6 +291,7 @@ const filterList = ref([
{ name: '待发货' },
{ name: '待收货' },
{ name: '退款/售后' },
{ name: '评价' },
{ name: '已关闭' }
]);
@ -173,6 +303,170 @@ const tabList = ref([
{ name: '飞猪', icon: '/static/image/shopping/taobao/lvxing.png', disabled: true }
]);
//
const screenshotImage = ref('');
const selectedImage = ref('');
const scrollTop = ref(0);
let longPressTimer = null;
// -
const chooseImage = () => {
if (selectedImage.value) return;
uni.chooseImage({
count: 1,
sourceType: ['album'],
success: (res) => {
selectedImage.value = res.tempFilePaths[0];
}
});
};
//
const handleTouchStart = (e) => {
const systemInfo = uni.getSystemInfoSync();
if (systemInfo.platform === 'ios' && systemInfo.safeAreaInsets?.bottom) {
const clientY = e.touches[0].clientY;
const windowHeight = systemInfo.windowHeight;
if (clientY > windowHeight - systemInfo.safeAreaInsets.bottom) {
return;
}
}
longPressTimer = setTimeout(() => {
uni.vibrateShort();
chooseImage();
}, 1200);
};
const handleTouchEnd = () => {
if (longPressTimer) {
clearTimeout(longPressTimer);
longPressTimer = null;
}
};
//
const onImageScroll = (e) => {
scrollTop.value = e.detail.scrollTop;
};
//
const confirmImage = () => {
uni.showLoading({
title: '处理中...'
})
const query = uni.createSelectorQuery().in(instance)
//
query.select('.image-box').boundingClientRect()
query.select('.crop-image-target').boundingClientRect()
query.exec(res => {
if (!res[0] || !res[1]) {
uni.hideLoading()
return
}
console.log('rects', res)
const container = res[0] //
const image = res[1] //
// ( / /?)
// canvas
// canvas drawImage : img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight
//
uni.getImageInfo({
src: selectedImage.value,
success: (imgInfo) => {
const scale = imgInfo.width / image.width // 图片 原始宽 / 渲染宽
const sTop = scrollTop.value * scale // Y
const sHeight = container.height * scale //
// widthFix
const sWidth = imgInfo.width
// (使)
// canvasContext使 pixelRatio
// uni-app canvas-id (px)
// canvas
const canvasW = container.width
const canvasH = container.height
const ctx = uni.createCanvasContext('crop-canvas', instance)
//
ctx.clearRect(0, 0, canvasW, canvasH)
//
// drawImage(imageResource, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
ctx.drawImage(
imgInfo.path,
0, sTop, sWidth, sHeight, //
0, 0, canvasW, canvasH //
)
ctx.draw(false, () => {
uni.canvasToTempFilePath({
canvasId: 'crop-canvas',
width: canvasW,
height: canvasH,
destWidth: sWidth, // 使,
destHeight: sHeight, // 使,
success: (res) => {
console.log('crop success (temp)', res
.tempFilePath)
//
uni.saveFile({
tempFilePath: res.tempFilePath,
success: (saveRes) => {
console.log('save success (saved)', saveRes.savedFilePath)
screenshotImage.value = saveRes.savedFilePath
selectedImage.value = '' //
setTimeout(() => {
plus.navigator.setStatusBarStyle("light");
}, 200)
//
uni.setStorageSync('taobao_screenshot', screenshotImage.value)
uni.hideLoading()
},
fail: (err) => {
console.error('saveFile fail', err)
uni.hideLoading()
uni.showToast({
title: '保存失败',
icon: 'none'
})
}
})
},
fail: (err) => {
console.error(err)
uni.hideLoading()
uni.showToast({
title: '裁剪失败',
icon: 'none'
})
}
}, instance)
})
},
fail: () => {
uni.hideLoading()
uni.showToast({
title: '图片加载失败',
icon: 'none'
})
}
})
})
}
//
const closeImage = () => {
selectedImage.value = '';
};
/**
* 切换tab
* @param index
@ -194,10 +488,10 @@ const updateFilterList = () => {
// tab
switch (currentTab.value) {
case 0:
sourceList = ["全部", "待付款", "待发货", "待收货", "退款/售后", "已关闭"];
sourceList = ["全部", "待付款", "待发货", "待收货", "退款/售后", "评价", "已关闭"];
break;
case 1:
sourceList = ["全部", "待付款", "待发货", "待收货", "退款/售后", "已关闭"];
sourceList = ["全部", "待付款", "待发货", "待收货", "退款/售后", "评价", "已关闭"];
break;
case 2:
sourceList = ["全部", "待付款", "待发货", "待收货", "待评价", "已关闭"];
@ -229,6 +523,89 @@ const goDetail = (item) => {
util.goPage(`/pages/shopping/taobao/shopping-order-detail/shopping-order-detail?id=${item.id}`)
}
/**
* 长按管理订单 - 记录坐标并显示自定义菜单
*/
const onItemLongPress = (data) => {
const { item, x, y } = data;
menuState.target = item;
// 60px 40px
//
const screenWidth = uni.getSystemInfoSync().windowWidth;
let posX = x - 40;
if (posX + 120 > screenWidth) {
posX = screenWidth - 130;
}
menuState.x = Math.max(10, posX);
menuState.y = y - 80;
menuState.show = true;
};
/**
* 处理菜单点击
*/
const handleMenuAction = (action) => {
const item = menuState.target;
menuState.show = false;
if (!item) return;
if (action === 'edit') {
uni.navigateTo({
url: `/pages/shopping/taobao/add-shopping-order/add-shopping-order?id=${item.id}&isEdit=true`
});
} else if (action === 'delete') {
uni.showModal({
title: '提示',
content: '确定要删除该订单吗?',
confirmColor: '#FF7824',
success: (modalRes) => {
if (modalRes.confirm) {
deleteOrder(item.id);
}
}
});
}
};
/**
* 从缓存执行删除
*/
const deleteOrder = (id) => {
let list = uni.getStorageSync('taobaoShopping') || [];
// 1.
const target = list.find(item => String(item.id) === String(id));
if (target) {
const imagesToClear = [];
if (target.goodsList?.[0]?.image) imagesToClear.push(target.goodsList[0].image);
if (target.productImgUrl) imagesToClear.push(target.productImgUrl);
imagesToClear.forEach(path => {
if (path && (path.includes('_doc') || path.includes('store_'))) {
uni.removeSavedFile({
filePath: path,
success: () => console.log('删除订单关联图片成功:', path),
fail: (err) => console.log('图片文件不存在或已删除:', path)
});
}
});
}
// 2.
list = list.filter(item => String(item.id) !== String(id));
//
uni.setStorageSync('taobaoShopping', list);
// UI
mockList.value = list;
uni.showToast({
title: '已删除',
icon: 'success'
});
};
</script>
@ -450,7 +827,252 @@ const goDetail = (item) => {
}
}
}
.menu-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
background-color: transparent;
}
.menu-content {
position: absolute;
width: 240rpx;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 16rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
border: 1px solid rgba(255, 255, 255, 0.2);
overflow: hidden;
animation: menu-show 0.15s ease-out;
}
.menu-item {
display: flex;
align-items: center;
padding: 24rpx 32rpx;
transition: background 0.2s;
&:active {
background-color: #f5f5f5;
}
text {
font-size: 28rpx;
color: #1A1A1A;
margin-left: 16rpx;
font-weight: 500;
}
}
.menu-line {
height: 1px;
background-color: #EEEEEE;
margin: 0 20rpx;
}
@keyframes menu-show {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
.null-data-box {
padding: 68rpx;
}
.bottom-fixed {
display: flex;
flex-direction: column;
.upload-screenshot-box {
width: 100%;
flex: 1;
min-height: 540rpx;
background-color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
position: relative;
.upload-screenshot {
width: 92rpx;
height: 92rpx;
}
.upload-screenshot-content {
width: 100%;
height: 100%;
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;
}
}
.screenshot-preview-box {
width: 100%;
height: 100%;
display: flex;
align-items: flex-start;
// flex-direction: column;
justify-content: center;
.screenshot-preview {
width: 100%;
height: 100%;
}
}
.scroll-image-box {
width: 100%;
min-height: 0; // flex
// overflow: hidden; // scroll-view
position: relative;
}
.dashed-line-box {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
border: 4rpx dashed #ffffff;
pointer-events: none;
.dashed-line-text {
height: 44rpx;
line-height: 44rpx;
width: 180rpx;
padding: 0 20rpx;
border-radius: 8rpx;
color: #1777FF;
font-size: 24rpx;
font-weight: 500;
background-color: #fff;
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -50%);
}
}
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.8);
z-index: 999;
.mask-icon {
position: absolute;
top: 50%;
right: 52rpx;
transform: translateY(-25%);
width: 360rpx;
height: 360rpx;
}
}
}
}
.bottom-img-popup-card {
width: 600rpx;
background-color: #FFFFFF;
border-radius: 32rpx;
overflow: hidden;
box-shadow: 0 20rpx 40rpx rgba(0, 0, 0, 0.15);
.p-header {
padding: 40rpx 0 20rpx;
text-align: center;
font-size: 32rpx;
font-weight: 600;
color: #1A1A1A;
}
.p-content {
padding: 20rpx 30rpx;
.option-item {
display: flex;
align-items: center;
padding: 24rpx;
margin-bottom: 20rpx;
background-color: #F8F9FA;
border-radius: 20rpx;
transition: all 0.2s;
&:active {
background-color: #F0F2F5;
transform: scale(0.98);
}
.preview-img {
width: 100rpx;
height: 100rpx;
border-radius: 12rpx;
background-color: #EEE;
}
.info {
flex: 1;
margin: 0 24rpx;
display: flex;
flex-direction: column;
.name {
font-size: 28rpx;
font-weight: 500;
color: #1A1A1A;
}
.desc {
font-size: 22rpx;
color: #8E8E93;
margin-top: 4rpx;
}
}
}
}
.p-footer {
height: 100rpx;
line-height: 100rpx;
text-align: center;
border-top: 1rpx solid #F0F2F5;
font-size: 30rpx;
color: #8E8E93;
&:active {
background-color: #F8F9FA;
}
}
}
</style>
<style>
@import '@/common/main.css';
page {
background-color: #F1F5F8;
}
</style>

View File

@ -2,30 +2,26 @@
<nav-bar title="订单详情" bgColor="#FFFFFF" isBack :buttonGroup="buttonGroup" @button-click="util.clickTitlePopupButton"
tipLayerType="taobao-shopping-order-detail-tip" isTipLayer tipLayerText="编辑订单信息">
<template v-slot:left>
<image @click="util.goBack" class="back-icon"
:src="`/static/image/shopping/taobao/detail/${order.statusType == 'refunding' ? 'refund-back' : 'back'}.png`"
<image v-if="order" @click="util.goBack" class="back-icon"
:src="`/static/image/shopping/taobao/detail/${order?.statusType == 'refunding' ? 'refund-back' : 'back'}.png`"
mode="aspectFit"></image>
</template>
<template v-slot:center>
<view v-if="order.statusType == 'refunding'" class="refunding-title-box">
<image class="icon" src="/static/image/shopping/taobao/detail/refund/finish.png">
</image>
<text>商家处理</text>
<image class="next icon" style="width: 20rpx;height: 20rpx;"
src="/static/image/shopping/taobao/detail/refund/next.png">
</image>
<image class="icon" src="/static/image/shopping/taobao/detail/refund/finish.png">
</image>
<text>寄回商品</text>
<image class="icon next" style="width: 20rpx;height: 20rpx;"
src="/static/image/shopping/taobao/detail/refund/next.png">
</image>
<text>3退款结束</text>
</view>
<view v-else class="title-box">
<view class="title">{{ titleList[order.statusType] }}</view>
<view v-if="order.statusType == 'wait_recv' && order.isSignFor" class="desc">
还剩{{ order.confirmReceiptCountdown }}自动确认</view>
<view v-if="order" class="center-content">
<view v-if="order.statusType == 'refunding'" class="refunding-title-box">
<image class="icon" src="/static/image/shopping/taobao/detail/refund/finish.png"></image>
<text>商家处理</text>
<image class="next icon" src="/static/image/shopping/taobao/detail/refund/next.png"></image>
<image class="icon" src="/static/image/shopping/taobao/detail/refund/finish.png"></image>
<text>寄回商品</text>
<image class="icon next" src="/static/image/shopping/taobao/detail/refund/next.png"></image>
<text>3退款结束</text>
</view>
<view v-else class="title-box">
<view class="title">{{ titleList[order.statusType] }}</view>
<view v-if="order.statusType == 'wait_recv' && order.isSignFor" class="desc">
还剩{{ order.confirmReceiptCountdown }}自动确认</view>
</view>
</view>
</template>
<template v-slot:right>
@ -36,7 +32,7 @@
</template>
</nav-bar>
<view v-if="order.statusType != 'refunding'">
<view v-if="order && order.statusType != 'refunding'">
<view v-if="order.statusType == 'wait_recv'" class="card status-box">
<image style="width: 34rpx;height: 34rpx;flex-shrink: 0;margin-right: 8rpx;"
:src="`/static/image/shopping/taobao/detail/${order.statusType == 'wait_recv' && order.isSignFor ? 'yiqianshou' : 'yunshuzhong'}.png`"
@ -100,7 +96,8 @@
<view class="goods-title flex-justify-between flex-align-center">
<view class="title-box flex ">
<text class="title flex-1">{{ item.title }}</text>
<uni-icons class="uni-icon" type="down" size="12" color="#7C8495"></uni-icons>
<uni-icons v-if="item.title.length > 15" class="uni-icon" type="down" size="12"
color="#7C8495"></uni-icons>
</view>
<text class="price wx-font-medium flex-align-center"><text class="small"></text>{{
@ -112,13 +109,14 @@
<view class="goods-specs flex-justify-between flex-align-center">
<view class="title-box flex ">
<text class="title flex-1">{{ item.specs }}</text>
<uni-icons class="uni-icon" type="down" size="12" color="#7C8495"></uni-icons>
<uni-icons v-if="item.specs.length > 15" class="uni-icon" type="down" size="12"
color="#7C8495"></uni-icons>
</view>
<text
v-if="item.oriPrice && Number(item.oriPrice) > 0 && Number(item.oriPrice) > Number(item.price)"
class="price wx-font-medium flex-align-center"><text class="small"></text>{{
item.oriPrice }}</text>
Number(item.oriPrice).toFixed(2) }}</text>
</view>
<view class="inline-tag flex-justify-between flex-align-center">
<text class="desc flex-1">
@ -219,8 +217,18 @@
</view>
</view>
</view>
<view class="card service-card flex-align-center flex-justify-between">
<text class="label">服务保障</text>
<view class="">
<text class="more">查看更多</text>
<uni-icons type="right" size="14" color="#EF7518"></uni-icons>
</view>
</view>
<view style="margin-top: 16rpx;">
<image style="width: 100%;" :src="screenshotImage" mode="widthFix"></image>
</view>
</view>
<view class="" v-else>
<view v-else-if="order.statusType == 'refunding'">
<view class="card refund-box">
<view class="card flex-column flex-align-center">
<view class="main-text">退款成功</view>
@ -228,8 +236,9 @@
<view class="line"></view>
</view>
<view class="flex-align-center refund-money-box" style="line-height: 34rpx;">
<image style="width: 34rpx;height: 34rpx;margin-right: 16rpx;" src=""></image>
<text class="label flex-1">退回支付宝小荷包</text>
<image style="width: 34rpx;height: 34rpx;margin-right: 16rpx;"
:src="`/static/image/shopping/taobao/detail/refund/icon${order.refundIcon}.png`"></image>
<text class="label flex-1">{{ order.statusDesc1 }}</text>
<text class="wx-font-medium">
<text style="font-size: 28rpx;"></text>
<text style="font-size: 38rpx;">{{ Number(order.refundMoney).toFixed(2).split('.')[0] }}.</text>
@ -241,7 +250,7 @@
src="/static/image/shopping/taobao/detail/refund/yunfeibaozhang.png"></image>
<view>
<view class="label">运费保障</view>
<view class="desc">您已享受全额保障5.56</view>
<view class="desc">{{ order.statusDesc2 }}</view>
</view>
</view>
</view>
@ -276,6 +285,11 @@
</view>
</view>
</view>
<view class="product-img-card">
<image :src="order.productImgUrl || '/static/image/shopping/taobao/detail/refund/product1.png'"
style="width: 100%;" mode="widthFix">
</image>
</view>
<view class="card help-box">
<view class="flex-align-center card-title-box">
<image style="width: 34rpx;height: 34rpx;margin-right: 16rpx;"
@ -291,13 +305,14 @@
<view class="btn">运费谁承担</view>
</view>
</view>
<view class="bottom-template">
</view>
<view class="bottom-template">
</view>
</view>
<view class="bottom-box flex-justify-between flex-align-center">
<view v-if="order" class="bottom-box flex-justify-between flex-align-center">
<view class="left-icons flex">
<view class="icon-box" v-for="icon in bottomBtnList[order.statusType].icons" :key="icon.name">
<image style="width: 40rpx;height: 40rpx;"
@ -338,6 +353,22 @@ import { onLoad, onShow } from '@dcloudio/uni-app';
import { util } from '@/utils/common.js';
import { shoppingType, defualtData } from '../json/order.json'
//
const buttonGroup = [
{
name: "编辑订单",
click: () => {
if (order.value && order.value.id) {
uni.navigateTo({
url: `/pages/shopping/taobao/add-shopping-order/add-shopping-order?id=${order.value.id}&isEdit=true`
});
} else {
uni.showToast({ title: '订单数据未加载', icon: 'none' });
}
}
}
]
const screenshotImage = ref('')
const titleList = {
"wait_pay": "待付款",
"wait_send": "待发货",
@ -533,9 +564,9 @@ const bottomBtnList = {
}
}
const isFoldProductCard = ref(true)
const isFoldOrderInfoCard = ref(true)
const isFoldRefundOrderInfoCard = ref(true)
const isFoldProductCard = ref(false)
const isFoldOrderInfoCard = ref(false)
const isFoldRefundOrderInfoCard = ref(false)
const getGoodsTotalPrice = (list) => {
@ -543,7 +574,6 @@ const getGoodsTotalPrice = (list) => {
for (const key in list) {
totalPrice = totalPrice + Number(list[key].oriPrice ? list[key].oriPrice : list[key].price) * Number(list[key].count || 1)
}
console.log("11111111111", totalPrice)
return totalPrice.toFixed(2)
}
@ -554,18 +584,105 @@ const getGoodsTotalCount = (list) => {
}
return totalCount
}
let order = ref('')
let order = ref(null)
const currentId = ref(null);
let countdownTimer = null;
const loadOrderDetail = () => {
if (!currentId.value) return;
// 1. ()
const storageList = uni.getStorageSync('taobaoShopping') || [];
const target = storageList.find(item => String(item.id) === String(currentId.value));
if (target) {
order.value = JSON.parse(JSON.stringify(target));
console.log('从缓存加载订单详情成功');
//
if (order.value.statusType === 'wait_pay' && order.value.payCountdown) {
initCountdown();
}
} else {
// 2. JSON
const defaultTarget = defualtData.find((item) => String(item.id) === String(currentId.value));
if (defaultTarget) {
order.value = JSON.parse(JSON.stringify(defaultTarget));
console.log('从默认数据加载订单详情');
//
if (order.value.statusType === 'wait_pay' && order.value.payCountdown) {
initCountdown();
}
}
}
}
/**
* 初始化并启动倒计时
*/
const initCountdown = () => {
if (countdownTimer) clearInterval(countdownTimer);
// "HH : mm : ss" "HH:mm:ss"
const parseTimeToSeconds = (timeStr) => {
if (!timeStr) return 0;
//
const parts = timeStr.replace(/\s/g, '').split(':');
let seconds = 0;
if (parts.length === 3) {
seconds = parseInt(parts[0]) * 3600 + parseInt(parts[1]) * 60 + parseInt(parts[2]);
} else if (parts.length === 2) {
seconds = parseInt(parts[0]) * 60 + parseInt(parts[1]);
}
return isNaN(seconds) ? 0 : seconds;
};
// "HH : mm : ss"
const formatSecondsToTime = (totalSeconds) => {
if (totalSeconds <= 0) return "00:00:00";
const h = Math.floor(totalSeconds / 3600);
const m = Math.floor((totalSeconds % 3600) / 60);
const s = totalSeconds % 60;
const pad = (n) => String(n).padStart(2, '0');
return `${pad(h)}:${pad(m)}:${pad(s)}`;
};
let remainingSeconds = parseTimeToSeconds(order.value.payCountdown);
if (remainingSeconds <= 0) return;
countdownTimer = setInterval(() => {
remainingSeconds--;
if (remainingSeconds <= 0) {
order.value.payCountdown = "00 : 00 : 00";
clearInterval(countdownTimer);
//
// order.value.status = '';
} else {
order.value.payCountdown = formatSecondsToTime(remainingSeconds);
}
}, 1000);
};
onLoad((options) => {
console.log('shoppingType', shoppingType)
if (options?.id) {
order.value = defualtData.find((item) => item.id == options.id)
currentId.value = options.id;
}
})
onShow(() => {
loadOrderDetail();
//
const savedScreenshot = uni.getStorageSync('taobao_screenshot');
if (savedScreenshot) {
screenshotImage.value = savedScreenshot;
}
})
onUnmounted(() => {
if (countdownTimer) {
clearInterval(countdownTimer);
countdownTimer = null;
}
})
</script>
@ -1136,6 +1253,7 @@ onShow(() => {
.help-box {
padding: 30rpx 32rpx;
margin-bottom: 120rpx;
.card-title-box {
width: 100%;
@ -1201,6 +1319,29 @@ onShow(() => {
::v-deep .uni-navbar__header-btns {
width: 24px !important;
}
.product-img-card {
margin: 16rpx 0;
margin-bottom: 10rpx;
}
.service-card {
padding: 28rpx 32rpx;
line-height: 30rpx;
.label {
font-size: 30rpx;
color: #1A1A1A;
line-height: 30rpx;
font-weight: 500;
}
.more {
font-size: 26rpx;
color: #EF7518;
line-height: 28rpx;
}
}
</style>
<style>
@import '@/common/main.css';

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB