2025-11-28 18:01:14 +08:00

161 lines
4.4 KiB
Vue
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.

<template>
<div class="dict-input-wrapper">
<!-- 字典选择弹窗 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="30vw" :close-on-click-modal="false" :draggable="true"
@close="handleDialogClose">
<el-input ref="inputRef" v-model="searchKey" placeholder="搜索(支持名称、编码、简拼)..." class="mb10" clearable
@clear="filterDictData" @input="filterDictData" />
<el-table :data="filteredDictData" height="300px" border @row-dblclick="selectItem" highlight-current-row>
<el-table-column prop="value" label="培养基代号" align="center" width="150" />
<el-table-column prop="label" label="培养基名称" align="center" show-overflow-tooltip />
<el-table-column prop="pinyin" label="简拼" align="center" width="150" /> <!-- 显示简拼便于调试 -->
</el-table>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue';
import { getbactmediumList } from '@/api/liswork/micro/index';
// @ts-ignore
import { getFirstLetter } from '@/utils/pinyin.js'; // 引入拼音处理工具
// 组件参数
const props = defineProps({
modelValue: { type: [String, Number], default: '' },
dictType: { type: String },
placeholder: { type: String, default: '请输入或双击选择' },
clearable: { type: Boolean, default: true },
disabled: { type: Boolean, default: false },
dialogTitle: { type: String, default: '选择字典项' },
tableKey: { type: Object, default: () => { } },
});
// 组件事件
const emit = defineEmits(['select']);
const dictData = ref([]); // 存储带简拼的字典数据
const filteredDictData = ref([]);
const isDictLoading = ref(false);
const dialogVisible = ref(false);
const searchKey = ref('');
// 加载字典数据(并添加简拼字段)
const loadDictData = async () => {
try {
isDictLoading.value = true;
const response = await getbactmediumList();
const rawData = response.data.map((item: any, index: number) => {
return {
value: item.mediumno || `未知编码_${index}`, // 确保value存在
label: item.mediumname || `未知名称_${index}`, // 确保label存在
};
});
// 为每个字典项添加简拼字段
dictData.value = (rawData || []).map((item: any) => ({
...item,
pinyin: getFirstLetter(item.label) // 新增pinyin字段存储简拼
}));
filteredDictData.value = [...dictData.value];
} catch (error) {
console.error(`加载${props.dictType}字典失败:`, error);
dictData.value = [];
filteredDictData.value = [];
} finally {
isDictLoading.value = false;
}
};
// 核心搜索逻辑(支持模糊搜索+简拼搜索)
const filterDictData = () => {
const key = searchKey.value.trim().toLowerCase();
if (!key) {
filteredDictData.value = [...dictData.value];
return;
}
filteredDictData.value = dictData.value.filter((item: any) => {
// 1. 模糊搜索:匹配label(名称)或value(编码)
const matchLabel = item.label.toLowerCase().includes(key);
const matchValue = String(item.value).toLowerCase().includes(key);
// 2. 简拼搜索:匹配首字母简拼
const matchPinyin = item.pinyin.toLowerCase().includes(key);
// 满足任一条件即匹配
return matchLabel || matchValue || matchPinyin;
});
};
const inputRef = ref()
// 关键修改:打开弹窗时重新加载数据
const openDictSelector = async () => {
if (props.disabled || isDictLoading.value) {
return;
}
// 打开弹窗前先加载数据(确保每次打开都是最新的)
await loadDictData();
// 数据加载完成后再显示弹窗
dialogVisible.value = true;
searchKey.value = '';
nextTick(() => {
setTimeout(() => {
inputRef.value.focus();
}, 100);
});
filterDictData();
};
// 选择字典项
const selectItem = (item: any) => {
emit('select', item);
dialogVisible.value = false;
};
const handleDialogClose = () => {
dialogVisible.value = false;
};
defineExpose({
openDictSelector, // 暴露打开弹窗的方法
// 可选:暴露其他可能需要的方法(如刷新字典数据)
loadDictData,
handleDialogClose
});
</script>
<style scoped>
/* 样式保持不变 */
.dict-input-wrapper {
position: relative;
}
.select-icon {
cursor: pointer;
color: #666;
margin-left: 5px;
}
.select-icon:hover {
color: #409eff;
}
:deep(.el-input__suffix) {
gap: 4px;
}
</style>