明树Git Lab

Commit 6371d7f5 authored by chenron's avatar chenron

tijiao

parent 627c0c82
Pipeline #103655 failed with stages
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
{
"recommendations": ["Vue.volar"]
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>葛洲坝交投</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
{
"name": "my-vue-project",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@element-plus/icons": "^0.0.11",
"@kjgl77/datav-vue3": "^1.7.4",
"axios": "^1.13.2",
"echarts": "^6.0.0",
"echarts-map": "^3.0.1",
"element-plus": "^2.11.8",
"less-loader": "^12.3.0",
"pinia": "^3.0.4",
"vue": "^3.5.24",
"vue-router": "^4.6.3"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.1",
"less": "^4.4.2",
"vite": "^7.2.2"
}
}
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>iconfont Demo</title>
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
<style>
.main .logo {
margin-top: 0;
height: auto;
}
.main .logo a {
display: flex;
align-items: center;
}
.main .logo .sub-title {
margin-left: 0.5em;
font-size: 22px;
color: #fff;
background: linear-gradient(-45deg, #3967FF, #B500FE);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=5072634" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe62f;</span>
<div class="name">全屏</div>
<div class="code-name">&amp;#xe62f;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1763957422227') format('woff2'),
url('iconfont.woff?t=1763957422227') format('woff'),
url('iconfont.ttf?t=1763957422227') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-quanping"></span>
<div class="name">
全屏
</div>
<div class="code-name">.icon-quanping
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-quanping"></use>
</svg>
<div class="name">全屏</div>
<div class="code-name">#icon-quanping</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>
@font-face {
font-family: "iconfont"; /* Project id 4534168 */
src: url('iconfont.woff2?t=1715591635208') format('woff2'),
url('iconfont.woff?t=1715591635208') format('woff'),
url('iconfont.ttf?t=1715591635208') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-quanping:before {
content: "\e62f";
}
window._iconfont_svg_string_5072634='<svg><symbol id="icon-quanping" viewBox="0 0 1024 1024"><path d="M181 357.5V181.2h176.4c14.3 0 25.9-11.6 25.9-25.9v-31.1c0-14.3-11.6-25.9-25.9-25.9H118c-11 0-20 9-20 20v239.4c0 14.3 11.6 25.9 25.9 25.9H155c14.4-0.1 26-11.7 26-26.1zM668.6 181.2H845v176.4c0 14.3 11.6 25.9 25.9 25.9H902c14.3 0 25.9-11.6 25.9-25.9V118.2c0-11-9-20-20-20H668.6c-14.3 0-25.9 11.6-25.9 25.9v31.1c0 14.3 11.6 26 25.9 26zM357.4 845.2H181V668.8c0-14.3-11.6-25.9-25.9-25.9H124c-14.3 0-25.9 11.6-25.9 25.9v239.4c0 11 9 20 20 20h239.4c14.3 0 25.9-11.6 25.9-25.9v-31.1c-0.1-14.4-11.7-26-26-26zM845 668.8v176.4H668.6c-14.3 0-25.9 11.6-25.9 25.9v31.1c0 14.3 11.6 25.9 25.9 25.9H908c11 0 20-9 20-20V668.8c0-14.3-11.6-25.9-25.9-25.9H871c-14.4 0-26 11.6-26 25.9z" ></path></symbol></svg>',(n=>{var t=(e=(e=document.getElementsByTagName("script"))[e.length-1]).getAttribute("data-injectcss"),e=e.getAttribute("data-disable-injectsvg");if(!e){var c,o,i,d,s,a=function(t,e){e.parentNode.insertBefore(t,e)};if(t&&!n.__iconfont__svg__cssinject__){n.__iconfont__svg__cssinject__=!0;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(t){console&&console.log(t)}}c=function(){var t,e=document.createElement("div");e.innerHTML=n._iconfont_svg_string_5072634,(e=e.getElementsByTagName("svg")[0])&&(e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.width=0,e.style.height=0,e.style.overflow="hidden",e=e,(t=document.body).firstChild?a(e,t.firstChild):t.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(c,0):(o=function(){document.removeEventListener("DOMContentLoaded",o,!1),c()},document.addEventListener("DOMContentLoaded",o,!1)):document.attachEvent&&(i=c,d=n.document,s=!1,r(),d.onreadystatechange=function(){"complete"==d.readyState&&(d.onreadystatechange=null,l())})}function l(){s||(s=!0,i())}function r(){try{d.documentElement.doScroll("left")}catch(t){return void setTimeout(r,50)}l()}})(window);
\ No newline at end of file
{
"id": "5072634",
"name": "葛洲坝交投",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "5650911",
"name": "全屏",
"font_class": "quanping",
"unicode": "e62f",
"unicode_decimal": 58927
}
]
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
\ No newline at end of file
<template>
<div class="app-container">
<router-view />
</div>
</template>
<script setup></script>
<style scoped lang="less"></style>
<template>
<!-- ECharts容器:设置方形尺寸 -->
<div class="double-circle-container" ref="chartRef"></div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import * as echarts from "echarts";
// 可传入的进度参数
const props = defineProps({
percent: {
type: Number,
default: 33.8, // 默认进度33.8%
},
});
const chartRef = ref(null);
let myChart = null;
// 初始化图表
const initChart = () => {
myChart = echarts.init(chartRef.value);
const option = {
// // 背景色:匹配截图的深蓝色网格背景
// backgroundColor: "transparent",
// 中心百分比文字
title: {
text: `${props.percent}%`,
left: "center",
top: "center",
textStyle: {
fontSize: 18,
fontWeight: "bold",
color: "#3b82f6", // 蓝色文字(匹配截图)
lineHeight: 1.2,
},
},
series: [
// 1. 外层圆环边框(浅色蓝环)
{
type: "pie",
radius: ["85%", "70%"], // 外层边框的粗细
startAngle: 0,
itemStyle: {
// color: "#87ceeb", // 浅蓝色实线边框
borderColor: "#8692fc",
borderWidth: 1,
},
label: { show: false },
labelLine: { show: false },
data: [
{ value: 33.8, name: "绿色扇区", itemStyle: { color: "#00FF00" } }, // 绿色扇区
{
value: 66.2,
name: "背景扇区",
itemStyle: { color: "transparent" },
},
],
},
],
};
myChart.setOption(option);
};
// 监听窗口resize实现自适应
const handleResize = () => {
myChart?.resize();
};
onMounted(() => {
initChart();
window.addEventListener("resize", handleResize);
});
onUnmounted(() => {
window.removeEventListener("resize", handleResize);
myChart?.dispose();
});
</script>
<style scoped lang="less">
.double-circle-container {
.vw(width, 120);
.vh(height,120);
// width: 120px;
// height: 120px;
}
</style>
<template>
<div class="stat-cards-container">
<div class="stat-card" v-for="(item, idx) in props.numberList" :key="idx">
<div class="stat-card-title">{{ item.title }}</div>
<div class="stat-card-value">
<div class="card-value-top">
<div>
<p class="pro-title">11月完成</p>
<p class="pro-value">1.1亿元</p>
</div>
<div>
<p class="pro-title">第三季度完成</p>
<p class="pro-value">4.21亿元</p>
</div>
</div>
<div class="card-value-bottom">
<div>
<p class="pro-title">2025年累计完成</p>
<p class="pro-value">112.1亿元</p>
</div>
<div class="value-bottom-right">
<p class="comparison">累计同期环比</p>
<p class="comparison-value">+1.2%</p>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, reactive, watch, ref } from "vue";
const props = defineProps({
numberList: {
type: Array,
default: () => [],
},
});
</script>
<style scoped lang="less">
.stat-cards-container {
display: flex;
justify-content: center;
align-items: center;
.stat-card {
.vw(width, 170);
.vw(border-radius, 5);
.vw(padding, 10);
.vw(margin,10);
background-image: url("../assets/images/complete.png");
background-repeat: no-repeat;
background-size: 100% 100%;
background-position: center;
.stat-card-title {
.font(12);
text-align: center;
}
.stat-card-value {
.font(12);
.card-value-top,
.card-value-bottom {
display: flex;
justify-content: space-between;
p {
height: 10px;
}
.pro-title {
.font(12);
}
.pro-value {
.font(16);
color: @Color;
}
.comparison {
.font(10);
}
.comparison-value {
color: green;
}
}
.value-bottom-right {
.vh(margin-top,13);
}
}
}
}
</style>
<template>
<div class="stat-cards-container">
<div class="stat-card" v-for="(item, idx) in props.numberList" :key="idx">
<div class="stat-card__title">{{ item.title }}</div>
<div class="stat-card__value">{{ item.value }}</div>
<div class="amount">
<div>
<p class="amount-title">实际完成金额</p>
<p class="amount-value">2.87亿元</p>
</div>
<div>
<p class="amount-title">计划完成金额</p>
<p class="amount-value">4.21亿元</p>
</div>
</div>
</div>
</div>
</template>
<script setup>
const props = defineProps({
numberList: {
type: Array,
default: () => [],
},
});
</script>
<style scoped lang="less">
.stat-cards-container {
display: flex;
.stat-card {
.vw(width, 170);
.vw(border-radius, 5);
.vw(padding, 10);
.vw(margin,10);
background-image: url("../assets/images/total2.png");
background-repeat: no-repeat;
background-size: 100% 100%;
background-position: center;
.stat-card__title {
.font(12);
font-weight: 700;
}
.stat-card__value {
.font(16);
}
.amount {
display: flex;
justify-content: space-between;
.amount-title {
.font(10);
.vh(height, 5);
}
.amount-value {
.font(20);
color: @Color;
}
}
}
}
</style>
<template>
<div class="stat-cards-container">
<div class="stat-card" v-for="(item, idx) in props.numberList" :key="idx">
<div class="stat-card__title">{{ item.title }}</div>
<div class="stat-card__value">{{ item.value }}</div>
</div>
</div>
</template>
<script setup>
import { onMounted, reactive, watch, ref } from "vue";
const props = defineProps({
numberList: {
type: Array,
default: () => [],
},
});
</script>
<style scoped lang="less">
.stat-cards-container {
display: flex;
.stat-card {
.vw(width, 170);
.vw(border-radius, 5);
.vw(padding, 10);
.vw(margin,10);
background-image: url("../assets/images/total2.png");
background-repeat: no-repeat;
background-size: 100% 100%;
background-position: center;
.stat-card__title {
.font(12);
}
.stat-card__value {
.vh(margin-top, 10);
.font(20);
}
}
}
</style>
<template>
<div class="construct-container">
<div class="construct-left">
<div class="tag-image">
<img src="../assets/images/建设.png" />
</div>
<div class="construct-left-map">
<Map />
</div>
</div>
<div class="construct-right">
<div>
<div class="info-title">项目概况</div>
<div>
<CommonTotal :numberList="projectList" />
</div>
</div>
<div>
<div class="info-title">投资完成情况</div>
<div>
<CommonTotal :numberList="investmentList" />
</div>
</div>
<div>
<div class="info-title">投资完成情况</div>
<div class="progress">
<div><CircleProgress /></div>
<div class="investment-progress">
<span>19.72/58.42亿元</span>
<div class="progress-image"></div>
</div>
</div>
</div>
<div>
<div class="info-title">投资回收完成情况</div>
<div>
<CommonTotal :numberList="recycleList" />
</div>
</div>
</div>
</div>
</template>
<script setup>
import Map from "./Map.vue";
import CommonTotal from "./CommonTotal.vue";
import { reactive, ref, onMounted, onUnmounted } from "vue";
import CircleProgress from "./CircleProgress.vue";
const projectList = reactive([
{ title: "总个数(个)", value: "59" },
{ title: "总投资(亿元)", value: "2733.35" },
{ title: "总规模(公里)", value: "5116.72" },
]);
const investmentList = reactive([
{ title: "10月完成投资(亿元)", value: "0" },
{ title: "2025年完成投资(亿元)", value: "19.725" },
{ title: "累计完成投资(亿元)", value: "807.56" },
]);
// recycleList
const recycleList = reactive([
{ title: "10月完成投资(亿元)", value: "0" },
{ title: "2025年完成投资(亿元)", value: "2.98" },
{ title: "完成率", value: "50.2%" },
]);
</script>
<style scoped lang="less">
.construct-container {
display: flex;
.construct-left {
// width: 65%;
flex: 1;
height: 100%;
.tag-image {
img {
.vw(width, 85);
}
}
.construct-left-map {
.vh(height, 700);
.vh(padding-top, 4);
}
}
.construct-right {
display: flex;
flex-direction: column;
justify-content: space-between;
.info-title {
.vw(width, 180);
.vh(height, 30);
.vh(line-height, 30);
.vw(margin-left,10);
.font(14);
.vw(padding-left,23);
text-align: left;
color: #fff;
font-family: YouSheBiaoTiYuan;
background-image: url("../assets/images/tag.png");
background-repeat: no-repeat;
background-size: cover;
background-position: center;
font-weight: 700;
letter-spacing: 3px;
background-size: 100% 100%;
}
.progress {
display: flex;
align-items: center;
.vw(margin-left, 10);
.investment-progress {
display: flex;
flex-direction: column;
align-items: end;
span {
.vh(margin-bottom,-20);
}
.progress-image {
justify-content: center;
align-items: center;
.vw(width,520);
.vh(height,85);
background-image: url("../assets/images/箭头.png");
background-repeat: no-repeat;
background-size: contain;
background-position: center;
background-size: 100% 100%;
}
}
}
}
}
</style>
<template>
<!-- <div class="map-container">
<div id="container" ref="mapRef"></div>
</div> -->
<div class="tourism">
<div style="background-color: #ffffff">
<div id="container"></div>
</div>
</div>
</template>
<script setup>
import AMapLoader from "@amap/amap-jsapi-loader";
import { onMounted } from "vue";
import gansuLine from "./gansu.json";
let map = null;
// 注意:要想市级区域正常显示,必须添加安全密钥
window._AMapSecurityConfig = {
securityJsCode: "75a8291a9e8f7c838fc5e4dd0d538f30",
};
// 初始化地图
const handleInitMap = () => {
AMapLoader.load({
key: "c691971f068b92c897fb908c4ddef6d4", // 申请好的Web端开发者Key
version: "2.0",
plugins: ["AMap.DistrictSearch", "AMap.GeoJSON"],
})
.then((AMap) => {
map = new AMap.Map("container", {
//设置地图容器id
viewMode: "2D",
zoom: 4, //初始化地图级别
center: [113.808299, 34.791787], //初始化地图中心点位置
mapStyle: "amap://styles/2d017848d08f94f20b6e50aaae661148",
});
let districtSearch = new AMap.DistrictSearch({
subdistrict: 0, //获取边界不需要返回下级行政区
extensions: "all", //返回行政区边界坐标组等具体信息
level: "province", //查询行政级别为 市 province-省 district-市
});
// handleDistrict(districtSearch);
addPolylines();
handleAddMarket();
})
.catch((e) => {
console.log(e);
});
};
// 高亮和描边
const handleDistrict = (districtSearch) => {
let polygons = [];
// let arr = ["湖北省", "湖南省"]; //此处为高亮的市名
districtSearch.search("中华人民共和国", function (status, result) {
// 查询成功时,result即为对应的行政区信息
// map.remove(polygons); //清除上次结果
let bounds = result.districtList[0].boundaries;
if (bounds) {
for (let i = 0, l = bounds.length; i < l; i++) {
//生成行政区划polygon
let polygon = new AMap.Polygon({
strokeWeight: 1,
path: bounds[i],
fillOpacity: 0.4,
fillColor: "#80d8ff",
strokeColor: "#0091ea",
});
polygons.push(polygon);
}
}
// 描边
for (let i = 0; i < bounds.length; i++) {
let outerPolyline = new AMap.Polyline({
path: bounds[i],
strokeColor: "#0435F9",
strokeWeight: 3,
map: map,
});
map.add(outerPolyline);
}
map.add(polygons);
map.setFitView(polygons); //视口自适应
});
};
// 添加新路线
const addPolylines = () => {
let geojsonObj = new AMap.GeoJSON({
geoJSON: gansuLine,
getPolyline: function (geojson, lnglats) {
// 生成路线
let polylineObj = new AMap.Polyline({
path: lnglats,
strokeWeight: 4,
strokeColor: "red",
extData: geojson.properties, // 自定义属性数据
});
// 生成新的路线,用于覆盖旧的
const newPolyline = new AMap.Polyline({
path: lnglats,
strokeWeight: 4,
strokeColor: "#00DDEB",
isOutline: true,
borderWeight: 2,
outlineColor: "rgba(0, 221, 235, 1)",
});
map.add(newPolyline);
newPolyline.hide();
// 获取路线数据
const properties = polylineObj.getExtData();
// 填报内容
let content = `
<div class="infoWindow">
<p class="infoWindow-title">${properties.name}</p>
</div>
`;
// 创建 infoWindow 实例
let infoWindow = new AMap.InfoWindow({
isCustom: true, // 使用自定义窗体
autoMove: true, // 是否自动调整窗体到视野内
closeWhenClickMap: true, // 控制是否在鼠标点击地图后关闭信息窗体
content: content, // 传入 dom 对象,或者 html 字符串
offset: new AMap.Pixel(120, 100),
});
// 鼠标经过
polylineObj.on("mouseover", function (e) {
console.log(e, "243234");
newPolyline.show();
infoWindow.open(map, [`${e.lnglat.getLng()}`, `${e.lnglat.getLat()}`]);
});
// 鼠标移出
polylineObj.on("mouseout", function (e) {
newPolyline.hide();
infoWindow.close();
});
// 鼠标双击
polylineObj.on("dblclick", function (e) {
const data = polylineObj.getExtData();
// showProject(data);
});
return polylineObj;
},
});
map.add(geojsonObj);
};
// 添加标记
const handleAddMarket = () => {
const markers = [];
const positionsList = [
{
number: 1,
position: [116.405467, 39.907761],
},
{
number: 5,
position: [114.298569, 30.584354],
},
{
number: 6,
position: [117.190186, 39.125595],
},
{
number: 4,
position: [112.549248, 37.857014],
},
{
number: 8,
position: [123.429092, 41.796768],
},
{
number: 2,
position: [121.472641, 31.231707],
},
{
number: 7,
position: [119.306236, 26.075302],
},
{
number: 9,
position: [106.504959, 29.533155],
},
{
number: 6,
position: [91.1145, 29.64415],
},
{
number: 3,
position: [101.77782, 36.61729],
},
{
number: 8,
position: [87.61688, 43.82663],
},
{
number: 10,
position: [111.75199, 40.84149],
},
{
number: 9,
position: [126.642464, 45.756966],
},
];
for (var i = 0, marker; i < positionsList.length; i++) {
marker = new AMap.Marker({
map: map,
position: positionsList[i].position,
// icon: "//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
offset: new AMap.Pixel(-13, -30),
content:
"" +
'<div class="custom-content-marker">' +
'<img src="//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png">' +
`<div class="anchorPoint"">${positionsList[i].number}</div>` +
"</div>",
});
markers.push(marker);
}
map.add([markers]);
};
onMounted(() => {
handleInitMap();
});
</script>
<style scoped lang="less">
.tourism {
width: 100%;
margin: 0 auto;
box-sizing: border-box;
}
#container {
padding: 0px;
margin: 0px auto;
width: 100%;
height: 800px;
}
.custom-content-marker {
position: relative;
width: 25px;
height: 34px;
}
/deep/.infoWindow {
color: #fff;
background-image: url("../assets/images/infoWindow.png");
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
// line-height: 32px;
// padding: 1px 0 25px 25px;
padding-left: 30px;
// padding-top: 8px;
width: 315px;
height: 220px;
}
/deep/.infoWindow-title {
display: flex;
align-items: center;
justify-items: flex-start;
height: 70px;
line-height: 70px;
.font(16);
font-weight: 700;
}
/deep/.infoWindow-content {
.font(24);
position: relative;
span {
display: inline-block;
position: absolute;
top: -50%;
}
}
/deep/.anchorPoint {
position: absolute;
color: #fff;
position: absolute;
top: 30%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
<template>
<div class="construct-container">
<div class="construct-left">
<div class="tag-image">
<img src="../assets/images/建设.png" />
</div>
<div class="construct-left-map">
<Map />
</div>
</div>
<div class="construct-right">
<div>
<div class="info-title">项目概况</div>
<div>
<CommonTotal :numberList="projectList" />
</div>
</div>
<div>
<div class="info-title">投资完成情况</div>
<div>
<CommonTotal :numberList="investmentList" />
</div>
</div>
<div>
<div class="info-title">经营计划完成情况</div>
<div>
<CommonComplete :numberList="completeList" />
</div>
</div>
<div>
<div class="info-title">投资回收完成情况</div>
<div>
<CommonTotal :numberList="recycleList" />
</div>
</div>
<div>
<div class="info-title">2025年经营计划完成进度</div>
<div>
<CommonPlant :numberList="operationList" />
</div>
</div>
</div>
</div>
</template>
<script setup>
import Map from "./Map.vue";
import CommonTotal from "./CommonTotal.vue";
import CommonComplete from "./CommonComplete.vue";
import CommonPlant from "./CommonPlant.vue";
import { reactive, ref, onMounted, onUnmounted } from "vue";
const projectList = reactive([
{ title: "总个数(个)", value: "59" },
{ title: "总投资(亿元)", value: "2733.35" },
{ title: "总规模(公里)", value: "5116.72" },
]);
const investmentList = reactive([
{ title: "10月完成投资(亿元)", value: "0" },
{ title: "2025年完成投资(亿元)", value: "19.725" },
{ title: "累计完成投资(亿元)", value: "807.56" },
]);
const recycleList = reactive([
{ title: "10月完成投资(亿元)", value: "0" },
{ title: "2025年完成投资(亿元)", value: "2.98" },
{ title: "完成率", value: "50.2%" },
]);
const operationList = reactive([
{ title: "营业收入完成进度", value: "68.1%" },
{ title: "运营成本完成进度", value: "68.1%" },
{ title: "利润总额完成进度", value: "68.1%" },
]);
const completeList = reactive([
{ title: "营业收入" },
{ title: "运营成本" },
{ title: "利润总额" },
]);
</script>
<style scoped lang="less">
.construct-container {
display: flex;
.construct-left {
// width: 65%;
flex: 1;
height: 100%;
.construct-left-map {
.vh(height, 700);
.vh(padding-top, 4);
}
}
.construct-right {
display: flex;
flex-direction: column;
justify-content: space-between;
.info-title {
.vw(width, 200);
.vh(height, 30);
.vh(line-height, 30);
.vw(margin-left,10);
.font(14);
.vw(padding-left,23);
text-align: left;
color: #fff;
font-family: YouSheBiaoTiYuan;
background-image: url("../assets/images/tag.png");
background-repeat: no-repeat;
background-size: cover;
background-position: center;
font-weight: 700;
letter-spacing: 3px;
background-size: 100% 100%;
}
}
}
</style>
<template>
<div class="stat-cards-container">
<div class="stat-card" v-for="(item, idx) in numberList" :key="idx">
<div class="stat-card__title">{{ item.title }}</div>
<div class="stat-card__value">{{ item.value }}</div>
</div>
</div>
</template>
<script setup>
import { onMounted, reactive, watch, ref } from "vue";
const props = defineProps({
currentName: {
type: String,
default: "立项",
},
});
const numberList = ref([]);
// 根据currentName设置不同的数据
const setNumberList = (name) => {
if (name === "立项") {
numberList.value = [
{ title: "总个数(个)", value: "59" },
{ title: "总投资(亿元)", value: "2733.35" },
{ title: "总规模(公里)", value: "5116.72" },
];
} else {
numberList.value = [
{ title: "总个数(个)", value: "59" },
{ title: "总投资(亿元)", value: "2733.35" },
{ title: "总规模(公里)", value: "5116.72" },
{ title: "累计完成投资(亿元)", value: "3116.44" },
];
}
};
watch(
() => props.currentName,
(newVal) => {
setNumberList(newVal);
},
{
immediate: true,
deep: true,
}
);
onMounted(() => {
setNumberList(props.currentName);
});
</script>
<style scoped lang="less">
.stat-cards-container {
display: flex;
justify-content: center;
align-items: center;
.stat-card {
.vw(width, 180);
.vh(height, 80);
.vw(border-radius, 5);
.vw(padding, 10);
.vw(padding, 10);
.vw(margin,10);
background-image: url("../assets/images/total.png");
background-repeat: no-repeat;
background-size: cover;
background-position: center;
.stat-card__title {
.font(14);
}
.stat-card__value {
.vh(margin-top, 20);
.font(20);
}
}
}
</style>
This source diff could not be displayed because it is too large. You can view the blob instead.
<template>
<el-container class="smart-city-container">
<!-- 顶部Header -->
<el-header class="city-header">
<div class="header-left">
<span class="city-name"></span>
</div>
<!-- </div> -->
<div class="header-right">
<div>
<el-dropdown>
<span class="username">管理员</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item>系统设置</el-dropdown-item>
<el-dropdown-item @click="handleLogout"
>退出登录</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
<!-- </div> -->
</el-header>
<el-container>
<!-- 侧边Aside -->
<el-aside width="220px" class="city-aside">
<el-menu
:default-active="$route.path"
active-text-color="#409EFF"
background-color="#1f313b"
text-color="#fff"
router
>
<template v-for="route in menuRoutes" :key="route.path">
<el-menu-item v-if="!route.meta?.parent" :index="route.path">
<el-icon><component :is="route.meta?.icon || 'menu'" /></el-icon>
<span>{{ route.meta?.menuName || route.name }}</span>
</el-menu-item>
<el-sub-menu v-else :index="route.meta.parent">
<template #title>
<el-icon
><component :is="route.meta?.icon || 'menu'"
/></el-icon>
<span>{{ route.meta.parent }}</span>
</template>
<el-menu-item
:index="route.path"
style="padding-left: 70px !important"
>
{{ route.meta.menuName }}
</el-menu-item>
</el-sub-menu>
</template>
</el-menu>
</el-aside>
<!-- 主内容Main -->
<el-main class="city-main">
<router-view />
</el-main>
</el-container>
</el-container>
</template>
<script setup>
import { computed } from "vue";
import { useRouter } from "vue-router";
const router = useRouter();
// 计算菜单路由
const menuRoutes = computed(() => {
const mainRoute = router.options.routes.find((route) => route.path === "/");
return mainRoute?.children || [];
});
const hanldeChangeLang = (type) => {
localStorage.setItem("lang", type);
};
// 处理退出登录
const handleLogout = () => {
// 清除登录状态
localStorage.removeItem("token");
// 跳转到登录页
router.push("/login");
};
</script>
<style scoped>
.smart-city-container {
height: 100vh;
overflow: hidden;
}
/* 选中菜单项样式 */
.el-menu-item.is-active {
background-color: #ecf3fd;
color: #3d84ee;
border-right: 4px solid #3d84ee;
}
.city-header {
width: 100%;
height: 64px;
background: #3db8c5
url("https://apaas-static.oss-cn-beijing.aliyuncs.com/app/header_bg.jpg")
no-repeat fixed top left / 100% 64px;
color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
}
.city-name {
font-size: 20px;
font-weight: bold;
}
.user-info {
display: flex;
align-items: center;
cursor: pointer;
}
.username {
margin-left: 10px;
color: #fff;
cursor: pointer;
}
.city-aside {
background-color: #fff;
width: 240px;
height: 100%;
box-shadow: 0 6px 10px 0 rgba(36, 36, 63, 0.05);
overflow: auto;
}
.city-main {
height: calc(100vh - 60px);
overflow-y: auto;
--el-main-padding: 0;
}
.header-right {
display: flex;
}
</style>
<template>
<div class="breadcrumb">
<el-breadcrumb separator="/">
<el-breadcrumb-item>
<router-link to="/homePage">首页</router-link>
</el-breadcrumb-item>
<el-breadcrumb-item v-for="item in breadcrumbList" :key="item.path">
<router-link :to="item.path">{{ item.title }}</router-link>
</el-breadcrumb-item>
</el-breadcrumb>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const breadcrumbList = ref([])
// 生成面包屑数据
const generateBreadcrumb = matchedRoutes => {
return matchedRoutes
.filter(route => route.meta?.menuName && route.path !== '/homePage')
.map(route => ({
path: route.path,
title: route.meta?.menuName || route.name || '未知页面'
}))
}
watch(
() => route.matched,
newVal => {
breadcrumbList.value = generateBreadcrumb(newVal)
},
{ immediate: true }
)
</script>
<style scoped lang="less">
.breadcrumb {
margin-bottom: 16px;
padding: 8px 0;
border-radius: 4px;
}
</style>
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElIcons from '@element-plus/icons'
import router from './router'
const app = createApp(App)
for (const [key, component] of Object.entries(ElIcons)) {
app.component(key, component)
}
app.use(ElementPlus).use(router).mount('#app')
import { createRouter, createWebHashHistory } from 'vue-router'
import MainLayout from '@/layouts/MainLayout.vue'
const routes = [
{
path: '/login',
name: 'login',
component: () => import('@/views/login/index.vue'),
meta: { requiresAuth: false }
},
{
path: '/',
name: '首页',
redirect: '/homePage',
component: MainLayout,
meta: { requiresAuth: true },
children: [
{
path: '/homePage',
name: '数据大屏',
title: 'dataSummary',
component: () => import('@/views/homePage/index.vue'),
meta: { menuName: '数据大屏', icon: 'home' }
},
// {
// path: '/overview/monitor',
// name: 'monitor',
// component: () => import('@/views/overview/MonitorView.vue'),
// meta: { menuName: '实时监测', parent: '城市概览', icon: 'monitor' },
// title: 'cityOverview'
// },
// {
// path: '/overview/analysis',
// name: 'analysis',
// component: () => import('@/views/overview/AnalysisView.vue'),
// meta: { menuName: '统计分析', parent: '环境管理', icon: 'data-analysis' },
// title: 'environmentalManagement'
// },
// {
// path: '/traffic/status',
// name: 'traffic-status',
// component: () => import('@/views/traffic/StatusView.vue'),
// meta: { menuName: '实时路况', parent: '社区管理', icon: 'traffic' },
// title: 'communityManagement'
// },
// {
// path: '/traffic/control',
// name: 'traffic-control',
// component: () => import('@/views/traffic/ControlView.vue'),
// meta: { menuName: '信号灯控制', parent: '交通管理', icon: 'traffic-light' },
// title: 'trafficManagement'
// },
// {
// path: '/environment',
// name: 'environment',
// component: () => import('@/views/EnvironmentView.vue'),
// meta: { menuName: '环境监测', icon: 'environment' },
// title: 'environmentalMonitoring'
// },
// {
// path: '/worker',
// name: 'worker',
// component: () => import('@/views/worker/worker.vue'),
// meta: { menuName: '系统日志', icon: 'worker' },
// title: 'worker'
// }
]
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
// 路由守卫 - 登录验证
router.beforeEach((to, from, next) => {
const isAuthenticated = localStorage.getItem('token') // 检查登录状态
if (to.meta.requiresAuth && !isAuthenticated) {
next('/login')
} else if (to.path === '/login' && isAuthenticated) {
next('/')
} else {
next()
}
})
export default router
const homeRoute = [
{
}
]
export default homeRoute
全局样式重置和滚动条控制
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
overflow: hidden; /* 隐藏浏览器滚动条 */
margin: 0;
padding: 0;
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
}
#app {
height: 100vh;
width: 100vw;
overflow: hidden; /* 确保应用容器不产生滚动条 */
}
/* 自定义滚动条样式 */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
/* 确保地图容器不产生滚动条 */
.map-container {
width: 100%;
height: 100%;
overflow: hidden;
}
#container {
width: 100%;
height: 100%;
overflow: hidden;
}
@charset "utf-8";
@designWidth: 1920; // 默认设计稿的宽度(根据开发UI稿更改)
@designHeight: 1080; // 默认设计稿的高度(根据开发UI稿更改)
.vw(@name, @px) {
@{name}: (@px / @designWidth) * 100vw;
}
.vh(@name, @px) {
@{name}: (@px / @designHeight) * 100vh;
}
.font(@px) {
font-size: (@px / @designWidth) * 100vw;
}
// 公共颜色
@Color:#96F6FF;
\ No newline at end of file
<template>
<div class="home-container">
<div class="header">
<el-row :gutter="20">
<el-col :span="5" class="header-left">
<div
class="nav-btn"
:class="{ active: selectedLeftBtn === 'equity' }"
@click="selectLeftBtn('equity')"
>
股权投资
</div>
<div
class="nav-btn"
:class="{ active: selectedLeftBtn === 'risk' }"
@click="selectLeftBtn('risk')"
>
固定风险投资
</div>
</el-col>
<el-col :span="14" class="title-section">
<p class="system-title">葛洲坝集团交通投资有限公司投资决策分析系统</p>
</el-col>
<el-col :span="5" class="header-right">
<div
class="nav-btn"
:class="{ active: selectedRightBtn === 'realestate' }"
@click="selectRightBtn('realestate')"
>
房地产投资
</div>
<div
class="nav-btn"
:class="{ active: selectedRightBtn === 'finance' }"
@click="selectRightBtn('finance')"
>
融资建设投资
</div>
</el-col>
</el-row>
</div>
<div class="content">
<div class="fullscreen-btn">
<span @click="toggleFullscreen" class="fullscreen-text">
<el-icon :size="18">
<full-screen />
</el-icon>
{{ isFullscreen ? "退出全屏" : "全屏" }}
</span>
</div>
<div class="content-btn">
<span
v-for="item in navList"
:key="item.index"
:class="{ active: selectedContentBtn === item.index }"
@click="selectContentBtn(item)"
>{{ item.name }}
</span>
</div>
<ProjectApproval
:currentName="selectedContentName"
v-if="
selectedContentBtn === 1 ||
selectedContentBtn === 4 ||
selectedContentBtn === 5
"
/>
<Construct v-else-if="selectedContentBtn === 2" />
<Operation v-else />
</div>
<div class="bottom"></div>
</div>
</template>
<script setup>
import Construct from "@/components/Construct.vue";
import ProjectApproval from "@/components/ProjectApproval.vue";
import Operation from "@/components/Operation.vue";
import { reactive, ref } from "vue";
import component from "element-plus/es/components/tree-select/src/tree-select-option.mjs";
const selectedLeftBtn = ref("equity");
const selectedRightBtn = ref("");
const selectedContentBtn = ref(3);
const selectedContentName = ref("立项");
const isFullscreen = ref(false);
const showPopup = ref(false);
const currentProject = ref({});
const popupStyle = ref({});
const navList = reactive([
{
index: 1,
name: "立项",
},
{
index: 2,
name: "建设",
},
{
index: 3,
name: "运营",
},
{
index: 4,
name: "转让",
},
{
index: 5,
name: "退出",
},
]);
const selectLeftBtn = (btn) => {
selectedLeftBtn.value = btn;
selectedRightBtn.value = "";
};
const selectRightBtn = (btn) => {
selectedRightBtn.value = btn;
selectedLeftBtn.value = "";
};
const selectContentBtn = (item) => {
selectedContentBtn.value = item.index;
selectedContentName.value = item.name;
};
const showProjectPopup = (event) => {
currentProject.value = {
name: "项目001",
data: [
{ label: "数据01", value: "3654.89", unit: "单位" },
{ label: "数据02", value: "3654.89", unit: "单位" },
{ label: "数据03", value: "3654.89", unit: "单位" },
],
};
popupStyle.value = {
left: `${event.clientX}px`,
top: `${event.clientY - 100}px`,
};
showPopup.value = true;
};
// 全屏切换功能
const toggleFullscreen = () => {
const homeContainer = document.querySelector(".home-container");
if (isFullscreen.value) {
// 退出全屏
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
homeContainer.style.height = "100%";
} else {
// 进入全屏
if (homeContainer.requestFullscreen) {
homeContainer.requestFullscreen();
} else if (homeContainer.webkitRequestFullscreen) {
homeContainer.webkitRequestFullscreen();
} else if (homeContainer.msRequestFullscreen) {
homeContainer.msRequestFullscreen();
}
homeContainer.style.height = "100vh";
}
isFullscreen.value = !isFullscreen.value;
};
// 监听全屏变化事件
window.addEventListener("fullscreenchange", () => {
if (!document.fullscreenElement) {
isFullscreen.value = false;
const homeContainer = document.querySelector(".home-container");
if (homeContainer) homeContainer.style.height = "100%";
} else {
isFullscreen.value = true;
const homeContainer = document.querySelector(".home-container");
if (homeContainer) homeContainer.style.height = "100vh";
}
});
</script>
<style scoped lang="less">
.home-container {
background-image: url("../../assets/images/bg.png");
background-repeat: no-repeat;
background-size: cover;
background-position: center;
width: 100%;
height: 100%;
overflow: hidden;
color: #fff;
display: flex;
flex-direction: column;
justify-content: space-between;
.header {
width: 100%;
.vh(height, 80);
text-align: center;
.title-section {
background-image: url("../../assets/images/header.png");
background-repeat: no-repeat;
background-size: cover;
background-position: center;
font-weight: 700;
letter-spacing: 3px;
.vh(margin-top, -15);
.font(24);
}
.header-left {
display: flex;
// justify-content: center;
align-items: center;
padding-left: 75px;
.nav-btn {
width: 100%;
.vh(line-height, 40);
cursor: pointer;
color: #fff;
.font(14);
background-repeat: no-repeat;
background-size: cover;
background-position: center;
&:not(.active) {
background-image: url("../../assets/images/left-btn.png");
}
&.active {
background-image: url("../../assets/images/left-hlightBtn.png");
}
}
}
.header-right {
display: flex;
justify-content: center;
align-items: center;
.nav-btn {
width: 100%;
.vh(line-height, 40);
cursor: pointer;
color: #fff;
.font(14);
background-repeat: no-repeat;
background-size: cover;
background-position: center;
&:not(.active) {
background-image: url("../../assets/images/right-btn.png");
}
&.active {
background-image: url("../../assets/images/right-hight-btn.png");
}
}
}
}
.content {
flex: 1;
.vw(padding-left, 20);
.vw(padding-right, 20);
.content-btn {
.vh(margin-top,-10);
.vh(margin-bottom,20);
text-align: center;
span {
.font(14);
.vw(width,110);
.vh(height,35);
display: inline-block;
cursor: pointer;
}
:nth-child(1) {
background-repeat: no-repeat;
background-size: cover;
background-position: center;
.vw(width,105);
.vh(height,35);
.vh(line-height,35);
text-align: center;
.vw(margin-right,-7);
background-image: url("../../assets/images/立项.png");
&.active {
background-image: url("../../assets/images/nav-hight-btn.png");
}
}
:nth-child(5) {
background-repeat: no-repeat;
background-size: cover;
background-position: center;
.vw(width,105);
.vh(height,35);
.vh(line-height,35);
text-align: center;
background-image: url("../../assets/images/退出.png");
&.active {
background-image: url("../../assets/images/退出-active.png");
}
}
:nth-child(2),
:nth-child(3),
:nth-child(4) {
background-repeat: no-repeat;
background-size: cover;
background-position: center;
.vw(width,108);
.vh(height,35);
.vh(line-height,35);
.vw(margin-right,-7);
text-align: center;
background-image: url("../../assets/images/default-btn.png");
&.active {
background-image: url("../../assets/images/nav-hight-btn.png");
}
}
}
}
.bottom {
background-image: url("../../assets/images/bottom.png");
background-repeat: no-repeat;
background-size: cover;
background-position: center;
width: 100%;
.vh(height, 80);
}
.fullscreen-btn {
display: flex;
cursor: pointer;
span {
margin-left: auto;
color: white;
font-weight: 700;
.font(16);
display: flex;
align-items: center;
gap: 6px;
}
}
}
</style>
<template>
<div class="map-container">
<div id="container" ref="mapRef"></div>
<div v-if="loading" class="loading">地图加载中...</div>
<div v-if="error" class="error">{{ error }}</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
const mapRef = ref(null);
const loading = ref(true);
const error = ref("");
let map = null;
let polylines = [];
window._AMapSecurityConfig = {
securityJsCode: "75a8291a9e8f7c838fc5e4dd0d538f30",
};
// 高德地图API密钥(请替换为您的实际密钥)
const AMAP_KEY = "c691971f068b92c897fb908c4ddef6d4";
// 折线数据 - 覆盖全国各省的不同线路
const polylineData = [
// 省内连接线
{
name: "丽江鹤峰到邬阳路线(从国道出发)",
type: "national",
path: [
[100.23, 26.88], // 丽江(云南省丽江市)
[101.5, 27.2], // 大理
[102.8, 27.8], // 攀枝花
[104.0, 28.5], // 宜宾
[105.0, 29.5], // 泸州
[106.5, 29.8], // 重庆
[108.0, 30.5], // 恩施
[109.8, 30.2], // 建始
[110.43, 29.87], // 鹤峰(恩施州鹤峰县)
[110.2, 30.0], // 走马镇
[110.1, 30.1], // 太平镇
[110.05, 30.15], // 邬阳乡
],
},
{
name: "广水鹤峰到邬阳路线",
type: "provincial",
path: [
[113.85, 31.62], // 广水(随州市广水市)
[112.5, 31.2], // 安陆
[111.8, 31.0], // 京山
[111.2, 30.8], // 钟祥
[110.8, 30.5], // 荆门
[110.6, 30.2], // 当阳
[110.43, 29.87], // 鹤峰(恩施州鹤峰县)
[110.2, 30.0], // 走马镇
[110.1, 30.1], // 太平镇
[110.05, 30.15], // 邬阳乡
],
},
{
name: "恩施到武汉路线",
type: "provincial",
path: [
[109.48, 30.28], // 恩施
[110.2, 30.5], // 宜昌
[111.3, 30.7], // 荆州
[112.3, 30.6], // 潜江
[113.0, 30.8], // 仙桃
[114.27, 30.58], // 武汉
],
},
{
name: "临沂到威海路线",
type: "national",
path: [
[118.35, 35.05], // 临沂
[118.8, 35.5], // 沂水
[119.2, 36.0], // 潍坊
[119.8, 36.8], // 烟台
[121.38, 37.52], // 威海
],
},
{
name: "丹东到齐齐哈尔路线",
type: "provincial",
path: [
[124.38, 40.13], // 丹东
[123.8, 40.5], // 凤城
[123.5, 41.0], // 本溪
[123.38, 41.8], // 沈阳
[122.8, 42.2], // 铁岭
[122.5, 43.0], // 四平
[123.9, 44.5], // 大庆
[123.97, 47.35], // 齐齐哈尔
],
},
{
name: "华山到兵马俑路线",
type: "provincial",
path: [
[110.09, 34.45], // 华山
[109.8, 34.4], // 华阴
[109.5, 34.35], // 渭南
[109.27, 34.38], // 临潼
[109.28, 34.38], // 兵马俑
],
},
{
name: "吉安到南昌路线",
type: "provincial",
path: [
[114.98, 27.12], // 吉安
[115.2, 27.5], // 吉水
[115.5, 28.0], // 樟树
[115.8, 28.4], // 丰城
[115.89, 28.68], // 南昌
],
},
];
// 加载高德地图API
const loadAmapScript = () => {
return new Promise((resolve, reject) => {
if (window.AMap) {
resolve();
return;
}
const script = document.createElement("script");
script.type = "text/javascript";
script.async = true;
// 使用您的高德地图API密钥
script.src = `https://webapi.amap.com/maps?v=2.0&key=${AMAP_KEY}&plugins=AMap.PolylineEditor`;
script.onerror = () => {
reject(new Error("高德地图API加载失败,请检查网络连接"));
};
script.onload = () => {
if (window.AMap) {
resolve();
} else {
reject(new Error("高德地图API初始化失败"));
}
};
document.head.appendChild(script);
});
};
// 初始化地图
const initMap = async () => {
try {
loading.value = true;
error.value = "";
// 加载高德地图API
await loadAmapScript();
// 创建地图实例
map = new AMap.Map("container", {
zoom: 3.9,
center: [108.95, 34.27], // 中国中心点
viewMode: "2D",
mapStyle: "amap://styles/2d017848d08f94f20b6e50aaae661148",
minZoom: 4,
});
// 标记
const markers = [];
const positionsList = [
{
number: 1,
position: [116.405467, 39.907761],
},
{
number: 5,
position: [114.298569, 30.584354],
},
{
number: 6,
position: [117.190186, 39.125595],
},
{
number: 4,
position: [112.549248, 37.857014],
},
{
number: 8,
position: [123.429092, 41.796768],
},
{
number: 2,
position: [121.472641, 31.231707],
},
{
number: 7,
position: [119.306236, 26.075302],
},
{
number: 9,
position: [106.504959, 29.533155],
},
{
number: 6,
position: [91.1145, 29.64415],
},
{
number: 3,
position: [101.77782, 36.61729],
},
{
number: 8,
position: [87.61688, 43.82663],
},
{
number: 10,
position: [111.75199, 40.84149],
},
{
number: 9,
position: [126.642464, 45.756966],
},
];
for (var i = 0, marker; i < positionsList.length; i++) {
marker = new AMap.Marker({
map: map,
position: positionsList[i].position,
// icon: "//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
offset: new AMap.Pixel(-13, -30),
content:
"" +
'<div class="custom-content-marker">' +
'<img src="//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png">' +
`<div class="close-btn"">${positionsList[i].number}</div>` +
"</div>",
});
markers.push(marker);
}
map.add([markers]);
// const viaMarker = new AMap.Marker({
// position: new AMap.LngLat(116.38, 39.92),
// content: markerContent,
// // 将一张图片的地址设置为 icon
// // icon: "//a.amap.com/jsapi_demos/static/demo-center/icons/dir-via-marker.png",
// // 设置了 icon 以后,设置 icon 的偏移量,以 icon 的 [center bottom] 为原点
// offset: new AMap.Pixel(-31, -30),
// size: new AMap.Size(45, 65),
// // imageSize: new AMap.Size(135, 40),
// // imageOffset: new AMap.Pixel(-95, -3),
// });
// map.add([viaMarker]);
// 地图初始化完成后自动添加路线
addPolylines();
loading.value = false;
} catch (err) {
console.error("地图初始化失败:", err);
error.value = `地图加载失败: ${err.message}`;
loading.value = false;
}
};
// 添加所有折线到地图
const addPolylines = () => {
if (!map) return;
// 清除之前的折线
clearPolylines();
// 添加折线
polylineData.forEach((data, index) => {
// 所有线路统一使用黄色
const polyline = new AMap.Polyline({
path: data.path,
strokeColor: "#FFD700", // 黄色
strokeWeight: 4,
strokeOpacity: 0.8,
strokeStyle: "solid",
cursor: "pointer",
});
// 添加鼠标悬停事件
polyline.on("mouseover", (e) => {
// 获取道路类型中文名
const getTypeName = (type) => {
const typeNames = {
highway: "高速公路",
national: "国道",
provincial: "省道",
urban: "城市快速路",
railway: "铁路",
};
return typeNames[type] || "其他道路";
};
// 创建信息窗体
const infoWindow = new AMap.InfoWindow({
content: `
<div style="padding: 12px; min-width: 200px;">
<h4 style="margin: 0 0 8px 0; color: #333; font-size: 14px; font-weight: bold;">${
data.name
}</h4>
<p style="margin: 4px 0; color: #666; font-size: 12px;">
<strong>类型:</strong> ${getTypeName(data.type)}
</p>
<p style="margin: 4px 0; color: #666; font-size: 12px;">
<strong>起点:</strong> ${data.path[0][0].toFixed(
2
)}, ${data.path[0][1].toFixed(2)}
</p>
<p style="margin: 4px 0; color: #666; font-size: 12px;">
<strong>终点:</strong> ${data.path[
data.path.length - 1
][0].toFixed(2)}, ${data.path[data.path.length - 1][1].toFixed(2)}
</p>
<p style="margin: 4px 0; color: #666; font-size: 12px;">
<strong>途经点数:</strong> ${data.path.length}
</p>
</div>
`,
offset: new AMap.Pixel(0, -30),
});
infoWindow.open(map, e.lnglat);
// 鼠标离开时关闭信息窗体
polyline.on("mouseout", () => {
infoWindow.close();
});
});
// 添加点击事件
polyline.on("click", (e) => {
console.log(`点击了折线: ${data.name}`);
});
map.add(polyline);
polylines.push(polyline);
});
};
// 清除所有折线
const clearPolylines = () => {
if (map && polylines.length > 0) {
map.remove(polylines);
polylines = [];
}
};
onMounted(() => {
initMap();
});
onUnmounted(() => {
if (map) {
map.destroy();
}
});
</script>
<style scoped lang="less">
.map-container {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
#container {
width: 100%;
height: 100%;
overflow: hidden;
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 20px;
border-radius: 8px;
font-size: 16px;
z-index: 1000;
}
.error {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(255, 0, 0, 0.1);
color: #ff0000;
padding: 20px;
border-radius: 8px;
font-size: 14px;
border: 1px solid #ff0000;
z-index: 1000;
max-width: 80%;
text-align: center;
}
}
.custom-content-marker {
position: relative;
width: 25px;
height: 34px;
}
/deep/.close-btn {
position: absolute;
color: #fff;
position: absolute;
top: 30%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
<template>
<div class="login-container">
<div class="login-form-wrapper">
<h2 class="login-title">后台管理系统登录</h2>
<el-form
ref="loginFormRef"
:model="loginForm"
:rules="loginRules"
label-width="80px"
class="login-form"
>
<el-form-item label="用户名" prop="username">
<el-input
v-model="loginForm.username"
placeholder="请输入用户名"
prefix-icon="el-icon-user"
></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
v-model="loginForm.password"
type="password"
placeholder="请输入密码"
prefix-icon="el-icon-lock"
></el-input>
</el-form-item>
<el-form-item>
<el-button
type="primary"
class="login-btn"
:loading="loading"
@click="handleLogin"
>
登录
</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { useRouter } from "vue-router";
import type { FormInstance, FormRules } from "element-plus";
const router = useRouter();
const loginFormRef = ref<FormInstance>();
const loading = ref(false);
// 登录表单数据
const loginForm = ref({
username: "",
password: "",
});
// 表单验证规则
const loginRules = ref<FormRules>({
username: [
{ required: true, message: "请输入用户名", trigger: "blur" },
{ min: 3, max: 20, message: "长度在 3 到 20 个字符", trigger: "blur" },
],
password: [
{ required: true, message: "请输入密码", trigger: "blur" },
{ min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" },
],
});
// 处理登录
const handleLogin = async () => {
try {
// 验证表单
await loginFormRef.value?.validate();
loading.value = true;
// 模拟登录请求
setTimeout(() => {
// 登录成功后设置token
const mockToken = "mock-jwt-token";
localStorage.setItem("token", mockToken);
loading.value = false;
// 跳转到首页
router.push("/");
}, 1000);
} catch (error) {
console.error("登录失败:", error);
loading.value = false;
}
};
</script>
<style scoped lang="less">
.login-container {
display: flex;
justify-content: flex-end;
align-items: center;
height: 100vh;
// background-image: url('@/assets/images/background.png');
// background-size: cover;
// background-position: center;
// background-repeat: no-repeat;
// padding-right: 100px;
}
.login-form-wrapper {
background-color: rgba(255, 255, 255, 0.9);
position: absolute;
top: 35%;
right: 6%;
transform: translateY(-50%);
padding: 48px;
box-sizing: border-box;
width: 460px;
height: 550px;
box-shadow: 0 0 16px #2e31361a;
border-radius: 8px;
:deep(.el-form-item) {
.el-form-item__content {
.el-input {
height: 48px;
border-radius: 4px;
.el-input__wrapper {
background: #f3f4f9;
}
}
}
}
}
.login-title {
text-align: center;
margin-bottom: 30px;
color: #304156;
}
.login-form {
.login-btn {
width: 100%;
}
}
</style>
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vite.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
},
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true,
additionalData: '@import "./src/styles/utils.less";',
}
}
},
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment