Files
2026-06-09 17:02:13 +08:00

176 lines
5.7 KiB
Vue

<template>
<page-layout :is-platform="ctx.isPlatform" title="药品佣金配置" :show-back="true">
<view class="page">
<view class="toolbar">
<input class="search" v-model="keyword" placeholder="搜索药品" @confirm="reload" />
<view class="search-btn" @click="reload">搜索</view>
</view>
<view v-if="salespersonId > 0" class="copy-row">
<picker :range="copyLabels" :value="copyIndex" @change="onCopyFrom">
<view class="copy-picker">{{ copyLabels[copyIndex] || '从其他推广员复制' }}</view>
</picker>
</view>
<view v-if="!list.length && !loading" class="empty">暂无药品</view>
<view v-for="item in list" :key="item.drug_id" class="row">
<view class="drug-info">
<text class="drug-name">{{ item.drug_name }}</text>
<text class="spec">{{ item.drug_spec }}</text>
<text class="price">售价 ¥{{ item.price }} / 供货 ¥{{ item.buy_price }}</text>
</view>
<input
class="commission-input"
v-model="dirtyMap[item.drug_id]"
type="digit"
placeholder="元/件"
@input="onCommissionInput(item.drug_id, $event)"
/>
</view>
<view v-if="salespersonId > 0" class="save-btn" @click="save">保存修改</view>
<view v-else class="hint">请先保存推广员基本信息后再配置药品佣金</view>
</view>
</page-layout>
</template>
<script>
import PageLayout from '../components/PageLayout.vue';
import { getSalespersonManageContext, resolveManageMode } from '../common/context.js';
export default {
components: { PageLayout },
data() {
return {
ctx: getSalespersonManageContext('clinic'),
salespersonId: 0,
storeId: 0,
keyword: '',
list: [],
loading: false,
dirtyMap: {},
copyOptions: [],
copyIndex: 0,
};
},
computed: {
copyLabels() {
return ['从其他推广员复制', ...this.copyOptions.map((o) => o.label)];
},
},
onLoad(options) {
this.ctx = getSalespersonManageContext(resolveManageMode(options));
this.salespersonId = Number(options.salesperson_id || 0);
this.storeId = Number(options.store_id || 0);
this.reload();
if (this.salespersonId > 0) this.loadCopyOptions();
},
methods: {
async reload() {
if (!this.salespersonId) return;
this.loading = true;
try {
const params = {
salesperson_id: this.salespersonId,
keyword: this.keyword,
page: 1,
pageSize: 100,
};
if (this.storeId > 0) params.store_id = this.storeId;
const wrap = await this.ctx.api.getDrugCommissionList(params);
const items = (wrap && wrap.ok && wrap.data && wrap.data.items) ? wrap.data.items : [];
this.list = items;
const map = { ...this.dirtyMap };
items.forEach((row) => {
if (map[row.drug_id] === undefined) {
map[row.drug_id] = row.commission || '';
}
});
this.dirtyMap = map;
} finally {
this.loading = false;
}
},
async loadCopyOptions() {
const wrap = await this.ctx.api.getList({ page: 1, pageSize: 100 });
if (!wrap || !wrap.ok) return;
this.copyOptions = (wrap.data.items || [])
.filter((sp) => Number(sp.id) !== this.salespersonId)
.map((sp) => ({
label: sp.nick_name || sp.phone || `推广员#${sp.id}`,
value: Number(sp.id),
}));
},
onCommissionInput(drugId, e) {
this.$set(this.dirtyMap, drugId, e.detail.value);
},
async onCopyFrom(e) {
const idx = Number(e.detail.value);
this.copyIndex = idx;
if (idx <= 0 || !this.copyOptions[idx - 1]) return;
const fromId = this.copyOptions[idx - 1].value;
const wrap = await this.ctx.api.getDrugCommissionCopyFrom(fromId);
if (!wrap || !wrap.ok) return;
const items = wrap.data.items || [];
const map = { ...this.dirtyMap };
items.forEach((row) => {
map[row.drug_id] = row.commission || '';
});
this.dirtyMap = map;
uni.showToast({ title: '已复制', icon: 'success' });
},
async save() {
const items = Object.keys(this.dirtyMap)
.filter((drugId) => this.dirtyMap[drugId] !== '' && this.dirtyMap[drugId] != null)
.map((drugId) => ({
drug_id: Number(drugId),
commission: String(this.dirtyMap[drugId]),
}));
if (!items.length) {
uni.showToast({ title: '无修改', icon: 'none' });
return;
}
uni.showLoading({ title: '保存中' });
try {
const wrap = await this.ctx.api.saveDrugCommission({
salesperson_id: this.salespersonId,
items,
});
if (wrap && wrap.ok) {
uni.showToast({ title: '保存成功', icon: 'success' });
}
} finally {
uni.hideLoading();
}
},
},
};
</script>
<style lang="scss" scoped>
.page { padding: 24rpx; padding-bottom: 120rpx; }
.toolbar { display: flex; gap: 12rpx; margin-bottom: 16rpx; }
.search { flex: 1; background: #fff; border-radius: 12rpx; padding: 16rpx 20rpx; font-size: 26rpx; }
.search-btn { background: #6ACDBB; color: #fff; padding: 16rpx 24rpx; border-radius: 12rpx; font-size: 26rpx; }
.copy-row { margin-bottom: 16rpx; }
.copy-picker { background: #fff; padding: 20rpx; border-radius: 12rpx; font-size: 26rpx; color: #6ACDBB; }
.row {
display: flex; align-items: center; background: #fff; border-radius: 16rpx;
padding: 20rpx; margin-bottom: 12rpx;
}
.drug-info { flex: 1; }
.drug-name { display: block; font-size: 28rpx; font-weight: 600; }
.spec, .price { font-size: 22rpx; color: #999; display: block; margin-top: 4rpx; }
.commission-input {
width: 140rpx; text-align: center; background: #f5f5f5; border-radius: 8rpx;
padding: 12rpx; font-size: 26rpx;
}
.save-btn {
position: fixed; left: 24rpx; right: 24rpx; bottom: 48rpx;
background: linear-gradient(90deg, #00BFA6, #6ACDBB); color: #fff;
text-align: center; padding: 24rpx; border-radius: 16rpx; font-size: 30rpx;
}
.hint { text-align: center; color: #999; padding: 40rpx; }
.empty { text-align: center; color: #999; padding: 80rpx 0; }
</style>