feat: 药品别名
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
/**
|
||||
* 中药药名气泡选择器
|
||||
* - 对齐诊断/医嘱 EntryKeywordBubble:Input 聚焦弹出 Teleport 浮层
|
||||
* - 远程搜索药品(getProductListDoctorReception),拼音/名称高亮
|
||||
* - 远程搜索药品(getProductListDoctorReception),支持药名/别名/首拼/全拼/数字
|
||||
* - 列表展示拼音列;命中别名时展示匹配别名及其拼音
|
||||
* - 选中后回传完整商品行,供接诊/复诊/特色方/常用方复用现有落库逻辑
|
||||
*/
|
||||
import {
|
||||
@@ -65,11 +66,11 @@ const emit = defineEmits<{
|
||||
select: [item: ChineseDrugBubbleItem];
|
||||
}>();
|
||||
|
||||
const ROW_HEIGHT = 44;
|
||||
const ROW_HEIGHT = 48;
|
||||
const HINT_HEIGHT = 34;
|
||||
const HEAD_HEIGHT = 32;
|
||||
const PANEL_PAD = 8;
|
||||
const PREFERRED_PANEL = 320;
|
||||
const PREFERRED_PANEL = 360;
|
||||
|
||||
const containerRef = ref<HTMLElement | null>(null);
|
||||
const panelRef = ref<HTMLElement | null>(null);
|
||||
@@ -127,6 +128,31 @@ function drugNameOf(item: ChineseDrugBubbleItem): string {
|
||||
return String(item?.drug?.drug_name || item?.drug_name || '').trim();
|
||||
}
|
||||
|
||||
/** 关键词命中的别名(后端 matched_alias) */
|
||||
function matchedAliasOf(item: ChineseDrugBubbleItem): string {
|
||||
return String(
|
||||
item?.matched_alias || item?.drug?.matched_alias || '',
|
||||
).trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼音展示:命中别名时用别名拼音,否则用药名首拼(全拼)
|
||||
*/
|
||||
function pinyinLabelOf(item: ChineseDrugBubbleItem): string {
|
||||
const aliasPy = String(
|
||||
item?.matched_alias_pinyin || item?.drug?.matched_alias_pinyin || '',
|
||||
).trim();
|
||||
if (matchedAliasOf(item) && aliasPy) return aliasPy;
|
||||
const display = String(item?.drug?.pinyin_display || '').trim();
|
||||
if (display) return display;
|
||||
const simple = String(item?.drug?.pinyin_simple || '').trim();
|
||||
const full = String(item?.drug?.pinyin_full || '').trim();
|
||||
if (simple && full && simple.toLowerCase() !== full.toLowerCase()) {
|
||||
return `${simple}(${full})`;
|
||||
}
|
||||
return simple || full || '-';
|
||||
}
|
||||
|
||||
function unitLabelOf(item: ChineseDrugBubbleItem): string {
|
||||
const unit = item?.drug?.unit || item?.unit;
|
||||
if (typeof unit === 'object' && unit?.name) return String(unit.name);
|
||||
@@ -155,7 +181,8 @@ function updatePanelPlacement() {
|
||||
const panelMax = Math.min(PREFERRED_PANEL, avail);
|
||||
listViewportH.value = Math.max(80, panelMax - HINT_HEIGHT - HEAD_HEIGHT);
|
||||
|
||||
const PANEL_MIN_WIDTH = 420;
|
||||
// 含拼音列后加宽,避免别名/全拼被裁切
|
||||
const PANEL_MIN_WIDTH = 560;
|
||||
const width = Math.min(
|
||||
Math.max(rect.width, PANEL_MIN_WIDTH),
|
||||
vw - PANEL_PAD * 2,
|
||||
@@ -228,9 +255,13 @@ async function fetchDrugs(kw: string) {
|
||||
(it) => drugNameOf(it),
|
||||
(it) =>
|
||||
[
|
||||
it.drug?.pinyin,
|
||||
it.drug?.pinyin_simple,
|
||||
it.drug?.pinyin_full,
|
||||
it.drug?.initials_of_pinyin,
|
||||
it.drug?.pinyin_display,
|
||||
it.drug?.drug_alias,
|
||||
it.matched_alias || it.drug?.matched_alias,
|
||||
it.matched_alias_pinyin || it.drug?.matched_alias_pinyin,
|
||||
it.drug?.search_digits,
|
||||
it.drug?.specification,
|
||||
]
|
||||
.map((v) => String(v || ''))
|
||||
@@ -440,7 +471,9 @@ defineExpose({
|
||||
v-if="!loading && options.length === 0"
|
||||
:image="Empty.PRESENTED_IMAGE_SIMPLE"
|
||||
:description="
|
||||
keyword.trim() ? '未找到匹配药材' : '请输入药名/拼音搜索'
|
||||
keyword.trim()
|
||||
? '未找到匹配药材'
|
||||
: '请输入药名/别名/拼音/数字搜索'
|
||||
"
|
||||
class="py-4"
|
||||
/>
|
||||
@@ -450,6 +483,7 @@ defineExpose({
|
||||
:class="{ 'has-score': !!keyword.trim() }"
|
||||
>
|
||||
<span class="col-name">药名</span>
|
||||
<span class="col-py">拼音</span>
|
||||
<span class="col-spec">规格/单位</span>
|
||||
<span class="col-price">价格</span>
|
||||
<span v-if="keyword.trim()" class="col-score">匹配度</span>
|
||||
@@ -480,13 +514,47 @@ defineExpose({
|
||||
@mousedown.prevent="selectItem(item)"
|
||||
@mouseenter="highlightIndex = index"
|
||||
>
|
||||
<span class="col-name" :title="drugNameOf(item)">
|
||||
<template
|
||||
v-for="(p, pi) in partsOf(drugNameOf(item))"
|
||||
:key="`n_${pi}`"
|
||||
<span
|
||||
class="col-name"
|
||||
:title="
|
||||
matchedAliasOf(item)
|
||||
? `${drugNameOf(item)}(别名:${matchedAliasOf(item)})`
|
||||
: drugNameOf(item)
|
||||
"
|
||||
>
|
||||
<span class="col-name__main">
|
||||
<template
|
||||
v-for="(p, pi) in partsOf(drugNameOf(item))"
|
||||
:key="`n_${pi}`"
|
||||
>
|
||||
<em v-if="p.hit" class="hit">{{ p.text }}</em>
|
||||
<template v-else>{{ p.text }}</template>
|
||||
</template>
|
||||
</span>
|
||||
<span
|
||||
v-if="matchedAliasOf(item)"
|
||||
class="col-name__alias"
|
||||
>
|
||||
<em v-if="p.hit" class="hit">{{ p.text }}</em>
|
||||
<template v-else>{{ p.text }}</template>
|
||||
别名:
|
||||
<template
|
||||
v-for="(p, pi) in partsOf(matchedAliasOf(item))"
|
||||
:key="`a_${pi}`"
|
||||
>
|
||||
<em v-if="p.hit" class="hit">{{ p.text }}</em>
|
||||
<template v-else>{{ p.text }}</template>
|
||||
</template>
|
||||
</span>
|
||||
</span>
|
||||
<span class="col-py" :title="pinyinLabelOf(item)">
|
||||
<template v-if="pinyinLabelOf(item) === '-'">-</template>
|
||||
<template v-else>
|
||||
<template
|
||||
v-for="(p, pi) in partsOf(pinyinLabelOf(item))"
|
||||
:key="`py_${pi}`"
|
||||
>
|
||||
<em v-if="p.hit" class="hit">{{ p.text }}</em>
|
||||
<template v-else>{{ p.text }}</template>
|
||||
</template>
|
||||
</template>
|
||||
</span>
|
||||
<span class="col-spec" :title="unitLabelOf(item)">
|
||||
@@ -589,7 +657,7 @@ defineExpose({
|
||||
.chinese-drug-name-bubble__head,
|
||||
.chinese-drug-name-bubble__row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 100px 72px;
|
||||
grid-template-columns: minmax(90px, 1.1fr) minmax(110px, 1.3fr) 90px 64px;
|
||||
gap: 8px;
|
||||
padding: 6px 12px;
|
||||
font-size: 13px;
|
||||
@@ -598,7 +666,7 @@ defineExpose({
|
||||
}
|
||||
.chinese-drug-name-bubble__head.has-score,
|
||||
.chinese-drug-name-bubble__row.has-score {
|
||||
grid-template-columns: 1fr 90px 64px 48px;
|
||||
grid-template-columns: minmax(90px, 1.1fr) minmax(100px, 1.2fr) 80px 56px 48px;
|
||||
}
|
||||
.chinese-drug-name-bubble__head {
|
||||
flex-shrink: 0;
|
||||
@@ -617,13 +685,37 @@ defineExpose({
|
||||
color: hsl(var(--accent-foreground));
|
||||
}
|
||||
.col-name,
|
||||
.col-py,
|
||||
.col-spec {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.col-name {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1px;
|
||||
min-width: 0;
|
||||
font-weight: 500;
|
||||
white-space: normal;
|
||||
line-height: 1.25;
|
||||
}
|
||||
.col-name__main {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.col-name__alias {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
.col-py {
|
||||
font-size: 12px;
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
.col-spec {
|
||||
font-size: 12px;
|
||||
@@ -641,7 +733,9 @@ defineExpose({
|
||||
color: #d4380d;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.chinese-drug-name-bubble__row.is-active .col-spec {
|
||||
.chinese-drug-name-bubble__row.is-active .col-spec,
|
||||
.chinese-drug-name-bubble__row.is-active .col-py,
|
||||
.chinese-drug-name-bubble__row.is-active .col-name__alias {
|
||||
color: inherit;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,10 @@ export interface WarehouseDrugItem {
|
||||
id: number;
|
||||
drug_name: string;
|
||||
pinyin_simple?: string;
|
||||
/** 关键词命中的别名(后端 matched_alias) */
|
||||
matched_alias?: string;
|
||||
/** 命中别名对应拼音展示 */
|
||||
matched_alias_pinyin?: string;
|
||||
specification?: string;
|
||||
image?: string;
|
||||
type?: number;
|
||||
@@ -212,8 +216,27 @@ watch(
|
||||
<div v-else class="warehouse-drug-item__img-placeholder">无图</div>
|
||||
</div>
|
||||
<div class="warehouse-drug-item__info">
|
||||
<div class="warehouse-drug-item__name">{{ item.drug_name }}</div>
|
||||
<div
|
||||
class="warehouse-drug-item__name"
|
||||
:title="
|
||||
item.matched_alias
|
||||
? `${item.drug_name}(别名:${item.matched_alias})`
|
||||
: item.drug_name
|
||||
"
|
||||
>
|
||||
{{ item.drug_name }}
|
||||
</div>
|
||||
<!-- 与开方气泡一致:命中别名时展示别名及拼音 -->
|
||||
<div v-if="item.matched_alias" class="warehouse-drug-item__alias">
|
||||
别名:{{ item.matched_alias }}
|
||||
<span v-if="item.matched_alias_pinyin">
|
||||
({{ item.matched_alias_pinyin }})
|
||||
</span>
|
||||
</div>
|
||||
<div class="warehouse-drug-item__meta">
|
||||
<span v-if="item.pinyin_simple && !item.matched_alias" class="warehouse-drug-item__py">
|
||||
拼音:{{ item.pinyin_simple }}
|
||||
</span>
|
||||
<span v-if="item.specification" class="warehouse-drug-item__spec">
|
||||
规格:{{ item.specification }}
|
||||
</span>
|
||||
@@ -321,7 +344,17 @@ watch(
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
&__alias {
|
||||
font-size: 12px;
|
||||
color: #8c8c8c;
|
||||
line-height: 1.3;
|
||||
margin-bottom: 4px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&__meta {
|
||||
@@ -332,6 +365,10 @@ watch(
|
||||
color: #999;
|
||||
}
|
||||
|
||||
&__py {
|
||||
color: #8c8c8c;
|
||||
}
|
||||
|
||||
&__spec {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user