|
|
@@ -6,6 +6,8 @@
|
|
|
<button @click="resetView" class="tool-btn">重置视图</button>
|
|
|
<button @click="zoomIn" class="tool-btn">放大</button>
|
|
|
<button @click="zoomOut" class="tool-btn">缩小</button>
|
|
|
+ <button @click="toggleOverdueCompoHighlight" class="tool-btn tool-btn-danger" :disabled="overdueLoading">{{ overdueLoading ? '查询中...' : (overdueActive ? `清除超期(${overdueCompoNames.length})` : '超期部件') }}</button>
|
|
|
+ <button @click="toggleDueSoonCompoHighlight" class="tool-btn tool-btn-warning" :disabled="dueSoonLoading">{{ dueSoonLoading ? '查询中...' : (dueSoonActive ? `清除即将到期(${dueSoonCompoNames.length})` : '即将到期') }}</button>
|
|
|
</div>
|
|
|
<span v-if="hoverShape && hoverShape.name" class="hover-name">{{ hoverShape.name }}</span>
|
|
|
</div>
|
|
|
@@ -71,6 +73,7 @@
|
|
|
<script>
|
|
|
import VueDraggableResizable from 'vue-draggable-resizable'
|
|
|
import 'vue-draggable-resizable/dist/VueDraggableResizable.css'
|
|
|
+ import { listDueSoonCompos, listOverdueCompos } from '@/api/reliability/rel_device'
|
|
|
|
|
|
export default {
|
|
|
name: 'ProcessDiagram',
|
|
|
@@ -94,6 +97,14 @@
|
|
|
scale: 1,
|
|
|
// 当前悬停的形状(只保留name用于tooltip显示)
|
|
|
hoverShape: null,
|
|
|
+ // 延期(逾期)部件高亮相关(延期计算在后端,前端只负责高亮展示)
|
|
|
+ overdueActive: false,
|
|
|
+ overdueCompoNames: [],
|
|
|
+ overdueLoading: false,
|
|
|
+ // 即将到期部件高亮相关(“周期最后20%以内 & 但不能延期”在后端计算;前端只负责高亮展示)
|
|
|
+ dueSoonActive: false,
|
|
|
+ dueSoonCompoNames: [],
|
|
|
+ dueSoonLoading: false,
|
|
|
// SVG 文件映射
|
|
|
svgMap: {
|
|
|
'224U': require('@/assets/visio/224U.svg'),
|
|
|
@@ -131,12 +142,121 @@
|
|
|
}
|
|
|
return photoPath;
|
|
|
},
|
|
|
+
|
|
|
+ // 点击按钮:查询即将到期部件并高亮(再次点击则清除高亮)
|
|
|
+ toggleDueSoonCompoHighlight() {
|
|
|
+ // 正在请求时禁止重复触发
|
|
|
+ if (this.dueSoonLoading) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (this.dueSoonActive) {
|
|
|
+ this.clearDueSoonCompoHighlight();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.fetchAndHighlightDueSoonCompos();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 从后端查询“即将到期部件”(20%阈值与“但不能延期”在后端计算),并在 SVG 上做黄色闪烁高亮
|
|
|
+ async fetchAndHighlightDueSoonCompos() {
|
|
|
+ const devTag = this.selectedDevice && this.selectedDevice.devTag ? this.selectedDevice.devTag : '';
|
|
|
+ if (!devTag) {
|
|
|
+ this.$message && this.$message.warning('缺少设备位号(devTag),无法查询即将到期部件');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.dueSoonLoading = true;
|
|
|
+ try {
|
|
|
+ const res = await listDueSoonCompos(devTag);
|
|
|
+ const dueSoonNames = (res && res.data) ? res.data : [];
|
|
|
+
|
|
|
+ // 每次查询前先清理旧的即将到期样式(避免后端结果变化导致残留)
|
|
|
+ this.clearDueSoonCompoHighlight();
|
|
|
+
|
|
|
+ this.dueSoonCompoNames = Array.isArray(dueSoonNames) ? dueSoonNames : [];
|
|
|
+ if (!this.dueSoonCompoNames.length) {
|
|
|
+ this.$message && this.$message.success('未发现即将到期部件');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.dueSoonActive = true;
|
|
|
+ this.applyDueSoonHighlightByNames(this.dueSoonCompoNames);
|
|
|
+ this.$message && this.$message.success(`已高亮即将到期部件:${this.dueSoonCompoNames.length} 个`);
|
|
|
+ } catch (e) {
|
|
|
+ this.$message && this.$message.error('查询即将到期部件失败');
|
|
|
+ } finally {
|
|
|
+ this.dueSoonLoading = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 按“部件名称列表”高亮 SVG 中同名(去掉 .xxx 后缀后匹配)的元素(黄色)
|
|
|
+ applyDueSoonHighlightByNames(dueSoonNames) {
|
|
|
+ if (!dueSoonNames || !dueSoonNames.length) return;
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const svgDoc = this.$refs.svgObject?.contentDocument;
|
|
|
+ if (!svgDoc) return;
|
|
|
+
|
|
|
+ const groups = svgDoc.querySelectorAll('g[id]');
|
|
|
+ const dueSoonSet = new Set(dueSoonNames);
|
|
|
+
|
|
|
+ groups.forEach((g) => {
|
|
|
+ const cleanName = this.getCleanGroupTitle(g);
|
|
|
+ if (!cleanName) return;
|
|
|
+ if (!dueSoonSet.has(cleanName)) return;
|
|
|
+
|
|
|
+ const innerPath = g.querySelector('path, line, rect, circle, polygon');
|
|
|
+ if (!innerPath) return;
|
|
|
+
|
|
|
+ if (!innerPath.getAttribute('data-orig-stroke')) {
|
|
|
+ this.saveOriginalStyles(innerPath);
|
|
|
+ }
|
|
|
+ this.addTransitionEffect(innerPath);
|
|
|
+ this.applyDueSoonEffect(innerPath);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 清除即将到期部件高亮
|
|
|
+ clearDueSoonCompoHighlight() {
|
|
|
+ this.dueSoonActive = false;
|
|
|
+ this.dueSoonCompoNames = [];
|
|
|
+ const svgDoc = this.$refs.svgObject?.contentDocument;
|
|
|
+ if (!svgDoc) return;
|
|
|
+ const flashingEls = svgDoc.querySelectorAll('.due-soon-flash');
|
|
|
+ flashingEls.forEach((el) => {
|
|
|
+ this.clearDueSoonEffect(el);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 应用即将到期黄色闪烁效果
|
|
|
+ applyDueSoonEffect(element) {
|
|
|
+ if (!element) return;
|
|
|
+ element.classList.add('due-soon-flash');
|
|
|
+ element.style.stroke = '#f59e0b';
|
|
|
+ element.style.strokeWidth = '4px';
|
|
|
+ element.style.filter = 'drop-shadow(0 0 6px #f59e0b)';
|
|
|
+ },
|
|
|
+
|
|
|
+ // 清除即将到期效果:若仍处于选中状态,则恢复选中样式;否则恢复原始样式
|
|
|
+ clearDueSoonEffect(element) {
|
|
|
+ if (!element) return;
|
|
|
+ element.classList.remove('due-soon-flash');
|
|
|
+ if (element.classList.contains('selected')) {
|
|
|
+ this.applySelectedEffect(element);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ element.style.opacity = '';
|
|
|
+ element.style.stroke = element.getAttribute('data-orig-stroke') || '';
|
|
|
+ element.style.strokeWidth = element.getAttribute('data-orig-stroke-width') || '';
|
|
|
+ element.style.filter = '';
|
|
|
+ },
|
|
|
// 初始化 SVG
|
|
|
initSvg() {
|
|
|
this.loading = false;
|
|
|
const svgDoc = this.$refs.svgObject.contentDocument;
|
|
|
if (!svgDoc) return;
|
|
|
|
|
|
+ // 注入延期闪烁动画样式(只注入一次)
|
|
|
+ this.injectOverdueFlashStyle(svgDoc);
|
|
|
+
|
|
|
// 所有带 id 的元素(Visio 的管线、设备组)
|
|
|
const groups = svgDoc.querySelectorAll("g[id]");
|
|
|
|
|
|
@@ -290,8 +410,13 @@
|
|
|
|
|
|
// 应用悬停效果
|
|
|
applyHoverEffect(element) {
|
|
|
+ if (!element) return;
|
|
|
// 如果元素已被选中,不应用悬停效果
|
|
|
if (element.classList.contains('selected')) return;
|
|
|
+ // 如果元素正在进行“延期闪烁高亮”,不叠加悬停样式,避免覆盖红色效果
|
|
|
+ if (element.classList.contains('overdue-flash')) return;
|
|
|
+ // 如果元素正在进行“即将到期闪烁高亮”,不叠加悬停样式,避免覆盖黄色效果
|
|
|
+ if (element.classList.contains('due-soon-flash')) return;
|
|
|
|
|
|
const tagName = element.tagName.toLowerCase();
|
|
|
const origStroke = element.getAttribute("data-orig-stroke") || "#000";
|
|
|
@@ -313,14 +438,171 @@
|
|
|
clearHoverEffect(element) {
|
|
|
// 如果元素已被选中,不清除选中样式
|
|
|
if (element.classList.contains('selected')) return;
|
|
|
+ // 如果元素正在进行“延期闪烁高亮”,不清除红色效果
|
|
|
+ if (element.classList.contains('overdue-flash')) return;
|
|
|
+ // 如果元素正在进行“即将到期闪烁高亮”,不清除黄色效果
|
|
|
+ if (element.classList.contains('due-soon-flash')) return;
|
|
|
|
|
|
element.style.stroke = element.getAttribute("data-orig-stroke") || "";
|
|
|
element.style.strokeWidth = element.getAttribute("data-orig-stroke-width") || "";
|
|
|
element.style.filter = "";
|
|
|
},
|
|
|
|
|
|
+ // 仅向 SVG 文档注入一次延期闪烁动画样式(避免 scoped 样式无法作用到 object 内部的 SVG)
|
|
|
+ injectOverdueFlashStyle(svgDoc) {
|
|
|
+ if (!svgDoc) return;
|
|
|
+ if (svgDoc.getElementById('overdue-flash-style')) return;
|
|
|
+ const styleEl = svgDoc.createElement('style');
|
|
|
+ styleEl.setAttribute('id', 'overdue-flash-style');
|
|
|
+ styleEl.textContent = `
|
|
|
+ @keyframes overdueFlashOpacity {
|
|
|
+ 0% { opacity: 1; }
|
|
|
+ 50% { opacity: 0.35; }
|
|
|
+ 100% { opacity: 1; }
|
|
|
+ }
|
|
|
+ .overdue-flash {
|
|
|
+ animation: overdueFlashOpacity 0.9s infinite;
|
|
|
+ }
|
|
|
+ .due-soon-flash {
|
|
|
+ animation: overdueFlashOpacity 0.9s infinite;
|
|
|
+ }
|
|
|
+ `;
|
|
|
+ // 放在 svg 根节点下,确保样式在 SVG 内部可用
|
|
|
+ (svgDoc.documentElement || svgDoc).appendChild(styleEl);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 点击按钮:查询延期部件并高亮(再次点击则清除高亮)
|
|
|
+ toggleOverdueCompoHighlight() {
|
|
|
+ // 正在请求时禁止重复触发
|
|
|
+ if (this.overdueLoading) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 已经处于高亮状态:点击则清除(需要“刷新”时可以先清除再点一次)
|
|
|
+ if (this.overdueActive) {
|
|
|
+ this.clearOverdueCompoHighlight();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.fetchAndHighlightOverdueCompos();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 从后端查询“延期部件”(延期计算在后端,前端只负责高亮展示),并在 SVG 上做红色闪烁高亮
|
|
|
+ async fetchAndHighlightOverdueCompos() {
|
|
|
+ const devTag = this.selectedDevice && this.selectedDevice.devTag ? this.selectedDevice.devTag : '';
|
|
|
+ if (!devTag) {
|
|
|
+ this.$message && this.$message.warning('缺少设备位号(devTag),无法查询延期部件');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.overdueLoading = true;
|
|
|
+ try {
|
|
|
+ const res = await listOverdueCompos(devTag);
|
|
|
+ const overdueNames = (res && res.data) ? res.data : [];
|
|
|
+
|
|
|
+ // 每次查询前先清理旧的延期样式(避免后端结果变化导致残留)
|
|
|
+ this.clearOverdueCompoHighlight();
|
|
|
+
|
|
|
+ this.overdueCompoNames = Array.isArray(overdueNames) ? overdueNames : [];
|
|
|
+ if (!this.overdueCompoNames.length) {
|
|
|
+ this.$message && this.$message.success('未发现超期部件');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.overdueActive = true;
|
|
|
+ this.applyOverdueHighlightByNames(this.overdueCompoNames);
|
|
|
+ this.$message && this.$message.success(`已高亮超期部件:${this.overdueCompoNames.length} 个`);
|
|
|
+ } catch (e) {
|
|
|
+ this.$message && this.$message.error('查询超期部件失败');
|
|
|
+ } finally {
|
|
|
+ this.overdueLoading = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 按“部件名称列表”高亮 SVG 中同名(去掉 .xxx 后缀后匹配)的元素
|
|
|
+ applyOverdueHighlightByNames(overdueNames) {
|
|
|
+ if (!overdueNames || !overdueNames.length) return;
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const svgDoc = this.$refs.svgObject?.contentDocument;
|
|
|
+ if (!svgDoc) return;
|
|
|
+
|
|
|
+ const groups = svgDoc.querySelectorAll('g[id]');
|
|
|
+ const overdueSet = new Set(overdueNames);
|
|
|
+
|
|
|
+ groups.forEach((g) => {
|
|
|
+ const cleanName = this.getCleanGroupTitle(g);
|
|
|
+ if (!cleanName) return;
|
|
|
+ if (!overdueSet.has(cleanName)) return;
|
|
|
+
|
|
|
+ const innerPath = g.querySelector('path, line, rect, circle, polygon');
|
|
|
+ if (!innerPath) return;
|
|
|
+
|
|
|
+ if (!innerPath.getAttribute('data-orig-stroke')) {
|
|
|
+ this.saveOriginalStyles(innerPath);
|
|
|
+ }
|
|
|
+ this.addTransitionEffect(innerPath);
|
|
|
+ this.applyOverdueEffect(innerPath);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 清除延期部件高亮
|
|
|
+ clearOverdueCompoHighlight() {
|
|
|
+ this.overdueActive = false;
|
|
|
+ this.overdueCompoNames = [];
|
|
|
+ const svgDoc = this.$refs.svgObject?.contentDocument;
|
|
|
+ if (!svgDoc) return;
|
|
|
+
|
|
|
+ // 仅清除延期样式,选中样式(selected)保持不变
|
|
|
+ const flashingEls = svgDoc.querySelectorAll('.overdue-flash');
|
|
|
+ flashingEls.forEach((el) => {
|
|
|
+ this.clearOverdueEffect(el);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 应用延期闪烁红色效果(参考 hover 的“匹配高亮”思路,但采用红色闪烁)
|
|
|
+ applyOverdueEffect(element) {
|
|
|
+ if (!element) return;
|
|
|
+ element.classList.add('overdue-flash');
|
|
|
+ element.style.stroke = '#ff0000';
|
|
|
+ element.style.strokeWidth = '4px';
|
|
|
+ element.style.filter = 'drop-shadow(0 0 6px #ff0000)';
|
|
|
+ },
|
|
|
+
|
|
|
+ // 清除延期效果:若仍处于选中状态,则恢复选中样式;否则恢复原始样式
|
|
|
+ clearOverdueEffect(element) {
|
|
|
+ if (!element) return;
|
|
|
+ element.classList.remove('overdue-flash');
|
|
|
+ if (element.classList.contains('selected')) {
|
|
|
+ this.applySelectedEffect(element);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ element.style.opacity = '';
|
|
|
+ element.style.stroke = element.getAttribute('data-orig-stroke') || '';
|
|
|
+ element.style.strokeWidth = element.getAttribute('data-orig-stroke-width') || '';
|
|
|
+ element.style.filter = '';
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取 SVG 组的 title(去掉 .xxx 后缀)
|
|
|
+ getCleanGroupTitle(group) {
|
|
|
+ const title = group && group.querySelector ? group.querySelector('title')?.textContent : null;
|
|
|
+ if (!title) return null;
|
|
|
+ return title.replace(/\.[^.]+$/, '');
|
|
|
+ },
|
|
|
+
|
|
|
// 应用选中效果
|
|
|
applySelectedEffect(element) {
|
|
|
+ // 如果当前元素已经处于“延期闪烁高亮”,则不覆盖为蓝色选中;保持红色闪烁提示
|
|
|
+ if (element && element.classList && element.classList.contains('overdue-flash')) {
|
|
|
+ this.applyOverdueEffect(element);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 如果当前元素已经处于“即将到期闪烁高亮”,则不覆盖为蓝色选中;保持黄色闪烁提示
|
|
|
+ if (element && element.classList && element.classList.contains('due-soon-flash')) {
|
|
|
+ this.applyDueSoonEffect(element);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
// 使用您提供的高亮样式
|
|
|
element.style.stroke = "#007bff"; // 高亮蓝色
|
|
|
element.style.strokeWidth = "4px";
|
|
|
@@ -329,6 +611,17 @@
|
|
|
|
|
|
// 清除选中效果
|
|
|
clearSelectedEffect(element) {
|
|
|
+ // 如果元素仍处于“延期闪烁高亮”,则恢复延期样式,不恢复原始样式
|
|
|
+ if (element && element.classList && element.classList.contains('overdue-flash')) {
|
|
|
+ this.applyOverdueEffect(element);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 如果元素仍处于“即将到期闪烁高亮”,则恢复即将到期样式,不恢复原始样式
|
|
|
+ if (element && element.classList && element.classList.contains('due-soon-flash')) {
|
|
|
+ this.applyDueSoonEffect(element);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
// 使用您提供的清除逻辑
|
|
|
element.style.stroke = element.getAttribute("data-orig-stroke") || "";
|
|
|
element.style.strokeWidth = element.getAttribute("data-orig-stroke-width") || "";
|
|
|
@@ -391,6 +684,14 @@
|
|
|
// 监听选中设备变化
|
|
|
selectedDevice: {
|
|
|
handler(newDevice) {
|
|
|
+ // 切换设备时,清理上一台设备的“延期闪烁高亮”状态
|
|
|
+ if (this.overdueActive) {
|
|
|
+ this.clearOverdueCompoHighlight();
|
|
|
+ }
|
|
|
+ // 切换设备时,清理上一台设备的“即将到期闪烁高亮”状态
|
|
|
+ if (this.dueSoonActive) {
|
|
|
+ this.clearDueSoonCompoHighlight();
|
|
|
+ }
|
|
|
if (newDevice && newDevice.devTag) {
|
|
|
this.highlightDevice(newDevice.devTag);
|
|
|
} else if (newDevice && newDevice.devName) {
|
|
|
@@ -419,56 +720,77 @@
|
|
|
|
|
|
<style scoped>
|
|
|
.svg-page {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- height: 100vh;
|
|
|
- background: #f6f8fa;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: 100vh;
|
|
|
+ background: #f6f8fa;
|
|
|
}
|
|
|
|
|
|
/* 工具栏样式 */
|
|
|
.toolbar {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- padding: 10px 20px;
|
|
|
- background: #ffffff;
|
|
|
- border-bottom: 1px solid #e5e7eb;
|
|
|
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 10px 20px;
|
|
|
+ background: #ffffff;
|
|
|
+ border-bottom: 1px solid #e5e7eb;
|
|
|
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
|
}
|
|
|
|
|
|
.toolbar-left {
|
|
|
- display: flex;
|
|
|
- gap: 10px;
|
|
|
+ display: flex;
|
|
|
+ gap: 10px;
|
|
|
}
|
|
|
|
|
|
.hover-name {
|
|
|
- font-size: 14px;
|
|
|
- font-weight: 500;
|
|
|
- color: #3b82f6;
|
|
|
- background: #eff6ff;
|
|
|
- padding: 6px 12px;
|
|
|
- border-radius: 4px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #3b82f6;
|
|
|
+ background: #eff6ff;
|
|
|
+ padding: 6px 12px;
|
|
|
+ border-radius: 4px;
|
|
|
}
|
|
|
|
|
|
.tool-btn {
|
|
|
- padding: 8px 16px;
|
|
|
- background: #3b82f6;
|
|
|
- color: white;
|
|
|
- border: none;
|
|
|
- border-radius: 6px;
|
|
|
- cursor: pointer;
|
|
|
- font-size: 14px;
|
|
|
- transition: background-color 0.2s;
|
|
|
+ padding: 8px 16px;
|
|
|
+ background: #3b82f6;
|
|
|
+ color: white;
|
|
|
+ border: none;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 14px;
|
|
|
+ transition: background-color 0.2s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .tool-btn:disabled {
|
|
|
+ opacity: 0.6;
|
|
|
+ cursor: not-allowed;
|
|
|
+ }
|
|
|
+
|
|
|
+ .tool-btn-danger {
|
|
|
+ background: #ef4444;
|
|
|
+ }
|
|
|
+
|
|
|
+ .tool-btn-danger:hover {
|
|
|
+ background: #dc2626;
|
|
|
+ }
|
|
|
+
|
|
|
+ .tool-btn-warning {
|
|
|
+ background: #f59e0b;
|
|
|
}
|
|
|
|
|
|
- .tool-btn:hover {
|
|
|
- background: #2563eb;
|
|
|
+ .tool-btn-warning:hover {
|
|
|
+ background: #d97706;
|
|
|
+ }
|
|
|
+
|
|
|
+ .tool-btn:not(.tool-btn-danger):not(.tool-btn-warning):hover {
|
|
|
+ background: #2563eb;
|
|
|
}
|
|
|
|
|
|
/* 主内容区域 */
|
|
|
.svg-page > div:not(.toolbar) {
|
|
|
- display: flex;
|
|
|
- flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex: 1;
|
|
|
}
|
|
|
|
|
|
.svg-container {
|