提交 f4c3b784 authored 作者: hsx's avatar hsx

feat:可变颜色的svg组件

上级 4578c5d8
<template>
<div class="color-svg" v-if="svgContent">
<div v-html="processedSvgContent" class="svg-container"></div>
</div>
<div class="color-svg-loading" v-else>
<div class="loading-spinner"></div>
</div>
</template>
<script setup lang="ts">
import { size } from 'lodash';
import { ref, computed, watch, onMounted } from 'vue';
// 组件属性
const props = defineProps({
// SVG地址
svgUrl: {
type: String,
required: true
},
// SVG颜色
color: {
type: String,
default: '#000'
}
, size: {
type: Number,
default: null
}
});
// 组件事件
const emit = defineEmits(['svg-loaded', 'svg-error']);
// 状态管理
const svgContent = ref<string>('');
const isLoading = ref<boolean>(false);
const error = ref<string>('');
// 处理后的SVG内容
const processedSvgContent = computed(() => {
if (!svgContent.value) return '';
// 替换SVG中的颜色
let processed = svgContent.value;
// 替换fill属性
processed = processed.replace(/fill="([^"]*)"/g, (match, p1) => {
// 保留透明和none值
if (p1 === 'none' || p1 === 'transparent') {
return match;
}
return `fill="${props.color}"`;
});
// 替换stroke属性
processed = processed.replace(/stroke="([^"]*)"/g, (match, p1) => {
// 保留透明和none值
if (p1 === 'none' || p1 === 'transparent') {
return match;
}
return `stroke="${props.color}"`;
});
// 替换width属性
processed = processed.replace(/width="([^"]*)"/g, (match, p1) => {
if (props.size !== null) {
return `width="${props.size}"`;
}
return match;
});
// 替换height属性
processed = processed.replace(/height="([^"]*)"/g, (match, p1) => {
if (props.size !== null) {
return `height="${props.size}"`;
}
return match;
});
console.log(processed)
return processed;
});
// 加载SVG内容
const loadSvgContent = async () => {
if (!props.svgUrl) return;
isLoading.value = true;
error.value = '';
try {
const response = await fetch(props.svgUrl);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const content = await response.text();
svgContent.value = content;
emit('svg-loaded', content);
} catch (err) {
error.value = err instanceof Error ? err.message : 'Failed to load SVG';
emit('svg-error', error.value);
console.error('Error loading SVG:', err);
} finally {
isLoading.value = false;
}
};
// 监听属性变化
watch(
() => props.svgUrl,
() => {
loadSvgContent();
}
);
watch(
() => props.color,
() => {
// 颜色变化时重新处理SVG,不需要重新加载
}
);
// 组件挂载时加载SVG
onMounted(() => {
loadSvgContent();
});
</script>
<style scoped>
.color-svg {
display: inline-block;
}
.svg-container {
display: inline-block;
width: 100%;
height: 100%;
}
.color-svg-loading {
display: flex;
align-items: center;
justify-content: center;
width: 100px;
height: 100px;
}
.loading-spinner {
width: 20px;
height: 20px;
border: 2px solid #f3f3f3;
border-top: 2px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
\ No newline at end of file
<template>
<el-space @click="onClick(person)">
<ElAvatar :size="48" :src="person[img]" alignment="center" />
<el-avatar :size="48" :src="person[img]" alignment="center" />
<el-space :size="0" direction="vertical" alignment="flex-start">
<div class="text-header">{{ person[name] }}</div>
<div class="person-position">{{ person[position] }}</div>
......@@ -10,7 +10,7 @@
<script setup>
import '@/styles/common.scss'
import { ElSpace } from 'element-plus';
import { ElSpace, ElAvatar } from 'element-plus';
const props = defineProps({
// 新闻列表数据
......
......@@ -9,7 +9,7 @@ const companyPagesRoutes = [
{
path: "/companyPages/:id",
name: "companyPages",
component: companyPages,
component: companyPages2,
meta: {
title: "企业主页",
dynamicTitle: true
......@@ -19,7 +19,7 @@ const companyPagesRoutes = [
{
path: "/companyPages2/:id",
name: "companyPages2",
component: companyPages2,
component: companyPages,
meta: {
title: "企业主页",
dynamicTitle: true
......
......@@ -15,6 +15,10 @@
flex: 1;
}
.full-width {
width: 100%;
}
// 文本超出指定行数省略号显示
@mixin text-ellipsis($line-clamp) {
overflow: hidden;
......
......@@ -5,7 +5,7 @@ const span = 12
</script>
<template>
<el-row class="wrapper">
<el-row class="wrapper layout-grid-line">
<el-col :span="span">
<pre>
{{ `import '@/styles/common.scss';
......
<script setup lang="ts">
import { ElRow, ElCol } from 'element-plus';
import '@/styles/common.scss'
import ColorSvg from '@/components/base/images/ColorSvg.vue';
const span = 12
</script>
<template>
<el-row class="wrapper layout-grid-line">
<el-col :span="span">
<pre>
{{ `import ColorSvg from '@/components/base/images/ColorSvg.vue';
<template>
<color-svg :size="64" :svg-url="'/icon/arrow-up.svg'" :color="'var(--color-orange-100)'" />
<color-svg :size="16" :svg-url="'/icon/arrow-up.svg'" :color="'var(--color-green-100)'" />
</template>
`}}
</pre>
<color-svg :size="64" :svg-url="'/icon/arrow-up.svg'" :color="'var(--color-orange-100)'" />
<color-svg :size="16" :svg-url="'/icon/arrow-up.svg'" :color="'var(--color-green-100)'" />
</el-col>
</el-row>
</template>
<style lang="scss" scoped></style>
\ No newline at end of file
<script setup lang="ts">
import { ElRow, ElCol } from 'element-plus';
import '@/styles/common.scss'
import PersonAvatar from '@/components/base/people/PersonAvatar.vue';
const span = 12
</script>
<template>
<el-row class="wrapper layout-grid-line">
<el-col :span="span">
<pre>
{{ `import PersonAvatar from '@/components/base/people/PersonAvatar.vue';
<template>
<person-avatar class="person-avatar" :person="{
name: '张三',
position: 'CEO,CTO',
avatarUrl: '/icon/美国.png'
}">
</person-avatar>
</template>
`}}
</pre>
<person-avatar class="person-avatar" :person="{
name: '张三',
position: 'CEO,CTO',
avatarUrl: '/icon/美国.png'
}">
</person-avatar>
</el-col>
</el-row>
</template>
<style lang="scss" scoped>
.person-avatar {
width: 200px;
}
</style>
\ No newline at end of file
......@@ -8,7 +8,7 @@ const span = 12
</script>
<template>
<el-row>
<el-row class="layout-grid-line">
<el-col :span="span">
<pre>
{{ `import '@/styles/radio.scss';
......
......@@ -5,7 +5,7 @@ const span = 12
</script>
<template>
<el-row :gutter="16">
<el-row :gutter="16" class="layout-grid-line">
<el-col :span="span">
<pre>
{{ `import '@/styles/tabs.scss';
......@@ -22,10 +22,8 @@ const span = 12
</el-tabs>
</el-col>
<el-col :span="span">
<pre>
{{ `import '@/styles/tabs.scss';
<template>
//确保父级position: relative;
<pre>{{ `import '@/styles/tabs.scss';\n<template>
//确保父级position: relative;
<el-tabs tabPosition="left" class="tabs-nav-no-wrap left-float-nav-tabs">
</template>
`}}
......
......@@ -2,11 +2,12 @@
import { ElSpace, ElRow, ElCol } from 'element-plus';
import '@/styles/tabs.scss'
import ColorPrefixTitle from '@/components/base/texts/ColorPrefixTitle.vue';
import AiTipPane from '@/components/base/panes/AiTipPane.vue';
const span = 12
</script>
<template>
<el-row>
<el-row class="layout-grid-line">
<el-col :span="span">
<pre>
{{ `import ColorPrefixTitle from '@/components/base/texts/ColorPrefixTitle.vue';
......@@ -23,6 +24,14 @@ const span = 12
<color-prefix-title color="red">科技领域</color-prefix-title>
</el-space>
</el-col>
<el-col :span="span">
<pre>{{ `import AiTipPane from '@/components/base/panes/AiTipPane.vue';\n<template>
<ai-tip-pane>huidadadadadasda</ai-tip-pane>
</template>
`}}
</pre>
<ai-tip-pane>huidadadadadasda</ai-tip-pane>
</el-col>
</el-row>
</template>
......
.layout-grid-line {
.el-col {
border: 1px double var(--bg-black-5);
}
}
\ No newline at end of file
......@@ -16,12 +16,18 @@
<el-tab-pane label="文本" lazy>
<text-page />
</el-tab-pane>
<el-tab-pane label="图片" lazy>
<images-page />
</el-tab-pane>
<el-tab-pane label="单选框" lazy>
<radio-page />
</el-tab-pane>
<el-tab-pane label="选项卡" lazy>
<tabs-page />
</el-tab-pane>
<el-tab-pane label="人物" lazy>
<people-page />
</el-tab-pane>
</el-tabs>
</div>
</el-space>
......@@ -31,6 +37,7 @@
<script setup>
import "@/styles/container.scss"
import "./devStyle.scss"
import TextStyle from './textStyle.vue';
import ConstStyle from './constStyle.vue';
import { ElTabs, ElTabPane, ElSpace } from "element-plus";
......@@ -38,6 +45,8 @@ import RadioPage from './RadioPage/index.vue';
import TabsPage from './TabsPage/index.vue';
import CommonPage from './CommonPage/index.vue';
import TextPage from './TextPage/index.vue';
import ImagesPage from './Images/index.vue';
import PeoplePage from './People/index.vue';
</script>
<style lang="scss" scoped>
......
......@@ -5,13 +5,4 @@
padding: 16px 160px;
// width: 1600px;
align-items: center;
/* 关键属性:允许溢出内容显示 */
overflow: visible;
/* 不裁剪子元素 */
/* 其他可选属性 */
position: relative;
/* 如果子元素需要绝对定位 */
min-height: 0;
/* 防止 flex 或 grid 容器压缩 */
}
\ No newline at end of file
......@@ -71,9 +71,9 @@ function nodeTopBottomLayout(nodes: Array<any>) {
const bottomCount = bottoms.length
// 列间距
const columnSpacing = 250
const columnSpacing = 60
// 上下列距离中心的距离
const verticalDistance = 260
const verticalDistance = 100
let ci = (topCount - 1) / 2
// 处理上列节点
......@@ -144,7 +144,8 @@ function updateCharts() {
offset: [0, -10],
formatter: '{b}',
fontSize: 14,
fontWeight: 'bold',
textBorderColor: 'rgb(255 255 255)',
// fontWeight: 'bold',
color: 'rgb(5, 95, 194)',
padding: [4, 6],
borderRadius: 4,
......
......@@ -7,7 +7,9 @@ import ColorPrefixTitle from '@/components/base/texts/ColorPrefixTitle.vue';
import GraphChart from './GraphChart.vue'
import { forEach } from 'lodash';
import AiTipPane from '@/components/base/panes/AiTipPane.vue';
import { getRuleOrg } from '@/api/ruleRestriction';
import ColorSvg from '@/components/base/images/ColorSvg.vue'
import MachineImg from '../../assets/images/机械设备.svg'
import FundImg from '../../assets/images/资金管理.svg'
const CompanyImg = "/icon/company/普通企业节点.svg"
const CompanyImg2 = "/icon/company/普通企业节点2.svg"
......@@ -30,8 +32,10 @@ const supplyTypeList = [{
}];
const dataTypeList = ref([{
name: '供应链', id: 'supply',
icon: MachineImg
}, {
name: '股权', id: 'equity',
icon: FundImg
}])
const selectedSupplyAreas = ref([]);
const selectedSupplyCountries = ref([]);
......@@ -191,11 +195,17 @@ async function handleDataTypeChange() {
</el-checkbox-group>
</div>
<div class="background-as-card flex-fill">
<graph-chart :nodes="nodes" :links="links" />
<el-radio-group v-model="selectedDataType" class="data-type-group" @change="handleDataTypeChange">
<el-radio-button v-for="item in dataTypeList" :label="item.id" :value="item.id">
{{ item.name }} </el-radio-button>
<color-svg :size="16" :svg-url="item.icon"
:color="item.id === selectedDataType ? 'var(--bg-white-100)' : 'var(--color-primary-100)'">
</color-svg>
<span class="text-title-3">
{{ item.name }}
</span>
</el-radio-button>
</el-radio-group>
<graph-chart :nodes="nodes" :links="links" />
<ai-tip-pane v-if="enterpriseInfo.id === '914403001922038216'">
华为构建了覆盖全球的复杂供应链网络,以自身为核心,辐射芯片、显示、摄像头等关键领域。其供应链深度扎根中国,同时整合美国高通、韩国三星、日本索尼等国际顶尖供应商,形成多元化供应格局。面对外部技术封锁,华为通过扶持海思等子公司强化垂直整合,并积极拓展本土替代资源,在保持技术领先的同时增强供应链韧性,展现出卓越的全球资源调配与风险管控能力。
</ai-tip-pane>
......@@ -221,20 +231,7 @@ async function handleDataTypeChange() {
}
.data-type-group {
padding: 0px 25px;
margin-bottom: 20px;
position: absolute;
padding: 10px 16px;
top: 16px;
svg {
width: 24px;
height: 24px;
}
.is-active {
svg {
height: 32px;
}
}
}
</style>
\ No newline at end of file
......@@ -4,7 +4,7 @@
</div>
<el-scrollbar>
<div class="common-page">
<el-space wrap :size="16" fill>
<el-space wrap :size="16" fill class="full-width">
<title-pane :enterprise-info="enterpriseInfo"></title-pane>
<el-tabs stretch class="tabs-header-as-card tabs-nav-no-wrap tabs-bar-as-btn tab-pane-overflow-visible">
<el-tab-pane label="企业详情">
......
......@@ -64,7 +64,8 @@
</div>
</div> -->
<div class="home-main-header-item-box">
<div class="item" v-for="(item, index) in govInsList" :key="index" @click="handleToInstitution(item)">
<div class="item" v-for="(item, index) in govInsList" :key="index"
@click="handleToInstitution(item)">
<div class="item-left">
<img :src="item.img ? item.img : DefaultIcon2" alt="" />
</div>
......@@ -122,7 +123,8 @@
}" v-for="(tag, index) in item.industryList" :key="index">
{{ tag.industryName }}
</div> -->
<AreaTag v-for="(tag, index) in item.industryList" :key="index" :tagName="tag.industryName">
<AreaTag v-for="(tag, index) in item.industryList" :key="index"
:tagName="tag.industryName">
</AreaTag>
</div>
<div class="box1-main-right-center">
......@@ -185,16 +187,17 @@
<div class="text">{{ "查看更多" }}</div>
</div>
</div> -->
<RiskSignal :list="warningList" @item-click="handleClickToDetail" @more-click="handleToMoreRiskSignal"
riskLevel="signalLevel" postDate="signalTime" name="signalTitle">
<RiskSignal :list="warningList" @item-click="handleClickToDetail"
@more-click="handleToMoreRiskSignal" riskLevel="signalLevel" postDate="signalTime"
name="signalTitle">
</RiskSignal>
</div>
<DivideHeader id="position2" class="divide2" :titleText="'资讯要闻'"></DivideHeader>
<div class="center-center">
<NewsList :newsList="newsList" @item-click="handleToNewsAnalysis" @more-click="handleToMoreNews" />
<!-- <NewsList :newsList="newsList" /> -->
<MessageBubble :messageList="messageList" @person-click="handleClickPerson" @info-click="handleGetMessage"
imageUrl="img" @more-click="handleToSocialDetail" />
<MessageBubble :messageList="messageList" @person-click="handleClickPerson"
@info-click="handleGetMessage" imageUrl="img" @more-click="handleToSocialDetail" />
</div>
<DivideHeader id="position3" class="divide3" :titleText="'数据总览'"></DivideHeader>
<div class="center-footer">
......@@ -209,7 +212,8 @@
<div class="box5-selectbox">
<el-select @change="handleBox5YearChange" v-model="box5SelectedYear" placeholder="选择时间"
style="width: 120px">
<el-option v-for="item in box5YearList" :key="item.value" :label="item.label" :value="item.value" />
<el-option v-for="item in box5YearList" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</div>
</div>
......@@ -227,7 +231,8 @@
<div class="box6-selectbox">
<el-select @change="handleBox6YearChange" v-model="box6SelectedYear" placeholder="选择时间"
style="width: 120px">
<el-option v-for="item in box6YearList" :key="item.value" :label="item.label" :value="item.value" />
<el-option v-for="item in box6YearList" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</div>
</div>
......@@ -243,7 +248,8 @@
<div class="header-title">{{ "关键行政令" }}</div>
</div>
<div class="box7-main">
<div class="box7-item" v-for="(item, index) in keyDecreeList" :key="index" @click="handleKeyDecree(item)">
<div class="box7-item" v-for="(item, index) in keyDecreeList" :key="index"
@click="handleKeyDecree(item)">
<div class="icon">
<img src="./assets/images/warning.png" alt="" />
</div>
......@@ -299,9 +305,9 @@
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox v-for="type in decreeTypeList" :key="type.id" v-model="checkedDecreeType"
:label="type.typeId" style="width: 180px" class="filter-checkbox"
@change="handleChangeCheckedDecreeType">
<el-checkbox v-for="type in decreeTypeList" :key="type.id"
v-model="checkedDecreeType" :label="type.typeId" style="width: 180px"
class="filter-checkbox" @change="handleChangeCheckedDecreeType">
{{ type.typeName }}
</el-checkbox>
</div>
......@@ -314,8 +320,9 @@
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox v-for="cate in govInsList" :key="cate.id" v-model="checkedGovIns" :label="cate.id"
style="width: 180px" class="filter-checkbox" @change="handleChangeCheckedGovIns">
<el-checkbox v-for="cate in govInsList" :key="cate.id" v-model="checkedGovIns"
:label="cate.id" style="width: 180px" class="filter-checkbox"
@change="handleChangeCheckedGovIns">
{{ cate.name }}
</el-checkbox>
</div>
......@@ -328,8 +335,8 @@
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox v-for="time in pubTime" :key="time.id" v-model="activePubTime" :label="time.id"
style="width: 100px" class="filter-checkbox"
<el-checkbox v-for="time in pubTime" :key="time.id" v-model="activePubTime"
:label="time.id" style="width: 100px" class="filter-checkbox"
@change="checked => handlePubTimeChange(time.id, checked)">
{{ time.name }}
</el-checkbox>
......@@ -343,8 +350,9 @@
</div>
<div class="select-main select-main1">
<div class="checkbox-group">
<el-checkbox v-for="area in areaList" :key="area.id" v-model="activeAreaList" :label="area.id"
style="width: 100px" @change="checked => handleAreaChange(area.id, checked)">
<el-checkbox v-for="area in areaList" :key="area.id" v-model="activeAreaList"
:label="area.id" style="width: 100px"
@change="checked => handleAreaChange(area.id, checked)">
{{ area.name }}
</el-checkbox>
</div>
......@@ -359,7 +367,8 @@
<div class="title">{{ "政令库" }}</div>
</div>
<div class="content-box" v-show="decreeList">
<div class="main-item" v-for="(item, index) in decreeList" :key="index" @click="handleClickDecree(item)">
<div class="main-item" v-for="(item, index) in decreeList" :key="index"
@click="handleClickDecree(item)">
<div class="main-item-left">
<div class="left-left">
{{ item.time.split("-")[0] }}<br />{{ item.time.split("-")[1] }}月{{
......@@ -401,8 +410,9 @@
{{ `共 ${totalDecreesNum} 项` }}
</div>
<div class="footer-right">
<el-pagination @current-change="handleCurrentChange" :pageSize="10" :current-page="currentPage"
background layout="prev, pager, next" :total="totalDecreesNum" />
<el-pagination @current-change="handleCurrentChange" :pageSize="10"
:current-page="currentPage" background layout="prev, pager, next"
:total="totalDecreesNum" />
</div>
</div>
</div>
......@@ -413,7 +423,7 @@
</template>
<script setup>
import NewsList from "@/components/base/NewsList/index.vue";
import NewsList from "@/components/base/newsList/index.vue";
import { onMounted, ref, computed, watch, nextTick } from "vue";
import router from "@/router";
import {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论