@befly-addon/admin 1.0.10 → 1.0.11

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 (35) hide show
  1. package/apis/api/all.ts +6 -11
  2. package/apis/menu/all.ts +8 -14
  3. package/package.json +15 -4
  4. package/util.ts +1 -150
  5. package/views/403/index.vue +68 -0
  6. package/views/admin/components/edit.vue +150 -0
  7. package/views/admin/components/role.vue +138 -0
  8. package/views/admin/index.vue +179 -0
  9. package/views/dict/components/edit.vue +159 -0
  10. package/views/dict/index.vue +162 -0
  11. package/views/index/components/addonList.vue +127 -0
  12. package/views/index/components/environmentInfo.vue +99 -0
  13. package/views/index/components/operationLogs.vue +114 -0
  14. package/views/index/components/performanceMetrics.vue +150 -0
  15. package/views/index/components/quickActions.vue +27 -0
  16. package/views/index/components/serviceStatus.vue +183 -0
  17. package/views/index/components/systemNotifications.vue +132 -0
  18. package/views/index/components/systemOverview.vue +190 -0
  19. package/views/index/components/systemResources.vue +106 -0
  20. package/views/index/components/userInfo.vue +206 -0
  21. package/views/index/index.vue +29 -0
  22. package/views/login/components/emailLoginForm.vue +167 -0
  23. package/views/login/components/registerForm.vue +170 -0
  24. package/views/login/components/welcomePanel.vue +61 -0
  25. package/views/login/index.vue +191 -0
  26. package/views/menu/components/edit.vue +153 -0
  27. package/views/menu/index.vue +177 -0
  28. package/views/news/detail/index.vue +26 -0
  29. package/views/news/index.vue +26 -0
  30. package/views/role/components/api.vue +283 -0
  31. package/views/role/components/edit.vue +132 -0
  32. package/views/role/components/menu.vue +146 -0
  33. package/views/role/index.vue +179 -0
  34. package/views/user/index.vue +322 -0
  35. package/apis/dashboard/addonList.ts +0 -47
