| | |
| | | class="search-box__input" |
| | | type="text" |
| | | v-model="keyword" |
| | | placeholder="搜索车辆编号/手机号" |
| | | placeholder="搜索用户手机号" |
| | | placeholder-class="search-box__placeholder" |
| | | confirm-type="search" |
| | | @confirm="handleSearch" |
| | | /> |
| | | </view> |
| | | </view> |
| | |
| | | </view> |
| | | |
| | | <view class="order-list"> |
| | | <view class="order-card" v-for="item in filteredOrders" :key="item.id"> |
| | | <view class="order-card" v-for="item in list" :key="item.id"> |
| | | <view class="order-card__head"> |
| | | <view class="order-card__code">车辆编号:{{ item.code }}</view> |
| | | <view class="order-card__amount" v-if="activeTab === 'completed'">{{ item.amount }}</view> |
| | | <view class="order-card__code">订单编号:{{ item.code || '-' }}</view> |
| | | </view> |
| | | <view class="order-card__row">车辆类型:{{ item.vehicleType }}</view> |
| | | <view class="order-card__row">用户手机:{{ item.mobile }}</view> |
| | | <view class="order-card__row">骑行时间:{{ item.rideTime }}</view> |
| | | <view class="order-card__row">车辆编号:{{ item.bikeCode || '-' }}</view> |
| | | <view class="order-card__row">订单类型:{{ item.bikeTypeText }}</view> |
| | | <view class="order-card__row">结算车型:{{ item.paramName || '-' }}</view> |
| | | <view class="order-card__row">用户手机:{{ item.phone || '-' }}</view> |
| | | <view class="order-card__row">骑行开始时间:{{ item.rentDate || '-' }}</view> |
| | | <view v-if="activeTab === 'completed'" class="order-card__row">结算时间:{{ item.closeDate || '-' }}</view> |
| | | |
| | | <view class="order-card__footer"> |
| | | <view class="order-card__track" @click="handleAction('查看轨迹')">查看轨迹</view> |
| | | <view v-if="Number(item.bikeType) === 1" class="order-card__track" @click="handleAction('查看轨迹', item)">查看轨迹</view> |
| | | <view class="order-card__actions" v-if="activeTab === 'renting'"> |
| | | <view class="action-btn action-btn--line" @click="handleAction('开锁')">开锁</view> |
| | | <view class="action-btn action-btn--line" @click="handleAction('关锁')">关锁</view> |
| | | <view class="action-btn action-btn--primary" @click="handleAction('强制还车')">强制还车</view> |
| | | <view v-if="Number(item.bikeType) === 1" class="action-btn action-btn--line" @click="handleAction('开锁', item)">开锁</view> |
| | | <view v-if="Number(item.bikeType) === 1" class="action-btn action-btn--line" @click="handleAction('关锁', item)">关锁</view> |
| | | <view class="action-btn action-btn--primary" @click="handleAction('强制还车', item)">强制还车</view> |
| | | </view> |
| | | <view class="order-card__actions" v-else> |
| | | <view class="action-btn action-btn--warn" @click="handleAction('退款')">退款</view> |
| | | <view class="action-btn action-btn--warn" @click="handleAction('退款', item)">退款</view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="empty-state" v-if="!filteredOrders.length">暂无订单数据</view> |
| | | <view class="empty-state" v-if="!list.length && !loading">暂无订单数据</view> |
| | | <view class="load-more-tip" v-if="list.length"> |
| | | {{ loading ? '加载中...' : (finished ? '没有更多了' : '上拉加载更多') }} |
| | | </view> |
| | | </view> |
| | | |
| | | <u-popup :show="showVehicleTypePopup" :round="16" mode="bottom" @close="showVehicleTypePopup = false"> |
| | |
| | | <view class="huanche_tips">强制还车后,车辆行程结束并自动结算</view> |
| | | <view class="huanche_footer"> |
| | | <view class="huanche_footer_btn line" @click="show = false">取消</view> |
| | | <view class="huanche_footer_btn pr">确定还车</view> |
| | | <view class="huanche_footer_btn pr" @click="confirmForceBack">确定还车</view> |
| | | </view> |
| | | </view> |
| | | </u-popup> |
| | | <!-- 订单退款 --> |
| | | <u-popup :show="show1" :closeOnClickOverlay="true" mode="bottom" bgColor="#fff" :round="10" @close="show1 = false"> |
| | | <u-popup :show="show1" :closeOnClickOverlay="true" mode="bottom" bgColor="#fff" :round="10" @close="closeRefundPopup"> |
| | | <view class="huanche"> |
| | | <view class="huanche_title">订单退款</view> |
| | | <view class="huanche_info"> |
| | | <view class="huanche_info_item"> |
| | | <view class="label">充值金额:</view> |
| | | <view class="val">100元</view> |
| | | <view class="val">{{ formatMoneyText(refundInfo.goodsorderMoney) }}</view> |
| | | </view> |
| | | <view class="huanche_info_item"> |
| | | <view class="label">结算金额:</view> |
| | | <view class="val">50元</view> |
| | | <view class="val">{{ formatMoneyText(refundInfo.closeMoney) }}</view> |
| | | </view> |
| | | <view class="huanche_info_item"> |
| | | <view class="label">已退金额:</view> |
| | | <view class="val">-</view> |
| | | <view class="val">{{ formatMoneyText(refundInfo.hasRefundMoney) }}</view> |
| | | </view> |
| | | <view class="huanche_info_item"> |
| | | <view class="label">可退金额:</view> |
| | | <view class="val">50元</view> |
| | | <view class="val">{{ formatMoneyText(refundInfo.canBanlanceMoney) }}</view> |
| | | </view> |
| | | </view> |
| | | <view class="huanche_form"> |
| | | <view class="huanche_form_item"> |
| | | <view class="lable"><text>*</text>退款金额(元)</view> |
| | | <view class="val"> |
| | | <input type="text" placeholder="请输入退款金额" /> |
| | | <input v-model="refundForm.money" type="digit" placeholder="请输入退款金额" /> |
| | | </view> |
| | | </view> |
| | | <view class="huanche_form_item"> |
| | | <view class="lable">退款说明</view> |
| | | <view class="val"> |
| | | <input type="text" placeholder="请输入退款原因" /> |
| | | <input v-model="refundForm.reason" type="text" placeholder="请输入退款原因" /> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view class="huanche_footer"> |
| | | <view class="huanche_footer_btn line" @click="show1 = false">取消</view> |
| | | <view class="huanche_footer_btn que">确定还车</view> |
| | | <view class="huanche_footer_btn line" @click="closeRefundPopup">取消</view> |
| | | <view class="huanche_footer_btn que" @click="confirmRefund">确认退款</view> |
| | | </view> |
| | | </view> |
| | | </u-popup> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | const rentingOrders = [ |
| | | { |
| | | id: 1, |
| | | code: 'BH1018', |
| | | vehicleType: '双排四座电动代步车', |
| | | mobile: '180****9930', |
| | | rideTime: '2025-05-01 11:30:52', |
| | | type: 'electric' |
| | | }, |
| | | { |
| | | id: 2, |
| | | code: 'BH1018', |
| | | vehicleType: '双排四座电动代步车', |
| | | mobile: '180****9930', |
| | | rideTime: '2025-05-01 11:30:52', |
| | | type: 'electric' |
| | | }, |
| | | { |
| | | id: 3, |
| | | code: 'BH1018', |
| | | vehicleType: '双排四座电动代步车', |
| | | mobile: '180****9930', |
| | | rideTime: '2025-05-01 11:30:52', |
| | | type: 'electric' |
| | | } |
| | | ] |
| | | |
| | | const completedOrders = [ |
| | | { |
| | | id: 11, |
| | | code: 'BH1018', |
| | | vehicleType: '双排四座电动代步车', |
| | | mobile: '180****9930', |
| | | rideTime: '05-01 11:30:52~05-01 12:21:11', |
| | | amount: '¥100.00', |
| | | type: 'electric' |
| | | }, |
| | | { |
| | | id: 12, |
| | | code: 'BH1018', |
| | | vehicleType: '双排四座电动代步车', |
| | | mobile: '180****9930', |
| | | rideTime: '05-01 11:30:52~05-01 12:21:11', |
| | | amount: '¥100.00', |
| | | type: 'electric' |
| | | }, |
| | | { |
| | | id: 13, |
| | | code: 'BH1018', |
| | | vehicleType: '双排四座电动代步车', |
| | | mobile: '180****9930', |
| | | rideTime: '05-01 11:30:52~05-01 12:21:11', |
| | | amount: '¥100.00', |
| | | type: 'electric' |
| | | } |
| | | ] |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | |
| | | activeTab: 'renting', |
| | | keyword: '', |
| | | selectedVehicleType: '', |
| | | page: 1, |
| | | list: [], |
| | | loading: false, |
| | | finished: false, |
| | | updatingLock: false, |
| | | forceBackLoading: false, |
| | | refundLoading: false, |
| | | currentOrderId: '', |
| | | refundOrderId: '', |
| | | refundInfo: { |
| | | canBanlanceMoney: '', |
| | | closeMoney: '', |
| | | goodsorderMoney: '', |
| | | hasRefundMoney: '' |
| | | }, |
| | | refundForm: { |
| | | money: '', |
| | | reason: '' |
| | | }, |
| | | searchTimer: null, |
| | | showVehicleTypePopup: false, |
| | | vehicleTypeOptions: [ |
| | | { label: '车辆类型', value: '' }, |
| | | { label: '双排四座电动代步车', value: 'electric' }, |
| | | { label: '普通自行车', value: 'bike' } |
| | | ], |
| | | rentingOrders, |
| | | completedOrders |
| | | { label: '订单类型', value: '' }, |
| | | { label: '自行车', value: '0' }, |
| | | { label: '电车', value: '1' } |
| | | ] |
| | | } |
| | | }, |
| | | computed: { |
| | | currentVehicleTypeLabel() { |
| | | const current = this.vehicleTypeOptions.find(item => item.value === this.selectedVehicleType) |
| | | return current ? current.label : '车辆类型' |
| | | return current ? current.label : '订单类型' |
| | | }, |
| | | filteredOrders() { |
| | | const source = this.activeTab === 'renting' ? this.rentingOrders : this.completedOrders |
| | | const keyword = this.keyword.trim().toLowerCase() |
| | | |
| | | return source.filter(item => { |
| | | const matchType = !this.selectedVehicleType || item.type === this.selectedVehicleType |
| | | const searchText = `${item.code}${item.mobile}`.toLowerCase() |
| | | const matchKeyword = !keyword || searchText.includes(keyword) |
| | | return matchType && matchKeyword |
| | | }) |
| | | currentStatus() { |
| | | return this.activeTab === 'renting' ? 1 : 4 |
| | | } |
| | | }, |
| | | watch: { |
| | | activeTab() { |
| | | this.resetAndLoad() |
| | | }, |
| | | selectedVehicleType() { |
| | | this.resetAndLoad() |
| | | }, |
| | | keyword() { |
| | | clearTimeout(this.searchTimer) |
| | | this.searchTimer = setTimeout(() => { |
| | | this.resetAndLoad() |
| | | }, 300) |
| | | } |
| | | }, |
| | | onLoad() { |
| | | this.getList() |
| | | }, |
| | | onReachBottom() { |
| | | this.getList() |
| | | }, |
| | | onUnload() { |
| | | clearTimeout(this.searchTimer) |
| | | }, |
| | | methods: { |
| | | handleSearch() { |
| | | clearTimeout(this.searchTimer) |
| | | this.resetAndLoad() |
| | | }, |
| | | toggleVehicleType() { |
| | | this.showVehicleTypePopup = true |
| | | }, |
| | |
| | | this.selectedVehicleType = value |
| | | this.showVehicleTypePopup = false |
| | | }, |
| | | handleAction(text) { |
| | | resetAndLoad() { |
| | | this.page = 1 |
| | | this.list = [] |
| | | this.finished = false |
| | | this.getList() |
| | | }, |
| | | formatMoneyText(value) { |
| | | if (value === '' || value === null || value === undefined) { |
| | | return '-' |
| | | } |
| | | |
| | | return `${value}元` |
| | | }, |
| | | resetRefundState() { |
| | | this.refundOrderId = '' |
| | | this.refundInfo = { |
| | | canBanlanceMoney: '', |
| | | closeMoney: '', |
| | | goodsorderMoney: '', |
| | | hasRefundMoney: '' |
| | | } |
| | | this.refundForm = { |
| | | money: '', |
| | | reason: '' |
| | | } |
| | | }, |
| | | closeRefundPopup() { |
| | | this.show1 = false |
| | | this.resetRefundState() |
| | | }, |
| | | async updateOrderLock(item, lockStatus) { |
| | | if (!item.bikeCode) { |
| | | uni.showToast({ |
| | | title: '车辆编号不能为空', |
| | | icon: 'none' |
| | | }) |
| | | return |
| | | } |
| | | |
| | | if (this.updatingLock) { |
| | | return |
| | | } |
| | | |
| | | this.updatingLock = true |
| | | |
| | | try { |
| | | const res = await this.$u.api.updateLockStatus({ |
| | | ids: item.bikeCode, |
| | | lockStatus |
| | | }) |
| | | |
| | | uni.showToast({ |
| | | title: res.code === 200 ? (lockStatus === 1 ? '开锁成功' : '关锁成功') : (res.msg || (lockStatus === 1 ? '开锁失败' : '关锁失败')), |
| | | icon: 'none' |
| | | }) |
| | | } catch (error) { |
| | | uni.showToast({ |
| | | title: error.message || (lockStatus === 1 ? '开锁失败' : '关锁失败'), |
| | | icon: 'none' |
| | | }) |
| | | } finally { |
| | | this.updatingLock = false |
| | | } |
| | | }, |
| | | async openRefundPopup(item) { |
| | | if (!item.id) { |
| | | uni.showToast({ |
| | | title: '订单ID不能为空', |
| | | icon: 'none' |
| | | }) |
| | | return |
| | | } |
| | | |
| | | if (this.refundLoading) { |
| | | return |
| | | } |
| | | |
| | | this.refundLoading = true |
| | | |
| | | try { |
| | | const res = await this.$u.api.getGoodsorderCanBanlanceDTO({ |
| | | orderId: item.id |
| | | }) |
| | | |
| | | if (res.code === 200) { |
| | | this.refundOrderId = item.id |
| | | this.refundInfo = { |
| | | canBanlanceMoney: res.data ? res.data.canBanlanceMoney : '', |
| | | closeMoney: res.data ? res.data.closeMoney : '', |
| | | goodsorderMoney: res.data ? res.data.goodsorderMoney : '', |
| | | hasRefundMoney: res.data ? res.data.hasRefundMoney : '' |
| | | } |
| | | this.refundForm = { |
| | | money: '', |
| | | reason: '' |
| | | } |
| | | this.show1 = true |
| | | } |
| | | |
| | | |
| | | } finally { |
| | | this.refundLoading = false |
| | | } |
| | | }, |
| | | async confirmRefund() { |
| | | if (!this.refundOrderId) { |
| | | uni.showToast({ |
| | | title: '订单ID不能为空', |
| | | icon: 'none' |
| | | }) |
| | | return |
| | | } |
| | | |
| | | if (!this.refundForm.money) { |
| | | uni.showToast({ |
| | | title: '请输入退款金额', |
| | | icon: 'none' |
| | | }) |
| | | return |
| | | } |
| | | |
| | | if (this.refundLoading) { |
| | | return |
| | | } |
| | | |
| | | this.refundLoading = true |
| | | |
| | | try { |
| | | const res = await this.$u.api.backGoodsorder({ |
| | | orderId: this.refundOrderId, |
| | | reason: this.refundForm.reason.trim(), |
| | | money: this.refundForm.money |
| | | }) |
| | | |
| | | |
| | | |
| | | if (res.code === 200) { |
| | | this.closeRefundPopup() |
| | | this.resetAndLoad() |
| | | uni.showToast({ |
| | | title: '退款成功', |
| | | icon: 'none' |
| | | }) |
| | | } |
| | | } finally { |
| | | this.refundLoading = false |
| | | } |
| | | }, |
| | | async confirmForceBack() { |
| | | if (!this.currentOrderId) { |
| | | uni.showToast({ |
| | | title: '订单ID不能为空', |
| | | icon: 'none' |
| | | }) |
| | | return |
| | | } |
| | | |
| | | if (this.forceBackLoading) { |
| | | return |
| | | } |
| | | |
| | | this.forceBackLoading = true |
| | | |
| | | try { |
| | | const res = await this.$u.api.forceBack({ |
| | | id: this.currentOrderId |
| | | }) |
| | | if (res.code === 200) { |
| | | this.show = false |
| | | this.currentOrderId = '' |
| | | this.resetAndLoad() |
| | | } |
| | | } finally { |
| | | this.forceBackLoading = false |
| | | } |
| | | }, |
| | | formatBikeType(bikeType) { |
| | | return Number(bikeType) === 1 ? '电车' : '自行车' |
| | | }, |
| | | async getList() { |
| | | if (this.loading || this.finished) { |
| | | return |
| | | } |
| | | |
| | | this.loading = true |
| | | |
| | | const model = { |
| | | phone: this.keyword.trim(), |
| | | status: this.currentStatus |
| | | } |
| | | |
| | | if (this.selectedVehicleType !== '') { |
| | | model.bikeType = Number(this.selectedVehicleType) |
| | | } |
| | | |
| | | try { |
| | | const res = await this.$u.api.operationOrderPage({ |
| | | capacity: 10, |
| | | page: this.page, |
| | | model |
| | | }) |
| | | |
| | | if (res.code === 200) { |
| | | const records = (res.data && res.data.records) || [] |
| | | const total = Number(res.data && res.data.total) |
| | | const list = records.map(item => ({ |
| | | ...item, |
| | | bikeTypeText: this.formatBikeType(item.bikeType) |
| | | })) |
| | | |
| | | this.list.push(...list) |
| | | this.page += 1 |
| | | |
| | | if (!records.length || (Number.isFinite(total) && total > 0 ? this.list.length >= total : records.length < 10)) { |
| | | this.finished = true |
| | | } |
| | | } |
| | | } finally { |
| | | this.loading = false |
| | | } |
| | | }, |
| | | async handleAction(text, item = {}) { |
| | | if (text === '开锁') { |
| | | await this.updateOrderLock(item, 1) |
| | | return |
| | | } |
| | | |
| | | if (text === '关锁') { |
| | | await this.updateOrderLock(item, 0) |
| | | return |
| | | } |
| | | |
| | | if (text === '强制还车') { |
| | | this.currentOrderId = item.id || '' |
| | | this.show = true |
| | | } else if (text === '退款') { |
| | | this.show1 = true |
| | | await this.openRefundPopup(item) |
| | | } else if (text === '查看轨迹') { |
| | | uni.navigateTo({ |
| | | url: `/pages/trajectory/trajectory?id=${item.id}` |
| | | }) |
| | | } |
| | | // uni.showToast({ |
| | | // title: `${text}功能待接入`, |
| | |
| | | margin-left: 16rpx; |
| | | font-size: 26rpx; |
| | | color: #333333; |
| | | background: transparent; |
| | | } |
| | | |
| | | .search-box__placeholder { |
| | |
| | | line-height: 58rpx; |
| | | } |
| | | |
| | | .order-card__amount { |
| | | font-weight: 600; |
| | | font-size: 28rpx; |
| | | color: #FF5A31; |
| | | line-height: 50rpx; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .order-card__row { |
| | | font-weight: 400; |
| | | font-size: 26rpx; |
| | |
| | | line-height: 44rpx; |
| | | } |
| | | |
| | | .load-more-tip { |
| | | padding: 28rpx 0 10rpx; |
| | | font-size: 24rpx; |
| | | line-height: 36rpx; |
| | | text-align: center; |
| | | color: #999999; |
| | | } |
| | | |
| | | .order-card__footer { |
| | | margin-top: 22rpx; |
| | | padding: 18rpx 0 20rpx; |