307 lines
12 KiB
Vue
307 lines
12 KiB
Vue
<template>
|
||
<view class="hsw-page">
|
||
<!-- 顶部Tab:全部/待上门/服务中/已完成/月账单 -->
|
||
<view class="hsw-tabs">
|
||
<view
|
||
class="hsw-tab"
|
||
:class="{ active: statusTab === item.v }"
|
||
v-for="item in orderTabs"
|
||
:key="item.v"
|
||
@tap="switchStatus(item.v)"
|
||
>{{ item.t }}</view>
|
||
</view>
|
||
<!-- 月账单子Tab -->
|
||
<view class="hsw-tabs hsw-tabs-bill" v-if="showMonthlyBill">
|
||
<view
|
||
class="hsw-tab"
|
||
:class="{ active: billTab === item.v }"
|
||
v-for="item in billTabs"
|
||
:key="item.v"
|
||
@tap="switchBillTab(item.v)"
|
||
>{{ item.t }}</view>
|
||
</view>
|
||
|
||
<!-- 列表区域 -->
|
||
<scroll-view class="hsw-list" scroll-y>
|
||
<!-- 普通服务单(非月账单模式) -->
|
||
<block v-if="!showMonthlyBill">
|
||
<view class="hsw-card" v-for="o in orders" :key="o.id">
|
||
<view class="hsw-head">
|
||
<text class="hsw-no">{{ o.order_no }}</text>
|
||
<text class="hsw-kind">{{ kindText(o.order_kind) }}</text>
|
||
</view>
|
||
<view class="hsw-row"><text>服务</text><text>{{ o.service_name }}</text></view>
|
||
<view class="hsw-row"><text>客户</text><text>{{ o.contact_name }} {{ o.contact_phone }}</text></view>
|
||
<view class="hsw-row"><text>地址</text><text>{{ o.service_address }}</text></view>
|
||
<view class="hsw-row"><text>金额</text><text class="hsw-amount">¥{{ o.amount }}</text></view>
|
||
<view class="hsw-foot">
|
||
<view class="hsw-btn ghost" v-if="o.status === 1" @tap="updateStatus(o, 2)">开始服务</view>
|
||
<view class="hsw-btn" v-if="o.status === 2 && o.order_kind === 1" @tap="openExtra(o)">代客补差</view>
|
||
<view class="hsw-btn ghost" v-if="o.status === 2" @tap="updateStatus(o, 4)">完成服务</view>
|
||
</view>
|
||
</view>
|
||
<view v-if="orders.length === 0" class="hsw-empty">暂无服务单</view>
|
||
</block>
|
||
<!-- 月账单列表(师傅可见所有状态) -->
|
||
<block v-else>
|
||
<view class="hsw-card hsw-bill-card" v-for="b in bills" :key="b.id">
|
||
<view class="hsw-head">
|
||
<text class="hsw-no">{{ b.bill_no }}</text>
|
||
<text class="hsw-kind" :class="b.push_status === 0 ? 'status-warn' : b.push_status === 1 ? 'status-info' : b.push_status === 2 ? 'status-ok' : 'status-cancel'">{{ pushStatusText(b.push_status) }}</text>
|
||
</view>
|
||
<view class="hsw-row"><text>服务</text><text>{{ b.service_name }}</text></view>
|
||
<view class="hsw-row"><text>客户</text><text>{{ b.contact_name }} {{ b.contact_phone }}</text></view>
|
||
<view class="hsw-row"><text>地址</text><text>{{ b.service_address }}</text></view>
|
||
<view class="hsw-row"><text>账单月份</text><text>{{ b.bill_month }}</text></view>
|
||
<view class="hsw-row"><text>金额</text><text class="hsw-amount">¥{{ b.amount }}</text></view>
|
||
<view class="hsw-foot">
|
||
<view class="hsw-btn" v-if="b.push_status === 0" @tap="openPush(b)">推送至用户支付</view>
|
||
<view class="hsw-btn ghost" v-if="b.push_status === 0" @tap="openReject(b)">拒绝</view>
|
||
<view class="hsw-btn ghost" v-if="b.push_status === 1">已推送,待用户支付</view>
|
||
<view class="hsw-btn ghost" v-if="b.push_status === 2">用户已支付</view>
|
||
<view class="hsw-btn ghost" v-if="b.push_status === 3">已拒绝{{ b.remark ? ':' + b.remark : '' }}</view>
|
||
</view>
|
||
</view>
|
||
<view v-if="bills.length === 0" class="hsw-empty">暂无月账单</view>
|
||
</block>
|
||
</scroll-view>
|
||
|
||
<!-- 代客补差弹层 -->
|
||
<view class="hsw-mask" v-if="showExtra" @tap.self="showExtra = false">
|
||
<view class="hsw-dialog">
|
||
<view class="hsw-dialog-tit">代客生成补差单</view>
|
||
<input class="hsw-dialog-input" type="digit" v-model="extraAmount" placeholder="请输入补差金额" />
|
||
<input class="hsw-dialog-input" v-model="extraRemark" placeholder="备注(选填)" />
|
||
<view class="hsw-dialog-btns">
|
||
<view class="hsw-dialog-btn cancel" @tap="showExtra = false">取消</view>
|
||
<view class="hsw-dialog-btn ok" @tap="submitExtra">确定</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 推送月账单弹层 -->
|
||
<view class="hsw-mask" v-if="showPush" @tap.self="showPush = false">
|
||
<view class="hsw-dialog">
|
||
<view class="hsw-dialog-tit">推送月账单</view>
|
||
<view class="hsw-dialog-info">确认推送至用户端?用户支付后该账单生效。</view>
|
||
<view class="hsw-dialog-btns">
|
||
<view class="hsw-dialog-btn cancel" @tap="showPush = false">取消</view>
|
||
<view class="hsw-dialog-btn ok" @tap="submitPush">确认推送</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 拒绝月账单弹层 -->
|
||
<view class="hsw-mask" v-if="showReject" @tap.self="showReject = false">
|
||
<view class="hsw-dialog">
|
||
<view class="hsw-dialog-tit">拒绝月账单</view>
|
||
<input class="hsw-dialog-input" v-model="rejectRemark" placeholder="请输入拒绝原因(选填)" />
|
||
<view class="hsw-dialog-btns">
|
||
<view class="hsw-dialog-btn cancel" @tap="showReject = false">取消</view>
|
||
<view class="hsw-dialog-btn ok" @tap="submitReject">确认拒绝</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { request } from '@/utils'
|
||
import { apiArr } from '@/api/homeService'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
employeeId: 0,
|
||
statusTab: 0,
|
||
orderTabs: [
|
||
{ v: 0, t: '全部' },
|
||
{ v: 1, t: '待上门' },
|
||
{ v: 2, t: '服务中' },
|
||
{ v: 4, t: '已完成' },
|
||
{ v: -1, t: '月账单' }
|
||
],
|
||
showMonthlyBill: false,
|
||
billTab: 0,
|
||
billTabs: [
|
||
{ v: 0, t: '全部' },
|
||
{ v: 1, t: '待推送' },
|
||
{ v: 2, t: '已推送' }
|
||
],
|
||
orders: [],
|
||
bills: [],
|
||
showExtra: false,
|
||
extraOrder: null,
|
||
extraAmount: '',
|
||
extraRemark: '',
|
||
showPush: false,
|
||
showReject: false,
|
||
pushBill: null,
|
||
rejectBill: null,
|
||
rejectRemark: ''
|
||
}
|
||
},
|
||
onLoad(options) {
|
||
this.employeeId = Number(options.employeeId || uni.getStorageSync('serviceEmployeeId') || 0)
|
||
if (!this.employeeId) {
|
||
const userId = uni.getStorageSync('userId')
|
||
request(apiArr.workerMyInfo, 'POST', { user_id: userId }, {}, false).then(res => {
|
||
if (res && res.is_worker && res.employee_id) {
|
||
this.employeeId = res.employee_id
|
||
uni.setStorageSync('serviceEmployeeId', res.employee_id)
|
||
this.loadOrders()
|
||
} else {
|
||
uni.showModal({ title: '提示', content: '您还不是服务师傅,请联系商家添加', showCancel: false })
|
||
}
|
||
})
|
||
}
|
||
},
|
||
onShow() {
|
||
if (this.employeeId) {
|
||
if (this.showMonthlyBill) {
|
||
this.loadBills()
|
||
} else {
|
||
this.loadOrders()
|
||
}
|
||
}
|
||
},
|
||
methods: {
|
||
switchStatus(v) {
|
||
if (v === -1) {
|
||
this.showMonthlyBill = true
|
||
this.billTab = 0
|
||
this.loadBills()
|
||
} else {
|
||
this.showMonthlyBill = false
|
||
this.statusTab = v
|
||
this.loadOrders()
|
||
}
|
||
},
|
||
switchBillTab(v) {
|
||
this.billTab = v
|
||
this.loadBills()
|
||
},
|
||
loadOrders() {
|
||
request(apiArr.workerOrderList, 'POST', {
|
||
employee_id: this.employeeId,
|
||
status: this.statusTab,
|
||
page_num: 1,
|
||
page_size: 50
|
||
}, {}, false).then(res => {
|
||
this.orders = res.rows || []
|
||
})
|
||
},
|
||
loadBills() {
|
||
request(apiArr.workerMonthlyBillList, 'POST', {
|
||
employee_id: this.employeeId,
|
||
user_id: Number(uni.getStorageSync('userId')) || 0,
|
||
page_num: 1,
|
||
page_size: 50
|
||
}, {}, false).then(res => {
|
||
let rows = res.rows || []
|
||
if (this.billTab === 1) rows = rows.filter(b => b.push_status === 0)
|
||
if (this.billTab === 2) rows = rows.filter(b => b.push_status === 1 || b.push_status === 2)
|
||
this.bills = rows
|
||
})
|
||
},
|
||
kindText(k) {
|
||
return k === 1 ? '定金/上门费' : k === 2 ? '补差/尾款' : k === 3 ? '月账单' : ''
|
||
},
|
||
pushStatusText(s) {
|
||
return s === 0 ? '待推送' : s === 1 ? '已推送待支付' : s === 2 ? '已支付' : s === 3 ? '已拒绝' : ''
|
||
},
|
||
updateStatus(o, status) {
|
||
request(apiArr.workerOrderStatus, 'POST', { order_id: o.id, status }).then(() => {
|
||
uni.showToast({ title: '操作成功', icon: 'none' })
|
||
this.loadOrders()
|
||
})
|
||
},
|
||
openExtra(o) {
|
||
this.extraOrder = o
|
||
this.extraAmount = ''
|
||
this.extraRemark = ''
|
||
this.showExtra = true
|
||
},
|
||
submitExtra() {
|
||
const amt = Number(this.extraAmount)
|
||
if (!amt || amt <= 0) { uni.showToast({ title: '请输入补差金额', icon: 'none' }); return }
|
||
request(apiArr.workerExtraOrder, 'POST', {
|
||
order_id: this.extraOrder.id,
|
||
amount: amt,
|
||
remark: this.extraRemark
|
||
}).then(() => {
|
||
this.showExtra = false
|
||
uni.showToast({ title: '已生成补差单,待客户支付', icon: 'none' })
|
||
this.loadOrders()
|
||
})
|
||
},
|
||
openPush(b) {
|
||
this.pushBill = b
|
||
this.showPush = true
|
||
},
|
||
submitPush() {
|
||
request(apiArr.workerPushBill, 'POST', {
|
||
bill_id: this.pushBill.id,
|
||
action: 1
|
||
}).then(() => {
|
||
this.showPush = false
|
||
uni.showToast({ title: '已推送,用户可支付', icon: 'none' })
|
||
this.loadBills()
|
||
}).catch(err => {
|
||
uni.showToast({ title: err.errMsg || '操作失败', icon: 'none' })
|
||
})
|
||
},
|
||
openReject(b) {
|
||
this.rejectBill = b
|
||
this.rejectRemark = ''
|
||
this.showReject = true
|
||
},
|
||
submitReject() {
|
||
request(apiArr.workerPushBill, 'POST', {
|
||
bill_id: this.rejectBill.id,
|
||
action: 3,
|
||
remark: this.rejectRemark
|
||
}).then(() => {
|
||
this.showReject = false
|
||
uni.showToast({ title: '已拒绝', icon: 'none' })
|
||
this.loadBills()
|
||
}).catch(err => {
|
||
uni.showToast({ title: err.errMsg || '操作失败', icon: 'none' })
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.hsw-page { display: flex; flex-direction: column; height: 100vh; background: #f5f5f5; }
|
||
.hsw-tabs { display: flex; background: #fff; }
|
||
.hsw-tab { flex: 1; text-align: center; padding: 24rpx 0; font-size: 26rpx; color: #666; }
|
||
.hsw-tab.active { color: #FF370B; font-weight: 600; border-bottom: 4rpx solid #FF370B; }
|
||
.hsw-tabs-bill { border-top: 1rpx solid #f0f0f0; }
|
||
.hsw-list { flex: 1; padding: 20rpx; box-sizing: border-box; }
|
||
.hsw-card { background: #fff; border-radius: 12rpx; padding: 20rpx; margin-bottom: 18rpx; }
|
||
.hsw-bill-card { border-left: 6rpx solid #FF370B; }
|
||
.hsw-head { display: flex; justify-content: space-between; font-size: 24rpx; color: #999; margin-bottom: 14rpx; }
|
||
.hsw-kind { color: #FF370B; }
|
||
.status-warn { color: #FF9800; }
|
||
.status-info { color: #2196F3; }
|
||
.status-ok { color: #4CAF50; }
|
||
.status-cancel { color: #999; }
|
||
.hsw-row { display: flex; justify-content: space-between; font-size: 26rpx; color: #333; padding: 8rpx 0; }
|
||
.hsw-row text:first-child { color: #999; }
|
||
.hsw-amount { color: #FF370B; font-weight: 600; }
|
||
.hsw-foot { display: flex; justify-content: flex-end; gap: 16rpx; margin-top: 16rpx; }
|
||
.hsw-btn { background: linear-gradient(91deg, #FF7658, #FF370B); color: #fff; font-size: 26rpx; padding: 12rpx 36rpx; border-radius: 40rpx; }
|
||
.hsw-btn.ghost { background: #fff; color: #FF370B; border: 1rpx solid #FF370B; }
|
||
.hsw-empty { text-align: center; color: #999; font-size: 26rpx; padding: 80rpx 0; }
|
||
.hsw-mask { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 999; }
|
||
.hsw-dialog { width: 600rpx; background: #fff; border-radius: 16rpx; padding: 32rpx; }
|
||
.hsw-dialog-tit { font-size: 30rpx; font-weight: 600; text-align: center; margin-bottom: 24rpx; }
|
||
.hsw-dialog-info { font-size: 26rpx; color: #666; text-align: center; margin-bottom: 24rpx; }
|
||
.hsw-dialog-input { border: 1rpx solid #eee; border-radius: 8rpx; height: 80rpx; padding: 0 20rpx; font-size: 28rpx; margin-bottom: 18rpx; }
|
||
.hsw-dialog-btns { display: flex; gap: 20rpx; margin-top: 10rpx; }
|
||
.hsw-dialog-btn { flex: 1; text-align: center; padding: 18rpx 0; border-radius: 44rpx; font-size: 28rpx; }
|
||
.hsw-dialog-btn.cancel { background: #f2f2f2; color: #666; }
|
||
.hsw-dialog-btn.ok { background: linear-gradient(91deg, #FF7658, #FF370B); color: #fff; }
|
||
</style> |