添加 请求 修改登录页

This commit is contained in:
GGJ
2023-12-26 08:45:15 +08:00
parent 46eb2d93fb
commit fea95de2da
34 changed files with 5892 additions and 541 deletions

View File

@@ -12,6 +12,7 @@
"@element-plus/icons-vue": "^2.3.1",
"@vueuse/core": "^10.7.0",
"axios": "^1.6.2",
"crypto-js": "^4.2.0",
"element-plus": "^2.4.4",
"lodash-es": "^4.17.21",
"mitt": "^3.0.1",

761
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

11
src/api/index.ts Normal file
View File

@@ -0,0 +1,11 @@
import request from '@/utils/request'
//get有值
export function getTest(params: any) {
return request.request({
url: '/test',
method: 'get',
params
})
}

8
src/api/types.ts Normal file
View File

@@ -0,0 +1,8 @@
// 登录
export interface LoginData {
username: String
password: String
imageCode: String
grant_type: String
verifyCode: number
}

19
src/api/user.ts Normal file
View File

@@ -0,0 +1,19 @@
import request from '@/utils/request'
import { LoginData } from './types.ts'
// 获取公钥
export function gongkey(params: any) {
return request.request({
url: '/user-boot/user/generateSm2Key',
method: 'get',
params
})
}
//登录获取token
export function login(params:LoginData) {
return request.request({
url: '/pqs-auth/oauth/token',
method: 'post',
params
})
}

3734
src/assets/commjs/sm2.js Normal file

File diff suppressed because it is too large Load Diff

257
src/assets/commjs/sm3.js Normal file
View File

