@scx-js/scx-admin 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/components/crud/crud-add-button.vue +28 -0
  2. package/components/crud/crud-batch-delete.vue +27 -0
  3. package/components/crud/crud-edit-dialog.vue +36 -0
  4. package/components/crud/crud-edit-form.vue +28 -0
  5. package/components/crud/crud-form-footer.vue +28 -0
  6. package/components/crud/crud-pagination.vue +51 -0
  7. package/components/crud/crud-reset-button.vue +19 -0
  8. package/components/crud/crud-search-button.vue +25 -0
  9. package/components/crud/crud-table-delete-button.vue +31 -0
  10. package/components/crud/crud-table-edit-button.vue +26 -0
  11. package/components/crud/crud-table.vue +131 -0
  12. package/components/crud/index.css +46 -0
  13. package/components/crud/index.vue +37 -0
  14. package/components/easy-ckeditor/default-editor-config.js +199 -0
  15. package/components/easy-ckeditor/easy-ckeditor-lazy.css +17 -0
  16. package/components/easy-ckeditor/easy-ckeditor-lazy.vue +106 -0
  17. package/components/easy-ckeditor/index.css +3 -0
  18. package/components/easy-ckeditor/index.vue +58 -0
  19. package/components/easy-ckeditor/plugins/scx-upload-adapter.js +39 -0
  20. package/components/easy-form-item/index.vue +168 -0
  21. package/components/easy-image/index.css +24 -0
  22. package/components/easy-image/index.vue +75 -0
  23. package/components/easy-monaco-editor/index.css +8 -0
  24. package/components/easy-monaco-editor/index.vue +70 -0
  25. package/components/easy-monaco-editor/use-worker.js +27 -0
  26. package/components/easy-select/index.vue +29 -0
  27. package/components/easy-upload/index.vue +94 -0
  28. package/components/easy-upload-list/index.vue +107 -0
  29. package/components/index.js +69 -0
  30. package/components/left-tree/index.css +74 -0
  31. package/components/left-tree/index.vue +130 -0
  32. package/components/scx-container/index.css +19 -0
  33. package/components/scx-container/index.vue +22 -0
  34. package/components/user-profile/change-password-dialog.vue +100 -0
  35. package/components/user-profile/change-user-avatar.vue +43 -0
  36. package/components/user-profile/change-username-dialog.vue +82 -0
  37. package/components/user-profile/index.css +8 -0
  38. package/components/user-profile/index.vue +77 -0
  39. package/index.js +4 -0
  40. package/layout/img/default-avatar.gif +0 -0
  41. package/layout/index.vue +24 -0
  42. package/layout/scx-app.vue +110 -0
  43. package/layout/scx-input.vue +84 -0
  44. package/layout/scx-logo.vue +65 -0
  45. package/layout/scx-main.vue +48 -0
  46. package/layout/scx-menu-item.vue +47 -0
  47. package/layout/scx-menu-toggle.vue +69 -0
  48. package/layout/scx-menu.vue +122 -0
  49. package/layout/scx-navbar.vue +47 -0
  50. package/layout/scx-notice.vue +211 -0
  51. package/layout/scx-sidebar.vue +70 -0
  52. package/layout/scx-theme-switch.vue +54 -0
  53. package/layout/scx-user-panel.vue +193 -0
  54. package/package.json +30 -0
  55. package/routes.js +57 -0
  56. package/scx/ali-oss.js +87 -0
  57. package/scx/auth-fetch.js +68 -0
  58. package/scx/crud-context.js +522 -0
  59. package/scx/easy-option.js +131 -0
  60. package/scx/index.js +8 -0
  61. package/scx/scx-auth-info.js +48 -0
  62. package/scx/scx-auth.js +197 -0
  63. package/scx/scx-config-manager.js +105 -0
  64. package/scx/scx-router.js +273 -0
  65. package/styles/index.css +37 -0
  66. package/util/cities.js +350 -0
  67. package/util/duration-format.js +27 -0
  68. package/util/element-plus-helper.js +114 -0
  69. package/util/get-order-number.js +7 -0
  70. package/util/index.js +4 -0
  71. package/util/nations.js +16 -0
  72. package/util/provinces.js +41 -0
  73. package/views/error-page.vue +79 -0
  74. package/views/login/index.css +95 -0
  75. package/views/login/login-and-register.vue +66 -0
  76. package/views/login/login-bg.vue +121 -0
  77. package/views/login/login-form-bg.vue +61 -0
  78. package/views/login/login-form.vue +137 -0
  79. package/views/login/login-message.js +28 -0
  80. package/views/login/login.vue +29 -0
  81. package/views/login/register-form.vue +148 -0
  82. package/views/no-perm.vue +7 -0
  83. package/views/not-found.vue +7 -0
  84. package/views/rocket.vue +84 -0