@@ -0,0 +1,167 @@
1
+ <template>
2
+ <tiny-form :model="$Data.formData" :rules="$Data2.formRules" :ref="(el) => ($From.form = el)" class="login-form" label-width="90px" label-position="left" :show-message="false">
3
+ <tiny-form-item prop="account" label="账号">
4
+ <tiny-input v-model="$Data.formData.account" placeholder="请输入用户名或邮箱" size="large" clearable>
5
+ <template #prefix-icon>
6
+ <i-lucide:user style="width: 18px; height: 18px" />
7
+ </template>
8
+ </tiny-input>
9
+ </tiny-form-item>
10
+
11
+ <tiny-form-item prop="password" label="密码">
12
+ <tiny-input v-model="$Data.formData.password" type="password" placeholder="请输入密码" size="large" clearable>
13
+ <template #prefix-icon>
14
+ <i-lucide:lock style="width: 18px; height: 18px" />
15
+ </template>
16
+ </tiny-input>
17
+ </tiny-form-item>
18
+
19
+ <div class="form-footer">
20
+ <a href="#" class="forgot-password">忘记密码?</a>
21
+ </div>
22
+
23
+ <tiny-button theme="primary" class="auth-btn" size="large" :loading="$Data.loading" @click="$Method.apiLogin"> 登录 </tiny-button>
24
+ </tiny-form>
25
+ </template>
26
+
27
+ <script setup lang="ts">
28
+ import { ref, shallowRef } from 'vue';
29
+ import { useRouter } from 'vue-router';
30
+ import { Modal } from '@opentiny/vue';
31
+
32
+ const router = useRouter();
33
+
34
+ // 表单引用
35
+ const $From = $shallowRef({
36
+ form: null
37
+ });
38
+
39
+ // 数据定义
40
+ const $Data = $ref({
41
+ loading: false,
42
+ formData: {
43
+ account: '',
44
+ password: ''
45
+ }
46
+ });
47
+
48
+ const $Data2 = $shallowRef({
49
+ formRules: {
50
+ account: [{ required: true, message: '请输入用户名或邮箱', trigger: 'blur' }],
51
+ password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
52
+ }
53
+ });
54
+
55
+ // 方法定义
56
+ const $Method = {
57
+ async apiLogin() {
58
+ try {
59
+ const valid = await $From.form.validate();
60
+
61
+ $Data.loading = true;
62
+
63
+ const res = await $Http('/addon/admin/auth/login', {
64
+ account: $Data.formData.account,
65
+ password: $Data.formData.password
66
+ });
67
+
68
+ // 先保存 token
69
+ $Storage.local.set('token', res.data.token);
70
+
71
+ // 如果返回用户信息,也可以存储
72
+ if (res.data.userInfo) {
73
+ $Storage.local.set('userInfo', res.data.userInfo);
74
+ }
75
+
76
+ Modal.message({
77
+ message: '登录成功',
78
+ status: 'success'
79
+ });
80
+
81
+ // 跳转到首页,路由守卫会自动加载菜单
82
+ await router.push('/');
83
+ } catch (error) {
84
+ console.log('🔥[ error ]-77', error);
85
+ } finally {
86
+ $Data.loading = false;
87
+ }
88
+ }
89
+ };
90
+ </script>
91
+
92
+ <style scoped lang="scss">
93
+ .login-form {
94
+ width: 100%;
95
+ max-width: 450px;
96
+ }
97
+
98
+ .tiny-form-item {
99
+ width: 100%;
100
+ margin-bottom: 1.2rem;
101
+
102
+ :deep(.tiny-form__controls) {
103
+ width: 100%;
104
+ }
105
+
106
+ :deep(.tiny-input) {
107
+ width: 100%;
108
+ background: #f8f9fa;
109
+ border: 1px solid #e0e0e0;
110
+ border-radius: 6px;
111
+ transition: all 0.3s;
112
+
113
+ &:hover {
114
+ border-color: #48b19f;
115
+ }
116
+
117
+ &:focus-within {
118
+ border-color: #48b19f;
119
+ background: #fff;
120
+ }
121
+
122
+ input {
123
+ padding: 0.75rem 1rem;
124
+ }
125
+ }
126
+ }
127
+
128
+ .form-footer {
129
+ width: 100%;
130
+ display: flex;
131
+ justify-content: flex-end;
132
+ margin-bottom: 1rem;
133
+ }
134
+
135
+ .forgot-password {
136
+ font-size: 0.8rem;
137
+ color: #888;
138
+ text-decoration: none;
139
+
140
+ &:hover {
141
+ color: #48b19f;
142
+ }
143
+ }
144
+
145
+ .auth-btn {
146
+ width: 100% !important;
147
+ max-width: 100%;
148
+ height: 44px;
149
+ border-radius: 6px;
150
+ background: #48b19f;
151
+ border: none;
152
+ font-size: 0.95rem;
153
+ font-weight: 600;
154
+ margin-top: 0.5rem;
155
+ transition: all 0.3s;
156
+
157
+ &:hover {
158
+ background: #3a9d8f;
159
+ transform: translateY(-1px);
160
+ box-shadow: 0 3px 10px rgba(72, 177, 159, 0.3);
161
+ }
162
+
163
+ :deep(.tiny-button__text) {
164
+ color: #fff;
165
+ }
166
+ }
167
+ </style>
@@ -0,0 +1,170 @@
1
+ <template>
2
+ <tiny-form :model="$Data.formData" :rules="$Data2.formRules" :ref="(el) => ($From.form = el)" class="login-form" label-width="70px" label-position="left">
3
+ <tiny-form-item prop="username" label="用户名">
4
+ <tiny-input v-model="$Data.formData.username" placeholder="请输入用户名" size="large" clearable>
5
+ <template #prefix-icon>
6
+ <i-lucide:user style="width: 18px; height: 18px" />
7
+ </template>
8
+ </tiny-input>
9
+ </tiny-form-item>
10
+
11
+ <tiny-form-item prop="email" label="邮箱">
12
+ <tiny-input v-model="$Data.formData.email" placeholder="请输入邮箱" size="large" clearable>
13
+ <template #prefix-icon>
14
+ <i-lucide:mail style="width: 18px; height: 18px" />
15
+ </template>
16
+ </tiny-input>
17
+ </tiny-form-item>
18
+
19
+ <tiny-form-item prop="password" label="密码">
20
+ <tiny-input v-model="$Data.formData.password" type="password" placeholder="请输入密码" size="large" clearable>
21
+ <template #prefix-icon>
22
+ <i-lucide:lock style="width: 18px; height: 18px" />
23
+ </template>
24
+ </tiny-input>
25
+ </tiny-form-item>
26
+
27
+ <tiny-form-item prop="nickname" label="昵称">
28
+ <tiny-input v-model="$Data.formData.nickname" placeholder="请输入昵称(选填)" size="large" clearable>
29
+ <template #prefix-icon>
30
+ <i-lucide:smile style="width: 18px; height: 18px" />
31
+ </template>
32
+ </tiny-input>
33
+ </tiny-form-item>
34
+
35
+ <tiny-button theme="primary" class="auth-btn" size="large" :loading="$Data.loading" @click="$Method.handleSubmit"> 注册 </tiny-button>
36
+ </tiny-form>
37
+ </template>
38
+
39
+ <script setup>
40
+ import { ref, shallowRef } from 'vue';
41
+
42
+ const emit = defineEmits(['success']);
43
+
44
+ // 表单引用
45
+ const $From = $shallowRef({
46
+ form: null
47
+ });
48
+
49
+ // 数据定义
50
+ const $Data = $ref({
51
+ loading: false,
52
+ formData: {
53
+ username: '',
54
+ email: '',
55
+ password: '',
56
+ nickname: ''
57
+ }
58
+ });
59
+
60
+ const $Data2 = $shallowRef({
61
+ formRules: {
62
+ username: [
63
+ { required: true, message: '请输入用户名', trigger: 'blur' },
64
+ { min: 3, max: 20, message: '用户名长度为 3-20 个字符', trigger: 'blur' }
65
+ ],
66
+ email: [
67
+ { required: true, message: '请输入邮箱', trigger: 'blur' },
68
+ { type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
69
+ ],
70
+ password: [
71
+ { required: true, message: '请输入密码', trigger: 'blur' },
72
+ { min: 6, message: '密码长度至少 6 个字符', trigger: 'blur' }
73
+ ]
74
+ // nickname 是选填项,不需要验证规则
75
+ }
76
+ });
77
+
78
+ // 方法定义
79
+ const $Method = {
80
+ async handleSubmit() {
81
+ const valid = await $From.form.validate();
82
+ if (!valid) return;
83
+
84
+ $Data.loading = true;
85
+
86
+ try {
87
+ await $Http('/addon/admin/register', $Data.formData);
88
+ MessagePlugin.success('注册成功,请登录');
89
+
90
+ // 清空表单
91
+ $Method.resetForm();
92
+
93
+ // 通知父组件注册成功,切换到登录模式
94
+ emit('success');
95
+ } catch (error) {
96
+ // 错误已经在 request 拦截器中处理
97
+ } finally {
98
+ $Data.loading = false;
99
+ }
100
+ },
101
+
102
+ // 清空表单
103
+ resetForm() {
104
+ $Data.formData.username = '';
105
+ $Data.formData.email = '';
106
+ $Data.formData.password = '';
107
+ $Data.formData.nickname = '';
108
+ }
109
+ };
110
+ </script>
111
+
112
+ <style scoped lang="scss">
113
+ .login-form {
114
+ width: 100%;
115
+ max-width: 450px;
116
+ }
117
+
118
+ .tiny-form-item {
119
+ width: 100%;
120
+ margin-bottom: 1.2rem;
121
+
122
+ :deep(.tiny-form__controls) {
123
+ width: 100%;
124
+ }
125
+
126
+ :deep(.tiny-input) {
127
+ width: 100%;
128
+ background: #f8f9fa;
129
+ border: 1px solid #e0e0e0;
130
+ border-radius: 6px;
131
+ transition: all 0.3s;
132
+
133
+ &:hover {
134
+ border-color: #48b19f;
135
+ }
136
+
137
+ &:focus-within {
138
+ border-color: #48b19f;
139
+ background: #fff;
140
+ }
141
+
142
+ input {
143
+ padding: 0.75rem 1rem;
144
+ }
145
+ }
146
+ }
147
+
148
+ .auth-btn {
149
+ width: 100% !important;
150
+ max-width: 100%;
151
+ height: 44px;
152
+ border-radius: 6px;
153
+ background: #48b19f;
154
+ border: none;
155
+ font-size: 0.95rem;
156
+ font-weight: 600;
157
+ margin-top: 0.5rem;
158
+ transition: all 0.3s;
159
+
160
+ &:hover {
161
+ background: #3a9d8f;
162
+ transform: translateY(-1px);
163
+ box-shadow: 0 3px 10px rgba(72, 177, 159, 0.3);
164
+ }
165
+
166
+ :deep(.tiny-button__text) {
167
+ color: #fff;
168
+ }
169
+ }
170
+ </style>
@@ -0,0 +1,61 @@
1
+ <template>
2
+ <div class="panel-content" v-if="!isSignUp">
3
+ <h2>你好,朋友!</h2>
4
+ <p>填写个人信息,开始使用</p>
5
+ <button class="toggle-btn" @click="$emit('toggle')">注册账号</button>
6
+ </div>
7
+ <div class="panel-content" v-else>
8
+ <h2>欢迎回来!</h2>
9
+ <p>使用您的账号登录</p>
10
+ <button class="toggle-btn" @click="$emit('toggle')">立即登录</button>
11
+ </div>
12
+ </template>
13
+
14
+ <script setup>
15
+ const props = defineProps({
16
+ isSignUp: {
17
+ type: Boolean,
18
+ default: false
19
+ }
20
+ });
21
+
22
+ defineEmits(['toggle']);
23
+ </script>
24
+
25
+ <style scoped lang="scss">
26
+ .panel-content {
27
+ text-align: center;
28
+ padding: 2rem;
29
+ max-width: 400px;
30
+
31
+ h2 {
32
+ font-size: 2rem;
33
+ font-weight: 600;
34
+ margin-bottom: 1rem;
35
+ }
36
+
37
+ p {
38
+ font-size: 1rem;
39
+ line-height: 1.6;
40
+ margin-bottom: 2rem;
41
+ opacity: 0.9;
42
+ }
43
+
44
+ .toggle-btn {
45
+ padding: 0.8rem 3rem;
46
+ border: 2px solid #fff;
47
+ background: transparent;
48
+ color: #fff;
49
+ border-radius: 25px;
50
+ font-size: 0.9rem;
51
+ font-weight: 600;
52
+ cursor: pointer;
53
+ transition: all 0.3s;
54
+
55
+ &:hover {
56
+ background: #fff;
57
+ color: #48b19f;
58
+ }
59
+ }
60
+ }
61
+ </style>
@@ -0,0 +1,191 @@
1
+ <template>
2
+ <div class="auth-container" :class="{ 'sign-up-mode': $Data.isSignUp }">
3
+ <!-- 左侧欢迎区域 -->
4
+ <div class="left-panel">
5
+ <WelcomePanel :is-sign-up="$Data.isSignUp" @toggle="$Method.toggleMode" />
6
+ </div>
7
+
8
+ <!-- 右侧表单区域 -->
9
+ <div class="right-panel">
10
+ <!-- 登录表单 -->
11
+ <div class="form-container sign-in-form" :class="{ active: !$Data.isSignUp }">
12
+ <h2 class="form-title">登录到 Befly</h2>
13
+
14
+ <!-- 邮箱登录 -->
15
+ <EmailLoginForm />
16
+ </div>
17
+
18
+ <!-- 注册表单 -->
19
+ <div class="form-container sign-up-form" :class="{ active: $Data.isSignUp }">
20
+ <h2 class="form-title">注册账号</h2>
21
+
22
+ <RegisterForm @success="$Method.handleRegisterSuccess" />
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </template>
27
+
28
+ <script setup>
29
+ import { ref } from 'vue';
30
+
31
+ import WelcomePanel from './components/welcomePanel.vue';
32
+ import EmailLoginForm from './components/emailLoginForm.vue';
33
+ import RegisterForm from './components/registerForm.vue';
34
+
35
+ // 数据定义
36
+ const $Data = $ref({
37
+ isSignUp: false
38
+ });
39
+
40
+ // 方法定义
41
+ const $Method = {
42
+ // 切换登录/注册模式
43
+ toggleMode() {
44
+ $Data.isSignUp = !$Data.isSignUp;
45
+ },
46
+
47
+ // 注册成功后切换到登录模式
48
+ handleRegisterSuccess() {
49
+ $Data.isSignUp = false;
50
+ }
51
+ };
52
+ </script>
53
+
54
+ <style scoped lang="scss">
55
+ .auth-container {
56
+ display: flex;
57
+ width: 100%;
58
+ min-height: 100vh;
59
+ overflow: hidden;
60
+ position: relative;
61
+ background: #fff;
62
+ }
63
+
64
+ // 青色滑动背景块
65
+ .left-panel {
66
+ position: absolute;
67
+ top: 0;
68
+ left: 0;
69
+ width: 50%;
70
+ height: 100%;
71
+ display: flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ background: linear-gradient(135deg, #48b19f 0%, #3a9d8f 100%);
75
+ color: #fff;
76
+ z-index: 5;
77
+ transition: transform 0.5s ease-in-out;
78
+ }
79
+
80
+ // 表单区域容器(全屏背景)
81
+ .right-panel {
82
+ position: absolute;
83
+ width: 100%;
84
+ height: 100%;
85
+ top: 0;
86
+ left: 0;
87
+ z-index: 1;
88
+ }
89
+
90
+ // 注册模式下青色块移动到右侧
91
+ .auth-container.sign-up-mode {
92
+ .left-panel {
93
+ transform: translateX(100%);
94
+ }
95
+ }
96
+
97
+ // 表单容器(跟随颜色区域滑动)
98
+ .form-container {
99
+ position: absolute;
100
+ width: 50%;
101
+ height: 100%;
102
+ top: 0;
103
+ display: flex;
104
+ flex-direction: column;
105
+ align-items: center;
106
+ justify-content: center;
107
+ padding: 3rem 2rem;
108
+ opacity: 0;
109
+ pointer-events: none;
110
+ transition: all 0.5s ease-in-out;
111
+
112
+ &.active {
113
+ opacity: 1;
114
+ pointer-events: all;
115
+ }
116
+ }
117
+
118
+ // 登录模式:登录表单在右侧
119
+ .auth-container:not(.sign-up-mode) {
120
+ .sign-in-form {
121
+ right: 0;
122
+ }
123
+
124
+ .sign-up-form {
125
+ left: 0;
126
+ }
127
+ }
128
+
129
+ // 注册模式:注册表单在左侧,登录表单在右侧
130
+ .auth-container.sign-up-mode {
131
+ .sign-in-form {
132
+ right: -50%;
133
+ }
134
+
135
+ .sign-up-form {
136
+ left: 0;
137
+ }
138
+ }
139
+
140
+ .form-title {
141
+ font-size: 1.8rem;
142
+ color: #333;
143
+ margin-bottom: 1.5rem;
144
+ font-weight: 600;
145
+ text-align: center;
146
+ width: 100%;
147
+ }
148
+
149
+ // 响应式设计
150
+ @media (max-width: 968px) {
151
+ .auth-container {
152
+ flex-direction: column;
153
+ }
154
+
155
+ .left-panel,
156
+ .right-panel {
157
+ flex: none;
158
+ width: 100%;
159
+ }
160
+
161
+ .left-panel {
162
+ order: 1 !important;
163
+ position: relative;
164
+ min-height: 200px;
165
+ }
166
+
167
+ .right-panel {
168
+ order: 2 !important;
169
+ min-height: 500px;
170
+ }
171
+
172
+ .form-container {
173
+ width: 100%;
174
+ padding: 2rem 1rem;
175
+ position: static;
176
+ }
177
+
178
+ .auth-container.sign-up-mode {
179
+ .left-panel {
180
+ transform: none;
181
+ }
182
+ }
183
+ }
184
+
185
+ @media (max-width: 576px) {
186
+ .form-title {
187
+ font-size: 1.5rem;
188
+ margin-bottom: 1.5rem;
189
+ }
190
+ }
191
+ </style>