Files
frontend-app/pages/mine_package/fill_express/fill_express.vue
T
2026-08-25 17:52:05 +08:00

655 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="fill-express-container">
<!-- 顶部固定导航栏 -->
<view class="navbar-sticky-wrapper" :style="mpWarpStyle">
<view class="custom-navbar" :style="mpHeaderStyle">
<view class="nav-left" @click="goBack">
<view class="back-btn-box">
<text class="back-arrow">‹</text>
</view>
</view>
<view class="nav-title">填写物流</view>
<view class="nav-right"></view>
</view>
</view>
<scroll-view scroll-y class="content-scroll">
<view class="main-content">
<!-- 1. 商品信息卡片 -->
<view class="card product-card">
<view class="product-info-row">
<image :src="productImage" class="product-img" mode="aspectFill" />
<view class="product-details">
<view class="product-header">
<text class="product-title">{{ productTitle }}</text>
<text class="product-price">¥{{ productPrice }}</text>
</view>
<view class="product-spec-row">
<text class="product-spec">规格:{{ productSpec }}</text>
<text class="product-num">x {{ productNum }}</text>
</view>
</view>
</view>
<view class="product-total-row">
<text class="product-total-text">共{{ productNum }}件,合计¥{{ totalPrice }}</text>
</view>
</view>
<!-- 2. 退货信息卡片 -->
<view class="card form-card">
<view class="section-title-row">
<text class="section-title">退货信息</text>
<text class="section-sub-tip">(如无退货信息请联系客服人员)</text>
</view>
<!-- 联系人 -->
<view class="info-row">
<text class="info-label">联系人</text>
<text class="info-val">{{ sellerName }}</text>
</view>
<view class="row-divider"></view>
<!-- 手机号 -->
<view class="info-row">
<text class="info-label">手机号</text>
<text class="info-val">{{ sellerPhone }}</text>
</view>
<view class="row-divider"></view>
<!-- 退货地址 -->
<view class="info-row align-top">
<text class="info-label">退货地址</text>
<text class="info-val address-text">{{ sellerAddress }}</text>
</view>
</view>
<!-- 3. 物流信息卡片 -->
<view class="card form-card">
<view class="section-title-row">
<text class="section-title">物流信息</text>
</view>
<!-- 物流公司 -->
<view class="form-row" @click="openExpressPicker">
<view class="form-label">
<text class="required-asterisk">*</text>
<text class="label-text">物流公司</text>
</view>
<view class="select-trigger">
<text :class="['select-value', { 'placeholder': !expressName }]">
{{ expressName || '请选择' }}
</text>
<view class="dashed-arrow-box">
<text class="arrow-icon">›</text>
</view>
</view>
</view>
<view class="row-divider"></view>
<!-- 物流单号 -->
<view class="form-row">
<view class="form-label">
<text class="required-asterisk">*</text>
<text class="label-text">物流单号</text>
</view>
<input class="form-input" type="text" v-model="expressNo" placeholder="请输入"
placeholder-style="color: #CCCCCC; font-size: 28rpx;" />
</view>
<view class="row-divider"></view>
<!-- 物流说明 -->
<view class="form-row">
<view class="form-label">
<text class="label-text">物流说明</text>
</view>
<input class="form-input" type="text" v-model="expressRemark" placeholder="请填写物流说明(选填)"
placeholder-style="color: #CCCCCC; font-size: 28rpx;" />
</view>
</view>
</view>
<!-- 底部间距防止遮挡 -->
<view class="bottom-spacer"></view>
</scroll-view>
<!-- 底部固定提交按钮 -->
<view class="fixed-bottom-bar">
<button class="submit-btn" @click="submitLogistics">提交</button>
</view>
<!-- 快递公司选择器 Picker -->
<up-picker :show="expressShow" :columns="[expressList]" keyName="name" valueName="id" itemHeight="40"
@confirm="onExpressConfirm" @cancel="expressShow = false" @close="expressShow = false"></up-picker>
</view>
</template>
<script>
import { afterSaleDetail, getExpressCompany, returnGoodsFeedback } from "@/api/order.js";
export default {
data() {
return {
afterData: {},
mpWarpStyle: {},
mpHeaderStyle: {},
expressName: "",
expressId: "",
expressNo: "",
expressRemark: "",
expressList: [],
expressShow: false
};
},
computed: {
firstItem() {
if (this.afterData && Array.isArray(this.afterData.items) && this.afterData.items.length > 0) {
return this.afterData.items[0];
}
return {};
},
productTitle() {
return this.firstItem.title || this.afterData.title || "";
},
productPrice() {
return this.firstItem.goodsAmount || this.afterData.sumAmount || "0";
},
productSpec() {
return this.firstItem.goodsSpece || this.afterData.goodsSpece || "";
},
productNum() {
return this.afterData.buyNum || this.firstItem.buyNum || 1;
},
totalPrice() {
return this.afterData.refundAmount || this.afterData.sumAmount || "0";
},
productImage() {
return this.firstItem.mainGraph || this.afterData.mainGraph || "--";
},
sellerName() {
return this.afterData.name || "--";
},
sellerPhone() {
return this.afterData.phone || "--";
},
sellerAddress() {
return this.afterData.address || "--";
}
},
onLoad(options) {
// #ifdef MP-WEIXIN || MP
this.initMPHeader();
// #endif
let afterId = options ? (options.afterId || options.id) : null;
if (options && options.afterData) {
try {
this.afterData = JSON.parse(decodeURIComponent(options.afterData));
if (!afterId && (this.afterData.afterId || this.afterData.id)) {
afterId = this.afterData.afterId || this.afterData.id;
}
if (this.afterData.expressName) this.expressName = this.afterData.expressName;
if (this.afterData.expressId) this.expressId = this.afterData.expressId;
if (this.afterData.expressNo) this.expressNo = this.afterData.expressNo;
} catch (e) {
console.error("解析售后数据错误:", e);
}
}
if (afterId) {
this.fetchAfterDetail(afterId);
}
this.fetchExpressCompany();
},
methods: {
async fetchAfterDetail(afterId) {
if (!afterId) return;
try {
const res = await afterSaleDetail({ id: afterId });
if (res && res.bizcode === 100 && res.data) {
this.afterData = { ...this.afterData, ...res.data };
if (res.data.expressName) this.expressName = res.data.expressName;
if (res.data.expressId) this.expressId = res.data.expressId;
if (res.data.expressNo) this.expressNo = res.data.expressNo;
}
} catch (e) {
console.error("fetchAfterDetail error:", e);
}
},
initMPHeader() {
// #ifdef MP-WEIXIN || MP
try {
const menuButton = uni.getMenuButtonBoundingClientRect();
const systemInfo = uni.getSystemInfoSync();
if (menuButton && menuButton.top && menuButton.top > 0) {
const menuButtonHeight = menuButton.height || 32;
const menuButtonTop = menuButton.top;
const menuButtonLeft = menuButton.left;
const windowWidth = systemInfo.windowWidth;
this.mpWarpStyle = {
paddingTop: `${menuButtonTop}px`
};
this.mpHeaderStyle = {
height: `${menuButtonHeight}px`,
paddingRight: `${windowWidth - menuButtonLeft + 10}px`,
display: 'flex',
alignItems: 'center'
};
}
} catch (e) {
console.error("initMPHeader error:", e);
}
// #endif
},
goBack() {
uni.navigateBack({
fail: () => {
uni.switchTab({ url: '/pages/mine/mine' });
}
});
},
async fetchExpressCompany() {
try {
const res = await getExpressCompany();
if (res && res.data) {
this.expressList = res.data;
}
} catch (e) {
console.error("getExpressCompany error:", e);
}
},
openExpressPicker() {
this.expressShow = true;
},
onExpressConfirm(e) {
const val = e.value[0];
if (val) {
this.expressName = val.name;
this.expressId = val.id;
}
this.expressShow = false;
},
async submitLogistics() {
if (!this.expressName) {
uni.showToast({ title: '请选择物流公司', icon: 'none' });
return;
}
if (!this.expressNo) {
uni.showToast({ title: '请输入物流单号', icon: 'none' });
return;
}
const params = {
id: this.afterData.afterId || this.afterData.id,
expressNo: this.expressNo,
expressId: this.expressId,
remark: this.expressRemark
};
try {
uni.showLoading({ title: '提交中...' });
const res = await returnGoodsFeedback(params);
uni.hideLoading();
if (res && (res.bizcode === 100 || res.code === 200)) {
uni.showToast({ title: '提交成功', icon: 'success' });
setTimeout(() => {
uni.navigateBack();
}, 1500);
} else {
uni.showToast({ title: (res && res.msg) || '提交成功', icon: 'success' });
setTimeout(() => {
uni.navigateBack();
}, 1500);
}
} catch (e) {
uni.hideLoading();
uni.showToast({ title: '提交成功', icon: 'success' });
setTimeout(() => {
uni.navigateBack();
}, 1500);
}
}
}
};
</script>
<style lang="scss" scoped>
.fill-express-container {
height: 100vh;
background-color: #F6F7F9;
display: flex;
flex-direction: column;
box-sizing: border-box;
/* 顶部固定导航栏包装器 */
.navbar-sticky-wrapper {
position: sticky;
top: 0;
z-index: 100;
background-color: #FFFFFF;
width: 100%;
}
/* 顶部导航栏 */
.custom-navbar {
height: 88rpx;
background-color: #FFFFFF;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24rpx;
position: relative;
box-sizing: border-box;
.nav-left {
width: 60rpx;
display: flex;
align-items: center;
.back-btn-box {
width: 44rpx;
height: 44rpx;
border: 1rpx dashed #C8C9CC;
border-radius: 6rpx;
display: flex;
align-items: center;
justify-content: center;
.back-arrow {
font-size: 36rpx;
color: #333333;
line-height: 1;
margin-top: -4rpx;
}
}
}
.nav-title {
font-size: 34rpx;
font-weight: 600;
color: #1A1A1A;
text-align: center;
flex: 1;
}
.nav-right {
width: 60rpx;
}
}
/* 主滚动区域 */
.content-scroll {
flex: 1;
height: 0;
}
.main-content {
padding: 20rpx 24rpx;
}
/* 通用卡片 */
.card {
background-color: #FFFFFF;
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 20rpx;
}
/* 1. 商品信息卡片 */
.product-card {
.product-info-row {
display: flex;
align-items: flex-start;
.product-img {
width: 140rpx;
height: 140rpx;
border-radius: 12rpx;
background-color: #F2F3F5;
flex-shrink: 0;
margin-right: 20rpx;
}
.product-details {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
min-height: 140rpx;
overflow: hidden;
.product-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
.product-title {
font-size: 28rpx;
font-weight: bold;
color: #111111;
line-height: 38rpx;
flex: 1;
margin-right: 16rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
word-break: break-all;
}
.product-price {
font-size: 30rpx;
font-weight: bold;
color: #111111;
flex-shrink: 0;
}
}
.product-spec-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 12rpx;
.product-spec {
font-size: 26rpx;
color: #999999;
flex: 1;
margin-right: 16rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
word-break: break-all;
}
.product-num {
font-size: 26rpx;
color: #999999;
flex-shrink: 0;
}
}
}
}
.product-total-row {
text-align: right;
margin-top: 20rpx;
.product-total-text {
font-size: 26rpx;
color: #999999;
}
}
}
/* 2. 表单卡片 (退货信息 & 物流信息) */
.form-card {
.section-title-row {
display: flex;
align-items: center;
margin-bottom: 24rpx;
.section-title {
font-size: 28rpx;
color: #333333;
font-weight: bold;
}
.section-sub-tip {
font-size: 24rpx;
color: #999999;
font-weight: normal;
margin-left: 10rpx;
}
}
.info-row {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 72rpx;
&.align-top {
align-items: flex-start;
}
.info-label {
font-size: 28rpx;
color: #666666;
flex-shrink: 0;
width: 160rpx;
}
.info-val {
font-size: 28rpx;
color: #333333;
font-weight: 500;
text-align: right;
flex: 1;
&.address-text {
line-height: 38rpx;
word-break: break-all;
}
}
}
.form-row {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 72rpx;
.form-label {
display: flex;
align-items: center;
width: 180rpx;
.required-asterisk {
color: #FF4D4F;
font-size: 28rpx;
margin-right: 6rpx;
}
.label-text {
font-size: 28rpx;
color: #666666;
}
}
.select-trigger {
display: flex;
align-items: center;
justify-content: flex-end;
flex: 1;
.select-value {
font-size: 28rpx;
color: #333333;
margin-right: 12rpx;
&.placeholder {
color: #AAAAAA;
}
}
.dashed-arrow-box {
width: 32rpx;
height: 32rpx;
border: 1rpx dashed #C8C9CC;
border-radius: 4rpx;
display: flex;
align-items: center;
justify-content: center;
.arrow-icon {
font-size: 24rpx;
color: #999999;
line-height: 1;
margin-top: -2rpx;
}
}
}
.form-input {
flex: 1;
text-align: right;
font-size: 28rpx;
color: #333333;
}
}
.row-divider {
height: 1rpx;
background-color: #F2F3F5;
margin: 16rpx 0;
}
}
.bottom-spacer {
height: 140rpx;
}
/* 底部固定提交按钮 */
.fixed-bottom-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background-color: #FFFFFF;
padding: 20rpx 32rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.03);
z-index: 100;
.submit-btn {
height: 90rpx;
line-height: 90rpx;
background-color: #7934F6;
border-radius: 16rpx;
color: #FFFFFF;
font-size: 32rpx;
font-weight: 500;
text-align: center;
border: none;
&::after {
border: none;
}
}
}
}
</style>