@@ -0,0 +1,79 @@
1
+ <template>
2
+ <div class="error-page">
3
+ <h1 class="heading">{{ message }}</h1>
4
+ <rocket/>
5
+ <div class="home-btn" @click="goHome">返回首页</div>
6
+ </div>
7
+ </template>
8
+
9
+ <script>
10
+ import {useRouter} from "vue-router";
11
+ import Rocket from "./rocket.vue";
12
+
13
+ export default {
14
+ name: "error-page",
15
+ components: {Rocket},
16
+ props: {
17
+ message: {type: String}
18
+ },
19
+ setup() {
20
+
21
+ const router = useRouter();
22
+
23
+ function goHome() {
24
+ router.push({name: "home"});
25
+ }
26
+
27
+ return {
28
+ goHome
29
+ };
30
+ }
31
+ };
32
+
33
+
34
+ </script>
35
+
36
+ <style scoped>
37
+ .heading {
38
+ text-align: center;
39
+ font-size: 9em;
40
+ line-height: 1.3em;
41
+ margin: 0 0 10px 0;
42
+ padding: 0;
43
+ text-shadow: 0 0 1rem #fefefe;
44
+ font-family: Arial, serif;
45
+ color: #b4b4b4;
46
+ }
47
+
48
+ .home-btn {
49
+ width: 150px;
50
+ text-align: center;
51
+ background: #FFFFFF;
52
+ padding: 8px 16px;
53
+ cursor: pointer;
54
+ border: 2px solid #ADD7F9;
55
+ border-radius: 5px;
56
+ color: #ADD7F9;
57
+ font-weight: 600;
58
+ transition: transform 0.1s;
59
+ user-select: none;
60
+ margin-top: 60px;
61
+ float: left;
62
+ }
63
+
64
+ .home-btn:hover {
65
+ transform: translate(0, -2px);
66
+ box-shadow: 0 2px 7px rgba(0, 0, 0, 0.1);
67
+ }
68
+
69
+ .error-page {
70
+ position: absolute;
71
+ display: flex;
72
+ flex-direction: column;
73
+ justify-content: center;
74
+ align-items: center;
75
+ width: 100%;
76
+ height: 100%;
77
+ }
78
+
79
+ </style>
@@ -0,0 +1,95 @@
1
+ /*----------------强制设置第三方组件在登录页的样式----------------*/
2
+
3
+ /*登录页所有的图标颜色*/
4
+ .login-form-bg .scx-icon {
5
+ fill: whitesmoke;
6
+ }
7
+
8
+ .login-form-bg.loginTab {
9
+ height: 309px;
10
+ }
11
+
12
+ .login-form-bg.loginTab.needAnimation .el-tabs__content {
13
+ transform-origin: 0 0 0;
14
+ animation: loginTabScale 300ms ease-in-out;
15
+ }
16
+
17
+ @keyframes loginTabScale {
18
+ 0% {
19
+ opacity: 0;
20
+ transform: scaleY(1.4);
21
+ }
22
+ 100% {
23
+ transform: scaleY(1.0);
24
+ }
25
+ }
26
+
27
+ .login-form-bg.registerTab {
28
+ height: 369px;
29
+ }
30
+
31
+ .login-form-bg.registerTab.needAnimation .el-tabs__content {
32
+ transform-origin: 0 0 0;
33
+ animation: registerTabScale 300ms ease-in-out;
34
+ }
35
+
36
+ @keyframes registerTabScale {
37
+ 0% {
38
+ opacity: 0;
39
+ transform: scaleY(0.74);
40
+ }
41
+ 100% {
42
+ transform: scaleY(1.0);
43
+ }
44
+ }
45
+
46
+
47
+ /*------------强制设置第三方组件在登录页的样式---------------*/
48
+ /* tabs */
49
+ .login-form-bg .el-tabs__nav-wrap::after {
50
+ background-color: transparent;
51
+ }
52
+
53
+ .login-form-bg .el-tabs__header {
54
+ user-select: none;
55
+ }
56
+
57
+ /* form */
58
+ .login-form-bg .el-input__inner {
59
+ height: 40px;
60
+ color: whitesmoke !important;
61
+ }
62
+
63
+ .login-form-bg .el-input__wrapper {
64
+ background: rgba(0, 0, 0, 0.1) !important;
65
+ border-style: unset;
66
+ box-shadow: 0 0 0 2px hsla(0, 0%, 100%, .3) inset;
67
+ border-radius: 2px;
68
+ }
69
+
70
+ .login-form-bg .el-input__wrapper:hover {
71
+ box-shadow: 0 0 0 2px #40a9ff inset;
72
+ }
73
+
74
+ .login-form-bg .el-input__wrapper:focus-within {
75
+ box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.5) inset;
76
+ }
77
+
78
+ .login-form-bg .el-input__prefix {
79
+ left: 15px;
80
+ }
81
+
82
+ .login-form-bg .el-tabs__item {
83
+ color: rgba(255, 252, 248, 0.85);
84
+ font-weight: 600;
85
+ transition: color 0.2s ease-in-out;
86
+ }
87
+
88
+ .login-form-bg .el-tabs__item.is-active,
89
+ .login-form-bg .el-tabs__item:hover {
90
+ color: #1890ff;
91
+ }
92
+
93
+
94
+
95
+
@@ -0,0 +1,66 @@
1
+ <template>
2
+
3
+ <login-bg>
4
+
5
+ <login-form-bg :class="[activeTab,{needAnimation:needAnimation}]">
6
+
7
+ <el-tabs v-model="activeTab" stretch>
8
+ <el-tab-pane label="账号登录" name="loginTab">
9
+ <login-form ref="loginFormRef"/>
10
+ </el-tab-pane>
11
+
12
+ <el-tab-pane label="注册账号" name="registerTab">
13
+ <register-form ref="registerFormRef" @register-success="onRegisterSuccess"/>
14
+ </el-tab-pane>
15
+ </el-tabs>
16
+
17
+ </login-form-bg>
18
+
19
+ </login-bg>
20
+
21
+ </template>
22
+
23
+ <script setup>
24
+ import "./index.css";
25
+ import {onMounted, ref, watch} from "vue";
26
+ import LoginForm from "./login-form.vue";
27
+ import RegisterForm from "./register-form.vue";
28
+ import LoginBg from "./login-bg.vue";
29
+ import LoginFormBg from "./login-form-bg.vue";
30
+
31
+ const activeTab = ref("loginTab");
32
+
33
+ const needAnimation = ref(false);
34
+
35
+ const loginFormRef = ref(null);
36
+
37
+ const registerFormRef = ref(null);
38
+
39
+ function changeActiveTab(tabName) {
40
+ if (tabName === "loginTab") {
41
+ console.log(loginFormRef);
42
+ loginFormRef.value.focus();
43
+ registerFormRef.value.resetFields();
44
+ } else if (tabName === "registerTab") {
45
+ registerFormRef.value.focus();
46
+ loginFormRef.value.resetFields();
47
+ }
48
+ }
49
+
50
+ function onRegisterSuccess({
51
+ username,
52
+ password
53
+ }) {
54
+ loginFormRef.value.loginForm.username = username;
55
+ loginFormRef.value.loginForm.password = password;
56
+ activeTab.value = "loginTab";
57
+ }
58
+
59
+ onMounted(() => {
60
+ watch(() => activeTab.value, (newVal) => {
61
+ needAnimation.value = true;
62
+ changeActiveTab(newVal);
63
+ }, {immediate: true});
64
+ });
65
+
66
+ </script>
@@ -0,0 +1,121 @@
1
+ <template>
2
+ <!-- 登录背景 -->
3
+ <div class="login-bg">
4
+ <!-- 小星星 -->
5
+ <div class="stars"></div>
6
+ <!-- 中间登录的div -->
7
+ <slot/>
8
+ <div class="login-footer">Powered By SCX @2018-2023</div>
9
+ </div>
10
+ </template>
11
+ <script setup>
12
+
13
+ </script>
14
+ <style scoped>
15
+ /*登录主背景*/
16
+ .login-bg {
17
+ background: radial-gradient(ellipse, transparent, #000000);
18
+ margin: 0;
19
+ padding: 0;
20
+ width: 100%;
21
+ height: 100%;
22
+ position: absolute;
23
+ perspective: 340px;
24
+ overflow: hidden;
25
+ display: flex;
26
+ justify-content: center;
27
+ align-items: center;
28
+ animation: login-bg 60s linear infinite;
29
+ }
30
+
31
+
32
+ @keyframes login-bg {
33
+ 0% {
34
+ background-color: #050526;
35
+ }
36
+ 25% {
37
+ background-color: #002e20;
38
+ }
39
+ 50% {
40
+ background-color: #300030;
41
+ }
42
+ 75% {
43
+ background-color: #1e0044;
44
+ }
45
+ 100% {
46
+ background-color: #050526;
47
+ }
48
+
49
+ }
50
+
51
+ .stars {
52
+ position: absolute;
53
+ top: 50%;
54
+ left: 50%;
55
+ width: 2px;
56
+ border-radius: 50%;
57
+ height: 2px;
58
+ box-shadow: 316px -155px #e6e6e6, 237px 174px #dbdbdb, -1386px 93px #c2c2c2, 67px -331px #c9c9c9, 716px -297px #f7f7f7, -562px 99px #e6e6e6, -126px -19px #d1d1d1, -585px 94px #f2f2f2, 1295px 47px #f7f7f7, -732px 373px #d6d6d6, -587px -106px #e0e0e0, -593px -293px #f0f0f0, 810px -466px #dedede, -786px -288px #ededed, 1269px 447px #e8e8e8, -386px 435px #dedede, -812px 392px #c7c7c7, 358px -21px #c9c9c9, 1144px -16px #d4d4d4, 786px -50px #cfcfcf, 395px -72px #fafafa, 966px -361px #d9d9d9, 1467px -371px #d4d4d4, 260px 408px #c2c2c2, 337px 199px #d9d9d9, 631px -158px #dedede, 272px -65px #d9d9d9, -1004px 344px #c9c9c9, -47px 26px #e0e0e0, 580px 138px #f2f2f2, -1017px 363px #fafafa, 1393px 447px #fcfcfc, -389px -236px #cccccc, 1290px 268px #fafafa, -1424px -232px #e8e8e8, 401px -10px #e6e6e6, -1020px 380px #dbdbdb, -45px -127px #fafafa, -1384px -457px #e3e3e3, -1033px -230px #e3e3e3, 1385px -159px #c7c7c7, 1171px 261px #ebebeb, 77px 286px #f2f2f2, 158px -138px #f7f7f7, 960px 190px #dedede, 1110px 153px #c2c2c2, 710px -298px #d9d9d9, -230px 413px #e8e8e8, -460px 253px #d4d4d4, -840px 199px #cccccc, -405px -294px #fcfcfc, 1034px 172px #d6d6d6, -901px 407px #ededed, 942px 81px white, 1156px 386px #e0e0e0, 79px -453px #c7c7c7, 562px 220px #cfcfcf, 527px -93px #c4c4c4, -509px 87px #d6d6d6, 143px -179px #f7f7f7, -558px 141px #d4d4d4, 191px -377px #cccccc, -1380px 68px #c2c2c2, 172px 285px #c4c4c4, -1403px -48px #ebebeb, -410px -11px #c4c4c4, -555px -8px #fcfcfc, 1429px 292px #cccccc, -658px -270px #fafafa, 748px 325px #c4c4c4, -1409px 391px #f0f0f0, 214px 82px #f2f2f2, 589px 411px white, -511px 67px #f2f2f2, -1375px 325px #c2c2c2, -1389px 225px #e8e8e8, 788px -447px #e0e0e0, 737px 250px #fafafa, 764px 45px #c2c2c2, 1382px 477px #d9d9d9, -1071px -280px whitesmoke, 1296px -137px #e3e3e3, 822px 301px #e3e3e3, 206px 222px #cccccc, 286px -262px white, 247px 59px #e0e0e0, 1224px -415px #d1d1d1, -155px 100px #c7c7c7, 471px -108px #fafafa, -1095px 255px #c2c2c2, 655px -350px #c7c7c7, 193px 38px #ededed, -156px -323px #cfcfcf, -890px -15px #d6d6d6, 1485px 373px #d4d4d4, -1486px 228px #dbdbdb, -465px 228px #e0e0e0, -83px -151px #e8e8e8, -198px -3px #d1d1d1, -1207px 72px whitesmoke, 492px 472px #ededed, 879px 322px #d4d4d4, 1425px -371px #ededed, -29px -207px #e3e3e3, -863px 343px #cccccc, 282px -415px #f0f0f0, -851px -120px #c4c4c4, 1142px -421px #d6d6d6, 1212px -134px #e0e0e0, -1277px -264px #e3e3e3, 557px 208px #f7f7f7, -328px -315px #c9c9c9, 988px 317px #f2f2f2, -1237px 267px #dedede, 1022px -468px #dedede, 654px -224px #f7f7f7, 1127px 199px #e8e8e8, -355px -181px #fcfcfc, -242px -398px white, 1321px -106px #f0f0f0, 119px 343px #e8e8e8, -958px -235px #f7f7f7, 937px 392px #d1d1d1, -885px -320px #d1d1d1, 1192px 341px #e6e6e6, -399px 77px whitesmoke, 1439px 20px #d1d1d1, -1224px 130px #e0e0e0, 430px 50px #c9c9c9, -673px 206px #c9c9c9, 1489px -5px whitesmoke, -833px 51px #f2f2f2, -476px -188px white, 747px -298px #f0f0f0, -259px -411px #c9c9c9, 351px 448px #e0e0e0, -119px -183px #cfcfcf, -1192px 114px #c4c4c4, 1391px 255px #dbdbdb, 401px 50px #c4c4c4, -497px 407px #dbdbdb, -1243px -402px #c4c4c4, -196px -70px #d6d6d6, -1494px -160px #d9d9d9, 1382px 247px #e0e0e0, 415px 190px #dbdbdb, -1112px -250px #d9d9d9, 552px -66px #c7c7c7, 379px -265px #e0e0e0, -1109px -104px #ededed, -119px 161px #d4d4d4, -1270px 223px #c4c4c4, 107px -246px #f7f7f7, -41px -37px #cccccc, 795px -134px #d1d1d1, 1238px 451px #f0f0f0, -323px 269px #d6d6d6, 982px -85px #c7c7c7, 1106px -65px #ebebeb, 1151px -90px #e8e8e8, -483px 276px #dbdbdb, 45px 146px #cfcfcf, 1087px 221px #d4d4d4, 1157px -182px #f7f7f7, 715px -171px #fcfcfc, -810px 408px #e0e0e0, -130px -105px #d4d4d4, -258px 187px #fcfcfc, 887px 39px #d9d9d9, 290px -207px #f0f0f0, -1449px -472px #d1d1d1, 1396px -87px whitesmoke, -1166px -91px #c9c9c9, 916px -294px white, -1439px -265px #ededed, 1069px -308px #c9c9c9, 1166px -299px #ebebeb, 934px -474px #dbdbdb, 368px 108px #cfcfcf, -84px -156px #dbdbdb, -670px -24px #c7c7c7, 260px -95px #c2c2c2, 1131px 465px #ebebeb, -577px -2px #d4d4d4, -104px -220px #d6d6d6, 1195px 431px #ebebeb, -809px -141px #e0e0e0, 1432px -38px #c4c4c4, -1300px -268px #f7f7f7, -200px -414px #ebebeb, -1123px 476px #d9d9d9, 223px -18px #cccccc, 643px -44px whitesmoke, 1306px 289px #cfcfcf, -736px 142px #d4d4d4, -416px 283px #f2f2f2, 511px 203px #c4c4c4, 1240px 396px #c2c2c2, -138px -126px #ebebeb, 714px 447px #c4c4c4, -1395px -368px #e6e6e6, 715px -241px #e0e0e0, -438px -245px #d4d4d4, -995px 82px #fafafa, -951px 366px #d4d4d4, -1110px -438px whitesmoke, -74px 120px #e0e0e0, 1467px -281px #d1d1d1, 317px -425px #dbdbdb, 1018px 365px #c7c7c7, -45px -189px #c4c4c4, 1497px 165px white, -133px 246px #f7f7f7, 401px 127px #e3e3e3, -185px 42px #f0f0f0, 55px 222px #fafafa, -900px -153px #f2f2f2, 419px -266px #d1d1d1, 274px 203px #ededed, 530px 217px white, -1015px -142px #cccccc, -389px -201px #fafafa, -367px -156px #d9d9d9, -961px -273px #c7c7c7, -1289px 335px #f7f7f7, 1412px 167px #d9d9d9, -93px 465px #d4d4d4, 200px 285px #e3e3e3, 414px -345px #ededed, -935px 88px #e0e0e0, 139px -26px #f0f0f0, 771px 453px #dedede, 1275px 179px whitesmoke, 937px -421px whitesmoke, -673px 248px #fcfcfc, 413px -421px #d1d1d1, 955px -110px #d9d9d9, -1223px 293px #d1d1d1, -60px 47px #e0e0e0, -765px 407px #cfcfcf, -762px -314px whitesmoke, -404px 443px #f7f7f7, -1426px 105px whitesmoke, 1px 424px #dbdbdb, -707px -158px #ededed, -332px -376px #e8e8e8, -395px -30px #c9c9c9, 693px 393px #c4c4c4, -905px -325px #c4c4c4, -878px -392px #e6e6e6, -571px 360px #d4d4d4, 233px 154px #c9c9c9, -1133px 371px #cccccc, 1131px 388px #c4c4c4, -1093px -397px #d6d6d6, -837px 110px #e6e6e6, 891px 6px #e0e0e0, 607px -129px #d1d1d1, 415px 43px #d4d4d4, -886px -105px #d1d1d1, -1431px 225px #e8e8e8, 27px -257px #e0e0e0, 1058px 297px #fcfcfc, -1020px 27px #f2f2f2, -1387px -28px #e0e0e0, 151px 434px #fcfcfc, -1046px 170px #d4d4d4, -1261px -296px #f2f2f2, -1391px 325px #e8e8e8, -389px 133px #e3e3e3, -1302px 277px #c9c9c9, 691px 351px #e8e8e8, 364px 3px #cccccc, -836px 68px #cccccc, 301px 175px #dedede, -760px -13px #e6e6e6, 661px -432px #c4c4c4, -922px -447px #d4d4d4, 258px 376px #ebebeb, -124px -165px #fafafa, -146px 428px #e0e0e0, -83px -264px #d9d9d9, -1264px -245px #c4c4c4, 172px -245px #d1d1d1, 548px -306px #dedede, 1319px -194px #ededed, 1077px 185px #e3e3e3, -107px -280px #d4d4d4, -1066px -420px #e3e3e3, 776px 215px whitesmoke, -657px 322px #c7c7c7, 508px -75px #d9d9d9, -498px -39px #f7f7f7, 535px -149px #c2c2c2, 182px 274px #f7f7f7, -1321px -212px #c7c7c7, 849px -408px #fcfcfc, -801px 96px #c2c2c2, -1111px -399px #d9d9d9, -1336px 465px #cfcfcf, -1131px 405px #d9d9d9, 872px -387px #d4d4d4, -1307px -92px #f7f7f7, 1416px 124px #ededed, -1176px -250px #d6d6d6, 164px -165px #e3e3e3, -1202px -40px #cccccc, 95px 478px #cccccc, -501px -384px #ebebeb, -1385px -255px #e3e3e3, -628px 214px #e0e0e0, -888px -470px #d4d4d4, 963px -444px #c4c4c4, -1068px -317px #c7c7c7, -694px 9px #e6e6e6, 983px 374px #f0f0f0, 1217px -43px #ededed, 744px -212px #c9c9c9, 605px -383px white, 43px 108px #e0e0e0, 965px -43px #cccccc, -1335px 265px white, -1330px -296px #f0f0f0, -1042px -247px whitesmoke, 964px 326px #c9c9c9, 1144px -267px white, -1329px -401px #cfcfcf, 628px 444px #c9c9c9, 1409px 240px #f0f0f0, 1174px 257px #d6d6d6, -1326px -68px #d4d4d4, -519px -331px #d4d4d4, 305px -189px #e6e6e6, -678px 434px white, 1381px -382px #f7f7f7, 11px -325px #d1d1d1, 145px 194px #ebebeb, 224px 214px #f7f7f7, -893px 421px #dbdbdb, -339px -383px #dbdbdb, -845px -20px #ebebeb, 1122px 297px #d6d6d6, 926px -475px #c7c7c7, 232px 105px #d6d6d6, -165px -380px #f0f0f0, -770px 43px #c9c9c9, -1400px -234px #c9c9c9, 1264px 339px #ededed, -781px -371px #f2f2f2, -1227px -192px #cccccc, 1218px 131px #e6e6e6;
59
+ animation: fly 30s linear infinite;
60
+ transform-style: preserve-3d;
61
+ }
62
+
63
+
64
+ @keyframes fly {
65
+ from {
66
+ transform: translateZ(0px);
67
+ }
68
+ to {
69
+ transform: translateZ(300px);
70
+ }
71
+ }
72
+
73
+ .stars:before, .stars:after {
74
+ content: "";
75
+ position: absolute;
76
+ width: inherit;
77
+ height: inherit;
78
+ box-shadow: inherit;
79
+ }
80
+
81
+ .stars:before {
82
+ transform: translateZ(-300px);
83
+ animation: fade1 10s linear infinite;
84
+ }
85
+
86
+ .stars:after {
87
+ transform: translateZ(-600px);
88
+ animation: fade2 10s linear infinite;
89
+ }
90
+
91
+ @keyframes fade1 {
92
+ from {
93
+ opacity: .5;
94
+ }
95
+ to {
96
+ opacity: 1;
97
+ }
98
+ }
99
+
100
+ @keyframes fade2 {
101
+ from {
102
+ opacity: 0;
103
+ }
104
+ to {
105
+ opacity: .5;
106
+ }
107
+ }
108
+
109
+ /*右下角标识*/
110
+ .login-footer {
111
+ position: fixed;
112
+ bottom: 1%;
113
+ right: 1%;
114
+ color: rgba(120, 120, 120, 0.1);
115
+ transition: all 0.5s ease-out;
116
+ }
117
+
118
+ .login-footer:hover {
119
+ color: rgba(255, 255, 255, 0.5)
120
+ }
121
+ </style>
@@ -0,0 +1,61 @@
1
+ <template>
2
+ <div class="login-form-bg">
3
+ <!-- 上面的说明文字 -->
4
+ <div class="title-container">
5
+ <scx-icon icon="outlined-scx-logo"/>
6
+ <span>系统登录</span>
7
+ </div>
8
+ <slot/>
9
+ </div>
10
+ </template>
11
+ <script setup>
12
+
13
+ </script>
14
+
15
+ <style scoped>
16
+
17
+ /*登录表单背景*/
18
+ .login-form-bg {
19
+ padding: 20px 20px 25px 20px;
20
+ width: 400px;
21
+ border-radius: 10px;
22
+ transition: all 300ms ease-in-out;
23
+ }
24
+
25
+
26
+ /*鼠标移入使背景明显*/
27
+ .login-form-bg:hover {
28
+ background: rgb(30, 30, 30);
29
+ box-shadow: 0 0 20px 2px rgba(0, 0, 0, 0.3);
30
+ }
31
+
32
+ /*登录标题*/
33
+ .title-container {
34
+ margin-bottom: 10px;
35
+ position: relative;
36
+ }
37
+
38
+ /*scx logo*/
39
+ .title-container > .scx-icon {
40
+ height: 44px;
41
+ width: 50px;
42
+ fill: #1890ff;
43
+ vertical-align: top;
44
+ margin-right: 2%;
45
+ margin-left: 19%;
46
+ margin-top: 4px;
47
+ transition: all 0.5s ease-out;
48
+ }
49
+
50
+ .title-container > .scx-icon:hover {
51
+ fill: #489349;
52
+ }
53
+
54
+ /*标题文字*/
55
+ .title-container > span {
56
+ font-size: 33px;
57
+ color: rgba(255, 252, 248, 0.85);
58
+ font-family: Avenir, "Helvetica Neue", Arial, Helvetica, sans-serif;
59
+ font-weight: 600;
60
+ }
61
+ </style>
@@ -0,0 +1,137 @@
1
+ <template>
2
+ <el-form ref="loginFormRef" :model="loginForm" :rules="loginFormRules">
3
+
4
+ <el-form-item prop="username">
5
+ <el-input ref="loginUsernameRef" v-model="loginForm.username"
6
+ placeholder="请输入用户名"
7
+ @keyup.enter="onLogin">
8
+ <template v-slot:prefix>
9
+ <scx-icon icon="outlined-user"/>
10
+ </template>
11
+ </el-input>
12
+ </el-form-item>
13
+
14
+ <el-form-item prop="password">
15
+ <el-input v-model="loginForm.password"
16
+ placeholder="请输入密码"
17
+ show-password
18
+ @keyup.enter="onLogin">
19
+ <template v-slot:prefix>
20
+ <scx-icon icon="outlined-unlock"/>
21
+ </template>
22
+ </el-input>
23
+ </el-form-item>
24
+
25
+ <el-button :loading="loginForm.loginBtnLoading" style="width: 100%" type="primary" @click="onLogin">
26
+ 登录
27
+ </el-button>
28
+
29
+ </el-form>
30
+ </template>
31
+ <script setup>
32
+ import {ElMessage} from "element-plus";
33
+ import {JsonVOError, useScxReq} from "@scx-js/scx-http";
34
+ import {useScxAuth, useScxRouter, useScxUserInfo} from "../../index.js";
35
+ import {reactive, ref} from "vue";
36
+ import {useRoute, useRouter} from "vue-router";
37
+ import {loginMessage} from "./login-message.js";
38
+
39
+ const auth = useScxAuth();
40
+ const req = useScxReq();
41
+ const scxRouter = useScxRouter();
42
+
43
+ const userInfo = useScxUserInfo();
44
+
45
+ const loginUsernameRef = ref(null);
46
+
47
+ const router = useRouter();
48
+ const route = useRoute();
49
+
50
+ const loginFormRef = ref(null);
51
+ const loginForm = reactive({
52
+ username: "",
53
+ password: "",
54
+ loginBtnLoading: false
55
+ });
56
+
57
+ const loginFormRules = {
58
+ username: [{
59
+ type: "string",
60
+ trigger: "change",
61
+ required: true,
62
+ validator: (rule, value, callback) => {
63
+ if (value.trim() === "") {
64
+ return callback("请输入正确的用户名 !!!");
65
+ } else {
66
+ callback();
67
+ }
68
+ }
69
+ }],
70
+ password: [{
71
+ type: "string",
72
+ required: true,
73
+ trigger: "change",
74
+ validator: (rule, value, callback) => {
75
+ if (value.length === 0) {
76
+ return callback("密码不能为空 !!!"); // reject with error message
77
+ } else {
78
+ callback();
79
+ }
80
+ }
81
+ }]
82
+ };
83
+
84
+
85
+ function onLogin() {
86
+ loginFormRef.value.validate((valid) => {
87
+ if (!valid) {
88
+ return;
89
+ }
90
+ loginForm.loginBtnLoading = true;
91
+ auth.login(loginForm.username, loginForm.password)
92
+ .then(() => {
93
+ auth.tokenCanUse().then(canUse => {
94
+ if (canUse) {
95
+ //1, 先获取需要重定向的页面
96
+ const redirectRoute = scxRouter.getRedirectRouteFromLoginRoute(route);
97
+ //2, 判断是否有权限访问
98
+ const canAccessThisRoute = scxRouter.canAccessThisRoute(redirectRoute);
99
+ //3, 如果用户没权限访问 则跳转首页
100
+ router.push(canAccessThisRoute ? redirectRoute : {name: "home"});
101
+ ElMessage.success("欢迎回来 " + userInfo.user.username + " !!!");
102
+ } else {
103
+ ElMessage.warning("认证 Token 无效 !!!");
104
+ }
105
+ });
106
+ })
107
+ .catch(error => {
108
+ if (error instanceof JsonVOError) {
109
+ ElMessage.error(loginMessage.t(error.message) || "未知错误 !!!");
110
+ } else {
111
+ ElMessage.error("Api 连接错误 !!!");
112
+ }
113
+ }).finally(() => {
114
+ loginForm.loginBtnLoading = false;
115
+ });
116
+ });
117
+
118
+ }
119
+
120
+ function focus() {
121
+ loginUsernameRef.value.focus();
122
+ }
123
+
124
+ function resetFields() {
125
+ loginFormRef.value.resetFields();
126
+ }
127
+
128
+ defineExpose({
129
+ focus,
130
+ resetFields,
131
+ loginForm
132
+ });
133
+ </script>
134
+
135
+ <style scoped>
136
+
137
+ </style>
@@ -0,0 +1,28 @@
1
+ class LoginMessage {
2
+ mapping = {
3
+ "Network Error": "网络错误 !!!",
4
+ "Request failed with status code 404": "Api 路径错误 !!!",
5
+ "Request failed with status code 500": "服务器端发生错误 !!!",
6
+ "unknown-user": "用户未找到 !!!",
7
+ "wrong-password": "密码错误 !!!",
8
+ usernameOrPasswordError: "用户名或密码错误 !!!",
9
+ userLocked: "用户已被锁定 !!!",
10
+ logonFailure: "登陆错误 !!!",
11
+ tooManyErrors: "登陆错误次数过多",
12
+ licenseError: "系统错误 !!!",
13
+ noPermission: "您没有权限进行该操作 !!!",
14
+ "Failed to fetch": "网络错误 !!!",
15
+ "username-already-exists": "用户名已被占用 !!!",
16
+ };
17
+
18
+ t(m) {
19
+ const message = this.mapping[m];
20
+ return message ? message : m;
21
+ }
22
+ }
23
+
24
+ const loginMessage = new LoginMessage();
25
+
26
+ export {
27
+ loginMessage,
28
+ };
@@ -0,0 +1,29 @@
1
+ <template>
2
+
3
+ <login-bg>
4
+
5
+ <login-form-bg>
6
+
7
+ <login-form ref="loginFormRef"/>
8
+
9
+ </login-form-bg>
10
+
11
+ </login-bg>
12
+
13
+ </template>
14
+
15
+ <script setup>
16
+ import "./index.css";
17
+ import {onMounted, ref} from "vue";
18
+ import LoginForm from "./login-form.vue";
19
+ import LoginBg from "./login-bg.vue";
20
+ import LoginFormBg from "./login-form-bg.vue";
21
+
22
+ const loginFormRef = ref(null);
23
+
24
+ onMounted(() => {
25
+ loginFormRef.value.focus();
26
+ loginFormRef.value.resetFields();
27
+ });
28
+
29
+ </script>