799 lines
22 KiB
Vue
799 lines
22 KiB
Vue
<template>
|
||
<clinic-page-layout title="对账单" :show-back="true">
|
||
<view class="reconciliation-container">
|
||
<!-- 顶部吸顶区:Tabs 与 时间快筛 -->
|
||
<page-sticky-header>
|
||
<view class="header-section">
|
||
<view class="tabs-wrap">
|
||
<u-tabs
|
||
:list="tabList"
|
||
:is-scroll="false"
|
||
:current="tabIndex"
|
||
active-color="#6ACDBB"
|
||
inactive-color="#86909C"
|
||
bg-color="transparent"
|
||
:bold="true"
|
||
@change="onTabChange"
|
||
/>
|
||
</view>
|
||
|
||
<view class="quick-filter">
|
||
<view class="date-range-picker">
|
||
<picker mode="date" :value="dateStart" @change="onStart">
|
||
<text class="date-text" :class="{'placeholder': !dateStart}">{{ dateStart || '开始日期' }}</text>
|
||
</picker>
|
||
<text class="sep">至</text>
|
||
<picker mode="date" :value="dateEnd" @change="onEnd">
|
||
<text class="date-text" :class="{'placeholder': !dateEnd}">{{ dateEnd || '结束日期' }}</text>
|
||
</picker>
|
||
</view>
|
||
<view class="filter-actions">
|
||
<text class="btn-clear" @click="resetFilter">清空</text>
|
||
<text class="btn-search" @click="reload">查询</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 药品折叠筛选面板 (保持逻辑不变,美化表单) -->
|
||
<collapsible-filter-panel v-if="tab === 'drug'" title="药品高级筛选" @clear="resetFilter">
|
||
<view class="filter-row switch-row">
|
||
<view class="filter-label-group">
|
||
<text class="filter-label">按订单维度拆分</text>
|
||
<text class="filter-hint">未勾选时按药品+供货价合并</text>
|
||
</view>
|
||
<switch :checked="byOrder" color="#6acdbb" style="transform:scale(0.85)" @change="onByOrderChange" />
|
||
</view>
|
||
|
||
<view class="filter-field">
|
||
<text class="filter-label">药品</text>
|
||
<view class="search-input-group">
|
||
<input
|
||
class="filter-input"
|
||
v-model="drugSearchQ"
|
||
placeholder="输入名称或拼音搜索"
|
||
placeholder-style="color:#BDBDBD"
|
||
confirm-type="search"
|
||
@confirm="searchDrugOptions"
|
||
/>
|
||
<text class="filter-link" @click="searchDrugOptions">搜索</text>
|
||
</view>
|
||
</view>
|
||
<view class="picker-wrap" v-if="drugOptionLabels.length">
|
||
<picker :range="drugOptionLabels" @change="onDrugPick">
|
||
<view class="filter-picker">{{ selectedDrugLabel || '点击选择匹配的药品' }}</view>
|
||
</picker>
|
||
<text v-if="drugId" class="filter-clear" @click="clearDrug">清除选择</text>
|
||
</view>
|
||
|
||
<view class="filter-field">
|
||
<text class="filter-label">订单</text>
|
||
<view class="search-input-group">
|
||
<input
|
||
class="filter-input"
|
||
v-model="orderSearchQ"
|
||
placeholder="输入订单号搜索"
|
||
placeholder-style="color:#BDBDBD"
|
||
confirm-type="search"
|
||
@confirm="searchOrderOptions"
|
||
/>
|
||
<text class="filter-link" @click="searchOrderOptions">搜索</text>
|
||
</view>
|
||
</view>
|
||
<view class="picker-wrap" v-if="orderOptionLabels.length">
|
||
<picker :range="orderOptionLabels" @change="onOrderPick">
|
||
<view class="filter-picker">{{ selectedOrderLabel || '点击选择匹配的订单' }}</view>
|
||
</picker>
|
||
<text v-if="orderId" class="filter-clear" @click="clearOrder">清除选择</text>
|
||
</view>
|
||
|
||
<view class="filter-query-btn" @click="reload">确认筛选</view>
|
||
</collapsible-filter-panel>
|
||
</page-sticky-header>
|
||
|
||
<!-- 统计卡片区:取消横向滑动,改为直观的网格平铺 -->
|
||
<view v-if="statItems.length" class="stats-grid-wrap">
|
||
<view class="stats-grid">
|
||
<view v-for="s in statItems" :key="s.key" class="stat-card">
|
||
<text class="stat-label">{{ s.label }}</text>
|
||
<text class="stat-value">{{ s.value }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 数据列表区 -->
|
||
<view class="list-wrap">
|
||
<view v-for="item in list" :key="item._wxKey" class="premium-card">
|
||
|
||
<!-- ================= 诊所对账模式 ================= -->
|
||
<template v-if="tab === 'store'">
|
||
<view class="card-head">
|
||
<text class="card-title">{{ rowStore(item).name }}</text>
|
||
<text v-if="rowStore(item).registrationPrice !== '¥0.00'" class="mini-tag">挂号费 {{ rowStore(item).registrationPrice }}</text>
|
||
</view>
|
||
|
||
<!-- 核心摘要 -->
|
||
<view class="hero-data">
|
||
<view class="data-box">
|
||
<text class="data-label">总销售额</text>
|
||
<text class="data-val text-primary">{{ rowStore(item).totalSales }}</text>
|
||
</view>
|
||
<view class="data-divider"></view>
|
||
<view class="data-box">
|
||
<text class="data-label">总供货额</text>
|
||
<text class="data-val">{{ rowStore(item).totalSupply }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 2x2 仪表盘网格:完美重构四大类费用 -->
|
||
<view class="dashboard-grid">
|
||
<!-- 草药 -->
|
||
<view class="dashboard-island">
|
||
<view class="island-head">
|
||
<text class="island-title">🌿 草药</text>
|
||
<text class="island-sales">销量 {{ rowStore(item).herbal.sales }}</text>
|
||
</view>
|
||
<view class="island-line"><text>销售</text><text>{{ rowStore(item).herbal.salesPrice }}</text></view>
|
||
<view class="island-line"><text>供货</text><text>{{ rowStore(item).herbal.supplyPrice }}</text></view>
|
||
</view>
|
||
<!-- 西药 -->
|
||
<view class="dashboard-island">
|
||
<view class="island-head">
|
||
<text class="island-title">💊 西药</text>
|
||
<text class="island-sales">销量 {{ rowStore(item).medicine.sales }}</text>
|
||
</view>
|
||
<view class="island-line"><text>销售</text><text>{{ rowStore(item).medicine.salesPrice }}</text></view>
|
||
<view class="island-line"><text>供货</text><text>{{ rowStore(item).medicine.supplyPrice }}</text></view>
|
||
</view>
|
||
<!-- 服务包 -->
|
||
<view class="dashboard-island">
|
||
<view class="island-head">
|
||
<text class="island-title">📦 服务包</text>
|
||
<text class="island-sales">销量 {{ rowStore(item).servicePackage.sales }}</text>
|
||
</view>
|
||
<view class="island-line"><text>销售</text><text>{{ rowStore(item).servicePackage.salesPrice }}</text></view>
|
||
<view class="island-line"><text>供货</text><text>{{ rowStore(item).servicePackage.supplyPrice }}</text></view>
|
||
</view>
|
||
<!-- 其他费用 -->
|
||
<view class="dashboard-island">
|
||
<view class="island-head">
|
||
<text class="island-title">🔖 其他费用</text>
|
||
</view>
|
||
<view class="island-line"><text>诊疗费</text><text>{{ rowStore(item).otherFees.treatment }}</text></view>
|
||
<view class="island-line"><text>加工费</text><text>{{ rowStore(item).otherFees.process }}</text></view>
|
||
<view class="island-line"><text>快递费</text><text>{{ rowStore(item).otherFees.express }}</text></view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<!-- ================= 药品对账模式 ================= -->
|
||
<template v-else>
|
||
<view class="card-head">
|
||
<text class="card-title">{{ rowDrug(item).drugName }}</text>
|
||
<view class="drug-meta" v-if="rowDrug(item).drugNumber">
|
||
<text class="mini-tag">编号 {{ rowDrug(item).drugNumber }}</text>
|
||
<text class="mini-tag gray">{{ rowDrug(item).typeText }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="info-island">
|
||
<view class="island-row">
|
||
<text class="island-label">销量</text>
|
||
<text class="island-value text-primary font-bold">{{ rowDrug(item).number }}</text>
|
||
</view>
|
||
<view class="island-row">
|
||
<text class="island-label">供货单价</text>
|
||
<text class="island-value">{{ rowDrug(item).marketPrice }}</text>
|
||
</view>
|
||
<view class="island-row">
|
||
<text class="island-label">总销售额</text>
|
||
<text class="island-value">{{ rowDrug(item).totalSales }}</text>
|
||
</view>
|
||
<view class="island-row">
|
||
<text class="island-label">总供货额</text>
|
||
<text class="island-value">{{ rowDrug(item).totalSupply }}</text>
|
||
</view>
|
||
<view class="island-row" v-if="rowDrug(item).orderNo">
|
||
<text class="island-label">订单号</text>
|
||
<text class="island-value font-mono">{{ rowDrug(item).orderNo }}</text>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="!loading && !list.length" class="empty-state">
|
||
<text>暂无对账数据</text>
|
||
</view>
|
||
</view>
|
||
</clinic-page-layout>
|
||
</template>
|
||
|
||
<script>
|
||
import ClinicPageLayout from '@/subPackages/sub_clinic_admin/components/clinic-page-layout.vue'
|
||
import PageStickyHeader from '@/subPackages/sub_clinic_admin/components/PageStickyHeader.vue'
|
||
import CollapsibleFilterPanel from '@/subPackages/sub_clinic_admin/components/CollapsibleFilterPanel.vue'
|
||
import {
|
||
getReconciliationList,
|
||
getReconciliationDrugList,
|
||
getReconciliationDrugOptions,
|
||
getReconciliationOrderOptions,
|
||
} from '@/api/clinicAdmin.js'
|
||
import { withWxKey } from '@/utils/wxListKey.js'
|
||
import {
|
||
mapReconciliationStoreRow,
|
||
mapReconciliationDrugRow,
|
||
mapReconciliationStoreCount,
|
||
mapReconciliationDrugCount,
|
||
} from '@/subPackages/sub_clinic_admin/common/display.js'
|
||
import {
|
||
buildStoreListParams,
|
||
buildDrugListParams,
|
||
buildSearchTimeQueryParams,
|
||
normalizeReconciliationResponse,
|
||
} from '@/subPackages/sub_clinic_admin/common/reconciliationParams.js'
|
||
import {
|
||
loadReconciliationFilter,
|
||
saveReconciliationFilter,
|
||
clearReconciliationFilter,
|
||
defaultReconciliationFilter,
|
||
} from '@/subPackages/sub_clinic_admin/common/filterCache.js'
|
||
|
||
export default {
|
||
components: { ClinicPageLayout, PageStickyHeader, CollapsibleFilterPanel },
|
||
data() {
|
||
return {
|
||
tab: 'store',
|
||
tabIndex: 0,
|
||
tabList: [{ name: '诊所对账' }, { name: '药品对账' }],
|
||
dateStart: '',
|
||
dateEnd: '',
|
||
list: [],
|
||
loading: false,
|
||
statItems: [],
|
||
byOrder: false,
|
||
drugSearchQ: '',
|
||
orderSearchQ: '',
|
||
drugOptions: [],
|
||
orderOptions: [],
|
||
drugId: null,
|
||
orderId: null,
|
||
selectedDrugLabel: '',
|
||
selectedOrderLabel: '',
|
||
}
|
||
},
|
||
computed: {
|
||
drugOptionLabels() {
|
||
return this.drugOptions.map(o => o.label)
|
||
},
|
||
orderOptionLabels() {
|
||
return this.orderOptions.map(o => o.label)
|
||
},
|
||
},
|
||
onLoad() {
|
||
this.applyReconciliationFilter(loadReconciliationFilter())
|
||
this.reload()
|
||
},
|
||
methods: {
|
||
applyReconciliationFilter(f) {
|
||
this.tabIndex = f.tabIndex
|
||
this.tab = f.tabIndex === 1 ? 'drug' : 'store'
|
||
this.dateStart = f.dateStart
|
||
this.dateEnd = f.dateEnd
|
||
this.byOrder = f.byOrder
|
||
this.drugSearchQ = f.drugSearchQ
|
||
this.orderSearchQ = f.orderSearchQ
|
||
this.drugId = f.drugId
|
||
this.orderId = f.orderId
|
||
this.selectedDrugLabel = f.selectedDrugLabel
|
||
this.selectedOrderLabel = f.selectedOrderLabel
|
||
this.drugOptions = []
|
||
this.orderOptions = []
|
||
},
|
||
persistReconciliationFilter() {
|
||
saveReconciliationFilter({
|
||
tabIndex: this.tabIndex,
|
||
dateStart: this.dateStart,
|
||
dateEnd: this.dateEnd,
|
||
byOrder: this.byOrder,
|
||
drugSearchQ: this.drugSearchQ,
|
||
orderSearchQ: this.orderSearchQ,
|
||
drugId: this.drugId,
|
||
orderId: this.orderId,
|
||
selectedDrugLabel: this.selectedDrugLabel,
|
||
selectedOrderLabel: this.selectedOrderLabel,
|
||
})
|
||
},
|
||
resetFilter() {
|
||
this.applyReconciliationFilter(defaultReconciliationFilter())
|
||
clearReconciliationFilter()
|
||
this.reload()
|
||
},
|
||
rowStore(item) {
|
||
return mapReconciliationStoreRow(item)
|
||
},
|
||
rowDrug(item) {
|
||
return mapReconciliationDrugRow(item)
|
||
},
|
||
onTabChange(index) {
|
||
this.tabIndex = index
|
||
this.tab = index === 0 ? 'store' : 'drug'
|
||
this.reload()
|
||
},
|
||
reload() {
|
||
this.persistReconciliationFilter()
|
||
this.load()
|
||
},
|
||
load() {
|
||
this.loading = true
|
||
const isDrug = this.tab === 'drug'
|
||
const api = isDrug ? getReconciliationDrugList : getReconciliationList
|
||
const params = isDrug
|
||
? buildDrugListParams({
|
||
dateStart: this.dateStart,
|
||
dateEnd: this.dateEnd,
|
||
drugId: this.drugId,
|
||
orderId: this.orderId,
|
||
byOrder: this.byOrder,
|
||
})
|
||
: buildStoreListParams({
|
||
dateStart: this.dateStart,
|
||
dateEnd: this.dateEnd,
|
||
excludeZeroSales: 0,
|
||
})
|
||
api(params).then(w => {
|
||
const { count, items } = normalizeReconciliationResponse(w.data)
|
||
this.statItems = isDrug
|
||
? mapReconciliationDrugCount(count)
|
||
: mapReconciliationStoreCount(count)
|
||
const keyField = isDrug ? 'drug_id' : 'id'
|
||
this.list = withWxKey(items, keyField, 'rec')
|
||
}).finally(() => { this.loading = false })
|
||
},
|
||
onStart(e) { this.dateStart = e.detail.value },
|
||
onEnd(e) { this.dateEnd = e.detail.value },
|
||
onByOrderChange(e) {
|
||
this.byOrder = !!e.detail.value
|
||
},
|
||
timeParams() {
|
||
return buildSearchTimeQueryParams(this.dateStart, this.dateEnd)
|
||
},
|
||
searchDrugOptions() {
|
||
if (!this.dateStart || !this.dateEnd) {
|
||
uni.showToast({ title: '请选择时间范围', icon: 'none' })
|
||
return
|
||
}
|
||
getReconciliationDrugOptions({
|
||
q: this.drugSearchQ,
|
||
limit: 20,
|
||
...this.timeParams(),
|
||
}).then(w => {
|
||
const items = (w.data && w.data.items) || []
|
||
this.drugOptions = items
|
||
if (!items.length) uni.showToast({ title: '无匹配药品', icon: 'none' })
|
||
})
|
||
},
|
||
searchOrderOptions() {
|
||
if (!this.dateStart || !this.dateEnd) {
|
||
uni.showToast({ title: '请选择时间范围', icon: 'none' })
|
||
return
|
||
}
|
||
getReconciliationOrderOptions({
|
||
q: this.orderSearchQ,
|
||
limit: 20,
|
||
...this.timeParams(),
|
||
}).then(w => {
|
||
const items = (w.data && w.data.items) || []
|
||
this.orderOptions = items
|
||
if (!items.length) uni.showToast({ title: '无匹配订单', icon: 'none' })
|
||
})
|
||
},
|
||
onDrugPick(e) {
|
||
const idx = Number(e.detail.value)
|
||
const opt = this.drugOptions[idx]
|
||
if (opt) {
|
||
this.drugId = opt.value
|
||
this.selectedDrugLabel = opt.label
|
||
}
|
||
},
|
||
onOrderPick(e) {
|
||
const idx = Number(e.detail.value)
|
||
const opt = this.orderOptions[idx]
|
||
if (opt) {
|
||
this.orderId = opt.value
|
||
this.selectedOrderLabel = opt.label
|
||
}
|
||
},
|
||
clearDrug() {
|
||
this.drugId = null
|
||
this.selectedDrugLabel = ''
|
||
this.drugOptions = []
|
||
},
|
||
clearOrder() {
|
||
this.orderId = null
|
||
this.selectedOrderLabel = ''
|
||
this.orderOptions = []
|
||
},
|
||
},
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
$theme-primary: #6acdbb;
|
||
$color-bg-base: #F5F7F8;
|
||
$color-text-main: #1D2129;
|
||
$color-text-body: #4E5969;
|
||
$color-text-muted: #86909C;
|
||
$color-border: #E5E6EB;
|
||
|
||
.reconciliation-container {
|
||
background-color: $color-bg-base;
|
||
min-height: 100vh;
|
||
padding-bottom: 60rpx;
|
||
}
|
||
|
||
/* 顶部吸顶区 */
|
||
.header-section {
|
||
background: #ffffff;
|
||
padding-bottom: 24rpx;
|
||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.02);
|
||
}
|
||
|
||
.tabs-wrap {
|
||
border-bottom: 1rpx solid $color-border;
|
||
}
|
||
|
||
.quick-filter {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 24rpx 32rpx 0;
|
||
}
|
||
|
||
.date-range-picker {
|
||
display: flex;
|
||
align-items: center;
|
||
background: #F7F8FA;
|
||
border-radius: 12rpx;
|
||
padding: 12rpx 24rpx;
|
||
flex: 1;
|
||
margin-right: 24rpx;
|
||
}
|
||
|
||
.date-text {
|
||
font-size: 26rpx;
|
||
color: $color-text-main;
|
||
font-weight: 500;
|
||
|
||
&.placeholder {
|
||
color: #BDBDBD;
|
||
font-weight: 400;
|
||
}
|
||
}
|
||
|
||
.sep {
|
||
color: $color-text-muted;
|
||
font-size: 24rpx;
|
||
margin: 0 16rpx;
|
||
}
|
||
|
||
.filter-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 20rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.btn-clear {
|
||
font-size: 26rpx;
|
||
color: $color-text-muted;
|
||
}
|
||
|
||
.btn-search {
|
||
font-size: 26rpx;
|
||
color: #fff;
|
||
background: $theme-primary;
|
||
padding: 10rpx 24rpx;
|
||
border-radius: 30rpx;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 药品筛选展开面板优化 */
|
||
.switch-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.filter-label-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.filter-label {
|
||
font-size: 28rpx;
|
||
color: $color-text-main;
|
||
font-weight: 500;
|
||
margin-bottom: 4rpx;
|
||
}
|
||
|
||
.filter-hint {
|
||
font-size: 22rpx;
|
||
color: $color-text-muted;
|
||
}
|
||
|
||
.filter-field {
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.search-input-group {
|
||
display: flex;
|
||
align-items: center;
|
||
background: #F7F8FA;
|
||
border-radius: 12rpx;
|
||
padding: 8rpx 8rpx 8rpx 24rpx;
|
||
margin-top: 12rpx;
|
||
}
|
||
|
||
.filter-input {
|
||
flex: 1;
|
||
font-size: 26rpx;
|
||
color: $color-text-main;
|
||
height: 60rpx;
|
||
}
|
||
|
||
.filter-link {
|
||
font-size: 26rpx;
|
||
color: $theme-primary;
|
||
padding: 12rpx 24rpx;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.picker-wrap {
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.filter-picker {
|
||
font-size: 26rpx;
|
||
color: $color-text-main;
|
||
padding: 20rpx 24rpx;
|
||
background: #F7F8FA;
|
||
border-radius: 12rpx;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.filter-clear {
|
||
font-size: 24rpx;
|
||
color: #F53F3F;
|
||
display: block;
|
||
text-align: right;
|
||
}
|
||
|
||
.filter-query-btn {
|
||
text-align: center;
|
||
padding: 24rpx;
|
||
background: $theme-primary;
|
||
color: #fff;
|
||
border-radius: 16rpx;
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
margin-top: 32rpx;
|
||
box-shadow: 0 8rpx 24rpx rgba(106, 205, 187, 0.2);
|
||
}
|
||
|
||
/* ================= 统计卡片平铺网格区 ================= */
|
||
.stats-grid-wrap {
|
||
padding: 24rpx 24rpx 8rpx; /* 控制和卡片之间的呼吸感 */
|
||
}
|
||
.stats-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr); /* 取消了scroll-x滚动,改成直接平铺两列 */
|
||
gap: 20rpx;
|
||
}
|
||
.stat-card {
|
||
background: #fff;
|
||
padding: 32rpx 24rpx;
|
||
border-radius: 20rpx;
|
||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.02);
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
}
|
||
.stat-label {
|
||
font-size: 24rpx;
|
||
color: $color-text-muted;
|
||
}
|
||
.stat-value {
|
||
font-size: 36rpx;
|
||
color: $color-text-main;
|
||
font-weight: 700;
|
||
margin-top: 12rpx;
|
||
font-family: DIN Alternate, monospace, sans-serif;
|
||
/* 添加截断处理防止极端数字导致错位 */
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
/* ================= 核心高级卡片 ================= */
|
||
.list-wrap {
|
||
padding: 0 24rpx;
|
||
}
|
||
|
||
.premium-card {
|
||
background: #ffffff;
|
||
border-radius: 24rpx;
|
||
padding: 32rpx;
|
||
margin-bottom: 24rpx;
|
||
border: 1rpx solid #E5E6EB;
|
||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.015);
|
||
}
|
||
|
||
.card-head {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.card-title {
|
||
font-size: 32rpx;
|
||
color: $color-text-main;
|
||
font-weight: 600;
|
||
flex: 1;
|
||
line-height: 1.4;
|
||
margin-right: 16rpx;
|
||
}
|
||
|
||
.mini-tag {
|
||
font-size: 20rpx;
|
||
padding: 4rpx 12rpx;
|
||
background: rgba(106, 205, 187, 0.1);
|
||
color: $theme-primary;
|
||
border-radius: 8rpx;
|
||
font-weight: 500;
|
||
white-space: nowrap;
|
||
|
||
&.gray {
|
||
background: #F2F3F5;
|
||
color: $color-text-body;
|
||
margin-left: 12rpx;
|
||
}
|
||
}
|
||
|
||
/* 诊所对账:核心摘要 */
|
||
.hero-data {
|
||
display: flex;
|
||
align-items: center;
|
||
background: #F8FBFB;
|
||
border-radius: 16rpx;
|
||
padding: 24rpx 32rpx;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.data-box {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.data-divider {
|
||
width: 2rpx;
|
||
height: 60rpx;
|
||
background: #EAEFEF;
|
||
margin: 0 32rpx;
|
||
}
|
||
|
||
.data-label {
|
||
font-size: 24rpx;
|
||
color: $color-text-muted;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.data-val {
|
||
font-size: 32rpx;
|
||
font-weight: 700;
|
||
color: $color-text-main;
|
||
font-family: DIN Alternate, monospace, sans-serif;
|
||
|
||
&.text-primary {
|
||
color: $theme-primary;
|
||
}
|
||
}
|
||
|
||
/* 诊所对账:2x2 仪表盘网格 */
|
||
.dashboard-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.dashboard-island {
|
||
background: #F7F8FA;
|
||
border-radius: 16rpx;
|
||
padding: 20rpx;
|
||
}
|
||
|
||
.island-head {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 16rpx;
|
||
padding-bottom: 12rpx;
|
||
border-bottom: 1rpx dashed #E5E6EB;
|
||
}
|
||
|
||
.island-title {
|
||
font-size: 26rpx;
|
||
font-weight: 600;
|
||
color: $color-text-main;
|
||
}
|
||
|
||
.island-sales {
|
||
font-size: 22rpx;
|
||
color: $theme-primary;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.island-line {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: 24rpx;
|
||
color: $color-text-body;
|
||
margin-bottom: 8rpx;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
text:last-child {
|
||
font-family: monospace, sans-serif;
|
||
color: $color-text-main;
|
||
}
|
||
}
|
||
|
||
/* 药品对账:通用信息岛 */
|
||
.drug-meta {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.info-island {
|
||
background: #F7F8FA;
|
||
border-radius: 16rpx;
|
||
padding: 24rpx;
|
||
}
|
||
|
||
.island-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: 26rpx;
|
||
margin-bottom: 16rpx;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.island-label {
|
||
color: $color-text-muted;
|
||
}
|
||
|
||
.island-value {
|
||
color: $color-text-main;
|
||
|
||
&.text-primary { color: $theme-primary; }
|
||
&.font-bold { font-weight: 600; font-size: 28rpx; }
|
||
&.font-mono { font-family: SF Pro Text, monospace, sans-serif; font-size: 24rpx; color: $color-text-muted; }
|
||
}
|
||
}
|
||
|
||
.empty-state {
|
||
text-align: center;
|
||
color: $color-text-muted;
|
||
padding: 120rpx 0;
|
||
font-size: 28rpx;
|
||
}
|
||
</style> |