Browse Source

工具页面样式修改

mh
hanyuqing 3 months ago
parent
commit
d943150e59
  1. 370
      vue/src/system/GraphStyle.vue

370
vue/src/system/GraphStyle.vue

@ -15,14 +15,11 @@
<div
v-for="tag in ['疾病','药品','检查','症状','其他']"
:key="tag"
class="tag-item-wrapper"
class="tag-pill"
:class="{ 'is-active': activeTags === tag }"
@click="handleTagClick(tag)"
>
<span class="color-dot" :style="{
backgroundColor: getStaticColor(tag) ,
opacity: activeTags === tag ? 0.3 : 1 }"></span>
<span class="tag-label-text">{{ tag }}</span>
{{ tag }}
</div>
</div>
@ -71,7 +68,13 @@
<div class="form-group">
<label>尺寸:</label>
<input v-model.number="nodeSize" type="number" min="30" max="100"/>
<input
:value="nodeSize"
type="number"
placeholder="30-100"
@blur="validateNodeSize($event)"
@keyup.enter="$event.target.blur()"
/>
</div>
<div class="color-picker-item">
@ -90,7 +93,13 @@
<div class="form-group">
<label>边框尺寸:</label>
<input v-model.number="nodeLineWidth" type="number" min="1" max="5"/>
<input
:value="nodeLineWidth"
type="number"
placeholder="1-5"
@blur="validateNodeLineWidth($event)"
@keyup.enter="$event.target.blur()"
/>
</div>
</div>
@ -143,7 +152,13 @@
<div class="form-group">
<label>线粗细:</label>
<input v-model.number="edgeLineWidth" type="number" min="1" max="5"/>
<input
:value="edgeLineWidth"
type="number"
placeholder="1-5"
@blur="validateEdgeLineWidth($event)"
@keyup.enter="$event.target.blur()"
/>
</div>
<div class="color-picker-item">
@ -294,24 +309,16 @@ import {ElMessageBox, ElMessage} from 'element-plus';
import {markRaw} from 'vue';
const tagToLabelMap = {
'疾病': 'Disease', '症状': 'Symptom', '病因': 'Cause', '药品': 'Drug', '科室': 'Department', '检查': 'Check'
'疾病': 'Disease', '症状': 'Symptom', '病因': 'Cause', '药品': 'Drug', '科室': 'Department', '检查': 'Check','其他':'Other'
};
const INITIAL_FILL_MAP = {
'Disease': '#EF4444',
'Drug': '#91cc75',
'Symptom': '#fac858',
'Check': '#336eee',
'Cause': '#59d1d4',
'Department': '#59d1d4',
'Disease': '#EF4444', 'Drug': '#91cc75', 'Symptom': '#fac858', 'Check': '#336eee',
'Cause': '#59d1d4', 'Department': '#59d1d4', 'Other': '#59d1d4'
};
const INITIAL_STROKE_MAP = {
'Disease': '#B91C1C',
'Drug': '#047857',
'Symptom': '#B45309',
'Check': '#1D4ED8',
'Cause': '#40999b',
'Department': '#40999b',
'Disease': '#B91C1C', 'Drug': '#047857', 'Symptom': '#B45309', 'Check': '#1D4ED8',
'Cause': '#40999b', 'Department': '#40999b', 'Other': '#40999b'
};
export default {
@ -319,7 +326,7 @@ export default {
components: {Menu},
data() {
return {
activeTags: '',
activeTags: '疾病',
styleGroups: [],
existingGroups: [],
activeCollapseNames: [],
@ -336,6 +343,7 @@ export default {
'Department': this.getInitialTagParams('Department'),
'DiseaseSite': this.getInitialTagParams('DiseaseSite'),
'Check': this.getInitialTagParams('Check'),
'Other': this.getInitialTagParams('Other'),
},
nodeShowLabel: true,
nodeFontFamily: 'Microsoft YaHei, sans-serif',
@ -353,7 +361,7 @@ export default {
edgeFontColor: '#666666',
edgeType: 'line',
edgeLineWidth: 2,
edgeStroke: '#b6b2b2',
edgeStroke: '#EF4444', //
defaultData: {
nodes: [
{id: "node1", data: {name: "霍乱", label: "Disease"}},
@ -384,13 +392,34 @@ export default {
}
},
watch: {
//
checkedGroupIds(newGroupIds) {
//
this.styleGroups.forEach(group => {
const isGroupChecked = newGroupIds.includes(group.id);
const childIds = group.configs.map(c => c.id);
if (isGroupChecked) {
// ID checkedConfigIds ()
this.checkedConfigIds = Array.from(new Set([...this.checkedConfigIds, ...childIds]));
} else {
// ID checkedConfigIds
this.checkedConfigIds = this.checkedConfigIds.filter(id => !childIds.includes(id));
}
});
},
// 线
nodeFill(newVal) {
this.edgeStroke = newVal;
},
nodeShowLabel: 'syncAndRefresh', nodeFontFamily: 'syncAndRefresh', nodeFontSize: 'syncAndRefresh',
nodeFontColor: 'syncAndRefresh', nodeShape: 'syncAndRefresh', nodeSize: 'syncAndRefresh',
nodeFill: 'syncAndRefresh', nodeStroke: 'syncAndRefresh', nodeLineWidth: 'syncAndRefresh',
nodeStroke: 'syncAndRefresh', nodeLineWidth: 'syncAndRefresh',
edgeShowLabel: 'syncAndRefresh', edgeEndArrow: 'syncAndRefresh', edgeFontFamily: 'syncAndRefresh',
edgeFontSize: 'syncAndRefresh', edgeFontColor: 'syncAndRefresh', edgeType: 'syncAndRefresh',
edgeLineWidth: 'syncAndRefresh', edgeStroke: 'syncAndRefresh'
},
created() {
this._graph = null;
this._nodeLabelMap = new Map();
@ -412,21 +441,47 @@ export default {
window.removeEventListener('resize', this.handleResize);
},
methods: {
getStaticColor(tag) {
const label = tagToLabelMap[tag];
if (label === 'Disease') return '#EF4444';
if (label === 'Drug') return '#91cc75';
if (label === 'Symptom') return '#fac858';
if (label === 'Check') return '#336eee';
return '#59d1d4';
validateNodeSize(event) {
const inputVal = event.target.value;
const val = parseInt(inputVal);
if (isNaN(val) || val < 30 || val > 100) {
ElMessage({ message: `节点尺寸请输入 30 到 100 之间的数字`, type: 'warning', duration: 1500 });
event.target.value = this.nodeSize;
return;
}
this.nodeSize = val;
this.syncAndRefresh();
},
validateNodeLineWidth(event) {
const inputVal = event.target.value;
const val = parseInt(inputVal);
if (isNaN(val) || val < 1 || val > 5) {
ElMessage({ message: `边框尺寸请输入 1 到 5 之间的数字`, type: 'warning', duration: 1500 });
event.target.value = this.nodeLineWidth;
return;
}
this.nodeLineWidth = val;
this.syncAndRefresh();
},
validateEdgeLineWidth(event) {
const inputVal = event.target.value;
const val = parseInt(inputVal);
if (isNaN(val) || val < 1 || val > 5) {
ElMessage({ message: `线条粗细请输入 1 到 5 之间的数字`, type: 'warning', duration: 1500 });
event.target.value = this.edgeLineWidth;
return;
}
this.edgeLineWidth = val;
this.syncAndRefresh();
},
getInitialTagParams(label) {
const fill = INITIAL_FILL_MAP[label] || '#59d1d4';
return {
nodeShowLabel: true, nodeFontFamily: 'Microsoft YaHei, sans-serif', nodeFontSize: 12, nodeFontColor: '#ffffff',
nodeShape: 'circle', nodeSize: 60, nodeFill: INITIAL_FILL_MAP[label] || '#59d1d4',
nodeShape: 'circle', nodeSize: 60, nodeFill: fill,
nodeStroke: INITIAL_STROKE_MAP[label] || '#40999b', nodeLineWidth: 2, edgeShowLabel: true, edgeEndArrow: true,
edgeFontFamily: 'Microsoft YaHei, sans-serif', edgeFontSize: 10, edgeFontColor: '#666666', edgeType: 'line',
edgeLineWidth: 2, edgeStroke: '#b6b2b2'
edgeLineWidth: 2, edgeStroke: fill // 线
};
},
handleTagClick(tag) {
@ -474,6 +529,14 @@ export default {
}
});
});
const hexToRgba = (hex, opacity) => {
if (!hex) return 'rgba(182, 178, 178, 0.5)';
if (hex.startsWith('rgba')) return hex;
let r = parseInt(hex.slice(1, 3), 16), g = parseInt(hex.slice(3, 5), 16), b = parseInt(hex.slice(5, 7), 16);
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
};
const nodes = this.defaultData.nodes.map(node => {
const labelEn = node.data?.label || '';
const s = labelToAppliedConfigMap[labelEn] || this.tagStyles[labelEn];
@ -488,35 +551,32 @@ export default {
}
};
});
let edgeS = this;
if (this.usingConfigIds.length > 0) {
const lastAppliedId = this.usingConfigIds[this.usingConfigIds.length - 1];
this.styleGroups.forEach(g => {
const found = g.configs.find(c => c.id === lastAppliedId);
if (found) edgeS = found.styles;
});
}
const hexToRgba = (hex, opacity) => {
if (!hex) return 'rgba(182, 178, 178, 0.5)';
let r = parseInt(hex.slice(1, 3), 16), g = parseInt(hex.slice(3, 5), 16), b = parseInt(hex.slice(5, 7), 16);
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
};
const edges = this.defaultData.edges.map(edge => {
const s = edgeS;
const sLabel = this._nodeLabelMap.get(edge.source);
const sourceNodeStyles = labelToAppliedConfigMap[sLabel] || this.tagStyles[sLabel];
const dynamicStroke = hexToRgba(sourceNodeStyles?.nodeFill, 0.5);
//
const s = labelToAppliedConfigMap[sLabel] || this.tagStyles[sLabel] || this;
// 线 edgeStroke
const strokeColor = hexToRgba(s.edgeStroke, 0.6);
return {
...edge, type: s.edgeType || 'line',
style: {
stroke: dynamicStroke, lineWidth: this.safeNum(s.edgeLineWidth, 2), endArrow: s.edgeEndArrow,
stroke: strokeColor,
lineWidth: this.safeNum(s.edgeLineWidth, 2),
endArrow: s.edgeEndArrow,
labelText: s.edgeShowLabel ? (edge.data?.relationship?.properties?.label || '') : '',
labelFill: s.edgeFontColor || '#666', labelFontSize: this.safeNum(s.edgeFontSize, 10),
labelFontFamily: s.edgeFontFamily || 'Microsoft YaHei', labelBackground: true,
labelBackgroundFill: '#fff', labelBackgroundOpacity: 0.7
labelFill: s.edgeFontColor || '#666',
labelFontSize: this.safeNum(s.edgeFontSize, 10),
labelFontFamily: s.edgeFontFamily || 'Microsoft YaHei',
labelBackground: true,
labelBackgroundFill: '#fff',
labelBackgroundOpacity: 0.7
}
};
});
this._graph.setData({nodes, edges});
this._graph.render();
},
@ -533,7 +593,6 @@ export default {
...conf, styles: typeof conf.styles === 'string' ? JSON.parse(conf.styles) : conf.styles
}))
}));
if (this.styleGroups.length > 0 && this.activeCollapseNames.length === 0) this.activeCollapseNames = [this.styleGroups[0].id];
}
} catch (err) {
console.error("加载配置失败:", err);
@ -583,7 +642,9 @@ export default {
},
handleSaveClick() {
this.fetchGroupNames();
this.saveForm.canvas_name = `样式_${new Date().toLocaleTimeString([], {hour: '2-digit', minute: '2-digit'})}`;
// 使 Date.now() 13
this.saveForm.canvas_name = Date.now().toString();
this.saveDialogVisible = true;
},
async confirmSave() {
@ -615,8 +676,7 @@ export default {
this.fetchConfigs();
this.updateAllElements();
}
} catch (err) {
}
} catch (err) {}
},
async deleteGroup(groupId) {
try {
@ -626,19 +686,27 @@ export default {
this.fetchConfigs();
this.updateAllElements();
}
} catch (err) {
}
} catch (err) {}
},
async handleUnifiedBatchDelete() {
try {
await ElMessageBox.confirm(`确定执行批量删除吗?`);
await ElMessageBox.confirm(
'确定执行批量删除吗?',
'批量删除', //
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
//
distinguishCancelAndClose: true,
}
);
for (const gid of this.checkedGroupIds) await deleteGraphStyleGroup(gid);
if (this.checkedConfigIds.length > 0) await batchDeleteGraphStyle({ids: this.checkedConfigIds});
this.clearSelection();
this.fetchConfigs();
this.updateAllElements();
} catch (e) {
}
} catch (e) {}
},
clearSelection() {
this.checkedConfigIds = [];
@ -652,6 +720,44 @@ export default {
</script>
<style scoped>
/* 精准控制“应用全案”按钮 */
.group-header-slot .el-button--primary.is-plain {
background-color: #1559f3 !important;
color: #ffffff !important;
border: none !important;
font-weight: bold;
}
.group-header-slot .el-button--primary.is-plain:hover {
opacity: 0.8;
background-color: #1559f3 !important;
color: #ffffff !important;
}
/* 精准控制弹窗中的“确定保存”按钮 */
.el-dialog__footer .el-button--primary {
background-color: #1559f3 !important;
border-color: #1559f3 !important;
color: #ffffff !important;
font-weight: bold;
}
.el-dialog__footer .el-button--primary:hover {
opacity: 0.8;
background-color: #1559f3 !important;
border-color: #1559f3 !important;
}
.control-panel::-webkit-scrollbar {
display: none !important;
}
.control-panel {
scrollbar-width: none !important; /* Firefox */
-ms-overflow-style: none !important; /* IE */
}
.knowledge-graph-container {
display: flex;
height: 100vh;
@ -660,10 +766,10 @@ export default {
}
.control-panel {
width: 300px;
width: 260px;
background: #ffffff;
border-right: 1px solid #e2e8f0;
padding: 20px;
padding: 10px;
display: flex;
flex-direction: column;
overflow-y: auto;
@ -704,44 +810,41 @@ export default {
color: #1157f3;
}
/* --- 修改后的标签过滤样式 --- */
.tag-filters {
display: flex;
flex-wrap: nowrap;
gap: 5px;
margin: 0 0 10px 0;
min-height: 40px;
overflow-x: auto;
gap: 6px;
margin-bottom: 10px;
padding-bottom: 10px;
}
.tag-item-wrapper {
display: flex;
align-items: center;
cursor: pointer;
transition: all 0.2s;
padding: 0 0;
border-radius: 4px;
.tag-pill {
flex-shrink: 0;
padding: 0 10px;
border-radius: 20px;
font-size: 12px;
font-weight: bold;
color: #ffffff;
background-color: #959390;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
user-select: none;
border: 1px solid transparent;
display: inline-flex;
align-items: center;
justify-content: center;
}
.tag-item-wrapper .color-dot {
width: 20px;
height: 10px;
border-radius: 6px;
margin-right: 4px;
opacity: 0.5;
}
/* 将文字样式改为常驻加粗 */
.tag-item-wrapper .tag-label-text {
font-size: 14px;
color: #111;
font-weight: bold;
.tag-pill:hover {
filter: brightness(1.1);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}
/* 仅控制圆点的透明度/阴影 */
.tag-item-wrapper.is-active .color-dot {
opacity: 1;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
.tag-pill.is-active {
background-color: #4a68db; /* 选中颜色 */
transform: translateY(-1px);
box-shadow: 0 4px 10px rgba(74, 104, 219, 0.3);
}
.section {
@ -815,19 +918,50 @@ export default {
flex: 1;
display: flex;
align-items: center;
gap: 10px;
gap: 12px;
}
/* 滑块轨道样式 */
.theme-slider {
flex: 1;
accent-color: #1559f3;
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 6px;
background: #dde5f3;
border-radius: 10px;
outline: none;
}
/* 中间的小圆点样式 */
.theme-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 14px;
height: 14px;
background: #1559f3;
border-radius: 50%;
cursor: pointer;
border: none;
box-shadow: none;
}
/* 中间的小圆点样式 */
.theme-slider::-moz-range-thumb {
width: 14px;
height: 14px;
background: #1559f3;
border-radius: 50%;
cursor: pointer;
border: none;
box-shadow: none;
}
/* 右侧数值样式 */
.val-text-black {
color: #000;
font-weight: bold;
font-size: 13px;
min-width: 35px;
font-size: 12px;
}
.color-picker-border {
@ -1059,4 +1193,46 @@ export default {
:deep(.el-collapse-item__header) {
padding: 0 10px;
}
</style>
/* 统一修改所有弹窗和消息框的标题与取消按钮 */
:deep(.el-dialog__title),
:deep(.el-message-box__title) {
color: #000000 !important;
font-weight: 600 !important;
}
:deep(.el-dialog__header),
:deep(.el-message-box__header) {
text-align: left !important;
}
:deep(.el-dialog__footer .el-button:first-child),
:deep(.el-message-box__btns .el-button:first-child) {
background-color: #e6e6e6 !important;
border-color: #e6e6e6 !important;
color: #333 !important;
}
:deep(.el-message-box__btns .el-button--primary) {
background-color: #1559f3 !important;
border-color: #1559f3 !important;
}
</style>
<style>
.el-message-box__header {
text-align: left !important;
padding-top: 15px !important;
}
.el-message-box__title {
color: #000000 !important;
font-weight: 500 !important;
font-size: 18px !important;
}
/* 之前讨论过的按钮颜色也请确保保留在此 */
.el-message-box__btns .el-button--primary {
background-color: #1559f3 !important;
border-color: #1559f3 !important;
}
</style>

Loading…
Cancel
Save