提交 2708cffc authored 作者: yanpeng's avatar yanpeng

投融资部分内容上传

上级 ad95a2a1
import request from "@/api/request.js";
\ No newline at end of file
// import request from "@/api/request.js";
// import { ElMessage } from "element-plus";
// const request200 = requestP => {
// return requestP.then(data => {
// if (data.code === 200) {
// console.log('返回的数据结构 =>', data.data)
// return data.data;
// }
// ElMessage({
// message: data.message,
// type: "error",
// duration: 3 * 1000
// });
// return null;
// });
// };
// export function getDataCount() {
// return request200(
// request({
// method: "GET",
// // url: "/api/entitiesDataCount/countData",
// url: "/api/sanctionList/invFin/getTotalInfo"
// })
// );
// }
import { http } from "./service.js";
/**
* 总次数统计
*/
export function getDataCount() {
return http.get("/api/sanctionList/invFin/getTotalInfo");
}
/**
* 最新出口管制政策
* url:/sanctionList/invFin/getLatestEntityListInfo
*/
export function getLatestEntityListInfo() {
return http.get("/api/sanctionList/invFin/getLatestEntityListInfo");
}
/**
* 风险信号
* url:/commonFeature/riskSignal/{moduleId}
*/
export function getRiskSignal(moduleId='0104') {
return http.get(`/api/commonFeature/riskSignal/${moduleId}`);
}
/**
* 新闻资讯
* url:/commonFeature/news/{moduleId}
*/
export function getNewsInfo(moduleId='0104') {
return http.get(`/api/commonFeature/news/${moduleId}`);
}
/**
* 社交媒体信息
* url:/commonFeature/remarks/{moduleId}
*/
export function getSocialMediaInfo(moduleId='0104') {
return http.get(`/api/commonFeature/remarks/${moduleId}`);
}
/**
* 发布频度
* url:/entitiesDataCount/getAnnualCount
*/
export function getReleaseCount(id) {
return http.get(`/api/entitiesDataCount/getAnnualCount?sanTypeId=${id}`);
}
/**
* 制裁领域分析
* url:/entitiesDataCount/getSanDomainCount
*/
export function getSanDomainCount(sanTypeIds) {
return http.get(`/api/entitiesDataCount/getSanDomainCount?sanTypeIds=${sanTypeIds}`);
}
/**
* 制裁清单增长趋势
* url:/entitiesDataCount/getAnnualSanDomain
*/
export function getAnnualSanDomain(params) {
return http.post("/api/entitiesDataCount/getAnnualSanDomain", params);
}
/**
* 全部制裁(历史制裁过程)
* url:/entitiesDataCount/getSanctionProcess
*/
export function getSanctionProcess(sanTypeIds = "1", pageNum = 1, pageSize = 10, isCn = false) {
return http.post("/api/entitiesDataCount/getSanctionProcess",{
sanTypeIds,
// typeName: tabMap[sanTypeId],
pageNum,
pageSize,
isCn
});
}
// 引入 axios 请求
import axios from 'axios'
// 引入 element-plus 里面的消息提示
import { ElMessage } from 'element-plus'
// Token 管理
const TOKEN_KEY = 'auth_token'
// 获取token
const getToken = () => {
return 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkYXRhLWNlbnRlciIsImF1ZCI6IndlYiIsImlzcyI6ImRhdGEtY2VudGVyIiwiZXhwIjozODI1ODM1NTkxLCJpYXQiOjE2NzgzNTE5NTMsImp0aSI6IjI4YmY1NTZjMTc0MDQ3YjJiNTExNWM3NzVhYjhlNWRmIiwidXNlcm5hbWUiOiJzdXBlcl91c2VyIn0.zHyVzsleX2lEqjDBYRpwluu_wy2nZKGl0dw3IUGnKNw'
// return localStorage.getItem(TOKEN_KEY)
}
// 设置 token
const setToken = (token) => {
localStorage.setItem(TOKEN_KEY, token)
}
// 移除 token
const removeToken = () => {
localStorage.removeItem(TOKEN_KEY)
}
// 导出 token 管理方法
export { getToken, setToken, removeToken }
// 创建 axios 实例
const service = axios.create({
timeout: 300 * 1000 // 请求超时时间
})
// request 拦截器
service.interceptors.request.use(config => {
// 获取 token 并添加到请求头
const token = getToken()
if (token) {
config.headers['token'] = token
}
// 图表解读等 AI 分析服务(Vite 代理 /aiAnalysis)需要 X-API-Key
const reqUrl = String(config.url || '')
if (reqUrl.includes('aiAnalysis')) {
const aiApiKey = import.meta.env.VITE_AI_ANALYSIS_API_KEY
if (aiApiKey) {
config.headers['X-API-Key'] = aiApiKey
}
}
return config
}, error => {
console.log(error)
return Promise.reject(error)
})
// response 拦截器
service.interceptors.response.use(
response => {
const res = response.data
// 根据需求:接口返回 code 不等于 200 的时候报错
if (res.code !== 200) {
ElMessage({
message: res.message || '请求失败',
type: 'error',
duration: 3 * 1000
})
return Promise.reject(res)
}
return res.data
},
error => {
console.log('err' + error)
const isCanceledError =
error?.code === 'ERR_CANCELED' ||
error?.name === 'CanceledError' ||
error?.name === 'AbortError' ||
(typeof error?.message === 'string' && /canceled/i.test(error.message))
if (isCanceledError) return Promise.reject(error)
// 处理 token 过期或无效的情况
const errUrl = String(error.config?.url || '')
const isAiAnalysisRequest = errUrl.includes('aiAnalysis')
if (
error.response &&
(error.response.status === 401 || error.response.status === 403) &&
!isAiAnalysisRequest
) {
ElMessage({
message: 'Token 已过期,请重新登录',
type: 'error',
duration: 3 * 1000
})
removeToken()
} else {
ElMessage({
message: error.message,
type: 'error',
duration: 3 * 1000
})
}
return Promise.reject(error)
}
)
// 封装通用请求函数(支持 http(config) 和 http.get/post 等调用方式)
function http(config) {
return service(config)
}
// 为 http 函数添加快捷方法
http.get = function(url, params) {
return service({ url, method: 'get', params })
}
http.post = function(url, data) {
return service({ url, method: 'post', data })
}
http.put = function(url, data) {
return service({ url, method: 'put', data })
}
http.delete = function(url, params) {
return service({ url, method: 'delete', params })
}
export { http }
export default service
\ No newline at end of file
......@@ -58,7 +58,7 @@ const routes = [
];
console.log('路由', routes)
const router = createRouter({
history: createWebHistory(),
routes
......
......@@ -5,7 +5,7 @@ const financeRoutes = [
// 投融资限制
{
path: "/finance",
name: "finance",
name: "Finance",
component: Finance,
meta: {
title: "投融资限制概览",
......
......@@ -73,13 +73,18 @@
</div>
<div class="box1-top-content-item">
<span class="box1-top-content-item-title">· 涉及领域:</span>
<div
<!-- <div
class="box1-top-content-item-tags"
v-for="(domainItem, index) in item.domains"
:key="index"
>
<el-tag :type="getTagType(domainItem)">{{ domainItem }}</el-tag>
</div>
</div> -->
<AreaTag
v-for="(domainItem, index) in item.domains"
:key="index"
:tagName="domainItem"
/>
</div>
</div>
</div>
......
{
"code": 200,
"message": "操作成功",
"success": true,
"data": {
"content": [
{
"createTime": null,
"updateTime": null,
"id": "3357",
"entityName": "Arrow Electronics (Hong Kong) Co., Ltd.",
"sanTypeId": 1,
"entityType": 2,
"entityId": null,
"entityNameZh": "艾睿电子(香港)有限公司",
"countryId": "0101",
"sanReason": "对于所有受《出口管理条例》(EAR)管制的项目,协助为伊朗代理人(包括哈马斯(Hamas))购买美国原产的电子元件,用于武器化无人机(UAV),违反美国国家安全;协助为伊朗代理人操作的武器化无人驾驶航空系统(UAS)购买美国原产的电子元件。",
"sanIntensity": "\u0000",
"startTime": "2025-10-09",
"endTime": null,
"isKey": "\u0000",
"techDomainList": null,
"techDomains": [],
"ruleOrgCount": 39
},
{
"createTime": null,
"updateTime": null,
"id": "3ef6b0b3-4f6a-4",
"entityName": "Shanghai Langqing Electronic Technology Co.",
"sanTypeId": 1,
"entityType": 2,
"entityId": null,
"entityNameZh": "上海朗晴电子科技有限公司",
"countryId": "0101",
"sanReason": "对于所有受《出口管理条例》(EAR)管辖的物品",
"sanIntensity": "\u0000",
"startTime": "2025-10-09",
"endTime": null,
"isKey": "\u0000",
"techDomainList": null,
"techDomains": [
"经济"
],
"ruleOrgCount": 93
},
{
"createTime": null,
"updateTime": null,
"id": "81fc1a85-a2be-4",
"entityName": "Easy Fly Intelligent Technology Co., Ltd.",
"sanTypeId": 1,
"entityType": 2,
"entityId": null,
"entityNameZh": "易飞智能科技有限公司",
"countryId": "0101",
"sanReason": "对于所有受《出口管理条例》(EAR)管辖的物品",
"sanIntensity": "\u0000",
"startTime": "2025-10-09",
"endTime": null,
"isKey": "\u0000",
"techDomainList": null,
"techDomains": [
"科技"
],
"ruleOrgCount": 18
},
{
"createTime": null,
"updateTime": null,
"id": "2813d17d-8edd-4",
"entityName": "Beijing Rageflight Technology Co., Ltd.",
"sanTypeId": 1,
"entityType": 2,
"entityId": null,
"entityNameZh": "北京锐飞科技有限公司",
"countryId": "0101",
"sanReason": "对于所有受《出口管理条例》(EAR)管辖的物品,为伊朗代理人操作的武器化无人驾驶航空系统(UAS)采购美国原产电子组件提供了便利。",
"sanIntensity": "\u0000",
"startTime": "2025-10-09",
"endTime": null,
"isKey": "\u0000",
"techDomainList": null,
"techDomains": [
"科技",
"军事"
],
"ruleOrgCount": 2
},
{
"createTime": null,
"updateTime": null,
"id": "f7bf81c6-9f5c-4",
"entityName": "Beijing Kevins Technology Development Co., Ltd.",
"sanTypeId": 1,
"entityType": 2,
"entityId": null,
"entityNameZh": "北京凯文斯科技发展有限公司",
"countryId": "0101",
"sanReason": "对于所有受《出口管理条例》(EAR)管辖的项目,协助为伊朗代理人操作的武器化无人飞行系统(UAS)采购美国原产电子元件;协助为伊朗代理人,包括哈马斯(Hamas),采购用于武器化无人飞行器(UAV)的美国原产电子元件,此举违背了美国国家安全。",
"sanIntensity": "\u0000",
"startTime": "2025-10-09",
"endTime": null,
"isKey": "\u0000",
"techDomainList": null,
"techDomains": [
"经济",
"安全"
],
"ruleOrgCount": 51
},
{
"createTime": null,
"updateTime": null,
"id": "3add08b1-3a8a-4",
"entityName": "China Address 17",
"sanTypeId": 1,
"entityType": 7,
"entityId": null,
"entityNameZh": "中国地址17",
"countryId": "0101",
"sanReason": "与艾米丽·刘(Emily Liu)的采购网络相关联,此人先前被海外资产控制办公室(OFAC)指定为支持伊朗设拉子电子工业(SEI)",
"sanIntensity": "\u0000",
"startTime": "2025-10-09",
"endTime": null,
"isKey": "\u0000",
"techDomainList": null,
"techDomains": [
"安全"
],
"ruleOrgCount": 66
},
{
"createTime": null,
"updateTime": null,
"id": "2b660bc7-d770-4",
"entityName": "Address 18",
"sanTypeId": 1,
"entityType": 7,
"entityId": null,
"entityNameZh": "地址18",
"countryId": "0101",
"sanReason": "对于商业管制清单(CCL)上的物品以及《出口管理条例》(EAR)第746部分第7号补编中列出的EAR 99物品",
"sanIntensity": "\u0000",
"startTime": "2025-10-09",
"endTime": null,
"isKey": "\u0000",
"techDomainList": null,
"techDomains": [
"经济"
],
"ruleOrgCount": 1
},
{
"createTime": null,
"updateTime": null,
"id": "ccaa8cd6-2b78-4",
"entityName": "Shanghai Bitconn Electronics Co., Ltd.",
"sanTypeId": 1,
"entityType": 2,
"entityId": null,
"entityNameZh": "上海比通电子有限公司",
"countryId": "0101",
"sanReason": "对于所有受《出口管理条例》(EAR)约束的项目,为伊朗代理人操作的武器化无人驾驶航空系统(UAS)购买美国原产电子元件提供了便利。",
"sanIntensity": "\u0000",
"startTime": "2025-10-09",
"endTime": null,
"isKey": "\u0000",
"techDomainList": null,
"techDomains": [
"经济",
"军事",
"科技"
],
"ruleOrgCount": 15
},
{
"createTime": null,
"updateTime": null,
"id": "8aa1686a-33e8-4",
"entityName": "Feng Bao Electronic Information Technology (Shanghai) Co., Ltd.",
"sanTypeId": 1,
"entityType": 2,
"entityId": null,
"entityNameZh": "丰宝电子信息科技(上海)有限公司",
"countryId": "0101",
"sanReason": "对于所有受《出口管理条例》(EAR)管辖的项目",
"sanIntensity": "\u0000",
"startTime": "2025-10-09",
"endTime": null,
"isKey": "\u0000",
"techDomainList": null,
"techDomains": [
"科技"
],
"ruleOrgCount": 42
},
{
"createTime": null,
"updateTime": null,
"id": "d9016b50-dee1-4",
"entityName": "Royal Impact Trading L.L.C.",
"sanTypeId": 1,
"entityType": 2,
"entityId": null,
"entityNameZh": "皇家影响力贸易有限责任公司",
"countryId": "134",
"sanReason": "对于所有受《出口管理条例》(EAR)管辖的项目,根据EAR第744.11节的规定,推定为拒绝批准,将美国原产项目转移至伊朗,包括归类于ECCN 2B350的项目。",
"sanIntensity": "\u0000",
"startTime": "2025-10-09",
"endTime": null,
"isKey": "\u0000",
"techDomainList": null,
"techDomains": [
"经济"
],
"ruleOrgCount": 39
}
],
"pageable": {
"sort": {
"unsorted": false,
"sorted": true,
"empty": false
},
"pageNumber": 0,
"pageSize": 10,
"offset": 0,
"unpaged": false,
"paged": true
},
"totalPages": 347,
"last": false,
"totalElements": 3461,
"sort": {
"unsorted": false,
"sorted": true,
"empty": false
},
"first": true,
"numberOfElements": 10,
"size": 10,
"number": 0,
"empty": false
}
}
\ No newline at end of file
<template>
<div class="sanction-container">
<!-- 页面标题区域 -->
<div class="page-header">
<!-- <h1 class="main-title">制裁分析</h1> -->
<div class="bill-info">
<div class="bill-details">
<div class="main-title">制裁分析</div>
<div class="bill-name-en">第119届美国国会众议院第1号法案One Big Beautiful Bill Act</div>
</div>
<div class="date-author">
<div class="date">2025年7月</div>
<div class="author">乔迪·阿灵顿(Jodey Arrington)</div>
</div>
</div>
</div>
<!-- 导航标签区域 -->
<!-- <div class="nav-section">
<div class="tabs">
<div class="tab-item active">制裁概况</div>
<div class="tab-item">深度挖掘</div>
<div class="tab-item">影响分析</div>
</div>
<div class="action-buttons">
<el-button>法案原文</el-button>
<el-button type="primary">分析报告</el-button>
</div>
</div> -->
<!-- 内容区域 -->
<!-- <div class="content-section">
<div class="content-placeholder">
<el-icon><document /></el-icon>
<p>这里是制裁概况的内容区域</p>
<p>请选择上方标签查看不同分析内容</p>
</div>
</div> -->
</div>
</template>
<script setup></script>
<style scoped>
.sanction-container {
width: 100%;
/* max-width: 1200px; */
background-color: #fff;
/* border-radius: 8px; */
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
overflow: hidden;
box-sizing: border-box;
padding-left: 5%;
padding-right: 5%;
}
.page-header {
padding: 24px;
padding-top: 0;
/* border-bottom: 1px solid #ebeef5; */
}
.main-title {
font-size: 20px;
font-weight: 700;
color: rgba(59, 65, 75, 1);
/* color: var(--base-color); */
margin-bottom: 8px;
}
.bill-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 16px;
}
.bill-details {
flex: 1;
}
.bill-name {
font-size: 16px;
color: #606266;
margin-bottom: 4px;
}
.bill-name-en {
font-size: 14px;
color: #909399;
font-style: italic;
}
.date-author {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.date {
font-size: 14px;
color: #606266;
margin-bottom: 4px;
}
.author {
font-size: 14px;
color: #606266;
}
.nav-section {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 24px;
background-color: #f8fafc;
border-bottom: 1px solid #ebeef5;
}
.tabs {
display: flex;
gap: 0;
}
.tab-item {
padding: 12px 24px;
font-size: 14px;
color: #606266;
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.3s;
}
.tab-item.active {
color: #409eff;
border-bottom-color: #409eff;
background-color: rgba(64, 158, 255, 0.1);
}
.tab-item:hover {
color: #409eff;
}
.action-buttons {
display: flex;
gap: 12px;
}
.content-section {
padding: 24px;
min-height: 400px;
}
.content-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 300px;
color: #909399;
}
.content-placeholder .el-icon {
font-size: 48px;
margin-bottom: 16px;
color: #dcdfe6;
}
.content-placeholder p {
font-size: 16px;
margin-top: 8px;
}
@media (max-width: 768px) {
.bill-info {
flex-direction: column;
align-items: flex-start;
}
.date-author {
align-items: flex-start;
margin-top: 12px;
}
.nav-section {
flex-direction: column;
align-items: flex-start;
gap: 16px;
}
.tabs {
width: 100%;
overflow-x: auto;
}
}
</style>
<template>
<div class="page-container">
<Header />
<!-- 导航标签区域 -->
<div class="nav-section">
<div class="tabs">
<div :class="['tab-item', { active: activeTab === '制裁概况' }]" @click="setActiveTab('制裁概况')">制裁概况</div>
<div :class="['tab-item', { active: activeTab === '深度挖掘' }]" @click="setActiveTab('深度挖掘')">深度挖掘</div>
<div :class="['tab-item', { active: activeTab === '影响分析' }]" @click="setActiveTab('影响分析')">影响分析</div>
</div>
<div class="action-buttons">
<el-button>法案原文</el-button>
<el-button type="primary">分析报告</el-button>
</div>
</div>
<!-- 内容区域 -->
<div class="content-section">
<!-- <div class="content-placeholder">
<el-icon><document /></el-icon>
<p>这里是制裁概况的内容区域</p>
<p>请选择上方标签查看不同分析内容</p>
</div> -->
<Survey v-if="activeTab === '制裁概况'" />
<DepthMine v-if="activeTab === '深度挖掘'" />
<ImpactAnalysis v-if="activeTab === '影响分析'" />
</div>
<div class="left-absolute">
<el-image :src="Left1" alt="" />
<el-image :src="Left2" alt="" />
<el-image :src="Left3" alt="" />
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import Header from "./header.vue";
import Survey from "./content/survey.vue";
import DepthMine from "./content/depthMine.vue";
import ImpactAnalysis from "./content/impactAnalysis.vue";
import Left1 from "@/assets/images/left-1.png";
import Left2 from "@/assets/images/left-2.png";
import Left3 from "@/assets/images/left-3.png";
const activeTab = ref("制裁概况");
const setActiveTab = tabName => {
activeTab.value = tabName;
};
</script>
<style scoped lang="scss">
.page-container {
position: relative;
margin: 0px auto;
background-color: rgba(247, 248, 249, 1);
}
.nav-section {
display: flex;
justify-content: space-between;
align-items: center;
/* padding: 16px 24px; */
padding-left: 6%;
padding-right: 6%;
background-color: #fff;
border-bottom: 1px solid #ebeef5;
}
.tabs {
display: flex;
gap: 0;
}
.tab-item {
width: 120px;
height: 40px;
text-align: center;
line-height: 30px;
// padding: 12px 24px;
font-size: 18px;
color: #606266;
cursor: pointer;
border-bottom: 3px solid transparent;
transition: all 0.3s;
box-sizing: border-box;
}
// .tab-item.active {
// color: #409eff;
// border-bottom-color: #409eff;
// background-color: rgba(64, 158, 255, 0.1);
// }
.tab-item.active {
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 18px;
font-weight: 700;
line-height: 30px;
border-bottom: 3px solid var(--color-main-active);
}
.tab-item:hover {
color: var(--color-main-active);
}
.action-buttons {
display: flex;
gap: 12px;
}
.content-section {
padding: 24px;
min-height: 400px;
}
.content-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 300px;
color: #909399;
}
.content-placeholder .el-icon {
font-size: 48px;
margin-bottom: 16px;
color: #dcdfe6;
}
.content-placeholder p {
font-size: 16px;
margin-top: 8px;
}
@media (max-width: 768px) {
.bill-info {
flex-direction: column;
align-items: flex-start;
}
.date-author {
align-items: flex-start;
margin-top: 12px;
}
.nav-section {
flex-direction: column;
align-items: flex-start;
gap: 16px;
}
.tabs {
width: 100%;
overflow-x: auto;
}
}
.left-absolute {
position: fixed;
left: 0;
top: 60%;
// width: 48px;
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
background-color: #fff;
border-radius: 10px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
padding: 16px 12px;
box-shadow: 0 0 15px 0 rgba(60, 87, 126, 0.2);
div {
width: 17px;
height: 18px;
}
}
</style>
<template>
<div class="message-bubble">
<div class="avatar-container">
<img :src="avatar" :alt="name" class="avatar" />
</div>
<div class="bubble-container">
<div class="bubble">
<div class="bubble-header">
<span class="name">{{ name }}</span>
<span class="meta">{{ time }} · {{ source }}</span>
</div>
<div class="bubble-content">
{{ content }}
</div>
<div class="triangle"></div>
</div>
</div>
</div>
</template>
<script setup>
defineProps({
avatar: {
type: String,
default: "https://via.placeholder.com/40x40/4A90E2/FFFFFF?text=T"
},
name: {
type: String,
default: "唐纳德·特朗普"
},
time: {
type: String,
default: "15:23"
},
source: {
type: String,
default: "发布于真实社交"
},
content: {
type: String,
default:
"埃隆·马斯克在强力支持我竞选总统之前,早就知道我强烈反对‘电动汽车强制令’。这太荒谬了,这一直是我竞选活动的主要部分。电动汽车没问题,但不应该强迫每个人都拥有一辆。埃隆获得的补贴可能远远超过历史上任何一个人。如果没有补贴,埃隆可能不得不关门大吉,回到南非老家。"
}
});
</script>
<style scoped>
.message-bubble {
display: flex;
max-width: 700px;
margin: 20px 0;
}
.avatar-container {
flex-shrink: 0;
margin-right: 12px;
}
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
object-fit: cover;
}
.bubble-container {
flex: 1;
position: relative;
}
.bubble {
background-color: rgba(246, 250, 255, 1);
border-radius: 12px;
padding: 12px 16px;
position: relative;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.bubble-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.name {
font-weight: bold;
font-size: 16px;
color: #333;
}
.meta {
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
text-align: right;
}
.bubble-content {
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: justify;
}
.triangle {
position: absolute;
left: -8px;
top: 15px;
width: 0;
height: 0;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
border-right: 8px solid rgba(246, 250, 255, 1);
}
/* 响应式设计 */
@media (max-width: 768px) {
.message-bubble {
max-width: 100%;
}
.bubble-header {
flex-direction: column;
align-items: flex-start;
}
.meta {
margin-top: 4px;
}
}
</style>
<template>
<div class="info-card">
<div class="color-bar" :style="{ backgroundColor: color }"></div>
<div class="card-content">
<div class="title-section">
<div class="main-title">{{ title }}</div>
<div class="sub-title">{{ subtitle }}</div>
</div>
<div class="description">{{ description }}</div>
<div v-if="quantity > 0" class="quantity" :style="{ color: color }">{{ quantity }}</div>
</div>
</div>
</template>
<script setup>
defineProps({
title: {
type: String,
default: "标题"
},
subtitle: {
type: String,
default: "Subtitle"
},
description: {
type: String,
default: "描述信息"
},
quantity: {
type: [Number, String],
default: 0
},
color: {
type: String,
default: "#409EFF"
}
});
</script>
<style scoped>
.info-card {
max-width: 388px;
min-width: 300px;
height: 150px;
border-radius: 12px;
background-color: white;
display: flex;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
position: relative;
overflow: hidden;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.info-card:hover {
transform: translateY(-3px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
.color-bar {
width: 6px;
height: 120px;
flex-shrink: 0;
margin-top: 15px;
}
.card-content {
flex: 1;
padding: 20px;
display: flex;
flex-direction: column;
position: relative;
}
.title-section {
margin-bottom: 12px;
}
.main-title {
font-size: 24px;
font-weight: 700;
color: #1f2937;
line-height: 1.2;
}
.sub-title {
font-size: 16px;
font-weight: 700;
line-height: 1.2;
color: #6b7280;
margin-top: 2px;
}
.description {
font-size: 16px;
font-weight: 400;
color: rgba(95, 101, 108, 1);
line-height: 1.4;
flex: 1;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.quantity {
position: absolute;
top: 20px;
right: 20px;
font-size: 32px;
font-weight: 700;
}
</style>
<template>
<div :class="['clickable-card', { disabled: disabled }]" @click="handleClick">
<span class="card-text">{{ text }}</span>
<!-- <span class="arrow-icon"></span> -->
<div class="icon">
<el-icon><ArrowRightBold /></el-icon>
</div>
</div>
</template>
<script setup>
import { ArrowRight, ArrowRightBold } from "@element-plus/icons-vue";
import { useRouter } from "vue-router";
const router = useRouter();
const props = defineProps({
text: {
type: String,
default: "点击跳转"
},
link: {
type: String,
default: ""
},
target: {
type: String,
default: "_self"
},
disabled: {
type: Boolean,
default: false
}
});
const emit = defineEmits(["click"]);
const handleClick = () => {
if (props.disabled) return;
emit("click");
if (props.link) {
if (props.link.startsWith("http") || props.link.startsWith("//")) {
// 外部链接
window.open(props.link, props.target);
} else {
router.push(props.link);
console.log(`跳转到: ${props.link}`);
}
}
};
</script>
<style lang="scss" scoped>
.clickable-card {
width: 160px;
height: 48px;
border-radius: 32px;
border: 1px solid rgba(174, 214, 255, 1);
background-color: rgba(231, 243, 255, 1);
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
/* padding: 0 16px; */
cursor: pointer;
transition: all 0.3s ease;
color: rgba(5, 95, 194, 1);
font-size: 20px;
font-weight: 500;
box-sizing: border-box;
position: relative;
.icon{
position: absolute;
top: 14px;
right: 12px;
}
}
.clickable-card:hover {
background-color: rgba(231, 243, 255, 0.5);
box-shadow: 0 2px 8px rgba(5, 95, 194, 0.1);
transform: translateY(-2px);
}
.clickable-card:active {
transform: translateY(0);
box-shadow: 0 1px 4px rgba(5, 95, 194, 0.1);
}
.clickable-card.disabled {
opacity: 0.5;
cursor: not-allowed;
}
.clickable-card.disabled:hover {
background-color: white;
box-shadow: none;
transform: none;
}
.arrow-icon {
font-weight: bold;
font-size: 16px;
}
</style>
<template>
<div class="news-list">
<div v-for="(item, index) in listData" :key="index" class="news-item" @click="handleItemClick(item)">
<div class="news-image">
<img :src="item.image" :alt="item.title" />
</div>
<div class="news-content">
<div class="news-header">
<div class="news-title">{{ item.title }}</div>
<div class="news-meta">
<span class="news-time">{{ item.time }}</span> ·
<span class="news-source">{{ item.source }}</span>
</div>
</div>
<div class="news-description">{{ item.description }}</div>
</div>
</div>
</div>
</template>
<script setup>
const props = defineProps({
listData: {
type: Array,
default: () => [
{
image: "https://via.placeholder.com/72x48/4A90E2/FFFFFF?text=News",
title: "美国智库激辩人工智能监管路径",
time: "11-4",
source: "华盛顿邮报",
description: "各方就AI监管模式展开讨论。有观点认为碎片化州级监管比全面联邦法规更灵活,也有分析指出..."
}
]
}
});
const emit = defineEmits(["item-click"]);
const handleItemClick = item => {
emit("item-click", item);
};
</script>
<style scoped>
.news-list {
width: 100%;
max-width: 800px;
}
.news-item {
display: flex;
padding: 10px 0;
align-items: center;
border-bottom: 1px solid #f0f0f0;
cursor: pointer;
transition: background-color 0.3s;
}
.news-item:hover {
background-color: #f9f9f9;
}
.news-item:last-child {
border-bottom: none;
}
.news-image {
width: 72px;
height: 48px;
flex-shrink: 0;
margin-right: 16px;
border-radius: 4px;
overflow: hidden;
}
.news-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.news-content {
flex: 1;
display: flex;
flex-direction: column;
}
.news-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 8px;
}
.news-title {
font-size: 16px;
font-weight: 700;
color: rgba(59, 65, 75, 1);
line-height: 24px;
flex: 1;
margin-right: 12px;
}
.news-meta {
display: flex;
align-items: center;
height: 24px;
line-height: 24px;
flex-shrink: 0;
font-size: 14px;
color: #999;
}
.news-time {
height: 22px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 22px;
letter-spacing: 0px;
text-align: right;
}
.news-source {
height: 22px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 22px;
letter-spacing: 0px;
text-align: right;
}
.news-description {
font-size: 16px;
color: rgba(59, 65, 75, 1);
line-height: 1.5;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
<template>
<div class="custom-title">
<div class="color-block block1"></div>
<div class="color-block block2"></div>
<div class="title-text">{{ title }}</div>
<div class="color-line"></div>
</div>
</template>
<script setup>
defineProps({
title: {
type: String,
default: "最新动态"
}
});
</script>
<style scoped>
.custom-title {
display: flex;
align-items: center;
width: 100%;
margin-bottom: 20px;
padding: 10px 15px;
}
.color-block {
background-color: rgba(174, 214, 255, 1);
height: 30px;
flex-shrink: 0;
}
.block1 {
width: 24px;
}
.block2 {
width: 8px;
margin-left: 10px;
}
.title-text {
font-size: 32px;
font-weight: 700;
margin-left: 20px;
white-space: nowrap;
}
.color-line {
background-color: rgba(174, 214, 255, 1);
height: 2px;
flex-grow: 1;
margin-left: 20px;
}
</style>
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论