@@ -0,0 +1,257 @@
/**
* 国密摘要算法SM3
* @param str:raw string
* @return the 256-bit hex string produced by SM3 from a raw string
*/
function sm3Digest(str) {
//1. 转换为二进制数组
var binArr = str2bin(str2rstr_utf8(str));
//2. 填充
var groupNum = alignSM3(binArr, str.length);
//3. 迭代压缩
var v = new Array(8);//初始值
v[0] = 0x7380166f;
v[1] = 0x4914b2b9;
v[2] = 0x172442d7;
v[3] = 0xda8a0600;
v[4] = 0xa96f30bc;
v[5] = 0x163138aa;
v[6] = 0xe38dee4d;
v[7] = 0xb0fb0e4e;
//按 512bit 分组进行压缩
for (var i = 0; i < groupNum; i++) {
v = compress(v, binArr, i);
}
return word2str(v, '');
}
/**
* 将数组转换为字符串。数组长度不定,每个元素为 32bit 的数字。
* @param words:数组,每个元素为 32bit 的数字
* @param seperator:在每个数组元素转换得到的字符串之间的分隔符
*/
function word2str(words, seperator) {
var prefix = Array(8).join('0');
for (var i = 0; i < words.length; i++) {
//若 hex 不足 8 位,则高位补 0
words[i] = (prefix + (words[i] >>> 0).toString(16)).slice(-8);
}
return words.join(seperator);
}
/**
* 将字符串转换为二进制数组,默认字符串编码为 UTF-8且范围在 0x00~0xFF 内。
* 若某些字符的编码超过此范围,则会只保留最低字节。加密可正常进行,但加密结果有误。
* 每个数组元素包含 4 个字符,即 32 bit。
* @param 字符串
* @return 数组,长度为(字符串长度 / 4每个元素为 32bit 的数字
*/
function str2bin(str) {
var binary = new Array(str.length >> 2);
for (var i = 0; i < str.length * 8; i += 8) {
binary[i >> 5] |= (str.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
}
return binary;
}
/**
* 对明文的二进制串进行填充
* <pre>
* | 满足 mod 512 = 448 | 固定 64 位 |
* | 明文二进制 |填充部分|明文二进制串的长度的二进制表示|
* xxxxxxxxxxxx 10.....0 0...........................xx
* </pre>
* @param arr:数组,每个元素为 32bit 的数字
* @param strLen明文字符串长度
* @return 数组,每个元素为 32bit 的数字,数组长度为 16 的倍数(包括 16
*/
function alignSM3(arr, strLen) {
//在明文二进制串后面拼接 1000 0000
arr[strLen >> 2] |= 0x80 << (24 - strLen % 4 * 8);
var groupNum = ((strLen + 8) >> 6) + 1;//以 512bit 为一组,总的组数
var wordNum = groupNum * 16;//一个 word 32bit总的 word 数
for (var i = (strLen >> 2) + 1; i < wordNum; i++) {
arr[i] = 0;
}
arr[wordNum - 1] = strLen * 8;//在末尾填上明文的二进制长度
return groupNum;
}
/**
* 压缩函数中的置换函数
*/
function p0(x) {
return x ^ bitRol(x, 9) ^ bitRol(x, 17);
}
/**
* 压缩函数中的置换函数
*/
function p1(x) {
return x ^ bitRol(x, 15) ^ bitRol(x, 23);
}
/**
* 循环左移
*/
function bitRol(input, n) {
return (input << n) | (input >>> (32 - n));
}
/**
* 压缩函数
*/
function compress(v, binArr, i) {
//将消息分组扩展成 132 个字
var w1 = new Array(68);
var w2 = new Array(64);
for (var j = 0; j < 68; j++) {
if (j < 16) {
w1[j] = binArr[i * 16 + j];
} else {
w1[j] = p1(w1[j-16] ^ w1[j-9] ^ bitRol(w1[j-3], 15)) ^ bitRol(w1[j-13], 7) ^ w1[j-6];
}
}
for (var j = 0; j < 64; j++) {
w2[j] = w1[j] ^ w1[j+4];
}
//压缩
var a = v[0];
var b = v[1];
var c = v[2];
var d = v[3];
var e = v[4];
var f = v[5];
var g = v[6];
var h = v[7];
var ss1;
var ss2;
var tt1;
var tt2;
for (var j = 0; j < 64; j++) {
ss1 = bitRol(addAll(bitRol(a, 12) , e , bitRol(t(j), j)), 7);
ss2 = ss1 ^ bitRol(a, 12);
tt1 = addAll(ff(a, b, c, j) , d , ss2 , w2[j]);
tt2 = addAll(gg(e, f, g, j) , h , ss1 , w1[j]);
d = c;
c = bitRol(b, 9);
b = a;
a = tt1;
h = g;
g = bitRol(f, 19);
f = e;
e = p0(tt2);
}
v[0] ^= a;
v[1] ^= b;
v[2] ^= c;
v[3] ^= d;
v[4] ^= e;
v[5] ^= f;
v[6] ^= g;
v[7] ^= h;
return v;
}
/**
* 常量 T 随 j 的不同而不同
*/
function t(j) {
if (0 <= j && j < 16) {
return 0x79CC4519;
} else if (j < 64) {
return 0x7A879D8A;
}
}
/**
* 布尔函数,随 j 的变化取不同的表达式
*/
function ff(x, y, z, j) {
if (0 <= j && j < 16) {
return x ^ y ^ z;
} else if (j < 64) {
return (x & y) | (x & z) | (y & z);
}
}
/**
* 布尔函数,随 j 的变化取不同的表达式
*/
function gg(x, y, z, j) {
if (0 <= j && j < 16) {
return x ^ y ^ z;
} else if (j < 64) {
return (x & y) | (~x & z);
}
}
/**
* 两数相加
* 避免某些 js 引擎的 32 位加法的 bug
*/
function safe_add(x, y) {
var lsw = ( x & 0xFFFF ) + (y & 0xFFFF);
var msw = ( x >> 16 ) + (y >> 16) + (lsw >> 16);
return (msw << 16) | ( lsw & 0xFFFF );
}
/**
* 将所有参数相加
*/
function addAll() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum = safe_add(sum, arguments[i]);
}
return sum;
}
/**
* UTF-16 --> UTF-8
*/
function str2rstr_utf8(input) {
var output = "" ;
var i = -1 ;
var x, y ;
while(++ i < input.length) {
//按 UTF-16 解码
x = input.charCodeAt(i);
y = i + 1 < input.length ? input .charCodeAt (i + 1) : 0 ;
if( 0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF ) {
x = 0x10000 + ((x & 0x03FF) << 10 ) + (y & 0x03FF);
i++;
}
//按 UTF-8 编码
if( x <= 0x7F ) {
output += String.fromCharCode(x);
}
else if(x <= 0x7FF) {
output += String.fromCharCode(
0xC0 | ((x >>> 6 ) & 0x1F),
0x80 | ( x & 0x3F ));
} else if(x <= 0xFFFF) {
output += String.fromCharCode(
0xE0 | ((x >>> 12) & 0x0F ),
0x80 | ((x >>> 6 ) & 0x3F),
0x80 | ( x & 0x3F ));
} else if(x <= 0x1FFFFF) {
output += String.fromCharCode(
0xF0 | ((x >>> 18) & 0x07 ),
0x80 | ((x >>> 12) & 0x3F),
0x80 | ((x >>> 6 ) & 0x3F),
0x80 | ( x & 0x3F ));
}
}
return output;
}
export {
sm3Digest
}

539
src/assets/font/demo.css Normal file
View File

@@ -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;
}

View File

@@ -0,0 +1,280 @@
<!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=3482754" 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">&#xe635;</span>
<div class="name">密码</div>
<div class="code-name">&amp;#xe635;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe639;</span>
<div class="name">用户</div>
<div class="code-name">&amp;#xe639;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe617;</span>
<div class="name">back</div>
<div class="code-name">&amp;#xe617;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe63e;</span>
<div class="name">platform-manage</div>
<div class="code-name">&amp;#xe63e;</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=1703485952035') format('woff2'),
url('iconfont.woff?t=1703485952035') format('woff'),
url('iconfont.ttf?t=1703485952035') 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-mima"></span>
<div class="name">
密码
</div>
<div class="code-name">.icon-mima
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-yonghu"></span>
<div class="name">
用户
</div>
<div class="code-name">.icon-yonghu
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-back"></span>
<div class="name">
back
</div>
<div class="code-name">.icon-back
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-platform-manage"></span>
<div class="name">
platform-manage
</div>
<div class="code-name">.icon-platform-manage
</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-mima"></use>
</svg>
<div class="name">密码</div>
<div class="code-name">#icon-mima</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-yonghu"></use>
</svg>
<div class="name">用户</div>
<div class="code-name">#icon-yonghu</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-back"></use>
</svg>
<div class="name">back</div>
<div class="code-name">#icon-back</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-platform-manage"></use>
</svg>
<div class="name">platform-manage</div>
<div class="code-name">#icon-platform-manage</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>

View File

