Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
najiu-admin-template
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
najiu-frontend
najiu-admin-template
Commits
ec9478f7
Commit
ec9478f7
authored
Feb 21, 2021
by
vben
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: refactor login page
parent
e3851dc5
Changes
33
Show whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
1220 additions
and
401 deletions
+1220
-401
extensions.json
.vscode/extensions.json
+1
-6
i18n-ally-reviews.yml
.vscode/i18n-ally-reviews.yml
+5
-0
CHANGELOG.zh_CN.md
CHANGELOG.zh_CN.md
+5
-0
themeConfig.ts
build/config/themeConfig.ts
+1
-1
package.json
package.json
+5
-5
login-bg.png
src/assets/images/login/login-bg.png
+0
-0
login-in.png
src/assets/images/login/login-in.png
+0
-0
login-bg.svg
src/assets/svg/login-bg.svg
+17
-0
login-box-bg.svg
src/assets/svg/login-box-bg.svg
+1
-0
AppLogo.vue
src/components/Application/src/AppLogo.vue
+8
-2
index.ts
src/components/CountDown/index.ts
+4
-0
CountButton.vue
src/components/CountDown/src/CountButton.vue
+57
-0
CountdownInput.vue
src/components/CountDown/src/CountdownInput.vue
+55
-0
useCountdown.ts
src/components/CountDown/src/useCountdown.ts
+51
-0
index.vue
src/components/StrengthMeter/src/index.vue
+7
-9
index.less
src/design/ant/index.less
+2
-4
breakpoint.less
src/design/var/breakpoint.less
+4
-24
index.vue
...layouts/default/header/components/user-dropdown/index.vue
+1
-1
countdown.ts
src/locales/lang/en/component/countdown.ts
+4
-0
login.ts
src/locales/lang/en/sys/login.ts
+30
-5
countdown.ts
src/locales/lang/zh_CN/component/countdown.ts
+4
-0
login.ts
src/locales/lang/zh_CN/sys/login.ts
+27
-2
LockPage.vue
src/views/sys/lock/LockPage.vue
+54
-111
ForgetPasswordForm.vue
src/views/sys/login/ForgetPasswordForm.vue
+90
-0
Login.vue
src/views/sys/login/Login.vue
+134
-183
LoginForm.vue
src/views/sys/login/LoginForm.vue
+171
-0
MobileForm.vue
src/views/sys/login/MobileForm.vue
+85
-0
QrCodeForm.vue
src/views/sys/login/QrCodeForm.vue
+40
-0
RegisterForm.vue
src/views/sys/login/RegisterForm.vue
+117
-0
useLogin.ts
src/views/sys/login/useLogin.ts
+134
-0
tailwind.config.js
tailwind.config.js
+0
-20
windi.config.ts
windi.config.ts
+71
-0
yarn.lock
yarn.lock
+35
-28
No files found.
.vscode/extensions.json
View file @
ec9478f7
{
{
"recommendations"
:
[
"recommendations"
:
[
"johnsoncodehk.volar"
,
"octref.vetur"
,
"octref.vetur"
,
"dbaeumer.vscode-eslint"
,
"dbaeumer.vscode-eslint"
,
"stylelint.vscode-stylelint"
,
"stylelint.vscode-stylelint"
,
"DavidAnson.vscode-markdownlint"
,
"esbenp.prettier-vscode"
,
"esbenp.prettier-vscode"
,
"mrmlnc.vscode-less"
,
"mrmlnc.vscode-less"
,
"antfu.i18n-ally"
,
"antfu.i18n-ally"
,
"cpylua.language-postcss"
,
"Orta.vscode-jest"
,
"antfu.iconify"
,
"antfu.iconify"
,
"mikestead.dotenv"
,
"mikestead.dotenv"
,
"bradlc.vscode-tailwindcss"
,
"bradlc.vscode-tailwindcss"
,
"heybourn.headwind"
,
"heybourn.headwind"
"znck.vue-language-features"
]
]
}
}
.vscode/i18n-ally-reviews.yml
0 → 100644
View file @
ec9478f7
# Review comments generated by i18n-ally. Please commit this file.
reviews
:
sys.login.autoLogin
:
description
:
'
1'
CHANGELOG.zh_CN.md
View file @
ec9478f7
## Wip
## Wip
### ✨ Refactor
-
登录页重构,新增注册页面/重置密码页面/手机登录/二维码登录
### ✨ Features
### ✨ Features
-
新增
`settingButtonPosition`
配置项,用于配置
`设置`
按钮位置
-
新增
`settingButtonPosition`
配置项,用于配置
`设置`
按钮位置
-
`modal`
可以通过双击头部切换全屏
-
`modal`
可以通过双击头部切换全屏
-
新增
`CountDownInput`
组件
### ⚡ Performance Improvements
### ⚡ Performance Improvements
...
...
build/config/themeConfig.ts
View file @
ec9478f7
...
@@ -94,7 +94,7 @@ export function generateModifyVars() {
...
@@ -94,7 +94,7 @@ export function generateModifyVars() {
'
disabled-color
'
:
'
rgba(0, 0, 0, 0.25)
'
,
// Failure color
'
disabled-color
'
:
'
rgba(0, 0, 0, 0.25)
'
,
// Failure color
'
heading-color
'
:
'
rgba(0, 0, 0, 0.85)
'
,
// Title color
'
heading-color
'
:
'
rgba(0, 0, 0, 0.85)
'
,
// Title color
'
text-color
'
:
'
rgba(0, 0, 0, 0.85)
'
,
// Main text color
'
text-color
'
:
'
rgba(0, 0, 0, 0.85)
'
,
// Main text color
'
text-color-secondary
'
:
'
rgba(0, 0, 0, 0.45)
'
,
// Subtext color
'
text-color-secondary
'
:
'
rgba(0, 0, 0, 0.45)
'
,
// Subtext color
'
font-size-base
'
:
'
14px
'
,
// Main font size
'
font-size-base
'
:
'
14px
'
,
// Main font size
'
box-shadow-base
'
:
'
0 2px 8px rgba(0, 0, 0, 0.15)
'
,
// Floating shadow
'
box-shadow-base
'
:
'
0 2px 8px rgba(0, 0, 0, 0.15)
'
,
// Floating shadow
'
border-color-base
'
:
'
#d9d9d9
'
,
// Border color,
'
border-color-base
'
:
'
#d9d9d9
'
,
// Border color,
...
...
package.json
View file @
ec9478f7
...
@@ -43,7 +43,7 @@
...
@@ -43,7 +43,7 @@
"
vditor
"
:
"
^3.8.1
"
,
"
vditor
"
:
"
^3.8.1
"
,
"
vue
"
:
"
^3.0.5
"
,
"
vue
"
:
"
^3.0.5
"
,
"
vue-i18n
"
:
"
9.0.0-rc.2
"
,
"
vue-i18n
"
:
"
9.0.0-rc.2
"
,
"
vue-router
"
:
"
^4.0.
3
"
,
"
vue-router
"
:
"
^4.0.
4
"
,
"
vue-types
"
:
"
^3.0.2
"
,
"
vue-types
"
:
"
^3.0.2
"
,
"
vuex
"
:
"
^4.0.0
"
,
"
vuex
"
:
"
^4.0.0
"
,
"
vuex-module-decorators
"
:
"
^1.0.1
"
,
"
vuex-module-decorators
"
:
"
^1.0.1
"
,
...
@@ -92,7 +92,7 @@
...
@@ -92,7 +92,7 @@
"
pretty-quick
"
:
"
^3.1.0
"
,
"
pretty-quick
"
:
"
^3.1.0
"
,
"
rimraf
"
:
"
^3.0.2
"
,
"
rimraf
"
:
"
^3.0.2
"
,
"
rollup-plugin-visualizer
"
:
"
^4.2.0
"
,
"
rollup-plugin-visualizer
"
:
"
^4.2.0
"
,
"
stylelint
"
:
"
^13.1
0
.0
"
,
"
stylelint
"
:
"
^13.1
1
.0
"
,
"
stylelint-config-prettier
"
:
"
^8.0.2
"
,
"
stylelint-config-prettier
"
:
"
^8.0.2
"
,
"
stylelint-config-standard
"
:
"
^20.0.0
"
,
"
stylelint-config-standard
"
:
"
^20.0.0
"
,
"
stylelint-order
"
:
"
^4.1.0
"
,
"
stylelint-order
"
:
"
^4.1.0
"
,
...
@@ -104,10 +104,10 @@
...
@@ -104,10 +104,10 @@
"
vite-plugin-imagemin
"
:
"
^0.2.6
"
,
"
vite-plugin-imagemin
"
:
"
^0.2.6
"
,
"
vite-plugin-mock
"
:
"
^2.1.4
"
,
"
vite-plugin-mock
"
:
"
^2.1.4
"
,
"
vite-plugin-purge-icons
"
:
"
^0.7.0
"
,
"
vite-plugin-purge-icons
"
:
"
^0.7.0
"
,
"
vite-plugin-pwa
"
:
"
^0.5.
1
"
,
"
vite-plugin-pwa
"
:
"
^0.5.
2
"
,
"
vite-plugin-style-import
"
:
"
^0.7.
2
"
,
"
vite-plugin-style-import
"
:
"
^0.7.
3
"
,
"
vite-plugin-theme
"
:
"
^0.4.3
"
,
"
vite-plugin-theme
"
:
"
^0.4.3
"
,
"
vite-plugin-windicss
"
:
"
0.
3.12
"
,
"
vite-plugin-windicss
"
:
"
0.
4.3
"
,
"
vue-eslint-parser
"
:
"
^7.5.0
"
,
"
vue-eslint-parser
"
:
"
^7.5.0
"
,
"
yargs
"
:
"
^16.2.0
"
"
yargs
"
:
"
^16.2.0
"
},
},
...
...
src/assets/images/login/login-bg.png
deleted
100644 → 0
View file @
e3851dc5
180 KB
src/assets/images/login/login-in.png
deleted
100644 → 0
View file @
e3851dc5
91.5 KB
src/assets/svg/login-bg.svg
0 → 100644
View file @
ec9478f7
<svg
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"6395"
height=
"1079"
viewBox=
"0 0 6395 1079"
>
<defs>
<clipPath
id=
"clip-path"
>
<rect
id=
"Rectangle_73"
data-name=
"Rectangle 73"
width=
"6395"
height=
"1079"
transform=
"translate(-5391)"
fill=
"#fff"
/>
</clipPath>
<linearGradient
id=
"linear-gradient"
x1=
"0.747"
y1=
"0.222"
x2=
"0.973"
y2=
"0.807"
gradientUnits=
"objectBoundingBox"
>
<stop
offset=
"0"
stop-color=
"#2b51b4"
/>
<stop
offset=
"1"
stop-color=
"#1c3faa"
/>
</linearGradient>
</defs>
<g
id=
"Mask_Group_1"
data-name=
"Mask Group 1"
transform=
"translate(5391)"
clip-path=
"url(#clip-path)"
>
<g
id=
"Group_118"
data-name=
"Group 118"
transform=
"translate(-419.333 -1.126)"
>
<path
id=
"Path_142"
data-name=
"Path 142"
d=
"M6271.734-6.176s-222.478,187.809-55.349,583.254c44.957,106.375,81.514,205.964,84.521,277,8.164,192.764-156.046,268.564-156.046,268.564l-653.53-26.8L5475.065-21.625Z"
transform=
"translate(-4876.383 0)"
fill=
"#f1f5f8"
/>
<path
id=
"Union_6"
data-name=
"Union 6"
d=
"M-2631.1,1081.8v-1.6H-8230.9V.022H-2631.1V0H-1871.4s-187.845,197.448-91.626,488.844c49.167,148.9,96.309,256.289,104.683,362.118,7.979,100.852-57.98,201.711-168.644,254.286-65.858,31.29-144.552,42.382-223.028,42.383C-2441.2,1147.632-2631.1,1081.8-2631.1,1081.8Z"
transform=
"translate(3259.524 0.803)"
fill=
"url(#linear-gradient)"
/>
</g>
</g>
</svg>
src/assets/svg/login-box-bg.svg
0 → 100644
View file @
ec9478f7
<svg
id=
"a622e68e-7a65-46e9-94a9-d455de519afc"
data-name=
"Layer 1"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"971.44"
height=
"502"
viewBox=
"0 0 971.44 502"
><defs><linearGradient
id=
"341b0e5e-a21f-44db-b85f-76180f33f0d3"
x1=
"599.5"
y1=
"668.05"
x2=
"599.5"
y2=
"199"
gradientUnits=
"userSpaceOnUse"
><stop
offset=
"0"
stop-color=
"gray"
stop-opacity=
"0.25"
/><stop
offset=
"0.54"
stop-color=
"gray"
stop-opacity=
"0.12"
/><stop
offset=
"1"
stop-color=
"gray"
stop-opacity=
"0.1"
/></linearGradient><linearGradient
id=
"9c19d1ba-0c1d-4cca-8c15-e6f3831a5e67"
x1=
"485.72"
y1=
"258.88"
x2=
"485.72"
y2=
"71.12"
xlink:href=
"#341b0e5e-a21f-44db-b85f-76180f33f0d3"
/><linearGradient
id=
"fe76f7c7-2126-4e48-920d-21143a22d340"
x1=
"132"
y1=
"515"
x2=
"303"
y2=
"515"
xlink:href=
"#341b0e5e-a21f-44db-b85f-76180f33f0d3"
/><linearGradient
id=
"2cf89a04-5a05-413b-983a-d2bc296cbb5e"
x1=
"933"
y1=
"568.28"
x2=
"1031"
y2=
"568.28"
xlink:href=
"#341b0e5e-a21f-44db-b85f-76180f33f0d3"
/></defs><title>
responsive
</title><g
opacity=
"0.7"
><path
d=
"M852.69,199H346.31A16.37,16.37,0,0,0,330,215.42V563.94a16.37,16.37,0,0,0,16.31,16.42H520.47v60.16h-7.94a8.3,8.3,0,0,0-8.27,8.33v12.07h16.21v7.14H678.53v-7.14h16.21V648.85a8.3,8.3,0,0,0-8.27-8.33H679V640h-.51V580.36H852.69A16.37,16.37,0,0,0,869,563.94V215.42A16.37,16.37,0,0,0,852.69,199Z"
transform=
"translate(-114.28 -199)"
fill=
"url(#341b0e5e-a21f-44db-b85f-76180f33f0d3)"
/></g><rect
x=
"407.72"
y=
"371"
width=
"156"
height=
"92"
fill=
"#bdbdbd"
/><g
opacity=
"0.1"
><path
d=
"M525.07,579H675.24c1.81-7.87,3.26-13,3.26-13h-157S523.11,571.11,525.07,579Z"
transform=
"translate(-114.28 -199)"
/></g><path
d=
"M235.82,3h499.8a16.1,16.1,0,0,1,16.1,16.1V327a0,0,0,0,1,0,0h-532a0,0,0,0,1,0,0V19.1A16.1,16.1,0,0,1,235.82,3Z"
fill=
"#535461"
/><path
d=
"M849.9,576H350.1A16.1,16.1,0,0,1,334,559.9V526H866v33.9A16.1,16.1,0,0,1,849.9,576Z"
transform=
"translate(-114.28 -199)"
fill=
"#bdbdbd"
/><circle
cx=
"485.72"
cy=
"352"
r=
"9"
fill=
"#535461"
/><path
d=
"M399.89,436H571.55a8.17,8.17,0,0,1,8.17,8.17V456a0,0,0,0,1,0,0h-188a0,0,0,0,1,0,0V444.17A8.17,8.17,0,0,1,399.89,436Z"
fill=
"#bdbdbd"
/><g
opacity=
"0.5"
><rect
x=
"320.72"
y=
"71.12"
width=
"330"
height=
"187.76"
rx=
"4.5"
ry=
"4.5"
fill=
"url(#9c19d1ba-0c1d-4cca-8c15-e6f3831a5e67)"
/></g><rect
x=
"324.95"
y=
"72.5"
width=
"321.54"
height=
"183.96"
rx=
"4.5"
ry=
"4.5"
fill=
"#fff"
/><g
opacity=
"0.5"
><rect
x=
"414.52"
y=
"98.91"
width=
"35.44"
height=
"31.9"
rx=
"4.5"
ry=
"4.5"
fill=
"#0960bd"
/></g><rect
x=
"460.59"
y=
"98.91"
width=
"95.69"
height=
"3.54"
rx=
"1.77"
ry=
"1.77"
fill=
"#e0e0e0"
/><rect
x=
"460.59"
y=
"109.55"
width=
"79.54"
height=
"3.54"
rx=
"1.77"
ry=
"1.77"
fill=
"#e0e0e0"
/><g
opacity=
"0.5"
><rect
x=
"414.52"
y=
"148.53"
width=
"35.44"
height=
"31.9"
rx=
"4.5"
ry=
"4.5"
fill=
"#0960bd"
/></g><rect
x=
"460.59"
y=
"148.53"
width=
"95.69"
height=
"3.54"
rx=
"1.77"
ry=
"1.77"
fill=
"#e0e0e0"
/><rect
x=
"460.59"
y=
"159.16"
width=
"95.69"
height=
"3.54"
rx=
"1.77"
ry=
"1.77"
fill=
"#e0e0e0"
/><g
opacity=
"0.5"
><rect
x=
"414.52"
y=
"198.15"
width=
"35.44"
height=
"31.9"
rx=
"4.5"
ry=
"4.5"
fill=
"#0960bd"
/></g><rect
x=
"460.59"
y=
"198.15"
width=
"95.69"
height=
"3.54"
rx=
"1.77"
ry=
"1.77"
fill=
"#e0e0e0"
/><rect
x=
"460.59"
y=
"208.78"
width=
"96.33"
height=
"3.54"
rx=
"1.59"
ry=
"1.59"
fill=
"#e0e0e0"
/><line
x1=
"485.72"
y1=
"42"
x2=
"485.72"
y2=
"20"
stroke=
"#0960bd"
stroke-miterlimit=
"10"
stroke-width=
"2"
/><line
x1=
"485.72"
y1=
"79"
x2=
"485.72"
y2=
"50.13"
stroke=
"#0960bd"
stroke-miterlimit=
"10"
stroke-width=
"2"
/><circle
cx=
"485.72"
cy=
"79"
r=
"4"
fill=
"#0960bd"
/><circle
cx=
"485.72"
cy=
"46"
r=
"4"
fill=
"none"
stroke=
"#fff"
stroke-miterlimit=
"10"
/><line
x1=
"485.72"
y1=
"42"
x2=
"485.72"
y2=
"20"
stroke=
"#0960bd"
stroke-miterlimit=
"10"
stroke-width=
"2"
/><line
x1=
"485.72"
y1=
"79"
x2=
"485.72"
y2=
"50.13"
stroke=
"#0960bd"
stroke-miterlimit=
"10"
stroke-width=
"2"
/><circle
cx=
"485.72"
cy=
"79"
r=
"4"
fill=
"#0960bd"
/><circle
cx=
"485.72"
cy=
"46"
r=
"4"
fill=
"none"
stroke=
"#fff"
stroke-miterlimit=
"10"
/><line
x1=
"485.72"
y1=
"279"
x2=
"485.72"
y2=
"310"
stroke=
"#0960bd"
stroke-miterlimit=
"10"
stroke-width=
"2"
/><line
x1=
"485.72"
y1=
"251"
x2=
"485.72"
y2=
"279.87"
stroke=
"#0960bd"
stroke-miterlimit=
"10"
stroke-width=
"2"
/><circle
cx=
"485.72"
cy=
"251"
r=
"4"
fill=
"#0960bd"
/><line
x1=
"305.72"
y1=
"168.5"
x2=
"274.22"
y2=
"168.5"
stroke=
"#0960bd"
stroke-miterlimit=
"10"
stroke-width=
"2"
/><line
x1=
"333.22"
y1=
"168.5"
x2=
"304.35"
y2=
"168.5"
stroke=
"#0960bd"
stroke-miterlimit=
"10"
stroke-width=
"2"
/><circle
cx=
"333.22"
cy=
"168.5"
r=
"4"
fill=
"#0960bd"
/><g
opacity=
"0.1"
><rect
x=
"408.22"
y=
"435.5"
width=
"156"
height=
"3"
/></g><g
opacity=
"0.7"
><path
d=
"M293.48,566.06H221.08l1-8.14c20.46-18.37,33.69-67.31,33.69-67.31a6.78,6.78,0,0,0-.87.18c-12,2.42-20.54,7.35-26.51,13.28l2.54-21.66c37.8-8.14,52.79-58.14,52.79-58.14-24.12,5.35-39.16,13.63-48.5,21.49l3.72-31.82c25.56,8.77,52-37.82,52-37.82l-1-.21.5-.32-.76.27c-28.25-6.09-43.35,10.06-48.25,16.77l.37-3.12q-1.12,3-2.18,5.88h0l0,.08q-3,8.13-5.49,16.06l0,0h0q-2.17,6.77-4.06,13.4l0-.06s-1.17-28.46-31.18-35.95c0,0,3.15,62.07,26.93,51.91h0c-2.2,9-4,17.66-5.56,26.07h0q-1.49,8.21-2.6,16l-.14.16.14-.12-.06.41v0h0q-1,7.07-1.7,13.78c.46-8.62-1.11-33.52-30.45-56.92,0,0-39,68.54,27.5,82,.15.13.3.26.44.38l-.1-.31.6.13.27-3.52a369.39,369.39,0,0,0,.23,44.1h0c.07,1,.14,2,.21,2.95H141.37c-27.94,57.79,15.52,89.46,15.52,89.46h120C323.49,596.66,293.48,566.06,293.48,566.06Zm-78-65.68h0v0Z"
transform=
"translate(-114.28 -199)"
fill=
"url(#fe76f7c7-2126-4e48-920d-21143a22d340)"
/></g><path
d=
"M217,588s-19-83,23-190"
transform=
"translate(-114.28 -199)"
fill=
"none"
stroke=
"#535461"
stroke-miterlimit=
"10"
stroke-width=
"3"
opacity=
"0.6"
/><path
d=
"M143,563H290s29,37-16,92H158S116,617,143,563Z"
transform=
"translate(-114.28 -199)"
fill=
"#0960bd"
/><path
d=
"M237.89,403.5s14.61-26,49.61-18c0,0-28.93,49.26-55,33.13Z"
transform=
"translate(-114.28 -199)"
fill=
"#4db6ac"
/><path
d=
"M228.63,431.09S227.5,404.5,198.5,397.5c0,0,3,58,26,48.5Z"
transform=
"translate(-114.28 -199)"
fill=
"#4db6ac"
/><path
d=
"M219.15,470.36s5.35-27.86,61.35-39.86c0,0-17.86,57.62-63.93,55.31Z"
transform=
"translate(-114.28 -199)"
fill=
"#4db6ac"
/><path
d=
"M214.61,501.63s5.89-29.13-29.11-56.13c0,0-38,64.67,27.48,76.83Z"
transform=
"translate(-114.28 -199)"
fill=
"#4db6ac"
/><path
d=
"M213.56,541.67S209.5,500.5,253.5,492.5c0,0-16.07,57.49-40,67.74Z"
transform=
"translate(-114.28 -199)"
fill=
"#4db6ac"
/><path
d=
"M233,419s38-29,54-34"
transform=
"translate(-114.28 -199)"
fill=
"none"
stroke=
"#535461"
stroke-miterlimit=
"10"
opacity=
"0.3"
/><path
d=
"M216.5,485.5s46-49,64-55"
transform=
"translate(-114.28 -199)"
fill=
"none"
stroke=
"#535461"
stroke-miterlimit=
"10"
opacity=
"0.3"
/><path
d=
"M198.5,397.5s28,38,26,48"
transform=
"translate(-114.28 -199)"
fill=
"none"
stroke=
"#535461"
stroke-miterlimit=
"10"
opacity=
"0.3"
/><path
d=
"M185.5,445.5s15,68,27,77"
transform=
"translate(-114.28 -199)"
fill=
"none"
stroke=
"#535461"
stroke-miterlimit=
"10"
opacity=
"0.3"
/><path
d=
"M213.5,560.5s24-66,40-68"
transform=
"translate(-114.28 -199)"
fill=
"none"
stroke=
"#535461"
stroke-miterlimit=
"10"
opacity=
"0.3"
/><g
opacity=
"0.1"
><path
d=
"M290,563H143c-.33.67-.65,1.34-1,2H285s28.29,36.11-14.4,90H274C319,600,290,563,290,563Z"
transform=
"translate(-114.28 -199)"
/></g><rect
y=
"455.6"
width=
"971.44"
height=
"32.93"
fill=
"#e0e0e0"
/><rect
x=
"41.16"
y=
"488.53"
width=
"889.11"
height=
"13.47"
fill=
"#e0e0e0"
/><rect
x=
"41.16"
y=
"488.53"
width=
"889.11"
height=
"4.49"
opacity=
"0.1"
/><line
x1=
"690.22"
y1=
"168.5"
x2=
"696.22"
y2=
"168.5"
stroke=
"#0960bd"
stroke-miterlimit=
"10"
stroke-width=
"2"
/><line
x1=
"637.22"
y1=
"168.5"
x2=
"682.1"
y2=
"168.5"
stroke=
"#0960bd"
stroke-miterlimit=
"10"
stroke-width=
"2"
/><circle
cx=
"637.22"
cy=
"168.5"
r=
"4"
fill=
"#0960bd"
/><circle
cx=
"686.22"
cy=
"168.5"
r=
"4"
fill=
"none"
stroke=
"#fff"
stroke-miterlimit=
"10"
/><g
opacity=
"0.7"
><path
d=
"M1027,643.88l.1-.15q.31-.48.61-1l.11-.19q.29-.49.55-1l.09-.17c.2-.39.39-.78.56-1.19h0a23.79,23.79,0,0,0,.94-2.51l.1-.33c.09-.31.18-.62.26-.93l.1-.44q.1-.42.18-.85c0-.16.06-.32.09-.48s.09-.56.13-.85,0-.33.06-.49.06-.61.08-.92c0-.14,0-.29,0-.43,0-.45,0-.91,0-1.36V548h-13.85V507.52h-17V548H988.39V489.86h-17V548H965V481.55h-17V548H933V630.6c0,13.48,11.21,24.4,25,24.4H1006a25.19,25.19,0,0,0,20.24-10.06l0,0Q1026.61,644.41,1027,643.88Z"
transform=
"translate(-114.28 -199)"
fill=
"url(#2cf89a04-5a05-413b-983a-d2bc296cbb5e)"
/></g><rect
x=
"835.72"
y=
"321"
width=
"16"
height=
"100"
fill=
"#535461"
/><rect
x=
"835.72"
y=
"288"
width=
"16"
height=
"33"
fill=
"#3ad29f"
/><rect
x=
"857.72"
y=
"329"
width=
"16"
height=
"100"
fill=
"#535461"
/><rect
x=
"857.72"
y=
"296"
width=
"16"
height=
"33"
fill=
"#4d8af0"
/><rect
x=
"884.72"
y=
"346"
width=
"16"
height=
"100"
fill=
"#535461"
/><rect
x=
"884.72"
y=
"313"
width=
"16"
height=
"33"
fill=
"#f55f44"
/><path
d=
"M821.72,352h92a0,0,0,0,1,0,0v79.5a23.5,23.5,0,0,1-23.5,23.5h-45a23.5,23.5,0,0,1-23.5-23.5V352A0,0,0,0,1,821.72,352Z"
fill=
"#0960bd"
/><g
opacity=
"0.1"
><path
d=
"M936,551v4h88v79.5a23.39,23.39,0,0,1-5,14.49,23.45,23.45,0,0,0,9-18.49V551Z"
transform=
"translate(-114.28 -199)"
/></g></svg>
\ No newline at end of file
src/components/Application/src/AppLogo.vue
View file @
ec9478f7
...
@@ -10,8 +10,13 @@
...
@@ -10,8 +10,13 @@
>
>
<img
src=
"../../../assets/images/logo.png"
/>
<img
src=
"../../../assets/images/logo.png"
/>
<div
<div
class=
"ml-2 truncate xs:opacity-0 md:opacity-100"
class=
"ml-2 truncate md:opacity-100"
:class=
"`$
{prefixCls}__title`"
:class=
"[
`$
{prefixCls}__title`,
{
'xs:opacity-0': !alwaysShowTitle,
},
]"
v-show="showTitle"
v-show="showTitle"
>
>
{{
title
}}
{{
title
}}
...
@@ -38,6 +43,7 @@
...
@@ -38,6 +43,7 @@
theme
:
propTypes
.
oneOf
([
'
light
'
,
'
dark
'
]),
theme
:
propTypes
.
oneOf
([
'
light
'
,
'
dark
'
]),
// Whether to show title
// Whether to show title
showTitle
:
propTypes
.
bool
.
def
(
true
),
showTitle
:
propTypes
.
bool
.
def
(
true
),
alwaysShowTitle
:
propTypes
.
bool
.
def
(
false
),
},
},
setup
()
{
setup
()
{
const
{
prefixCls
}
=
useDesign
(
'
app-logo
'
);
const
{
prefixCls
}
=
useDesign
(
'
app-logo
'
);
...
...
src/components/CountDown/index.ts
0 → 100644
View file @
ec9478f7
import
CountButton
from
'
./src/CountButton.vue
'
;
import
CountdownInput
from
'
./src/CountdownInput.vue
'
;
export
{
CountdownInput
,
CountButton
};
src/components/CountDown/src/CountButton.vue
0 → 100644
View file @
ec9478f7
<
template
>
<Button
v-bind=
"$attrs"
:disabled=
"isStart"
@
click=
"handleStart"
:loading=
"loading"
>
{{
!
isStart
?
t
(
'
component.countdown.normalText
'
)
:
t
(
'
component.countdown.sendText
'
,
[
currentCount
])
}}
</Button>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
,
ref
,
PropType
}
from
'
vue
'
;
import
{
Button
}
from
'
ant-design-vue
'
;
import
{
useCountdown
}
from
'
./useCountdown
'
;
import
{
isFunction
}
from
'
/@/utils/is
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
export
default
defineComponent
({
name
:
'
CountButton
'
,
components
:
{
Button
},
props
:
{
count
:
{
type
:
Number
,
default
:
60
,
},
beforeStartFunc
:
{
type
:
Function
as
PropType
<
()
=>
boolean
>
,
default
:
null
,
},
},
setup
(
props
)
{
const
loading
=
ref
(
false
);
const
{
currentCount
,
isStart
,
start
}
=
useCountdown
(
props
.
count
);
const
{
t
}
=
useI18n
();
/**
* @description: Judge whether there is an external function before execution, and decide whether to start after execution
*/
async
function
handleStart
()
{
const
{
beforeStartFunc
}
=
props
;
if
(
beforeStartFunc
&&
isFunction
(
beforeStartFunc
))
{
loading
.
value
=
true
;
try
{
const
canStart
=
await
beforeStartFunc
();
canStart
&&
start
();
}
finally
{
loading
.
value
=
false
;
}
}
else
{
start
();
}
}
return
{
handleStart
,
isStart
,
currentCount
,
loading
,
t
};
},
});
</
script
>
src/components/CountDown/src/CountdownInput.vue
0 → 100644
View file @
ec9478f7
<
template
>
<div
:class=
"prefixCls"
>
<AInput
v-bind=
"$attrs"
:size=
"size"
v-model:value=
"state"
>
<template
#addonAfter
>
<CountButton
:size=
"size"
:count=
"count"
:beforeStartFunc=
"sendCodeApi"
/>
</
template
>
</AInput>
</div>
</template>
<
script
lang=
"ts"
>
import
{
defineComponent
,
PropType
}
from
'
vue
'
;
import
{
Input
}
from
'
ant-design-vue
'
;
import
CountButton
from
'
./CountButton.vue
'
;
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
import
{
useRuleFormItem
}
from
'
/@/hooks/component/useFormItem
'
;
export
default
defineComponent
({
name
:
'
CountDownInput
'
,
components
:
{
[
Input
.
name
]:
Input
,
CountButton
},
props
:
{
value
:
propTypes
.
string
,
size
:
propTypes
.
oneOf
([
'
default
'
,
'
large
'
,
'
small
'
]),
count
:
propTypes
.
number
.
def
(
60
),
sendCodeApi
:
{
type
:
Function
as
PropType
<
()
=>
boolean
>
,
default
:
null
,
},
},
setup
(
props
)
{
const
{
prefixCls
}
=
useDesign
(
'
countdown-input
'
);
const
[
state
]
=
useRuleFormItem
(
props
);
return
{
prefixCls
,
state
};
},
});
</
script
>
<
style
lang=
"less"
>
@prefix-cls: ~'@{namespace}-countdown-input';
.@{prefix-cls} {
.ant-input-group-addon {
padding-right: 0;
background-color: transparent;
border: none;
button {
font-size: 14px;
}
}
}
</
style
>
src/components/CountDown/src/useCountdown.ts
0 → 100644
View file @
ec9478f7
import
{
ref
,
unref
}
from
'
vue
'
;
import
{
tryOnUnmounted
}
from
'
/@/utils/helper/vueHelper
'
;
export
function
useCountdown
(
count
:
number
)
{
const
currentCount
=
ref
(
count
);
const
isStart
=
ref
(
false
);
let
timerId
:
ReturnType
<
typeof
setInterval
>
|
null
;
function
clear
()
{
timerId
&&
window
.
clearInterval
(
timerId
);
}
function
stop
()
{
isStart
.
value
=
false
;
timerId
=
null
;
clear
();
}
function
start
()
{
if
(
unref
(
isStart
)
||
!!
timerId
)
{
return
;
}
isStart
.
value
=
true
;
timerId
=
setInterval
(()
=>
{
if
(
unref
(
currentCount
)
===
1
)
{
stop
();
currentCount
.
value
=
count
;
}
else
{
currentCount
.
value
-=
1
;
}
},
1000
);
}
function
reset
()
{
currentCount
.
value
=
count
;
stop
();
}
function
restart
()
{
reset
();
start
();
}
tryOnUnmounted
(()
=>
{
reset
();
});
return
{
start
,
reset
,
restart
,
clear
,
stop
,
currentCount
,
isStart
};
}
src/components/StrengthMeter/src/index.vue
View file @
ec9478f7
<
template
>
<
template
>
<div
:class=
"prefixCls"
>
<div
:class=
"prefixCls"
class=
"relative"
>
<InputPassword
<InputPassword
v-if=
"showInput"
v-if=
"showInput"
v-bind=
"$attrs"
v-bind=
"$attrs"
...
@@ -24,15 +24,14 @@
...
@@ -24,15 +24,14 @@
import
{
Input
}
from
'
ant-design-vue
'
;
import
{
Input
}
from
'
ant-design-vue
'
;
import
zxcvbn
from
'
@zxcvbn-ts/core
'
;
import
zxcvbn
from
'
@zxcvbn-ts/core
'
;
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
export
default
defineComponent
({
export
default
defineComponent
({
name
:
'
StrengthMeter
'
,
name
:
'
StrengthMeter
'
,
components
:
{
InputPassword
:
Input
.
Password
},
components
:
{
InputPassword
:
Input
.
Password
},
props
:
{
props
:
{
value
:
propTypes
.
string
,
value
:
propTypes
.
string
,
showInput
:
propTypes
.
bool
.
def
(
true
),
showInput
:
propTypes
.
bool
.
def
(
true
),
disabled
:
propTypes
.
bool
,
disabled
:
propTypes
.
bool
,
},
},
...
@@ -43,9 +42,9 @@
...
@@ -43,9 +42,9 @@
const
getPasswordStrength
=
computed
(()
=>
{
const
getPasswordStrength
=
computed
(()
=>
{
const
{
disabled
}
=
props
;
const
{
disabled
}
=
props
;
if
(
disabled
)
return
null
;
if
(
disabled
)
return
-
1
;
const
innerValue
=
unref
(
innerValueRef
);
const
innerValue
=
unref
(
innerValueRef
);
const
score
=
innerValue
?
zxcvbn
(
unref
(
innerValueRef
)).
score
:
null
;
const
score
=
innerValue
?
zxcvbn
(
unref
(
innerValueRef
)).
score
:
-
1
;
emit
(
'
score-change
'
,
score
);
emit
(
'
score-change
'
,
score
);
return
score
;
return
score
;
});
});
...
@@ -57,6 +56,7 @@
...
@@ -57,6 +56,7 @@
watchEffect
(()
=>
{
watchEffect
(()
=>
{
innerValueRef
.
value
=
props
.
value
||
''
;
innerValueRef
.
value
=
props
.
value
||
''
;
});
});
watch
(
watch
(
()
=>
unref
(
innerValueRef
),
()
=>
unref
(
innerValueRef
),
(
val
)
=>
{
(
val
)
=>
{
...
@@ -77,14 +77,12 @@
...
@@ -77,14 +77,12 @@
@prefix-cls: ~'@{namespace}-strength-meter';
@prefix-cls: ~'@{namespace}-strength-meter';
.@{prefix-cls} {
.@{prefix-cls} {
position: relative;
&-bar {
&-bar {
position: relative;
position: relative;
height:
4
px;
height:
6
px;
margin: 10px auto 6px;
margin: 10px auto 6px;
background: @disabled-color;
background: @disabled-color;
border-radius:
3
px;
border-radius:
6
px;
&::before,
&::before,
&::after {
&::after {
...
...
src/design/ant/index.less
View file @
ec9478f7
...
@@ -13,10 +13,8 @@
...
@@ -13,10 +13,8 @@
}
}
}
}
body {
span.anticon:not(.app-iconify) {
.anticon:not(.app-iconify) {
vertical-align: 0.125em;
vertical-align: 0.1em;
}
}
}
.ant-back-top {
.ant-back-top {
...
...
src/design/var/breakpoint.less
View file @
ec9478f7
...
@@ -2,37 +2,17 @@
...
@@ -2,37 +2,17 @@
// ==============屏幕断点============
// ==============屏幕断点============
// =================================
// =================================
// Extra small screen / phone
@screen-xs: 480px;
@screen-xs-min: @screen-xs;
// Small screen / tablet
// Small screen / tablet
@screen-sm: 576px;
@screen-sm: 640px;
@screen-sm-min: @screen-sm;
// Medium screen / desktop
// Medium screen / desktop
@screen-md: 768px;
@screen-md: 768px;
@screen-md-min: @screen-md;
// Large screen / wide desktop
// Large screen / wide desktop
@screen-lg: 992px;
@screen-lg: 1024px;
@screen-lg-min: @screen-lg;
// Extra large screen / full hd
// Extra large screen / full hd
@screen-xl: 1200px;
@screen-xl: 1280px;
@screen-xl-min: @screen-xl;
// Extra extra large screen / large desktop
// Extra extra large screen / large desktop
@screen-xxl: 1600px;
@screen-2xl: 1536px;
@screen-xxl-min: @screen-xxl;
@screen-xxxl: 1900px;
@screen-xxxl-min: @screen-xxxl;
// provide a maximum
@screen-xs-max: (@screen-sm-min - 1px);
@screen-sm-max: (@screen-md-min - 1px);
@screen-md-max: (@screen-lg-min - 1px);
@screen-lg-max: (@screen-xl-min - 1px);
@screen-xl-max: (@screen-xxl-min - 1px);
@screen-xxl-max: (@screen-xxxl-min - 1px);
src/layouts/default/header/components/user-dropdown/index.vue
View file @
ec9478f7
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
<span
:class=
"[prefixCls, `$
{prefixCls}--${theme}`]">
<span
:class=
"[prefixCls, `$
{prefixCls}--${theme}`]">
<img
:class=
"`$
{prefixCls}__header`" :src="headerImg" />
<img
:class=
"`$
{prefixCls}__header`" :src="headerImg" />
<span
:class=
"`$
{prefixCls}__info`">
<span
:class=
"`$
{prefixCls}__info`">
<span
:class=
"`$
{prefixCls}__name
anticon`
">
{{
getUserInfo
.
realName
}}
</span>
<span
:class=
"`$
{prefixCls}__name
`" class="truncate
">
{{
getUserInfo
.
realName
}}
</span>
</span>
</span>
</span>
</span>
...
...
src/locales/lang/en/component/countdown.ts
0 → 100644
View file @
ec9478f7
export
default
{
normalText
:
'
Get SMS code
'
,
sendText
:
'
Reacquire in {0}s
'
,
};
src/locales/lang/en/sys/login.ts
View file @
ec9478f7
export
default
{
export
default
{
loginButton
:
'
Login
'
,
backSignIn
:
'
Back sign in
'
,
autoLogin
:
'
AutoLogin
'
,
mobileSignInFormTitle
:
'
Mobile sign in
'
,
forgetPassword
:
'
Forget Password
'
,
qrSignInFormTitle
:
'
Qr code sign in
'
,
signInFormTitle
:
'
Sign in
'
,
signUpFormTitle
:
'
Sign up
'
,
forgetFormTitle
:
'
Reset password
'
,
signInTitle
:
'
Backstage management system
'
,
signInDesc
:
'
Enter your personal details and get started!
'
,
policy
:
'
I agree to the xxx Privacy Policy
'
,
scanSign
:
`scanning the code to complete the login`
,
loginButton
:
'
Sign in
'
,
registerButton
:
'
Sign up
'
,
rememberMe
:
'
Remember me
'
,
forgetPassword
:
'
Forget Password?
'
,
otherSignIn
:
'
Sign in with
'
,
// notify
// notify
loginSuccessTitle
:
'
Login successful
'
,
loginSuccessTitle
:
'
Login successful
'
,
loginSuccessDesc
:
'
Welcome back
'
,
loginSuccessDesc
:
'
Welcome back
'
,
// placeholder
// placeholder
accountPlaceholder
:
'
Please input Username
'
,
accountPlaceholder
:
'
Please input username
'
,
passwordPlaceholder
:
'
Please input Password
'
,
passwordPlaceholder
:
'
Please input password
'
,
smsPlaceholder
:
'
Please input sms code
'
,
mobilePlaceholder
:
'
Please input mobile
'
,
policyPlaceholder
:
'
Register after checking
'
,
diffPwd
:
'
The two passwords are inconsistent
'
,
userName
:
'
Username
'
,
password
:
'
Password
'
,
confirmPassword
:
'
Confirm Password
'
,
email
:
'
Email
'
,
smsCode
:
'
SMS code
'
,
mobile
:
'
Mobile
'
,
};
};
src/locales/lang/zh_CN/component/countdown.ts
0 → 100644
View file @
ec9478f7
export
default
{
normalText
:
'
获取验证码
'
,
sendText
:
'
{0}秒后重新获取
'
,
};
src/locales/lang/zh_CN/sys/login.ts
View file @
ec9478f7
export
default
{
export
default
{
backSignIn
:
'
返回
'
,
signInFormTitle
:
'
登录
'
,
mobileSignInFormTitle
:
'
手机登录
'
,
qrSignInFormTitle
:
'
二维码登录
'
,
signUpFormTitle
:
'
注册
'
,
forgetFormTitle
:
'
重置密码
'
,
signInTitle
:
'
开箱即用的中后台管理系统
'
,
signInDesc
:
'
输入您的个人详细信息开始使用!
'
,
policy
:
'
我同意xxx隐私政策
'
,
scanSign
:
`扫码后点击"确认",即可完成登录`
,
loginButton
:
'
登录
'
,
loginButton
:
'
登录
'
,
autoLogin
:
'
自动登录
'
,
registerButton
:
'
注册
'
,
forgetPassword
:
'
忘记密码
'
,
rememberMe
:
'
记住我
'
,
forgetPassword
:
'
忘记密码?
'
,
otherSignIn
:
'
其他登录方式
'
,
// notify
// notify
loginSuccessTitle
:
'
登录成功
'
,
loginSuccessTitle
:
'
登录成功
'
,
...
@@ -10,4 +24,15 @@ export default {
...
@@ -10,4 +24,15 @@ export default {
// placeholder
// placeholder
accountPlaceholder
:
'
请输入账号
'
,
accountPlaceholder
:
'
请输入账号
'
,
passwordPlaceholder
:
'
请输入密码
'
,
passwordPlaceholder
:
'
请输入密码
'
,
smsPlaceholder
:
'
请输入验证码
'
,
mobilePlaceholder
:
'
请输入手机号码
'
,
policyPlaceholder
:
'
勾选后才能注册
'
,
diffPwd
:
'
两次输入密码不一致
'
,
userName
:
'
账号
'
,
password
:
'
密码
'
,
confirmPassword
:
'
确认密码
'
,
email
:
'
邮箱
'
,
smsCode
:
'
短信验证码
'
,
mobile
:
'
手机号码
'
,
};
};
src/views/sys/lock/LockPage.vue
View file @
ec9478f7
<
template
>
<
template
>
<div
:class=
"prefixCls"
>
<div
<div
:class=
"`$
{prefixCls}__unlock`" @click="handleShowForm(false)" v-show="showDate">
:class=
"prefixCls"
class=
"fixed inset-0 flex h-screen w-screen bg-black items-center justify-center"
>
<div
:class=
"`$
{prefixCls}__unlock`"
class="absolute top-0 left-1/2 flex pt-5 h-16 items-center justify-center sm:text-md xl:text-xl text-white flex-col cursor-pointer transform translate-x-1/2"
@click="handleShowForm(false)"
v-show="showDate"
>
<LockOutlined
/>
<LockOutlined
/>
<span>
{{
t
(
'
sys.lock.unlock
'
)
}}
</span>
<span>
{{
t
(
'
sys.lock.unlock
'
)
}}
</span>
</div>
</div>
<div
:class=
"`$
{prefixCls}__date`">
<div
class=
"flex w-screen h-screen justify-center items-center"
>
<div
:class=
"`$
{prefixCls}__hour`">
<div
:class=
"`$
{prefixCls}__hour`" class="relative mr-5 md:mr-20 w-2/5 h-2/5 md:h-4/5">
{{
hour
}}
<span>
{{
hour
}}
</span>
<span
class=
"meridiem"
v-show=
"showDate"
>
{{
meridiem
}}
</span>
<span
class=
"meridiem absolute left-5 top-5 text-md xl:text-xl"
v-show=
"showDate"
>
{{
meridiem
}}
</span>
</div>
</div>
<div
:class=
"`$
{prefixCls}__minute`">
<div
:class=
"`$
{prefixCls}__minute
w-2/5 h-2/5 md:h-4/5
`">
{{
minute
}}
<span>
{{
minute
}}
</span>
</div>
</div>
</div>
</div>
<transition
name=
"fade-slide"
>
<transition
name=
"fade-slide"
>
<div
:class=
"`$
{prefixCls}-entry`" v-show="!showDate">
<div
:class=
"`$
{prefixCls}-entry`" v-show="!showDate">
<div
:class=
"`$
{prefixCls}-entry-content`">
<div
:class=
"`$
{prefixCls}-entry-content`">
<div
:class=
"`$
{prefixCls}-entry__header`">
<div
:class=
"`$
{prefixCls}-entry__header
enter-x
`">
<img
:src=
"headerImg"
:class=
"`$
{prefixCls}-entry__header-img`" />
<img
:src=
"headerImg"
:class=
"`$
{prefixCls}-entry__header-img`" />
<p
:class=
"`$
{prefixCls}-entry__header-name`">
<p
:class=
"`$
{prefixCls}-entry__header-name`">
{{
realName
}}
{{
realName
}}
</p>
</p>
</div>
</div>
<InputPassword
:placeholder=
"t('sys.lock.placeholder')"
v-model:value=
"password"
/>
<InputPassword
<span
:class=
"`$
{prefixCls}-entry__err-msg`" v-if="errMsgRef">
:placeholder=
"t('sys.lock.placeholder')"
class=
"enter-x"
v-model:value=
"password"
/>
<span
:class=
"`$
{prefixCls}-entry__err-msg enter-x`" v-if="errMsgRef">
{{
t
(
'
sys.lock.alert
'
)
}}
{{
t
(
'
sys.lock.alert
'
)
}}
</span>
</span>
<div
:class=
"`$
{prefixCls}-entry__footer`">
<div
:class=
"`$
{prefixCls}-entry__footer
enter-x
`">
<a-button
<a-button
type=
"link"
type=
"link"
size=
"small"
size=
"small"
class=
"mt-2 mr-2"
class=
"mt-2 mr-2
enter-x
"
:disabled=
"loadingRef"
:disabled=
"loadingRef"
@
click=
"handleShowForm(true)"
@
click=
"handleShowForm(true)"
>
>
...
@@ -40,7 +54,7 @@
...
@@ -40,7 +54,7 @@
<a-button
<a-button
type=
"link"
type=
"link"
size=
"small"
size=
"small"
class=
"mt-2 mr-2"
class=
"mt-2 mr-2
enter-x
"
:disabled=
"loadingRef"
:disabled=
"loadingRef"
@
click=
"goLogin"
@
click=
"goLogin"
>
>
...
@@ -54,11 +68,11 @@
...
@@ -54,11 +68,11 @@
</div>
</div>
</transition>
</transition>
<div
:class=
"`$
{prefixCls}__footer-date`
">
<div
class=
"absolute bottom-5 w-full text-gray-300 xl:text-xl 2xl:text-3xl text-center enter-y
"
>
<div
class=
"t
ime
"
v-show=
"!showDate"
>
<div
class=
"t
ext-5xl mb-4 enter-x
"
v-show=
"!showDate"
>
{{
hour
}}
:
{{
minute
}}
<span
class=
"
meridiem
"
>
{{
meridiem
}}
</span>
{{
hour
}}
:
{{
minute
}}
<span
class=
"
text-3xl
"
>
{{
meridiem
}}
</span>
</div>
</div>
<div
class=
"
date
"
>
{{
year
}}
/
{{
month
}}
/
{{
day
}}
{{
week
}}
</div>
<div
class=
"
text-2xl
"
>
{{
year
}}
/
{{
month
}}
/
{{
day
}}
{{
week
}}
</div>
</div>
</div>
</div>
</div>
</
template
>
</
template
>
...
@@ -144,125 +158,54 @@
...
@@ -144,125 +158,54 @@
@prefix-cls: ~'@{namespace}-lock-page';
@prefix-cls: ~'@{namespace}-lock-page';
.@{prefix-cls} {
.@{prefix-cls} {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: @lock-page-z-index;
z-index: @lock-page-z-index;
display: flex;
width: 100vw;
height: 100vh;
// background: rgba(23, 27, 41);
background: #000;
align-items: center;
justify-content: center;
&__unlock {
&__unlock {
position: absolute;
top: 0;
left: 50%;
display: flex;
height: 50px;
padding-top: 20px;
font-size: 18px;
color: #fff;
cursor: pointer;
transform: translate(-50%, 0);
transform: translate(-50%, 0);
flex-direction: column;
align-items: center;
justify-content: space-between;
transition: all 0.3s;
}
&__date {
display: flex;
width: 100vw;
height: 100vh;
align-items: center;
justify-content: center;
}
&__hour {
position: relative;
margin-right: 80px;
.meridiem {
position: absolute;
top: 20px;
left: 20px;
font-size: 26px;
}
@media (max-width: @screen-xs) {
margin-right: 20px;
}
}
}
&__hour,
&__hour,
&__minute {
&__minute {
display: flex;
display: flex;
width: 40%;
height: 74%;
font-weight: 700;
font-weight: 700;
color: #bababa;
color: #bababa;
background: #141313;
background: #141313;
border-radius: 30px;
border-radius: 30px;
justify-content: center;
justify-content: center;
align-items: center;
align-items: center;
@media (min-width: @screen-xxxl-min) {
font-size: 46em;
}
@media (min-width: @screen-xl-max) and (max-width: @screen-xxl-max) {
font-size: 38em;
}
@media (min-width: @screen-lg-max) and (max-width: @screen-xl-max) {
@media screen and (max-width: @screen-md) {
font-size: 30em;
span:not(.meridiem) {
font-size: 160px;
}
}
@media (min-width: @screen-md-max) and (max-width: @screen-lg-max) {
font-size: 23em;
}
}
@media (min-width: @screen-sm-max) and (max-width: @screen-md-max) {
height: 50%;
font-size: 12em;
border-radius: 10px;
.meridiem
{
@media screen and (min-width: @screen-md)
{
font-size: 20px;
span:not(.meridiem) {
}
font-size: 160px;
}
}
@media (min-width: @screen-xs-max) and (max-width: @screen-sm-max) {
font-size: 13em;
}
}
@media (max-width: @screen-xs) {
height: 30%;
font-size: 5em;
border-radius: 10px;
.meridiem {
@media screen and (max-width: @screen-sm) {
font-size: 14px;
span:not(.meridiem) {
font-size: 90px;
}
}
}
}
@media screen and (min-width: @screen-lg) {
span:not(.meridiem) {
font-size: 220px;
}
}
}
&__footer-date {
@media screen and (min-width: @screen-xl) {
position: absolute;
span:not(.meridiem) {
bottom: 20px;
font-size: 260px;
width: 100%;
font-family: helvetica;
color: #bababa;
text-align: center;
.time {
font-size: 50px;
.meridiem {
font-size: 32px;
}
}
}
}
@media screen and (min-width: @screen-2xl) {
.date {
span:not(.meridiem) {
font-size: 26px;
font-size: 320px;
}
}
}
}
}
...
...
src/views/sys/login/ForgetPasswordForm.vue
0 → 100644
View file @
ec9478f7
<
template
>
<Form
class=
"p-4"
:model=
"formData"
:rules=
"getFormRules"
ref=
"formRef"
>
<FormItem
name=
"account"
class=
"enter-x"
>
<Input
size=
"large"
v-model:value=
"formData.account"
:placeholder=
"t('sys.login.userName')"
/>
</FormItem>
<FormItem
name=
"mobile"
class=
"enter-x"
>
<Input
size=
"large"
v-model:value=
"formData.mobile"
:placeholder=
"t('sys.login.mobile')"
/>
</FormItem>
<FormItem
name=
"sms"
class=
"enter-x"
>
<CountdownInput
size=
"large"
v-model:value=
"formData.sms"
:placeholder=
"t('sys.login.smsCode')"
/>
</FormItem>
<FormItem
class=
"enter-x"
>
<Button
type=
"primary"
size=
"large"
block
@
click=
"handleReset"
:loading=
"loading"
class=
"enter-x"
>
{{
t
(
'
common.resetText
'
)
}}
</Button>
<Button
size=
"large"
block
class=
"mt-4 enter-x"
@
click=
"handleBackLogin"
>
{{
t
(
'
sys.login.backSignIn
'
)
}}
</Button>
</FormItem>
</Form>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
,
reactive
,
ref
}
from
'
vue
'
;
import
{
Form
,
Input
,
Button
}
from
'
ant-design-vue
'
;
import
{
CountdownInput
}
from
'
/@/components/CountDown
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
LoginStateEnum
,
useLoginState
,
useFormRules
,
useFormValid
}
from
'
./useLogin
'
;
export
default
defineComponent
({
name
:
'
ForgetPasswordForm
'
,
components
:
{
Button
,
Form
,
FormItem
:
Form
.
Item
,
Input
,
CountdownInput
,
},
setup
()
{
const
{
t
}
=
useI18n
();
const
{
setLoginState
}
=
useLoginState
();
const
{
getFormRules
}
=
useFormRules
();
const
formRef
=
ref
<
any
>
(
null
);
const
loading
=
ref
(
false
);
const
formData
=
reactive
({
account
:
''
,
mobile
:
''
,
sms
:
''
,
});
const
{
validForm
}
=
useFormValid
(
formRef
);
async
function
handleReset
()
{
const
data
=
await
validForm
();
if
(
!
data
)
return
;
console
.
log
(
data
);
}
function
handleBackLogin
()
{
setLoginState
(
LoginStateEnum
.
LOGIN
);
}
return
{
t
,
formRef
,
formData
,
getFormRules
,
handleReset
,
loading
,
handleBackLogin
,
};
},
});
</
script
>
src/views/sys/login/Login.vue
View file @
ec9478f7
<
template
>
<
template
>
<div
class=
"login"
>
<div
:class=
"prefixCls"
class=
"relative w-full h-full px-4"
>
<div
class=
"opacity-0 login-mask lg:opacity-100"
></div>
<AppLocalePicker
<div
class=
"justify-center login-form-wrap lg:justify-end"
>
class=
"absolute top-4 right-4 enter-x text-white xl:text-gray-600"
<div
class=
"mx-6 login-form"
>
:showText=
"false"
<AppLocalePicker
v-if=
"showLocale"
class=
"login-form__locale"
/>
<div
class=
"px-2 py-10 login-form__content"
>
<header>
<img
:src=
"logo"
class=
"mr-4"
/>
<h1>
{{
title
}}
</h1>
</header>
<a-form
class=
"login-form__main"
:model=
"formData"
:rules=
"formRules"
ref=
"formRef"
>
<a-form-item
name=
"account"
>
<a-input
size=
"large"
v-model:value=
"formData.account"
placeholder=
"username: vben"
/>
</a-form-item>
<a-form-item
name=
"password"
>
<a-input-password
size=
"large"
visibilityToggle
v-model:value=
"formData.password"
placeholder=
"password: 123456"
/>
/>
</a-form-item>
<span
class=
"-enter-x xl:hidden"
>
<a-row>
<AppLogo
:alwaysShowTitle=
"true"
/>
<a-col
:span=
"12"
>
</span>
<a-form-item>
<!-- No logic, you need to deal with it yourself -->
<div
class=
"container relative h-full py-2 mx-auto sm:px-10"
>
<a-checkbox
v-model:checked=
"autoLogin"
size=
"small"
>
{{
<div
class=
"flex h-full"
>
t
(
'
sys.login.autoLogin
'
)
<div
class=
"hidden xl:flex xl:flex-col xl:w-6/12 min-h-full mr-4 pl-4"
>
}}
</a-checkbox>
<AppLogo
class=
"-enter-x"
/>
</a-form-item>
<div
class=
"my-auto"
>
</a-col>
<img
<a-col
:span=
"12"
>
:alt=
"title"
<a-form-item
:style=
"
{ 'text-align': 'right' }">
src=
"../../../assets/svg/login-box-bg.svg"
<!-- No logic, you need to deal with it yourself -->
class=
"w-1/2 -mt-16 -enter-x"
<a-button
type=
"link"
size=
"small"
>
/>
{{
t
(
'
sys.login.forgetPassword
'
)
}}
<div
class=
"mt-10 font-medium text-white -enter-x"
>
</a-button>
<span
class=
"mt-4 text-3xl inline-block"
>
{{
t
(
'
sys.login.signInTitle
'
)
}}
</span>
</a-form-item>
</div>
</a-col>
<div
class=
"mt-5 text-md text-white font-normal dark:text-gray-500 -enter-x"
>
</a-row>
{{
t
(
'
sys.login.signInDesc
'
)
}}
<a-form-item>
</div>
<a-button
</div>
type=
"primary"
</div>
size=
"large"
<div
class=
"h-full xl:h-auto flex py-5 xl:py-0 xl:my-0 w-full xl:w-6/12"
>
class=
"rounded-sm"
<div
:block=
"true"
class=
"my-auto mx-auto xl:ml-20 bg-white xl:bg-transparent px-5 py-8 sm:px-8 xl:p-0 rounded-md shadow-md xl:shadow-none w-full sm:w-3/4 lg:w-2/4 xl:w-auto enter-x relative"
@
click=
"login"
:loading=
"formState.loading"
>
>
{{
t
(
'
sys.login.loginButton
'
)
}}
<h2
class=
"font-bold text-2xl xl:text-3xl enter-x text-center xl:text-left mb-6"
>
</a-button>
{{
getFormTitle
}}
</a-form-item>
</h2>
</a-form>
<LoginForm
v-show=
"getShowLogin"
/>
<ForgetPasswordForm
v-if=
"getShowResetPassword"
/>
<RegisterForm
v-if=
"getShowRegister"
/>
<MobileForm
v-if=
"getShowMobile"
/>
<QrCodeForm
v-if=
"getShowQrCode"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</
template
>
</
template
>
<
script
lang=
"ts"
>
<
script
lang=
"ts"
>
import
{
defineComponent
,
reactive
,
ref
,
unref
,
toRaw
}
from
'
vue
'
;
import
{
defineComponent
,
computed
}
from
'
vue
'
;
import
{
Checkbox
,
Form
,
Input
,
Row
,
Col
}
from
'
ant-design-vue
'
;
import
{
Button
}
from
'
/@/components/Butt
on
'
;
import
{
AppLogo
}
from
'
/@/components/Applicati
on
'
;
import
{
AppLocalePicker
}
from
'
/@/components/Application
'
;
import
{
AppLocalePicker
}
from
'
/@/components/Application
'
;
import
LoginForm
from
'
./LoginForm.vue
'
;
import
ForgetPasswordForm
from
'
./ForgetPasswordForm.vue
'
;
import
RegisterForm
from
'
./RegisterForm.vue
'
;
import
MobileForm
from
'
./MobileForm.vue
'
;
import
QrCodeForm
from
'
./QrCodeForm.vue
'
;
import
{
userStore
}
from
'
/@/store/modules/user
'
;
import
{
useMessage
}
from
'
/@/hooks/web/useMessage
'
;
import
{
useGlobSetting
,
useProjectSetting
}
from
'
/@/hooks/setting
'
;
import
{
useGlobSetting
,
useProjectSetting
}
from
'
/@/hooks/setting
'
;
import
logo
from
'
/@/assets/images/logo.png
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
import
{
useShowLoginForm
,
useFormTitle
}
from
'
./useLogin
'
;
export
default
defineComponent
({
export
default
defineComponent
({
name
:
'
Login
'
,
components
:
{
components
:
{
[
Checkbox
.
name
]:
Checkbox
,
AppLogo
,
[
Form
.
name
]:
Form
,
Login
Form
,
[
Form
.
Item
.
name
]:
Form
.
Ite
m
,
ForgetPasswordFor
m
,
[
Input
.
name
]:
Input
,
RegisterForm
,
[
Input
.
Password
.
name
]:
Input
.
Password
,
MobileForm
,
AButton
:
Button
,
QrCodeForm
,
AppLocalePicker
,
AppLocalePicker
,
[
Row
.
name
]:
Row
,
[
Col
.
name
]:
Col
,
},
},
setup
()
{
setup
()
{
const
formRef
=
ref
<
any
>
(
null
);
const
autoLoginRef
=
ref
(
false
);
const
globSetting
=
useGlobSetting
();
const
globSetting
=
useGlobSetting
();
const
{
getFormTitle
}
=
useFormTitle
();
const
{
prefixCls
}
=
useDesign
(
'
login
'
);
const
{
locale
}
=
useProjectSetting
();
const
{
locale
}
=
useProjectSetting
();
const
{
notification
}
=
useMessage
();
const
{
t
}
=
useI18n
();
const
{
t
}
=
useI18n
();
const
formData
=
reactive
({
account
:
'
vben
'
,
password
:
'
123456
'
,
});
const
formState
=
reactive
({
loading
:
false
,
});
const
formRules
=
reactive
({
account
:
[{
required
:
true
,
message
:
t
(
'
sys.login.accountPlaceholder
'
),
trigger
:
'
blur
'
}],
password
:
[
{
required
:
true
,
message
:
t
(
'
sys.login.passwordPlaceholder
'
),
trigger
:
'
blur
'
},
],
});
async
function
handleLogin
()
{
const
form
=
unref
(
formRef
);
if
(
!
form
)
return
;
formState
.
loading
=
true
;
try
{
const
data
=
await
form
.
validate
();
const
userInfo
=
await
userStore
.
login
(
toRaw
({
password
:
data
.
password
,
username
:
data
.
account
,
})
);
if
(
userInfo
)
{
notification
.
success
({
message
:
t
(
'
sys.login.loginSuccessTitle
'
),
description
:
`
${
t
(
'
sys.login.loginSuccessDesc
'
)}
:
${
userInfo
.
realName
}
`
,
duration
:
3
,
});
}
}
catch
(
error
)
{
}
finally
{
formState
.
loading
=
false
;
}
}
return
{
return
{
formRef
,
formData
,
formState
,
formRules
,
login
:
handleLogin
,
autoLogin
:
autoLoginRef
,
title
:
globSetting
&&
globSetting
.
title
,
logo
,
t
,
t
,
showLocale
:
locale
.
show
,
prefixCls
,
title
:
computed
(()
=>
globSetting
?.
title
??
''
),
showLocale
:
computed
(()
=>
locale
.
show
),
getFormTitle
,
...
useShowLoginForm
(),
};
};
},
},
});
});
</
script
>
</
script
>
<
style
lang=
"less"
>
<
style
lang=
"less"
>
.login-form__locale {
@prefix-cls: ~'@{namespace}-login';
position: absolute;
@logo-prefix-cls: ~'@{namespace}-app-logo';
top: 14px;
@countdown-prefix-cls: ~'@{namespace}-countdown-input';
right: 14px;
z-index: 1;
}
.login {
.@{prefix-cls} {
position: relative;
@media (max-width: @screen-xl) {
height: 100vh;
background: linear-gradient(180deg, #1c3faa, #1c3faa);
background: url(../../../assets/images/login/login-bg.png) no-repeat;
background-size: 100% 100%;
&-mask {
height: 100%;
background: url(../../../assets/images/login/login-in.png) no-repeat;
background-position: 30% 30%;
background-size: 80% 80%;
}
}
&-form {
&::before {
position: relative;
bottom: 60px;
width: 400px;
background: @white;
border: 10px solid rgba(255, 255, 255, 0.5);
border-width: 8px;
border-radius: 4px;
background-clip: padding-box;
&__main {
margin: 30px auto 0 auto !important;
}
&-wrap {
position: absolute;
position: absolute;
top: 0;
top: 0;
right: 0;
left: 0;
display: flex;
width: 100%;
width: 100%;
height: 100%;
height: 100%;
align-items: center;
margin-left: -48%;
background-image: url(/@/assets/svg/login-bg.svg);
background-position: 100%;
background-repeat: no-repeat;
background-size: auto 100%;
content: '';
@media (max-width: @screen-xl) {
display: none;
}
}
}
&__content {
.@{logo-prefix-cls} {
position: relative;
position: absolute;
width: 100%;
top: 12px;
height: 100%;
height: 30px;
padding: 60px 0 40px 0;
border: 1px solid #999;
&__title {
border-radius: 2px;
font-size: 16px;
color: #fff;
}
header {
img {
width: 32px;
}
}
.container {
.@{logo-prefix-cls} {
display: flex;
display: flex;
justify-content: center;
width: 60%;
align-items: center;
height: 80px;
&__title {
font-size: 24px;
color: #fff;
}
img {
img {
display: inline-block;
width: 48px;
width: 48px;
}
}
}
}
h1 {
&-sign-in-way {
margin-bottom: 0;
.anticon {
font-size: 24px;
font-size: 22px;
text-align: center;
color: #888;
cursor: pointer;
&:hover {
color: @primary-color;
}
}
}
}
}
form {
input:not([type='checkbox']) {
width: 80%;
min-width: 360px;
@media (max-width: @screen-sm) {
min-width: 240px;
}
}
}
}
.@{countdown-prefix-cls} input {
min-width: unset;
}
.ant-divider-inner-text {
font-size: 12px;
color: @text-color-secondary;
}
}
}
}
</
style
>
</
style
>
src/views/sys/login/LoginForm.vue
0 → 100644
View file @
ec9478f7
<
template
>
<Form
class=
"p-4"
:model=
"formData"
:rules=
"getFormRules"
ref=
"formRef"
>
<FormItem
name=
"account"
class=
"enter-x"
>
<Input
size=
"large"
v-model:value=
"formData.account"
:placeholder=
"t('sys.login.userName')"
/>
</FormItem>
<FormItem
name=
"password"
class=
"enter-x"
>
<InputPassword
size=
"large"
visibilityToggle
v-model:value=
"formData.password"
:placeholder=
"t('sys.login.password')"
/>
</FormItem>
<ARow
class=
"enter-x"
>
<ACol
:span=
"12"
>
<FormItem>
<!-- No logic, you need to deal with it yourself -->
<Checkbox
v-model:checked=
"rememberMe"
size=
"small"
>
{{
t
(
'
sys.login.rememberMe
'
)
}}
</Checkbox>
</FormItem>
</ACol>
<ACol
:span=
"12"
>
<FormItem
:style=
"
{ 'text-align': 'right' }">
<!-- No logic, you need to deal with it yourself -->
<Button
type=
"link"
size=
"small"
@
click=
"setLoginState(LoginStateEnum.RESET_PASSWORD)"
>
{{
t
(
'
sys.login.forgetPassword
'
)
}}
</Button>
</FormItem>
</ACol>
</ARow>
<FormItem
class=
"enter-x"
>
<Button
type=
"primary"
size=
"large"
block
@
click=
"handleLogin"
:loading=
"loading"
class=
"enter-x"
>
{{
t
(
'
sys.login.loginButton
'
)
}}
</Button>
<!--
<Button
size=
"large"
class=
"mt-4 enter-x"
block
@
click=
"handleRegister"
>
{{
t
(
'
sys.login.registerButton
'
)
}}
</Button>
-->
</FormItem>
<ARow
class=
"enter-x"
>
<ACol
:span=
"7"
>
<Button
block
@
click=
"setLoginState(LoginStateEnum.MOBILE)"
>
{{
t
(
'
sys.login.mobileSignInFormTitle
'
)
}}
</Button>
</ACol>
<ACol
:span=
"8"
:offset=
"1"
>
<Button
block
@
click=
"setLoginState(LoginStateEnum.QR_CODE)"
>
{{
t
(
'
sys.login.qrSignInFormTitle
'
)
}}
</Button>
</ACol>
<ACol
:span=
"7"
:offset=
"1"
>
<Button
block
@
click=
"setLoginState(LoginStateEnum.REGISTER)"
>
{{
t
(
'
sys.login.registerButton
'
)
}}
</Button>
</ACol>
</ARow>
<Divider>
{{
t
(
'
sys.login.otherSignIn
'
)
}}
</Divider>
<div
class=
"flex justify-evenly enter-x"
:class=
"`$
{prefixCls}-sign-in-way`">
<GithubFilled
/>
<WechatFilled
/>
<AlipayCircleFilled
/>
<GoogleCircleFilled
/>
<TwitterCircleFilled
/>
</div>
</Form>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
,
reactive
,
ref
,
toRaw
}
from
'
vue
'
;
import
{
Checkbox
,
Form
,
Input
,
Row
,
Col
,
Button
,
Divider
}
from
'
ant-design-vue
'
;
import
{
GithubFilled
,
WechatFilled
,
AlipayCircleFilled
,
GoogleCircleFilled
,
TwitterCircleFilled
,
}
from
'
@ant-design/icons-vue
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
useMessage
}
from
'
/@/hooks/web/useMessage
'
;
import
{
userStore
}
from
'
/@/store/modules/user
'
;
import
{
LoginStateEnum
,
useLoginState
,
useFormRules
,
useFormValid
}
from
'
./useLogin
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
export
default
defineComponent
({
name
:
'
LoginForm
'
,
components
:
{
Checkbox
,
Button
,
Form
,
FormItem
:
Form
.
Item
,
Input
,
Divider
,
InputPassword
:
Input
.
Password
,
[
Col
.
name
]:
Col
,
[
Row
.
name
]:
Row
,
GithubFilled
,
WechatFilled
,
AlipayCircleFilled
,
GoogleCircleFilled
,
TwitterCircleFilled
,
},
setup
()
{
const
{
t
}
=
useI18n
();
const
{
notification
}
=
useMessage
();
const
{
prefixCls
}
=
useDesign
(
'
login
'
);
const
{
setLoginState
}
=
useLoginState
();
const
{
getFormRules
}
=
useFormRules
();
const
formRef
=
ref
<
any
>
(
null
);
const
loading
=
ref
(
false
);
const
rememberMe
=
ref
(
false
);
const
formData
=
reactive
({
account
:
'
vben
'
,
password
:
'
123456
'
,
});
const
{
validForm
}
=
useFormValid
(
formRef
);
async
function
handleLogin
()
{
const
data
=
await
validForm
();
if
(
!
data
)
return
;
try
{
loading
.
value
=
true
;
const
userInfo
=
await
userStore
.
login
(
toRaw
({
password
:
data
.
password
,
username
:
data
.
account
,
})
);
if
(
userInfo
)
{
notification
.
success
({
message
:
t
(
'
sys.login.loginSuccessTitle
'
),
description
:
`
${
t
(
'
sys.login.loginSuccessDesc
'
)}
:
${
userInfo
.
realName
}
`
,
duration
:
3
,
});
}
}
finally
{
loading
.
value
=
false
;
}
}
return
{
t
,
prefixCls
,
formRef
,
formData
,
getFormRules
,
rememberMe
,
handleLogin
,
loading
,
setLoginState
,
LoginStateEnum
,
};
},
});
</
script
>
src/views/sys/login/MobileForm.vue
0 → 100644
View file @
ec9478f7
<
template
>
<Form
class=
"p-4"
:model=
"formData"
:rules=
"getFormRules"
ref=
"formRef"
>
<FormItem
name=
"mobile"
class=
"enter-x"
>
<Input
size=
"large"
v-model:value=
"formData.mobile"
:placeholder=
"t('sys.login.mobile')"
/>
</FormItem>
<FormItem
name=
"sms"
class=
"enter-x"
>
<CountdownInput
size=
"large"
v-model:value=
"formData.sms"
:placeholder=
"t('sys.login.smsCode')"
/>
</FormItem>
<FormItem
class=
"enter-x"
>
<Button
type=
"primary"
size=
"large"
block
@
click=
"handleLogin"
:loading=
"loading"
class=
"enter-x"
>
{{
t
(
'
sys.login.loginButton
'
)
}}
</Button>
<Button
size=
"large"
block
class=
"mt-4 enter-x"
@
click=
"handleBackLogin"
>
{{
t
(
'
sys.login.backSignIn
'
)
}}
</Button>
</FormItem>
</Form>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
,
reactive
,
ref
}
from
'
vue
'
;
import
{
Form
,
Input
,
Button
}
from
'
ant-design-vue
'
;
import
{
CountdownInput
}
from
'
/@/components/CountDown
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
LoginStateEnum
,
useLoginState
,
useFormRules
,
useFormValid
}
from
'
./useLogin
'
;
export
default
defineComponent
({
name
:
'
MobileForm
'
,
components
:
{
Button
,
Form
,
FormItem
:
Form
.
Item
,
Input
,
CountdownInput
,
},
setup
()
{
const
{
t
}
=
useI18n
();
const
{
setLoginState
}
=
useLoginState
();
const
{
getFormRules
}
=
useFormRules
();
const
formRef
=
ref
<
any
>
(
null
);
const
loading
=
ref
(
false
);
const
formData
=
reactive
({
mobile
:
''
,
sms
:
''
,
});
const
{
validForm
}
=
useFormValid
(
formRef
);
async
function
handleLogin
()
{
const
data
=
await
validForm
();
if
(
!
data
)
return
;
console
.
log
(
data
);
}
function
handleBackLogin
()
{
setLoginState
(
LoginStateEnum
.
LOGIN
);
}
return
{
t
,
formRef
,
formData
,
getFormRules
,
handleLogin
,
loading
,
handleBackLogin
,
};
},
});
</
script
>
src/views/sys/login/QrCodeForm.vue
0 → 100644
View file @
ec9478f7
<
template
>
<div
class=
"enter-x min-w-64 min-h-64"
>
<QrCode
:value=
"qrCodeUrl"
class=
"enter-x flex justify-center xl:justify-start"
:width=
"280"
/>
<Divider>
{{
t
(
'
sys.login.scanSign
'
)
}}
</Divider>
<Button
size=
"large"
block
class=
"mt-4 enter-x"
@
click=
"handleBackLogin"
>
{{
t
(
'
sys.login.backSignIn
'
)
}}
</Button>
</div>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'
vue
'
;
import
{
Button
,
Divider
}
from
'
ant-design-vue
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
LoginStateEnum
,
useLoginState
}
from
'
./useLogin
'
;
import
{
QrCode
}
from
'
/@/components/Qrcode/index
'
;
const
qrCodeUrl
=
'
https://vvbin.cn/next/login
'
;
export
default
defineComponent
({
name
:
'
QrCodeForm
'
,
components
:
{
Button
,
QrCode
,
Divider
,
},
setup
()
{
const
{
t
}
=
useI18n
();
const
{
setLoginState
}
=
useLoginState
();
function
handleBackLogin
()
{
setLoginState
(
LoginStateEnum
.
LOGIN
);
}
return
{
t
,
handleBackLogin
,
qrCodeUrl
,
};
},
});
</
script
>
src/views/sys/login/RegisterForm.vue
0 → 100644
View file @
ec9478f7
<
template
>
<Form
class=
"p-4"
:model=
"formData"
:rules=
"getFormRules"
ref=
"formRef"
>
<FormItem
name=
"account"
class=
"enter-x"
>
<Input
size=
"large"
v-model:value=
"formData.account"
:placeholder=
"t('sys.login.userName')"
/>
</FormItem>
<FormItem
name=
"mobile"
class=
"enter-x"
>
<Input
size=
"large"
v-model:value=
"formData.mobile"
:placeholder=
"t('sys.login.mobile')"
/>
</FormItem>
<FormItem
name=
"sms"
class=
"enter-x"
>
<CountdownInput
size=
"large"
v-model:value=
"formData.sms"
:placeholder=
"t('sys.login.smsCode')"
/>
</FormItem>
<FormItem
name=
"password"
class=
"enter-x"
>
<StrengthMeter
size=
"large"
v-model:value=
"formData.password"
:placeholder=
"t('sys.login.password')"
/>
</FormItem>
<FormItem
name=
"confirmPassword"
class=
"enter-x"
>
<InputPassword
size=
"large"
visibilityToggle
v-model:value=
"formData.confirmPassword"
:placeholder=
"t('sys.login.confirmPassword')"
/>
</FormItem>
<FormItem
class=
"enter-x"
name=
"policy"
>
<!-- No logic, you need to deal with it yourself -->
<Checkbox
v-model:checked=
"formData.policy"
size=
"small"
>
{{
t
(
'
sys.login.policy
'
)
}}
</Checkbox>
</FormItem>
<Button
type=
"primary"
size=
"large"
block
@
click=
"handleReset"
:loading=
"loading"
class=
"enter-x"
>
{{
t
(
'
sys.login.registerButton
'
)
}}
</Button>
<Button
size=
"large"
block
class=
"mt-4 enter-x"
@
click=
"handleBackLogin"
>
{{
t
(
'
sys.login.backSignIn
'
)
}}
</Button>
</Form>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
,
reactive
,
ref
}
from
'
vue
'
;
import
{
Form
,
Input
,
Button
,
Divider
,
Checkbox
}
from
'
ant-design-vue
'
;
import
{
StrengthMeter
}
from
'
/@/components/StrengthMeter
'
;
import
{
CountdownInput
}
from
'
/@/components/CountDown
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
LoginStateEnum
,
useLoginState
,
useFormRules
,
useFormValid
}
from
'
./useLogin
'
;
export
default
defineComponent
({
name
:
'
RegisterPasswordForm
'
,
components
:
{
Button
,
Form
,
FormItem
:
Form
.
Item
,
Input
,
Divider
,
InputPassword
:
Input
.
Password
,
Checkbox
,
StrengthMeter
,
CountdownInput
,
},
setup
()
{
const
{
t
}
=
useI18n
();
const
{
setLoginState
}
=
useLoginState
();
const
formRef
=
ref
<
any
>
(
null
);
const
loading
=
ref
(
false
);
const
formData
=
reactive
({
account
:
''
,
password
:
''
,
confirmPassword
:
''
,
mobile
:
''
,
sms
:
''
,
policy
:
false
,
});
const
{
getFormRules
}
=
useFormRules
(
formData
);
const
{
validForm
}
=
useFormValid
(
formRef
);
async
function
handleReset
()
{
const
data
=
await
validForm
();
if
(
!
data
)
return
;
console
.
log
(
data
);
}
function
handleBackLogin
()
{
setLoginState
(
LoginStateEnum
.
LOGIN
);
}
return
{
t
,
formRef
,
formData
,
getFormRules
,
handleReset
,
loading
,
handleBackLogin
,
};
},
});
</
script
>
src/views/sys/login/useLogin.ts
0 → 100644
View file @
ec9478f7
import
{
RuleObject
}
from
'
ant-design-vue/lib/form/interface
'
;
import
{
ref
,
computed
,
unref
,
Ref
}
from
'
vue
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
export
enum
LoginStateEnum
{
LOGIN
,
REGISTER
,
RESET_PASSWORD
,
MOBILE
,
QR_CODE
,
}
const
currentState
=
ref
(
LoginStateEnum
.
LOGIN
);
export
function
useFormTitle
()
{
const
{
t
}
=
useI18n
();
const
getFormTitle
=
computed
(()
=>
{
const
titleObj
=
{
[
LoginStateEnum
.
RESET_PASSWORD
]:
t
(
'
sys.login.forgetFormTitle
'
),
[
LoginStateEnum
.
LOGIN
]:
t
(
'
sys.login.signInFormTitle
'
),
[
LoginStateEnum
.
REGISTER
]:
t
(
'
sys.login.signUpFormTitle
'
),
[
LoginStateEnum
.
MOBILE
]:
t
(
'
sys.login.mobileSignInFormTitle
'
),
[
LoginStateEnum
.
QR_CODE
]:
t
(
'
sys.login.qrSignInFormTitle
'
),
};
return
titleObj
[
unref
(
currentState
)];
});
return
{
getFormTitle
};
}
export
function
useLoginState
()
{
function
setLoginState
(
state
:
LoginStateEnum
)
{
currentState
.
value
=
state
;
}
const
getLoginState
=
computed
(()
=>
currentState
.
value
);
return
{
setLoginState
,
getLoginState
};
}
export
function
useShowLoginForm
()
{
const
getShowLogin
=
computed
(()
=>
unref
(
currentState
)
===
LoginStateEnum
.
LOGIN
);
const
getShowResetPassword
=
computed
(
()
=>
unref
(
currentState
)
===
LoginStateEnum
.
RESET_PASSWORD
);
const
getShowRegister
=
computed
(()
=>
unref
(
currentState
)
===
LoginStateEnum
.
REGISTER
);
const
getShowMobile
=
computed
(()
=>
unref
(
currentState
)
===
LoginStateEnum
.
MOBILE
);
const
getShowQrCode
=
computed
(()
=>
unref
(
currentState
)
===
LoginStateEnum
.
QR_CODE
);
return
{
getShowLogin
,
getShowResetPassword
,
getShowRegister
,
getShowMobile
,
getShowQrCode
};
}
export
function
useFormValid
<
T
extends
Object
=
any
>
(
formRef
:
Ref
<
any
>
)
{
async
function
validForm
()
{
const
form
=
unref
(
formRef
);
if
(
!
form
)
return
;
const
data
=
await
form
.
validate
();
return
data
as
T
;
}
return
{
validForm
};
}
export
function
useFormRules
(
formData
?:
Recordable
)
{
const
{
t
}
=
useI18n
();
const
getAccountFormRule
=
computed
(()
=>
createRule
(
t
(
'
sys.login.accountPlaceholder
'
)));
const
getPasswordFormRule
=
computed
(()
=>
createRule
(
t
(
'
sys.login.passwordPlaceholder
'
)));
const
getSmsFormRule
=
computed
(()
=>
createRule
(
t
(
'
sys.login.smsPlaceholder
'
)));
const
getMobileFormRule
=
computed
(()
=>
createRule
(
t
(
'
sys.login.mobilePlaceholder
'
)));
const
validatePolicy
=
async
(
_
:
RuleObject
,
value
:
boolean
)
=>
{
return
!
value
?
Promise
.
reject
(
t
(
'
sys.login.policyPlaceholder
'
))
:
Promise
.
resolve
();
};
const
validateConfirmPassword
=
(
password
:
string
)
=>
{
return
async
(
_
:
RuleObject
,
value
:
string
)
=>
{
if
(
!
value
)
{
return
Promise
.
reject
(
t
(
'
sys.login.passwordPlaceholder
'
));
}
if
(
value
!==
password
)
{
return
Promise
.
reject
(
t
(
'
sys.login.diffPwd
'
));
}
return
Promise
.
resolve
();
};
};
const
getFormRules
=
computed
(()
=>
{
const
accountFormRule
=
unref
(
getAccountFormRule
);
const
passwordFormRule
=
unref
(
getPasswordFormRule
);
const
smsFormRule
=
unref
(
getSmsFormRule
);
const
mobileFormRule
=
unref
(
getMobileFormRule
);
const
mobileRule
=
{
sms
:
smsFormRule
,
mobile
:
mobileFormRule
,
};
switch
(
unref
(
currentState
))
{
case
LoginStateEnum
.
REGISTER
:
return
{
account
:
accountFormRule
,
password
:
passwordFormRule
,
confirmPassword
:
[
{
validator
:
validateConfirmPassword
(
formData
?.
password
),
trigger
:
'
change
'
},
],
policy
:
[{
validator
:
validatePolicy
,
trigger
:
'
change
'
}],
...
mobileRule
,
};
case
LoginStateEnum
.
RESET_PASSWORD
:
return
{
account
:
accountFormRule
,
...
mobileRule
,
};
case
LoginStateEnum
.
MOBILE
:
return
mobileRule
;
default
:
return
{
account
:
accountFormRule
,
password
:
passwordFormRule
,
};
}
});
return
{
getFormRules
};
}
function
createRule
(
message
:
string
)
{
return
[
{
required
:
true
,
message
,
trigger
:
'
change
'
,
},
];
}
tailwind.config.js
deleted
100644 → 0
View file @
e3851dc5
/* eslint-disable @typescript-eslint/no-var-requires */
const
colors
=
require
(
'
windicss/colors
'
);
const
defaultTheme
=
require
(
'
windicss/defaultTheme
'
);
module
.
exports
=
{
darkMode
:
'
class
'
,
plugins
:
[
require
(
'
windicss/plugin/forms
'
),
require
(
'
windicss/plugin/typography
'
),
require
(
'
windicss/plugin/line-clamp
'
),
require
(
'
windicss/plugin/aspect-ratio
'
),
],
theme
:
{
extend
:
{
colors
,
fontFamily
:
{
sans
:
[
'
Righteous
'
,
...
defaultTheme
.
fontFamily
.
sans
],
},
},
},
};
windi.config.ts
0 → 100644
View file @
ec9478f7
import
lineClamp
from
'
windicss/plugin/line-clamp
'
;
import
colors
from
'
windicss/colors
'
;
import
{
defineConfig
}
from
'
vite-plugin-windicss
'
;
export
default
defineConfig
({
darkMode
:
'
class
'
,
plugins
:
[
lineClamp
,
createEnterPlugin
()],
theme
:
{
extend
:
{
colors
,
},
// screen: {
// sm: '576px',
// md: '768px',
// lg: '992px',
// xl: '1200px',
// '2xl': '1600px',
// },
},
});
/**
* Used for animation when the element is displayed
* @param maxOutput The larger the maxOutput output, the larger the generated css volume
*/
function
createEnterPlugin
(
maxOutput
=
10
)
{
const
createCss
=
(
index
:
number
,
d
=
'
x
'
)
=>
{
const
upd
=
d
.
toUpperCase
();
return
{
[
`*> .enter-
${
d
}
:nth-child(
${
index
}
)`
]:
{
transform
:
`translate
${
upd
}
(50px)`
,
},
[
`*> .-enter-
${
d
}
:nth-child(
${
index
}
)`
]:
{
transform
:
`translate
${
upd
}
(-50px)`
,
},
[
`* > .enter-
${
d
}
:nth-child(
${
index
}
),* > .-enter-
${
d
}
:nth-child(
${
index
}
)`
]:
{
'
z-index
'
:
`
${
10
-
index
}
`
,
opacity
:
'
0
'
,
animation
:
`enter-
${
d
}
-animation 0.4s ease-in-out 0.3s`
,
'
animation-fill-mode
'
:
'
forwards
'
,
'
animation-delay
'
:
`
${(
index
*
1
)
/
10
}
s`
,
},
};
};
const
handler
=
({
addBase
})
=>
{
for
(
let
index
=
1
;
index
<
maxOutput
;
index
++
)
{
addBase
({
...
createCss
(
index
,
'
x
'
),
...
createCss
(
index
,
'
y
'
),
});
}
addBase
({
[
`@keyframes enter-x-animation`
]:
{
to
:
{
opacity
:
'
1
'
,
transform
:
'
translateX(0)
'
,
},
},
[
`@keyframes enter-y-animation`
]:
{
to
:
{
opacity
:
'
1
'
,
transform
:
'
translateY(0)
'
,
},
},
});
};
return
{
handler
};
}
yarn.lock
View file @
ec9478f7
...
@@ -1936,14 +1936,16 @@
...
@@ -1936,14 +1936,16 @@
dependencies:
dependencies:
vue-demi latest
vue-demi latest
"@windicss/plugin-utils@0.
3.12
":
"@windicss/plugin-utils@0.
4.3
":
version "0.
3.12
"
version "0.
4.3
"
resolved "https://registry.npmjs.org/@windicss/plugin-utils/-/plugin-utils-0.
3.12.tgz#69b55be1ffb45753e6f01aa236f5ecd8df7a92ee
"
resolved "https://registry.npmjs.org/@windicss/plugin-utils/-/plugin-utils-0.
4.3.tgz#84e85fd3cd6eaf54ca72cae276f9cf0610f45e56
"
integrity sha512-
XA+xeyu5KM322dIp+EEHeXnAPuK+KxuWyoGvJnxXi9U50nIp0QraqXAH7xl9ghIkVHvVrb8pmm8vHpzFvsqF2A
==
integrity sha512-
ilddLED+sZQIA9rOwE5eYwdBEBWKREvAVkkiAOOTNf7oDcP/a1cxT3f/nE4tgfhz+MC/FKcy7NkfrqfXRdEQaQ
==
dependencies:
dependencies:
esbuild "^0.8.49"
esbuild-register "^2.0.0"
fast-glob "^3.2.5"
fast-glob "^3.2.5"
micromatch "^4.0.2"
micromatch "^4.0.2"
windicss "^2.1.1
2
"
windicss "^2.1.1
5
"
"@zxcvbn-ts/core@^0.2.0":
"@zxcvbn-ts/core@^0.2.0":
version "0.2.0"
version "0.2.0"
...
@@ -3870,6 +3872,11 @@ esbuild@^0.8.48:
...
@@ -3870,6 +3872,11 @@ esbuild@^0.8.48:
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.8.48.tgz#a57e4dde84ec56da1c6ecaefee97e9da6c5b00b5"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.8.48.tgz#a57e4dde84ec56da1c6ecaefee97e9da6c5b00b5"
integrity sha512-lrH8lA8wWQ6Lpe1z6C7ZZaFSmRsUlcQAqe16nf7ITySQ7MV4+vI7qAqQlT/u+c3+9AL3VXmT4MXTxV2e63pO4A==
integrity sha512-lrH8lA8wWQ6Lpe1z6C7ZZaFSmRsUlcQAqe16nf7ITySQ7MV4+vI7qAqQlT/u+c3+9AL3VXmT4MXTxV2e63pO4A==
esbuild@^0.8.49:
version "0.8.49"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.8.49.tgz#3d33f71b3966611f822cf4c838115f3fbd16def2"
integrity sha512-itiFVYv5UZz4NooO7/Y0bRGVDGz/M/cxKbl6zyNI5pnKaz1mZjvZXAFhhDVz6rGCmcdTKj5oag6rh8DaaSSmfQ==
escalade@^3.1.1:
escalade@^3.1.1:
version "3.1.1"
version "3.1.1"
resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
...
@@ -8454,10 +8461,10 @@ stylelint-order@^4.1.0:
...
@@ -8454,10 +8461,10 @@ stylelint-order@^4.1.0:
postcss "^7.0.31"
postcss "^7.0.31"
postcss-sorting "^5.0.1"
postcss-sorting "^5.0.1"
stylelint@^13.1
0
.0:
stylelint@^13.1
1
.0:
version "13.1
0
.0"
version "13.1
1
.0"
resolved "https://registry.npmjs.org/stylelint/-/stylelint-13.1
0.0.tgz#67b0c6f378c3fa61aa569a55d38feb8570b0b587
"
resolved "https://registry.npmjs.org/stylelint/-/stylelint-13.1
1.0.tgz#591981fbdd68c9d3d3e6147a0cd6a07539fc216d
"
integrity sha512-
eDuLrL0wzPKbl5/TbNGZcbw0lTIGbDEr5W6lCODvb1gAg0ncbgCRt7oU0C2VFDvbrcY0A3MFZOwltwTRmc0XC
w==
integrity sha512-
DhrKSWDWGZkCiQMtU+VroXM6LWJVC8hSK24nrUngTSQvXGK75yZUq4yNpynqrxD3a/fzKMED09V+XxO4z4lTb
w==
dependencies:
dependencies:
"@stylelint/postcss-css-in-js" "^0.37.2"
"@stylelint/postcss-css-in-js" "^0.37.2"
"@stylelint/postcss-markdown" "^0.36.2"
"@stylelint/postcss-markdown" "^0.36.2"
...
@@ -9262,17 +9269,17 @@ vite-plugin-purge-icons@^0.7.0:
...
@@ -9262,17 +9269,17 @@ vite-plugin-purge-icons@^0.7.0:
"@purge-icons/generated" "^0.7.0"
"@purge-icons/generated" "^0.7.0"
rollup-plugin-purge-icons "^0.7.0"
rollup-plugin-purge-icons "^0.7.0"
vite-plugin-pwa@^0.5.
1
:
vite-plugin-pwa@^0.5.
2
:
version "0.5.
1
"
version "0.5.
2
"
resolved "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.5.
1.tgz#7f94b8c4092ba0bba0a1bceb690e7420b18071e7
"
resolved "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.5.
2.tgz#48131ebadc0c98c34a543dbf1bb1c86aeef532e0
"
integrity sha512-
hf8BgyH0XLNEJUoMsk7ywMoE+OoQelK/+4RQoftQomZhlKXgsTWrfshFGOV7sKUbLsxMh0cVoh1DmAulQmRzKQ
==
integrity sha512-
4SHKxYhd5sCF/ebbgxGYlN91UHlylzh7C32a5+Y2c2vbrWzw5x62ZxsYzolQzBosdOim4Ez+e/dX4hmP3BCmow
==
dependencies:
dependencies:
debug "^4.3.2"
debug "^4.3.2"
fast-glob "^3.2.5"
fast-glob "^3.2.5"
pretty-bytes "^5.5.0"
pretty-bytes "^5.5.0"
workbox-build "^6.1.0"
workbox-build "^6.1.0"
vite-plugin-style-import@^0.7.
2
:
vite-plugin-style-import@^0.7.
3
:
version "0.7.3"
version "0.7.3"
resolved "https://registry.npmjs.org/vite-plugin-style-import/-/vite-plugin-style-import-0.7.3.tgz#4a9fb08bf5f2fc4796391c9be9a587ecb5c97e9e"
resolved "https://registry.npmjs.org/vite-plugin-style-import/-/vite-plugin-style-import-0.7.3.tgz#4a9fb08bf5f2fc4796391c9be9a587ecb5c97e9e"
integrity sha512-oKM6vOl7iWaB5U1HcR5oM1oPRhT1n5yJt7h4h9jwpMPCD5ckHPcSjjSU7ZlOJkoS/IWEnDkQqoZi162bOs1rTQ==
integrity sha512-oKM6vOl7iWaB5U1HcR5oM1oPRhT1n5yJt7h4h9jwpMPCD5ckHPcSjjSU7ZlOJkoS/IWEnDkQqoZi162bOs1rTQ==
...
@@ -9295,13 +9302,13 @@ vite-plugin-theme@^0.4.3:
...
@@ -9295,13 +9302,13 @@ vite-plugin-theme@^0.4.3:
es-module-lexer "^0.3.26"
es-module-lexer "^0.3.26"
tinycolor2 "^1.4.2"
tinycolor2 "^1.4.2"
vite-plugin-windicss@0.
3.12
:
vite-plugin-windicss@0.
4.3
:
version "0.
3.12
"
version "0.
4.3
"
resolved "https://registry.npmjs.org/vite-plugin-windicss/-/vite-plugin-windicss-0.
3.12.tgz#5503b4ee738268a37c857c0cf55cea41f28fa3e6
"
resolved "https://registry.npmjs.org/vite-plugin-windicss/-/vite-plugin-windicss-0.
4.3.tgz#f86e5a3b78882caa3cdd50cba2b08770e2d627c8
"
integrity sha512-
NuzIjSrqBQKvpbLJoU9qi8PIWBBXCqBmuLg9Dl/cFl4MB/vAHIOB6sZYJatCBFTU39Kw4UU0GhAjDBSNqzTn0w
==
integrity sha512-
Lnv6OhcYzcJvecTs4LIpMSfo54rSewkHrW85IVwy8hacR0krY319jXr5nwiDpSTp6HM3QJhoJ4zxHF+t5Q+Nwg
==
dependencies:
dependencies:
"@windicss/plugin-utils" "0.
3.12
"
"@windicss/plugin-utils" "0.
4.3
"
windicss "^2.1.1
2
"
windicss "^2.1.1
5
"
vite@2.0.1:
vite@2.0.1:
version "2.0.1"
version "2.0.1"
...
@@ -9356,10 +9363,10 @@ vue-i18n@9.0.0-rc.2:
...
@@ -9356,10 +9363,10 @@ vue-i18n@9.0.0-rc.2:
"@intlify/shared" "9.0.0-rc.2"
"@intlify/shared" "9.0.0-rc.2"
"@vue/devtools-api" "^6.0.0-beta.3"
"@vue/devtools-api" "^6.0.0-beta.3"
vue-router@^4.0.
3
:
vue-router@^4.0.
4
:
version "4.0.
3
"
version "4.0.
4
"
resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.0.
3.tgz#8b26050c88b2dec7e27a88835f71046b365823ec
"
resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.0.
4.tgz#ad9b4b7bbdad622407b4ff189b1646f48c1e9053
"
integrity sha512-
AD1OjtVPyQHTSpoRsEGfPpxRQwhAhxcacOYO3zJ3KNkYP/r09mileSp6kdMQKhZWP2cFsPR3E2M3PZguSN5/w
w==
integrity sha512-
uN6PDEaYdU9aRO7mU+Dkr1uaY49hV3fucEDG/Vre/Qj8ct3RoJS16vcPrvKVzn69zDDjBV5b9Xw7fZA9r6b/I
w==
vue-types@^3.0.0:
vue-types@^3.0.0:
version "3.0.1"
version "3.0.1"
...
@@ -9434,10 +9441,10 @@ which@^2.0.1:
...
@@ -9434,10 +9441,10 @@ which@^2.0.1:
dependencies:
dependencies:
isexe "^2.0.0"
isexe "^2.0.0"
windicss@^2.1.1
2
:
windicss@^2.1.1
5
:
version "2.1.1
2
"
version "2.1.1
5
"
resolved "https://registry.npmjs.org/windicss/-/windicss-2.1.1
2.tgz#840b963f03af7a3e31b989d2b51de52dcd57a37a
"
resolved "https://registry.npmjs.org/windicss/-/windicss-2.1.1
5.tgz#0a5bf1a56711ab53de8093a3c855764d93ffac00
"
integrity sha512-
VC057iG65zlvdqUI+1ynzOuKikalvYg6XqPGbG17HEAfwQ0sg1dACTk2plEp1QAEQNtKU3BnLnueWa4oKlltEQ
==
integrity sha512-
gBihXNJPzv/kBaelOlXvbrmWsWuv98OPSf/yUYjc8EnRGCOxDOQIRin4FYPTWCmZi91PZThh7nMjzQZiBV+MYg
==
wmf@~1.0.1:
wmf@~1.0.1:
version "1.0.2"
version "1.0.2"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment