236 lines
8.1 KiB
Vue
236 lines
8.1 KiB
Vue
<template>
|
|
<page-layout :is-platform="ctx.isPlatform" :title="pageTitle" :show-back="true">
|
|
<view class="page">
|
|
<view class="tabs">
|
|
<view
|
|
v-for="tab in tabs"
|
|
:key="tab.key"
|
|
class="tab"
|
|
:class="{ active: activeTab === tab.key }"
|
|
@click="switchTab(tab.key)"
|
|
>{{ tab.label }}</view>
|
|
</view>
|
|
|
|
<view v-if="activeTab !== 'history'" class="toolbar">
|
|
<input class="search" v-model="orderNo" placeholder="订单号" @confirm="loadOrders" />
|
|
<view class="search-btn" @click="loadOrders">查询</view>
|
|
</view>
|
|
|
|
<template v-if="activeTab === 'pending'">
|
|
<view class="settle-actions">
|
|
<view class="settle-btn" @click="goPeriodSettle">按时间段结算</view>
|
|
<view class="settle-btn primary" @click="goOrderSettle">结算选中订单</view>
|
|
</view>
|
|
<view v-for="item in orderList" :key="item.order_id" class="order-row" @click="toggleSelect(item)">
|
|
<view class="checkbox" :class="{ checked: selectedIds.includes(item.order_id) }" />
|
|
<view class="order-info">
|
|
<text class="order-no">{{ item.order_no }}</text>
|
|
<text class="sub">明细 {{ item.item_count }} 条 · {{ item.order_pay_at_text }}</text>
|
|
</view>
|
|
<text class="amount">¥{{ item.commission_amount }}</text>
|
|
</view>
|
|
</template>
|
|
|
|
<template v-else-if="activeTab === 'settled'">
|
|
<view v-for="item in orderList" :key="item.order_id" class="order-row" @click="showOrderDetail(item)">
|
|
<view class="order-info">
|
|
<text class="order-no">{{ item.order_no }}</text>
|
|
<text class="sub">明细 {{ item.item_count }} 条 · {{ item.order_pay_at_text }}</text>
|
|
</view>
|
|
<text class="amount">¥{{ item.commission_amount }}</text>
|
|
</view>
|
|
</template>
|
|
|
|
<template v-else>
|
|
<view v-for="item in settlementList" :key="item.id" class="order-row" @click="goSettlementDetail(item.id)">
|
|
<view class="order-info">
|
|
<text class="order-no">{{ item.settlement_no }}</text>
|
|
<text class="sub">{{ item.settlement_type_text }} · {{ item.created_at_text }}</text>
|
|
</view>
|
|
<text class="amount">¥{{ item.amount }}</text>
|
|
</view>
|
|
</template>
|
|
|
|
<view v-if="!loading && isEmpty" class="empty">暂无数据</view>
|
|
</view>
|
|
</page-layout>
|
|
</template>
|
|
|
|
<script>
|
|
import PageLayout from '../components/PageLayout.vue';
|
|
import { getSalespersonManageContext, resolveManageMode } from '../common/context.js';
|
|
|
|
const ROOT = '/subPackages/sub_salesperson_manage';
|
|
|
|
export default {
|
|
components: { PageLayout },
|
|
data() {
|
|
return {
|
|
ctx: getSalespersonManageContext('clinic'),
|
|
salespersonId: 0,
|
|
storeId: 0,
|
|
nickName: '',
|
|
activeTab: 'pending',
|
|
tabs: [
|
|
{ key: 'pending', label: '待结算' },
|
|
{ key: 'settled', label: '已结算' },
|
|
{ key: 'history', label: '结算历史' },
|
|
],
|
|
orderNo: '',
|
|
orderList: [],
|
|
settlementList: [],
|
|
selectedIds: [],
|
|
loading: false,
|
|
};
|
|
},
|
|
computed: {
|
|
pageTitle() {
|
|
return this.nickName ? `服务费与结算 - ${this.nickName}` : '服务费与结算';
|
|
},
|
|
isEmpty() {
|
|
if (this.activeTab === 'history') return !this.settlementList.length;
|
|
return !this.orderList.length;
|
|
},
|
|
},
|
|
onLoad(options) {
|
|
this.ctx = getSalespersonManageContext(resolveManageMode(options));
|
|
this.salespersonId = Number(options.salesperson_id || 0);
|
|
this.storeId = Number(options.store_id || 0);
|
|
this.nickName = decodeURIComponent(options.nick_name || '');
|
|
this.loadData();
|
|
},
|
|
methods: {
|
|
switchTab(key) {
|
|
this.activeTab = key;
|
|
this.selectedIds = [];
|
|
this.loadData();
|
|
},
|
|
loadData() {
|
|
if (this.activeTab === 'history') this.loadSettlements();
|
|
else this.loadOrders();
|
|
},
|
|
buildParams() {
|
|
const params = {
|
|
salesperson_id: this.salespersonId,
|
|
page: 1,
|
|
pageSize: 50,
|
|
order_no: this.orderNo,
|
|
};
|
|
if (this.storeId > 0) params.store_id = this.storeId;
|
|
if (this.activeTab === 'pending') params.status = 0;
|
|
if (this.activeTab === 'settled') params.status = 1;
|
|
return params;
|
|
},
|
|
async loadOrders() {
|
|
this.loading = true;
|
|
try {
|
|
const wrap = await this.ctx.api.getCommissionOrderList(this.buildParams());
|
|
this.orderList = (wrap && wrap.ok && wrap.data && wrap.data.items) ? wrap.data.items : [];
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
},
|
|
async loadSettlements() {
|
|
this.loading = true;
|
|
try {
|
|
const params = { salesperson_id: this.salespersonId, page: 1, pageSize: 50 };
|
|
if (this.storeId > 0) params.store_id = this.storeId;
|
|
const wrap = await this.ctx.api.getSettlementList(params);
|
|
this.settlementList = (wrap && wrap.ok && wrap.data && wrap.data.items) ? wrap.data.items : [];
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
},
|
|
toggleSelect(item) {
|
|
const id = item.order_id;
|
|
const idx = this.selectedIds.indexOf(id);
|
|
if (idx >= 0) this.selectedIds.splice(idx, 1);
|
|
else this.selectedIds.push(id);
|
|
},
|
|
goPeriodSettle() {
|
|
uni.navigateTo({
|
|
url: `${ROOT}/settlement/preview?mode=${this.ctx.mode}&salesperson_id=${this.salespersonId}&store_id=${this.storeId}`,
|
|
});
|
|
},
|
|
async goOrderSettle() {
|
|
if (!this.selectedIds.length) {
|
|
uni.showToast({ title: '请勾选订单', icon: 'none' });
|
|
return;
|
|
}
|
|
const params = {
|
|
salesperson_id: this.salespersonId,
|
|
settlement_type: 2,
|
|
order_ids: this.selectedIds.join(','),
|
|
};
|
|
if (this.storeId > 0) params.store_id = this.storeId;
|
|
uni.showLoading({ title: '预览中' });
|
|
try {
|
|
const wrap = await this.ctx.api.getSettlementPreview(params);
|
|
if (!wrap || !wrap.ok) return;
|
|
const preview = wrap.data || {};
|
|
const q = [
|
|
`mode=${this.ctx.mode}`,
|
|
`salesperson_id=${this.salespersonId}`,
|
|
`store_id=${this.storeId}`,
|
|
'settlement_type=2',
|
|
`order_ids=${this.selectedIds.join(',')}`,
|
|
`amount=${encodeURIComponent(preview.amount || '0.00')}`,
|
|
`record_count=${preview.record_count || 0}`,
|
|
].join('&');
|
|
uni.navigateTo({ url: `${ROOT}/settlement/confirm?${q}` });
|
|
} finally {
|
|
uni.hideLoading();
|
|
}
|
|
},
|
|
async showOrderDetail(item) {
|
|
const params = {
|
|
salesperson_id: this.salespersonId,
|
|
order_id: item.order_id,
|
|
page: 1,
|
|
pageSize: 100,
|
|
};
|
|
if (this.storeId > 0) params.store_id = this.storeId;
|
|
const wrap = await this.ctx.api.getCommissionList(params);
|
|
const items = (wrap && wrap.ok && wrap.data && wrap.data.items) ? wrap.data.items : [];
|
|
const lines = items.map((r) => `${r.drug_info || ''} ¥${r.commission_amount}`).join('\n');
|
|
uni.showModal({
|
|
title: `订单 ${item.order_no}`,
|
|
content: lines || '无明细',
|
|
showCancel: false,
|
|
});
|
|
},
|
|
goSettlementDetail(id) {
|
|
uni.navigateTo({
|
|
url: `${ROOT}/settlement/detail?mode=${this.ctx.mode}&id=${id}&store_id=${this.storeId}`,
|
|
});
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.page { padding: 24rpx; }
|
|
.tabs { display: flex; background: #fff; border-radius: 16rpx; margin-bottom: 20rpx; overflow: hidden; }
|
|
.tab { flex: 1; text-align: center; padding: 20rpx; font-size: 26rpx; color: #666; }
|
|
.tab.active { background: #6ACDBB; color: #fff; font-weight: 600; }
|
|
.toolbar { display: flex; gap: 12rpx; margin-bottom: 16rpx; }
|
|
.search { flex: 1; background: #fff; border-radius: 12rpx; padding: 16rpx; font-size: 26rpx; }
|
|
.search-btn { background: #6ACDBB; color: #fff; padding: 16rpx 24rpx; border-radius: 12rpx; font-size: 26rpx; }
|
|
.settle-actions { display: flex; gap: 12rpx; margin-bottom: 16rpx; }
|
|
.settle-btn { flex: 1; text-align: center; padding: 16rpx; background: #fff; border-radius: 12rpx; font-size: 26rpx; color: #6ACDBB; border: 1rpx solid #6ACDBB; }
|
|
.settle-btn.primary { background: #6ACDBB; color: #fff; border: none; }
|
|
.order-row {
|
|
display: flex; align-items: center; background: #fff; border-radius: 16rpx;
|
|
padding: 24rpx; margin-bottom: 12rpx;
|
|
}
|
|
.checkbox {
|
|
width: 36rpx; height: 36rpx; border: 2rpx solid #ddd; border-radius: 8rpx; margin-right: 16rpx;
|
|
}
|
|
.checkbox.checked { background: #6ACDBB; border-color: #6ACDBB; }
|
|
.order-info { flex: 1; }
|
|
.order-no { display: block; font-size: 28rpx; font-weight: 600; }
|
|
.sub { font-size: 22rpx; color: #999; }
|
|
.amount { font-size: 30rpx; color: #F97316; font-weight: 600; }
|
|
.empty { text-align: center; color: #999; padding: 80rpx 0; }
|
|
</style>
|