提交 f09c15f0 authored 作者: coderBryanFu's avatar coderBryanFu

update

// @see: https://www.prettier.cn
module.exports = {
// 超过最大值换行
printWidth: 130,
// 缩进字节数
tabWidth: 4,
// 使用制表符而不是空格缩进行
useTabs: true,
// 结尾不用分号(true有,false没有)
semi: true,
// 使用单引号(true单双引号,false双引号)
singleQuote: false,
// 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>"
quoteProps: "as-needed",
// 在对象,数组括号与文字之间加空格 "{ foo: bar }"
bracketSpacing: true,
// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none
trailingComma: "none",
// 在JSX中使用单引号而不是双引号
jsxSingleQuote: false,
// (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid:省略括号 ,always:不省略括号
arrowParens: "avoid",
// 如果文件顶部已经有一个 doclock,这个选项将新建一行注释,并打上@format标记。
insertPragma: false,
// 指定要使用的解析器,不需要写文件开头的 @prettier
requirePragma: false,
// 默认值。因为使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本样式进行折行
proseWrap: "preserve",
// 在html中空格是否是敏感的 "css" - 遵守CSS显示属性的默认值, "strict" - 空格被认为是敏感的 ,"ignore" - 空格被认为是不敏感的
htmlWhitespaceSensitivity: "css",
// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>"
endOfLine: "auto",
// 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码
rangeStart: 0,
rangeEnd: Infinity,
// Vue文件脚本和样式标签缩进
vueIndentScriptAndStyle: false
};
<template>
<div id="app">
<el-container>
<el-header>
<nav class="navbar">
<div class="nav-brand">
<el-icon class="brand-icon"><Monitor /></el-icon>
<span class="brand-text">某方向风险监测预警系统</span>
</div>
<div class="nav-menu">
<el-dropdown @command="handleHomeCommand" class="home-dropdown">
<div class="nav-link dropdown-trigger">
<el-icon><House /></el-icon>
<span>首页</span>
<el-icon class="dropdown-arrow"><ArrowDown /></el-icon>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="/">智库首页</el-dropdown-item>
<el-dropdown-item command="/billHome">法案首页</el-dropdown-item>
<el-dropdown-item command="/exportControl">出口管制</el-dropdown-item>
<el-dropdown-item command="/decree">政令</el-dropdown-item>
<el-dropdown-item command="/marketAccessRestrictions">市场准入限制</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="nav-link">
<el-icon><User /></el-icon>
<span>国家</span>
</div>
<div class="nav-link">
<el-icon><Location /></el-icon>
<span>领域</span>
</div>
<div class="nav-link">
<el-icon><Document /></el-icon>
<span>要素</span>
</div>
<div class="nav-link">
<el-icon><Bell /></el-icon>
<span>事件</span>
</div>
</div>
<div class="user-info">
<el-icon><Message /></el-icon>
<el-icon><User /></el-icon>
<span>管理员</span>
</div>
</nav>
</el-header>
<el-main class="main-container">
<router-view />
</el-main>
</el-container>
</div>
<div id="app">
<el-container>
<el-header>
<nav class="navbar">
<div class="nav-brand">
<el-icon class="brand-icon"><Monitor /></el-icon>
<span class="brand-text">某方向风险监测预警系统</span>
</div>
<div class="nav-menu">
<el-dropdown @command="handleHomeCommand" class="home-dropdown">
<div class="nav-link dropdown-trigger">
<el-icon><House /></el-icon>
<span>首页</span>
<el-icon class="dropdown-arrow"><ArrowDown /></el-icon>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="/">智库首页</el-dropdown-item>
<el-dropdown-item command="/billHome">法案首页</el-dropdown-item>
<el-dropdown-item command="/exportControl">出口管制</el-dropdown-item>
<el-dropdown-item command="/decree">政令</el-dropdown-item>
<el-dropdown-item command="/marketAccessRestrictions">市场准入限制</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="nav-link">
<el-icon><User /></el-icon>
<span>国家</span>
</div>
<div class="nav-link">
<el-icon><Location /></el-icon>
<span>领域</span>
</div>
<div class="nav-link">
<el-icon><Document /></el-icon>
<span>要素</span>
</div>
<div class="nav-link">
<el-icon><Bell /></el-icon>
<span>事件</span>
</div>
</div>
<div class="user-info">
<el-icon><Message /></el-icon>
<el-icon><User /></el-icon>
<span>管理员</span>
</div>
</nav>
</el-header>
<!-- 面包屑导航 -->
<Breadcrumb />
<el-main class="main-container">
<router-view />
</el-main>
</el-container>
</div>
</template>
<script setup>
import { Monitor, House, User, Location, Document, Bell, Message, ArrowDown } from '@element-plus/icons-vue'
import { useRouter } from 'vue-router'
import { Monitor, House, User, Location, Document, Bell, Message, ArrowDown } from "@element-plus/icons-vue";
import { useRouter } from "vue-router";
import Breadcrumb from "@/components/BreadCrumb/index.vue";
const router = useRouter()
const router = useRouter();
const handleHomeCommand = (command) => {
router.push(command)
}
const handleHomeCommand = command => {
router.push(command);
};
</script>
<style>
/* 全局样式重置 */
* {
box-sizing: border-box;
box-sizing: border-box;
}
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
body {
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
}
</style>
<style scoped>
#app {
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
width: 100%;
min-height: 100vh;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
width: 100%;
height: 100vh;
overflow-y: hidden;
}
/* 确保Element Plus容器组件占满宽度 */
.el-container {
width: 100%;
min-height: 100vh;
width: 100%;
/* min-height: 100vh; */
height: 100%;
margin-bottom: 20px;
}
.navbar {
display: flex;
justify-content: center;
align-items: center;
padding: 0 24px;
background: white;
color: #333;
height: 100%;
border-bottom: 1px solid #e5e7eb;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
position: relative;
display: flex;
justify-content: center;
align-items: center;
padding: 0 24px;
background: white;
color: #333;
height: 100%;
border-bottom: 1px solid #e5e7eb;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
position: relative;
}
.main-container {
/* 移除宽度限制,让子页面自己控制布局 */
width: 100%;
/* 移除宽度限制,让子页面自己控制布局 */
width: 100%;
}
.nav-brand {
display: flex;
align-items: center;
gap: 12px;
position: absolute;
left: 24px;
display: flex;
align-items: center;
gap: 12px;
position: absolute;
left: 24px;
}
.brand-icon {
font-size: 24px;
color: #1e3a8a;
font-size: 24px;
color: #1e3a8a;
}
.brand-text {
font-size: 18px;
font-weight: 600;
color: #333;
font-size: 18px;
font-weight: 600;
color: #333;
}
.nav-menu {
display: flex;
align-items: center;
gap: 32px;
display: flex;
align-items: center;
gap: 32px;
}
.nav-link {
display: flex;
align-items: center;
gap: 6px;
color: #333;
text-decoration: none;
padding: 8px 12px;
border-radius: 6px;
transition: all 0.3s;
font-size: 14px;
cursor: pointer;
display: flex;
align-items: center;
gap: 6px;
color: #333;
text-decoration: none;
padding: 8px 12px;
border-radius: 6px;
transition: all 0.3s;
font-size: 14px;
cursor: pointer;
}
.nav-link:hover,
.nav-link.router-link-active {
background-color: #1459BB;
color: #fff;
background-color: #1459bb;
color: #fff;
}
.home-dropdown {
display: inline-block;
display: inline-block;
}
.dropdown-trigger {
cursor: pointer;
cursor: pointer;
}
.dropdown-arrow {
font-size: 12px;
margin-left: 4px;
transition: transform 0.3s;
font-size: 12px;
margin-left: 4px;
transition: transform 0.3s;
}
.home-dropdown:hover .dropdown-arrow {
transform: rotate(180deg);
transform: rotate(180deg);
}
.user-info {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
background: #f3f4f6;
border-radius: 6px;
color: #333;
position: absolute;
right: 24px;
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
background: #f3f4f6;
border-radius: 6px;
color: #333;
position: absolute;
right: 24px;
}
.el-header {
padding: 0;
height: 60px;
padding: 0;
height: 60px;
}
.el-main {
padding: 0;
height: calc(100vh - 60px);
background-color: rgba(246, 251, 255, 1);
overflow-y: auto;
padding: 0;
height: calc(100vh - 60px);
background-color: rgba(246, 251, 255, 1);
overflow-y: auto;
}
</style>
\ No newline at end of file
</style>
<svg width="410" height="404" viewBox="0 0 410 404" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M399.641 59.5246L215.643 388.545C211.844 395.338 202.084 395.378 198.228 388.618L10.5817 59.5563C6.38087 52.1896 12.6802 43.2665 21.0281 44.7586L205.223 77.6824C206.398 77.8924 207.601 77.8904 208.776 77.6763L389.119 44.8058C397.439 43.2894 403.768 52.1434 399.641 59.5246Z" fill="url(#paint0_linear)"/>
<path d="M292.965 1.5744L156.801 28.2552C154.563 28.6937 152.906 30.5903 152.771 32.8664L144.395 174.33C144.198 177.662 147.258 180.248 150.51 179.498L188.42 170.749C191.967 169.931 195.172 173.055 194.443 176.622L183.18 231.775C182.422 235.487 185.907 238.661 189.532 237.56L212.947 230.446C216.577 229.344 220.065 232.527 219.297 236.242L201.398 322.875C200.278 328.294 207.486 331.249 210.492 326.603L212.5 323.5L323.454 102.072C325.312 98.3645 322.108 94.137 318.036 94.9228L279.014 102.454C275.347 103.161 272.227 99.746 273.262 96.1583L298.731 7.86689C299.767 4.27314 296.636 0.855181 292.965 1.5744Z" fill="url(#paint1_linear)"/>
<defs>
<linearGradient id="paint0_linear" x1="6.00017" y1="32.9999" x2="235" y2="344" gradientUnits="userSpaceOnUse">
<stop stop-color="#41D1FF"/>
<stop offset="1" stop-color="#BD34FE"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="194.651" y1="8.81818" x2="236.076" y2="292.989" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFEA83"/>
<stop offset="0.0833333" stop-color="#FFDD35"/>
<stop offset="1" stop-color="#FFA800"/>
</linearGradient>
</defs>
</svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1672991576281" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="722" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M486.4 609.28h51.2v138.24h-51.2zM371.2 453.12h-51.2v-102.4c0-102.4 81.92-184.32 184.32-184.32s184.32 81.92 184.32 184.32v61.44h-51.2v-61.44c0-74.24-58.88-133.12-133.12-133.12-74.24 0-133.12 58.88-133.12 133.12v102.4z" fill="#333333" p-id="723"></path><path d="M512 593.92m-48.64 0a48.64 48.64 0 1 0 97.28 0 48.64 48.64 0 1 0-97.28 0Z" fill="#333333" p-id="724"></path><path d="M724.48 893.44H299.52c-33.28 0-58.88-25.6-58.88-58.88v-332.8c0-33.28 25.6-58.88 58.88-58.88h422.4c33.28 0 58.88 25.6 58.88 58.88v332.8c2.56 33.28-25.6 58.88-56.32 58.88zM299.52 491.52c-5.12 0-7.68 2.56-7.68 7.68v332.8c0 5.12 2.56 7.68 7.68 7.68h422.4c5.12 0 7.68-2.56 7.68-7.68v-332.8c0-5.12-2.56-7.68-7.68-7.68H299.52z" fill="#333333" p-id="725"></path></svg>
\ No newline at end of file
export const TAGTYPE = ["primary", "success", "warning", "danger", "info"];
<template>
<div class="breadcrumb-container">
<el-breadcrumb :separator-icon="ArrowRight">
<el-breadcrumb-item
v-for="(item, index) in breadcrumbList"
:key="index"
:to="index < breadcrumbList.length - 1 ? { path: item.path } : undefined"
>
<span :class="{ 'last-item': index === breadcrumbList.length - 1, 'breadcrumb-link': true }">
{{ item.meta.title }}
</span>
</el-breadcrumb-item>
</el-breadcrumb>
</div>
</template>
<script setup>
import { ArrowRight } from "@element-plus/icons-vue";
import { computed } from "vue";
import { useRoute, useRouter } from "vue-router";
const route = useRoute();
const router = useRouter();
// 生成面包屑数据
const breadcrumbList = computed(() => {
const matched = route.matched.filter(item => item.meta && item.meta.title);
// 确保首页始终在第一位
const first = matched[0];
if (!first || first.path !== "/") {
matched.unshift({
path: "/",
meta: { title: "首页" }
});
}
return matched;
});
</script>
<style scoped>
.breadcrumb-container {
height: 64px;
padding: 12px 20px;
display: flex;
justify-content: flex-start;
align-items: center;
background-color: #f5f7fa;
border-bottom: 1px solid #e4e7ed;
background-image: url("../../assets/images/title-bgc.png");
}
.last-item {
color: #fff;
font-size: 20px;
font-weight: 700;
}
.breadcrumb-link {
color: #fff;
font-size: 20px;
font-weight: 700;
}
:deep(.el-breadcrumb) {
font-size: 20px;
}
:deep(.el-breadcrumb__item:last-child .el-breadcrumb__inner) {
color: #fff;
font-size: 20px;
font-weight: 700;
}
:deep(.el-breadcrumb__inner a, .el-breadcrumb__inner.is-link) {
color: #fff;
font-size: 20px;
font-weight: 700;
}
</style>
<template>
<div ref="chartRef" :style="{ width, height }"></div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch, nextTick } from "vue";
import * as echarts from "echarts";
// 定义组件props
const props = defineProps({
// 图表配置项
option: {
type: Object,
required: true
},
// 图表宽度
width: {
type: String,
default: "100%"
},
// 图表高度
height: {
type: String,
default: "400px"
},
// 图表主题
theme: {
type: String,
default: ""
},
// 是否显示加载动画
loading: {
type: Boolean,
default: false
},
// 自动调整大小
autoresize: {
type: Boolean,
default: true
}
});
// 定义可触发的事件
const emit = defineEmits(["chart-click", "chart-ready"]);
// 图表实例和容器引用
const chartRef = ref(null);
let chartInstance = null;
// 初始化图表
const initChart = () => {
if (!chartRef.value) return;
// 销毁现有实例
if (chartInstance) {
chartInstance.dispose();
}
// 创建新实例
chartInstance = echarts.init(chartRef.value, props.theme);
// 设置配置项
chartInstance.setOption(props.option);
// 绑定事件
chartInstance.on("click", params => {
emit("chart-click", params);
});
// 图表准备就绪
emit("chart-ready", chartInstance);
// 处理加载状态
if (props.loading) {
chartInstance.showLoading();
} else {
chartInstance.hideLoading();
}
};
// 调整图表大小
const resizeChart = () => {
if (chartInstance) {
chartInstance.resize();
}
};
// 监听选项变化
watch(
() => props.option,
newOption => {
if (chartInstance) {
chartInstance.setOption(newOption);
}
},
{ deep: true }
);
// 监听加载状态变化
watch(
() => props.loading,
loading => {
if (chartInstance) {
if (loading) {
chartInstance.showLoading();
} else {
chartInstance.hideLoading();
}
}
}
);
// 组件挂载
onMounted(() => {
nextTick(() => {
initChart();
// 如果启用自动调整大小,监听窗口变化
if (props.autoresize) {
window.addEventListener("resize", resizeChart);
}
});
});
// 组件卸载
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
if (props.autoresize) {
window.removeEventListener("resize", resizeChart);
}
});
// 暴露方法给父组件
defineExpose({
getInstance: () => chartInstance,
resize: resizeChart
});
</script>
<template>
<div class="custom-container" :style="{ height: height ? height : 'auto' }">
<!-- 顶部区域 -->
<div class="header-top">
<slot name="header-top"></slot>
</div>
<div class="container-header">
<div class="header-left">
<slot name="header-left">
<!-- <div class="blue-title-block"></div> -->
<el-image :src="titleIcon" class="header-icon" fit="contain" />
<div :class="headerTitleClasses">{{ title }}</div>
</slot>
</div>
<div class="header-right">
<slot name="header-right"></slot>
<!-- <img class="pushpin" src="@/assets/images/icon-pushpin.png" alt="" /> -->
</div>
</div>
<!-- 内容区域 -->
<div class="container-content">
<slot>
<div class="content-placeholder">
<el-icon><Document /></el-icon>
<div>这里是内容区域</div>
</div>
</slot>
</div>
<!-- 底部区域 -->
<div class="container-footer">
<slot name="footer">
<!-- <el-button>默认按钮</el-button> -->
</slot>
</div>
</div>
</template>
<script setup>
import { ref, computed } from "vue";
import { Document } from "@element-plus/icons-vue";
const props = defineProps({
title: {
type: String,
default: "容器标题"
},
height: {
type: String,
default: ""
},
titleIcon: {
type: String,
default: ""
},
titleType: {
type: String,
default: ""
}
});
const headerTitleClasses = computed(() => [
"header-title",
{
[`header-title-${props.titleType}`]: props.titleType
}
]);
</script>
<style scoped lang="scss">
.custom-container {
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(60, 87, 126, 0.2);
overflow: hidden;
width: 100%;
margin-bottom: 15px;
position: relative;
}
.container-header {
display: flex;
justify-content: space-between;
align-items: center;
// padding: 10px 16px;
height: 48px;
padding: 0 16px;
border-bottom: 1px solid #ebeef5;
/* background-color: #f8fafc; */
padding-left: 0;
}
.header-left {
display: flex;
align-items: center;
padding-left: 14px;
}
.header-icon {
width: 20px;
height: 20px;
margin-right: 14px;
}
.blue-title-block {
width: 8px;
height: 16px;
background-color: var(--base-color);
/* border-radius: 3px; */
margin-right: 14px;
}
.header-title {
font-size: $base-font-size;
font-weight: 700;
/* color: rgba(10, 87, 166, 1); */
/* color: var(--base-color); */
color: $base-color;
line-height: 48px;
padding: 0 12px;
}
.header-title-primary {
background: $base-color;
color: white;
}
.header-title-danger {
background: red;
color: white;
}
.header-right {
display: flex;
align-items: center;
gap: 12px;
}
.pushpin {
width: 28px;
height: 28px;
}
.container-content {
padding: 24px;
/* min-height: 200px; */
padding-top: 10px;
height: 80%;
}
.content-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
color: #909399;
font-size: 16px;
}
.content-placeholder .el-icon {
font-size: 48px;
margin-bottom: 16px;
color: #dcdfe6;
}
.container-footer {
/* padding: 16px 24px; */
background-color: #f8fafc;
/* border-top: 1px solid #ebeef5; */
display: flex;
justify-content: flex-end;
gap: 12px;
}
</style>
<template>
<IntegratedTable
:columns="columns"
:data="tableData"
:pagination="pagination"
@page-change="handlePageChange"
@size-change="handleSizeChange"
>
<template #header>
<div class="table-header">
<div class="table-title">自定义标题</div>
<div class="table-actions">
<el-button type="primary" size="small">新增</el-button>
</div>
</div>
</template>
</IntegratedTable>
</template>
<script setup>
import IntegratedTable from './index.vue'
const columns = [
{
prop: 'name',
label: '姓名',
width: '150px'
},
{
prop: 'age',
label: '年龄',
width: '100px'
},
{
prop: 'address',
label: '地址',
width: '200px'
}
]
const tableData = [
{
name: '张三',
age: 25,
address: '北京市海淀区'
},
{
name: '李四',
age: 30,
address: '上海市浦东新区'
},
{
name: '王五',
age: 28,
address: '广州市天河区'
}
]
const pagination = {
total: 100,
currentPage: 1,
pageSize: 10
}
const handlePageChange = (page) => {
pagination.currentPage = page
}
const handleSizeChange = (size) => {
pagination.pageSize = size
}
</script>
<template>
<div class="table-with-pagination">
<slot name="header" v-if="showHeader">
<div class="table-header">
<div class="table-title">数据列表</div>
</div>
</slot>
<div class="table-content">
<el-table :data="data" stripe style="width: 100%">
<el-table-column
v-for="col in columns"
:key="col.prop"
:prop="col.prop"
:label="col.label"
:width="col.width"
:align="col.align || 'left'"
>
<template #default="scope" v-if="col.formatter">
{{ col.formatter(scope.row[col.prop], scope.row) }}
</template>
</el-table-column>
</el-table>
</div>
<div class="integrated-pagination" v-if="pagination.total > 0">
<div class="pagination-info">
共 {{ pagination.total }} 条记录,第 {{ pagination.currentPage }} 页 / 共 {{ totalPages }} 页
</div>
<div class="custom-pagination">
<div class="page-size-selector">
<span>每页</span>
<el-select
:model-value="pagination.pageSize"
@update:model-value="handleSizeChange"
size="small"
style="width: 90px;"
>
<el-option label="10条" :value="10"></el-option>
<el-option label="20条" :value="20"></el-option>
<el-option label="50条" :value="50"></el-option>
<el-option label="100条" :value="100"></el-option>
</el-select>
</div>
<div class="page-jumper">
<span>跳至</span>
<el-input
v-model="jumpPage"
placeholder="页码"
size="small"
class="page-input"
@keyup.enter="jumpToPage"
></el-input>
<span></span>
<el-button size="small" @click="jumpToPage">确定</el-button>
</div>
<div class="page-buttons">
<button
class="page-btn"
:class="{ disabled: pagination.currentPage === 1 }"
@click="handlePageChange(pagination.currentPage - 1)"
>
上一页
</button>
<template v-for="page in totalPages" :key="page">
<button
v-if="
page === 1 ||
page === totalPages ||
(page >= pagination.currentPage - 2 && page <= pagination.currentPage + 2)
"
class="page-btn"
:class="{ active: page === pagination.currentPage }"
@click="handlePageChange(page)"
>
{{ page }}
</button>
<span
v-else-if="
(page === pagination.currentPage - 3 && pagination.currentPage > 4) ||
(page === pagination.currentPage + 3 && pagination.currentPage < totalPages - 3)
"
class="page-btn disabled"
>
...
</span>
</template>
<button
class="page-btn"
:class="{ disabled: pagination.currentPage === totalPages }"
@click="handlePageChange(pagination.currentPage + 1)"
>
下一页
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import { computed, ref } from 'vue'
import { ElTable, ElTableColumn, ElButton, ElSelect, ElOption, ElInput } from 'element-plus'
export default {
name: 'IntegratedTable',
components: {
ElTable,
ElTableColumn,
ElButton,
ElSelect,
ElOption,
ElInput
},
props: {
columns: {
type: Array,
required: true
},
data: {
type: Array,
required: true
},
pagination: {
type: Object,
default: () => ({
currentPage: 1,
pageSize: 10,
total: 0
})
},
showHeader: {
type: Boolean,
default: true
}
},
emits: ['page-change', 'size-change'],
setup(props, { emit }) {
// 计算总页数
const totalPages = computed(() => {
return Math.ceil(props.pagination.total / props.pagination.pageSize)
})
// 处理页码变化
const handlePageChange = (page) => {
if (page < 1 || page > totalPages.value) return
emit('page-change', page)
}
// 处理每页大小变化
const handleSizeChange = (size) => {
emit('size-change', parseInt(size))
}
// 跳转到指定页
const jumpToPage = () => {
const page = parseInt(jumpPage.value)
if (page && page >= 1 && page <= totalPages.value) {
handlePageChange(page)
}
jumpPage.value = ''
}
const jumpPage = ref('')
return {
totalPages,
handlePageChange,
handleSizeChange,
jumpToPage,
jumpPage
}
}
}
</script>
<style scoped>
.table-with-pagination {
background: white;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.table-header {
padding: 16px 20px;
background: #f8f9fa;
border-bottom: 1px solid #ebeef5;
display: flex;
justify-content: space-between;
align-items: center;
}
.table-title {
font-size: 16px;
font-weight: 600;
color: #303133;
}
.table-content {
padding: 0 20px;
}
.integrated-pagination {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 20px;
background: #f8f9fa;
border-top: 1px solid #ebeef5;
}
.pagination-info {
font-size: 14px;
color: #606266;
}
.custom-pagination {
display: flex;
align-items: center;
gap: 10px;
}
.page-size-selector {
display: flex;
align-items: center;
gap: 8px;
}
.page-jumper {
display: flex;
align-items: center;
gap: 8px;
}
.page-input {
width: 60px;
}
.page-buttons {
display: flex;
gap: 5px;
}
.page-btn {
min-width: 32px;
height: 32px;
padding: 0 8px;
border: 1px solid #dcdfe6;
background: white;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
}
.page-btn:hover {
background: #f5f7fa;
}
.page-btn.active {
background: #409eff;
color: white;
border-color: #409eff;
}
.page-btn.disabled {
color: #c0c4cc;
cursor: not-allowed;
background: #f5f7fa;
}
@media (max-width: 768px) {
.integrated-pagination {
flex-direction: column;
gap: 15px;
align-items: flex-start;
}
.table-header {
flex-direction: column;
gap: 15px;
align-items: flex-start;
}
}
</style>
import { AuthStore } from "@/stores/modules/auth";
/**
* @description 页面按钮权限
* */
export const useAuthButtons = () => {
const authStore = AuthStore();
const authButtons = authStore.authButtonListGet || [];
let currentPageAuthButton = {};
authButtons.authButton.forEach(item => (currentPageAuthButton[item] = true));
return currentPageAuthButton;
};
import { onActivated, onDeactivated, onBeforeUnmount } from "vue";
// import echarts from "@/plugins/echarts";
export const useEcharts = (myChart, options) => {
if (options && typeof options === "object") {
myChart.setOption(options);
}
const echartsResize = () => {
myChart && myChart.resize();
};
window.addEventListener("resize", echartsResize);
onActivated(() => {
window.addEventListener("resize", echartsResize);
});
onDeactivated(() => {
window.removeEventListener("resize", echartsResize);
});
onBeforeUnmount(() => {
window.removeEventListener("resize", echartsResize);
});
};
import { computed, onBeforeMount } from "vue";
import { getLightColor, getDarkColor } from "@/utils/tool";
import { GlobalStore } from "@/stores";
import { DEFAULT_PRIMARY } from "@/config/config";
import { ElMessage } from "element-plus";
import { setCssVar } from "@/utils/css";
export const useTheme = () => {
const globalStore = GlobalStore();
const themeConfig = computed(() => globalStore.themeConfig);
// 修改主题颜色
const changePrimary = val => {
if (!val) {
val = DEFAULT_PRIMARY;
ElMessage({ type: "success", message: `主题颜色已重置为 ${DEFAULT_PRIMARY}` });
}
globalStore.setThemeConfig({ ...themeConfig.value, primary: val });
document.documentElement.style.setProperty("--el-color-primary", themeConfig.value.primary);
document.documentElement.style.setProperty(
"--el-color-primary-dark-2",
themeConfig.value.isDark
? `${getLightColor(themeConfig.value.primary, 0.2)}`
: `${getDarkColor(themeConfig.value.primary, 0.3)}`
);
// 颜色加深或变浅
for (let i = 1; i <= 9; i++) {
document.documentElement.style.setProperty(
`--el-color-primary-light-${i}`,
themeConfig.value.isDark
? `${getDarkColor(themeConfig.value.primary, i / 10)}`
: `${getLightColor(themeConfig.value.primary, i / 10)}`
);
}
};
// 切换黑夜模式
const switchDark = () => {
const body = document.documentElement;
if (themeConfig.value.isDark) body.setAttribute("class", "dark");
else body.setAttribute("class", "");
changePrimary(themeConfig.value.primary);
};
onBeforeMount(() => {
changePrimary(themeConfig.value.primary);
});
// 初始化 theme 配置
const initTheme = () => {
switchDark();
changePrimary(themeConfig.value.primary);
setCssVar("--vda-theme-x", `${0}px`)
setCssVar("--vda-theme-y", `${0}px`)
setCssVar("--vda-theme-r", `${1372}px`)
const handler = () => {}
document.startViewTransition ? document.startViewTransition() : handler()
};
return {
changePrimary,
switchDark,
initTheme,
};
};
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import CardTitle from './components/CardTitle.vue'
import { withFallbackImage } from './utils'
import './styles/scrollbar.css'
import './styles/elui.css'
import './styles/main.css'
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
import CardTitle from "./components/CardTitle.vue";
import { withFallbackImage } from "./utils";
import "./styles/scrollbar.css";
import "./styles/elui.css";
import "./styles/main.css";
const app = createApp(App)
const app = createApp(App);
// 注册所有图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
app.component(key, component);
}
// 注册全局函数
app.config.globalProperties.$withFallbackImage = withFallbackImage
app.use(router)
app.use(ElementPlus)
app.component('CardTitle', CardTitle)
app.mount('#app')
\ No newline at end of file
app.config.globalProperties.$withFallbackImage = withFallbackImage;
app.use(router);
app.use(ElementPlus);
app.component("CardTitle", CardTitle);
app.mount("#app");
import * as echarts from "echarts/core";
import {
BarChart,
LineChart,
PieChart,
MapChart,
PictorialBarChart,
RadarChart,
ScatterChart,
LinesChart,
GraphChart
} from "echarts/charts";
import {
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
LegendComponent,
RadarComponent,
ToolboxComponent,
DataZoomComponent,
VisualMapComponent,
TimelineComponent,
CalendarComponent,
GraphicComponent
} from "echarts/components";
import { LabelLayout, UniversalTransition } from "echarts/features";
import { CanvasRenderer } from "echarts/renderers";
// 注册必须的组件
echarts.use([
LegendComponent,
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
BarChart,
LineChart,
PieChart,
MapChart,
RadarChart,
PictorialBarChart,
RadarComponent,
ToolboxComponent,
DataZoomComponent,
VisualMapComponent,
TimelineComponent,
CalendarComponent,
GraphicComponent,
ScatterChart,
LabelLayout,
UniversalTransition,
CanvasRenderer,
LinesChart,
GraphChart
]);
// 导出
export default echarts;
import * as components from "@element-plus/icons-vue";
export default {
install: app => {
for (const key in components) {
const componentConfig = components[key];
app.component(componentConfig.name, componentConfig);
}
}
};
export const TAGTYPE = ["primary", "success", "warning", "danger", "info"];
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'
import ThinkTankDetail from '@/views/ThinkTankDetail/index.vue'
import ReportDetail from '@/views/ReportDetail/index.vue'
import { createRouter, createWebHistory } from "vue-router";
import Home from "../views/Home.vue";
import About from "../views/About.vue";
import ThinkTankDetail from "@/views/ThinkTankDetail/index.vue";
import ReportDetail from "@/views/ReportDetail/index.vue";
// 法案相关组件
import BillHome from '@/views/bill/billHome/index.vue'
......@@ -21,7 +21,7 @@ import BillInfluenceScientificResearch from '@/views/bill/influence/scientificRe
import BillRelevantCircumstance from '@/views/bill/relevantCircumstance/index.vue'
// 出口管制
import ExportControl from '@/views/exportControl/index.vue'
import ExportControl from "@/views/exportControl/index.vue";
// 政令
import Decree from '@/views/decree/decreeHome/index.vue'
......@@ -33,50 +33,48 @@ import DecreeDeepDig from '@/views/decree/decreeLayout/deepdig/index.vue'
import DecreeInfluence from '@/views/decree/decreeLayout/influence/index.vue'
// 市场准入限制
import MarketAccessRestrictions from '@/views/marketAccessRestrictions/marketAccessHome/index.vue'
import MarketAccessLayout from '@/views/marketAccessRestrictions/marketAccessLayout/index.vue'
import MarketAccessOverview from '@/views/marketAccessRestrictions/marketAccessLayout/overview/index.vue'
import MarketAccessCase from '@/views/marketAccessRestrictions/marketAccessLayout/case/index.vue'
import MarketSingleCaseLayout from '@/views/marketAccessRestrictions/singleCaseLayout/index.vue'
import MarketSingleCaseOverview from '@/views/marketAccessRestrictions/singleCaseLayout/overview/index.vue'
import MarketSingleCaseDeepdig from '@/views/marketAccessRestrictions/singleCaseLayout/deepdig/index.vue'
import MarketAccessRestrictions from "@/views/marketAccessRestrictions/marketAccessHome/index.vue";
import MarketAccessLayout from "@/views/marketAccessRestrictions/marketAccessLayout/index.vue";
import MarketAccessOverview from "@/views/marketAccessRestrictions/marketAccessLayout/overview/index.vue";
import MarketAccessCase from "@/views/marketAccessRestrictions/marketAccessLayout/case/index.vue";
import MarketSingleCaseLayout from "@/views/marketAccessRestrictions/singleCaseLayout/index.vue";
import MarketSingleCaseOverview from "@/views/marketAccessRestrictions/singleCaseLayout/overview/index.vue";
import MarketSingleCaseDeepdig from "@/views/marketAccessRestrictions/singleCaseLayout/deepdig/index.vue";
const routes = [
// 智库系统的主要路由
{
path: '/',
name: 'Home',
component: Home,
meta: {
title: '首页'
},
},
{
path: '/about',
name: 'About',
component: About,
meta: {
title: '关于我们'
}
},
{
path: '/think-tank/:id',
name: 'ThinkTankDetail',
component: ThinkTankDetail,
meta: {
title: '智库详情'
}
},
{
path: '/report/:id',
name: 'ReportDetail',
component: ReportDetail,
meta: {
title: '报告详情'
}
},
// 智库系统的主要路由
{
path: "/",
name: "Home",
component: Home,
meta: {
title: "首页"
}
},
{
path: "/about",
name: "About",
component: About,
meta: {
title: "关于我们"
}
},
{
path: "/think-tank/:id",
name: "ThinkTankDetail",
component: ThinkTankDetail,
meta: {
title: "智库详情"
}
},
{
path: "/report/:id",
name: "ReportDetail",
component: ReportDetail,
meta: {
title: "报告详情"
}
},
// 法案系统路由
{
......@@ -191,15 +189,15 @@ const routes = [
]
},
// 出口管制首页
{
path: '/exportControl',
name: 'ExportControl',
component: ExportControl,
meta: {
title: '出口管制'
},
},
// 出口管制首页
{
path: "/exportControl",
name: "ExportControl",
component: ExportControl,
meta: {
title: "出口管制"
}
},
// 政令首页
{
......@@ -331,20 +329,68 @@ const routes = [
]
},
]
// 转移过来的页面
{
path: "/analysis",
name: "analysis",
component: () => import("@/views/analysis/index.vue"),
meta: {
title: "分析页"
}
},
{
path: "/infoplatform",
name: "infoplatform",
component: () => import("@/views/infoPlatform/index.vue"),
meta: {
title: "信息平台"
}
},
{
path: "/rulelimit",
name: "rulelimit",
component: () => import("@/views/ruleLimit/index.vue"),
meta: {
title: "规则限制"
}
},
{
path: "/ruledetail",
name: "ruledetail",
component: () => import("@/views/ruleDetail/index.vue"),
meta: {
title: "规则详情"
}
},
{
path: "/researchfunding",
name: "researchfunding",
component: () => import("@/views/researchFunding/index.vue"),
meta: {
title: "科研资助"
}
},
{
path: "/decree",
name: "decree",
component: () => import("@/views/decree/index.vue"),
meta: {
title: "政令信息"
}
}
];
const router = createRouter({
history: createWebHistory(),
routes
})
history: createWebHistory(),
routes
});
// 路由守卫 - 设置页面标题
router.beforeEach((to, from, next) => {
if (to.meta.title) {
// document.title = `${to.meta.title} - Think Tank`
}
next()
})
if (to.meta.title) {
// document.title = `${to.meta.title} - Think Tank`
}
next();
});
export default router
\ No newline at end of file
export default router;
/* 全局 css 变量 */
$primary-color: var(--el-color-primary);
$base-color: rgba(10, 87, 166, 1);
$base-font-size: 16px;
// :root {
// --base-color: #{$base-color};
// }
差异被折叠。
差异被折叠。
差异被折叠。
<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 {
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;
/* padding-left: 2%;
padding-right: 2%; */
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>
差异被折叠。
export const data = [
{
id: 11,
name: "拜登AI芯片出口管制",
info: {
fullName: "推动美国人工智能技术栈出口",
fullNameEn: "Ending Crime and Disorder on America’s Streets",
tags: ["人工智能", "出口管制", "半导体产业", "税收", "光伏产业"],
time: "2025年7月23日",
president: "唐纳德·约翰·特朗普(Donald John Trump)",
orderNum: "第14320号行政命令 (EO 14320)",
period: "签署后90天内建立机制并开始实施"
},
clause: [
{
id: 1,
content: '要求商务部在90天内建立"全栈式"美国AI出口机制。'
},
{
id: 2,
content: '要求每个纳入出口计划的提案必须涵盖完整的"全栈AI技术包"。'
},
{
id: 3,
content: '指示联邦机构提供贷款、担保、股权投资和技术援助支持入选的"优先AI出口包"。'
},
{
id: 4,
content: "要求输出技术必须符合美国出口管制法规,并由多部门对最终用户进行合规与安全联合审查。"
},
{
id: 5,
content: '明确政策目标为"减少对对手国家开发的AI技术的国际依赖"。'
},
{
id: 6,
content: '要求每个纳入出口计划的提案必须涵盖完整的"全栈AI技术包"。'
}
]
},
{
id: 22,
name: "特朗普撤销拜登AI规则",
info: {
fullName: "推动美国人工智能技术栈出口",
fullNameEn: "推动美国人工智能技术栈出口",
tags: ["AI", "出口", "管制"],
time: "2025年7月23日",
president: "唐纳德·约翰·特朗普(Donald John Trump)",
orderNum: "第14320号行政命令 (EO 14320)",
period: "签署后90天内建立机制并开始实施"
},
clause: [
{
id: 1,
content: '要求商务部在90天内建立"全栈式"美国AI出口机制。'
},
{
id: 2,
content: '要求每个纳入出口计划的提案必须涵盖完整的"全栈AI技术包"。'
},
{
id: 3,
content: '指示联邦机构提供贷款、担保、股权投资和技术援助支持入选的"优先AI出口包"。'
},
{
id: 4,
content: "要求输出技术必须符合美国出口管制法规,并由多部门对最终用户进行合规与安全联合审查。"
},
{
id: 5,
content: '明确政策目标为"减少对对手国家开发的AI技术的国际依赖"。'
}
]
},
{
id: 33,
name: "美国AI行动计划",
info: {
fullName: "推动美国人工智能技术栈出口",
fullNameEn: "推动美国人工智能技术栈出口",
tags: ["AI", "出口", "管制"],
time: "2025年7月23日",
president: "唐纳德·约翰·特朗普(Donald John Trump)",
orderNum: "第14320号行政命令 (EO 14320)",
period: "签署后90天内建立机制并开始实施"
},
clause: [
{
id: 1,
content: '要求商务部在90天内建立"全栈式"美国AI出口机制。'
},
{
id: 2,
content: '要求每个纳入出口计划的提案必须涵盖完整的"全栈AI技术包"。'
},
{
id: 3,
content: '指示联邦机构提供贷款、担保、股权投资和技术援助支持入选的"优先AI出口包"。'
},
{
id: 4,
content: "要求输出技术必须符合美国出口管制法规,并由多部门对最终用户进行合规与安全联合审查。"
},
{
id: 5,
content: '明确政策目标为"减少对对手国家开发的AI技术的国际依赖"。'
}
]
},
{
id: 44,
name: "对中国AI芯片限制",
info: {
fullName: "推动美国人工智能技术栈出口",
fullNameEn: "推动美国人工智能技术栈出口",
tags: ["AI", "出口", "管制"],
time: "2025年7月23日",
president: "唐纳德·约翰·特朗普(Donald John Trump)",
orderNum: "第14320号行政命令 (EO 14320)",
period: "签署后90天内建立机制并开始实施"
},
clause: [
{
id: 1,
content: '要求商务部在90天内建立"全栈式"美国AI出口机制。'
},
{
id: 2,
content: '要求每个纳入出口计划的提案必须涵盖完整的"全栈AI技术包"。'
},
{
id: 3,
content: '指示联邦机构提供贷款、担保、股权投资和技术援助支持入选的"优先AI出口包"。'
},
{
id: 4,
content: "要求输出技术必须符合美国出口管制法规,并由多部门对最终用户进行合规与安全联合审查。"
},
{
id: 5,
content: '明确政策目标为"减少对对手国家开发的AI技术的国际依赖"。'
}
]
}
];
差异被折叠。
<template>
<div class="sanction-container">
<!-- 页面标题区域 -->
<div class="page-header">
<!-- <h1 class="main-title">制裁分析</h1> -->
<img class="page-header-img" src="@/assets/images/decree-national.png" alt="" />
<div class="bill-details">
<div class="main-title">EO 14320-促进美国人工智能技术栈的出口</div>
<div class="bill-name-en">总统行动 | 行政命令 | Ending Crime and Disorder on America’s Streets</div>
</div>
<div class="date-author">
<div class="date">2025年7月23日</div>
<div class="author">唐纳德·约翰·特朗普(Donald John Trump))</div>
</div>
<!-- <div class="bill-info">
</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;
margin-top: 10px;
/* border-bottom: 1px solid #ebeef5; */
display: flex;
justify-content: flex-start;
align-items: center;
gap: 12px;
}
.page-header-img {
width: 64px;
height: 64px;
}
.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;
margin-right: auto;
}
.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>
</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";
const activeTab = ref("政令概况");
const setActiveTab = tabName => {
activeTab.value = tabName;
};
</script>
<style scoped>
.page-container {
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 {
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;
padding-left: 6%;
padding-right: 6%;
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>
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论