提交 accf8ee8 authored 作者: yanpeng's avatar yanpeng

Merge branch 'master' into yp-dev

......@@ -20,7 +20,7 @@ export function getBillInfo(params) {
export function getBillPerson(params) {
return request({
method: 'GET',
url: `/api/billInfoBean/person/${params.billId}`,
url: `/bill/billInfoBean/person/${params.billId}`,
params,
})
}
......
......@@ -32,7 +32,13 @@ export function getEnterpriseNewDynamic(params) {
url: `/api/enterprisePage/newDynamic/${params}`,
})
}
//企业基本信息:最新动态(分页)
export function getEnterpriseNewDynamicPage(params) {
return request({
method: 'GET',
url: `/api/enterprisePage/newDynamicPage/${params}`,
})
}
//企业研发投入:年度研发投入对比
export function getEnterpriseStudy(params) {
......
......@@ -48,6 +48,8 @@ const handleToNewsAnalysis = (item, index) => {
};
</script>
<style lang="scss" scoped>
@use '@/styles/common.scss';
.box3-item {
display: flex;
align-items: center;
......@@ -90,12 +92,8 @@ const handleToNewsAnalysis = (item, index) => {
.title {
// width: 500px;
height: 24px;
color: rgba(59, 65, 75, 1);
font-family: 'Source Han Sans CN';
font-size: 16px;
font-weight: 700;
line-height: 24px;
@extend .text-title-3-bold;
color: var(--text-primary-80-color);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
......@@ -108,39 +106,15 @@ const handleToNewsAnalysis = (item, index) => {
.time {
text-align: right;
height: 22px;
color: rgba(95, 101, 108, 1);
font-family: 'Source Han Sans CN';
font-size: 14px;
font-weight: 400;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@extend .text-tip-2;
color: var(--text-primary-65-color);
}
}
.right-footer {
height: 48px;
/* 调整为2行的高度:24px × 2 = 48px */
color: rgba(59, 65, 75, 1);
font-family: 'Source Han Sans CN';
font-size: 16px;
font-weight: 400;
line-height: 24px;
overflow: hidden;
display: -webkit-box;
/* 关键 */
-webkit-line-clamp: 2;
/* 显示2行 */
-webkit-box-orient: vertical;
/* 垂直方向排列 */
text-overflow: ellipsis;
/* 第二行省略号 */
white-space: normal;
/* 改为 normal */
word-break: break-word;
/* 允许单词换行 */
@extend .text-compact;
color: var(--text-primary-65-color);
@include common.text-ellipsis(2);
}
}
</style>
\ No newline at end of file
......@@ -236,25 +236,6 @@ const handleMoreClick = () => {
.item-left {
margin-top: 4px;
margin-left: 0px;
margin-bottom: 4px;
width: 40px;
height: 40px;
border-radius: 20px;
color: rgba(82, 196, 26, 1);
background: rgba(246, 255, 237, 1);
font-family: Microsoft YaHei;
font-size: 12px;
font-weight: 400;
line-height: 14px;
box-sizing: border-box;
padding: 6px 4px;
text-align: center;
flex-shrink: 0;
}
.item-right {
margin-left: 12px;
height: 46px;
......
......@@ -9,7 +9,7 @@ import { ElScrollbar, ElSpace } from "element-plus";
<template>
<el-scrollbar>
<div class="common-page">
<el-space direction="vertical" alignment="flex-start">
<el-space direction="vertical" :size="20" alignment="flex-start">
<div class="text-title-0-show">开发样式</div>
<div class="text-title-1-show">样式变量</div>
<const-style></const-style>
......
//企业主页
const companyPages = () => import('@/views/companyPages/index.vue')
const companyPages2 = () => import('@/views/companyPages2/index.vue')
const companyPagesRoutes = [
......@@ -14,6 +15,16 @@ const companyPagesRoutes = [
dynamicTitle: true
}
},
// todo: 开发过程测试,开发完成后删除,by hsx ,20260306
{
path: "/companyPages2/:id",
name: "companyPages2",
component: companyPages2,
meta: {
title: "企业主页",
dynamicTitle: true
}
},
]
......
// 风险信号
const RiskSignal = () => import('@/views/riskSignal/index.vue')
const viewRiskSignal = () => import('@/views/viewRiskSignal/index.vue')
const riskSignalRoutes = [
const viewRiskSignalRoutes = [
//风险信号页面路由
{
path: "/riskSignal",
name: "riskSignal",
component: RiskSignal,
path: "/viewRiskSignal",
name: "viewRiskSignal",
component: viewRiskSignal,
meta: {
title: "风险信号"
}
}
]
export default riskSignalRoutes
\ No newline at end of file
export default viewRiskSignalRoutes
\ No newline at end of file
/***背景作为卡片***/
.background-as-card {
background-color: var(--color-primary-65);
background-color: var(--bg-white-80);
border-radius: 10px;
border: 1px solid rgba(234, 236, 238, 1);
border: 1px solid var(--bg-white-100);
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
}
......@@ -10,10 +10,29 @@
.flex-display{
display: flex;
}
// 文本超出指定行数省略号显示
@mixin text-ellipsis($line-clamp) {
overflow: hidden;
display: -webkit-box;
/* 关键 */
-webkit-line-clamp: $line-clamp;
/* 显示2行 */
-webkit-box-orient: vertical;
/* 垂直方向排列 */
text-overflow: ellipsis;
/* 第二行省略号 */
white-space: normal;
/* 改为 normal */
word-break: break-word;
/* 允许单词换行 */
}
//禁止换行
.text-nowrap{
white-space: nowrap;
}
/***文本样式***/
.text-base{
color: var(--color-primary-90);
color: var(--color-primary-80);
}
//0级标题
......
......@@ -3,6 +3,7 @@
/***没有nav下划线***/
.common-descriptions .el-descriptions__label{
@extend .text-tip-1-bold;
color: var(--text-primary-80-color);
}
.common-descriptions .el-descriptions__content{
@extend .text-tip-1;
......
......@@ -4,8 +4,6 @@
--font-family-base: "Source Han Sans CN";
--font-size-base: 16px;
--color-bg-hover: #f6faff;
/* 普通按钮颜色 */
......@@ -29,6 +27,7 @@
--bg-black-5: #EAECEE;
--bg-black-2: #F7F8F9;
--bg-white-100: #FFFFFF;
--bg-white-80: rgba(255, 255, 255, 0.8);
--bg-white-65: rgba(255, 255, 255, 0.65);
--bg-white-50: rgba(255, 255, 255, 0.5);
--bg-white-35: rgba(255, 255, 255, 0.35);
......
......@@ -685,7 +685,7 @@ const filteredHotNewsList = computed(() => {
const handleToRiskManage = () => {
// 这里的路由路径请根据实际情况修改
// router.push('/riskSignalManage');
const route = router.resolve("/riskSignal");
const route = router.resolve("/viewRiskSignal");
window.open(route.href, "_blank");
console.log("跳转到风险信号管理");
};
......
......@@ -2,13 +2,13 @@
<div class="resource-library-section">
<div class="home-content-footer-header">
<div class="btn-box">
<div class="btn" :class="{ btnActive: activeTabName === cate.name, disabled: index > 2 }"
v-for="(cate, index) in tabList" :key="index" @click="index <= 2 && handleClickTab(cate)">
<div class="btn" :class="{ btnActive: activeTabName === cate.name, disabled: cate.active === false}"
v-for="(cate, index) in tabList" :key="index" @click="cate.active === true && handleClickTab(cate)">
{{ cate.name }}
</div>
</div>
</div>
<div class="home-content-footer-main">
<div class="home-content-footer-main" :class="{ 'committee-full-layout': activeTabName === '委员会' }">
<div class="left" v-if="['国会法案', '国会议员', '议员合作关系'].includes(activeTabName)">
<div class="select-box">
<div class="select-box-header">
......@@ -77,8 +77,8 @@
</div>
</div>
</div>
<div class="right">
<div class="right-header">
<div class="right" :class="{ 'right-full': activeTabName === '委员会' }">
<div class="right-header" v-if="activeTabName !== '委员会'">
<div class="right-header-box">
<el-select v-model="footerSelect1" placeholder="选择委员会" style="width: 240px" @change="handleFooterSelect1Change">
<el-option v-for="item in postOrgList" :key="item.departmentId" :label="item.departmentName" :value="item.departmentId" />
......@@ -177,6 +177,22 @@
<div class="member-info">关注领域:{{ item.focus || '-' }}</div>
</div>
</div>
<div v-else-if="activeTabName === '委员会'" class="committee-list">
<div class="committee-card" v-for="item in committeeList" :key="item.id">
<div class="committee-info">
<img class="committee-avatar" :src="item.avatar || defaultAvatar" alt="committee-avatar" />
<div class="committee-text">
<div class="committee-name">{{ item.name }}</div>
<div class="committee-desc">{{ item.desc }}</div>
</div>
</div>
<div class="committee-bill-grid">
<div class="committee-bill-item" v-for="(bill, idx) in item.bills" :key="`${item.id}-bill-${idx}`">
{{ bill }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
......@@ -201,9 +217,9 @@ const props = defineProps({
const tabList = ref([
{ name: "国会法案", active: true },
{ name: "国会议员", active: false },
{ name: "国会议员", active: true },
{ name: "议员合作关系", active: false },
{ name: "涉华委员会", active: false }
{ name: "委员会", active: true }
]);
const activeTabName = ref("国会法案");
const handleClickTab = tab => {
......@@ -216,6 +232,10 @@ const handleClickTab = tab => {
if (tab.name === "国会法案") {
currentPage.value = 1;
handleGetBills();
return;
}
if (tab.name === "委员会") {
handleGetCommitteeList();
}
};
......@@ -249,6 +269,30 @@ const memberTotal = ref(0);
const memberPageSize = ref(15);
const memberCurrentPage = ref(1);
const committeeList = ref([
{
id: "committee-1",
avatar: "",
name: "美中经济与安全审查委员会",
desc: "聚焦中美经贸、科技与国家安全议题,跟踪涉华政策与立法动态。",
bills: ["2025年涉华关键技术审查法案", "供应链安全与关键矿产保障法案", "对华投资限制与透明度加强法案", "联邦科研合作安全审查法案"]
},
{
id: "committee-2",
avatar: "",
name: "众议院外交事务委员会",
desc: "负责对外政策与国际关系立法,持续推进对华议题相关审议与听证。",
bills: ["印太战略资源配置法案", "对外援助合规与问责法案", "跨境数据安全与执法协作法案", "关键基础设施网络韧性法案"]
},
{
id: "committee-3",
avatar: "",
name: "参议院军事委员会",
desc: "围绕国防授权、军费及安全合作展开审查,关注涉华国防与技术议题。",
bills: ["国防授权法涉华条款(示例)", "先进半导体供应安全法案", "军民两用技术出口管制法案", "海外关键设施安全评估法案"]
}
]);
const bills = ref([]);
const total = ref(0);
const pageSize = ref(4);
......@@ -263,6 +307,20 @@ const getRiskTagClass = riskSignal => {
return "";
};
// 获取委员会列表(占位)
const handleGetCommitteeList = async () => {
loading.value = true;
try {
// TODO: 接入委员会列表接口后,在此替换为真实请求并赋值 committeeList
// const res = await getCommitteeList(params);
// committeeList.value = res?.data?.content || [];
} catch (error) {
committeeList.value = [];
} finally {
loading.value = false;
}
};
const handleGetHylyList = async () => {
try {
const res = await getHylyList();
......@@ -551,6 +609,17 @@ onMounted(() => {
justify-content: space-between;
align-items: flex-start;
&.committee-full-layout {
.right {
margin-left: 0;
width: 1600px;
.right-main {
height: auto;
}
}
}
.left {
width: 300px;
padding-bottom: 33px;
......@@ -662,6 +731,14 @@ onMounted(() => {
.right-main {
height: 1264px;
.member-grid,
.coop-list,
.committee-list {
display: grid;
column-gap: 16px;
row-gap: 16px;
}
.member-grid,
.coop-list {
display: grid;
......@@ -834,6 +911,72 @@ onMounted(() => {
grid-template-columns: 1fr;
}
.committee-list {
grid-template-columns: 1fr;
.committee-card {
padding: 20px 24px;
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: #fff;
}
.committee-info {
display: flex;
gap: 16px;
align-items: flex-start;
padding-bottom: 16px;
border-bottom: 1px solid #eaeced;
}
.committee-avatar {
width: 64px;
height: 64px;
border-radius: 50%;
object-fit: cover;
flex-shrink: 0;
}
.committee-name {
color: #3b414b;
font-family: "Microsoft YaHei";
font-size: 20px;
font-weight: 700;
line-height: 28px;
}
.committee-desc {
margin-top: 8px;
color: #5f656c;
font-family: "Microsoft YaHei";
font-size: 16px;
font-weight: 400;
line-height: 24px;
}
.committee-bill-grid {
margin-top: 16px;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.committee-bill-item {
height: 48px;
padding: 0 14px;
border-radius: 6px;
background: #f5f8fc;
color: #3b414b;
font-family: "Microsoft YaHei";
font-size: 15px;
font-weight: 400;
line-height: 48px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.right-main-box {
position: relative;
width: 1280px;
......
import "echarts-wordcloud";
const getWordCloudChart = (data) => {
const getWordCloudChart = (data = []) => {
const option = {
grid: {
left: 0,
......
<template>
<div class="container">
<div class="svg-timeline">
<svg :viewBox="`0 0 ${svgWidth} ${svgHeight}`" width="100%" height="100%">
<line
v-if="nodes.length > 0"
:x1="nodes[0].x - 100"
:y1="nodes[0].y"
:x2="nodes[0].x"
:y2="nodes[0].y"
stroke="#e8f2ff"
stroke-width="2"
marker-end="url(#arrow)"
/>
<path :d="arcPaths" fill="none" stroke="#e8f2ff" stroke-width="2" marker-end="url(#arrow)" />
<circle
v-for="(node, idx) in nodes"
:key="'circle' + idx"
:cx="node.x"
:cy="node.y"
r="4"
fill="#fff"
stroke="#1677ff"
stroke-width="3"
/>
<line
v-for="(node, idx) in nodes"
:key="'line' + idx"
:x1="node.x"
:y1="node.y + 4"
:x2="node.x"
:y2="node.y + verticalLineLength"
stroke="#1677ff"
:stroke-width="verticalLineWidth"
/>
<foreignObject
v-for="(node, idx) in nodes"
:key="'fo-' + idx"
:x="node.x + 15"
:y="node.y + 5"
:width="nodeGapX - 30"
height="100"
style="overflow: visible;"
>
<div class="node-content" xmlns="http://www.w3.org/1999/xhtml">
<div class="date">{{ node.formattedDate }}</div>
<el-tooltip
effect="dark"
:content="node.actionTitle"
popper-class="common-prompt-popper"
placement="top"
:show-after="500"
>
<div class="title">{{ node.actionTitle }}</div>
</el-tooltip>
<div class="votes" v-if="node.voteString">{{ node.voteString }}</div>
</div>
</foreignObject>
<text
v-if="startMonth && nodes.length > 0"
:x="nodes[0].x - 110"
:y="nodes[0].y + 5"
text-anchor="end"
fill="rgb(5, 95, 194)"
font-size="16"
font-weight="700"
>
{{ startMonth }}
</text>
<line
v-if="nodes.length > 0"
:x1="nodes[nodes.length - 1].x"
:y1="nodes[nodes.length - 1].y"
:x2="nodes[nodes.length - 1].row % 2 === 0 ? nodes[nodes.length - 1].x + 100 : nodes[nodes.length - 1].x - 100"
:y2="nodes[nodes.length - 1].y"
stroke="#e8f2ff"
stroke-width="2"
marker-end="url(#arrow)"
/>
<text
v-if="endMonth && nodes.length > 0"
:x="nodes[nodes.length - 1].row % 2 === 0 ? nodes[nodes.length - 1].x + 110 : nodes[nodes.length - 1].x - 110"
:y="nodes[nodes.length - 1].y + 5"
:text-anchor="nodes[nodes.length - 1].row % 2 === 0 ? 'start' : 'end'"
fill="rgb(5, 95, 194)"
font-size="16"
font-weight="700"
>
{{ endMonth }}
</text>
</svg>
</div>
</div>
</template>
<script>
export default {
name: "SBillProgressTimeline",
props: ["dataList"],
data() {
return {
maxPerRow: 5,
nodeGapX: 200,
nodeGapY: 180,
leftMargin: 150,
verticalLineLength: 80,
verticalLineWidth: 1
};
},
computed: {
startMonth() {
if (this.sortedDataList.length === 0) return '';
const date = new Date(this.sortedDataList[0].actionDate);
return `${date.getFullYear()}${date.getMonth() + 1}月`;
},
endMonth() {
if (this.sortedDataList.length === 0) return '';
const date = new Date(this.sortedDataList[this.sortedDataList.length - 1].actionDate);
return `${date.getFullYear()}${date.getMonth() + 1}月`;
},
sortedDataList() {
if (!this.dataList || !Array.isArray(this.dataList)) return [];
return [...this.dataList]
.filter(item => item && item.actionDate)
.sort((a, b) => new Date(a.actionDate) - new Date(b.actionDate));
},
nodes() {
return this.sortedDataList.map((item, idx) => {
const row = Math.floor(idx / this.maxPerRow);
const col = idx % this.maxPerRow;
let x, y;
if (row % 2 === 0) {
x = this.leftMargin + col * this.nodeGapX + 50;
} else {
x = this.leftMargin + (this.maxPerRow - 1 - col) * this.nodeGapX + 50;
}
y = 60 + row * this.nodeGapY;
let formattedDate = "";
if (item.actionDate) {
const dateObj = new Date(item.actionDate);
if (!isNaN(dateObj.getTime())) {
formattedDate = `${dateObj.getMonth() + 1}${dateObj.getDate()}日`;
}
}
let voteString = "";
if (item.agreeVote !== null && item.agreeVote !== undefined && item.disagreeVote !== null && item.disagreeVote !== undefined) {
voteString = `${item.agreeVote}票赞成 : ${item.disagreeVote}票反对`;
}
return { ...item, x, y, row, formattedDate, voteString };
});
},
arcPaths() {
if (this.nodes.length < 2) return "";
let path = `M ${this.nodes[0].x} ${this.nodes[0].y}`;
for (let i = 1; i < this.nodes.length; i++) {
const prev = this.nodes[i - 1];
const curr = this.nodes[i];
const isTurnPoint = i % this.maxPerRow === 0;
if (isTurnPoint) {
const radius = 10 / 2;
if (prev.row % 2 === 0) {
path += ` L ${prev.x + radius} ${prev.y} A ${radius} ${radius} 0 0 1 ${curr.x - radius} ${curr.y} L ${curr.x} ${curr.y}`;
} else {
path += ` L ${prev.x - radius} ${prev.y} A ${radius} ${radius} 0 0 0 ${curr.x + radius} ${curr.y} L ${curr.x} ${curr.y}`;
}
} else {
path += ` L ${curr.x} ${curr.y}`;
}
}
return path;
},
svgWidth() {
return this.leftMargin + this.maxPerRow * this.nodeGapX + 50;
},
svgHeight() {
const listLength = (this.dataList && Array.isArray(this.dataList)) ? this.dataList.length : 0;
return Math.ceil(listLength / this.maxPerRow) * this.nodeGapY + 40;
}
}
};
</script>
<style lang="scss" scoped>
.container {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.svg-timeline {
width: 100%;
.node-content {
font-family: Microsoft YaHei, sans-serif;
text-align: left;
padding-left: 4px;
.date {
color: rgb(5, 95, 194);
font-weight: 700;
font-size: 16px;
line-height: 22px;
margin-bottom: 0px;
margin-top: 6px;
}
.title {
color: rgb(59, 65, 75);
font-weight: 700;
font-size: 16px;
line-height: 22px;
margin-bottom: 0px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
display: block;
}
.votes {
color: rgb(95, 101, 108);
font-size: 16px;
font-weight: 400;
line-height: 22px;
}
}
}
</style>
<style>
.common-prompt-popper.el-popper {
padding: 8px 16px !important;
border-radius: 10px !important;
background-color: rgb(59, 65, 75) !important;
font-size: 16px !important;
font-weight: 400 !important;
font-family: "Microsoft YaHei" !important;
line-height: 30px !important;
color: #fff !important;
border: none !important;
max-width: 600px;
}
.common-prompt-popper.el-popper .el-popper__arrow::before {
background-color: rgb(59, 65, 75) !important;
border-color: rgb(59, 65, 75) !important;
}
</style>
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none" customFrame="#000000">
<rect id="Icon图标/Line/double right" width="16.000000" height="16.000000" x="0.000000" y="0.000000" transform="matrix(0,1,-1,0,16,0)" />
<path id="形状" d="M5.519 5.19219L1.52994 0.0953125C1.48307 0.034375 1.40963 0 1.33307 0L0.125253 0C0.0205652 0 -0.0372473 0.120312 0.0268152 0.201562L4.17369 5.5L0.0268152 10.7984C-0.0372473 10.8797 0.0205652 11 0.125253 11L1.33307 11C1.40963 11 1.48307 10.9641 1.52994 10.9047L5.519 5.80937C5.66119 5.62656 5.66119 5.37344 5.519 5.19219ZM6.27994 0.0953125L10.269 5.19219C10.4112 5.37344 10.4112 5.62656 10.269 5.80937L6.27994 10.9047C6.23306 10.9641 6.15963 11 6.08307 11L4.87525 11C4.77056 11 4.71275 10.8797 4.77681 10.7984L8.92369 5.5L4.77681 0.201562C4.71275 0.120312 4.77056 0 4.87525 0L6.08307 0C6.15963 0 6.23306 0.034375 6.27994 0.0953125Z" fill="rgb(5,95,194)" fill-rule="evenodd" transform="matrix(0,1,-1,0,13.5,3.8125)" />
</svg>
......@@ -89,7 +89,7 @@
<div class="item-left">相关领域:</div>
<div class="item-right1">
<!-- <div class="right1-item" v-for="item in basicInfo.hylyList" :key="item">{{ item }}</div> -->
<AreaTag v-for="item, index in basicInfo.hylyList" :key="index" :tagName="item"></AreaTag>
<AreaTag v-for="item, index in basicInfo.hylyList" :key="index" :tagName="item"/>
</div>
</div>
<div class="box1-right-item">
......@@ -144,9 +144,19 @@
</div>
</div> -->
<AnalysisBox title="法案进展" :showAllBtn="false">
<template #header-btn>
<div class="progress-header-btns">
<div class="btn" :class="{ btnActive: progressMode === 'latest' }" @click="handleSwitchProgressMode('latest')">
最新进展
</div>
<div class="btn" :class="{ btnActive: progressMode === 'early' }" @click="handleSwitchProgressMode('early')">
前期进程
</div>
</div>
</template>
<div class="box2-main">
<div class="box2-main-center">
<STimeline :dataList="timelineData" />
<STimeline :dataList="timelineData" :mode="progressMode" :maxCount="5" />
</div>
</div>
</AnalysisBox>
......@@ -261,7 +271,7 @@
</div>
<div class="info-box">
<div class="info-left">
<img :src="defaultAvatar" alt="" @click="handleClickAvatar(curPerson)" />
<img class="person-avatar" :src="curPerson.imageUrl || defaultAvatar" alt="" @click="handleClickAvatar(curPerson)" />
<div class="usr-icon1">
<img src="./assets/images/usr-icon1.png" alt="" />
</div>
......@@ -292,13 +302,8 @@
</div>
<div class="right-main-box2" v-if="curPerson.tagList && curPerson.tagList.length">
<!-- <WordCloudMap :data="wordCloudData" :shape="circle" /> -->
<div class="tag-box" :class="{
status0: index % 4 === 0,
status1: index % 4 === 1,
status2: index % 4 === 2,
status3: index % 4 === 3
}" v-for="(tag, index) in curPerson.tagList" :key="index">
{{ tag.industryName }}
<div class="tag-box status"v-for="(tag, index) in curPerson.tagList" :key="index">
{{ tag }}
</div>
</div>
<div class="right-main-box3">
......@@ -329,88 +334,10 @@
</el-timeline-item> -->
</el-timeline>
</div>
<div class="right-main-box3-footer">
<div class="btn-more" @click="handleClickMore2">
<img src="../assets/images/btn-more.png" alt="" />
</div>
</div>
</div>
</div>
</AnalysisBox>
</div>
<el-dialog v-model="isShowDialog" class="dialog-box" width="1280">
<div class="dialog-inner-box">
<div class="inner-left">
<div class="info-box">
<div class="info-top">
<img :src="defaultAvatar" alt="" />
<div class="usr-icon1">
<img src="./assets/images/usr-icon1.png" alt="" />
</div>
<div class="usr-icon2">
<img src="./assets/images/usr-icon2.png" alt="" />
</div>
</div>
<div class="info-footer">
<div class="info-right-title">{{ curPerson.name }}</div>
<div class="info-right-item">
<div class="item-left">英文名:</div>
<div class="item-right">{{ curPerson.ename }}</div>
</div>
<div class="info-right-item">
<div class="item-left">党派:</div>
<div class="item-right">{{ curPerson.dp }}</div>
</div>
<div class="info-right-item">
<div class="item-left">选区:</div>
<div class="item-right">{{ curPerson.xq }}</div>
</div>
<div class="info-right-item">
<div class="item-left">职位:</div>
<div class="item-right">{{ curPerson.zw }}</div>
</div>
</div>
</div>
<div class="tag-wrapper" v-if="curPerson.tagList && curPerson.tagList.length">
<div class="tag-box" :class="{
status0: index % 4 === 0,
status1: index % 4 === 1,
status2: index % 4 === 2,
status3: index % 4 === 3
}" v-for="(tag, index) in curPerson.tagList" :key="index">
{{ tag.industryName }}
</div>
</div>
<div class="more">更多议员 ></div>
</div>
<div class="inner-right">
<div class="btn-box">
<div class="btn" :class="{ btnActive: dialogBoxBtnActive === 0 }" @click="handleClcikDialogBoxBtn(0)">
新闻动态
</div>
<div class="btn" :class="{ btnActive: dialogBoxBtnActive === 1 }" @click="handleClcikDialogBoxBtn(1)">
人物履历
</div>
</div>
<div class="inner-right-main">
<el-timeline style="max-width: 840px">
<el-timeline-item :timestamp="item.newsDate" placement="top" v-for="(item, index) in curPerson.newsList"
:key="index">
<div class="timeline-content1">
<div class="text">
{{ item.newsContent }}
</div>
<div class="pic">
<img :src="defaultNew" alt="" />
</div>
</div>
</el-timeline-item>
</el-timeline>
</div>
</div>
</div>
</el-dialog>
</div>
</template>
......@@ -446,11 +373,10 @@ const handleClcikDialogBoxBtn = index => {
};
const timelineData = ref([]);
const progressMode = ref("latest");
const isShowDialog = ref(false);
const handleClickMore2 = () => {
isShowDialog.value = true;
const handleSwitchProgressMode = mode => {
progressMode.value = mode;
};
// 获取基本信息
......@@ -529,6 +455,32 @@ onMounted(() => {
height: 880px;
display: flex;
.progress-header-btns {
display: flex;
gap: 8px;
.btn {
height: 28px;
padding: 0 12px;
box-sizing: border-box;
border: 1px solid var(--btn-plain-border-color);
border-radius: 4px;
background: var(--btn-plain-bg-color);
color: var(--btn-plain-text-color);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 26px;
cursor: pointer;
}
.btnActive {
border: 1px solid var(--btn-active-border-color);
background: var(--btn-active-bg-color);
color: var(--btn-active-text-color);
}
}
.box-header {
height: 56px;
display: flex;
......@@ -913,17 +865,6 @@ onMounted(() => {
left: 50%;
transform: translateX(-50%);
z-index: 99;
.btn-more {
width: 108px;
height: 32px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
}
}
}
......@@ -1007,6 +948,13 @@ onMounted(() => {
.info-left {
cursor: pointer;
.person-avatar {
width: 128px;
height: 128px;
border-radius: 50%;
object-fit: cover;
}
img {
width: 128px;
height: 128px;
......@@ -1117,28 +1065,10 @@ onMounted(() => {
display: inline-block;
}
.status0 {
border: 1px solid rgba(217, 247, 190, 1);
color: rgba(82, 196, 26, 1);
background: rgba(246, 255, 237, 1);
}
.status1 {
border: 1px solid rgba(186, 224, 255, 1);
color: rgba(22, 119, 255, 1);
background: rgba(230, 244, 255, 1);
}
.status2 {
border: 1px solid rgba(255, 241, 184, 1);
color: rgba(250, 173, 20, 1);
background: rgba(255, 251, 230, 1);
}
.status3 {
border: 1px solid rgba(255, 204, 199, 1);
color: rgba(255, 77, 79, 1);
background: rgba(255, 241, 240, 1);
.status {
// border: 1px solid rgba(217, 247, 190, 1);
color: rgb(5, 95, 194);
background: rgb(231, 243, 255);
}
}
......@@ -1156,37 +1086,19 @@ onMounted(() => {
.title {
margin-left: 12px;
height: 22px;
color: rgba(95, 101, 108, 1);
height: 24px;
color: rgb(59, 65, 75);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 600;
line-height: 22px;
font-size: 18px;
font-weight: 700;
line-height: 24px;
}
}
.right-main-box3-main {
margin-top: 18px;
height: 412px;
overflow-y: auto;
}
.right-main-box3-footer {
margin-top: 1px;
display: flex;
justify-content: center;
.btn-more {
width: 108px;
height: 32px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
}
}
}
}
......
<template>
<!-- 资本规模组件 -->
<el-space :size="24">
<!-- 遍历资本规模数据 -->
<div v-for="(t, i) in scales" :key="i" class="item-box">
<!-- 标题 -->
<div class="item-title">{{ t.title }}</div>
<!-- 数值区域 -->
<el-space :size="6">
<!-- 数值图标 -->
<div class="item-value-img" />
<!-- 数值 -->
<div class="item-value">
{{ t.value }}
</div>
</el-space>
</div>
</el-space>
</template>
<script setup>
// 导入Vue组合式API
import { ref, watch } from 'vue'
// 导入Element Plus组件
import { ElSpace } from 'element-plus'
// 响应式数据
const scales = ref([]) // 资本规模数据列表
// 定义组件属性
const props = defineProps({
enterpriseInfo: {
type: Object,
default: {}
}
});
// 监听企业信息变化,更新资本规模数据
watch(() => props.enterpriseInfo, (newVal, oldVal) => {
// 如果没有年份信息,直接返回
if (!newVal?.year)
return
const scales1 = []
// 添加营业额数据
if (newVal.turnover) {
scales1.push({
title: newVal.year + '年营业额',
// 文字转数字,保留整数,添加单位
value: Number(newVal.turnover).toFixed(0) + '亿'
})
}
// 添加总资产数据
if (newVal.totalAssets) {
scales1.push({
title: newVal.year + '年总资产',
// 文字转数字,保留整数,添加单位
value: Number(newVal.totalAssets).toFixed(0) + '亿'
})
}
// 添加净资产数据
if (newVal.netAssets) {
scales1.push({
title: newVal.year + '年净资产',
// 文字转数字,保留整数,添加单位
value: Number(newVal.netAssets).toFixed(0) + '亿'
})
}
// 更新资本规模数据
scales.value = scales1
}, { immediate: true }) // immediate: true 表示组件挂载时立即执行
</script>
<style lang="scss" scoped>
// 导入通用样式
@use '@/styles/common.scss';
/* 项目盒子样式 */
.item-box {
white-space: nowrap; // 禁止换行
text-align: right; // 右对齐
}
/* 项目标题样式 */
.item-title {
@extend .text-tip-1;
color: var(--text-primary-80-color);
}
/* 项目数值样式 */
.item-value {
@extend .text-title-0-bold;
color: var(--color-primary-100);
}
/* 项目数值图标样式 */
.item-value-img {
width: 8px;
height: 6px;
background-image: url(../images/Regular_polygon_11097_225086.png);
background-size: 100% 100%;
background-repeat: no-repeat;
position: relative;
flex-shrink: 0; // 防止收缩
}
</style>
\ No newline at end of file
<template>
<!-- 企业基本信息组件 -->
<analysis-box title="基本信息" :showAllBtn="false">
<div class="box-wrap">
<!-- 企业图片 -->
<el-image :src="enterpriseInfo.picture" class="company-picture" />
<!-- 企业基本信息描述 -->
<el-descriptions title='' :column="1" class="common-descriptions">
<el-descriptions-item label="成立时间:">{{ enterpriseInfo.establishmentDate }}</el-descriptions-item>
<el-descriptions-item label="总部地址:">{{ enterpriseInfo.address }}</el-descriptions-item>
<el-descriptions-item label="联系方式:">{{ enterpriseInfo.telephone }}</el-descriptions-item>
<el-descriptions-item label="企业类型:">{{ enterpriseInfo.companyType }}</el-descriptions-item>
<el-descriptions-item label="业务范围:">{{ enterpriseInfo.businessScope }}</el-descriptions-item>
<el-descriptions-item label="分支机构:">
<div style="margin-left: 86px;">
<li v-for="(t, i) in branchs" :key="i">{{ t.orgName }}</li>
</div>
</el-descriptions-item>
</el-descriptions>
<!-- 分隔线 -->
<el-divider></el-divider>
<!-- 关键人物标题 -->
<div class="text-tip-1-bold" style="margin-bottom: 19px;">关键人物:</div>
<!-- 关键人物列表 -->
<el-space wrap>
<person-avatar style="width: 200px;" v-for="(t, i) in persons" :key="i" :person="t"></person-avatar>
</el-space>
</div>
</analysis-box>
</template>
<script setup>
// 导入组件
import AnalysisBox from '@/components/base/boxBackground/analysisBox.vue';
import { ref, watch } from 'vue';
import { getEnterpriseBranch, getEnterpriseKeyPerson } from '@/api/companyPages';
import PersonAvatar from '@/components/base/people/personAvatar.vue';
import { ElDescriptions, ElDescriptionsItem, ElDivider, ElImage, ElSpace } from 'element-plus';
import '@/styles/descriptions.scss'
// 定义组件属性
const props = defineProps({
enterpriseInfo: {
type: Object,
default: {}
}
});
// 响应式数据
const branchs = ref([]) // 分支机构列表
const persons = ref([]) // 关键人物列表
/**
* 获取企业相关数据
* @param {string} id - 企业ID
*/
const featchData = async (id) => {
// 获取分支机构数据
var res = await getEnterpriseBranch(id);
if (res?.code === 200) {
branchs.value = res.data;
}
// 获取关键人物数据
res = await getEnterpriseKeyPerson(id);
if (res?.code === 200) {
persons.value = res.data;
}
}
// 监听企业信息变化,当企业信息更新时重新获取数据
watch(() => props.enterpriseInfo, async (newVal, oldVal) => {
if (newVal) {
await featchData(newVal.id)
}
}, { immediate: true }) // immediate: true 表示组件挂载时立即执行
</script>
<style lang="css" scoped>
/* 容器样式 */
.box-wrap {
margin: 25px;
}
/* 企业图片样式 */
.company-picture {
border-radius: 4px;
margin-bottom: 16px;
}
</style>
\ No newline at end of file
<template>
<!-- 企业最新动态组件 -->
<analysis-box title="最新动态" :showAllBtn="false">
<!-- 顶部分隔线 -->
<el-divider></el-divider>
<!-- 新闻列表 -->
<el-space :size="0" direction="vertical">
<news-item class="list-item" v-for="(t, i) in newsPage.content" :key="i" :news="t"></news-item>
</el-space>
<!-- 底部分隔线 -->
<el-divider></el-divider>
<!-- 分页组件 -->
<el-pagination style="margin: 25px;" background layout="total, ->, prev, pager, next"
:total="newsPage.totalElements" v-on:current-change="onCurrentChange">
</el-pagination>
</analysis-box>
</template>
<script setup>
// 导入API
import { getEnterpriseNewDynamicPage } from '@/api/companyPages';
// 导入组件
import AnalysisBox from '@/components/base/boxBackground/analysisBox.vue';
import NewsItem from '@/components/base/newsList/NewsItem.vue';
import { ElDivider, ElSpace, ElPagination } from 'element-plus';
// 导入Vue组合式API
import { ref, watch } from 'vue';
// 响应式数据
const newsPage = ref({}) // 新闻分页数据
// 定义组件属性
const props = defineProps({
enterpriseInfo: {
type: Object,
default: {}
}
});
/**
* 更新新闻列表
* @param {string} id - 企业ID
* @param {number} page - 页码(从0开始)
*/
const updateNews = async (id, page) => {
// 获取企业最新动态分页数据
const res = await getEnterpriseNewDynamicPage(`${id}?pageNumber=${page}`);
if (res?.code === 200) {
// 处理新闻数据,添加来源信息
res.data?.content?.forEach(t => {
t.from = `${t.time} · ${t.orgName}`
});
// 更新新闻分页数据
newsPage.value = res.data;
}
}
// 监听企业信息变化,当企业信息更新时重新获取新闻
watch(() => props.enterpriseInfo, async (newVal, oldVal) => {
if (newVal) {
await updateNews(newVal.id, 0) // 默认从第0页开始
}
}, { immediate: true }) // immediate: true 表示组件挂载时立即执行
/**
* 分页变化处理函数
* @param {number} e - 当前页码(从1开始)
*/
const onCurrentChange = e => {
console.log(e) // 打印当前页码
updateNews(props.enterpriseInfo.id, e - 1) // 转换为从0开始的页码
}
</script>
<style lang="css" scoped>
/* 新闻列表项样式 */
.list-item {
margin-bottom: 20px;
/* 底部外边距 */
border-bottom: 1px solid rgba(240, 242, 244, 1);
/* 底部边框 */
}
</style>
\ No newline at end of file
<script setup lang="ts">
import '@/styles/tabs.scss'
import { ElTabPane, ElTabs } from 'element-plus';
</script>
<template>
<el-tabs tabPosition="left" class="disinheritance tabs-nav-no-wrap left-float-nav-tabs">
<el-tab-pane label="企业规模"></el-tab-pane>
<el-tab-pane label="市值变化"></el-tab-pane>
<el-tab-pane label="研发投入"></el-tab-pane>
<el-tab-pane label="市场占比"></el-tab-pane>
</el-tabs>
</template>
\ No newline at end of file
<template>
<!-- 企业标题面板组件 -->
<div class="box background-as-card">
<!-- 企业Logo -->
<img v-if="enterpriseInfo.logoUrl" :src="enterpriseInfo.logoUrl" alt="logo" class="company-logo" />
<!-- 企业信息区域 -->
<el-space fill :size="4">
<!-- 企业名称 -->
<div class="company-name">{{ enterpriseInfo.orgName }}</div>
<!-- 企业英文名称 -->
<div class="company-name2">{{ enterpriseInfo.orgNameEn }}</div>
<!-- 企业简介 -->
<div class="company-name2">{{ enterpriseInfo.orgIntroduction }}</div>
<!-- 供应区域标签 -->
<el-space>
<area-tag v-for="(t, i) in areas" :key="i" :tagName="t.name"></area-tag>
</el-space>
</el-space>
<capital-scale :enterpriseInfo="enterpriseInfo"></capital-scale>
</div>
</template>
<script setup>
// 导入组件
import AreaTag from '@/components/base/AreaTag/index.vue';
// 导入API
import { getSupplyAreaList } from '@/api/companyPages';
// 导入Vue组合式API
import { ref, watch } from 'vue';
import { ElSpace } from 'element-plus';
// 导入自定义组件
import CapitalScale from './capitalScale.vue'
// 响应式数据
const areas = ref([]) // 供应区域列表
// 定义组件属性
const props = defineProps({
enterpriseInfo: {
type: Object,
default: {}
}
});
// 监听企业信息变化,当企业信息更新时重新获取供应区域
watch(() => props.enterpriseInfo, async (newVal, oldVal) => {
if (newVal) {
await initAreas(newVal.id)
}
})
/**
* 初始化供应区域列表
* @param {string} id - 企业ID
*/
const initAreas = async (id) => {
// 获取供应区域数据
const res = await getSupplyAreaList(id);
if (res?.code === 200) {
// 更新供应区域列表
areas.value = res.data;
}
}
</script>
<style lang="scss" scoped>
// 导入通用样式
@use '@/styles/common.scss';
/* 容器样式 */
.box {
width: 100%;
height: 160px;
top: 80px;
left: 160px;
padding: 16px 19px;
border-radius: 10px;
display: flex;
align-items: center;
}
/* 企业Logo样式 */
.company-logo {
width: 128px;
height: 128px;
margin-right: 21px;
object-fit: contain;
}
/* 企业名称样式 */
.company-name {
@extend .text-title-1-bold;
color: var(--text-primary-80-color);
}
/* 企业英文名称和简介样式 */
.company-name2 {
@extend .text-tip-1;
color: var(--text-primary-80-color);
@include common.text-ellipsis(2); // 最多显示2行,超出部分省略
}
</style>
\ No newline at end of file
<template>
<div class="background-container"
:style="{ backgroundImage: `linear-gradient(to bottom, var(--bg-white-80), var(--bg-white-100)), url(${enterpriseInfo.picture})` }">
</div>
<el-scrollbar>
<div class="common-page">
<el-space wrap :size="16">
<title-pane :enterprise-info="enterpriseInfo"></title-pane>
<el-tabs stretch class="tabs-header-as-card tabs-nav-no-wrap tabs-bar-as-btn">
<el-tab-pane label="企业详情">
<div class="flex-display">
<news-pane :enterprise-info="enterpriseInfo" />
<base-info class="base-info" :enterprise-info="enterpriseInfo" />
</div>
</el-tab-pane>
<el-tab-pane lazy label="经营情况">
<operating-pages />
</el-tab-pane>
<el-tab-pane lazy label="供应链 / 股权">
<div class="flex-display">
</div>
</el-tab-pane>
</el-tabs>
</el-space>
</div>
</el-scrollbar>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { getEnterprisePageInfo } from '@/api/companyPages';
import TitlePane from './component/titlePane.vue';
import NewsPane from './component/detailsPages/newsPane.vue';
import BaseInfo from './component/detailsPages/baseInfo.vue';
import OperatingPages from './component/operatingPages/index.vue';
import '@/styles/tabs.scss'
import '@/styles/container.scss'
import { ElScrollbar, ElSpace, ElTabs, ElTabPane } from 'element-plus';
const route = useRoute();
const companyId = route.params.id;
const enterpriseInfo = ref({})
console.log(companyId)
onMounted(() => {
init();
});
const init = async () => {
const res = await getEnterprisePageInfo(companyId);
if (res?.code === 200) {
enterpriseInfo.value = res.data
}
}
</script>
<style lang="scss" scoped>
.background-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 383px;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
z-index: -1;
}
.base-info {
max-width: 520px;
width: 520px;
margin-left: 16px;
}
</style>
\ No newline at end of file
......@@ -222,7 +222,7 @@ const warningList = ref([
// 查看更多风险信号
const handleToMoreRiskSignal = () => {
const route = router.resolve("/riskSignal");
const route = router.resolve("/viewRiskSignal");
window.open(route.href, "_blank");
};
</script>
......
......@@ -541,7 +541,7 @@ const handleClickToDetail = university => {
// 查看更多风险信号
const handleToMoreRiskSignal = () => {
const route = router.resolve("/riskSignal");
const route = router.resolve("/viewRiskSignal");
window.open(route.href, "_blank");
};
......
......@@ -1548,7 +1548,7 @@ const handleClickToSurveyDetail = id => {
// 查看更多风险信号
const handleToMoreRiskSignal = () => {
const route = router.resolve("/riskSignal");
const route = router.resolve("/viewRiskSignal");
window.open(route.href, "_blank");
};
......
......@@ -225,7 +225,7 @@ const handleToSearch = () => {
// 查看更多风险信号
const handleToMoreRiskSignal = () => {
const route = router.resolve("/riskSignal");
const route = router.resolve("/viewRiskSignal");
window.open(route.href, "_blank");
};
......
......@@ -196,7 +196,7 @@ const handleToRiskDetail = (item) => {
// 查看更多动态
const handleToMoreRiskSignal = () => {
const route = router.resolve("/riskSignal");
const route = router.resolve("/viewRiskSignal");
window.open(route.href, "_blank");
};
......
......@@ -150,7 +150,7 @@ const handleGetRiskSignal = async () => {
// 查看更多风险信号
const handleToMoreRiskSignal = () => {
const route = router.resolve("/riskSignal");
const route = router.resolve("/viewRiskSignal");
window.open(route.href, "_blank");
};
const box1Data = ref([])
......
......@@ -839,7 +839,7 @@ const handleClickCate = cate => {
// 查看更多风险信号
const handleToMoreRiskSignal = () => {
const route = router.resolve("/riskSignal");
const route = router.resolve("/viewRiskSignal");
window.open(route.href, "_blank");
};
......
......@@ -1351,7 +1351,7 @@ const handleClick = tank => {
// 查看更多风险信号
const handleToMoreRiskSignal = () => {
const route = router.resolve("/riskSignal");
const route = router.resolve("/viewRiskSignal");
window.open(route.href, "_blank");
};
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论