feat:评价区改造

This commit is contained in:
2026-08-06 18:50:25 +08:00
parent 8225be60c6
commit aa20d121f7
13 changed files with 3323 additions and 1325 deletions
+23 -5
View File
@@ -134,7 +134,7 @@ export function afterSaleDetail(data) {
export function cancelAfterSale(data) { export function cancelAfterSale(data) {
return request({ return request({
url: "/order/cancelAfterApply", url: "/order/cancelAfterApply",
method: "post", method: "post",
data, data,
}); });
} }
@@ -142,8 +142,8 @@ export function cancelAfterSale(data) {
// 寄回商品反馈 // 寄回商品反馈
export function returnGoodsFeedback(data) { export function returnGoodsFeedback(data) {
return request({ return request({
url: "/order/sendGoodsBack", url: "/order/sendGoodsBack",
method: "post", method: "post",
data, data,
}); });
} }
@@ -161,7 +161,7 @@ export function getExpressCompany() {
export function cancelOrder(data) { export function cancelOrder(data) {
return request({ return request({
url: "/order/cancelOrder", url: "/order/cancelOrder",
method: "post", method: "post",
data, data,
}); });
} }
@@ -170,7 +170,25 @@ export function cancelOrder(data) {
export function deleteOrderQuery(data) { export function deleteOrderQuery(data) {
return request({ return request({
url: "/order/deleteOrder", url: "/order/deleteOrder",
method: "post", method: "post",
data,
});
}
// 修改订单地址
export function updateOrderAddress(data) {
return request({
url: "/order/updateAddress",
method: "post",
data,
});
}
// 待发货订单申请修改地址
export function applyUpdateAddress(data) {
return request({
url: "/order/applyModifyShippingAddress",
method: "post",
data, data,
}); });
} }
+241 -42
View File
@@ -1,22 +1,69 @@
<template> <template>
<view class="parity-product-item" @click.stop="onClick"> <view class="parity-product-item-wrap">
<image class="top-img" :src="obj.url" mode="widthFix" lazy-load /> <!-- 样式 1 (图2样式) -->
<view class="shop-bottom-panel"> <view class="parity-product-item type-1" @click.stop="onClick" v-if="type == 1 || type == '1'">
<text class="title text-30 text-zu text-overflow"> <image class="top-img-1" :src="obj.url" mode="aspectFill" lazy-load />
{{ obj.title }} <view class="shop-bottom-panel-1">
</text> <view class="title-box">
<!-- 有优惠券 --> <text class="tag-badge" :style="{ backgroundColor: effectiveTagColor }" v-if="tagName || obj.tagName">
<view class="flex-r-lr price-line coupon-line" v-if="obj.buyDeductionValue"> {{ tagName || obj.tagName }}
<view class="text-28 text-zi text-bold"> </text>
<view class="text-28 text-bold">{{ obj.buyDeductionValue }}数字积分</view> <text class="title-text">{{ obj.title }}</text>
<view class="text-24">+{{ obj.price }}元</view> </view>
<!-- 有优惠券/积分 -->
<view class="price-action-row" v-if="obj.buyDeductionValue">
<view class="price-left">
<view class="price-main">
<text class="price-num">{{ obj.buyDeductionValue }}积分</text>
</view>
<view class="price-sub">
<text class="sales-text">+{{ obj.price }}元</text>
</view>
</view>
<view class="buy-btn">兑换</view>
</view>
<!-- 无优惠券/现金价格 -->
<view class="price-action-row" v-else>
<view class="price-left">
<view class="price-main">
<text class="price-symbol">¥</text>
<text class="price-num">{{ obj.price }}</text>
</view>
<view class="price-sub">
<text class="orig-price" v-if="hasOrigPrice">
¥{{ getOrigPrice }}
</text>
<text class="orig-price-sep" v-if="hasSales">|</text>
<text class="sales-text" v-if="hasSales">全网销量{{ limit999(obj.sales) }}</text>
</view>
</view>
<view class="buy-btn">购买</view>
</view> </view>
<text class="text-20 sold">兑换</text>
</view> </view>
<!-- 无优惠券 --> </view>
<view class="flex-r-lr price-line" v-else>
<text class="text-28 text-zi text-bold">¥{{ obj.price }}</text> <!-- 样式 2 (保持现状 / 图1样式) -->
<text class="text-24 sold">全网销量{{ limit999(obj.sales) }}件</text> <view class="parity-product-item type-2" @click.stop="onClick" v-else>
<image class="top-img" :src="obj.url" mode="widthFix" lazy-load />
<view class="shop-bottom-panel">
<text class="title text-30 text-zu text-overflow">
{{ obj.title }}
</text>
<!-- 有优惠券 -->
<view class="flex-r-lr price-line coupon-line" v-if="obj.buyDeductionValue">
<view class="text-28 text-zi text-bold">
<view class="text-28 text-bold">{{ obj.buyDeductionValue }}数字积分</view>
<view class="text-24">+{{ obj.price }}元</view>
</view>
<text class="text-20 sold">兑换</text>
</view>
<!-- 无优惠券 -->
<view class="flex-r-lr price-line" v-else>
<text class="text-28 text-zi text-bold">¥{{ obj.price }}</text>
<text class="text-24 sold">全网销量{{ limit999(obj.sales) }}件</text>
</view>
</view> </view>
</view> </view>
</view> </view>
@@ -29,6 +76,41 @@ export default {
obj: { obj: {
type: Object, type: Object,
default: () => ({}) default: () => ({})
},
type: {
type: [Number, String],
default: 2
},
tagName: {
type: String,
default: ''
},
tagColor: {
type: String,
default: ''
}
},
computed: {
getOrigPrice() {
if (this.obj && this.obj.aa !== undefined && this.obj.aa !== null && this.obj.aa !== '') {
return this.obj.aa;
}
return this.obj ? (this.obj.originalPrice || this.obj.marketPrice || this.obj.linePrice || this.obj.oldPrice || '') : '';
},
hasOrigPrice() {
return !!this.getOrigPrice;
},
hasSales() {
return this.obj && this.obj.sales !== undefined && this.obj.sales !== null && this.obj.sales !== '';
},
effectiveTagColor() {
if (this.tagColor) return this.tagColor;
const tag = this.tagName || (this.obj && this.obj.tagName) || '';
if (tag.includes('信任')) return '#7A35F6';
if (tag.includes('爆款')) return '#FF2A2A';
if (tag.includes('低价') || tag.includes('好物')) return '#FF9800';
if (tag.includes('品牌') || tag.includes('特卖')) return '#333333';
return '#7A35F6';
} }
}, },
methods: { methods: {
@@ -47,39 +129,156 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.parity-product-item { /* 样式 1 (图2 高保真) 专用 CSS */
.parity-product-item.type-1 {
width: 100%;
background: #ffffff;
border-radius: 20rpx;
overflow: hidden;
.top-img-1 {
width: 100%;
height: 340rpx;
display: block;
border-radius: 20rpx 20rpx 0 0;
}
.shop-bottom-panel-1 {
padding: 20rpx 24rpx 24rpx;
}
.title-box {
font-size: 28rpx;
color: #1a1a1a;
max-height: 80rpx;
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
word-break: break-all;
}
.tag-badge {
font-size: 20rpx;
color: #ffffff;
padding: 4rpx 10rpx;
border-radius: 8rpx;
margin-right: 10rpx;
display: inline-flex;
}
.title-text {
vertical-align: middle;
}
.price-action-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20rpx;
}
.price-left {
display: flex;
align-items: baseline;
flex-wrap: wrap;
flex: 1;
min-width: 0;
margin-right: 12rpx;
}
.price-main {
color: #FF2A2A;
font-weight: bold;
margin-right: 8rpx;
display: flex;
align-items: baseline;
}
.price-symbol {
font-size: 24rpx;
}
.price-num {
font-size: 40rpx;
line-height: 44rpx;
}
.price-sub {
display: inline-flex;
align-items: center;
font-size: 24rpx;
color: #b0b0b0;
white-space: nowrap;
}
.orig-price {
text-decoration: line-through;
color: #b0b0b0;
font-size: 24rpx;
}
.orig-price-sep {
margin: 0 8rpx;
color: #d0d0d0;
font-size: 20rpx;
}
.sales-text {
color: #b0b0b0;
font-size: 24rpx;
}
.buy-btn {
width: 130rpx;
height: 60rpx;
background: linear-gradient(270deg, #A45BFF 0%, #7934F6 100%);
border-radius: 30rpx;
font-size: 28rpx;
color: #ffffff;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
}
/* 样式 2 (图1) 保持原样 */
.parity-product-item.type-2 {
width: 332rpx; width: 332rpx;
background: #fff; background: #fff;
border-radius: 12rpx; border-radius: 12rpx;
overflow: hidden; overflow: hidden;
margin-bottom: 0; margin-bottom: 0;
/* 瀑布流父层控制间距,这里清零 */
.top-img {
width: 332rpx;
display: block;
border-radius: 12rpx 12rpx 0 0;
}
.shop-bottom-panel {
padding: 12rpx 16rpx 16rpx;
}
.title {
line-height: 40rpx;
max-width: 300rpx;
}
.price-line {
margin-top: 10rpx;
}
.sold {
color: #999;
}
} }
.top-img { /* 通用工具类 */
width: 332rpx;
display: block;
border-radius: 12rpx 12rpx 0 0;
}
.shop-bottom-panel {
padding: 12rpx 16rpx 16rpx;
}
.title {
line-height: 40rpx;
max-width: 300rpx;
}
.price-line {
margin-top: 10rpx;
}
.sold {
color: #999;
}
/* 通用工具类(如已全局引入可删除) */
.text-overflow { .text-overflow {
display: block; display: block;
width: 100%; width: 100%;
+1 -1
View File
@@ -336,7 +336,7 @@ export default {
id: 5, id: 5,
title: '地址管理', title: '地址管理',
url: 'https://static.tbmall.xin/static/mine/tool_dz.png', url: 'https://static.tbmall.xin/static/mine/tool_dz.png',
path: '/pages/mine_package/mine_address/mine_address' path: '/pages/mine_package/mine_address/mine_address?moduleType=1'
}, },
{ {
id: 9, id: 9,
+366 -74
View File
@@ -1,34 +1,117 @@
<template> <template>
<view class="mine_address_warp"> <view class="mine_address_page">
<Header :leftTitle="$t('address.title')" left-path-type="switchTab" left-path="/pages/mine/mine" /> <!-- 顶部导航栏 (白色底) -->
<view v-for="item in addressList" :key="item.id" class="address_item" <view class="header_box">
v-if="addressList && addressList.length !== 0"> <Header :leftTitle="headerTitle" leftPath="1" />
<view class="address_item_info"> </view>
<view>{{ item.name }}</view>
<view style="margin-left: 20rpx;">{{ item.phone }}</view> <!-- 页面内容容器 -->
</view> <view class="content_container">
<view class="address_item_address"> <!-- ===== 样式2 (moduleType == 2): 展示原地址卡片 + 选择新的收货地址卡片 ===== -->
{{ item.countryName }} {{ item.provinceName }} {{ item.cityName }} {{ item.areaName }} {{ <template v-if="moduleType == 2 || moduleType == '2'">
item.townshipName }} {{ item.address }} <!-- 原地址卡片 -->
</view> <view v-if="currentOriginalAddress" class="card_wrapper">
<view class="address_operate"> <view class="card_header">
<up-checkbox :customStyle="{}" label="已默认" name="agree" usedAlone :checked="item.isDefault" <text class="card_title">原地址</text>
shape="circle" activeColor="#FF7C41" @change="isDefaultChange(item)"> </view>
</up-checkbox> <view class="address_item original_item">
<view class="operate_item"> <view class="address_info">
<view class="operate_" @click="deleteAddressFun(item)">删除</view> <text class="name">{{ currentOriginalAddress.name }}</text>
<view class="operate_" @click="updateAddress(item)">修改</view> <text class="phone">{{ currentOriginalAddress.phone }}</text>
</view>
<view class="address_detail">
{{ formatAddress(currentOriginalAddress) }}
</view>
</view>
</view> </view>
<!-- 选择新的收货地址卡片 -->
<view class="card_wrapper">
<view class="card_header">
<text class="card_title">选择新的收货地址</text>
</view>
<view v-if="addressList && addressList.length > 0" class="address_list">
<view
v-for="(item, index) in addressList"
:key="item.id || index"
class="address_item"
:class="{ 'border_bottom': index !== addressList.length - 1 }"
@click="selectAddress(item)"
>
<view class="address_info">
<text class="name">{{ item.name }}</text>
<text class="phone">{{ item.phone }}</text>
</view>
<view class="address_detail">
{{ formatAddress(item) }}
</view>
<view class="address_operate">
<view class="default_check" @click.stop="isDefaultChange(item)">
<view class="check_icon" :class="{ checked: isItemDefault(item) }">
<text v-if="isItemDefault(item)" class="check_mark">✓</text>
</view>
<text class="check_label">已默认</text>
</view>
<view class="operate_btns">
<view class="btn_item" @click.stop="deleteAddressFun(item)">删除</view>
<view class="btn_item" @click.stop="updateAddress(item)">修改</view>
</view>
</view>
</view>
</view>
<!-- 暂无地址 -->
<view v-else class="empty_wrapper">
<image src="/pages/other_package/static/not_search.png" class="empty_img" mode="aspectFit" />
<text class="empty_text">暂无地址,快去添加吧~</text>
</view>
</view>
</template>
<!-- ===== 样式1 (moduleType == 1 / 默认): 单卡片列表 ===== -->
<template v-else>
<view v-if="addressList && addressList.length > 0" class="card_wrapper">
<view
v-for="(item, index) in addressList"
:key="item.id || index"
class="address_item"
:class="{ 'border_bottom': index !== addressList.length - 1 }"
>
<view class="address_info">
<text class="name">{{ item.name }}</text>
<text class="phone">{{ item.phone }}</text>
</view>
<view class="address_detail">
{{ formatAddress(item) }}
</view>
<view class="address_operate">
<view class="default_check" @click.stop="isDefaultChange(item)">
<view class="check_icon" :class="{ checked: isItemDefault(item) }">
<text v-if="isItemDefault(item)" class="check_mark">✓</text>
</view>
<text class="check_label">已默认</text>
</view>
<view class="operate_btns">
<view class="btn_item" @click.stop="deleteAddressFun(item)">删除</view>
<view class="btn_item" @click.stop="updateAddress(item)">修改</view>
</view>
</view>
</view>
</view>
<!-- 暂无地址 -->
<view v-else class="empty_wrapper">
<image src="/pages/other_package/static/not_search.png" class="empty_img" mode="aspectFit" />
<text class="empty_text">暂无地址,快去添加吧~</text>
</view>
</template>
</view>
<!-- 底部固定新增按钮 -->
<view class="bottom_btn_bar">
<view class="add_btn" @click="jumpAddAddress">
新增地址
</view> </view>
</view> </view>
<view v-else class="not_order_warp">
<view class="not_order_warp_img"><up-image src="/pages/other_package/static/not_search.png" width="100" height="100"
bgColor="#f1f6ff00"></up-image></view>
<view class="not_order_msg_warp">暂无地址,快去添加吧~</view>
</view>
<view class="add_but" @click="jumpAddAddress">
新增地址
</view>
</view> </view>
</template> </template>
@@ -37,61 +120,121 @@ import { getAddress, setAddressDefault, deleteAddress } from '@/api/address.js';
import Header from '@/components/header.vue'; import Header from '@/components/header.vue';
export default { export default {
components: { Header },
data() { data() {
return { return {
addressList: [], moduleType: '1', // 1: 图一模式 (默认), 2: 图二模式
options: [ originalId: '',
{ text: '删除' } passedOriginalAddress: null,
] addressList: []
};
},
computed: {
headerTitle() {
if (this.$t && typeof this.$t === 'function') {
try {
const title = this.$t('address.title');
if (title && title !== 'address.title') return title;
} catch (e) {}
}
return '地址管理';
},
currentOriginalAddress() {
if (this.passedOriginalAddress) {
return this.passedOriginalAddress;
}
if (this.originalId && this.addressList && this.addressList.length > 0) {
const found = this.addressList.find(item => String(item.id) === String(this.originalId));
if (found) return found;
}
if (this.addressList && this.addressList.length > 0) {
const defaultItem = this.addressList.find(item => this.isItemDefault(item));
return defaultItem || this.addressList[0];
}
return null;
}
},
onLoad(options) {
if (options) {
const typeVal = options.moduleType || options.type || options.mode || options.style || options.pageType || '1';
this.moduleType = String(typeVal);
if (options.originalId || options.addressId || options.id) {
this.originalId = options.originalId || options.addressId || options.id;
}
if (options.originalAddress) {
try {
this.passedOriginalAddress = JSON.parse(decodeURIComponent(options.originalAddress));
} catch (e) {
console.error('Parse originalAddress error:', e);
}
}
} }
}, },
components: { Header },
onShow() { onShow() {
this.getAddressList(); this.getAddressList();
}, },
methods: { methods: {
// 格式化完整地址显示
formatAddress(item) {
if (!item) return '';
const parts = [
item.countryName,
item.provinceName,
item.cityName,
item.areaName,
item.townshipName,
item.address
].filter(Boolean);
return parts.join(' ') || item.address || '';
},
// 判断是否为默认地址
isItemDefault(item) {
if (!item) return false;
return item.isDefault === true || item.isDefault === 1 || item.isDefault === '1';
},
// 添加地址 // 添加地址
jumpAddAddress() { jumpAddAddress() {
uni.navigateTo({ uni.navigateTo({
url: '/pages/mine_package/mine_address_add/mine_address_add', url: '/pages/mine_package/mine_address_add/mine_address_add'
}) });
}, },
// 查询地址 // 查询地址列表
async getAddressList() { async getAddressList() {
const res = await getAddress(); const res = await getAddress();
if (res && res.bizcode === 100) { if (res && res.bizcode === 100) {
this.addressList = res.data; this.addressList = res.data || [];
} }
}, },
// 设为默认地址 // 设为默认地址
async isDefaultChange(item) { async isDefaultChange(item) {
const params = { const params = {
id: item.id, id: item.id
} };
const res = await setAddressDefault(params); const res = await setAddressDefault(params);
if (res && res.bizcode === 100) { if (res && res.bizcode === 100) {
this.getAddressList(); this.getAddressList();
} }
}, },
// 删除地址 // 删除地址确认
deleteAddressFun(item) { deleteAddressFun(item) {
const then = this; const that = this;
uni.showModal({ uni.showModal({
title: '提示', title: '提示',
content: '是否要删除该地址?', content: '是否要删除该地址?',
success: function (res) { success: function (res) {
if (res.confirm) { if (res.confirm) {
then.deleteAddress(item); that.deleteAddress(item);
} }
} }
}); });
}, },
// 删除的方法 // 执行删除
async deleteAddress(item) { async deleteAddress(item) {
const params = { const params = {
id: item.id, id: item.id
} };
const respon = await deleteAddress(params); const respon = await deleteAddress(params);
if (respon && respon.bizcode === 100) { if (respon && respon.bizcode === 100) {
this.getAddressList(); this.getAddressList();
@@ -100,59 +243,208 @@ export default {
// 修改地址 // 修改地址
updateAddress(item) { updateAddress(item) {
uni.navigateTo({ uni.navigateTo({
url: '/pages/mine_package/mine_address_add/mine_address_add?id=' + item.id, url: '/pages/mine_package/mine_address_add/mine_address_add?id=' + item.id
}) });
}, },
// 选择地址(针对模式2)
selectAddress(item) {
uni.$emit('selectAddress', item);
if (this.moduleType == 2 || this.moduleType == '2') {
uni.navigateBack({
fail: () => {}
});
}
}
} }
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.mine_address_warp { .mine_address_page {
height: calc(100vh - 188rpx); min-height: 100vh;
overflow-y: auto;
background-color: $app-bj; background-color: $app-bj;
padding: 30rpx; display: flex;
flex-direction: column;
box-sizing: border-box;
}
.header_box {
background-color: #FFFFFF;
position: sticky;
top: 0;
z-index: 99;
::v-deep .header_ {
background-color: #FFFFFF;
}
}
.content_container {
padding: 24rpx;
padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
flex: 1;
}
.card_wrapper {
background: #FFFFFF;
border-radius: 24rpx;
padding: 0 30rpx;
margin-bottom: 24rpx;
overflow: hidden;
}
.card_header {
padding: 24rpx 0 20rpx;
border-bottom: 1rpx solid #F0F0F0;
.card_title {
font-size: 28rpx;
color: #888888;
font-weight: 400;
}
} }
.address_item { .address_item {
background: #FFFFFF; padding: 30rpx 0;
border-radius: 24rpx;
padding: 30rpx; &.border_bottom {
margin-bottom: 30rpx; border-bottom: 1rpx solid #F0F0F0;
}
&.original_item {
padding: 24rpx 0 30rpx;
}
} }
.address_item_info { .address_info {
font-weight: bold;
font-size: 32rpx;
color: #222222;
display: flex; display: flex;
align-items: center;
.name {
font-size: 28rpx;
color: #333333;
font-weight: 400;
}
.phone {
font-size: 28rpx;
color: #333333;
margin-left: 20rpx;
font-weight: 400;
}
} }
.address_item_address { .address_detail {
font-weight: 500; font-size: 32rpx;
font-size: 26rpx; font-weight: 600;
color: #666666; color: #1A1A1A;
margin-top: 10rpx; margin-top: 12rpx;
line-height: 1.4;
word-break: break-all;
} }
.address_operate { .address_operate {
display: flex; display: flex;
align-items: center;
justify-content: space-between; justify-content: space-between;
margin-top: 30rpx; margin-top: 24rpx;
} }
.operate_item { .default_check {
display: flex; display: flex;
align-items: center; align-items: center;
.check_icon {
width: 36rpx;
height: 36rpx;
border-radius: 50%;
border: 2rpx solid #CCCCCC;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12rpx;
box-sizing: border-box;
transition: all 0.2s ease;
&.checked {
background: linear-gradient(135deg, #9747FF 0%, #7934F6 100%);
border-color: #7934F6;
}
.check_mark {
color: #FFFFFF;
font-size: 22rpx;
font-weight: bold;
line-height: 1;
}
}
.check_label {
font-size: 26rpx;
color: #333333;
}
} }
.operate_ { .operate_btns {
padding: 10rpx 30rpx; display: flex;
background: #F3F3F3; align-items: center;
border-radius: 25rpx;
font-size: 24rpx; .btn_item {
color: #222222; padding: 10rpx 28rpx;
margin-left: 20rpx; background: #F3F3F5;
border-radius: 30rpx;
font-size: 24rpx;
color: #333333;
margin-left: 16rpx;
line-height: 1.2;
display: flex;
align-items: center;
justify-content: center;
}
}
.empty_wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
.empty_img {
width: 200rpx;
height: 200rpx;
}
.empty_text {
margin-top: 20rpx;
font-size: 28rpx;
color: #999999;
}
}
.bottom_btn_bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #F5F5F5;
padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
z-index: 100;
box-sizing: border-box;
.add_btn {
height: 88rpx;
background: linear-gradient(90deg, #8A38F5 0%, #A855F7 100%);
border-radius: 16rpx;
color: #FFFFFF;
font-size: 32rpx;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 12rpx rgba(121, 52, 246, 0.25);
}
} }
</style> </style>
+72 -3
View File
@@ -99,7 +99,7 @@
<view>共{{ item.buyNum }}件,合计¥{{ item.sumAmount }}</view> <view>共{{ item.buyNum }}件,合计¥{{ item.sumAmount }}</view>
</view> --> </view> -->
<view class="collect_msg" v-if="item.buyDeductionValue">共{{ item.buyNum }}件,合计数字积分{{ item.buyDeductionValue <view class="collect_msg" v-if="item.buyDeductionValue">共{{ item.buyNum }}件,合计数字积分{{ item.buyDeductionValue
}} }}
+¥{{ item.sumAmount }}</view> +¥{{ item.sumAmount }}</view>
<view class="collect_msg" v-if="!item.buyDeductionValue">运费:¥{{ item.postage }},商品总价:¥{{ item.sumAmount }} <view class="collect_msg" v-if="!item.buyDeductionValue">运费:¥{{ item.postage }},商品总价:¥{{ item.sumAmount }}
</view> </view>
@@ -133,6 +133,14 @@
查看售后 查看售后
</view> </view>
<!-- 修改地址按钮 (待发货/待收货状态) -->
<view class="operate_comm operate_but_3" v-if="
([MINE_ORDER_TYPE.UNSHIPPED, MINE_ORDER_TYPE.NOT_RECEIVE].includes(form.type) ||
[ORDER_TYPE.UNSHIPPED, ORDER_TYPE.NOT_RECEIVE].includes(item.status)) && item.modifyShippingAddressStatus == 0
" @click="changeOrderAddress(item)">
修改地址
</view>
<view :class="[ <view :class="[
'operate_comm', 'operate_comm',
form.type === MINE_ORDER_TYPE.UNPAID form.type === MINE_ORDER_TYPE.UNPAID
@@ -141,7 +149,7 @@
]" v-if="!item.isAfter && form.type !== MINE_ORDER_TYPE.AFTER_SALE && item.status !== 5" ]" v-if="!item.isAfter && form.type !== MINE_ORDER_TYPE.AFTER_SALE && item.status !== 5"
@click="onSaleAfter(item)"> @click="onSaleAfter(item)">
{{ {{
form.type === MINE_ORDER_TYPE.UNPAID ? "取消支付" : "去售后" form.type === MINE_ORDER_TYPE.UNPAID ? "取消支付" : "申请售后"
}} }}
</view> </view>
@@ -306,7 +314,9 @@ import {
afterSaleDetail, afterSaleDetail,
cancelOrder, cancelOrder,
orderLogistics, orderLogistics,
deleteOrderQuery deleteOrderQuery,
updateOrderAddress,
applyUpdateAddress
} from "@/api/order.js"; } from "@/api/order.js";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { formatDate1, copyData } from "@/utils/index.js"; import { formatDate1, copyData } from "@/utils/index.js";
@@ -318,6 +328,16 @@ import { RETURN_REASON_LIST } from "@/pages/mine_package/mine_order/emun/index.j
export default { export default {
components: { DownPopup, afterSales, refundPopup }, components: { DownPopup, afterSales, refundPopup },
created() {
uni.$on('selectAddress', this.onSelectAddressForOrder);
},
beforeUnmount() {
uni.$off('selectAddress', this.onSelectAddressForOrder);
},
beforeDestroy() {
uni.$off('selectAddress', this.onSelectAddressForOrder);
},
computed: { computed: {
MINE_ORDER_TYPE() { MINE_ORDER_TYPE() {
return MINE_ORDER_TYPE; return MINE_ORDER_TYPE;
@@ -346,6 +366,7 @@ export default {
}, },
data() { data() {
return { return {
changingOrder: null,
salesServer: 1, //为1展示申请售后 2:选择退货原因 3.退货退款申请,4.退款申请失败 salesServer: 1, //为1展示申请售后 2:选择退货原因 3.退货退款申请,4.退款申请失败
orderTypeList: [ orderTypeList: [
{ {
@@ -479,6 +500,54 @@ export default {
url: "/pages/rwa_package/kefu/kefu?scene=order", url: "/pages/rwa_package/kefu/kefu?scene=order",
}); });
}, },
// 修改订单地址:跳转至 mine_address 页面 (moduleType=2)
changeOrderAddress(item) {
this.changingOrder = item;
const originalId = item.addressId || item.address?.id || (item.address && item.address.id) || '';
let url = `/pages/mine_package/mine_address/mine_address?moduleType=2`;
if (originalId) {
url += `&originalId=${originalId}`;
}
if (item.address) {
try {
url += `&originalAddress=${encodeURIComponent(JSON.stringify(item.address))}`;
} catch (e) { }
}
uni.navigateTo({ url });
},
// 选择新地址后的回调处理,选择后直接返回此页面并触发接口修改
async onSelectAddressForOrder(addressObj) {
if (!this.changingOrder || !addressObj) return;
const order = this.changingOrder;
this.changingOrder = null;
try {
const params = {
orderId: order.id, // 订单ID
addrId: addressObj.id // 选中地址ID
};
console.log("选择新地址后的回调处理,选择后直接返回此页面并触发接口修改", params)
const res = await applyUpdateAddress(params);
if (res && res.bizcode === 100) {
if (this.$refs.uToastRef) {
this.$refs.uToastRef.show({
type: 'success',
message: '地址修改成功'
});
} else {
uni.showToast({
title: '地址修改成功',
icon: 'success'
});
}
}
} catch (e) {
console.error('updateOrderAddress error:', e);
}
this.form.page = 1;
this.loadData();
},
// 售后 // 售后
onSaleAfter(item) { onSaleAfter(item) {
console.log("售后---1", item, this.form.type); console.log("售后---1", item, this.form.type);
File diff suppressed because it is too large Load Diff
@@ -122,7 +122,7 @@ export default {
// 地址 // 地址
if (type === "address") { if (type === "address") {
uni.navigateTo({ uni.navigateTo({
url: '/pages/mine_package/mine_address/mine_address' url: '/pages/mine_package/mine_address/mine_address?moduleType=1'
}) })
} else if (type === "aboutUs") { } else if (type === "aboutUs") {
uni.navigateTo({ uni.navigateTo({
+371 -276
View File
@@ -1,276 +1,371 @@
<template> <template>
<view class="content"> <view class="page-container">
<TopSafe bgColor="#fff"></TopSafe> <!-- 顶部安全距离 -->
<view class="search-view"> <TopSafe bgColor="#ffffff"></TopSafe>
<view class="head-view">
<u-icon size="30rpx" name="arrow-left" @click="onBack" color="#333"></u-icon> <!-- 1. 自定义导航栏:左边返回箭头,中间“商品搜索”标题 -->
<view class="search-box"> <view class="custom-navbar">
<input class="input-view wx-width" v-model="searchInput"></input> <view class="nav-back flex-c" @click="onBack">
<!-- <u-input class="input-view wx-width" <u-icon name="arrow-left" size="36rpx" color="#333333"></u-icon>
v-model="searchInput"></u-input> --> </view>
<view class="search-btn flex-c" @click="onSearch"> <view class="nav-title">商品搜索</view>
<text class="text-32 text-white">搜索</text> <view class="nav-right"></view>
</view> </view>
</view>
<!-- 2. 搜索框部分:放大镜 + 输入框 + 右侧紫色搜索按钮 -->
</view> <view class="search-bar-box">
<view class="top-view mt-24"> <view class="search-inner">
<view class="flex-r-lr"> <u-icon name="search" size="36rpx" color="#999999" class="search-icon"></u-icon>
<text class="text-32 text-bold text-zu">搜索历史</text> <input
<u-icon size="40rpx" name="trash" @click="isDel = !isDel" color="#333"></u-icon> class="search-input"
</view> v-model="searchInput"
<view class="history-view" v-if="historyList.length"> placeholder="请输入商品关键字"
<view class="history-box flex-c mt-24 mr-32" v-for="(item, index) in historyList" :key="item"> placeholder-style="color: #999999; font-size: 28rpx;"
<text class="text-24 text-fu line-h" @click="onText(item)">{{ item }}</text> confirm-type="search"
<u-icon size="32rpx" class="close-pos" v-if="isDel" @click="onDel(index)" name="close-circle" @confirm="onSearch"
color="#333"></u-icon> />
</view> <view class="search-btn flex-c" @click="onSearch">
</view> <text class="search-btn-text">搜索</text>
<view class="history-on-data flex-c" v-else> </view>
<text class="text-40 text-bold">暂无历史记录</text> </view>
</view> </view>
</view>
<view class="bottom-view"> <!-- 3. 历史搜索部分 -->
<view class="bottom-head"> <view class="history-container">
<text class="text-32 text-bold text-zu">商品展示</text> <view class="history-header flex-r-lr">
</view> <text class="section-title">历史搜索</text>
<view class="bottom-scroll" v-if="dataList.length"> <u-icon name="trash" size="38rpx" color="#999999" @click="toggleDel"></u-icon>
<ShopItem :obj="item" class="mt-24" @click="onJump(item)" v-for="(item, index) in dataList" </view>
:key="item.id"></ShopItem>
</view> <!-- 历史记录标签列表 -->
<view class="bottom-scroll-no " v-else> <view class="history-tags flex-r" v-if="historyList.length">
<text class="text-48 text-bold" style="margin-top:200rpx">暂无数据</text> <view
</view> class="history-tag-item flex-r"
</view> v-for="(item, index) in historyList"
</view> :key="index"
@click="onText(item)"
<DownPopup></DownPopup> >
</view> <text class="tag-text">{{ item }}</text>
</template> <u-icon
name="close-circle-fill"
<script> size="28rpx"
import { getUserInfo } from '@/api/auth.js'; color="#999999"
import Header from '@/components/common/header.vue'; class="del-icon"
import TopSafe from '@/components/common/top-safe.nvue' v-if="isDel"
import DownPopup from '@/components/common/down-popup.vue'; @click.stop="onDel(index)"
import { searchList } from '@/api/product.js' ></u-icon>
import ShopItem from './components/shop-item.vue' </view>
import func from '@/utils/func.js'; </view>
export default { <!-- 无历史记录时显示 -->
components: { Header, TopSafe, DownPopup, ShopItem }, <view class="history-empty" v-else>
data() { <text class="empty-text">暂无搜索内容</text>
return { </view>
searchInput: '', </view>
historyList: [],
isDel: false, <!-- 4. 猜你喜欢部分 -->
dataList: [], <view class="recommend-container">
}; <view class="recommend-header">
}, <text class="section-title">猜你喜欢</text>
onShow() { </view>
this.init(); <!-- 猜你喜欢下面的列表按要求空着 -->
}, <view class="recommend-list">
methods: { <view class="product-grid" v-if="dataList && dataList.length">
init() { <ShopItem
// this.isSignContract() :obj="item"
// this.getSignContract() class="product-item"
@click="onJump(item)"
let arr = uni.getStorageSync('history') || ''; v-for="item in dataList"
if (arr) { :key="item.id"
this.historyList = arr.split(','); ></ShopItem>
} else { </view>
this.historyList = []; </view>
} </view>
},
onJump(item) { <DownPopup></DownPopup>
uni.navigateTo({ </view>
url: '/pages/other_package/productInfo/productInfo?id=' + item.id, </template>
})
}, <script>
onBack() { import { getUserInfo } from '@/api/auth.js';
uni.navigateBack(); import Header from '@/components/common/header.vue';
}, import TopSafe from '@/components/common/top-safe.nvue';
onSearch() { import DownPopup from '@/components/common/down-popup.vue';
if (!this.searchInput) { import { searchList } from '@/api/product.js';
return; import ShopItem from './components/shop-item.vue';
} import func from '@/utils/func.js';
this.onAdd();
let params = { export default {
keyword: this.searchInput components: { Header, TopSafe, DownPopup, ShopItem },
} data() {
searchList(params).then((res) => { return {
this.dataList = res.data; searchInput: '',
console.log('res', res) historyList: [],
}) isDel: false,
}, dataList: [],
onDel(index) { };
this.historyList.splice(index, 1); },
this.onSave() onShow() {
}, this.init();
onAdd() { },
methods: {
if (this.searchInput) { init() {
let bool = false; let arr = uni.getStorageSync('history') || '';
this.historyList.forEach(item => { if (arr) {
if (item == this.searchInput) { this.historyList = arr.split(',').filter(item => item.trim() !== '');
bool = true; } else {
} this.historyList = [];
}) }
if (!bool) { },
this.historyList.unshift(this.searchInput); onJump(item) {
if (this.historyList.length > 15) { uni.navigateTo({
this.historyList.pop(); url: '/pages/other_package/productInfo/productInfo?id=' + item.id,
} });
this.onSave(); },
} onBack() {
uni.navigateBack();
} },
}, onSearch() {
onText(item) { if (!this.searchInput || !this.searchInput.trim()) {
this.searchInput = item; return;
}, }
onSave() { this.onAdd();
if (this.historyList.length) { let params = {
uni.setStorageSync('history', this.historyList.join(',')); keyword: this.searchInput.trim()
} else { };
uni.setStorageSync('history', ''); searchList(params).then((res) => {
} this.dataList = res.data || [];
} });
} },
} onDel(index) {
</script> this.historyList.splice(index, 1);
this.onSave();
<style lang="scss" scoped> if (this.historyList.length === 0) {
.search-view { this.isDel = false;
width: 100%; }
height: calc(100% - var(--status-bar-height)); },
display: flex; toggleDel() {
flex-direction: column; if (this.historyList.length > 0) {
align-items: center; this.isDel = !this.isDel;
box-sizing: border-box; }
},
.top-view { onAdd() {
width: 100%; if (this.searchInput && this.searchInput.trim()) {
min-height: 150rpx; let val = this.searchInput.trim();
display: flex; let index = this.historyList.indexOf(val);
flex-direction: column; if (index > -1) {
padding: 0 32rpx; this.historyList.splice(index, 1);
box-sizing: border-box; }
overflow-y: auto; this.historyList.unshift(val);
if (this.historyList.length > 15) {
.history-on-data { this.historyList.pop();
width: 100%; }
height: 100%; this.onSave();
}
} },
onText(item) {
.history-view { this.searchInput = item;
width: 100%; this.onSearch();
display: flex; },
flex-wrap: wrap; onSave() {
if (this.historyList.length) {
.history-box { uni.setStorageSync('history', this.historyList.join(','));
position: relative; } else {
padding: 8rpx 22rpx; uni.setStorageSync('history', '');
box-sizing: border-box; }
border-radius: 8rpx; }
border: 2rpx solid #7932FE; }
};
.close-pos { </script>
right: -20rpx;
position: absolute; <style lang="scss" scoped>
top: -40%; /* 避免全局 .content 的 align-items: center 导致元素全挤在中间 */
} .page-container {
} width: 750rpx;
} min-width: 750rpx;
} max-width: 100%;
min-height: 100vh;
.bottom-view { background-color: #ffffff;
width: 100%; display: flex;
flex: 1; flex-direction: column;
display: flex; align-items: stretch;
flex-direction: column; box-sizing: border-box;
padding: 0 32rpx; }
box-sizing: border-box;
/* 导航栏 */
.bottom-head { .custom-navbar {
height: 50rpx; width: 100%;
display: flex; height: 88rpx;
} display: flex;
flex-direction: row;
.bottom-scroll { align-items: center;
width: 100%; justify-content: space-between;
height: calc(100vh - 50rpx - 324rpx - 4rpx - 88rpx - var(--status-bar-height)); padding: 0 32rpx;
overflow-y: auto; box-sizing: border-box;
display: flex; background-color: #ffffff;
flex-wrap: wrap; position: relative;
justify-content: space-between;
.nav-back {
} width: 60rpx;
height: 60rpx;
.bottom-scroll-no { display: flex;
width: 100%; align-items: center;
display: flex; justify-content: flex-start;
flex-direction: column; }
align-items: center;
.nav-title {
} font-size: 34rpx;
} font-weight: bold;
color: #1a1a1a;
.head-view { position: absolute;
width: 100%; left: 50%;
height: 118rpx; transform: translateX(-50%);
min-height: 118rpx; white-space: nowrap;
display: flex; }
flex-direction: row;
align-items: center; .nav-right {
padding: 0 32rpx; width: 60rpx;
box-sizing: border-box; }
background-color: #fff; }
/* #ifdef MP-WEIXIN */
padding-top: 80rpx !important; /* 搜索框 */
height: auto !important; .search-bar-box {
min-height: calc(118rpx + 80rpx) !important; width: 100%;
/* #endif */ padding: 16rpx 32rpx;
box-sizing: border-box;
.search-box {
width: 100%; .search-inner {
height: 84rpx; width: 100%;
min-height: 16rpx; height: 80rpx;
display: flex; background-color: #ffffff;
flex-direction: row; border-radius: 40rpx;
justify-content: space-between; display: flex;
align-items: center; flex-direction: row;
border-radius: 16rpx; align-items: center;
border: 2rpx solid #7932FE; padding: 0 8rpx 0 28rpx;
margin-left: 24rpx; box-sizing: border-box;
} border: 2rpx solid #efefef;
.search-btn { .search-icon {
width: 156rpx; margin-right: 12rpx;
height: 100%; }
border-radius: 16rpx;
background: linear-gradient(270deg, #B164FB 0%, #7934F6 100%); .search-input {
} flex: 1;
height: 100%;
.input-view { font-size: 28rpx;
height: 72rpx; color: #333333;
box-sizing: border-box; background: transparent;
padding: 0 30rpx !important; border: none;
border-radius: 36rpx; }
margin-left: 12rpx;
flex: 1; .search-btn {
} height: 64rpx;
padding: 0 32rpx;
/* #ifdef MP-WEIXIN */ background: linear-gradient(270deg, #b164fb 0%, #7934f6 100%);
.wx-width { border-radius: 32rpx;
width: 350rpx !important; display: flex;
flex: none; align-items: center;
} justify-content: center;
/* #endif */ .search-btn-text {
font-size: 28rpx;
color: #ffffff;
} font-weight: 500;
} }
</style> }
}
}
/* 历史搜索 */
.history-container {
width: 100%;
padding: 32rpx 32rpx 16rpx 32rpx;
box-sizing: border-box;
.history-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
}
.history-tags {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-top: 24rpx;
width: 100%;
.history-tag-item {
padding: 10rpx 28rpx;
background-color: #f5f5f7;
border-radius: 30rpx;
margin-right: 20rpx;
margin-bottom: 20rpx;
display: flex;
flex-direction: row;
align-items: center;
.tag-text {
font-size: 26rpx;
color: #666666;
}
.del-icon {
margin-left: 10rpx;
}
}
}
.history-empty {
margin-top: 16rpx;
width: 100%;
.empty-text {
font-size: 26rpx;
color: #999999;
}
}
}
/* 猜你喜欢 */
.recommend-container {
width: 100%;
padding: 32rpx 32rpx;
box-sizing: border-box;
.recommend-header {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
}
.recommend-list {
width: 100%;
margin-top: 24rpx;
.product-grid {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
}
}
</style>
+454
View File
@@ -0,0 +1,454 @@
<template>
<view class="sort_warp" :class="platformType ? '' : 'iosplatformType'">
<TopSafe></TopSafe>
<view class="sort_header">
<!-- 分类切换 -->
<view class="sort_category_header">
<view :class="selCategory === 1
? 'category_item category_item_sel'
: 'category_item'
" @click="checkCategory(1)">
<view>分类</view>
<view v-if="selCategory === 1" class="category_item_sel_but"></view>
</view>
<!-- <view :class="selCategory === 2 ? 'category_item category_item_sel':'category_item'" @click="checkCategory(2)">
<view>品牌</view>
<view v-if="selCategory === 2" class="category_item_sel_but"></view>
</view> -->
</view>
<!-- 搜索 -->
<view style="width: 200rpx" @click="jumpSearch" class="jump-search">
<up-search shape="square" bgColor="#EEEEEEFF" color="#666666FF" :showAction="false"
placeholder="搜索"></up-search>
</view>
</view>
<view class="u-menu-wrap">
<!-- 左侧类别 -->
<scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop">
<view v-for="(item, index) in tabbarList" :key="index" class="u-tab-item"
:class="[current == index ? 'u-tab-item-active' : '']" :data-current="index"
@tap.stop="swichMenu(item, index)">
<text class="u-line-1">{{ item.name }}</text>
</view>
</scroll-view>
<!-- 商品类别数据 -->
<scroll-view scroll-y class="right-box" :scroll-top="rightScrollTop">
<!-- banner图 -->
<view style="padding: 0rpx 20rpx" v-if="bannerList && bannerList.length > 0">
<up-swiper :list="bannerList" height="80px"></up-swiper>
</view>
<view class="page-view">
<!-- 这里还有一层循环 -->
<up-loading-page :loading="tabbarContentLoading"></up-loading-page>
<view class="class-item" v-for="(item, index) in tabbarContentList" :key="index">
<view class="item-title">
<text>{{ item.name }}</text>
</view>
<view class="item-container" v-if="item.foods && item.foods.length !== 0">
<view class="thumb-box" v-for="(item1, index1) in item.foods" :key="item1.id || index1" @click="jumpInfo(item1)">
<image class="item-menu-image" :src="item1.icon ? item1.icon : '/static/common/def_img.jpg'"
mode="aspectFill" lazy-load>
</image>
<view class="item-menu-name">{{ item1.name }}</view>
</view>
</view>
<view v-else class="not_order_warp">
<view class="not_order_warp_img"><up-image src="https://static.tbmall.xin/static/not_shopping.png"
width="100" height="100" bgColor="#f1f6ff00"></up-image></view>
<view class="not_order_msg_warp">暂无分类,快去添加吧~</view>
</view>
</view>
</view>
</scroll-view>
</view>
<!-- #ifndef H5 || MP-WEIXIN-->
<CustomTabBar :tabIndex="1" />
<!-- #endif -->
</view>
</template>
<script>
import { getCascadeCategory, getCarouselImage } from "@/api/common.js";
import CustomTabBar from "@/components/custom-tab-bar.vue";
import { APP_PAGE_TYPE } from "@/utils/enumUtils.js";
import TopSafe from '@/components/common/top-safe.nvue';
export default {
components: { CustomTabBar, TopSafe },
data() {
return {
selCategory: 1,
scrollTop: 0, //tab标题的滚动条位置
rightScrollTop: 0, // 右侧内容的滚动条位置
current: null, // 预设当前项的值
menuHeight: 0, // 左边菜单的高度
menuItemHeight: 0, // 左边菜单item的高度
bannerList: [],
tabbarList: [], // 左侧的主分类
tabbarContentList: [], // 右侧内容的分类
tabbarContentLoading: false,
platformType: true,
isFromSortShop: false,
};
},
onShow() {
/*#ifdef APP-PLUS*/
uni.hideTabBar({
animation: false,
});
const appUpdate = uni.getStorageSync("platform");
this.platformType = appUpdate == "android" ? "ANDROID" : "IOS";
/*#endif*/
const isBackFromSortShop = this.isFromSortShop;
this.isFromSortShop = false;
this.getSort(0).then((resp) => {
if (resp && resp.length !== 0) {
this.tabbarList = resp;
let targetIndex = 0;
let fData = resp[0];
if (isBackFromSortShop) {
const sortId = uni.getStorageSync("sortId");
if (sortId && sortId !== 0) {
resp.forEach((item, index) => {
if (item.id === sortId) {
fData = item;
targetIndex = index;
}
});
} else if (this.current !== null && this.current >= 0 && this.current < resp.length) {
targetIndex = this.current;
fData = resp[targetIndex];
}
} else {
uni.removeStorageSync("sortId");
this.current = 0;
this.scrollTop = 0;
targetIndex = 0;
fData = resp[0];
}
this.swichMenu(fData, targetIndex, true);
}
});
this.getCarouselImage();
},
methods: {
checkCategory(val) {
this.selCategory = val;
},
// 查询轮播图
async getCarouselImage() {
const params = {
pageUi: APP_PAGE_TYPE.SORT,
};
const resp = await getCarouselImage(params);
if (resp && resp.bizcode === 100) {
const data = resp.data || [];
this.bannerList =
data.length !== 0 ? data.map((obj) => obj.carouselImage) : [];
}
},
jumpSearch(item) {
uni.navigateTo({
url: "/pages/rwa_package/insights/search",
});
},
jumpInfo(item) {
console.log(item, "item");
this.isFromSortShop = true;
// uni.navigateTo({
// url: `/pages/other_package/productInfo/productInfo?id=${item.id}`,
// })
uni.navigateTo({
url: `/pages/rwa_package/shop/sort-shop?id=${item.id}&name=${item.name}`,
});
},
// 查询分类
async getSort(pId) {
const params = {
parentId: pId,
};
console.log('查询分类', params, pId);
const resp = await getCascadeCategory(params);
if (resp && resp.bizcode === 100) {
return resp.data;
}
return [];
},
getImg() {
return Math.floor(Math.random() * 35);
},
// 点击左边的栏目切换
async swichMenu(item, index, force = false) {
console.log('点击左边的栏目切换', item, index, "item, index");
if (!force && index == this.current && this.tabbarContentList.length > 0) return;
if (item && item.id) {
uni.setStorageSync("sortId", item.id);
}
this.rightScrollTop = 0;
this.tabbarContentLoading = true;
const firstData = await this.getSort(item.id);
for (let fItem of firstData) {
const twoData = await this.getSort(fItem.id);
fItem.foods = twoData;
}
this.tabbarContentList = firstData;
this.current = index;
// 如果为0,意味着尚未初始化
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
await this.getElRect("menu-scroll-view", "menuHeight");
await this.getElRect("u-tab-item", "menuItemHeight");
}
// 将菜单活动item垂直居中
this.scrollTop =
index * this.menuItemHeight +
this.menuItemHeight / 2 -
this.menuHeight / 2;
this.tabbarContentLoading = false;
},
// 获取一个目标元素的高度
getElRect(elClass, dataVal) {
return new Promise((resolve) => {
const query = uni.createSelectorQuery().in(this);
query
.select("." + elClass)
.fields({ size: true }, (res) => {
if (!res) {
setTimeout(() => {
this.getElRect(elClass, dataVal).then(resolve);
}, 10);
return;
}
this[dataVal] = res.height;
resolve(res);
})
.exec();
});
},
// 分享给朋友
onShareAppMessage() {
return {
title: 'TB聚合商城', // 分享标题
path: '/pages/sort/sort' // 分享路径
}
},
// 分享到朋友圈
onShareTimeline() {
return {
title: 'TB聚合商城',
query: ''
}
},
},
};
</script>
<style lang="scss" scoped>
page {
height: 100%;
overflow: hidden;
}
.sort_warp {
height: 100vh;
/* #ifdef H5 */
height: calc(100vh - var(--window-top, 0px) - var(--window-bottom, 0px));
/* #endif */
display: flex;
flex-direction: column;
overflow: hidden;
box-sizing: border-box;
background-color: #fff;
}
.sort_header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 30rpx 10rpx;
flex-shrink: 0;
background-color: #fff;
z-index: 10;
/* #ifdef MP-WEIXIN */
margin-top: 80rpx;
/* #endif */
.sort_category_header {
display: flex;
align-items: center;
}
.jump-search {
display: flex;
}
.category_item {
width: 140rpx;
font-weight: bold;
font-size: 36rpx;
color: #999999;
}
.category_item_sel {
font-size: 44rpx;
color: #1a1a1a;
}
.category_item_sel_but {
height: 8rpx;
width: 50rpx;
background: $app-bt-bj;
margin-top: 4rpx;
margin-left: 12%;
border-radius: 20rpx;
}
}
.sort_content {}
.u-menu-wrap {
flex: 1;
min-height: 0;
width: 100%;
display: flex;
flex-direction: row;
overflow: hidden;
margin-top: 10rpx;
}
.u-search-inner {
background-color: rgb(234, 234, 234);
border-radius: 100rpx;
display: flex;
align-items: center;
padding: 10rpx 16rpx;
}
.u-search-text {
font-size: 26rpx;
color: $u-tips-color;
margin-left: 10rpx;
}
.u-tab-view {
width: 200rpx;
height: 100%;
flex-shrink: 0;
background: #f6f6f6;
overflow-y: auto;
box-sizing: border-box;
-webkit-overflow-scrolling: touch;
/* #ifdef APP-PLUS */
padding-bottom: calc(110rpx + env(safe-area-inset-bottom));
/* #endif */
/* #ifndef APP-PLUS */
padding-bottom: 0rpx;
/* #endif */
}
.u-tab-item {
height: 110rpx;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #444;
font-weight: 400;
line-height: 1;
padding: 0 10rpx;
text-align: center;
}
.u-tab-item-active {
position: relative;
color: #000;
font-size: 30rpx;
font-weight: 600;
background: #fff;
}
.u-tab-item-active::before {
content: "";
position: absolute;
border-left: 4px solid $app-bt-bj;
height: 32rpx;
left: 0;
top: 39rpx;
}
.right-box {
flex: 1;
min-width: 0;
height: 100%;
overflow-y: auto;
background-color: rgb(250, 250, 250);
box-sizing: border-box;
-webkit-overflow-scrolling: touch;
/* #ifdef APP-PLUS */
padding-bottom: calc(110rpx + env(safe-area-inset-bottom));
/* #endif */
/* #ifndef APP-PLUS */
padding-bottom: 0rpx;
/* #endif */
}
.page-view {
padding: 16rpx;
}
.class-item {
margin-bottom: 30rpx;
background-color: #fff;
padding: 16rpx;
border-radius: 8rpx;
&:last-child {
margin-bottom: 0;
}
}
.item-title {
font-size: 26rpx;
color: $u-main-color;
font-weight: bold;
}
.item-menu-name {
font-weight: normal;
font-size: 24rpx;
color: $u-main-color;
margin-top: 10rpx;
text-align: center;
word-break: break-all;
}
.item-container {
display: flex;
flex-wrap: wrap;
}
.thumb-box {
width: 33.333333%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin-top: 20rpx;
}
.item-menu-image {
width: 110rpx;
height: 110rpx;
border-radius: 8rpx;
}
</style>
+857 -454
View File
File diff suppressed because it is too large Load Diff
+406
View File
@@ -0,0 +1,406 @@
<template>
<view class="content-two">
<view class="top-header-container">
<TopSafe></TopSafe>
<view class="head-view">
<view class="head-search" @click="onJumpSearch">
<u-icon size="24" name="search" color="#999"></u-icon>
<text class="text-28 text-fu" style="margin-left: 12rpx">搜索</text>
</view>
</view>
<view class="tab-box">
<view class="tab-item" v-for="(item, index) in tabArr" :key="item.id" @click="onTab(item.id)">
<image :src="curTab == item.id ? item.iconActive : item.icon" mode="aspectFill" class="tab-img">
</image>
<view class="tab-name" :style="{
color: curTab == item.id ? '#7A35F6' : '#666',
}">{{ item.name }}</view>
</view>
</view>
</view>
<mescroll-uni ref="mescrollRef" :top="mescrollTop" :bottom="mescrollBottom" :safearea="isApp"
@down="downCallback" @up="upCallback" :up="upOption" :down="downOption" @init="mescrollInit">
<view class="setting-view">
<view class="name-box">
<!-- 原来单个 v-for 替换成两列 -->
<view class="mescrollUniView">
<view class="fall-col">
<ParityProductItem v-for="(item, i) in leftList" :key="item.id" :obj="item" @ok="onJumpShop"
style="margin-top: 24rpx" />
</view>
<view class="fall-col">
<ParityProductItem v-for="(item, i) in rightList" :key="item.id" :obj="item"
@ok="onJumpShop" style="margin-top: 24rpx" />
</view>
</view>
</view>
</view>
</mescroll-uni>
<!-- #ifndef H5 || MP-WEIXIN-->
<CustomTabBar :tabIndex="2" />
<!-- #endif -->
<up-toast ref="uToastRef"></up-toast>
</view>
</template>
<script>
import Header from "@/components/common/header.vue";
import TopSafe from "@/components/common/top-safe.nvue";
import MyBtn from "@/components/common/my-btn.vue";
import ParityProductItem from "@/components/shop/parity-product-item.vue";
import { searchList, getGoodsTags } from "@/api/product.js";
import CustomTabBar from "@/components/custom-tab-bar.vue";
import MescrollMixin from "@/components/mescroll-uni/mescroll-mixins.js";
import MescrollUni from "@/components/mescroll-uni/mescroll-uni.vue";
export default {
mixins: [MescrollMixin],
components: { Header, TopSafe, MyBtn, ParityProductItem, CustomTabBar, MescrollUni },
computed: {
isApp() {
// #ifdef APP-PLUS
return true;
// #endif
// #ifndef APP-PLUS
return false;
// #endif
},
mescrollTop() {
// #ifdef MP-WEIXIN
return '400rpx';
// #endif
// #ifdef H5
return '260rpx';
// #endif
// #ifdef APP-PLUS
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 0;
return (statusBarHeight * 2 + 248) + 'rpx';
// #endif
},
mescrollBottom() {
// #ifdef APP-PLUS
return '100rpx';
// #endif
// #ifndef APP-PLUS
return '0rpx';
// #endif
},
},
data() {
return {
dataList: [],
tabArr: [
{
id: 7,
name: '信任专享',
icon: 'https://static.tbmall.xin/static/new-home/xinren.png',
iconActive: 'https://static.tbmall.xin/static/new-home/xinren_active.png',
}, {
id: 15,
name: '全网爆款',
icon: 'https://static.tbmall.xin/static/new-home/baokuan.png',
iconActive: 'https://static.tbmall.xin/static/new-home/baokuan_active.png',
}, {
id: 16,
name: '低价好物',
icon: 'https://static.tbmall.xin/static/new-home/cart.png',
iconActive: 'https://static.tbmall.xin/static/new-home/cart_active.png',
}, {
id: 6,
name: '品牌特卖',
icon: 'https://static.tbmall.xin/static/new-home/huiyuan.png',
iconActive: 'https://static.tbmall.xin/static/new-home/huiyuan_active.png',
},
],
curTab: 7,
upOption: {
auto: false,
page: {
size: 10, // 每页数据的数量,默认10
},
noMoreSize: 10, // 配置列表的总数量要大于等于5条才显示'-- END --'的提示
empty: {
tip: `空空如也`,
},
textColor: "#333",
bgColor: "rgba(0,0,0,0)",
},
downOption: {
auto: false,
textColor: "#333",
bgColor: "rgba(0,0,0,0)",
},
leftList: [],
rightList: [],
mescroll: null,
};
},
onLoad(options) {
console.log("+++++", options)
if (options.index) {
this.curTab = options.index;
}
this.getSearchList()
},
onShow() {
/*#ifdef APP-PLUS*/
uni.hideTabBar({
animation: false,
});
/*#endif*/
if (this.tabArr.length > 0) {
const sortParams = uni.getStorageSync('sortParams');
if (sortParams) {
const targetIndex = this.tabArr.find(item => item.name === sortParams.value)?.id;
uni.removeStorageSync('sortParams');
if (targetIndex) {
this.curTab = targetIndex;
this.dataList = [];
this.downCallback();
}
} else {
this.getSearchList()
}
}
},
methods: {
/**
* 查询分类列表
*/
async getSortList() {
const resp = await getGoodsTags({ type: 5 });
if (resp && resp.bizcode === 100) {
this.tabArr = resp.data.sort((a, b) => a.sort - b.sort);
this.$nextTick(() => {
this.applySortParams();
this.downCallback();
});
}
},
applySortParams() {
const sortParams = uni.getStorageSync('sortParams');
if (sortParams && this.tabArr.length > 0) {
uni.removeStorageSync('sortParams');
const targetIndex = this.tabArr.findIndex(item => item.name === sortParams.value);
if (targetIndex !== -1 && targetIndex !== this.curTab) {
this.curTab = targetIndex;
this.dataList = [];
}
}
},
mescrollInit(mescroll) {
this.mescroll = mescroll;
},
upCallback(page) {
let pageNum = page.num;
let pageSize = page.size;
let params = {
type: 2,
page: page.num,
pageSize: page.size,
isPar: true,
tag: this.curTab
};
searchList(params).then((res) => {
let curPageLen = res.data.length;
if (page.num === 1) this.dataList = [];
this.dataList = this.dataList.concat(res.data);
this.waterfall();
this.mescroll.endBySize(curPageLen, res.data.total);
});
},
downCallback() {
this.mescroll && this.mescroll.resetUpScroll();
},
onTab(index) {
if (index != this.curTab) {
this.curTab = index;
console.log("----", this.curTab)
this.dataList = [];
this.mescroll && this.mescroll.scrollTo(0, 0);
this.downCallback();
}
},
async getSearchList() {
const params = {
page: 1,
pageSize: 10,
isPar: true,
tag: this.curTab
};
const resp = await searchList(params);
if (resp && resp.bizcode === 100) {
this.dataList = resp.data || [];
this.waterfall();
}
},
waterfall() {
this.leftList = this.dataList
.map((item, index) => {
if (index % 2 == 0) return item;
return null;
})
.filter(Boolean);
this.rightList = this.dataList
.map((item, index) => {
if (index % 2 != 0) return item;
return null;
})
.filter(Boolean);
console.log(this.leftList, this.rightList);
},
onJumpSearch() {
uni.navigateTo({
url: "/pages/rwa_package/insights/search",
});
},
onJumpShop(id) {
uni.navigateTo({
url: "/pages/other_package/productInfo/productInfo?id=" + id,
});
},
onShare() {
uni.navigateTo({
url: "/pages/other_package/invite_friends/invite_friends",
});
},
},
};
</script>
<style lang="scss" scoped>
.content-two {
min-height: 100vh;
background-color: #fff;
}
.top-header-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 99;
background-color: #fff;
/* #ifdef MP-WEIXIN */
padding-top: 40rpx;
/* #endif */
}
.head-view {
width: 100%;
min-height: 88rpx;
height: 88rpx;
display: flex;
align-items: center;
padding: 0 32rpx;
box-sizing: border-box;
background-color: #fff;
.head-search {
width: 100%;
height: 76rpx;
padding: 0 24rpx;
flex-direction: row;
display: flex;
background-color: #f7f7f7;
align-items: center;
border-radius: 16rpx;
}
}
.tab-box {
width: 100%;
height: 160rpx;
min-height: 80rpx;
display: flex;
flex-direction: row;
align-items: center;
padding: 0 32rpx;
box-sizing: border-box;
background-color: #fff;
overflow-x: auto;
.tab-item {
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
.tab-img {
width: 56rpx;
height: 56rpx;
}
.tab-name {
font-size: 28rpx;
margin-top: 24rpx;
}
}
}
.tab-view {
width: 100%;
height: 80rpx;
min-height: 80rpx;
display: flex;
flex-direction: row;
padding: 0 32rpx;
box-sizing: border-box;
background-color: #fff;
overflow-x: auto;
.tab-list {
margin-right: 24rpx;
display: flex;
flex-direction: column;
height: 60rpx;
min-height: 60rpx;
align-items: center;
justify-content: space-between;
margin-top: 22rpx;
}
.line {
width: 48rpx;
height: 6rpx;
background-color: #7a35f6;
}
}
.setting-view {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
padding: 0 32rpx 40rpx;
box-sizing: border-box;
.name-box {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
.mescrollUniView {
width: calc(100vw - 48rpx);
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.fall-col {
width: 332rpx;
/* 与 ParityProductItem 宽度一致 */
height: 100%;
}
}
}
}
</style>
+45 -11
View File
@@ -14,7 +14,8 @@
<image :src="curTab == item.id ? item.iconActive : item.icon" mode="aspectFill" class="tab-img"> <image :src="curTab == item.id ? item.iconActive : item.icon" mode="aspectFill" class="tab-img">
</image> </image>
<view class="tab-name" :style="{ <view class="tab-name" :style="{
color: curTab == item.id ? '#7A35F6' : '#666', color: curTab == item.id ? getTabColor(item) : '#999',
fontWeight: curTab == item.id ? 'bold' : 'normal'
}">{{ item.name }}</view> }">{{ item.name }}</view>
</view> </view>
</view> </view>
@@ -23,15 +24,19 @@
@up="upCallback" :up="upOption" :down="downOption" @init="mescrollInit"> @up="upCallback" :up="upOption" :down="downOption" @init="mescrollInit">
<view class="setting-view"> <view class="setting-view">
<view class="name-box"> <view class="name-box">
<!-- 原来单个 v-for 替换成两列 --> <!-- 传1: 图2单列展示 / 传2: 图1双列瀑布流 -->
<view class="mescrollUniView"> <view class="single-col" v-if="itemType == 1">
<ParityProductItem v-for="(item, i) in dataList" :key="item.id" :obj="item" :type="itemType"
:tag-name="curTabName" :tag-color="curTabColor" @ok="onJumpShop" style="margin-top: 24rpx" />
</view>
<view class="mescrollUniView" v-else>
<view class="fall-col"> <view class="fall-col">
<ParityProductItem v-for="(item, i) in leftList" :key="item.id" :obj="item" @ok="onJumpShop" <ParityProductItem v-for="(item, i) in leftList" :key="item.id" :obj="item" :type="itemType"
style="margin-top: 24rpx" /> :tag-name="curTabName" :tag-color="curTabColor" @ok="onJumpShop" style="margin-top: 24rpx" />
</view> </view>
<view class="fall-col"> <view class="fall-col">
<ParityProductItem v-for="(item, i) in rightList" :key="item.id" :obj="item" @ok="onJumpShop" <ParityProductItem v-for="(item, i) in rightList" :key="item.id" :obj="item" :type="itemType"
style="margin-top: 24rpx" /> :tag-name="curTabName" :tag-color="curTabColor" @ok="onJumpShop" style="margin-top: 24rpx" />
</view> </view>
</view> </view>
</view> </view>
@@ -58,6 +63,15 @@ export default {
mixins: [MescrollMixin], mixins: [MescrollMixin],
components: { Header, TopSafe, MyBtn, ParityProductItem, CustomTabBar, MescrollUni }, components: { Header, TopSafe, MyBtn, ParityProductItem, CustomTabBar, MescrollUni },
computed: { computed: {
curTabItem() {
return this.tabArr.find(item => item.id == this.curTab) || this.tabArr[0] || {};
},
curTabName() {
return this.curTabItem.name || '信任精选';
},
curTabColor() {
return this.getTabColor(this.curTabItem);
},
isApp() { isApp() {
// #ifdef APP-PLUS // #ifdef APP-PLUS
return true; return true;
@@ -89,26 +103,31 @@ export default {
}, },
data() { data() {
return { return {
itemType: 1, // 1: 图2样式, 2: 图1样式
dataList: [], dataList: [],
tabArr: [ tabArr: [
{ {
id: 7, id: 7,
name: '信任专享', name: '信任精选',
color: '#7A35F6',
icon: 'https://static.tbmall.xin/static/new-home/xinren.png', icon: 'https://static.tbmall.xin/static/new-home/xinren.png',
iconActive: 'https://static.tbmall.xin/static/new-home/xinren_active.png', iconActive: 'https://static.tbmall.xin/static/new-home/xinren_active.png',
}, { }, {
id: 15, id: 15,
name: '全网爆款', name: '全网爆款',
color: '#FF2A2A',
icon: 'https://static.tbmall.xin/static/new-home/baokuan.png', icon: 'https://static.tbmall.xin/static/new-home/baokuan.png',
iconActive: 'https://static.tbmall.xin/static/new-home/baokuan_active.png', iconActive: 'https://static.tbmall.xin/static/new-home/baokuan_active.png',
}, { }, {
id: 16, id: 16,
name: '低价好物', name: '低价好物',
color: '#FF9800',
icon: 'https://static.tbmall.xin/static/new-home/cart.png', icon: 'https://static.tbmall.xin/static/new-home/cart.png',
iconActive: 'https://static.tbmall.xin/static/new-home/cart_active.png', iconActive: 'https://static.tbmall.xin/static/new-home/cart_active.png',
}, { }, {
id: 6, id: 6,
name: '品牌特卖', name: '品牌特卖',
color: '#333333',
icon: 'https://static.tbmall.xin/static/new-home/huiyuan.png', icon: 'https://static.tbmall.xin/static/new-home/huiyuan.png',
iconActive: 'https://static.tbmall.xin/static/new-home/huiyuan_active.png', iconActive: 'https://static.tbmall.xin/static/new-home/huiyuan_active.png',
}, },
@@ -160,12 +179,21 @@ export default {
this.downCallback(); this.downCallback();
} }
} else { } else {
this.getSearchList();
this.getSearchList()
} }
} }
}, },
methods: { methods: {
getTabColor(item) {
if (!item) return '#7A35F6';
if (item.color) return item.color;
const name = item.name || '';
if (name.includes('信任')) return '#7A35F6';
if (name.includes('爆款')) return '#FF2A2A';
if (name.includes('低价') || name.includes('好物')) return '#FF9800';
if (name.includes('品牌') || name.includes('特卖')) return '#333333';
return '#7A35F6';
},
/** /**
* 查询分类列表 * 查询分类列表
*/ */
@@ -278,7 +306,7 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.content-two { .content-two {
min-height: 100vh; min-height: 100vh;
background-color: #fff; background-color: #f5f5f5;
} }
.top-header-container { .top-header-container {
@@ -389,6 +417,12 @@ export default {
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
.single-col {
width: 100%;
display: flex;
flex-direction: column;
}
.mescrollUniView { .mescrollUniView {
width: calc(100vw - 48rpx); width: calc(100vw - 48rpx);
display: flex; display: flex;
+21 -1
View File
@@ -547,4 +547,24 @@ export const SORT_TYPE = [
value: "限时秒杀", value: "限时秒杀",
path: "/pages/active/limited-time/limited-time" path: "/pages/active/limited-time/limited-time"
}, },
] ]
// 物流更改状态 0=未申请,1=待审核,2=审核通过,3=审核驳回
export const LOGISTICS_STATUS_UPDATE = [
{
key: 0,
value: "未申请"
},
{
key: 1,
value: "待审核"
},
{
key: 2,
value: "审核通过"
},
{
key: 3,
value: "审核驳回"
},
]