@@ -0,0 +1,31 @@
@font-face {
font-family: "iconfont"; /* Project id 3482754 */
src: url('iconfont.woff2?t=1703485952035') format('woff2'),
url('iconfont.woff?t=1703485952035') format('woff'),
url('iconfont.ttf?t=1703485952035') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-mima:before {
content: "\e635";
}
.icon-yonghu:before {
content: "\e639";
}
.icon-back:before {
content: "\e617";
}
.icon-platform-manage:before {
content: "\e63e";
}

View File

@@ -0,0 +1 @@
window._iconfont_svg_string_3482754='<svg><symbol id="icon-mima" viewBox="0 0 1024 1024"><path d="M860.58 489.4c-0.09-47.06-29.76-88.04-72.49-101.63-16.6-5.3-33.82-6.09-51.12-5.3-7.68 0.35-12.01 0.71-11.12-10.95 2.12-28.52 2.47-57.39 1.23-86.09-4.06-94.48-70.11-174.13-163.18-198.41-88.3-23.04-182.87 15.72-233.64 93.86-40.62 62.34-35.23 130.94-31.97 201.58-11.92 0-22.69-0.26-33.38 0-56.25 1.5-101.1 46-101.37 102.16-0.53 117.88-0.62 235.75 0 353.63 0.35 57.31 44.94 104.2 101.9 104.54 165.29 1.06 330.68 0.97 495.97 0 55.01-0.35 98.9-46.71 99.16-101.89 0.45-117.15 0.36-234.33 0.01-351.5zM566.02 666.18c-8.65 6.53-11.3 12.72-11.04 22.87 0.62 25.78 0.44 51.66 0.18 77.44-0.44 29.76-17.31 47.68-43.97 47.24-25.7-0.35-41.77-18.01-42.21-46.8-0.26-15.1-0.44-30.11 0-45.21 0.8-26.23-0.09-48.39-23.75-69.58-25.52-22.95-25.96-57.83-10.95-89.88 15.54-33.03 42.91-48.39 72.4-50.51 42.12 0.44 75.76 25.34 87.33 59.96 11.47 34.51 1.06 72.48-27.99 94.47z m59.86-283.44c-37.35-0.71-74.7-0.27-112.05-0.27-38.06 0-76.2-0.79-114.26 0.35-14.84 0.45-17.75-4.68-17.22-18.1 1.06-22.96 0.09-46 0.35-68.96 0.8-71.88 57.39-128.65 128.48-129 71.17-0.35 128.65 55.8 130.15 127.68 0.53 24.46-0.71 48.92 0.35 73.29 0.54 12.88-4.23 15.18-15.8 15.01z" fill="#050101" ></path></symbol><symbol id="icon-yonghu" viewBox="0 0 1024 1024"><path d="M502.496 63.136c125.888 0 227.936 100.384 227.936 224.192 0 123.84-102.048 224.224-227.936 224.224-125.888 0-227.936-100.384-227.936-224.224C274.56 163.488 376.64 63.136 502.496 63.136L502.496 63.136zM502.496 63.136c125.888 0 227.936 100.384 227.936 224.192 0 123.84-102.048 224.224-227.936 224.224-125.888 0-227.936-100.384-227.936-224.224C274.56 163.488 376.64 63.136 502.496 63.136L502.496 63.136zM417.024 586.304l189.984 0c162.624 0 294.432 129.632 294.432 289.6l0 18.656c0 63.04-131.84 65.44-294.432 65.44l-189.984 0c-162.624 0-294.432-0.096-294.432-65.44l0-18.656C122.592 715.936 254.4 586.304 417.024 586.304L417.024 586.304zM417.024 586.304" fill="#272636" ></path></symbol><symbol id="icon-back" viewBox="0 0 1024 1024"><path d="M482.7 249.9V106.1c0-37.4-45.3-56.2-71.7-29.7L140.3 347c-16.4 16.4-16.4 43 0 59.4L410.9 677c26.5 26.5 71.7 7.7 71.7-29.7v-155c96.1-0.3 271.5-10.7 271.5 227.7 0 118.1-92.8 216.8-216 239.6 198.1-24.4 326-236 326-361.9 0.1-292.6-309.4-346.3-381.4-347.8z" fill="" ></path></symbol><symbol id="icon-platform-manage" viewBox="0 0 1024 1024"><path d="M186.561 655.343v0.047l282.35 139.201c27.067 13.355 59.018 13.355 86.086 0l282.35-139.154L944.22 708.06c9.678 4.76 15.782 14.445 15.782 25.031 0 10.586-6.104 20.27-15.782 25.03L554.997 950c-27.058 13.335-58.98 13.335-86.04 0L79.738 758.076c-9.627-4.78-15.688-14.435-15.688-24.984 0-10.55 6.061-20.205 15.687-24.985l106.825-52.764zM554.997 74.016L944.22 265.939c9.625 4.774 15.686 14.43 15.686 24.984 0 10.549-6.061 20.205-15.686 24.98L554.997 507.828c-27.058 13.336-58.98 13.336-86.04 0L79.738 315.902c-9.627-4.774-15.688-14.43-15.688-24.979 0-10.554 6.061-20.21 15.687-24.984L468.91 74.016c27.068-13.355 59.02-13.355 86.087 0z" ></path><path d="M185.891 434.654l283.067 139.529c27.058 13.335 58.981 13.335 86.04 0l283.018-139.529 106.204 52.301c9.678 4.756 15.782 14.44 15.782 25.027 0 10.59-6.104 20.275-15.782 25.03L554.997 728.936c-27.058 13.335-58.98 13.335-86.04 0L79.738 537.013c-9.65-4.766-15.735-14.436-15.735-25.008 0-10.568 6.085-20.238 15.734-25.003l106.155-52.348z" ></path></symbol></svg>',function(n){var t=(t=document.getElementsByTagName("script"))[t.length-1],e=t.getAttribute("data-injectcss"),t=t.getAttribute("data-disable-injectsvg");if(!t){var o,c,i,l,a,d=function(t,e){e.parentNode.insertBefore(t,e)};if(e&&!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)}}o=function(){var t,e=document.createElement("div");e.innerHTML=n._iconfont_svg_string_3482754,(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?d(e,t.firstChild):t.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(o,0):(c=function(){document.removeEventListener("DOMContentLoaded",c,!1),o()},document.addEventListener("DOMContentLoaded",c,!1)):document.attachEvent&&(i=o,l=n.document,a=!1,r(),l.onreadystatechange=function(){"complete"==l.readyState&&(l.onreadystatechange=null,s())})}function s(){a||(a=!0,i())}function r(){try{l.documentElement.doScroll("left")}catch(t){return void setTimeout(r,50)}s()}}(window);

View File

@@ -0,0 +1,37 @@
{
"id": "3482754",
"name": "灿能——电能质量光伏全景管理系统",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "8765228",
"name": "密码",
"font_class": "mima",
"unicode": "e635",
"unicode_decimal": 58933
},
{
"icon_id": "677608",
"name": "用户",
"font_class": "yonghu",
"unicode": "e639",
"unicode_decimal": 58937
},
{
"icon_id": "1471594",
"name": "back",
"font_class": "back",
"unicode": "e617",
"unicode_decimal": 58903
},
{
"icon_id": "30132209",
"name": "platform-manage",
"font_class": "platform-manage",
"unicode": "e63e",
"unicode_decimal": 58942
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/assets/login/big_bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
src/assets/login/jhui.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
src/assets/login/kt.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
src/assets/login/login.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 KiB

BIN
src/assets/login/login2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 KiB

BIN
src/assets/login/login3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 KiB

BIN
src/assets/login/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
src/assets/login/logo1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
src/assets/login/njcn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,8 +1,8 @@
<template>
<component :is='config.layout.layoutMode'></component>
<component :is="config.layout.layoutMode"></component>
</template>
<script setup lang='ts'>
<script setup lang="ts">
import { reactive } from 'vue'
import { useConfig } from '@/stores/config'
import { useNavTabs } from '@/stores/navTabs'
@@ -81,50 +81,63 @@ const init = () => {
]
},
{
'id': 2,
'pid': 0,
'type': 'menu_dir',
'title': '权限管理',
'name': 'auth',
'path': 'auth',
'icon': 'fa fa-group',
'menu_type': null,
'url': '',
'component': '',
'keepalive': 0,
'extend': 'none',
'children': [
{
'id': 3,
'pid': 2,
'type': 'menu',
'title': '角色管理',
'name': 'auth/role',
'path': 'auth/role',
'icon': 'fa fa-group',
'menu_type': 'tab',
'url': '',
'component': '/src/views/auth/role.vue',
'keepalive': 'auth/role',
'extend': 'none',
'children': []
id: 3,
pid: 0,
type: 'menu',
title: '测试1',
name: 'test',
path: 'test',
icon: 'fa fa-dashboard',
menu_type: 'tab',
url: '',
component: '/src/views/dashboard/test.vue',
keepalive: 'test',
extend: 'none'
},
{
'id': 13,
'pid': 2,
'type': 'menu',
'title': '菜单规则管理',
'name': 'auth/menu',
'path': 'auth/menu',
'icon': 'el-icon-Grid',
'menu_type': 'tab',
'url': '',
'component': '/src/views/auth/menu/index.vue',
'keepalive': 'auth/menu',
'extend': 'none',
'children': []
id: 2,
pid: 0,
type: 'menu_dir',
title: '权限管理',
name: 'auth',
path: 'auth',
icon: 'fa fa-group',
menu_type: null,
url: '',
component: '',
keepalive: 0,
extend: 'none',
children: [
{
id: 3,
pid: 2,
type: 'menu',
title: '角色管理',
name: 'auth/role',
path: 'auth/role',
icon: 'fa fa-group',
menu_type: 'tab',
url: '',
component: '/src/views/auth/role.vue',
keepalive: 'auth/role',
extend: 'none',
children: []
},
{
id: 13,
pid: 2,
type: 'menu',
title: '菜单规则管理',
name: 'auth/menu',
path: 'auth/menu',
icon: 'el-icon-Grid',
menu_type: 'tab',
url: '',
component: '/src/views/auth/menu/index.vue',
keepalive: 'auth/menu',
extend: 'none',
children: []
}
]
}
])

View File

@@ -9,6 +9,7 @@ import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/display.css'
// modules import mark, Please do not remove.
import '@/styles/index.scss'
import '@/assets/font/iconfont.css'
const app = createApp(App)

View File

@@ -3,6 +3,7 @@ import staticRoutes from '@/router/static'
import { useConfig } from '@/stores/config'
import NProgress from 'nprogress'
import { loading } from '@/utils/loading'
import { ElMessage } from 'element-plus'
const router = createRouter({
history: createWebHashHistory(),
@@ -17,6 +18,21 @@ router.beforeEach((to, from, next) => {
window.existLoading = true
}
console.log(to)
// if (to.path == '/login' || to.path == '/404') {
// // 登录或者注册才可以往下进行
// next()
// } else {
// // 获取 token
// const token = localStorage.getItem('toKen')
// // token 不存在
// if (token === null || token === '') {
// ElMessage.error('您还没有登录,请先登录')
// next('/login')
// } else {
// next()
// }
// }
next()
})

View File

@@ -26,6 +26,7 @@ export const useAdminInfo = defineStore('adminInfo', {
setToken(token: string, type: 'auth' | 'refresh') {
const field = type == 'auth' ? 'token' : 'refresh_token'
this[field] = token
window.localStorage.setItem('token', token)
},
getToken(type: 'auth' | 'refresh' = 'auth') {
return type === 'auth' ? this.token : this.refresh_token

62
src/utils/request.ts Normal file
View File

@@ -0,0 +1,62 @@
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
class HttpRequest {
getInsideConfig() {
const config = {
baseURL: '/api', // 所有的请求地址前缀部分(没有后端请求不用写)
timeout: 80000, // 请求超时时间(毫秒)
// headers: {
// 设置后端需要的传参类型
// 'Content-Type': 'application/json',
// 'token': x-auth-token',//一开始就要token
// 'X-Requested-With': 'XMLHttpRequest',
// },
}
return config
}
// 请求拦截
interceptors(instance: AxiosInstance, url: string | number | undefined) {
instance.interceptors.request.use(
config => {
const token: string | undefined = '' //getToken() //此处换成自己获取回来的token通常存在在cookie或者store里面
// 请求头携带token
if (token) {
config.headers['Authorization'] = token
config.headers.Authorization = +token
} else {
config.headers['Authorization'] = 'Basic bmpjbnRlc3Q6bmpjbnBxcw=='
}
return config
},
(error: any) => {
return Promise.reject(error)
}
)
//响应拦截
instance.interceptors.response.use(
res => {
//返回数据
const { data } = res
console.log('返回数据处理', data)
return data
},
(error: any) => {
console.log('error==>', error)
return Promise.reject(error)
}
)
}
request(options: AxiosRequestConfig) {
const instance = axios.create()
options = Object.assign(this.getInsideConfig(), options)
this.interceptors(instance, options.url)
return instance(options)
}
}
const request = new HttpRequest()
export default request

View File

@@ -0,0 +1,11 @@
<template>
<el-button @click="click">测试1</el-button>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { getTest } from '@/api/index'
const click = () => {
getTest({ name: '111', paw: 'asd' })
}
</script>
<style lang="scss" scoped></style>

View File

@@ -1,84 +1,95 @@
<template>
<div>
<div @contextmenu.stop='' id='bubble' class='bubble'>
<canvas id='bubble-canvas' class='bubble-canvas'></canvas>
<div @contextmenu.stop="" id="bubble" class="bubble">
<div class="login-image"></div>
<div class="login-container-form">
<div class="title-container">
<div class="title">
<span style="font-size: 28px">电能质量数据监测云平台</span>
</div>
<div class='login'>
<div class='login-box'>
<div class='head'>
<img src='@/assets/login-header.png' alt='' />
</div>
<div class='form'>
<img class='profile-avatar' src='@/assets/avatar.png' alt='' />
<div class='content'>
<el-form @keyup.enter='onSubmit()' ref='formRef' size='large' :model='form'>
<el-form-item prop='username'>
<el-form :rules="rules" ref="formRef" size="large" class="login-form" :model="form">
<el-form-item prop="username">
<el-input
ref='usernameRef'
type='text'
ref="usernameRef"
v-model="form.username"
type="text"
clearable
v-model='form.username'
placeholder='请输入账号'
placeholder="用户名"
autocomplete="off"
>
<template #prefix>
<Icon name='fa fa-user' class='form-item-icon' size='16'
color='var(--el-input-icon-color)' />
<span class="iconfont icon-yonghu" style="color: #003078"></span>
</template>
</el-input>
</el-form-item>
<el-form-item prop='password'>
<el-form-item prop="password">
<el-input
ref='passwordRef'
v-model='form.password'
type='password'
placeholder='请输入密码'
ref="passwordRef"
v-model="form.password"
type="password"
placeholder="密码"
show-password
autocomplete="off"
>
<template #prefix>
<Icon name='fa fa-unlock-alt' class='form-item-icon' size='16'
color='var(--el-input-icon-color)' />
<span class="iconfont icon-mima" style="color: #003078"></span>
</template>
</el-input>
</el-form-item>
<el-form-item>
<el-button
:loading='state.submitLoading'
class='submit-button'
:loading="state.submitLoading"
class="submit-btn"
round
type='primary'
size='large'
@click='onSubmit()'
type="info"
@click="onSubmit(formRef)"
>
登录
</el-button>
</el-form-item>
</el-form>
</div>
</div>
<div class="copy-right">
<span>版权所有 @ 南京灿能电力自动化股份有限公司</span>
<br />
<img style="width: 20px; height: 20px; position: absolute" src="@/assets/login/jhui.png" />
<span>  苏公网安备 32011502011902</span>
</div>
</div>
</div>
</template>
<script setup lang='ts'>
<script setup lang="ts">
import { onMounted, onBeforeUnmount, reactive, ref, nextTick } from 'vue'
import * as pageBubble from '@/utils/pageBubble'
import type { FormInstance, InputInstance } from 'element-plus'
import { sm3Digest } from '@/assets/commjs/sm3'
import { sm2, encrypt } from '@/assets/commjs/sm2.js'
import { gongkey, login } from '@/api/user'
import type { FormInstance, InputInstance, FormRules } from 'element-plus'
let timer: number
const formRef = ref<FormInstance>()
const usernameRef = ref<InputInstance>()
const passwordRef = ref<InputInstance>()
interface RuleForm {
username: string
password: string
}
const state = reactive({
showCaptcha: false,
submitLoading: false
})
const form = reactive({
username: '',
password: '',
password: ''
})
const rules = reactive<FormRules<RuleForm>>({
username: [{ required: true, trigger: 'blur', message: '请输入用户名' }],
password: [{ required: true, trigger: 'blur', message: '请输入密码' }]
})
const focusInput = () => {
if (form.username === '') {
@@ -91,8 +102,7 @@ const focusInput = () => {
onMounted(() => {
timer = window.setTimeout(() => {
pageBubble.init()
}, 1000)
}, 0)
})
onBeforeUnmount(() => {
@@ -100,89 +110,149 @@ onBeforeUnmount(() => {
pageBubble.removeListeners()
})
const onSubmit = (captchaInfo = '') => {
state.submitLoading = true
setTimeout(() => {
state.submitLoading = false
}, 3000)
const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
console.log()
gongkey({ loginName: encrypt(form.username) }).then(res => {
window.localStorage.setItem('publicKey', res.data)
let jiamipassword = sm2(sm3Digest(form.password) + '|' + form.password, res.data, 0)
login({
username: encrypt(form.username),
password: jiamipassword,
grant_type: 'captcha',
imageCode: '',
verifyCode: 0
}).then(res => {
window.localStorage.setItem('token', '123')
})
})
// routePush({ name: 'dashboard' })
// state.submitLoading = true
// setTimeout(() => {
// state.submitLoading = false
// }, 3000)
}
})
}
</script>
<style scoped lang='scss'>
.switch-language {
position: fixed;
top: 20px;
right: 20px;
z-index: 1;
<style scoped lang="scss">
.bubble {
position: relative;
width: 100%;
min-height: 100%;
overflow: hidden;
background-color: #003078 !important;
background-position: center 110px;
background-repeat: repeat;
background-size: 100%;
background-image: url(https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg);
}
.bubble {
overflow: hidden;
background: url(@/assets/bg.jpg) repeat;
.login-image {
position: absolute;
top: 50%;
left: 20%;
width: 45%;
height: 80%;
background: url('../../assets/login/login2.png') no-repeat center center;
background-size: contain;
transform: translate(-15%, -50%);
// box-shadow: 0 0 0 #011b2bab;
}
.form-item-icon {
height: auto;
}
.login {
.login-container-form {
position: absolute;
top: 0;
display: flex;
width: 100vw;
height: 100vh;
align-items: center;
justify-content: center;
.login-box {
overflow: hidden;
width: 430px;
padding: 0;
background: var(--ba-bg-color-overlay);
margin-bottom: 80px;
}
.head {
background: #ccccff;
img {
display: block;
width: 430px;
margin: 0 auto;
user-select: none;
}
}
.form {
top: 50%;
left: 85%;
width: 500px;
height: auto;
border-radius: 30px;
transform: translate(-85%, -50%);
box-shadow: 3px 3px 2px 2px #011b2bab;
.title-container {
position: relative;
.profile-avatar {
display: block;
position: absolute;
height: 100px;
width: 100px;
border-radius: 50%;
border: 4px solid var(--ba-bg-color-overlay);
top: -50px;
right: calc(50% - 50px);
z-index: 2;
user-select: none;
width: 398px;
max-width: 100%;
padding: 20px 0 0;
margin: 0 auto;
.title {
margin-bottom: 20px;
font-size: 33px;
font-weight: 600;
color: rgba(255, 255, 255, 0.85);
text-align: center;
& :v-deep .svg-icon {
// color: $;
}
.content {
padding: 100px 40px 40px 40px;
.logo {
width: 46px;
height: 46px;
margin-right: 10px;
vertical-align: middle;
}
.submit-button {
width: 100%;
letter-spacing: 2px;
font-weight: 300;
margin-top: 15px;
--el-button-bg-color: var(--el-color-primary);
}
}
}
.login-form {
position: relative;
width: 368px;
max-width: 100%;
//padding: 20px 0 0;
margin: 0 auto;
margin-bottom: 20px;
overflow: hidden;
&.el-input {
input {
height: 40px;
padding-right: 40px;
padding-left: 40px;
line-height: 40px;
border-radius: 5px;
}
.el-input__prefix,
.el-input__suffix {
width: 40px;
line-height: 40px;
.svg-icon {
font-size: 16px;
vertical-align: -0.25em;
}
}
.el-input__prefix {
left: 0;
}
.el-input__suffix {
right: 0;
}
}
}
.copy-right {
position: absolute;
bottom: 10px;
width: 100%;
font-size: 14px;
color: rgb(233, 229, 229);
text-align: center;
}
:v-deep.el-form-item--large {
margin-bottom: 15px;
}
.submit-btn {
width: 100%;
margin-top: 0px;
margin-bottom: 20px;
background: #4d6ea1;
border-radius: 0;
}
@media screen and (max-width: 720px) {
.login {
display: flex;
@@ -196,15 +266,6 @@ const onSubmit = (captchaInfo = '') => {
}
}
.chang-lang :deep(.el-dropdown-menu__item) {
justify-content: center;
}
.content :deep(.el-input__prefix) {
display: flex;
align-items: center;
}
@media screen and (max-height: 800px) {
.login .login-box {
margin-bottom: 0;

View File

@@ -0,0 +1,213 @@
<template>
<div>
<div @contextmenu.stop='' id='bubble' class='bubble'>
<canvas id='bubble-canvas' class='bubble-canvas'></canvas>
</div>
<div class='login'>
<div class='login-box'>
<div class='head'>
<img src='@/assets/login-header.png' alt='' />
</div>
<div class='form'>
<img class='profile-avatar' src='@/assets/avatar.png' alt='' />
<div class='content'>
<el-form @keyup.enter='onSubmit()' ref='formRef' size='large' :model='form'>
<el-form-item prop='username'>
<el-input
ref='usernameRef'
type='text'
clearable
v-model='form.username'
placeholder='请输入账号'
>
<template #prefix>
<Icon name='fa fa-user' class='form-item-icon' size='16'
color='var(--el-input-icon-color)' />
</template>
</el-input>
</el-form-item>
<el-form-item prop='password'>
<el-input
ref='passwordRef'
v-model='form.password'
type='password'
placeholder='请输入密码'
show-password
>
<template #prefix>
<Icon name='fa fa-unlock-alt' class='form-item-icon' size='16'
color='var(--el-input-icon-color)' />
</template>
</el-input>
</el-form-item>
<el-form-item>
<el-button
:loading='state.submitLoading'
class='submit-button'
round
type='primary'
size='large'
@click='onSubmit()'
>
登录
</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang='ts'>
import { onMounted, onBeforeUnmount, reactive, ref, nextTick } from 'vue'
import * as pageBubble from '@/utils/pageBubble'
import type { FormInstance, InputInstance } from 'element-plus'
let timer: number
const formRef = ref<FormInstance>()
const usernameRef = ref<InputInstance>()
const passwordRef = ref<InputInstance>()
const state = reactive({
showCaptcha: false,
submitLoading: false
})
const form = reactive({
username: '',
password: '',
})
const focusInput = () => {
if (form.username === '') {
usernameRef.value!.focus()
} else if (form.password === '') {
passwordRef.value!.focus()
}
}
onMounted(() => {
timer = window.setTimeout(() => {
pageBubble.init()
}, 1000)
})
onBeforeUnmount(() => {
clearTimeout(timer)
pageBubble.removeListeners()
})
const onSubmit = (captchaInfo = '') => {
state.submitLoading = true
setTimeout(() => {
state.submitLoading = false
}, 3000)
}
</script>
<style scoped lang='scss'>
.switch-language {
position: fixed;
top: 20px;
right: 20px;
z-index: 1;
}
.bubble {
overflow: hidden;
background: url(@/assets/bg.jpg) repeat;
}
.form-item-icon {
height: auto;
}
.login {
position: absolute;
top: 0;
display: flex;
width: 100vw;
height: 100vh;
align-items: center;
justify-content: center;
.login-box {
overflow: hidden;
width: 430px;
padding: 0;
background: var(--ba-bg-color-overlay);
margin-bottom: 80px;
}
.head {
background: #ccccff;
img {
display: block;
width: 430px;
margin: 0 auto;
user-select: none;
}
}
.form {
position: relative;
.profile-avatar {
display: block;
position: absolute;
height: 100px;
width: 100px;
border-radius: 50%;
border: 4px solid var(--ba-bg-color-overlay);
top: -50px;
right: calc(50% - 50px);
z-index: 2;
user-select: none;
}
.content {
padding: 100px 40px 40px 40px;
}
.submit-button {
width: 100%;
letter-spacing: 2px;
font-weight: 300;
margin-top: 15px;
--el-button-bg-color: var(--el-color-primary);
}
}
}
@media screen and (max-width: 720px) {
.login {
display: flex;
align-items: center;
justify-content: center;
.login-box {
width: 340px;
margin-top: 0;
}
}
}
.chang-lang :deep(.el-dropdown-menu__item) {
justify-content: center;
}
.content :deep(.el-input__prefix) {
display: flex;
align-items: center;
}
@media screen and (max-height: 800px) {
.login .login-box {
margin-bottom: 0;
}
}
</style>

View File

@@ -5,10 +5,32 @@ const nodeResolve = (dir: string) => path.resolve(__dirname, '.', dir)
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
'/api': {
// target: "http://192.168.1.115:10215", //黄正剑
// target: "http://192.168.1.22:10215", //超高压
target: "http://192.168.1.9:10215", //数据中心
// target: "http://192.168.1.13:10215", //治理
// target: 'http://192.168.1.18:10215', // 河北
// target: "http://192.168.1.31:10215", // 海南
// target: "http://192.168.1.29:10215", // 冀北
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''), //路径重写,把'/api'替换为''
},
'/api1': {
//target: "http://192.168.1.65:7300/mock/6384a6175854f20022dc9300/jibei",
target: 'http://192.168.1.9:8088',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api1/, ''), //路径重写,把'/api'替换为''
}
}
},
resolve: {
alias: {
'@': nodeResolve('src'),
'~': nodeResolve('public'),
'~': nodeResolve('public')
}
}
})