Files
xk-doctor-wx/subPackages/sub_business_shared/common/display.js

627 lines
21 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { formatMoney } from './format.js'
/** 展示用优先顶层合并医嘱含系统规则文案fallback content 纯医嘱 */
export function formatDoctorOrder(item) {
const pres = item && item.prescription ? item.prescription : item
if (!pres) return '-'
const raw = pres.doctor_order != null && pres.doctor_order !== ''
? pres.doctor_order
: (pres.content && pres.content.doctor_order) || ''
if (Array.isArray(raw)) {
const list = raw.map(s => String(s).trim()).filter(Boolean)
return list.length ? list.join('') : '-'
}
const parts = String(raw).split('|').map(s => s.trim()).filter(Boolean)
return parts.length ? parts.join('') : (raw ? String(raw) : '-')
}
const DEFAULT_DRUG_IMAGE =
'https://xkyp-web2.obs.cn-south-1.myhuaweicloud.com/buy/public/drug_no_mage.png'
/** 兼容 int 时间戳 / datetime 字符串 */
export function formatDateTime(v) {
if (v === null || v === undefined || v === '') return '-'
if (typeof v === 'number') {
const ms = v < 1e12 ? v * 1000 : v
const d = new Date(ms)
if (Number.isNaN(d.getTime())) return '-'
return d.toLocaleString()
}
const s = String(v)
if (s === '2021-01-01 00:00:00') return '-'
return s
}
export function withdrawalCheckStatusText(s) {
const m = { 1: '待审核', 2: '审核成功', 3: '拒绝', 4: '提现失败' }
return m[s] || '-'
}
export function dakuanStatusText(s) {
if (s === -1) return '打款失败'
if (s === 0) return '处理中'
if (s === 1) return '打款成功'
return '-'
}
export function isWithdrawalRejected(item) {
return item && Number(item.check_status) === 3
}
/** 提现列表行展示yii_cash_apply */
export function mapWithdrawalRow(item) {
if (!item) return {}
const checkStatus = item.check_status
return {
id: item.id,
orderNo: item.order_no || '-',
applyCash: formatMoney(item.apply_cash),
trueCash: formatMoney(item.true_cash),
chargeCash: formatMoney(item.charge_cash),
applyTime: formatDateTime(item.apply_time),
checkStatusText: item.check_status_txt || withdrawalCheckStatusText(checkStatus),
checkResult: item.check_result || '',
isRejected: isWithdrawalRejected(item),
dakuanStatusText: item.dakuan_status_txt || dakuanStatusText(item.dakuan_status),
dakuanTime: formatDateTime(item.dakuan_time),
_raw: item,
}
}
/** 结算记录列表行yii_ledger_log */
export function mapSettlementRow(item) {
if (!item) return {}
const isIncrease = item.merged
? (item.type_txt === '增加' || Number(item.amount) >= 0)
: item.type === 1
return {
id: item.id,
orderNo: item.order_no || (item.order_id ? '订单#' + item.order_id : '-'),
orderTypeText: item.order_type_txt || '',
feeTypeText: item.fee_type_txt || '-',
amountText: formatMoney(item.amount),
amountClass: isIncrease ? 'text-success' : 'text-danger',
typeText: item.type_txt || '-',
content: item.content || '',
createdAt: formatDateTime(item.created_at),
merged: !!item.merged,
orderId: item.order_id,
orderType: item.order_type,
_raw: item,
}
}
export function ledgerTypeClass(item) {
return item && item.type === 1 ? 'inc' : 'dec'
}
/** 商品订单状态(对齐 PC product-order */
export function orderStatusText(status) {
const m = {
0: '待支付',
1: '待发货',
2: '待收货',
3: '待评价',
4: '已退款',
5: '退款中',
6: '已收货',
7: '确认收货',
8: '拒绝退款',
9: '已取消',
}
return m[status] != null ? m[status] : '-'
}
export function deliveryMethodText(dm) {
if (dm === 0) return '快递到家'
if (dm === 1) return '药店自提'
return '-'
}
export function orderOnlineText(isOnline) {
if (isOnline === 1) return '在线问诊'
if (isOnline === 2) return '在线复诊'
return '线下就诊'
}
export function prescriptionTypeText(pt) {
const m = {
1: '中药',
2: '西药',
3: '保健食品',
5: '产品服务包',
6: '非药品',
7: '医疗器械',
}
return m[pt] != null ? m[pt] : '其他'
}
export function orderTypeText(ot) {
const m = {
1: '处方订单',
2: '预约购药订单',
3: '商城处方订单',
}
return m[ot] != null ? m[ot] : '其他'
}
export function erpSyncText(v) {
if (v === 1) return '已同步'
return '未同步'
}
export function prescriptionStatusText(status) {
const m = { 0: '待审核', 1: '已审核', 2: '已驳回', 3: '已过期' }
return m[status] != null ? m[status] : '-'
}
export function freeShippingText(v) {
if (v === 1) return '包邮'
return '不包邮'
}
function pickReceiverMobile(item) {
const addr = item.address
if (addr && typeof addr === 'object' && addr.mobile) return addr.mobile
return item.patient_mobile || ''
}
function buildProductSummary(items, prescriptionType, max = 2) {
if (!Array.isArray(items) || !items.length) return ''
return items.slice(0, max).map(p => formatOrderProductLine(p, prescriptionType)).join('')
}
function pickAddrName(item) {
const addr = item.address
if (addr && typeof addr === 'object' && addr.name) return addr.name
if (typeof addr === 'string') {
try {
const o = JSON.parse(addr)
return o.name || ''
} catch (e) {
return ''
}
}
return item.patient || item.express_name || '-'
}
/** 订单列表卡片 */
export function mapOrderListRow(item) {
if (!item) return {}
const store = item.store || {}
const user = item.user || {}
const pt = item.prescription_type
return {
id: item.id,
orderNo: item.order_no || '-',
totalPayPrice: formatMoney(item.total_pay_price),
itemsPrice: formatMoney(item.items_price),
transExpenses: formatMoney(item.trans_expenses),
registerPrice: item.register_id != null && item.register_price != null
? formatMoney(item.register_price)
: '',
registerOrderNo: item.register_order_no || '',
statusText: orderStatusText(item.status),
statusClass: 'tag-status',
prescriptionTypeText: prescriptionTypeText(pt),
prescriptionTypeClass: 'tag-type',
orderTypeText: orderTypeText(item.order_type),
onlineText: orderOnlineText(item.is_online),
erpStatusText: erpSyncText(item.is_sync_erp),
freeShippingText: freeShippingText(item.is_free_shipping),
receiverName: pickAddrName(item),
receiverMobile: pickReceiverMobile(item),
deliveryText: deliveryMethodText(item.delivery_method),
deliveryClass: 'tag-delivery',
userNickname: user.nickname || '-',
patientName: (item.user_patient && item.user_patient.name) || item.patient || '-',
upId: Number(item.up_id || (item.user_patient && item.user_patient.id) || 0),
payTime: formatDateTime(item.pay_time),
createdAt: formatDateTime(item.created_at),
storeName: store.name || '-',
productSummary: buildProductSummary(item.product_order_items, pt),
pId: item.p_id,
canViewPrescription: !!(item.p_id && item.order_type !== 2 && item.order_type !== 3),
_raw: item,
}
}
/**
* 列表卡片瘦字段:只保留 UI 需要的标量,丢弃处方 content / 明细整包,
* 避免微信小程序 setData 体积过大(曾出现 ~1.5MB 告警)
* @param {Object} raw 接口订单行
* @returns {Object}
*/
export function toOrderCardRow(raw) {
if (!raw) return { _wxKey: '0', id: 0 }
const d = mapOrderListRow(raw)
const id = raw.id
const status = raw.status
// 样式用:已完成/取消给语义 class其余用状态码
let statusKey = status != null ? String(status) : 'default'
if (status === 6 || status === 7) statusKey = 'done'
else if (status === 9) statusKey = 'cancel'
const payText = (d.totalPayPrice || '').replace('¥', '').trim()
return {
_wxKey: id != null && id !== '' ? String(id) : 'ord0',
id,
status,
statusKey,
orderNo: d.orderNo,
storeName: d.storeName,
statusText: d.statusText,
productSummary: d.productSummary || '药品订单',
prescriptionTypeText: d.prescriptionTypeText,
deliveryText: d.deliveryText,
patientName: d.patientName,
userNickname: d.userNickname,
receiverName: d.receiverName,
receiverMobile: d.receiverMobile,
createdAt: d.createdAt,
totalPayPrice: d.totalPayPrice,
payAmountText: payText,
pId: d.pId,
canViewPrescription: d.canViewPrescription,
upId: d.upId,
}
}
/** 物流详情(对齐 PC express-detail/detail-by-order */
export function mapExpressDetail(data) {
if (!data || typeof data !== 'object') {
return { hasData: false, companyName: '', expressNo: '', stateText: '', tracks: [] }
}
const rawDetail = data.detail
const tracks = Array.isArray(rawDetail)
? rawDetail.map(d => ({
status: d.status || '-',
time: d.detail_at || '',
detail: d.detail || '',
}))
: []
return {
hasData: !!(data.express_no || data.express_company_name || tracks.length),
companyName: data.express_company_name || '-',
expressNo: data.express_no || '-',
stateText: data.state_txt || '-',
tracks,
}
}
/** 订单详情商品行 */
export function mapOrderProductItem(p, prescriptionType) {
if (!p) return {}
const drug = p.drug || {}
const sourceInfo = drug.source_info || {}
const manufacturer = sourceInfo.name || drug.source || '暂无'
const dosage = p.dosage > 0 ? p.dosage : 1
const qty = prescriptionType === 1
? '*' + ((p.number != null ? p.number : 0) * dosage)
: '×' + (p.number != null ? p.number : 0)
const isTcm = prescriptionType === 1
const unitName =
(drug.unit && drug.unit.name) ||
(p.unit && p.unit.name) ||
p.unit_name ||
'g'
return {
id: p.id,
drugName: p.drug_name || drug.drug_name || '药品',
drugNumber: drug.drug_number || '',
imageUrl: resolveDrugImage(p.drug_image || drug.image),
specification: drug.specification || (isTcm ? unitName : '暂无'),
manufacturer,
qty,
price: isTcm
? (p.price != null && p.price !== '' ? p.price + ' 元/' + unitName : '—')
: formatMoney(p.price),
buyPrice: p.buy_price != null && p.buy_price !== ''
? p.buy_price + ' 元/' + unitName
: '—',
isTcm,
}
}
/** 订单详情处方块 */
export function mapOrderPrescription(info) {
const pres = info && info.prescription
const content = pres && pres.content
if (!content || info.order_type === 2 || info.order_type === 3) return null
const doctor = content.doctor || {}
const depart = doctor.depart || {}
const title = doctor.title || {}
return {
prescriptionNo: content.prescription_no || '-',
diagnose: content.clinical_diagnose || '-',
doctorOrder: formatDoctorOrder(pres),
doctorName: doctor.name || '-',
departName: depart.name || '-',
titleName: title.name || '-',
}
}
export function mapOrderDetailDisplay(info) {
if (!info || !info.id) return {}
const freeShip = info.is_free_shipping === 1 || info.free_ship === 1
const canView = !!(info.p_id && info.order_type !== 2 && info.order_type !== 3)
const presStatus = info.prescription && info.prescription.status != null
? info.prescription.status
: null
return {
orderTypeText: orderTypeText(info.order_type),
marketPrice: formatMoney(info.market_price),
freeShippingText: freeShip ? '是' : '否',
cancelRemark: info.cancel_remark || '无',
showPrescription: mapOrderPrescription(info),
prescriptionId: info.p_id,
canViewPrescription: canView,
prescriptionStatusText: canView && presStatus != null ? prescriptionStatusText(presStatus) : '',
statusText: orderStatusText(info.status),
prescriptionTypeText: prescriptionTypeText(info.prescription_type),
deliveryText: deliveryMethodText(info.delivery_method),
}
}
function parseRecipeContent(raw) {
if (!raw) return null
if (typeof raw === 'object') return raw
try {
return JSON.parse(raw)
} catch (e) {
return null
}
}
/** 完整处方详情(对齐 PC PrescriptionDetail.vue */
export function mapPrescriptionDetailView(item) {
if (!item) return null
const content = item.content || {}
const patient = content.patient || {}
const doctor = content.doctor || {}
const depart = doctor.depart || {}
const title = doctor.title || {}
const pt = item.prescription_type
const recipes = []
const repice = content.repice || content.recipe || []
const list = Array.isArray(repice) ? repice : []
if (pt === 1) {
list.forEach((recipe) => {
const drugs = parseRecipeContent(recipe.content)
const drugLines = Array.isArray(drugs)
? drugs.map(d => {
const name = d.name || d.drug_name || '—'
const num = d.number != null ? d.number : ''
const way = (d.use_way && d.use_way.name) || d.useWay || '煎服'
const unit =
(d.unit && d.unit.name) ||
(d.use_unit && d.use_unit.name) ||
'g'
return {
name,
qty: num !== '' ? num + ' /' + unit : '',
usage: way,
specification: d.specification || '',
}
})
: []
recipes.push({
type: 'tcm',
drugs: drugLines,
usage: recipe.consumption != null && recipe.dosage != null
? `每日${recipe.consumption}次,共${recipe.dosage}`
: '',
process: [recipe.process_rule_note, recipe.process_rule].filter(Boolean).join(''),
})
})
} else {
list.forEach((recipe) => {
const d = parseRecipeContent(recipe.content)
if (!d) return
const unitName = (d.unit && d.unit.name) || d.unit || ''
recipes.push({
type: 'west',
drugs: [{
name: d.name || d.drug_name || '—',
qty: (d.number != null ? d.number : '') + unitName,
usage: d.useWay || (d.use_way && d.use_way.name) || '',
specification: d.specification || '',
}],
usage: '',
process: '',
})
})
}
const tcm = item.online_tcm_print || {}
return {
prescriptionNo: item.prescription_no || content.prescription_no || '-',
createdAt: item.created_at || '-',
patientName: patient.name || '-',
patientSex: patient.sex === 1 ? '男' : patient.sex === 2 ? '女' : '-',
patientAge: patient.age != null ? String(patient.age) : '-',
category: content.category || '-',
diagnose: content.clinical_diagnose || '-',
doctorOrder: formatDoctorOrder(item),
doctorName: doctor.name || '-',
departName: depart.name || '-',
titleName: title.name || '-',
tcmSyndrome: tcm.show && tcm.tcm_syndrome ? tcm.tcm_syndrome : '',
tcmMethod: tcm.show && tcm.tcm_method ? tcm.tcm_method : '',
tcmDisease: tcm.show && tcm.tcm_disease ? tcm.tcm_disease : '',
recipes,
prescriptionType: pt,
}
}
/** 订单商品行展示 */
export function formatOrderProductLine(p, prescriptionType) {
if (!p) return '-'
const name = p.drug_name || (p.drug && p.drug.drug_name) || '药品'
const num = p.number != null ? p.number : ''
if (prescriptionType === 1) {
const dosage = p.dosage > 0 ? p.dosage : 1
return name + ' ×' + (num * dosage)
}
return name + ' ×' + num
}
export function resolveDrugImage(url) {
if (!url) return DEFAULT_DRUG_IMAGE
const s = String(url)
if (s.indexOf('http://') === 0 || s.indexOf('https://') === 0) return s
return DEFAULT_DRUG_IMAGE
}
/** 仓库 1=下架 2=上架 */
export function warehouseStatusText(status) {
if (status === 2) return '上架'
if (status === 1) return '下架'
return '-'
}
export function mapWarehouseRow(item, warehouseType = 'store') {
if (!item) return {}
const drug = item.drug || {}
const storeDrug = drug.drug_store_drug || {}
const suggestPrice = storeDrug.price != null ? storeDrug.price : drug.price
const isPlatform = warehouseType === 'platform'
const supplyRaw = isPlatform
? (item.market_price ?? item.buy_price)
: (item.buy_price ?? item.market_price)
return {
id: item.id,
drugName: drug.drug_name || '-',
imageUrl: resolveDrugImage(drug.image),
buyPrice: formatMoney(supplyRaw),
price: formatMoney(item.price),
suggestPrice: formatMoney(suggestPrice),
stock: item.stock != null ? item.stock : '-',
statusText: warehouseStatusText(item.status),
isOnShelf: item.status === 2,
pinyin: drug.pinyin || '-',
_raw: item,
}
}
function mapReconciliationCategory(rec, prefix) {
const sales = rec[prefix + '_sales']
const salesPrice = rec[prefix + '_sales_price']
const supplyPrice = rec[prefix + '_supply_price']
return {
sales: sales != null ? String(sales) : '-',
salesPrice: formatMoney(salesPrice),
supplyPrice: formatMoney(supplyPrice),
}
}
export function mapReconciliationStoreRow(item) {
if (!item) return {}
const rec = item.reconciliation || {}
return {
id: item.id,
name: item.name || '-',
totalSales: formatMoney(rec.total_sales_price),
totalSupply: formatMoney(rec.total_supply_price),
herbalSalesPrice: formatMoney(rec.herbal_sales_price),
medicineSalesPrice: formatMoney(rec.medicine_sales_price),
registrationPrice: formatMoney(rec.registration_price),
herbal: mapReconciliationCategory(rec, 'herbal'),
medicine: mapReconciliationCategory(rec, 'medicine'),
servicePackage: mapReconciliationCategory(rec, 'service_package'),
otherFees: {
express: formatMoney(rec.express_price),
process: formatMoney(rec.process_price),
treatment: formatMoney(rec.treatment_price),
},
_raw: item,
}
}
/** 订单追溯对账汇总summary 字段,对齐 mapReconciliationStoreRow 结构) */
export function mapReconciliationOrderSummary(summary) {
if (!summary) return null
return {
totalSales: formatMoney(summary.total_sales_price),
totalSupply: formatMoney(summary.total_supply_price),
registrationPrice: formatMoney(summary.registration_price),
registerOrderNo: summary.register_order_no || '',
herbal: mapReconciliationCategory(summary, 'herbal'),
medicine: mapReconciliationCategory(summary, 'medicine'),
servicePackage: mapReconciliationCategory(summary, 'service_package'),
otherFees: {
express: formatMoney(summary.express_price),
process: formatMoney(summary.process_price),
treatment: formatMoney(summary.treatment_price),
},
_raw: summary,
}
}
export function mapReconciliationDrugRow(item) {
if (!item) return {}
return {
drugId: item.drug_id,
drugName: item.drug_name || '-',
drugNumber: item.drug_number || '',
typeText: item.type_txt || '-',
number: item.number != null ? item.number : '-',
marketPrice: formatMoney(item.market_price),
totalSales: formatMoney(item.total_sales_price),
totalSupply: formatMoney(item.total_supply_price),
orderNo: item.order_no || '',
_raw: item,
}
}
export function formatPricePlain(v) {
if (v === null || v === undefined || v === '') return '-'
return '¥' + Number(v).toFixed(2)
}
/** 汇总项:隐藏全零噪音 */
export function filterReconciliationStatItems(items) {
return items.filter(s => {
if (s.key === 'total_sales_price' || s.key === 'total_supply_price') return true
if (s.isCount) {
const n = Number(s.raw)
return !Number.isNaN(n) && n !== 0
}
const v = s.raw
if (v === null || v === undefined || v === '') return false
const n = Number(v)
return !Number.isNaN(n) && n !== 0
})
}
/** 诊所对账汇总(对齐 PC setStoreStatistics */
export function mapReconciliationStoreCount(count) {
if (!count) return []
const items = [
{ key: 'total_sales_price', label: '总销售金额', value: formatPricePlain(count.total_sales_price), raw: count.total_sales_price },
{ key: 'total_supply_price', label: '总供货金额', value: formatPricePlain(count.total_supply_price), raw: count.total_supply_price },
{ key: 'herbal_sales', label: '草药销量', value: count.herbal_sales != null ? String(count.herbal_sales) : '-', raw: count.herbal_sales, isCount: true },
{ key: 'herbal_sales_price', label: '草药销售金额', value: formatPricePlain(count.herbal_sales_price), raw: count.herbal_sales_price },
{ key: 'herbal_supply_price', label: '草药供货金额', value: formatPricePlain(count.herbal_supply_price), raw: count.herbal_supply_price },
{ key: 'medicine_sales', label: '成药销量', value: count.medicine_sales != null ? String(count.medicine_sales) : '-', raw: count.medicine_sales, isCount: true },
{ key: 'medicine_sales_price', label: '成药销售金额', value: formatPricePlain(count.medicine_sales_price), raw: count.medicine_sales_price },
{ key: 'medicine_supply_price', label: '成药供货金额', value: formatPricePlain(count.medicine_supply_price), raw: count.medicine_supply_price },
{ key: 'express_price', label: '快递费', value: formatPricePlain(count.express_price), raw: count.express_price },
{ key: 'process_price', label: '加工费', value: formatPricePlain(count.process_price), raw: count.process_price },
{ key: 'treatment_price', label: '诊疗费', value: formatPricePlain(count.treatment_price), raw: count.treatment_price },
{ key: 'outpatient_price', label: '门诊收入', value: formatPricePlain(count.outpatient_price), raw: count.outpatient_price },
{ key: 'registration_price', label: '挂号费', value: formatPricePlain(count.registration_price), raw: count.registration_price },
]
return filterReconciliationStatItems(items)
}
/** 药品对账汇总(对齐 PC setDrugStatistics */
export function mapReconciliationDrugCount(count) {
if (!count) return []
return [
{ key: 'total_sales_price', label: '总销售金额', value: formatPricePlain(count.total_sales_price) },
{ key: 'total_supply_price', label: '总供货金额', value: formatPricePlain(count.total_supply_price) },
{ key: 'number', label: '销量', value: count.number != null ? String(count.number) : '-' },
]
}