- doctor-login submitLogin 增加「请输入密码」前置校验, 与 getCode 一致,避免空密码误触发登录请求 - 配合后端 service_user 空密码回退 PC 医生/药师密码校验
257 lines
9.6 KiB
Vue
257 lines
9.6 KiB
Vue
<template>
|
||
<store-page-layout title="门店详情" :show-back="true">
|
||
<view class="page" v-if="store.id">
|
||
<view class="hero-card">
|
||
<text class="name">{{ store.name }}</text>
|
||
<text class="sub">ID {{ store.id }} · {{ clinicTypeText(store.clinic_type) }}</text>
|
||
<text class="addr">{{ store.position || '暂无地址' }}</text>
|
||
</view>
|
||
|
||
<!-- 只读信息:业务员无编辑权限时展示配置摘要 -->
|
||
<view v-if="!canEdit" class="section">
|
||
<text class="section-title">门店信息</text>
|
||
<view class="info-row"><text>推广员可见价格</text><text>{{ Number(store.salesperson_see_price) === 1 ? '是' : '否' }}</text></view>
|
||
<view class="info-row"><text>包邮</text><text>{{ Number(store.is_shipping_free) === 1 ? '是' : '否' }}</text></view>
|
||
<view class="info-row"><text>订阅价格波动</text><text>{{ Number(store.subscribe_price_change) === 0 ? '是' : '否' }}</text></view>
|
||
<view class="info-row"><text>查看毛利率</text><text>{{ Number(store.see_rate) === 1 ? '是' : '否' }}</text></view>
|
||
<view class="info-row"><text>开方可选医保</text><text>{{ Number(store.allow_insurance_category) === 1 ? '是' : '否' }}</text></view>
|
||
<view class="info-row"><text>诊所类型</text><text>{{ clinicTypeText(store.clinic_type) }}</text></view>
|
||
</view>
|
||
|
||
<view v-if="canEdit" class="section">
|
||
<text class="section-title">门店配置</text>
|
||
<view v-if="!isSalesperson" class="switch-row">
|
||
<text>推广员可见价格</text>
|
||
<switch :checked="Number(store.salesperson_see_price) === 1" color="#6ACDBB" @change="toggleSeePrice" />
|
||
</view>
|
||
<view class="switch-row">
|
||
<text>包邮</text>
|
||
<switch :checked="Number(store.is_shipping_free) === 1" color="#6ACDBB" @change="toggleShipping" />
|
||
</view>
|
||
<view class="switch-row">
|
||
<text>订阅价格波动</text>
|
||
<switch :checked="Number(store.subscribe_price_change) === 0" color="#6ACDBB" @change="toggleSubscribe" />
|
||
</view>
|
||
<view class="switch-row">
|
||
<text>查看毛利率</text>
|
||
<switch :checked="Number(store.see_rate) === 1" color="#6ACDBB" @change="toggleSeeRate" />
|
||
</view>
|
||
<view class="switch-row">
|
||
<text>开方可选医保</text>
|
||
<switch :checked="Number(store.allow_insurance_category) === 1" color="#6ACDBB" @change="toggleInsurance" />
|
||
</view>
|
||
<view class="picker-row">
|
||
<text>诊所类型</text>
|
||
<picker :range="clinicTypeLabels" :value="clinicTypeIndex" @change="onClinicType">
|
||
<view class="picker-val">{{ clinicTypeLabels[clinicTypeIndex] }}</view>
|
||
</picker>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="section">
|
||
<text class="section-title">快捷操作</text>
|
||
<view class="action-grid">
|
||
<view v-if="canEdit" class="action-btn" @click="goEdit">编辑资料</view>
|
||
<view v-if="canEdit" class="action-btn" @click="goDrugPrice">修改药品价格</view>
|
||
<view v-if="canEdit" class="action-btn" @click="goConsultation">在线复诊配置</view>
|
||
<view v-if="canEdit && !isSalesperson" class="action-btn" @click="goPromoters">管理推广员</view>
|
||
<view class="action-btn" @click="openQr">诊所二维码</view>
|
||
<view class="action-btn" @click="goBankCardReport">{{ bankCardReportButtonText }}</view>
|
||
<view v-if="canEdit && !hasAdminAccount" class="action-btn warn" @click="openPc">开通后台</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="store.online_consultation_doctor_name || store.delegate_store_name" class="section">
|
||
<text class="section-title">在线复诊</text>
|
||
<text v-if="store.delegate_store_name" class="info-line">委托诊所:{{ store.delegate_store_name }}</text>
|
||
<text v-if="store.online_consultation_doctor_name" class="info-line">负责人:{{ store.online_consultation_doctor_name }}</text>
|
||
</view>
|
||
</view>
|
||
</store-page-layout>
|
||
</template>
|
||
|
||
<script>
|
||
/**
|
||
* 门店详情:超管可编辑;业务员默认只读,系统配置开启后显示编辑入口
|
||
*/
|
||
import StorePageLayout from '@/subPackages/sub_platform_admin/components/store-page-layout.vue';
|
||
import {
|
||
getStoreDetail,
|
||
getSalespersonStoreEditPermission,
|
||
toggleSalespersonSeePrice,
|
||
updateStoreShippingFree,
|
||
updateStoreSubscribeStatus,
|
||
updateStoreSeeRate,
|
||
updateStoreAllowInsurance,
|
||
updateStoreClinicType,
|
||
openStorePcWindows,
|
||
openStoreQrCode,
|
||
isSalespersonStoreMode,
|
||
} from '@/api/storeManage.js';
|
||
import { openQrCodePreview, buildClinicQrPayload } from '@/utils/qrCodePreview.js';
|
||
|
||
const ROOT = '/subPackages/sub_platform_admin/store';
|
||
const MANAGE_ROOT = '/subPackages/sub_salesperson_manage';
|
||
|
||
export default {
|
||
components: { StorePageLayout },
|
||
data() {
|
||
return {
|
||
storeId: 0,
|
||
store: {},
|
||
clinicTypeLabels: ['未设置', '西医诊所', '中医诊所'],
|
||
isSalesperson: false,
|
||
/** 业务员编辑开关;超管始终 true */
|
||
salespersonEditEnabled: false,
|
||
};
|
||
},
|
||
computed: {
|
||
canEdit() {
|
||
if (!this.isSalesperson) return true;
|
||
return !!this.salespersonEditEnabled;
|
||
},
|
||
clinicTypeIndex() {
|
||
return Number(this.store.clinic_type) || 0;
|
||
},
|
||
hasAdminAccount() {
|
||
const admin = this.store.new_admin || this.store.newAdmin;
|
||
return !!(admin && (admin.id || admin.code));
|
||
},
|
||
bankCardReportButtonText() {
|
||
const text = this.store.bank_card_report_status_text;
|
||
if (Number(this.store.bank_card_report_status) === 0 || !text || text === '未报备') {
|
||
return '银行卡报备';
|
||
}
|
||
return `银行卡报备(${text})`;
|
||
},
|
||
},
|
||
onLoad(options) {
|
||
this.storeId = Number(options.id || 0);
|
||
this.isSalesperson = isSalespersonStoreMode();
|
||
this.bootstrap();
|
||
},
|
||
methods: {
|
||
clinicTypeText(type) {
|
||
return this.clinicTypeLabels[Number(type) || 0] || '未设置';
|
||
},
|
||
async bootstrap() {
|
||
if (this.isSalesperson) {
|
||
try {
|
||
const wrap = await getSalespersonStoreEditPermission();
|
||
const data = wrap && wrap.ok ? wrap.data : null;
|
||
this.salespersonEditEnabled = !!(data && data.salesperson_store_edit_enabled);
|
||
} catch (e) {
|
||
this.salespersonEditEnabled = false;
|
||
}
|
||
}
|
||
await this.loadDetail();
|
||
},
|
||
async loadDetail() {
|
||
if (!this.storeId) return;
|
||
const wrap = await getStoreDetail(this.storeId);
|
||
if (wrap && wrap.ok) {
|
||
this.store = wrap.data || {};
|
||
}
|
||
},
|
||
async toggleSeePrice() {
|
||
const wrap = await toggleSalespersonSeePrice(this.storeId);
|
||
if (wrap && wrap.ok && wrap.data) {
|
||
this.store.salesperson_see_price = wrap.data.see_price;
|
||
}
|
||
},
|
||
async toggleShipping() {
|
||
const wrap = await updateStoreShippingFree(this.storeId);
|
||
if (wrap && wrap.ok) await this.loadDetail();
|
||
},
|
||
async toggleSubscribe() {
|
||
const wrap = await updateStoreSubscribeStatus(this.storeId);
|
||
if (wrap && wrap.ok) await this.loadDetail();
|
||
},
|
||
async toggleSeeRate() {
|
||
const wrap = await updateStoreSeeRate(this.storeId);
|
||
if (wrap && wrap.ok) await this.loadDetail();
|
||
},
|
||
async toggleInsurance() {
|
||
const wrap = await updateStoreAllowInsurance(this.storeId);
|
||
if (wrap && wrap.ok) await this.loadDetail();
|
||
},
|
||
async onClinicType(e) {
|
||
const idx = Number(e.detail.value);
|
||
if (idx <= 0) return;
|
||
const wrap = await updateStoreClinicType(this.storeId, idx);
|
||
if (wrap && wrap.ok) {
|
||
this.store.clinic_type = idx;
|
||
uni.showToast({ title: '已更新', icon: 'success' });
|
||
}
|
||
},
|
||
goEdit() {
|
||
uni.navigateTo({ url: `${ROOT}/edit?id=${this.storeId}` });
|
||
},
|
||
goDrugPrice() {
|
||
uni.navigateTo({ url: `${ROOT}/drug-price?id=${this.storeId}&name=${encodeURIComponent(this.store.name || '')}` });
|
||
},
|
||
goConsultation() {
|
||
uni.navigateTo({ url: `${ROOT}/consultation?id=${this.storeId}` });
|
||
},
|
||
goPromoters() {
|
||
uni.navigateTo({ url: `${MANAGE_ROOT}/index?mode=platform&store_id=${this.storeId}` });
|
||
},
|
||
goBankCardReport() {
|
||
if (!this.storeId) return;
|
||
uni.navigateTo({
|
||
url: `/subPackages/sub_salesperson/store-bank-card/report?store_id=${this.storeId}`,
|
||
});
|
||
},
|
||
async openQr() {
|
||
uni.showLoading({ title: '生成中' });
|
||
try {
|
||
const wrap = await openStoreQrCode(this.storeId);
|
||
if (wrap && wrap.ok) {
|
||
await this.loadDetail();
|
||
const payload = buildClinicQrPayload(this.store);
|
||
openQrCodePreview({ type: 'clinic', title: this.store.name, payload: payload.payload });
|
||
}
|
||
} finally {
|
||
uni.hideLoading();
|
||
}
|
||
},
|
||
async openPc() {
|
||
uni.showModal({
|
||
title: '开通后台',
|
||
content: '确定为该诊所开通 PC 后台账号?',
|
||
success: async (res) => {
|
||
if (!res.confirm) return;
|
||
const wrap = await openStorePcWindows(this.storeId);
|
||
if (wrap && wrap.ok) {
|
||
uni.showToast({ title: '开通成功', icon: 'success' });
|
||
await this.loadDetail();
|
||
}
|
||
},
|
||
});
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.page { padding: 24rpx; }
|
||
.hero-card { background: linear-gradient(135deg, #6acdbb, #4db6a8); border-radius: 20rpx; padding: 32rpx; color: #fff; margin-bottom: 24rpx; }
|
||
.name { display: block; font-size: 36rpx; font-weight: 700; }
|
||
.sub, .addr { display: block; font-size: 24rpx; margin-top: 8rpx; opacity: 0.9; }
|
||
.section { background: #fff; border-radius: 20rpx; padding: 24rpx; margin-bottom: 20rpx; }
|
||
.section-title { display: block; font-size: 28rpx; font-weight: 600; margin-bottom: 16rpx; }
|
||
.switch-row, .picker-row, .info-row {
|
||
display: flex; justify-content: space-between; align-items: center;
|
||
padding: 20rpx 0; border-bottom: 1rpx solid #f0f0f0; font-size: 28rpx;
|
||
}
|
||
.info-row text:last-child { color: #6b7280; }
|
||
.picker-val { color: #6ACDBB; }
|
||
.action-grid { display: flex; flex-wrap: wrap; gap: 16rpx; }
|
||
.action-btn {
|
||
flex: 1; min-width: 40%; text-align: center; padding: 20rpx;
|
||
background: #f0fbf8; color: #6ACDBB; border-radius: 12rpx; font-size: 26rpx;
|
||
}
|
||
.action-btn.warn { background: #FEF3C7; color: #D97706; }
|
||
.info-line { display: block; font-size: 26rpx; color: #666; margin-bottom: 8rpx; }
|
||
</style>
|