1. 特色方模块

This commit is contained in:
李琦
2026-07-03 07:57:26 +08:00
parent 03973e8718
commit f18916f9d5
23 changed files with 1408 additions and 186 deletions

View File

@@ -28,6 +28,7 @@
<!-- 操作面板通栏 -->
<view class="setting-panel">
<wx-bind-entry ref="wxBindEntry" />
<account-switch-entry />
<view
class="setting-item action-item"
@@ -48,10 +49,11 @@
<script>
import ClinicPageLayout from '@/subPackages/sub_clinic_admin/components/clinic-page-layout.vue'
import AccountSwitchEntry from '@/components/account-switch/account-switch-entry.vue'
import WxBindEntry from '@/components/wx-bind-entry/wx-bind-entry.vue'
import { clearLoginStorage } from '@/utils/loginSession.js'
export default {
components: { ClinicPageLayout, AccountSwitchEntry },
components: { ClinicPageLayout, AccountSwitchEntry, WxBindEntry },
data() {
return {
displayName: '',
@@ -68,6 +70,7 @@ export default {
const user = uni.getStorageSync('clinic_admin_user') || {}
this.displayName = user.nick_name || user.name || user.account || '管理员'
this.storeName = user.store_name || (user.store && user.store.name) || '-'
if (this.$refs.wxBindEntry) this.$refs.wxBindEntry.refresh()
},
methods: {
logout() {

View File

@@ -48,6 +48,8 @@
<view class="setting-panel">
<wx-bind-entry ref="wxBindEntry" />
<account-switch-entry />
<view
@@ -84,6 +86,8 @@ import ClinicSalespersonPageLayout from '@/subPackages/sub_clinic_salesperson/co
import AccountSwitchEntry from '@/components/account-switch/account-switch-entry.vue'
import WxBindEntry from '@/components/wx-bind-entry/wx-bind-entry.vue'
import { getClinicSalespersonMyInfo } from '@/api/clinicSalesperson.js'
import { clearLoginStorage } from '@/utils/loginSession.js'
@@ -92,7 +96,7 @@ import { clearLoginStorage } from '@/utils/loginSession.js'
export default {
components: { ClinicSalespersonPageLayout, AccountSwitchEntry },
components: { ClinicSalespersonPageLayout, AccountSwitchEntry, WxBindEntry },
data() {
@@ -124,6 +128,8 @@ export default {
this.loadProfile()
if (this.$refs.wxBindEntry) this.$refs.wxBindEntry.refresh()
},
methods: {

View File

@@ -35,28 +35,17 @@
<d-text :text="userInfo.title.name" color="#31353D"></d-text>
</view> -->
</view>
<view class="p-row-32 m-t-8 white b-r-8">
<account-switch-entry />
</view>
<view class="p-row-32 m-t-8" style="height: 100rpx;">
<u-button :throttle-time="0" shape="circle" :custom-style="{backgroundColor:'#6ACDBB',color:'#fff',heigth:'96rpx'}" @click="logout">
退出登录</u-button>
</view>
</view>
</template>
<script>
import {
info,
logout,
toUpload,
} from '@/api/all.js'
import AccountSwitchEntry from '@/components/account-switch/account-switch-entry.vue'
import { chooseAvatarImage } from '@/common/js/select-avatar-image.js';
export default {
components: { AccountSwitchEntry },
components: {},
data() {
return {
doctorInfo: []
@@ -112,29 +101,6 @@
},
});
},
logout() {
logout({store_id: uni.getStorageSync('store_id') || 11001,}).then((res) => {
if (res.errcode != -1) {
uni.clearStorage()
uni.clearStorageSync()
this.$go('/pages/login/index', 2)
} else {
this.$toast(res.msg);
}
})
}
// // 医生详情
// getInfo() {
// info({
// store_id: uni.getStorageSync('store_id') || '11001'
// }).then((res) => {
// // console.log(res.data, 'work-res');
// if (res.errcode == 0) {
// this.doctorInfo = res.data
// }
// })
// }
},
mounted() {
this.getDoctor()

View File

@@ -9,6 +9,7 @@
</view>
</view>
<view class="setting-panel">
<wx-bind-entry ref="wxBindEntry" />
<account-switch-entry />
<view class="setting-item action-item" @click="logout">
<text class="danger-text">退出登录</text>
@@ -21,11 +22,12 @@
<script>
import BusinessPageLayout from '@/subPackages/sub_platform_admin/components/business-page-layout.vue'
import AccountSwitchEntry from '@/components/account-switch/account-switch-entry.vue'
import WxBindEntry from '@/components/wx-bind-entry/wx-bind-entry.vue'
import { getPlatformAdminContext } from '@/subPackages/sub_platform_admin/common/context.js'
import { clearLoginStorage } from '@/utils/loginSession.js'
export default {
components: { BusinessPageLayout, AccountSwitchEntry },
components: { BusinessPageLayout, AccountSwitchEntry, WxBindEntry },
provide() { return { businessContext: getPlatformAdminContext() } },
data() { return { displayName: '', roleText: '平台管理员' } },
computed: {
@@ -35,6 +37,7 @@ export default {
const user = uni.getStorageSync('platform_admin_user') || {}
this.displayName = user.nick_name || '管理员'
this.roleText = (user.roles && user.roles.name) || '平台管理员'
if (this.$refs.wxBindEntry) this.$refs.wxBindEntry.refresh()
},
methods: {
logout() {

View File

@@ -9,6 +9,7 @@
</view>
</view>
<view class="setting-panel">
<wx-bind-entry ref="wxBindEntry" />
<account-switch-entry />
<view class="setting-item" @click="logout"><text class="danger-text">退出登录</text></view>
</view>
@@ -19,11 +20,12 @@
<script>
import BusinessPageLayout from '@/subPackages/sub_salesperson/components/business-page-layout.vue'
import AccountSwitchEntry from '@/components/account-switch/account-switch-entry.vue'
import WxBindEntry from '@/components/wx-bind-entry/wx-bind-entry.vue'
import { getSalespersonContext } from '@/subPackages/sub_salesperson/common/context.js'
import { clearLoginStorage } from '@/utils/loginSession.js'
export default {
components: { BusinessPageLayout, AccountSwitchEntry },
components: { BusinessPageLayout, AccountSwitchEntry, WxBindEntry },
provide() { return { businessContext: getSalespersonContext() } },
data() { return { displayName: '', roleText: '业务员' } },
computed: { avatarText() { return (this.displayName || '业').slice(0, 1) } },
@@ -31,6 +33,7 @@ export default {
const user = uni.getStorageSync('salesperson_user') || {}
this.displayName = user.nick_name || '业务员'
this.roleText = (user.roles && user.roles.name) || '业务员'
if (this.$refs.wxBindEntry) this.$refs.wxBindEntry.refresh()
},
methods: {
logout() {

View File

@@ -35,6 +35,55 @@
<text class="register-mode-hint__text">{{ registerModeHint }}</text>
</view>
<view
v-if="!isSalespersonTransferMode && hasSpecialPrescriptionRecord"
class="special-rx-card mx-32 m-t-12"
>
<view class="special-rx-card__inner flex-row flex-ali-center">
<u-image
v-if="specialPrescriptionRecord.special_prescription && specialPrescriptionRecord.special_prescription.cover_image"
width="96rpx"
height="96rpx"
border-radius="12"
:src="specialPrescriptionRecord.special_prescription.cover_image"
/>
<view class="flex-1 m-l-16">
<view class="fs-28 font-bold text-gray">
{{ (specialPrescriptionRecord.special_prescription && specialPrescriptionRecord.special_prescription.name) || '特色方' }}
</view>
<view class="fs-24 color-sub m-t-8">
剂量{{ specialPrescriptionRecord.dose_count }}
</view>
<view class="m-t-8">
<u-tag
v-if="Number(specialPrescriptionRecord.status) === 0"
text="待导入"
type="warning"
size="mini"
/>
<u-tag
v-else-if="Number(specialPrescriptionRecord.status) === 1"
text="已应用"
type="success"
size="mini"
/>
<u-tag v-else text="已完成" type="info" size="mini" />
</view>
</view>
</view>
<view class="special-rx-card__action m-t-16">
<u-button
size="default"
type="primary"
:loading="applyingSpecialPrescription"
:custom-style="{ backgroundColor: '#6ACDBB', color: '#fff', border: 'none', width: '100%' }"
@click="handleApplySpecialPrescription"
>
导入
</u-button>
</view>
</view>
<view v-if="!isSalespersonTransferMode && allowInsuranceCategory" class="mx-32 m-t-12 flex flex-ali-center">
<u-button size="mini" :type="feeCategory === 1 ? 'success' : 'default'" @click="feeCategory = 1">自费</u-button>
<u-button size="mini" class="m-l-16" :type="feeCategory === 2 ? 'success' : 'default'" @click="feeCategory = 2">医保</u-button>
@@ -539,6 +588,7 @@ import {
getProductListDoctorReception,
getPatientInfoByPatientId,
getPatientItem,
applySpecialPrescriptionApi,
getProcessRuleList,
getCommonPrescriptionListApi,
saveWestCommonPrescriptionApi,
@@ -571,6 +621,10 @@ import {
getClinicSalespersonSeePriceConfig,
getClinicSalespersonProcessRuleList,
} from '@/api/clinicSalesperson.js';
import {
pickSpecialPrescriptionRecord,
applySpecialPrescriptionPayload,
} from './utils/specialPrescription.js';
const PENDING_RX_FROM_CHAT = 'xk_pending_rx_from_chat';
const SALESPERSON_TRANSFER_STORAGE_KEY = 'salesperson_transfer';
@@ -676,6 +730,9 @@ export default {
sendMode: 0,
selectedStoreId: null,
registerOrderType: null,
specialPrescriptionRecord: null,
applyingSpecialPrescription: false,
pendingImportSpecial: false,
/** 在线复诊中药术语表HTTP 拉取,内存缓存) */
traditionalTcmData: null,
@@ -803,6 +860,9 @@ export default {
if (this.registerOrderType === null || this.registerOrderType === undefined || this.registerOrderType === '') return '';
return this.isOnlineRevisit ? '当前:在线复诊开方(提交后将向患者发送处方消息)' : '当前:线下开方';
},
hasSpecialPrescriptionRecord() {
return !!this.specialPrescriptionRecord;
},
navbarTitle() {
if (this.isSalespersonTransferMode) {
return '传方';
@@ -905,6 +965,7 @@ export default {
}
this.patientId = options.patient_id || '';
this.pendingReusePrescriptionId = options.reuse_prescription_id ? String(options.reuse_prescription_id) : '';
this.pendingImportSpecial = String(options.import_special) === '1';
this.isCommonPrescription = String(options.save_common) === '1';
if (!this.isCommonPrescription) {
uni.removeStorageSync('add');
@@ -969,6 +1030,10 @@ export default {
await this.maybeApplyReusePrescription();
if (this.activeCategory === 1) await this.checkAndShowTransferTip();
this.applyPendingExperienceDrugFromChat();
if (this.pendingImportSpecial && this.hasSpecialPrescriptionRecord) {
await this.handleApplySpecialPrescription();
this.pendingImportSpecial = false;
}
}
// #ifdef MP-WEIXIN
this.$nextTick(() => {
@@ -1099,6 +1164,7 @@ export default {
async loadRegisterOrderType() {
if (!this.registerId) {
this.registerOrderType = null;
this.specialPrescriptionRecord = null;
return;
}
try {
@@ -1109,9 +1175,11 @@ export default {
} else {
this.registerOrderType = null;
}
this.specialPrescriptionRecord = pickSpecialPrescriptionRecord(data);
} catch (e) {
console.warn(e);
this.registerOrderType = null;
this.specialPrescriptionRecord = null;
}
},
async loadBasicConfigData() {
@@ -1386,6 +1454,22 @@ export default {
this.saveToLocalStorage();
},
handleOpenCommonPrescriptionModal() { this.showCommonPrescriptionModal = true; },
async handleApplySpecialPrescription() {
if (!this.registerId || this.applyingSpecialPrescription) return;
this.applyingSpecialPrescription = true;
try {
const res = await applySpecialPrescriptionApi({ register_id: this.registerId });
const data = res.result || res.data || res;
applySpecialPrescriptionPayload(this, data);
await this.loadRegisterOrderType();
this.$toast(`已导入特色方:${data.special_prescription_name || ''}`);
} catch (error) {
console.error('导入特色方失败:', error);
this.$toast('导入特色方失败,请稍后重试');
} finally {
this.applyingSpecialPrescription = false;
}
},
async handleSelectCommonPrescription(item) {
try {
const payload = item && item.apply_payload;
@@ -2541,6 +2625,18 @@ export default {
color: #008771;
line-height: 1.5;
}
.special-rx-card {
padding: 20rpx 24rpx;
background: #fffaf5;
border-radius: 12rpx;
border: 1rpx solid #ffe0c2;
}
.special-rx-card__inner {
width: 100%;
}
.special-rx-card__action {
width: 100%;
}
.bottom {
position: fixed;
bottom: 0;

View File

@@ -0,0 +1,54 @@
/**
* 从 patient-item 等接口响应中解析特色方选方记录
*/
export function pickSpecialPrescriptionRecord(data) {
if (!data || typeof data !== 'object') {
return null;
}
return (
data.special_prescription_patient_record
|| data.specialPrescriptionPatientRecord
|| null
);
}
/**
* 将 apply 接口返回的数据写入处方页 state
*/
export function applySpecialPrescriptionPayload(page, data) {
const categoryMap = { west: 2, chinese: 1, granular: 1 };
const prescriptionType = data.prescription_type || 'chinese';
page.activeCategory = categoryMap[prescriptionType] || 1;
page.loadCurrentCategoryDrugs();
const recipes = data.recipes || [];
page.currentDrugs.splice(0, page.currentDrugs.length);
recipes.forEach((recipe) => {
const drugId = recipe.drug_id || recipe.id;
page.currentDrugs.push(page.prepareDrugForCart({
index_id: recipe.id,
id: drugId,
drug_id: drugId,
drug_name: recipe.drug_name || recipe.name,
number: recipe.number || 1,
price: recipe.price || 0,
buy_price: recipe.buy_price,
way_id: recipe.way_id || 0,
}));
});
page.chineseConfig = {
...page.chineseConfig,
ruleType: data.rule_type ?? 1,
dosage: data.dosage ?? data.dose_count ?? 7,
dayDosage: data.day_dosage ?? 2,
packageMethodId: data.package_method_id ?? 2,
};
if (data.clinical_diagnose) {
page.diagnosisText = data.clinical_diagnose;
const names = String(data.clinical_diagnose).split('').filter(Boolean);
page.diagnoses = names.map((name, index) => ({ id: `temp_${index}`, name }));
}
if (data.doctor_order) {
page.medicalAdvice = data.doctor_order;
}
page.saveToLocalStorage();
}

View File

@@ -67,6 +67,54 @@
</view>
</view>
<!-- 特色方信息 -->
<view v-if="infoList.special_prescription_patient_record" class="modern-card">
<view class="card-title">特色方</view>
<view class="special-rx-info flex-row flex-ali-center">
<u-image
v-if="infoList.special_prescription_patient_record.special_prescription && infoList.special_prescription_patient_record.special_prescription.cover_image"
width="96rpx"
height="96rpx"
border-radius="12"
:src="infoList.special_prescription_patient_record.special_prescription.cover_image"
/>
<view class="flex-1 m-l-16">
<view class="info-value font-bold">
{{ (infoList.special_prescription_patient_record.special_prescription && infoList.special_prescription_patient_record.special_prescription.name) || '特色方' }}
</view>
<view class="info-row" style="border-bottom: none; padding: 8rpx 0 0;">
<text class="info-label">剂量</text>
<text class="info-value">{{ infoList.special_prescription_patient_record.dose_count }} </text>
</view>
<view class="m-t-8">
<u-tag
v-if="Number(infoList.special_prescription_patient_record.status) === 0"
text="待导入"
type="warning"
size="mini"
/>
<u-tag
v-else-if="Number(infoList.special_prescription_patient_record.status) === 1"
text="已应用"
type="success"
size="mini"
/>
<u-tag v-else text="已完成" type="info" size="mini" />
</view>
</view>
</view>
<view class="m-t-24">
<u-button
type="primary"
shape="circle"
:custom-style="{ backgroundColor: '#6ACDBB', color: '#fff', border: 'none' }"
@click="goImportSpecialPrescription"
>
导入
</u-button>
</view>
</view>
<!-- 健康信息 -->
<view class="modern-card">
<view class="card-title">健康信息</view>
@@ -201,6 +249,7 @@ import {
receptionApi,
endOfDiagnosisApi
} from '@/api/reception.js'
import { pickSpecialPrescriptionRecord } from '@/subPackages/sub_workbench/prescription_v2/utils/specialPrescription.js'
function emptyHealthInquiry() {
return {
@@ -235,7 +284,8 @@ function normalizeRegisterDetail(raw) {
store: store && store.name !== undefined ? store : {
name: ''
},
healthInquery: hi || emptyHealthInquiry()
healthInquery: hi || emptyHealthInquiry(),
special_prescription_patient_record: pickSpecialPrescriptionRecord(raw),
})
}
@@ -471,7 +521,7 @@ export default {
this.$toast(this.apiMsg(res))
return
}
const raw = res.result || res.data
const raw = res.result || res.data || res
this.infoList = normalizeRegisterDetail(raw)
if (this.infoList.status !== 7) {
if (this.rxTabIndex === 0) {
@@ -489,6 +539,19 @@ export default {
const patientId = this.infoList.user_patient_id;
this.$go(`/subPackages/sub_workbench/prescription_v2/index?register_id=${registerId}&patient_id=${patientId}`);
},
goImportSpecialPrescription() {
const registerId = this.infoList.id;
const patientId = this.infoList.user_patient_id;
if (!registerId) {
this.$toast('挂号信息无效');
return;
}
let url = `/subPackages/sub_workbench/prescription_v2/index?register_id=${registerId}&import_special=1`;
if (patientId) {
url += `&patient_id=${patientId}`;
}
this.$go(url);
},
goToReusePrescription(prescriptionId) {
const registerId = this.infoList.id;
const patientId = this.infoList.user_patient_id;