提交 e785c522 authored 作者: caijian's avatar caijian

Merge branch 'cj_dev'

......@@ -14,6 +14,8 @@
"@microsoft/fetch-event-source": "^2.0.1",
"@traptitech/markdown-it-katex": "^3.6.0",
"axios": "^1.12.2",
"d3": "^7.9.0",
"d3-cloud": "^1.2.7",
"echarts": "^5.4.3",
"echarts-liquidfill": "^3.1.0",
"echarts-wordcloud": "^2.1.0",
......@@ -2364,6 +2366,21 @@
"node": ">=12"
}
},
"node_modules/d3-cloud": {
"version": "1.2.7",
"resolved": "https://registry.npmmirror.com/d3-cloud/-/d3-cloud-1.2.7.tgz",
"integrity": "sha512-8TrgcgwRIpoZYQp7s3fGB7tATWfhckRb8KcVd1bOgqkNdkJRDGWfdSf4HkHHzZxSczwQJdSxvfPudwir5IAJ3w==",
"license": "BSD-3-Clause",
"dependencies": {
"d3-dispatch": "^1.0.3"
}
},
"node_modules/d3-cloud/node_modules/d3-dispatch": {
"version": "1.0.6",
"resolved": "https://registry.npmmirror.com/d3-dispatch/-/d3-dispatch-1.0.6.tgz",
"integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==",
"license": "BSD-3-Clause"
},
"node_modules/d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmmirror.com/d3-color/-/d3-color-3.1.0.tgz",
......
......@@ -23,6 +23,8 @@
"@microsoft/fetch-event-source": "^2.0.1",
"@traptitech/markdown-it-katex": "^3.6.0",
"axios": "^1.12.2",
"d3": "^7.9.0",
"d3-cloud": "^1.2.7",
"echarts": "^5.4.3",
"echarts-liquidfill": "^3.1.0",
"echarts-wordcloud": "^2.1.0",
......
......@@ -27,6 +27,7 @@
<div class="tech-tags">
<el-tag type="primary" size="small" v-for="tag in props.reportSummary.researchTypes" :key="tag">{{ tag }}</el-tag>
</div>
<WordCloud :words="props.reportSummary.researchTypes" />
</div>
</div>
</el-col>
......@@ -51,8 +52,8 @@
<!-- 中间:标题和内容 -->
<div class="item-main">
<h4 class="item-title">{{ item.title }}</h4>
<p class="item-content">{{ item.content }}</p>
<h4 class="item-title">{{ item.content }}</h4>
<p class="item-content">{{ item.econtent }}</p>
</div>
<!-- 右侧:标签 -->
......@@ -93,6 +94,8 @@
import { ref } from 'vue'
import { Paperclip } from '@element-plus/icons-vue'
import CardTitle from '@/components/CardTitle.vue'
import { mockMainContentList } from '../mockData'
import WordCloud from './WordCloud.vue'
const props = defineProps({
reportSummary: {
......@@ -148,71 +151,7 @@ const updatePagination = (apiResponse) => {
}
}
const mainContentList = ref([
{
id: 1,
title: '主要内容1',
content: '主要内容1',
econtent: 'main content one',
serialNum: 1,
tags: [
{ name: '出口管制', type: 'danger' },
{ name: '资本管制', type: 'warning' },
{ name: '技术封锁', type: 'danger' }
]
},
{
id: 2,
title: '主要内容2',
content: '主要内容2',
econtent: 'main content two',
serialNum: 2,
tags: [
{ name: '金融制裁', type: 'danger' }
]
},
{
id: 3,
title: '主要内容3',
content: '主要内容3',
econtent: 'main content three',
serialNum: 3,
tags: [
{ name: '资本管制', type: 'warning' }
]
},
{
id: 4,
title: '主要内容4',
content: '主要内容4',
econtent: 'main content four',
serialNum: 4,
tags: [
{ name: '对台军售', type: 'warning' }
]
},
{
id: 5,
title: '主要内容5',
content: '主要内容5',
econtent: 'main content five',
serialNum: 5,
tags: [
{ name: '出口管制', type: 'danger' }
]
},
{
id: 6,
title: '主要内容6',
content: '主要内容6',
econtent: 'main content six',
serialNum: 6,
tags: [
{ name: '关税贸易', type: 'primary' },
{ name: '供应链打击', type: 'warning' }
]
}
])
const mainContentList = ref(mockMainContentList)
</script>
<style scoped>
......@@ -261,6 +200,8 @@ const mainContentList = ref([
.tech-tags {
display: flex;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 10px;
}
.tag-row {
......
......@@ -45,31 +45,29 @@
<div class="card-body">
<div class="policy-list">
<div
v-for="(item, index) in props.policy"
v-for="(item, index) in policyList"
:key="index"
class="policy-item"
@click="openPolicyDetail(item)"
>
<div class="policy-number">{{ index + 1 }}</div>
<div class="policy-content">
<p class="policy-text">{{ item.content }}</p>
<!-- <div class="policy-tags">
<el-tag size="small">{{ item.category }}</el-tag>
<el-tag size="small">{{ item.subcategory }}</el-tag>
</div> -->
<!-- <div class="policy-status">
<div class="status-info">
<span class="status-label">相关立法已通过:</span>
<span class="status-bill">{{ item.relatedBill }}</span>
<el-tag
:type="getStatusType(item.status)"
size="small"
class="status-tag"
>
{{ item.status }}
</el-tag>
<p class="policy-text">{{ item.text }}</p>
<div class="policy-tags">
<el-tag size="small" v-for="tag in item.tags" :key="tag">{{ tag }}</el-tag>
</div>
<div class="policy-related-bill" v-if="getRelatedBills(item).length > 0">
<div
v-for="(bill, billIndex) in getRelatedBills(item)"
:key="billIndex"
class="bill-item"
>
<span class="bill-tag">法案</span>
<span class="bill-year">{{ bill.year }}</span>
<span class="bill-title">{{ bill.title }}</span>
<el-icon class="bill-arrow"><ArrowRight /></el-icon>
</div>
</div> -->
</div>
</div>
<div class="policy-status">
<el-tag :type="getStatusType(item.status)" size="small">{{ item.status }}</el-tag>
......@@ -201,49 +199,76 @@ const selectedPolicy = ref(null)
const policyList = ref([
{
text: '允许OPT的国际学生出国旅行并持多次入境签证重新进入美国。',
category: '人才交流',
tags: ['人才交流', '移民政策'],
subcategory: '移民政策',
relatedBill: '2024重塑美国人口结构法案',
relatedBills: [
{ year: '2024', title: '重塑美国人口结构法案' },
{ year: '2025', title: '开放人才法案' }
],
status: '已实施',
detailedDescription: '当前基于就业的绿卡上限设定为140,000个。每个国家的上限设定为总数的7%。这意味着每年只有大约9,800名在美国的中国工人可以通过就业优先类别成为合法永久居民。这个上限造成了符合要求的中国申请者的积压,他们必须等待多年才能获得绿卡批准。在这种情况中,高技能移民报告他们有意愿离开第三国或返回原籍国。美国可以从自己1992年通过的《华人学生保护法》中汲取训练。该法案使某些中国公民免于上限和其他要求。因此,54,000名中国移民住于了这个机会。受过教育的中国移民的回归率较低于今天,尽管有美国移民身份可以让他们提高工人在中国劳动力市场的价值并降低回中国的风险来同时间注,但持有绿卡可以对回归的效果太大,因为维持绿卡需要满足国际任务要求。'
},
{
text: '增加中国公民可获得 H-1B 签证数量。',
category: '人才交流',
tags: ['人才交流', '移民政策'],
subcategory: '移民政策',
relatedBill: '2024调整签证政策以吸纳外国重点领域人才法案',
relatedBills: [
{ year: '2024', title: '调整签证政策以吸纳外国重点领域人才法案' }
],
status: '部分实施'
},
{
text: '通过就业偏好类别增加卡的数量。',
category: '人才交流',
tags: ['人才交流', '移民政策'],
subcategory: '移民政策',
relatedBill: '2024重塑美国人口结构法案',
relatedBills: [
{ year: '2024', title: '重塑美国人口结构法案' }
],
status: '已实施'
},
{
text: '推动清洁能源生产的内,化石燃料重新配置出口。',
category: '人才交流',
tags: ['人才交流', '移民政策'],
subcategory: '移民政策',
relatedBill: '',
relatedBills: [],
status: '未实施'
},
{
text: '支持国内核工业商业化扩张。',
category: '人才交流',
tags: ['人才交流', '移民政策'],
subcategory: '移民政策',
relatedBill: '2024重塑美国人口结构法案',
relatedBills: [
{ year: '2024', title: '重塑美国人口结构法案' }
],
status: '已实施'
},
{
text: '在美国和友好国家建立关键矿产加工能力',
category: '人才交流',
tags: ['人才交流', '移民政策'],
subcategory: '移民政策',
relatedBill: '2024重塑美国人口结构法案',
relatedBills: [
{ year: '2024', title: '重塑美国人口结构法案' },
{ year: '2025', title: '开放人才法案' }
],
status: '已实施'
}
])
// 获取相关法案列表(兼容旧数据格式)
const getRelatedBills = (item) => {
if (item.relatedBills && Array.isArray(item.relatedBills)) {
return item.relatedBills
}
// 兼容旧格式:relatedBill 字符串
if (item.relatedBill) {
const match = item.relatedBill.match(/^(\d{4})(.+)$/)
if (match) {
return [{ year: match[1], title: match[2] }]
}
}
return []
}
// 相关政策动态数据
const policyDynamics = ref([
{
......@@ -327,7 +352,7 @@ const closeDetailModal = () => {
<style scoped>
.policy-tracking {
/* padding: 20px 0; */
padding: 0;
}
.policy-card,
......@@ -447,6 +472,68 @@ const closeDetailModal = () => {
margin-bottom: 12px;
}
.policy-related-bill {
display: flex;
gap: 12px;
flex-wrap: wrap;
margin-top: 8px;
}
.bill-item {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 10px;
background: #fff;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
}
.bill-item:hover {
background: #f5f7fa;
}
.bill-tag {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 2px 8px;
background: #a8d5ff;
color: #fff;
font-size: 12px;
font-weight: 500;
border-radius: 3px;
white-space: nowrap;
}
.bill-year {
font-size: 13px;
font-weight: 500;
color: #1e3a8a;
white-space: nowrap;
}
.bill-title {
font-size: 13px;
font-weight: 500;
color: #1e3a8a;
white-space: nowrap;
}
.bill-arrow {
width: 18px;
height: 18px;
background: #a8d5ff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #1e3a8a;
font-size: 12px;
flex-shrink: 0;
}
.policy-status {
/* background: #f8f9fa; */
padding: 8px 12px;
......
<template>
<div class="word-cloud-container">
<svg :width="width" :height="height" ref="svgRef">
</svg>
<div v-if="!words || words.length === 0" class="no-data-message">
{{ emptyText }}
</div>
</div>
</template>
<script>
import { defineComponent, ref, watch, onMounted, nextTick } from 'vue';
import * as d3 from 'd3';
import cloud from 'd3-cloud';
// 默认颜色数组,您可以根据需要扩展
const defaultColors = [
'#f56c6c', // 红色
'#e6a23c', // 橙色
'#67c23a', // 绿色
'#409eff', // 蓝色
'#909399', // 灰色
'#b3a2c7', // 紫色
'#49a37e', // 军绿
];
export default defineComponent({
name: 'WordCloud',
props: {
// 词汇数组,例如:['通用人工智能', 'AI芯片', '出口管制']
words: {
type: Array,
required: true,
default: () => [],
},
// 词云容器的宽度
width: {
type: [Number, String],
default: 600,
},
// 词云容器的高度
height: {
type: [Number, String],
default: 400,
},
// 词汇的最小字号
minFontSize: {
type: Number,
default: 16,
},
// 词汇的最大字号
maxFontSize: {
type: Number,
default: 50,
},
// 词汇颜色数组
colors: {
type: Array,
default: () => defaultColors,
},
// 词汇为空时的提示文本
emptyText: {
type: String,
default: '暂无词云数据',
},
},
setup(props) {
const svgRef = ref(null);
/**
* @description 根据词汇数组,计算词频,并转换成d3-cloud所需的格式
* @param {Array<string>} rawWords 原始词汇数组
* @returns {Array<{text: string, size: number}>} 转换后的数据
*/
const prepareData = (rawWords) => {
if (!rawWords || rawWords.length === 0) return [];
// 1. 计算词频
const wordCounts = rawWords.reduce((acc, word) => {
acc[word] = (acc[word] || 0) + 1;
return acc;
}, {});
// 2. 转换为d3-cloud所需的格式,并找出最大/最小词频
let minCount = Infinity;
let maxCount = -Infinity;
const data = Object.entries(wordCounts).map(([text, count]) => {
if (count < minCount) minCount = count;
if (count > maxCount) maxCount = count;
return { text, count };
});
// 3. 将词频映射到字号范围
const sizeScale = d3
.scaleLinear()
.domain([minCount, maxCount])
.range([props.minFontSize, props.maxFontSize]);
return data.map((d) => ({
...d,
size: sizeScale(d.count), // size就是字号
}));
};
/**
* @description 绘制词云
* @param {Array<{text: string, size: number, x: number, y: number, rotate: number}>} words 布局后的词汇数据
*/
const drawCloud = (words) => {
const svg = d3.select(svgRef.value);
// 清空SVG内容
svg.selectAll('*').remove();
// 创建一个<g>元素并平移到中心
const g = svg
.append('g')
.attr(
'transform',
`translate(${props.width / 2}, ${props.height / 2})`
);
// 绑定数据并创建<text>元素
const wordElements = g.selectAll('text').data(words, (d) => d.text);
// 进入(Enter)阶段:添加新的<text>元素
wordElements
.enter()
.append('text')
.style('font-size', (d) => `${d.size}px`)
.style('fill', (_, i) => props.colors[i % props.colors.length]) // 循环使用颜色
.attr('text-anchor', 'middle') // 文本居中
// *********** 关键修改:移除悬浮样式和交互,保持水平布局 ***********
.attr('transform', (d) => `translate(${d.x}, ${d.y})`) // 移除rotate属性
.text((d) => d.text);
// ************************************************************
// 退出(Exit)阶段:移除多余的<text>元素(如果更新时词汇减少)
wordElements.exit().remove();
};
/**
* @description 启动d3-cloud布局引擎
* @param {Array<{text: string, count: number, size: number}>} data 待布局的词汇数据
*/
const generateLayout = (data) => {
if (!data || data.length === 0) {
d3.select(svgRef.value).selectAll('*').remove();
return;
}
const layout = cloud()
.size([props.width, props.height]) // 词云的尺寸
.words(data) // 传入词汇数据
.padding(5) // 词汇之间的最小间距
// *********** 关键修改:固定旋转角度为 0,实现水平布局 ***********
.rotate(0)
// ************************************************************
.font('Impact') // 字体
.fontSize((d) => d.size) // 使用计算出的字号
.on('end', drawCloud); // 布局计算完成后调用drawCloud
layout.start(); // 启动布局
};
/**
* @description 核心渲染函数,处理数据并启动布局
*/
const renderWordCloud = () => {
// 保证在DOM更新后执行
nextTick(() => {
const processedData = prepareData(props.words);
generateLayout(processedData);
});
};
onMounted(renderWordCloud);
// 监听props变化,重新渲染词云
watch(() => [props.words, props.width, props.height, props.minFontSize, props.maxFontSize], () => {
renderWordCloud();
}, { deep: true });
return {
svgRef,
renderWordCloud,
};
},
});
</script>
<style lang="scss">
.word-cloud-container {
display: flex;
justify-content: center;
align-items: center;
position: relative;
width: v-bind(width + 'px'); // 动态绑定宽度
height: v-bind(height + 'px'); // 动态绑定高度
border: 1px solid #ebeef5;
border-radius: 4px;
overflow: hidden;
// 词云SVG的样式
svg {
display: block; // 移除底部空白
}
// 词汇文本的通用样式
text {
font-weight: bold;
// *********** 关键修改:移除transition和cursor,避免交互 ***********
}
.no-data-message {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 16px;
color: #909399;
background-color: #f5f7fa;
}
}
</style>
\ No newline at end of file
......@@ -4,18 +4,37 @@
<header class="report-header">
<div class="header-container">
<div class="header-content">
<div class="title-area">
<div class="source-info">
<!-- <img src="/placeholder.svg?height=40&width=40" alt="智库logo" class="source-logo"> -->
<span class="source-name">{{ reportSummary.thinkTankName }}</span>
<!-- 左侧封面图片 -->
<div class="cover-image-area">
<div class="book-cover">
<div class="cover-title">{{ reportSummary.name }}</div>
<div class="cover-subtitle">{{ reportSummary.ename }}</div>
<div class="cover-globe"></div>
</div>
</div>
<!-- 中间标题区域 -->
<div class="title-area">
<h1 class="main-title">{{ reportSummary.name }}</h1>
<h2 class="sub-title">{{ reportSummary.ename }}</h2>
<div class="tags-area">
<el-tag type="primary" size="small" v-for="tag in reportSummary.tags" :key="tag">{{ tag }}</el-tag>
<span
v-for="(tag, index) in reportSummary.tags"
:key="tag"
class="tag-item"
:class="{ 'tag-primary': index % 2 === 0, 'tag-danger': index % 2 === 1 }"
>
{{ tag }}
</span>
</div>
</div>
<!-- 右侧元信息 -->
<div class="meta-info">
<div class="source-info">
<el-icon class="source-icon"><TrendCharts /></el-icon>
<span class="source-name">{{ reportSummary.thinkTankName }}</span>
</div>
<div class="publish-date">{{ reportSummary.times }}</div>
</div>
</div>
......@@ -41,14 +60,14 @@
</span>
</template>
</el-tab-pane>
<el-tab-pane label="影响分析" name="analysis">
<!-- <el-tab-pane label="影响分析" name="analysis">
<template #label>
<span class="tab-label">
<el-icon><TrendCharts /></el-icon>
影响分析
</span>
</template>
</el-tab-pane>
</el-tab-pane> -->
</el-tabs>
<div class="action-buttons">
......@@ -97,6 +116,7 @@ import {
getThinkTankReportPolicy
} from '@/api'
import { useRoute } from 'vue-router'
import { mockContent } from '../mockData'
// 引入组件
import Overview from './Overview.vue'
......@@ -113,6 +133,20 @@ const getReportSummary = async () => {
const { data } = await getThinkTankReportSummary({ id: route.params.id })
console.log('getReportSummary', data)
reportSummary.value = data
reportSummary.value = {
thinkTankName: '兰德公司',
name: '美国经济竞争分析',
ename: 'Analysis of US Economic Competition',
tags: ['美国', '经济竞争', '政治竞争', '军事竞争'],
times: '2025-11-27',
summary: mockContent,
researchTypes: ['人工智能',
'军事与安全',
'半导体与高科技',
'经济与贸易',
'国际规则与多边体系',
'地缘政治'],
}
}
const getContent = async () => {
......@@ -140,6 +174,7 @@ onMounted(() => {
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
min-height: 100vh;
width: 100%;
--max-width: 1650px;
}
/* Header Styles - 占满宽度 */
......@@ -151,71 +186,167 @@ onMounted(() => {
}
.header-container {
max-width: 1200px;
max-width: var(--max-width);
margin: 0 auto;
padding: 24px 24px 0;
padding: 32px 24px 0;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 24px;
}
.title-area {
flex: 1;
/* 左侧封面图片区域 */
.cover-image-area {
flex-shrink: 0;
}
.source-info {
.book-cover {
width: 88px;
height: 115px;
background: linear-gradient(135deg, #d4a574 0%, #c8965f 100%);
border-radius: 4px;
padding: 16px 12px;
display: flex;
align-items: center;
margin-bottom: 15px;
}
.source-logo {
width: 40px;
height: 40px;
border-radius: 8px;
margin-right: 10px;
flex-direction: column;
justify-content: space-between;
position: relative;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.source-name {
.cover-title {
font-size: 14px;
color: #666;
font-weight: 600;
color: #fff;
line-height: 1.3;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.cover-subtitle {
font-size: 10px;
color: rgba(255, 255, 255, 0.9);
line-height: 1.2;
margin-top: 4px;
}
.cover-globe {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
width: 60px;
height: 60px;
background: radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.3) 0%, transparent 70%);
border-radius: 50%;
opacity: 0.6;
}
.cover-globe::before {
content: '';
position: absolute;
top: 20%;
left: 30%;
width: 40%;
height: 30%;
background: rgba(255, 255, 255, 0.2);
border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
}
.cover-globe::after {
content: '';
position: absolute;
top: 50%;
right: 20%;
width: 35%;
height: 25%;
background: rgba(255, 255, 255, 0.15);
border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
}
/* 中间标题区域 */
.title-area {
flex: 1;
min-width: 0;
}
.main-title {
font-size: 24px;
font-weight: 600;
color: #333;
margin: 0 0 8px 0;
font-size: 28px;
font-weight: 700;
color: #2c3e50;
margin: 0 0 10px 0;
line-height: 1.4;
}
.sub-title {
font-size: 16px;
color: #666;
font-weight: normal;
margin: 0 0 15px 0;
line-height: 1.4;
color: #7f8c8d;
font-weight: 400;
margin: 0 0 16px 0;
line-height: 1.5;
}
.tags-area {
display: flex;
gap: 8px;
gap: 10px;
flex-wrap: wrap;
}
.tag-item {
display: inline-block;
padding: 4px 12px;
border-radius: 4px;
font-size: 13px;
font-weight: 500;
border: 1.5px solid;
background: transparent;
}
.tag-primary {
color: #409eff;
border-color: #409eff;
}
.tag-danger {
color: #f56c6c;
border-color: #f56c6c;
}
/* 右侧元信息 */
.meta-info {
flex-shrink: 0;
text-align: right;
color: #666;
font-size: 14px;
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 12px;
}
.publish-date {
.source-info {
display: flex;
align-items: center;
gap: 6px;
color: #606266;
}
.source-icon {
font-size: 18px;
color: #8B5CF6;
}
.source-name {
font-size: 14px;
color: #606266;
font-weight: 500;
}
.publish-date {
color: #606266;
font-size: 14px;
font-weight: 400;
}
/* Header Tabs区域 */
.header-tabs {
background-color: #fff;
......@@ -224,7 +355,7 @@ onMounted(() => {
}
.tabs-container {
max-width: 1200px;
max-width: var(--max-width);
margin: 0 auto;
padding: 0 24px;
display: flex;
......@@ -300,7 +431,7 @@ onMounted(() => {
}
.content-container {
max-width: 1200px;
max-width: var(--max-width);
width: 100%;
border-radius: 8px;
}
......@@ -328,12 +459,42 @@ onMounted(() => {
@media (max-width: 768px) {
.header-container {
padding: 16px 16px 0;
padding: 20px 16px 0;
}
.header-content {
flex-direction: column;
gap: 16px;
gap: 20px;
}
.cover-image-area {
align-self: center;
}
.book-cover {
width: 100px;
height: 140px;
}
.title-area {
text-align: center;
}
.main-title {
font-size: 22px;
}
.sub-title {
font-size: 14px;
}
.tags-area {
justify-content: center;
}
.meta-info {
align-items: center;
text-align: center;
}
.tabs-container {
......@@ -360,7 +521,52 @@ onMounted(() => {
@media (max-width: 480px) {
.header-container {
padding: 12px 12px 0;
padding: 16px 12px 0;
}
.book-cover {
width: 80px;
height: 120px;
padding: 12px 8px;
}
.cover-title {
font-size: 11px;
}
.cover-subtitle {
font-size: 8px;
}
.cover-globe {
width: 45px;
height: 45px;
bottom: 15px;
}
.main-title {
font-size: 20px;
}
.sub-title {
font-size: 13px;
}
.tag-item {
font-size: 12px;
padding: 3px 10px;
}
.source-icon {
font-size: 16px;
}
.source-name {
font-size: 13px;
}
.publish-date {
font-size: 13px;
}
.tabs-container {
......@@ -377,14 +583,6 @@ onMounted(() => {
padding: 12px;
}
.main-title {
font-size: 20px;
}
.sub-title {
font-size: 14px;
}
.action-buttons {
flex-wrap: wrap;
gap: 8px;
......
......@@ -66,7 +66,7 @@
</div>
<div class="subscription-box">
<h3>动态订阅1</h3>
<h3>动态订阅</h3>
<p>选择您感兴趣的研究领域,获取最新报告和相关书目。</p>
<el-button type="primary" style="width: 100%;">保存订阅设置</el-button>
</div>
......
......@@ -437,4 +437,118 @@ export const mockRandResearcherCategories = {
"中国": 8,
"其他": 6
}
}
\ No newline at end of file
}
export const mockMainContentList = [
{
"id": 1,
"title": "虽然表面上类似于西方私人公司,但中国私营公司与政府的联系更加紧密...",
"content": "虽然表面上类似于西方私人公司,但中国私营公司与政府的联系更加紧密,并且可以更多地获得政府资源。",
"econtent": "Although superficially resembling Western private companies, Chinese private companies are more tightly bound to...",
"serialNum": 1,
"tags": [
{ "name": "关税", "type": "default" },
{ "name": "跨境电商", "type": "default" }
]
},
{
"id": 2,
"title": "这些概念上的差异意味着,试图改变中国经济将很困难,中国私营企业可能需要与西方公司区别对待。",
"content": "这些概念上的差异意味着,试图改变中国经济将很困难,中国私营企业可能需要与西方公司区别对待。",
"econtent": "These conceptual differences mean that trying to change the Chinese economy will be difficult and that Chinese ...",
"serialNum": 2,
"tags": [
{ "name": "私有经济", "type": "default" }
]
},
{
"id": 3,
"title": "大多数强制性经济措施在实现战略目标方面都取得了有限的成功...",
"content": "大多数强制性经济措施在实现战略目标方面都取得了有限的成功,并影响了美国和盟国经济体。",
"econtent": "Most coercive economic measures have shown limited success in meeting their strategic objectives and have affected...",
"serialNum": 3,
"tags": [
{ "name": "技术封锁", "type": "danger" },
{ "name": "半导体", "type": "default" }
]
},
{
"id": 4,
"title": "合作措施没有改变这种关系,但已经实现了更有限的目标,也可能具有积极的外部性...",
"content": "合作措施没有改变这种关系,但已经实现了更有限的目标,也可能具有积极的外部性、成本更低。",
"econtent": "Cooperative measures have not modified the relationship but have achieved more circumscribed goals and may...",
"serialNum": 4,
"tags": [
{ "name": "关税", "type": "default" },
{ "name": "跨境电商", "type": "default" }
]
},
{
"id": 5,
"title": "自20世纪90年代中期以来,全球经济日益相互关联,这主要是因为越来越依赖中国作为许多国家的投入供应商。",
"content": "自20世纪90年代中期以来,全球经济日益相互关联,这主要是因为越来越依赖中国作为许多国家的投入供应商。",
"econtent": "The global economy has become increasingly interconnected since the mid-1990s, largely because of an increasing...",
"serialNum": 5,
"tags": [
{ "name": "关税", "type": "default" },
{ "name": "跨境电商", "type": "default" }
]
},
{
"id": 6,
"title": "这些概念上的差异意味着,试图改变中国经济将很困难...",
"content": "这些概念上的差异意味着,试图改变中国经济将很困难,中国私营企业可能需要与西方公司区别对待。",
"econtent": "These conceptual differences mean that trying to change the Chinese economy will be difficult and that Chinese ...",
"serialNum": 6,
"tags": [
{ "name": "关税", "type": "default" },
{ "name": "跨境电商", "type": "default" }
]
},
{
"id": 7,
"title": "中国学生返回中国可以通过加强生产力的经济联系来使美国受益...",
"content": "中国学生返回中国可以通过加强生产力的经济联系来使美国受益,但也可能引发对知识产权转让或盗窃的担忧...",
"econtent": "Return migration of Chinese students to China could benefit the United States by strengthening productivity...",
"serialNum": 7,
"tags": [
{ "name": "移民", "type": "default" },
{ "name": "知识产权", "type": "default" }
]
},
{
"id": 8,
"title": "美国和中国经济通过能源交织在一起,两国都寻求能源安全和环境安全。",
"content": "美国和中国经济通过能源交织在一起,两国都寻求能源安全和环境安全。",
"econtent": "The U.S. and Chinese economies are intertwined through energy, and both countries seek energy security and...",
"serialNum": 8,
"tags": [
{ "name": "能源", "type": "default" },
{ "name": "环境安全", "type": "default" }
]
},
{
"id": 9,
"title": "与盟国一起投资技术、降低与盟国的贸易成本...",
"content": "与盟国一起投资技术、降低与盟国的贸易成本,以及开发替代商品,可以与中国分离并确保生产网络安全的...",
"econtent": "Investments in technology with allies, lowering trade costs with allies, and developing alternative goods can be an...",
"serialNum": 9,
"tags": [
{ "name": "产业结构", "type": "default" }
]
},
{
"id": 10,
"title": "美国和中国经济通过能源交织在一起,两国都寻求能源安全和环境安全。",
"content": "美国和中国经济通过能源交织在一起,两国都寻求能源安全和环境安全。",
"econtent": "The U.S. and Chinese economies are intertwined through energy, and both countries seek energy security and...",
"serialNum": 10,
"tags": [
{ "name": "能源", "type": "default" },
{ "name": "环境安全", "type": "default" }
]
}
]
export const mockContent = ` 包括经济竞争在内的美中竞争自2017年以来一直在定义美国外交政策。这两个经济体是世界上第一和第二大国家经济体,并且深深交织在一起。改变关系,无论多么必要,可能是昂贵的。因此,美国面临着一项挑战,确保其经济在耦合的战略竞争条件下满足国家的需求。
为了应对这一挑战,兰德大学的研究人员对美中竞争进行了经济和制度分析,进行了参与式的远见练习,以了解确保美国经济健康的长期路径,并创建了两个经济竞争游戏,探索多个国家在相互交流的同时确保经济健康的动态...`
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论