This commit is contained in:
Ranyunqiao
2026-06-24 16:16:51 +08:00
parent 74cf599ea7
commit 2ba26594e3
5 changed files with 347 additions and 28 deletions

View File

@@ -0,0 +1,9 @@
-- Initialize update_time for all TCM syndromes to a default past timestamp so they don't sort before active ones in nulls-first ORDER BY
UPDATE cli_condition_definition
SET update_time = '2000-01-01 00:00:00'
WHERE source_enum = 6;
-- Set update_time for the 8 core TCM syndromes so that they sort at the top of the list
UPDATE cli_condition_definition
SET update_time = CURRENT_TIMESTAMP
WHERE source_enum = 6 AND name IN ('阴证', '阳证', '寒证', '热证', '虚证', '实证', '闭证', '脱证');

View File

@@ -1,4 +1,4 @@
<template> <template>
<el-dialog <el-dialog
v-model="dialogVisible" v-model="dialogVisible"
:title="isUpdateMode ? '修改中医诊断' : '添加中医诊断'" :title="isUpdateMode ? '修改中医诊断' : '添加中医诊断'"
@@ -227,7 +227,7 @@ function handleClickRow(row) {
selectedDisease.value = true; selectedDisease.value = true;
syndromeSelected.value = false; syndromeSelected.value = false;
timestamp.value = Date.now(); timestamp.value = Date.now();
getTcmSyndrome().then((res) => { getTcmSyndrome({ pageSize: 3000 }).then((res) => {
syndromeList.value = res.data.records; syndromeList.value = res.data.records;
}); });
tcmDiagonsisSaveList.value.push({ tcmDiagonsisSaveList.value.push({

View File

@@ -40,20 +40,18 @@
label="中医证候" label="中医证候"
prop="syndromeCode" prop="syndromeCode"
> >
<el-select <el-cascader
ref="cascaderRef"
v-model="formData.syndromeCode" v-model="formData.syndromeCode"
:options="getGroupedSyndromeOptions(syndromeOptions)"
:props="{ emitPath: false, checkStrictly: true }"
:show-all-levels="false"
placeholder="请选择中医证候" placeholder="请选择中医证候"
filterable filterable
clearable clearable
style="width: 100%" style="width: 100%"
> @change="handleSyndromeCodeChange"
<el-option />
v-for="item in syndromeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
@@ -83,6 +81,7 @@ const { proxy } = getCurrentInstance()
const conditionOptions = ref([]) const conditionOptions = ref([])
const syndromeOptions = ref([]) const syndromeOptions = ref([])
const cascaderRef = ref(null)
const formData = ref({ const formData = ref({
conditionCode: '', conditionCode: '',
@@ -129,7 +128,7 @@ function loadConditionOptions() {
} }
function loadSyndromeOptions(conditionCode) { function loadSyndromeOptions(conditionCode) {
const params = conditionCode ? { conditionCode } : {} const params = conditionCode ? { conditionCode, pageSize: 3000 } : { pageSize: 3000 }
getTcmSyndrome(params).then((res) => { getTcmSyndrome(params).then((res) => {
if (res.data && res.data.records) { if (res.data && res.data.records) {
syndromeOptions.value = res.data.records.map((item) => ({ syndromeOptions.value = res.data.records.map((item) => ({
@@ -177,6 +176,154 @@ const openAct = () => {
loadConditionOptions() loadConditionOptions()
loadSyndromeOptions() loadSyndromeOptions()
} }
function getGroupedSyndromeOptions(options) {
if (!options || !options.length) return []
const seen = new Set()
const uniqueOptions = []
options.forEach(item => {
if (!seen.has(item.label)) {
seen.add(item.label)
uniqueOptions.push(item)
}
})
const nameToItems = {}
uniqueOptions.forEach(item => {
const name = item.label
if (!nameToItems[name]) {
nameToItems[name] = []
}
nameToItems[name].push(item)
})
// Level 3 Children of 阴证 (寒证, 虚证)
const childrenOfYin = []
;['寒证', '虚证'].forEach(name => {
if (nameToItems[name]) {
childrenOfYin.push(...nameToItems[name])
}
})
// Level 3 Children of 阳证 (热证, 实证)
const childrenOfYang = []
;['热证', '实证'].forEach(name => {
if (nameToItems[name]) {
childrenOfYang.push(...nameToItems[name])
}
})
// Level 2 under 八纲总纲 (阴证, 阳证)
const level2OfBagang = []
if (nameToItems['阴证']) {
nameToItems['阴证'].forEach(item => {
level2OfBagang.push({
value: item.value,
label: item.label,
id: item.id,
children: childrenOfYin.length ? childrenOfYin : undefined
})
})
} else if (childrenOfYin.length > 0) {
level2OfBagang.push({
value: 'virtual-yin',
label: '阴证',
children: childrenOfYin
})
}
if (nameToItems['阳证']) {
nameToItems['阳证'].forEach(item => {
level2OfBagang.push({
value: item.value,
label: item.label,
id: item.id,
children: childrenOfYang.length ? childrenOfYang : undefined
})
})
} else if (childrenOfYang.length > 0) {
level2OfBagang.push({
value: 'virtual-yang',
label: '阳证',
children: childrenOfYang
})
}
// Level 2 under 危重急症 (闭证, 脱证)
const level2OfWeizhong = []
;['闭证', '脱证'].forEach(name => {
if (nameToItems[name]) {
level2OfWeizhong.push(...nameToItems[name])
}
})
// Level 2 under 其他证候 (all other syndromes)
const level2OfOther = []
const specialNames = new Set(['阴证', '阳证', '寒证', '热证', '虚证', '实证', '闭证', '脱证'])
options.forEach(item => {
if (!specialNames.has(item.label)) {
level2OfOther.push(item)
}
})
const finalTree = []
if (level2OfBagang.length > 0) {
finalTree.push({
value: 'root-bagang',
label: '八纲总纲',
children: level2OfBagang
})
}
if (level2OfWeizhong.length > 0) {
finalTree.push({
value: 'root-weizhong',
label: '危重急症',
children: level2OfWeizhong
})
}
if (level2OfOther.length > 0) {
finalTree.push({
value: 'root-other',
label: '其他证候',
children: level2OfOther
})
}
return finalTree
}
function handleSyndromeCodeChange(val) {
console.log('handleSyndromeCodeChange called with:', val)
if (val === 'root-bagang' || val === 'root-weizhong' || val === 'root-other' || (typeof val === 'string' && val.startsWith('virtual-'))) {
formData.value.syndromeCode = ''
} else if (val) {
if (cascaderRef.value) {
console.log('Cascader Ref component instance:', cascaderRef.value)
if (typeof cascaderRef.value.togglePopperVisible === 'function') {
cascaderRef.value.togglePopperVisible(false)
}
if (typeof cascaderRef.value.toggleDropDownVisible === 'function') {
cascaderRef.value.toggleDropDownVisible(false)
}
cascaderRef.value.popperVisible = false
if (typeof cascaderRef.value.blur === 'function') {
cascaderRef.value.blur()
}
}
if (document.activeElement && typeof document.activeElement.blur === 'function') {
console.log('Blurring active element:', document.activeElement)
document.activeElement.blur()
}
setTimeout(() => {
document.body.click()
}, 50)
}
}
const closedAct = () => { const closedAct = () => {
emit('update:visible', false) emit('update:visible', false)
} }

View File

@@ -268,22 +268,19 @@
:prop="`diagnosisList.${scope.rowIndex}.tcmSyndromeCode`" :prop="`diagnosisList.${scope.rowIndex}.tcmSyndromeCode`"
:rules="scope.row.diagnosisSystem === '中医' ? [{ required: true, message: '请选择中医证候', trigger: 'change' }] : []" :rules="scope.row.diagnosisSystem === '中医' ? [{ required: true, message: '请选择中医证候', trigger: 'change' }] : []"
> >
<el-select <el-cascader
:ref="el => setCascaderRef(el, scope.rowIndex)"
v-model="scope.row.tcmSyndromeCode" v-model="scope.row.tcmSyndromeCode"
:options="getGroupedSyndromeOptions(scope.row.syndromeOptions)"
:props="{ emitPath: false, checkStrictly: true }"
:show-all-levels="false"
placeholder="请选择中医证候" placeholder="请选择中医证候"
filterable filterable
clearable clearable
style="width: 100%" style="width: 100%"
@focus="loadSyndromeOptions(scope.row)" @focus="loadSyndromeOptions(scope.row)"
@change="(val) => handleSyndromeSelect(val, scope.row)" @change="(val) => handleSyndromeSelect(val, scope.row, scope.rowIndex)"
> />
<el-option
v-for="item in (scope.row.syndromeOptions || [])"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item> </el-form-item>
</template> </template>
<el-form-item v-else> <el-form-item v-else>
@@ -419,6 +416,12 @@ const rowIndex = ref();
const diagnosis = ref(); const diagnosis = ref();
const orgOrUser = ref(); const orgOrUser = ref();
const syndromeOptions = ref([]); const syndromeOptions = ref([]);
const cascaderRefs = ref({});
const setCascaderRef = (el, index) => {
if (el) {
cascaderRefs.value[index] = el;
}
};
const form = ref({ const form = ref({
diagnosisList: [], diagnosisList: [],
}); });
@@ -832,8 +835,11 @@ function handleDiagnosisSystemChange(row) {
// 加载中医证候选项(按诊断名称关联过滤) // 加载中医证候选项(按诊断名称关联过滤)
function loadSyndromeOptions(row) { function loadSyndromeOptions(row) {
if (row.syndromeOptions && row.syndromeOptions.length) {
return;
}
const conditionCode = row.ybNo; const conditionCode = row.ybNo;
const params = conditionCode ? { conditionCode } : {}; const params = conditionCode ? { conditionCode, pageSize: 3000 } : { pageSize: 3000 };
getTcmSyndrome(params).then((res) => { getTcmSyndrome(params).then((res) => {
if (res.data && res.data.records) { if (res.data && res.data.records) {
row.syndromeOptions = res.data.records.map((item) => ({ row.syndromeOptions = res.data.records.map((item) => ({
@@ -848,11 +854,43 @@ function loadSyndromeOptions(row) {
} }
// 中医证候选中赋值 // 中医证候选中赋值
function handleSyndromeSelect(val, row) { function handleSyndromeSelect(val, row, rowIndex) {
console.log('handleSyndromeSelect called with:', val, 'rowIndex:', rowIndex);
if (val) { if (val) {
if (val === 'root-bagang' || val === 'root-weizhong' || val === 'root-other' || (typeof val === 'string' && val.startsWith('virtual-'))) {
row.tcmSyndromeCode = '';
row.tcmSyndromeName = '';
row.syndromeDefinitionId = '';
return;
}
const selected = (row.syndromeOptions || []).find((item) => item.value === val); const selected = (row.syndromeOptions || []).find((item) => item.value === val);
row.tcmSyndromeName = selected ? selected.label : ''; row.tcmSyndromeName = selected ? selected.label : '';
row.syndromeDefinitionId = selected ? selected.id : ''; row.syndromeDefinitionId = selected ? selected.id : '';
// Close the cascader dropdown programmatically
if (rowIndex !== undefined && cascaderRefs.value[rowIndex]) {
const refEl = cascaderRefs.value[rowIndex];
console.log('Cascader Ref component instance:', refEl);
if (refEl) {
if (typeof refEl.togglePopperVisible === 'function') {
refEl.togglePopperVisible(false);
}
if (typeof refEl.toggleDropDownVisible === 'function') {
refEl.toggleDropDownVisible(false);
}
refEl.popperVisible = false;
if (typeof refEl.blur === 'function') {
refEl.blur();
}
}
}
if (document.activeElement && typeof document.activeElement.blur === 'function') {
console.log('Blurring active element:', document.activeElement);
document.activeElement.blur();
}
setTimeout(() => {
document.body.click();
}, 50);
} else { } else {
row.tcmSyndromeName = ''; row.tcmSyndromeName = '';
row.syndromeDefinitionId = ''; row.syndromeDefinitionId = '';
@@ -1120,9 +1158,14 @@ function handleChange(value) {
*/ */
function handleSelsectDiagnosis(row) { function handleSelsectDiagnosis(row) {
console.log(row); console.log(row);
form.value.diagnosisList[rowIndex.value].ybNo = row.ybNo; const targetRow = form.value.diagnosisList[rowIndex.value];
form.value.diagnosisList[rowIndex.value].name = row.name; targetRow.ybNo = row.ybNo;
form.value.diagnosisList[rowIndex.value].definitionId = row.id; targetRow.name = row.name;
targetRow.definitionId = row.id;
targetRow.syndromeOptions = [];
targetRow.tcmSyndromeCode = '';
targetRow.tcmSyndromeName = '';
targetRow.syndromeDefinitionId = '';
} }
/**获取焦点时 打开列表 */ /**获取焦点时 打开列表 */
function handleFocus(row, index) { function handleFocus(row, index) {
@@ -1189,6 +1232,126 @@ function handleNodeClick(data) {
} }
} }
function getGroupedSyndromeOptions(options) {
if (!options || !options.length) return [];
const seen = new Set();
const uniqueOptions = [];
options.forEach(item => {
if (!seen.has(item.label)) {
seen.add(item.label);
uniqueOptions.push(item);
}
});
const nameToItems = {};
uniqueOptions.forEach(item => {
const name = item.label;
if (!nameToItems[name]) {
nameToItems[name] = [];
}
nameToItems[name].push(item);
});
// Level 3 Children of 阴证 (寒证, 虚证)
const childrenOfYin = [];
['寒证', '虚证'].forEach(name => {
if (nameToItems[name]) {
childrenOfYin.push(...nameToItems[name]);
}
});
// Level 3 Children of 阳证 (热证, 实证)
const childrenOfYang = [];
['热证', '实证'].forEach(name => {
if (nameToItems[name]) {
childrenOfYang.push(...nameToItems[name]);
}
});
// Level 2 under 八纲总纲 (阴证, 阳证)
const level2OfBagang = [];
if (nameToItems['阴证']) {
nameToItems['阴证'].forEach(item => {
level2OfBagang.push({
value: item.value,
label: item.label,
id: item.id,
children: childrenOfYin.length ? childrenOfYin : undefined
});
});
} else if (childrenOfYin.length > 0) {
level2OfBagang.push({
value: 'virtual-yin',
label: '阴证',
children: childrenOfYin
});
}
if (nameToItems['阳证']) {
nameToItems['阳证'].forEach(item => {
level2OfBagang.push({
value: item.value,
label: item.label,
id: item.id,
children: childrenOfYang.length ? childrenOfYang : undefined
});
});
} else if (childrenOfYang.length > 0) {
level2OfBagang.push({
value: 'virtual-yang',
label: '阳证',
children: childrenOfYang
});
}
// Level 2 under 危重急症 (闭证, 脱证)
const level2OfWeizhong = [];
['闭证', '脱证'].forEach(name => {
if (nameToItems[name]) {
level2OfWeizhong.push(...nameToItems[name]);
}
});
// Level 2 under 其他证候 (all other syndromes)
const level2OfOther = [];
const specialNames = new Set(['阴证', '阳证', '寒证', '热证', '虚证', '实证', '闭证', '脱证']);
options.forEach(item => {
if (!specialNames.has(item.label)) {
level2OfOther.push(item);
}
});
const finalTree = [];
if (level2OfBagang.length > 0) {
finalTree.push({
value: 'root-bagang',
label: '八纲总纲',
children: level2OfBagang
});
}
if (level2OfWeizhong.length > 0) {
finalTree.push({
value: 'root-weizhong',
label: '危重急症',
children: level2OfWeizhong
});
}
if (level2OfOther.length > 0) {
finalTree.push({
value: 'root-other',
label: '其他证候',
children: level2OfOther
});
}
return finalTree;
}
defineExpose({ getList, getDetail, handleSaveDiagnosis }); defineExpose({ getList, getDetail, handleSaveDiagnosis });
</script> </script>

View File

@@ -444,7 +444,7 @@ function handleTcmSyndromeClick(row, index) {
function handleSyndromeSearch() {} function handleSyndromeSearch() {}
function loadSyndromeList() { function loadSyndromeList() {
getTcmSyndrome().then((res) => { getTcmSyndrome({ pageSize: 3000 }).then((res) => {
if (res.data && res.data.records) { if (res.data && res.data.records) {
syndromeList.value = res.data.records syndromeList.value = res.data.records
} }