2026-06-09 17:02:13 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<page-layout :is-platform="ctx.isPlatform" :title="isUpdate ? '编辑推广员' : '新增推广员'" :show-back="true">
|
|
|
|
|
|
<view class="page">
|
|
|
|
|
|
<store-search-picker v-if="ctx.isPlatform && !isUpdate" v-model="form.store_id" :api="ctx.api" />
|
|
|
|
|
|
|
|
|
|
|
|
<view class="field">
|
|
|
|
|
|
<text class="label">手机号</text>
|
|
|
|
|
|
<input class="input" v-model="form.phone" type="number" maxlength="11" placeholder="请输入手机号" :disabled="isUpdate" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="field">
|
|
|
|
|
|
<text class="label">名称</text>
|
|
|
|
|
|
<input class="input" v-model="form.nick_name" placeholder="请输入名称" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="field">
|
|
|
|
|
|
<text class="label">西药分成类型</text>
|
|
|
|
|
|
<picker :range="splitTypeLabels" :value="splitTypeIndex" @change="onSplitType">
|
|
|
|
|
|
<view class="picker-val">{{ splitTypeLabels[splitTypeIndex] }}</view>
|
|
|
|
|
|
</picker>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view v-if="Number(form.split_type) === 1" class="field">
|
|
|
|
|
|
<text class="label">分成比例(%)</text>
|
|
|
|
|
|
<input class="input" v-model="form.split" type="digit" placeholder="0-100" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view v-else class="field link" @click="goDrugCommission">
|
|
|
|
|
|
<text class="label">药品佣金配置</text>
|
|
|
|
|
|
<text class="link-text">去配置元/件分成 ></text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="section-title">中药推广分成</view>
|
|
|
|
|
|
<view class="field">
|
|
|
|
|
|
<text class="label">中药分成(%)</text>
|
|
|
|
|
|
<input class="input" v-model="form.tcm_split" type="digit" placeholder="0 表示不分成" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view v-if="Number(form.tcm_split) > 0" class="field">
|
|
|
|
|
|
<text class="label">中药分成基数</text>
|
|
|
|
|
|
<picker :range="tcmBaseLabels" :value="tcmBaseIndex" @change="onTcmBase">
|
|
|
|
|
|
<view class="picker-val">{{ tcmBaseLabels[tcmBaseIndex] }}</view>
|
|
|
|
|
|
</picker>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
2026-07-07 08:50:05 +08:00
|
|
|
|
<view class="section-title">邀请关系(可选)</view>
|
|
|
|
|
|
<view class="field-col">
|
|
|
|
|
|
<text class="label block">邀请人推广员</text>
|
|
|
|
|
|
<salesperson-picker
|
|
|
|
|
|
v-model="form.parent_salesperson_id"
|
|
|
|
|
|
:exclude-id="form.id"
|
|
|
|
|
|
:store-id="form.store_id"
|
|
|
|
|
|
:fetch-options="fetchSalespersonOptions"
|
|
|
|
|
|
:initial-selected="parentInitial"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view v-if="Number(form.parent_salesperson_id) > 0" class="field">
|
|
|
|
|
|
<text class="label">邀请分成(%)</text>
|
|
|
|
|
|
<input class="input" v-model="form.inviter_split" type="digit" placeholder="上级从订单利润中获得的比例" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
2026-06-09 17:02:13 +08:00
|
|
|
|
<view class="submit-btn" @click="submit">保存</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</page-layout>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import PageLayout from './components/PageLayout.vue';
|
|
|
|
|
|
import StoreSearchPicker from './components/StoreSearchPicker.vue';
|
2026-07-07 08:50:05 +08:00
|
|
|
|
import SalespersonPicker from './components/SalespersonPicker.vue';
|
2026-06-09 17:02:13 +08:00
|
|
|
|
import { getSalespersonManageContext, resolveManageMode } from './common/context.js';
|
|
|
|
|
|
import { SPLIT_TYPE_OPTIONS, TCM_BASE_OPTIONS } from './common/labels.js';
|
|
|
|
|
|
|
|
|
|
|
|
const ROOT = '/subPackages/sub_salesperson_manage';
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
2026-07-07 08:50:05 +08:00
|
|
|
|
components: { PageLayout, StoreSearchPicker, SalespersonPicker },
|
2026-06-09 17:02:13 +08:00
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
ctx: getSalespersonManageContext('clinic'),
|
|
|
|
|
|
isUpdate: false,
|
2026-07-07 08:50:05 +08:00
|
|
|
|
parentInitial: null,
|
2026-06-09 17:02:13 +08:00
|
|
|
|
form: {
|
|
|
|
|
|
id: 0,
|
|
|
|
|
|
store_id: 0,
|
|
|
|
|
|
phone: '',
|
|
|
|
|
|
nick_name: '',
|
|
|
|
|
|
split_type: 0,
|
|
|
|
|
|
split: 0,
|
|
|
|
|
|
tcm_split: 0,
|
|
|
|
|
|
tcm_base_type: 0,
|
2026-07-07 08:50:05 +08:00
|
|
|
|
parent_salesperson_id: 0,
|
|
|
|
|
|
inviter_split: 0,
|
2026-06-09 17:02:13 +08:00
|
|
|
|
},
|
|
|
|
|
|
splitTypeLabels: SPLIT_TYPE_OPTIONS.map((o) => o.label),
|
|
|
|
|
|
tcmBaseLabels: TCM_BASE_OPTIONS.map((o) => o.label),
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
splitTypeIndex() {
|
|
|
|
|
|
return SPLIT_TYPE_OPTIONS.findIndex((o) => o.value === Number(this.form.split_type));
|
|
|
|
|
|
},
|
|
|
|
|
|
tcmBaseIndex() {
|
|
|
|
|
|
return TCM_BASE_OPTIONS.findIndex((o) => o.value === Number(this.form.tcm_base_type));
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
onLoad(options) {
|
|
|
|
|
|
this.ctx = getSalespersonManageContext(resolveManageMode(options));
|
|
|
|
|
|
this.isUpdate = !!options.id;
|
|
|
|
|
|
if (options.id) {
|
|
|
|
|
|
this.form.id = Number(options.id);
|
|
|
|
|
|
this.form.store_id = Number(options.store_id || 0);
|
|
|
|
|
|
this.loadDetail(options);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
2026-07-07 08:50:05 +08:00
|
|
|
|
fetchSalespersonOptions(params) {
|
|
|
|
|
|
return this.ctx.api.getSalespersonOptions(params);
|
|
|
|
|
|
},
|
2026-06-09 17:02:13 +08:00
|
|
|
|
async loadDetail(options) {
|
|
|
|
|
|
const wrap = await this.ctx.api.getList({ page: 1, pageSize: 100 });
|
|
|
|
|
|
if (!wrap || !wrap.ok) return;
|
|
|
|
|
|
const item = (wrap.data.items || []).find((r) => Number(r.id) === Number(options.id));
|
|
|
|
|
|
if (!item) return;
|
|
|
|
|
|
this.form.phone = item.phone || '';
|
|
|
|
|
|
this.form.nick_name = item.nick_name || '';
|
|
|
|
|
|
this.form.split_type = Number(item.split_type) || 0;
|
|
|
|
|
|
this.form.split = item.split || 0;
|
|
|
|
|
|
this.form.tcm_split = item.tcm_split || 0;
|
|
|
|
|
|
this.form.tcm_base_type = Number(item.tcm_base_type) || 0;
|
2026-07-07 08:50:05 +08:00
|
|
|
|
this.form.parent_salesperson_id = Number(item.parent_salesperson_id) || 0;
|
|
|
|
|
|
this.form.inviter_split = item.inviter_split || 0;
|
|
|
|
|
|
if (this.form.parent_salesperson_id > 0) {
|
|
|
|
|
|
this.parentInitial = {
|
|
|
|
|
|
id: this.form.parent_salesperson_id,
|
|
|
|
|
|
nick_name: item.parent_nick_name,
|
|
|
|
|
|
phone: item.parent_phone,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2026-06-09 17:02:13 +08:00
|
|
|
|
if (!this.form.store_id && item.qr_code) {
|
|
|
|
|
|
this.form.store_id = item.qr_code.store_id || 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
onSplitType(e) {
|
|
|
|
|
|
const idx = Number(e.detail.value);
|
|
|
|
|
|
this.form.split_type = SPLIT_TYPE_OPTIONS[idx].value;
|
|
|
|
|
|
},
|
|
|
|
|
|
onTcmBase(e) {
|
|
|
|
|
|
const idx = Number(e.detail.value);
|
|
|
|
|
|
this.form.tcm_base_type = TCM_BASE_OPTIONS[idx].value;
|
|
|
|
|
|
},
|
|
|
|
|
|
goDrugCommission() {
|
|
|
|
|
|
const id = this.form.id || '';
|
|
|
|
|
|
const storeId = this.form.store_id || '';
|
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
|
url: `${ROOT}/drug-commission/index?mode=${this.ctx.mode}&salesperson_id=${id}&store_id=${storeId}`,
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
async submit() {
|
|
|
|
|
|
if (!this.form.phone || !this.form.nick_name) {
|
|
|
|
|
|
uni.showToast({ title: '请填写手机号和名称', icon: 'none' });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (this.ctx.isPlatform && !this.isUpdate && !this.form.store_id) {
|
|
|
|
|
|
uni.showToast({ title: '请选择诊所', icon: 'none' });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-07-07 08:50:05 +08:00
|
|
|
|
if (Number(this.form.parent_salesperson_id) > 0 && !(Number(this.form.inviter_split) > 0)) {
|
|
|
|
|
|
uni.showToast({ title: '请填写邀请分成比例', icon: 'none' });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-06-09 17:02:13 +08:00
|
|
|
|
const payload = { ...this.form };
|
|
|
|
|
|
if (Number(payload.split_type) === 0) payload.split = 0;
|
2026-07-07 08:50:05 +08:00
|
|
|
|
if (!(Number(payload.parent_salesperson_id) > 0)) {
|
|
|
|
|
|
payload.parent_salesperson_id = 0;
|
|
|
|
|
|
payload.inviter_split = 0;
|
|
|
|
|
|
}
|
2026-06-09 17:02:13 +08:00
|
|
|
|
|
|
|
|
|
|
uni.showLoading({ title: '保存中' });
|
|
|
|
|
|
try {
|
|
|
|
|
|
const wrap = this.isUpdate
|
|
|
|
|
|
? await this.ctx.api.update(payload)
|
|
|
|
|
|
: await this.ctx.api.create(payload);
|
|
|
|
|
|
if (wrap && wrap.ok) {
|
|
|
|
|
|
if (!this.isUpdate && wrap.data && wrap.data.admin_account_created === false) {
|
|
|
|
|
|
uni.showToast({ title: '已创建,请手动开通后台', icon: 'none', duration: 2500 });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
uni.showToast({ title: '保存成功', icon: 'success' });
|
|
|
|
|
|
}
|
|
|
|
|
|
setTimeout(() => uni.navigateBack(), 500);
|
|
|
|
|
|
}
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
uni.hideLoading();
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.page { padding: 24rpx; }
|
|
|
|
|
|
.field {
|
|
|
|
|
|
display: flex; align-items: center; background: #fff; border-radius: 16rpx;
|
|
|
|
|
|
padding: 24rpx; margin-bottom: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
.field.link { justify-content: space-between; }
|
|
|
|
|
|
.label { width: 200rpx; font-size: 28rpx; color: #333; flex-shrink: 0; }
|
|
|
|
|
|
.input { flex: 1; font-size: 28rpx; text-align: right; }
|
|
|
|
|
|
.picker-val { flex: 1; font-size: 28rpx; text-align: right; color: #333; }
|
|
|
|
|
|
.link-text { font-size: 26rpx; color: #6ACDBB; }
|
|
|
|
|
|
.section-title { font-size: 26rpx; color: #999; margin: 24rpx 0 12rpx 8rpx; }
|
2026-07-07 08:50:05 +08:00
|
|
|
|
.field-col { background: #fff; border-radius: 16rpx; padding: 24rpx; margin-bottom: 16rpx; }
|
|
|
|
|
|
.label.block { display: block; width: auto; margin-bottom: 16rpx; }
|
2026-06-09 17:02:13 +08:00
|
|
|
|
.submit-btn {
|
|
|
|
|
|
margin-top: 40rpx; background: linear-gradient(90deg, #00BFA6, #6ACDBB);
|
|
|
|
|
|
color: #fff; text-align: center; padding: 24rpx; border-radius: 16rpx; font-size: 30rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|