|
|
- <template>
- <view class="container">
- <!-- 顶部导航 -->
- <view class="nav-bar">
- <view class="back" @tap="goBack">
- <text class="iconfont">←</text>
- </view>
- <text class="title">修改订单</text>
- <view class="right-btns">
- <text class="more">⋯</text>
- <text class="share">○</text>
- </view>
- </view>
-
- <!-- 内容区域 -->
- <view class="content">
- <!-- 回收流程卡片 -->
- <view class="card process-card">
- <view class="card-title">回收流程</view>
- <view class="process-steps">
- <view class="step-item">
- <image src="/static/pickup/note.png" mode="aspectFit"></image>
- <view class="step-label">
- <text class="step-num">①</text>
- <text>在线预约</text>
- </view>
- </view>
- <view class="step-item">
- <image src="/static/pickup/box.png" mode="aspectFit"></image>
- <view class="step-label">
- <text class="step-num">②</text>
- <text>快递上门</text>
- </view>
- </view>
- <view class="step-item">
- <image src="/static/pickup/search.png" mode="aspectFit"></image>
- <view class="step-label">
- <text class="step-num">③</text>
- <text>透明质检</text>
- </view>
- </view>
- <view class="step-item">
- <image src="/static/pickup/money.png" mode="aspectFit"></image>
- <view class="step-label">
- <text class="step-num">④</text>
- <text>现金打款</text>
- </view>
- </view>
- </view>
- <view class="divider"></view>
-
- <!-- 取件信息 -->
- <view class="pickup-info">
- <view class="info-item" @tap="selectAddress">
- <text class="label">取件地址</text>
- <view class="value">
- <text class="text">{{ displayAddress }}</text>
- <text class="arrow">></text>
- </view>
- </view>
- <view class="info-item" @tap="openTimePicker">
- <text class="label">上门时间</text>
- <view class="value">
- <text class="text">{{ appointmentTime }}</text>
- <text class="arrow">></text>
- </view>
- </view>
- </view>
- </view>
-
- <!-- 订单详情卡片 -->
- <view class="card">
- <view class="card-header">
- <text class="title">订单详情</text>
- </view>
- <view class="order-items">
- <view class="order-item" v-for="(item, index) in selectedItems" :key="index">
- <image :src="item.icon" mode="aspectFit"></image>
- <view class="item-info">
- <view class="name-row">
- <text class="name">{{ item.name }}</text>
- <text class="rules" @tap="showRules">回收规则 ></text>
- </view>
- <text class="desc">{{ item.desc }}</text>
- <text class="price">¥ {{ item.unitPrice }}/件</text>
- </view>
- <view class="quantity-control">
- <text class="btn minus" @tap="decreaseQuantity(index)">-</text>
- <text class="quantity">{{ item.quantity }}</text>
- <text class="btn plus" @tap="increaseQuantity(index)">+</text>
- </view>
- </view>
- </view>
- </view>
- </view>
-
- <!-- 底部提交栏 -->
- <view class="bottom-bar">
- <view class="agreement">
- <view class="custom-checkbox" :class="{ active: agreed }" @tap="toggleAgreement">
- <text v-if="agreed" class="checkbox-icon">✓</text>
- </view>
- <text>我已阅读并同意</text>
- <text class="link">《回收服务协议》</text>
- <text>和</text>
- <text class="link">《隐私政策》</text>
- </view>
- <view class="submit-info">
- <view class="submit-infos">
- <view class="count">
- <text>已选</text>
- <text class="num">{{ totalCount }}</text>
- <text>件</text>
- <text class="estimate">预估回收可得</text>
- </view>
- <view class="price">
- <!-- <text class="symbol">¥</text> -->
- <text class="value">{{ totalPriceRange }}</text>
- </view>
- </view>
-
- <view class="price-submit">
- <button class="submit-btn" :disabled="!canSubmit" @tap="submitOrder">
- 预约上门取件
- </button>
- </view>
- </view>
- </view>
-
- <!-- 时间选择器弹窗 -->
- <view class="time-picker" v-if="showTimePicker">
- <view class="mask" @tap="closeTimePicker"></view>
- <view class="picker-content">
- <view class="picker-header">
- <text class="reset" @tap="resetPicker">重置</text>
- <text class="title">预约上门时间</text>
- </view>
- <view class="date-tabs">
- <view
- class="date-tab"
- v-for="(tab, index) in ['今天', '明天', '后天', '自定义']"
- :key="index"
- :class="{ active: currentDateTab === index }"
- @tap="selectDateTab(index)"
- >
- {{ tab }}
- </view>
- </view>
- <picker-view
- class="time-picker-view"
- :value="pickerValue"
- @change="onPickerChange"
- >
- <picker-view-column>
- <view class="picker-item" v-for="year in years" :key="year">{{year}}年</view>
- </picker-view-column>
- <picker-view-column>
- <view class="picker-item" v-for="month in months" :key="month">{{month}}月</view>
- </picker-view-column>
- <picker-view-column>
- <view class="picker-item" v-for="day in days" :key="day">{{day}}日</view>
- </picker-view-column>
- </picker-view>
- <view class="confirm-btn" @tap="confirmTime">确认</view>
- </view>
- </view>
- </view>
- </template>
-
- <script>
- import pullRefreshMixin from '@/pages/mixins/pullRefreshMixin.js'
-
- export default {
- mixins: [pullRefreshMixin],
- data() {
- return {
- address: '',
- selectedAddress: null,
- displayAddress: '请选择取件地址',
- addressDetail: {
- province: '',
- city: '',
- district: '',
- street: '',
- address: '',
- name: '',
- phone: '',
- isDefault: false
- },
- appointmentTime: '预约 周四 11:00~13:00',
- timeDetail: {
- date: '',
- time: '',
- displayText: ''
- },
- totalCount: 16,
- estimatePrice: '73.6-75.8',
- agreed: true,
- showTimePicker: false,
- currentDateTab: 0,
- pickerValue: [0, 0, 0],
- years: [],
- months: [],
- days: [],
- selectedDate: '',
- timeSlot: '11:00~13:00', // 固定时间段
- selectedItems: [
- {
- name: '羽绒服',
- desc: '允许脏破烂,160码以上',
- unitPrice: 8,
- quantity: 8
- },
- {
- name: '品牌羽绒服',
- desc: '允许脏破烂,160码以上',
- unitPrice: 10,
- quantity: 1
- }
- ],
- totalPriceRange: '¥ 73.6-75.8'
- }
- },
- computed: {
- displayAddress() {
- if (this.selectedAddress) {
- return this.selectedAddress.address
- }
- return '请选择取件地址'
- },
- totalPriceRange() {
- const totalPrice = this.selectedItems.reduce((total, item) => total + item.unitPrice * item.quantity, 0)
- return `¥ ${totalPrice.toFixed(2)}-${(totalPrice + 2).toFixed(2)}`
- },
- canSubmit() {
- return this.agreed &&
- this.selectedAddress &&
- this.timeDetail.date &&
- this.selectedItems.length > 0
- }
- },
- methods: {
- async onRefresh() {
- // 模拟刷新数据
- await new Promise(resolve => setTimeout(resolve, 1000))
- this.stopPullRefresh()
- },
- goBack() {
- uni.navigateBack()
- },
- selectAddress() {
- uni.navigateTo({
- url: '/pages/component/select'
- })
- },
- openTimePicker() {
- this.showTimePicker = true
- if (!this.years.length) {
- this.initDatePicker()
- }
- },
- closeTimePicker() {
- this.showTimePicker = false
- },
- initDatePicker() {
- const currentDate = new Date()
- const currentYear = currentDate.getFullYear()
-
- // 生成年份数据(从当年开始)
- this.years = Array.from({length: 5}, (_, i) => currentYear + i)
-
- // 生成月份数据
- this.months = Array.from({length: 12}, (_, i) => i + 1)
-
- // 生成日期数据
- this.updateDays(currentYear, currentDate.getMonth() + 1)
-
- // 设置默认值为当前日期
- this.pickerValue = [0, currentDate.getMonth(), currentDate.getDate() - 1]
- },
-
- updateDays(year, month) {
- const daysInMonth = new Date(year, month, 0).getDate()
- this.days = Array.from({length: daysInMonth}, (_, i) => i + 1)
- },
-
- selectDateTab(index) {
- this.currentDateTab = index
-
- if (index < 3) { // 今天、明天、后天
- const date = new Date()
- date.setDate(date.getDate() + index)
-
- // 找到对应的年份索引
- const yearIndex = this.years.findIndex(year => year === date.getFullYear())
-
- this.pickerValue = [
- yearIndex,
- date.getMonth(),
- date.getDate() - 1
- ]
-
- // 更新天数
- this.updateDays(date.getFullYear(), date.getMonth() + 1)
- }
- },
-
- onPickerChange(e) {
- // 切换到自定义选项
- this.currentDateTab = 3
-
- const values = e.detail.value
- const year = this.years[values[0]]
- const month = this.months[values[1]]
-
- // 更新天数
- this.updateDays(year, month)
-
- // 如果选择的日期超过了当月的最大天数,调整为最后一天
- if (values[2] >= this.days.length) {
- values[2] = this.days.length - 1
- }
-
- this.pickerValue = values
- },
-
- resetPicker() {
- this.initDatePicker()
- this.currentDateTab = 0
- },
-
- confirmTime() {
- const year = this.years[this.pickerValue[0]]
- const month = this.months[this.pickerValue[1]]
- const day = this.days[this.pickerValue[2]]
-
- // 创建日期对象
- const date = new Date(year, month - 1, day)
-
- // 获取周几
- const weekDays = ['日', '一', '二', '三', '四', '五', '六']
- const weekDay = weekDays[date.getDay()]
-
- // 设置格式化后的时间
- this.timeDetail = {
- date: `${year}-${month}-${day}`,
- time: this.timeSlot,
- displayText: `预约 周${weekDay} ${this.timeSlot}`
- }
- this.appointmentTime = this.timeDetail.displayText
-
- this.closeTimePicker()
- },
-
- handleAddressSelected(address) {
- console.log('接收到选中的地址:', address)
- this.selectedAddress = address
- this.address = address.address
- this.$forceUpdate()
- },
- handleTimeSelected(time) {
- this.timeDetail = time
- this.appointmentTime = time.displayText
- },
- showRules() {
- uni.navigateTo({
- url: '/pages/rules/recycle'
- })
- },
- toggleAgreement() {
- this.agreed = !this.agreed
- },
- viewAgreement() {
- uni.navigateTo({
- url: '/pages/agreement/service'
- })
- },
- viewPrivacy() {
- uni.navigateTo({
- url: '/pages/agreement/privacy'
- })
- },
- submitOrder() {
- // 表单验证
- if (!this.agreed) {
- return uni.showToast({
- title: '请先同意服务协议',
- icon: 'none'
- })
- }
- if (!this.selectedAddress) {
- return uni.showToast({
- title: '请选择取件地址',
- icon: 'none'
- })
- }
- if (!this.timeDetail.date) {
- return uni.showToast({
- title: '请选择上门时间',
- icon: 'none'
- })
- }
- if (this.selectedItems.length === 0) {
- return uni.showToast({
- title: '请选择回收物品',
- icon: 'none'
- })
- }
-
- // 提交订单
- uni.showLoading({
- title: '提交中...'
- })
-
- // 构建订单数据
- const orderData = {
- address: this.selectedAddress,
- time: this.timeDetail,
- items: this.selectedItems,
- totalCount: this.totalCount,
- totalPrice: this.totalPriceRange
- }
-
- // 模拟提交
- setTimeout(() => {
- uni.hideLoading()
- uni.showToast({
- title: '修改成功',
- icon: 'success'
- })
- setTimeout(() => {
- uni.navigateBack()
- }, 1500)
- }, 1000)
- },
- decreaseQuantity(index) {
- if (this.selectedItems[index].quantity > 1) {
- this.selectedItems[index].quantity--
- }
- },
- increaseQuantity(index) {
- this.selectedItems[index].quantity++
- }
- },
- onLoad(options) {
- if (options.id) {
- this.addressDetail = {
- province: '海南省',
- city: '海口市',
- district: '秀英区',
- street: '秀英街道',
- address: '5单元1...',
- name: '张三',
- phone: '13800138000'
- }
- this.timeDetail = {
- date: '2024-03-21',
- time: '11:00-13:00',
- displayText: '周四 11:00~13:00'
- }
- }
-
- // 监听地址选择事件
- uni.$on('addressSelected', (address) => {
- console.log('接收到选中的地址:', address)
- this.selectedAddress = address
- this.address = address.address
- this.$forceUpdate()
- })
- },
- onUnload() {
- // 页面卸载时移除事件监听
- uni.$off('addressSelected')
- },
- onShow() {
- // 页面显示时触发,包括从地址选择页面返回时
- console.log('当前选中的地址:', this.selectedAddress)
- if (this.selectedAddress) {
- // 确保地址信息被正确更新
- this.address = this.selectedAddress.address
- // 强制更新视图
- this.$forceUpdate()
- }
-
- const selectedTime = getApp().globalData.selectedTime
- if (selectedTime) {
- this.handleTimeSelected(selectedTime)
- getApp().globalData.selectedTime = null
- }
- },
- created() {
- this.initDatePicker()
- },
- watch: {
- showTimePicker(val) {
- if (val) {
- this.updateDays(this.pickerValue[0], this.pickerValue[1])
- }
- }
- }
- }
- </script>
-
- <style lang="scss" scoped>
- .container {
- min-height: 100vh;
- background: #F7F8FA;
- padding-bottom: calc(180rpx + env(safe-area-inset-bottom));
- }
-
- .nav-bar {
- display: flex;
- align-items: center;
- height: 88rpx;
- background: #fff;
- padding: 0 30rpx;
-
- .back {
- padding: 20rpx;
- margin-left: -20rpx;
- }
-
- .title {
- flex: 1;
- text-align: center;
- font-size: 34rpx;
- font-weight: 500;
- }
-
- .right-btns {
- display: flex;
- gap: 30rpx;
-
- .more, .share {
- font-size: 40rpx;
- color: #333;
- }
- }
- }
-
- .content {
- padding: 20rpx;
- }
-
- .card {
- background: #fff;
- border-radius: 20rpx;
- margin-bottom: 20rpx;
- overflow: hidden;
-
- &.process-card {
- background: #fffbf6;
- }
-
- .card-title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- padding: 30rpx;
- border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
- }
- }
-
- .process-steps {
- display: flex;
- justify-content: space-between;
- padding: 30rpx;
-
- .step-item {
- flex: 1;
- display: flex;
- flex-direction: column;
- align-items: center;
-
- image {
- width: 80rpx;
- height: 80rpx;
- margin-bottom: 12rpx;
- }
-
- .step-label {
- text-align: center;
-
- .step-num {
- color: #FF9500;
- font-size: 26rpx;
- margin-right: 4rpx;
- }
-
- text {
- font-size: 26rpx;
- color: #333;
- }
- }
- }
- }
-
- .divider {
- height: 1rpx;
- background: rgba(0, 0, 0, 0.05);
- margin: 0 30rpx;
- }
-
- .pickup-info {
- padding: 0 30rpx;
-
- .info-item {
- padding: 30rpx 0;
- border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
-
- &:last-child {
- border-bottom: none;
- }
-
- .label {
- font-size: 28rpx;
- color: #333;
- margin-bottom: 16rpx;
- display: block;
- }
-
- .value {
- display: flex;
- justify-content: space-between;
- align-items: center;
-
- .text {
- flex: 1;
- font-size: 28rpx;
- color: #333;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- .arrow {
- color: #999;
- font-size: 28rpx;
- margin-left: 10rpx;
- }
- }
- }
- }
-
- .order-items {
- padding: 0 30rpx;
-
- .order-item {
- display: flex;
- align-items: center;
- padding: 30rpx 0;
- border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
-
- &:last-child {
- border-bottom: none;
- }
-
- image {
- width: 120rpx;
- height: 120rpx;
- margin-right: 20rpx;
- }
-
- .item-info {
- flex: 1;
-
- .name-row {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 8rpx;
-
- .name {
- font-size: 30rpx;
- color: #333;
- }
-
- .rules {
- font-size: 24rpx;
- color: #999;
- }
- }
-
- .desc {
- font-size: 24rpx;
- color: #999;
- margin-bottom: 8rpx;
- }
-
- .price {
- font-size: 28rpx;
- color: #FF9500;
- }
- }
-
- .quantity-control {
- display: flex;
- align-items: center;
- margin: 0 20rpx;
-
- .btn {
- width: 60rpx;
- height: 60rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- background: #f5f5f5;
- border-radius: 30rpx;
- font-size: 36rpx;
- color: #333;
- }
-
- .quantity {
- width: 80rpx;
- text-align: center;
- font-size: 28rpx;
- }
- }
- }
- }
-
- .bottom-bar {
- position: fixed;
- left: 0;
- right: 0;
- bottom: 0;
- background: #fff;
- padding: 20rpx 30rpx calc(20rpx + env(safe-area-inset-bottom));
- box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
-
- .agreement {
- display: flex;
- align-items: center;
- margin-bottom: 20rpx;
- font-size: 24rpx;
- color: #666;
-
- .custom-checkbox {
- width: 32rpx;
- height: 32rpx;
- border-radius: 50%;
- border: 2rpx solid #ddd;
- margin-right: 10rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all 0.2s;
-
- &.active {
- background: #FFB74D;
- border-color: #FFB74D;
- }
-
- .checkbox-icon {
- color: #fff;
- font-size: 24rpx;
- line-height: 1;
- }
- }
-
- .link {
- color: #FFB74D;
- margin: 0 4rpx;
- }
- }
-
- .submit-info {
- display: flex;
- justify-content: space-between;
- align-items: center;
- .price {
- margin-right: 20rpx;
-
- .symbol {
- font-size: 24rpx;
- color: #FF9500;
- }
-
- .value {
- font-size: 36rpx;
- color: #FF9500;
- font-weight: bold;
- }
- }
-
- .count {
- font-size: 26rpx;
- color: #666;
-
- .num {
- color: #FF9500;
- margin: 0 4rpx;
- }
-
- .estimate {
- margin-left: 20rpx;
- }
- }
-
- .price-submit {
- display: flex;
- align-items: center;
-
-
- .submit-btn {
- height: 80rpx;
- padding: 0 40rpx;
- background: #FFB74D;
- color: #fff;
- font-size: 28rpx;
- border-radius: 40rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- border: none;
-
- &[disabled] {
- opacity: 0.5;
- }
-
- &::after {
- border: none;
- }
- }
- }
- }
- }
-
- .time-picker {
- position: fixed;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- z-index: 1000;
-
- .mask {
- position: absolute;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- background: rgba(0, 0, 0, 0.5);
- }
-
- .picker-content {
- position: absolute;
- left: 0;
- right: 0;
- bottom: 0;
- background: #fff;
- border-radius: 20rpx 20rpx 0 0;
- padding-bottom: env(safe-area-inset-bottom);
-
- .picker-header {
- padding: 30rpx;
- display: flex;
- align-items: center;
- border-bottom: 1rpx solid #eee;
-
- .reset {
- color: #666;
- font-size: 28rpx;
- }
-
- .title {
- flex: 1;
- text-align: center;
- font-size: 32rpx;
- font-weight: 500;
- }
- }
-
- .date-tabs {
- display: flex;
- padding: 20rpx;
- background: #f8f8f8;
-
- .date-tab {
- flex: 1;
- height: 70rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 28rpx;
- color: #333;
- background: #fff;
- margin: 0 10rpx;
- border-radius: 8rpx;
-
- &:last-child {
- color: #FF9500;
- background: rgba(255, 149, 0, 0.1);
- }
-
- &.active {
- background: #FF9500;
- color: #fff;
- }
- }
- }
-
- .time-picker-view {
- width: 100%;
- height: 400rpx;
-
- .picker-item {
- line-height: 80rpx;
- text-align: center;
- }
- }
-
- .confirm-btn {
- margin: 30rpx;
- height: 90rpx;
- background: #FF9500;
- color: #fff;
- font-size: 32rpx;
- border-radius: 45rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- }
- }
- </style>
|