A:前端增加资料库页面
This commit is contained in:
1 parent
76d747bbd9
commit
bc0053e051
31 files changed
+2364
-204
No files matched your search
@@ -1,86 +0,0 @@
|
||||
/* color palette from <https://github.com/vuejs/theme> */
|
||||
:root {
|
||||
--vt-c-white: #ffffff;
|
||||
--vt-c-white-soft: #f8f8f8;
|
||||
--vt-c-white-mute: #f2f2f2;
|
||||
|
||||
--vt-c-black: #181818;
|
||||
--vt-c-black-soft: #222222;
|
||||
--vt-c-black-mute: #282828;
|
||||
|
||||
--vt-c-indigo: #2c3e50;
|
||||
|
||||
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
||||
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
||||
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
||||
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
||||
|
||||
--vt-c-text-light-1: var(--vt-c-indigo);
|
||||
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
||||
--vt-c-text-dark-1: var(--vt-c-white);
|
||||
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
||||
}
|
||||
|
||||
/* semantic color variables for this project */
|
||||
:root {
|
||||
--color-background: var(--vt-c-white);
|
||||
--color-background-soft: var(--vt-c-white-soft);
|
||||
--color-background-mute: var(--vt-c-white-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-light-2);
|
||||
--color-border-hover: var(--vt-c-divider-light-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-light-1);
|
||||
--color-text: var(--vt-c-text-light-1);
|
||||
|
||||
--section-gap: 160px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-background: var(--vt-c-black);
|
||||
--color-background-soft: var(--vt-c-black-soft);
|
||||
--color-background-mute: var(--vt-c-black-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-dark-2);
|
||||
--color-border-hover: var(--vt-c-divider-dark-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-dark-1);
|
||||
--color-text: var(--vt-c-text-dark-2);
|
||||
}
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
color: var(--color-text);
|
||||
background: var(--color-background);
|
||||
transition:
|
||||
color 0.5s,
|
||||
background-color 0.5s;
|
||||
line-height: 1.6;
|
||||
font-family:
|
||||
Inter,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
'Segoe UI',
|
||||
Roboto,
|
||||
Oxygen,
|
||||
Ubuntu,
|
||||
Cantarell,
|
||||
'Fira Sans',
|
||||
'Droid Sans',
|
||||
'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-size: 15px;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
@@ -0,0 +1,539 @@
|
||||
/* 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;
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
<!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=4810610" 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"></span>
|
||||
<div class="name">重新开始</div>
|
||||
<div class="code-name">&#xe648;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">重新</div>
|
||||
<div class="code-name">&#xe7a8;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">体质辨别-重新测试</div>
|
||||
<div class="code-name">&#xe629;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">箭头-左</div>
|
||||
<div class="code-name">&#xe659;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">箭头 右</div>
|
||||
<div class="code-name">&#xe61c;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">重新加载</div>
|
||||
<div class="code-name">&#xe7b8;</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=1737291281379') format('woff2'),
|
||||
url('iconfont.woff?t=1737291281379') format('woff'),
|
||||
url('iconfont.ttf?t=1737291281379') 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"
|
||||
><span class="iconfont">&#x33;</span>
|
||||
</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-zhongxinkaishi"></span>
|
||||
<div class="name">
|
||||
重新开始
|
||||
</div>
|
||||
<div class="code-name">.icon-zhongxinkaishi
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-zhongxin"></span>
|
||||
<div class="name">
|
||||
重新
|
||||
</div>
|
||||
<div class="code-name">.icon-zhongxin
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-tizhibianbiezhongxinceshi"></span>
|
||||
<div class="name">
|
||||
体质辨别-重新测试
|
||||
</div>
|
||||
<div class="code-name">.icon-tizhibianbiezhongxinceshi
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-jiantouzuo"></span>
|
||||
<div class="name">
|
||||
箭头-左
|
||||
</div>
|
||||
<div class="code-name">.icon-jiantouzuo
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-jiantouyou"></span>
|
||||
<div class="name">
|
||||
箭头 右
|
||||
</div>
|
||||
<div class="code-name">.icon-jiantouyou
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-zhongxinjiazai"></span>
|
||||
<div class="name">
|
||||
重新加载
|
||||
</div>
|
||||
<div class="code-name">.icon-zhongxinjiazai
|
||||
</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"><link rel="stylesheet" href="./iconfont.css">
|
||||
</code></pre>
|
||||
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
|
||||
<pre><code class="language-html"><span class="iconfont icon-xxx"></span>
|
||||
</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-zhongxinkaishi"></use>
|
||||
</svg>
|
||||
<div class="name">重新开始</div>
|
||||
<div class="code-name">#icon-zhongxinkaishi</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-zhongxin"></use>
|
||||
</svg>
|
||||
<div class="name">重新</div>
|
||||
<div class="code-name">#icon-zhongxin</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-tizhibianbiezhongxinceshi"></use>
|
||||
</svg>
|
||||
<div class="name">体质辨别-重新测试</div>
|
||||
<div class="code-name">#icon-tizhibianbiezhongxinceshi</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-jiantouzuo"></use>
|
||||
</svg>
|
||||
<div class="name">箭头-左</div>
|
||||
<div class="code-name">#icon-jiantouzuo</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-jiantouyou"></use>
|
||||
</svg>
|
||||
<div class="name">箭头 右</div>
|
||||
<div class="code-name">#icon-jiantouyou</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-zhongxinjiazai"></use>
|
||||
</svg>
|
||||
<div class="name">重新加载</div>
|
||||
<div class="code-name">#icon-zhongxinjiazai</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"><script src="./iconfont.js"></script>
|
||||
</code></pre>
|
||||
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
|
||||
<pre><code class="language-html"><style>
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
</code></pre>
|
||||
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
|
||||
<pre><code class="language-html"><svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-xxx"></use>
|
||||
</svg>
|
||||
</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>
|
||||
@@ -0,0 +1,39 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 4810610 */
|
||||
src: url('iconfont.woff2?t=1737291281379') format('woff2'),
|
||||
url('iconfont.woff?t=1737291281379') format('woff'),
|
||||
url('iconfont.ttf?t=1737291281379') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-zhongxinkaishi:before {
|
||||
content: "\e648";
|
||||
}
|
||||
|
||||
.icon-zhongxin:before {
|
||||
content: "\e7a8";
|
||||
}
|
||||
|
||||
.icon-tizhibianbiezhongxinceshi:before {
|
||||
content: "\e629";
|
||||
}
|
||||
|
||||
.icon-jiantouzuo:before {
|
||||
content: "\e659";
|
||||
}
|
||||
|
||||
.icon-jiantouyou:before {
|
||||
content: "\e61c";
|
||||
}
|
||||
|
||||
.icon-zhongxinjiazai:before {
|
||||
content: "\e7b8";
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
window._iconfont_svg_string_4810610='<svg><symbol id="icon-zhongxinkaishi" viewBox="0 0 1024 1024"><path d="M895.1296 485.888a384 384 0 1 0-149.9136 331.2128 25.6 25.6 0 0 1 31.1296 40.6528 435.2 435.2 0 1 1 168.9088-387.328l21.504-21.504a25.6 25.6 0 0 1 36.1984 36.1984l-72.3968 72.3968a25.4976 25.4976 0 0 1-36.1984 0l-72.3968-72.3968a25.6 25.6 0 0 1 36.1984-36.1984l36.9664 36.9664z m-225.0752-2.56a35.84 35.84 0 0 1 0 57.344l-177.5104 133.12a35.84 35.84 0 0 1-57.344-28.672V378.88a35.84 35.84 0 0 1 57.344-28.672l177.5104 133.12zM486.4 409.6v204.8l136.5504-102.4L486.4 409.6z" fill="#9DA7B2" ></path></symbol><symbol id="icon-zhongxin" viewBox="0 0 1024 1024"><path d="M362.666667 938.666667c0-17.066667-8.533333-32-23.466667-38.4C189.866667 834.133333 85.333333 684.8 85.333333 512S189.866667 189.866667 339.2 123.733333C354.133333 115.2 362.666667 100.266667 362.666667 85.333333v-2.133333c0-32-32-51.2-59.733334-38.4C123.733333 125.866667 0 305.066667 0 512s123.733333 386.133333 302.933333 467.2c27.733333 12.8 59.733333-8.533333 59.733334-40.533333z" ></path><path d="M467.2 985.6l-102.4-179.2c-10.666667-17.066667-34.133333-17.066667-44.8 0l-102.4 179.2c-10.666667 17.066667 2.133333 38.4 21.333333 38.4h206.933334c19.2 0 32-21.333333 21.333333-38.4zM661.333333 85.333333c0 17.066667 8.533333 32 23.466667 38.4C834.133333 189.866667 938.666667 339.2 938.666667 512s-104.533333 322.133333-253.866667 388.266667c-14.933333 6.4-23.466667 21.333333-23.466667 38.4v2.133333c0 32 32 51.2 59.733334 38.4C900.266667 898.133333 1024 718.933333 1024 512S900.266667 125.866667 721.066667 44.8C693.333333 32 661.333333 53.333333 661.333333 85.333333z" ></path><path d="M556.8 38.4l102.4 179.2c10.666667 17.066667 34.133333 17.066667 44.8 0l102.4-179.2c10.666667-17.066667-2.133333-38.4-21.333333-38.4h-206.933334c-19.2 0-32 21.333333-21.333333 38.4z" ></path></symbol><symbol id="icon-tizhibianbiezhongxinceshi" viewBox="0 0 1024 1024"><path d="M149.996806 543.064927 297.814628 386.075665l-86.602808 0c0.798407-2.29414 1.595534-4.584441 2.459195-6.845313 51.376955-138.245898 178.257074-236.080139 326.671142-236.080139 193.875904 0 351.062208 166.989816 351.062208 372.930105 0 205.969717-157.186304 372.964651-351.062208 372.964651-142.633296 0-265.392154-90.328706-320.290286-220.063385-0.532271-1.230877-0.931474-2.560275-1.395932-3.824419l-94.178715 99.399066c0.597525 1.161784 1.061983 2.495021 1.727322 3.654246 0.133068 0.267415 0.266136 0.532271 0.397924 0.798407 83.080351 152.435529 238.274477 254.991116 416.064535 254.991116 265.326899 0 480.404081-228.502953 480.404081-510.381435 0-281.840098-215.077182-510.311063-480.404081-510.311063-221.789428 0-408.487349 159.648058-463.785964 376.652164-0.532271 1.996017-0.665339 4.087995-1.131076 6.11472L2.181544 386.074386 149.996806 543.064927z" fill="#262535" ></path></symbol><symbol id="icon-jiantouzuo" viewBox="0 0 1024 1024"><path d="M257.243317 303.056224c-13.846356 0-25.071002 11.224646-25.071002 25.071002s11.224646 25.071002 25.071002 25.071002c13.845333 0 25.071002-11.224646 25.071002-25.071002S271.089673 303.056224 257.243317 303.056224zM257.243317 350.691127c-12.44238 0-22.562878-10.121522-22.562878-22.563902 0-12.443403 10.120498-22.563902 22.562878-22.563902s22.562878 10.120498 22.562878 22.563902C279.806195 340.569606 269.685697 350.691127 257.243317 350.691127z" ></path><path d="M255.843434 309.422212l2.801812 0 0 20.205181-2.801812 0 0-20.205181Z" ></path><path d="M255.941672 326.72632l20.203134 0 0 2.801812-20.203134 0 0-2.801812Z" ></path><path d="M239.460302 462.750319C378.354676 335.865467 517.179464 208.980615 656.052349 82.228793c57.18849-52.247968 142.42785 32.586163 85.012186 85.016279C617.487008 280.122909 493.910505 392.96186 370.332978 505.844813 494.544955 622.62554 618.711905 739.541343 742.945371 856.364025c56.576553 53.15564-28.662807 138.079822-85.059258 84.96716C518.404362 810.141284 378.943077 678.951383 239.460302 547.761482 216.39498 525.96506 215.805556 484.274542 239.460302 462.750319z" ></path></symbol><symbol id="icon-jiantouyou" viewBox="0 0 1024 1024"><path d="M312.889 995.556c-17.067 0-28.445-5.69-39.822-17.067-22.756-22.756-17.067-56.889 5.689-79.645L642.844 568.89c11.378-11.378 17.067-22.756 17.067-34.133 0-11.378-5.689-22.756-17.067-34.134L273.067 187.733c-22.756-22.755-28.445-56.889-5.69-79.644 22.756-22.756 56.89-28.445 79.645-5.689l364.09 312.889C745.243 443.733 768 489.244 768 534.756s-17.067 85.333-51.2 119.466L352.711 984.178c-11.378 5.689-28.444 11.378-39.822 11.378z" ></path></symbol><symbol id="icon-zhongxinjiazai" viewBox="0 0 1024 1024"><path d="M952.529455 459.752727a34.909091 34.909091 0 0 0-49.361455 0l-21.085091 21.085091C860.625455 276.317091 687.220364 116.363636 477.090909 116.363636a400.570182 400.570182 0 0 0-48.686545 3.211637c-7.842909 0.930909-15.616 2.164364-23.342546 3.560727-4.701091 0.837818-9.402182 1.582545-14.010182 2.56-9.844364 2.164364-19.572364 4.654545-29.160727 7.540364-6.865455 2.024727-13.521455 4.398545-20.Line truncated
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"id": "4810610",
|
||||
"name": "argus",
|
||||
"font_family": "iconfont",
|
||||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "2743897",
|
||||
"name": "重新开始",
|
||||
"font_class": "zhongxinkaishi",
|
||||
"unicode": "e648",
|
||||
"unicode_decimal": 58952
|
||||
},
|
||||
{
|
||||
"icon_id": "29849119",
|
||||
"name": "重新",
|
||||
"font_class": "zhongxin",
|
||||
"unicode": "e7a8",
|
||||
"unicode_decimal": 59304
|
||||
},
|
||||
{
|
||||
"icon_id": "375868",
|
||||
"name": "体质辨别-重新测试",
|
||||
"font_class": "tizhibianbiezhongxinceshi",
|
||||
"unicode": "e629",
|
||||
"unicode_decimal": 58921
|
||||
},
|
||||
{
|
||||
"icon_id": "830289",
|
||||
"name": "箭头-左",
|
||||
"font_class": "jiantouzuo",
|
||||
"unicode": "e659",
|
||||
"unicode_decimal": 58969
|
||||
},
|
||||
{
|
||||
"icon_id": "15726826",
|
||||
"name": "箭头 右",
|
||||
"font_class": "jiantouyou",
|
||||
"unicode": "e61c",
|
||||
"unicode_decimal": 58908
|
||||
},
|
||||
{
|
||||
"icon_id": "4430546",
|
||||
"name": "重新加载",
|
||||
"font_class": "zhongxinjiazai",
|
||||
"unicode": "e7b8",
|
||||
"unicode_decimal": 59320
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,15 @@
|
||||
*{
|
||||
@import "base.css";
|
||||
@import "var.css";
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
/* 禁止选中 */
|
||||
.no-select {
|
||||
user-select: none;
|
||||
-webkit-user-select: none; /* Safari */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* IE10+/Edge */
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
:root {
|
||||
--header-height: 64px;
|
||||
}
|
||||
@@ -4,12 +4,12 @@
|
||||
<n-layout-header bordered class="layout-header">
|
||||
<div class="header-content">
|
||||
<!-- 左侧 Logo 和标题 -->
|
||||
<div class="header-left">
|
||||
<router-link to="/" class="header-left no-select">
|
||||
<n-icon size="32" class="logo-icon">
|
||||
<img src="@/assets/logo.svg" alt="logo" />
|
||||
</n-icon>
|
||||
<span class="site-title">标题</span>
|
||||
</div>
|
||||
<span class="site-title">Argus</span>
|
||||
</router-link>
|
||||
|
||||
<!-- 中间搜索框 -->
|
||||
<div class="header-center">
|
||||
@@ -42,7 +42,7 @@
|
||||
show-trigger
|
||||
collapse-mode="width"
|
||||
:collapsed-width="64"
|
||||
:width="240"
|
||||
:width="290"
|
||||
:native-scrollbar="false"
|
||||
class="layout-sider"
|
||||
>
|
||||
@@ -71,7 +71,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, h } from 'vue'
|
||||
import { ref, watch, computed, h } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { NMenu, NIcon } from 'naive-ui'
|
||||
import {
|
||||
@@ -137,25 +137,31 @@ const menuOptionsWithIcons = computed(() => {
|
||||
})
|
||||
})
|
||||
|
||||
// 当前激活的菜单项
|
||||
const activeKey = computed(() => {
|
||||
const currentPath = route.path
|
||||
// 从菜单选项中找到匹配当前路径的key
|
||||
for (const option of menuOptions) {
|
||||
if ('children' in option) {
|
||||
for (const child of option.children) {
|
||||
if (child.path === currentPath) {
|
||||
return child.key
|
||||
const activeKey = ref('')
|
||||
// 监听路由变化,更新activeKey
|
||||
watch(
|
||||
() => route.path,
|
||||
(currentPath) => {
|
||||
// 从菜单选项中找到匹配当前路径的key
|
||||
for (const option of menuOptions) {
|
||||
if ('children' in option) {
|
||||
for (const child of option.children) {
|
||||
if (child.path === currentPath) {
|
||||
activeKey.value = child.key
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (option.path === currentPath) {
|
||||
activeKey.value = option.key
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (option.path === currentPath) {
|
||||
return option.key
|
||||
}
|
||||
}
|
||||
}
|
||||
return ''
|
||||
})
|
||||
activeKey.value = ''
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
// 处理菜单选择
|
||||
const handleMenuSelect = (key: string) => {
|
||||
@@ -184,11 +190,6 @@ const handleMenuSelect = (key: string) => {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
:root {
|
||||
--header-height: 64px;
|
||||
}
|
||||
</style>
|
||||
<style scoped>
|
||||
.layout-container {
|
||||
height: 100vh;
|
||||
@@ -216,6 +217,12 @@ const handleMenuSelect = (key: string) => {
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
min-width: 200px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.header-left:hover {
|
||||
opacity: 0.8;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
@@ -264,6 +271,7 @@ const handleMenuSelect = (key: string) => {
|
||||
.layout-sider {
|
||||
height: 100%;
|
||||
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
.sidebar-menu {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Time:2025/6/15 20:13 49
|
||||
* Name:httpConfig.ts
|
||||
* Path:src/config
|
||||
* ProjectName:argus-front
|
||||
* Author:charlatans
|
||||
*
|
||||
* Il n'ya qu'un héroïsme au monde :
|
||||
* c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
*/
|
||||
import type { HttpConfig } from '@/types/http.ts'
|
||||
|
||||
// 2. 配置管理器 (config/httpConfig.ts)
|
||||
class HttpConfigManager {
|
||||
private config: HttpConfig = {
|
||||
baseURL: import.meta.env.VITE_APP_API_URL || 'http://localhost:8726',
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置配置
|
||||
*/
|
||||
setConfig(config: Partial<HttpConfig>): void {
|
||||
this.config = { ...this.config, ...config };
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置
|
||||
*/
|
||||
getConfig(): HttpConfig {
|
||||
return { ...this.config };
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置基础URL
|
||||
*/
|
||||
setBaseURL(baseURL: string): void {
|
||||
this.config.baseURL = baseURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置端口
|
||||
*/
|
||||
setPort(host: string, port: number): void {
|
||||
const protocol = this.config.baseURL.startsWith('https') ? 'https' : 'http';
|
||||
this.config.baseURL = `${protocol}://${host}:${port}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置超时时间
|
||||
*/
|
||||
setTimeout(timeout: number): void {
|
||||
this.config.timeout = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认请求头
|
||||
*/
|
||||
setHeaders(headers: Record<string, string>): void {
|
||||
this.config.headers = { ...this.config.headers, ...headers };
|
||||
}
|
||||
}
|
||||
|
||||
export const httpConfig = new HttpConfigManager();
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Time:2024/8/30 下午2:21 50
|
||||
* Name:app.ts
|
||||
* Path:src/constants
|
||||
* ProjectName:utopia-front-vue
|
||||
* Author:charlatans
|
||||
*
|
||||
* Il n'ya qu'un héroïsme au monde :
|
||||
* c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
*/
|
||||
|
||||
const app = {
|
||||
/**
|
||||
* 生产
|
||||
*/
|
||||
PRODUCTION: 'production',
|
||||
/**
|
||||
* 开发
|
||||
*/
|
||||
DEVELOPMENT: 'development',
|
||||
|
||||
/**
|
||||
* 是否是生产环境【默认是】
|
||||
*/
|
||||
IS_PRODUCTION: true,
|
||||
|
||||
/**
|
||||
* 是否展示生成路由
|
||||
*/
|
||||
IS_SHOW_GENERATE_ROUTER: false
|
||||
}
|
||||
|
||||
export default app
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Time:2024/8/30 下午2:28 44
|
||||
* Name:logUtil.ts
|
||||
* Path:src/constants
|
||||
* ProjectName:utopia-front-vue
|
||||
* Author:charlatans
|
||||
*
|
||||
* Il n'ya qu'un héroïsme au monde :
|
||||
* c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 日志级别
|
||||
*/
|
||||
const level = {
|
||||
error: 0,
|
||||
warn: 1,
|
||||
info: 2,
|
||||
http: 3,
|
||||
verbose: 4,
|
||||
debug: 5,
|
||||
silly: 6
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志工具类常量
|
||||
*/
|
||||
const logUtil = {
|
||||
/**
|
||||
* 日志级别
|
||||
*/
|
||||
level: level,
|
||||
ERROR: 'error',
|
||||
WARN: 'warn',
|
||||
INFO: 'info',
|
||||
HTTP: 'http',
|
||||
VERBOSE: 'verbose',
|
||||
DEBUG: 'debug',
|
||||
SILLY: 'silly'
|
||||
|
||||
}
|
||||
|
||||
export type Color =
|
||||
'primary'
|
||||
| 'success'
|
||||
| 'info'
|
||||
| 'warning'
|
||||
| 'danger'
|
||||
| 'error';
|
||||
|
||||
export const COLOR_MAP: Record<Color, string> = {
|
||||
primary: '#2d8cf0',
|
||||
success: '#19be6b',
|
||||
info: '#909399',
|
||||
warning: '#ff9900',
|
||||
danger: '#35495E',
|
||||
error: '#FF0000'
|
||||
}
|
||||
export default { logUtil, COLOR_MAP }
|
||||
@@ -1,4 +1,5 @@
|
||||
import './assets/main.css'
|
||||
import "./assets/icon/ali/iconfont.css"
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
@@ -8,6 +9,10 @@ import router from './router'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
import httpPlugin from './plugins/http';
|
||||
app.use(httpPlugin);
|
||||
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Time:2025/6/15 20:23 36
|
||||
* Name:http.ts
|
||||
* Path:src/plugins
|
||||
* ProjectName:argus-front
|
||||
* Author:charlatans
|
||||
*
|
||||
* Il n'ya qu'un héroïsme au monde :
|
||||
* c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
*/
|
||||
import { type App } from 'vue';
|
||||
import { httpConfig } from '@/config/httpConfig.ts'
|
||||
import { httpClient } from '@/utils/http.ts'
|
||||
|
||||
export default {
|
||||
install(app: App) {
|
||||
// 更新HTTP配置
|
||||
const config = httpConfig.getConfig();
|
||||
httpClient.updateConfig(config);
|
||||
|
||||
// 注册全局属性
|
||||
app.config.globalProperties.$http = httpClient;
|
||||
app.config.globalProperties.$httpConfig = httpConfig;
|
||||
|
||||
// 提供注入
|
||||
app.provide('$http', httpClient);
|
||||
app.provide('$httpConfig', httpConfig);
|
||||
}
|
||||
};
|
||||
@@ -1,31 +1,11 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
// const router = createRouter({
|
||||
// history: createWebHistory(import.meta.env.BASE_URL),
|
||||
// routes: [
|
||||
// {
|
||||
// path: '/',
|
||||
// name: 'home',
|
||||
// component: HomeView,
|
||||
// },
|
||||
// {
|
||||
// path: '/about',
|
||||
// name: 'about',
|
||||
// // route level code-splitting
|
||||
// // this generates a separate chunk (About.[hash].js) for this route
|
||||
// // which is lazy-loaded when the route is visited.
|
||||
// component: () => import('../views/AboutView.vue'),
|
||||
// },
|
||||
// ],
|
||||
// })
|
||||
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
redirect: '/photo'
|
||||
redirect: '/photos'
|
||||
},
|
||||
{
|
||||
path: '/photos',
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Time:2025/6/15 20:12 37
|
||||
* Name:http.ts
|
||||
* Path:src/types
|
||||
* ProjectName:argus-front
|
||||
* Author:charlatans
|
||||
*
|
||||
* Il n'ya qu'un héroïsme au monde :
|
||||
* c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
*/
|
||||
|
||||
// 1. 配置接口和类型定义
|
||||
export interface HttpConfig {
|
||||
baseURL: string;
|
||||
timeout?: number;
|
||||
headers?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface ApiResponse<T = unknown> {
|
||||
code: number;
|
||||
data: T;
|
||||
message: string;
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
export interface RequestConfig {
|
||||
url: string;
|
||||
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
||||
params?: unknown;
|
||||
data?: unknown;
|
||||
headers?: Record<string, string>;
|
||||
timeout?: number;
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
import axios, {
|
||||
type AxiosInstance,
|
||||
type AxiosRequestConfig,
|
||||
type AxiosResponse,
|
||||
AxiosError,
|
||||
type InternalAxiosRequestConfig,
|
||||
} from 'axios'
|
||||
// 或者混合导入(如果同时需要导入值和类型)
|
||||
import type { ApiResponse, HttpConfig, RequestConfig } from '@/types/http.ts'
|
||||
import { disLog, logB, logN, logS } from '@/utils/logHelper/logUtils'
|
||||
|
||||
class HttpClient {
|
||||
private axiosInstance: AxiosInstance
|
||||
private pending: Map<string, AbortController> = new Map()
|
||||
|
||||
constructor() {
|
||||
this.axiosInstance = axios.create()
|
||||
this.setupInterceptors()
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新配置
|
||||
*/
|
||||
updateConfig(config: HttpConfig): void {
|
||||
this.axiosInstance.defaults.baseURL = config.baseURL
|
||||
this.axiosInstance.defaults.timeout = config.timeout || 10000
|
||||
this.axiosInstance.defaults.headers.common = {
|
||||
...this.axiosInstance.defaults.headers.common,
|
||||
...config.headers,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成请求标识符
|
||||
*/
|
||||
private getRequestKey(config: AxiosRequestConfig): string {
|
||||
return `${config.method?.toUpperCase()}_${config.url}_${JSON.stringify(
|
||||
config.params,
|
||||
)}_${JSON.stringify(config.data)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加请求到待处理列表
|
||||
*/
|
||||
private addPending(config: InternalAxiosRequestConfig): void {
|
||||
const requestKey = this.getRequestKey(config)
|
||||
config.signal = new AbortController().signal
|
||||
|
||||
if (this.pending.has(requestKey)) {
|
||||
this.pending.get(requestKey)?.abort()
|
||||
}
|
||||
|
||||
const controller = new AbortController()
|
||||
config.signal = controller.signal
|
||||
this.pending.set(requestKey, controller)
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除请求从待处理列表
|
||||
*/
|
||||
private removePending(config: AxiosRequestConfig): void {
|
||||
const requestKey = this.getRequestKey(config)
|
||||
if (this.pending.has(requestKey)) {
|
||||
this.pending.delete(requestKey)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置拦截器
|
||||
*/
|
||||
private setupInterceptors(): void {
|
||||
// 请求拦截器
|
||||
this.axiosInstance.interceptors.request.use(
|
||||
(config: InternalAxiosRequestConfig) => {
|
||||
console.group("请求链接: "+config.url);
|
||||
// 防止重复请求
|
||||
this.addPending(config)
|
||||
|
||||
// 添加时间戳防止缓存
|
||||
if (config.method?.toLowerCase() === 'get') {
|
||||
config.params = {
|
||||
...config.params,
|
||||
_t: Date.now(),
|
||||
}
|
||||
}
|
||||
|
||||
// 添加token
|
||||
const token = localStorage.getItem('token')
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
|
||||
logB.success('请求发送:', config)
|
||||
return config
|
||||
},
|
||||
(error: AxiosError) => {
|
||||
logB.error('请求错误:', error)
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
|
||||
// 响应拦截器
|
||||
this.axiosInstance.interceptors.response.use(
|
||||
(response: AxiosResponse<ApiResponse>) => {
|
||||
this.removePending(response.config)
|
||||
|
||||
logB.success('响应接收:', response)
|
||||
|
||||
// 统一处理响应数据
|
||||
const { data } = response
|
||||
|
||||
console.groupEnd();
|
||||
if (data.success || data.code === 200) {
|
||||
return response
|
||||
} else {
|
||||
// 业务错误处理
|
||||
const errorMessage = data.message || '请求失败'
|
||||
return Promise.reject(new Error(errorMessage))
|
||||
}
|
||||
},
|
||||
(error: AxiosError<ApiResponse>) => {
|
||||
this.removePending(error.config || {})
|
||||
|
||||
logB.error('响应错误:', error)
|
||||
|
||||
// 统一错误处理
|
||||
this.handleError(error)
|
||||
console.groupEnd();
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一错误处理
|
||||
*/
|
||||
private handleError(error: AxiosError<ApiResponse>): void {
|
||||
let message = '网络错误'
|
||||
|
||||
if (error.response) {
|
||||
const { status, data } = error.response
|
||||
|
||||
switch (status) {
|
||||
case 400:
|
||||
message = data?.message || '请求参数错误'
|
||||
break
|
||||
case 401:
|
||||
message = '未授权,请重新登录'
|
||||
// 清除token并跳转到登录页
|
||||
localStorage.removeItem('token')
|
||||
// router.push('/login');
|
||||
break
|
||||
case 403:
|
||||
message = '拒绝访问'
|
||||
break
|
||||
case 404:
|
||||
message = '请求的资源不存在'
|
||||
break
|
||||
case 500:
|
||||
message = '服务器内部错误'
|
||||
break
|
||||
default:
|
||||
message = data?.message || `错误码: ${status}`
|
||||
}
|
||||
} else if (error.code === 'ECONNABORTED') {
|
||||
message = '请求超时'
|
||||
} else if (error.message.includes('Network Error')) {
|
||||
message = '网络连接异常'
|
||||
}
|
||||
logB.error(message)
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用请求方法
|
||||
*/
|
||||
async request<T = unknown>(config: RequestConfig): Promise<ApiResponse<T>> {
|
||||
try {
|
||||
const response = await this.axiosInstance.request<ApiResponse<T>>(config)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET请求
|
||||
*/
|
||||
async get<T = unknown>(
|
||||
url: string,
|
||||
params?: unknown,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<ApiResponse<T>> {
|
||||
return this.request<T>({
|
||||
url,
|
||||
method: 'GET',
|
||||
params,
|
||||
...config,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* POST请求
|
||||
*/
|
||||
async post<T = unknown>(
|
||||
url: string,
|
||||
data?: unknown,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<ApiResponse<T>> {
|
||||
return this.request<T>({
|
||||
url,
|
||||
method: 'POST',
|
||||
data,
|
||||
...config,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT请求
|
||||
*/
|
||||
async put<T = unknown>(
|
||||
url: string,
|
||||
data?: unknown,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<ApiResponse<T>> {
|
||||
return this.request<T>({
|
||||
url,
|
||||
method: 'PUT',
|
||||
data,
|
||||
...config,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE请求
|
||||
*/
|
||||
async delete<T = unknown>(
|
||||
url: string,
|
||||
params?: unknown,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<ApiResponse<T>> {
|
||||
return this.request<T>({
|
||||
url,
|
||||
method: 'DELETE',
|
||||
params,
|
||||
...config,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* PATCH请求
|
||||
*/
|
||||
async patch<T = unknown>(
|
||||
url: string,
|
||||
data?: unknown,
|
||||
config?: AxiosRequestConfig,
|
||||
): Promise<ApiResponse<T>> {
|
||||
return this.request<T>({
|
||||
url,
|
||||
method: 'PATCH',
|
||||
data,
|
||||
...config,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消所有请求
|
||||
*/
|
||||
cancelAllRequests(): void {
|
||||
this.pending.forEach((controller) => {
|
||||
controller.abort()
|
||||
})
|
||||
this.pending.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Axios实例
|
||||
*/
|
||||
getAxiosInstance(): AxiosInstance {
|
||||
return this.axiosInstance
|
||||
}
|
||||
}
|
||||
|
||||
export const httpClient = new HttpClient()
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Time:2024/8/31 下午4:46 46
|
||||
* Name:logEnum.ts
|
||||
* Path:src/utils/logHelper
|
||||
* ProjectName:utopia-front-vue
|
||||
* Author:charlatans
|
||||
*
|
||||
* Il n'ya qu'un héroïsme au monde :
|
||||
* c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 日志等级列表,重要等级越高数字越小
|
||||
*/
|
||||
export enum LogLevelEnum {
|
||||
/**
|
||||
* v.
|
||||
*/
|
||||
VERBOSE = 40,
|
||||
|
||||
/**
|
||||
* d.
|
||||
*/
|
||||
DEBUG = 30,
|
||||
|
||||
/**
|
||||
* i.
|
||||
*/
|
||||
INFO = 20,
|
||||
|
||||
/**
|
||||
* w.
|
||||
*/
|
||||
WARN = 10,
|
||||
|
||||
/**
|
||||
* e.
|
||||
*/
|
||||
ERROR = 0,
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志等级名称
|
||||
*/
|
||||
export const LevelName = {
|
||||
VERBOSE: 'VERBOSE',
|
||||
DEBUG: 'DEBUG',
|
||||
INFO: 'INFO',
|
||||
WARN: 'WARN',
|
||||
ERROR: 'ERROR'
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志样式
|
||||
*/
|
||||
enum logStyle {
|
||||
BackgroundColor = 10,
|
||||
TextColor = 20,
|
||||
BackgroundAndTextColor = 30
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志输出颜色
|
||||
*/
|
||||
enum logColor {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定等级名称
|
||||
* @param level
|
||||
*/
|
||||
export function getLogLevelName (level: LogLevelEnum): string {
|
||||
switch (level) {
|
||||
case LogLevelEnum.VERBOSE:
|
||||
return LevelName.VERBOSE
|
||||
case LogLevelEnum.DEBUG:
|
||||
return LevelName.DEBUG
|
||||
case LogLevelEnum.INFO:
|
||||
return LevelName.INFO
|
||||
case LogLevelEnum.WARN:
|
||||
return LevelName.WARN
|
||||
case LogLevelEnum.ERROR:
|
||||
return LevelName.ERROR
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Time:2024/8/26 下午5:02 17
|
||||
* Name:logUtils.ts
|
||||
* Path:src/utils
|
||||
* ProjectName:utopia-front-vue
|
||||
* Author:charlatans
|
||||
*
|
||||
* Il n'ya qu'un héroïsme au monde :
|
||||
* c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
*/
|
||||
import app from '@/constants/app'
|
||||
import type { Color } from '@/constants/logUtil'
|
||||
import { COLOR_MAP } from '@/constants/logUtil'
|
||||
import {
|
||||
LevelName,
|
||||
LogLevelEnum
|
||||
} from '@/utils/logHelper/logEnum'
|
||||
|
||||
const env = import.meta.env
|
||||
// 是否输出日志
|
||||
const isPrint = env.VITE_MODE !== app.PRODUCTION
|
||||
const COLORS: Color[] = [
|
||||
'primary',
|
||||
'success',
|
||||
'info',
|
||||
'warning',
|
||||
'danger',
|
||||
'error'
|
||||
]
|
||||
|
||||
// 日志输出等级
|
||||
const logPrintLevel = LogLevelEnum.DEBUG
|
||||
|
||||
const getColor = (type: Color) => COLOR_MAP[type]
|
||||
|
||||
/**
|
||||
* 输出函数
|
||||
*/
|
||||
type Log<T extends any[]> = (type: Color, ...args: T) => void
|
||||
|
||||
/**
|
||||
* 返回值
|
||||
*/
|
||||
type Created<T extends any[]> = Record<Color, (...args: T) => void>
|
||||
|
||||
const createLog = <T extends any[]> (
|
||||
fn: Log<T>
|
||||
): Created<T> => {
|
||||
return COLORS.reduce((logs, type) => {
|
||||
logs[type] = (...args: T) => fn(type, ...args)
|
||||
return logs
|
||||
}, {} as Created<T>)
|
||||
}
|
||||
|
||||
const nsLog = (type: Color, ns: string, msg: string, ...args: any[]) => {
|
||||
const color = getColor(type)
|
||||
console.log(
|
||||
`%c ${ns} %c ${msg} %c ${args.length ? '%o' : ''}`,
|
||||
`background:${color};border:1px solid ${color}; padding: 1px; border-radius: 4px 0 0 4px; color: #fff;`,
|
||||
`border:1px solid ${color}; padding: 1px; border-radius: 0 4px 4px 0; color: ${color};`,
|
||||
'background:transparent',
|
||||
...args
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印格式化日志
|
||||
*/
|
||||
export const logN = createLog(nsLog)
|
||||
|
||||
const sLog = (type: Color, msg: string, ...args: any[]) => {
|
||||
const color = getColor(type)
|
||||
console.log(
|
||||
`%c ${msg} ${args.length ? '%o' : ''}`,
|
||||
`color: ${color};`,
|
||||
...args
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印带有颜色的日志
|
||||
*/
|
||||
export const logS = createLog(sLog)
|
||||
|
||||
const bLog = (type: Color, msg: string, ...args: any[]) => {
|
||||
const color = getColor(type)
|
||||
console.log(
|
||||
`%c ${msg} ${args.length ? '%o' : ''}`,
|
||||
`background:${color}; padding: 2px; border-radius: 4px; color: #fff;`,
|
||||
...args
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印带有颜色背景的日志
|
||||
*/
|
||||
export const logB = createLog(bLog)
|
||||
|
||||
export const disLog = () => {
|
||||
console.log = function() {}
|
||||
}
|
||||
|
||||
const logHelper = {
|
||||
/**
|
||||
* DEBUG
|
||||
*/
|
||||
d: (tag: string, msg: string) => {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const logStyleFormat = (): string => {
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印日志
|
||||
* @param level 日志等级
|
||||
* @param tag 标记
|
||||
* @param msg 信息
|
||||
* @param e 报错信息【存在报错信息,默认使用 **ERROR** 等级】
|
||||
*/
|
||||
const print = (
|
||||
level: LogLevelEnum, tag: string, msg: string,
|
||||
e: Error | null | undefined = null) => {
|
||||
if (logPrintLevel > level) {
|
||||
return
|
||||
}
|
||||
// 格式化字符串
|
||||
// let str = formatMessage(msg)
|
||||
//
|
||||
// // 获取日志等级名称
|
||||
// let levelName = getLogLevelName(level)
|
||||
|
||||
switch (level) {
|
||||
case LogLevelEnum.VERBOSE:
|
||||
console.log()
|
||||
return LevelName.VERBOSE
|
||||
case LogLevelEnum.DEBUG:
|
||||
return LevelName.DEBUG
|
||||
case LogLevelEnum.INFO:
|
||||
return LevelName.INFO
|
||||
case LogLevelEnum.WARN:
|
||||
return LevelName.WARN
|
||||
case LogLevelEnum.ERROR:
|
||||
return LevelName.ERROR
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化输出信息
|
||||
* @param str
|
||||
*/
|
||||
const formatMessage = (str: string): string => {
|
||||
return `[${str}]`
|
||||
}
|
||||
@@ -1,11 +1,315 @@
|
||||
<script setup lang="ts">
|
||||
import { httpClient } from '@/utils/http.ts'
|
||||
import { CloseOutline, FolderOutline, CheckmarkCircle, EllipseOutline } from '@vicons/ionicons5'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { NSpace, NInput, NButton, NIcon, NTag, NCard, NEmpty, useMessage } from 'naive-ui'
|
||||
|
||||
// 消息提示
|
||||
const message = useMessage()
|
||||
|
||||
// 当前输入的路径
|
||||
const inputPath = ref('')
|
||||
|
||||
// 已添加的路径列表
|
||||
interface LibraryPath {
|
||||
id: string
|
||||
path: string
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
const libraryPaths = ref<LibraryPath[]>([
|
||||
{ id: '1', path: 'C:\\Users\\Documents\\教师资料', enabled: true },
|
||||
{ id: '2', path: 'D:\\程序员学习资料', enabled: true }
|
||||
])
|
||||
|
||||
// 选择文件夹
|
||||
// const selectFolder = async () => {
|
||||
// // 这里应该调用 Electron 或其他桌面框架的文件选择 API
|
||||
// // 示例代码,实际需要根据你的环境调整
|
||||
// try {
|
||||
// // const result = await window.electronAPI.selectFolder()
|
||||
// // if (result) {
|
||||
// // inputPath.value = result
|
||||
// // }
|
||||
//
|
||||
// // 临时模拟
|
||||
// inputPath.value = 'C:\\Users\\Documents\\示例路径'
|
||||
// message.info('请在实际环境中实现文件夹选择功能')
|
||||
// } catch (error) {
|
||||
// message.error('选择文件夹失败')
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// 选择文件夹(使用浏览器 File System Access API)
|
||||
const selectFolder = async () => {
|
||||
try {
|
||||
// 检查浏览器是否支持
|
||||
if (!('showDirectoryPicker' in window)) {
|
||||
message.warning('您的浏览器不支持文件夹选择功能,请手动输入路径')
|
||||
return
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-expect-error
|
||||
const dirHandle = await window.showDirectoryPicker()
|
||||
// 获取文件夹名称作为路径(实际项目中可能需要完整路径)
|
||||
inputPath.value = dirHandle.name
|
||||
} catch (err) {
|
||||
// 用户取消选择
|
||||
console.log('用户取消选择文件夹')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 添加路径
|
||||
const addPath = async () => {
|
||||
if (!inputPath.value.trim()) {
|
||||
message.warning('请输入或选择文件路径')
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否已存在
|
||||
if (libraryPaths.value.some(item => item.path === inputPath.value)) {
|
||||
message.warning('该路径已存在')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 发送到后端
|
||||
const response = await httpClient.post('/v1/library', {
|
||||
path: inputPath.value
|
||||
})
|
||||
|
||||
// 添加到列表
|
||||
libraryPaths.value.push({
|
||||
id: Date.now().toString(),
|
||||
path: inputPath.value,
|
||||
enabled: true
|
||||
})
|
||||
|
||||
// 清空输入
|
||||
inputPath.value = ''
|
||||
message.success('添加成功')
|
||||
} catch (error) {
|
||||
message.error('添加失败,请重试')
|
||||
}
|
||||
}
|
||||
|
||||
// 切换启用状态
|
||||
const toggleEnabled = async (item: LibraryPath) => {
|
||||
try {
|
||||
item.enabled = !item.enabled
|
||||
|
||||
// 发送到后端
|
||||
await httpClient.put(`/api/library/${item.id}`, {
|
||||
enabled: item.enabled
|
||||
})
|
||||
|
||||
message.success(item.enabled ? '已启用' : '已禁用')
|
||||
} catch (error) {
|
||||
// 恢复原状态
|
||||
item.enabled = !item.enabled
|
||||
message.error('操作失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 删除路径
|
||||
const removePath = async (item: LibraryPath) => {
|
||||
try {
|
||||
// 发送到后端
|
||||
await httpClient.delete(`/api/library/${item.id}`)
|
||||
|
||||
// 从列表中移除
|
||||
const index = libraryPaths.value.findIndex(p => p.id === item.id)
|
||||
if (index > -1) {
|
||||
libraryPaths.value.splice(index, 1)
|
||||
}
|
||||
|
||||
message.success('删除成功')
|
||||
} catch (error) {
|
||||
message.error('删除失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 开始任务
|
||||
const startTask = async () => {
|
||||
const enabledPaths = libraryPaths.value.filter(item => item.enabled)
|
||||
|
||||
if (enabledPaths.length === 0) {
|
||||
message.warning('请至少选择一个启用的路径')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await httpClient.post('/api/task/create', {
|
||||
paths: enabledPaths.map(item => item.path)
|
||||
})
|
||||
|
||||
message.success('任务已创建,正在处理中...')
|
||||
} catch (error) {
|
||||
message.error('创建任务失败')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
httpClient.get("v1/library").then((res) => {
|
||||
console.log(res);
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="library-manager">
|
||||
<!-- 顶部:添加资料库区域 -->
|
||||
<n-card class="add-section" title="添加资料库" size="small">
|
||||
<n-space>
|
||||
<n-input
|
||||
v-model:value="inputPath"
|
||||
size="large"
|
||||
placeholder="输入文件夹路径..."
|
||||
style="width: 500px"
|
||||
@keyup.enter="addPath"
|
||||
>
|
||||
<template #prefix>
|
||||
<n-icon :component="FolderOutline" />
|
||||
</template>
|
||||
<template #suffix>
|
||||
<n-button
|
||||
type="tertiary"
|
||||
size="small"
|
||||
@click="selectFolder"
|
||||
>
|
||||
选择文件夹
|
||||
</n-button>
|
||||
</template>
|
||||
</n-input>
|
||||
<n-button
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="addPath"
|
||||
>
|
||||
添加
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-card>
|
||||
|
||||
<!-- 中间:已选择的路径列表 -->
|
||||
<n-card class="paths-section" title="资料库列表" size="small">
|
||||
<div v-if="libraryPaths.length > 0" class="paths-container">
|
||||
<n-tag
|
||||
v-for="item in libraryPaths"
|
||||
:key="item.id"
|
||||
class="library-tag"
|
||||
:type="item.enabled ? 'success' : 'default'"
|
||||
size="large"
|
||||
>
|
||||
<n-space align="center" :size="12">
|
||||
<n-icon
|
||||
size="20"
|
||||
:component="item.enabled ? CheckmarkCircle : EllipseOutline"
|
||||
class="check-icon"
|
||||
@click="toggleEnabled(item)"
|
||||
/>
|
||||
<span class="path-text">{{ item.path }}</span>
|
||||
<n-icon
|
||||
size="18"
|
||||
:component="CloseOutline"
|
||||
class="close-icon"
|
||||
@click="removePath(item)"
|
||||
/>
|
||||
</n-space>
|
||||
</n-tag>
|
||||
</div>
|
||||
<n-empty v-else description="暂无资料库,请添加文件夹路径" />
|
||||
</n-card>
|
||||
|
||||
<!-- 底部:操作按钮 -->
|
||||
<n-card class="action-section" size="small">
|
||||
<n-space justify="start">
|
||||
<n-button
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="startTask"
|
||||
:disabled="libraryPaths.length === 0"
|
||||
>
|
||||
<template #icon>
|
||||
<span class="iconfont icon-zhongxinkaishi"></span>
|
||||
</template>
|
||||
开始检索
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.library-manager {
|
||||
padding: 20px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.add-section,
|
||||
.paths-section,
|
||||
.action-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.paths-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.library-tag {
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.library-tag:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.path-text {
|
||||
font-size: 14px;
|
||||
max-width: 400px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.check-icon:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.close-icon:hover {
|
||||
color: #d03050;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* 深色主题适配 */
|
||||
:deep(.n-card) {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
:deep(.n-card-header) {
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
:deep(.n-card__content) {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user