@befly-addon/admin 1.1.29 → 1.1.31
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.
- package/apis/admin/cacheRefresh.ts +29 -24
- package/apis/admin/del.ts +12 -12
- package/apis/admin/detail.ts +9 -41
- package/apis/admin/ins.ts +28 -21
- package/apis/admin/list.ts +12 -12
- package/apis/admin/upd.ts +49 -14
- package/apis/api/all.ts +14 -10
- package/apis/api/list.ts +16 -25
- package/apis/auth/login.ts +55 -52
- package/apis/auth/sendSmsCode.ts +6 -6
- package/apis/dashboard/configStatus.ts +18 -18
- package/apis/dashboard/environmentInfo.ts +12 -12
- package/apis/dashboard/performanceMetrics.ts +5 -5
- package/apis/dashboard/permissionStats.ts +7 -7
- package/apis/dashboard/serviceStatus.ts +29 -29
- package/apis/dashboard/systemInfo.ts +5 -5
- package/apis/dashboard/systemOverview.ts +7 -7
- package/apis/dashboard/systemResources.ts +8 -8
- package/apis/dict/all.ts +24 -7
- package/apis/dict/del.ts +9 -17
- package/apis/dict/detail.ts +30 -16
- package/apis/dict/ins.ts +36 -18
- package/apis/dict/items.ts +27 -0
- package/apis/dict/list.ts +35 -10
- package/apis/dict/upd.ts +54 -20
- package/apis/dictType/all.ts +11 -0
- package/apis/dictType/del.ts +32 -0
- package/apis/dictType/detail.ts +17 -0
- package/apis/dictType/ins.ts +30 -0
- package/apis/dictType/list.ts +22 -0
- package/apis/dictType/upd.ts +42 -0
- package/apis/email/config.ts +4 -4
- package/apis/email/logList.ts +10 -10
- package/apis/email/send.ts +18 -18
- package/apis/email/verify.ts +5 -5
- package/apis/loginLog/list.ts +10 -10
- package/apis/menu/all.ts +17 -20
- package/apis/menu/list.ts +12 -13
- package/apis/operateLog/list.ts +10 -10
- package/apis/role/all.ts +7 -7
- package/apis/role/apiSave.ts +14 -16
- package/apis/role/apis.ts +24 -0
- package/apis/role/del.ts +27 -19
- package/apis/role/detail.ts +6 -7
- package/apis/role/ins.ts +10 -10
- package/apis/role/list.ts +11 -11
- package/apis/role/menuSave.ts +12 -14
- package/apis/role/menus.ts +24 -0
- package/apis/role/save.ts +14 -15
- package/apis/role/upd.ts +10 -10
- package/apis/sysConfig/all.ts +5 -6
- package/apis/sysConfig/del.ts +10 -10
- package/apis/sysConfig/get.ts +10 -11
- package/apis/sysConfig/ins.ts +11 -11
- package/apis/sysConfig/list.ts +9 -9
- package/apis/sysConfig/upd.ts +11 -11
- package/libs/emailHelper.ts +7 -7
- package/package.json +46 -34
- package/plugins/email.ts +9 -9
- package/tables/admin.json +0 -6
- package/tables/dict.json +13 -19
- package/tables/dictType.json +28 -0
- package/tables/role.json +4 -2
- package/views/403_1/index.vue +19 -3
- package/views/config/dict/components/edit.vue +76 -124
- package/views/config/dict/index.vue +142 -84
- package/views/config/dictType/components/edit.vue +105 -0
- package/views/config/dictType/index.vue +242 -0
- package/views/config/index.vue +12 -0
- package/views/config/system/components/edit.vue +36 -36
- package/views/config/system/index.vue +79 -50
- package/views/index/components/addonList.vue +3 -3
- package/views/index/components/environmentInfo.vue +10 -10
- package/views/index/components/operationLogs.vue +10 -10
- package/views/index/components/performanceMetrics.vue +8 -8
- package/views/index/components/quickActions.vue +3 -3
- package/views/index/components/serviceStatus.vue +19 -19
- package/views/index/components/systemNotifications.vue +12 -12
- package/views/index/components/systemOverview.vue +7 -7
- package/views/index/components/systemResources.vue +11 -11
- package/views/index/components/userInfo.vue +20 -19
- package/views/index/index.vue +12 -5
- package/views/log/email/index.vue +58 -51
- package/views/log/index.vue +12 -0
- package/views/log/login/index.vue +45 -38
- package/views/log/operate/index.vue +55 -48
- package/views/login_1/index.vue +191 -2
- package/views/people/admin/components/edit.vue +28 -29
- package/views/people/admin/index.vue +76 -40
- package/views/people/index.vue +12 -0
- package/views/permission/api/index.vue +21 -15
- package/views/permission/index.vue +12 -0
- package/views/permission/menu/index.vue +31 -16
- package/views/permission/role/components/api.vue +23 -23
- package/views/permission/role/components/edit.vue +18 -18
- package/views/permission/role/components/menu.vue +17 -19
- package/views/permission/role/index.vue +84 -49
- package/apis/admin/roleDetail.ts +0 -29
- package/apis/admin/roleSave.ts +0 -39
- package/apis/auth/logout.ts +0 -17
- package/apis/auth/register.ts +0 -43
- package/apis/dashboard/changelog.ts +0 -31
- package/apis/role/apiDetail.ts +0 -24
- package/apis/role/menuDetail.ts +0 -24
- package/views/403_1/meta.json +0 -4
- package/views/config/dict/meta.json +0 -4
- package/views/config/meta.json +0 -4
- package/views/config/system/meta.json +0 -4
- package/views/index/meta.json +0 -4
- package/views/log/email/meta.json +0 -4
- package/views/log/login/meta.json +0 -4
- package/views/log/meta.json +0 -4
- package/views/log/operate/meta.json +0 -4
- package/views/login_1/components/emailLoginForm.vue +0 -174
- package/views/login_1/components/registerForm.vue +0 -175
- package/views/login_1/components/welcomePanel.vue +0 -61
- package/views/login_1/meta.json +0 -4
- package/views/people/admin/meta.json +0 -4
- package/views/people/meta.json +0 -4
- package/views/permission/api/meta.json +0 -4
- package/views/permission/menu/meta.json +0 -4
- package/views/permission/meta.json +0 -4
- package/views/permission/role/meta.json +0 -4
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
{{ $Method.formatTime(row.loginTime) }}
|
|
23
23
|
</template>
|
|
24
24
|
<template #deviceType="{ row }">
|
|
25
|
-
<TTag shape="round" variant="light-outline">{{ row.deviceType ||
|
|
25
|
+
<TTag shape="round" variant="light-outline">{{ row.deviceType || "desktop" }}</TTag>
|
|
26
26
|
</template>
|
|
27
27
|
</TTable>
|
|
28
28
|
</div>
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
{{ $Method.formatTime(value) }}
|
|
38
38
|
</template>
|
|
39
39
|
<template #deviceType="{ value }">
|
|
40
|
-
<TTag shape="round" variant="light-outline">{{ value ||
|
|
40
|
+
<TTag shape="round" variant="light-outline">{{ value || "desktop" }}</TTag>
|
|
41
41
|
</template>
|
|
42
42
|
</DetailPanel>
|
|
43
43
|
</div>
|
|
@@ -50,43 +50,50 @@
|
|
|
50
50
|
</template>
|
|
51
51
|
|
|
52
52
|
<script setup>
|
|
53
|
-
import { Button as TButton, Table as TTable, Tag as TTag, Pagination as TPagination, MessagePlugin } from
|
|
54
|
-
import ILucideRotateCw from
|
|
55
|
-
import DetailPanel from
|
|
56
|
-
import { $Http } from
|
|
57
|
-
import { withDefaultColumns } from
|
|
53
|
+
import { Button as TButton, Table as TTable, Tag as TTag, Pagination as TPagination, MessagePlugin } from "tdesign-vue-next";
|
|
54
|
+
import ILucideRotateCw from "~icons/lucide/rotate-cw";
|
|
55
|
+
import DetailPanel from "@/components/DetailPanel.vue";
|
|
56
|
+
import { $Http } from "@/plugins/http";
|
|
57
|
+
import { withDefaultColumns } from "befly-vite/utils/withDefaultColumns";
|
|
58
|
+
|
|
59
|
+
definePage({
|
|
60
|
+
meta: {
|
|
61
|
+
title: "登录日志",
|
|
62
|
+
order: 1
|
|
63
|
+
}
|
|
64
|
+
});
|
|
58
65
|
|
|
59
66
|
// 响应式数据
|
|
60
67
|
const $Data = $ref({
|
|
61
68
|
tableData: [],
|
|
62
69
|
loading: false,
|
|
63
70
|
columns: withDefaultColumns([
|
|
64
|
-
{ colKey:
|
|
65
|
-
{ colKey:
|
|
66
|
-
{ colKey:
|
|
67
|
-
{ colKey:
|
|
68
|
-
{ colKey:
|
|
69
|
-
{ colKey:
|
|
70
|
-
{ colKey:
|
|
71
|
-
{ colKey:
|
|
71
|
+
{ colKey: "username", title: "用户名", fixed: "left" },
|
|
72
|
+
{ colKey: "id", title: "序号" },
|
|
73
|
+
{ colKey: "ip", title: "登录IP" },
|
|
74
|
+
{ colKey: "browserName", title: "浏览器" },
|
|
75
|
+
{ colKey: "osName", title: "操作系统" },
|
|
76
|
+
{ colKey: "deviceType", title: "设备类型" },
|
|
77
|
+
{ colKey: "loginTime", title: "登录时间" },
|
|
78
|
+
{ colKey: "loginResult", title: "登录结果" }
|
|
72
79
|
]),
|
|
73
80
|
// 详情面板显示更多字段
|
|
74
81
|
detailFields: [
|
|
75
|
-
{ colKey:
|
|
76
|
-
{ colKey:
|
|
77
|
-
{ colKey:
|
|
78
|
-
{ colKey:
|
|
79
|
-
{ colKey:
|
|
80
|
-
{ colKey:
|
|
81
|
-
{ colKey:
|
|
82
|
-
{ colKey:
|
|
83
|
-
{ colKey:
|
|
84
|
-
{ colKey:
|
|
85
|
-
{ colKey:
|
|
86
|
-
{ colKey:
|
|
87
|
-
{ colKey:
|
|
88
|
-
{ colKey:
|
|
89
|
-
{ colKey:
|
|
82
|
+
{ colKey: "username", title: "用户名" },
|
|
83
|
+
{ colKey: "nickname", title: "昵称" },
|
|
84
|
+
{ colKey: "ip", title: "登录IP" },
|
|
85
|
+
{ colKey: "browserName", title: "浏览器" },
|
|
86
|
+
{ colKey: "browserVersion", title: "浏览器版本" },
|
|
87
|
+
{ colKey: "osName", title: "操作系统" },
|
|
88
|
+
{ colKey: "osVersion", title: "系统版本" },
|
|
89
|
+
{ colKey: "deviceType", title: "设备类型" },
|
|
90
|
+
{ colKey: "deviceVendor", title: "设备厂商" },
|
|
91
|
+
{ colKey: "deviceModel", title: "设备型号" },
|
|
92
|
+
{ colKey: "engineName", title: "渲染引擎" },
|
|
93
|
+
{ colKey: "cpuArchitecture", title: "CPU架构" },
|
|
94
|
+
{ colKey: "loginTime", title: "登录时间" },
|
|
95
|
+
{ colKey: "loginResult", title: "登录结果" },
|
|
96
|
+
{ colKey: "failReason", title: "失败原因" }
|
|
90
97
|
],
|
|
91
98
|
pagerConfig: {
|
|
92
99
|
currentPage: 1,
|
|
@@ -107,7 +114,7 @@ const $Method = {
|
|
|
107
114
|
async apiLoginLogList() {
|
|
108
115
|
$Data.loading = true;
|
|
109
116
|
try {
|
|
110
|
-
const res = await $Http(
|
|
117
|
+
const res = await $Http("/addon/admin/loginLog/list", {
|
|
111
118
|
page: $Data.pagerConfig.currentPage,
|
|
112
119
|
limit: $Data.pagerConfig.limit
|
|
113
120
|
});
|
|
@@ -123,7 +130,7 @@ const $Method = {
|
|
|
123
130
|
$Data.activeRowKeys = [];
|
|
124
131
|
}
|
|
125
132
|
} catch (error) {
|
|
126
|
-
MessagePlugin.error(
|
|
133
|
+
MessagePlugin.error("加载数据失败");
|
|
127
134
|
} finally {
|
|
128
135
|
$Data.loading = false;
|
|
129
136
|
}
|
|
@@ -160,14 +167,14 @@ const $Method = {
|
|
|
160
167
|
|
|
161
168
|
// 格式化时间
|
|
162
169
|
formatTime(timestamp) {
|
|
163
|
-
if (!timestamp) return
|
|
170
|
+
if (!timestamp) return "-";
|
|
164
171
|
const date = new Date(timestamp);
|
|
165
172
|
const year = date.getFullYear();
|
|
166
|
-
const month = String(date.getMonth() + 1).padStart(2,
|
|
167
|
-
const day = String(date.getDate()).padStart(2,
|
|
168
|
-
const hours = String(date.getHours()).padStart(2,
|
|
169
|
-
const minutes = String(date.getMinutes()).padStart(2,
|
|
170
|
-
const seconds = String(date.getSeconds()).padStart(2,
|
|
173
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
174
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
175
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
176
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
177
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
171
178
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
172
179
|
}
|
|
173
180
|
};
|
|
@@ -70,41 +70,48 @@
|
|
|
70
70
|
</template>
|
|
71
71
|
|
|
72
72
|
<script setup>
|
|
73
|
-
import { Button as TButton, Table as TTable, Tag as TTag, Pagination as TPagination, Select as TSelect, Option as TOption, MessagePlugin } from
|
|
74
|
-
import ILucideRotateCw from
|
|
75
|
-
import DetailPanel from
|
|
76
|
-
import { $Http } from
|
|
77
|
-
import { withDefaultColumns } from
|
|
73
|
+
import { Button as TButton, Table as TTable, Tag as TTag, Pagination as TPagination, Select as TSelect, Option as TOption, MessagePlugin } from "tdesign-vue-next";
|
|
74
|
+
import ILucideRotateCw from "~icons/lucide/rotate-cw";
|
|
75
|
+
import DetailPanel from "@/components/DetailPanel.vue";
|
|
76
|
+
import { $Http } from "@/plugins/http";
|
|
77
|
+
import { withDefaultColumns } from "befly-vite/utils/withDefaultColumns";
|
|
78
|
+
|
|
79
|
+
definePage({
|
|
80
|
+
meta: {
|
|
81
|
+
title: "操作日志",
|
|
82
|
+
order: 3
|
|
83
|
+
}
|
|
84
|
+
});
|
|
78
85
|
|
|
79
86
|
// 响应式数据
|
|
80
87
|
const $Data = $ref({
|
|
81
88
|
tableData: [],
|
|
82
89
|
loading: false,
|
|
83
90
|
columns: withDefaultColumns([
|
|
84
|
-
{ colKey:
|
|
85
|
-
{ colKey:
|
|
86
|
-
{ colKey:
|
|
87
|
-
{ colKey:
|
|
88
|
-
{ colKey:
|
|
89
|
-
{ colKey:
|
|
90
|
-
{ colKey:
|
|
91
|
-
{ colKey:
|
|
92
|
-
{ colKey:
|
|
91
|
+
{ colKey: "username", title: "操作人", fixed: "left", width: 100 },
|
|
92
|
+
{ colKey: "id", title: "序号", width: 80 },
|
|
93
|
+
{ colKey: "module", title: "模块", width: 100 },
|
|
94
|
+
{ colKey: "action", title: "操作", width: 80 },
|
|
95
|
+
{ colKey: "path", title: "请求路径", ellipsis: true },
|
|
96
|
+
{ colKey: "ip", title: "IP地址", width: 130 },
|
|
97
|
+
{ colKey: "duration", title: "耗时", width: 100 },
|
|
98
|
+
{ colKey: "operateTime", title: "操作时间", width: 170 },
|
|
99
|
+
{ colKey: "result", title: "结果", width: 80 }
|
|
93
100
|
]),
|
|
94
101
|
detailFields: [
|
|
95
|
-
{ colKey:
|
|
96
|
-
{ colKey:
|
|
97
|
-
{ colKey:
|
|
98
|
-
{ colKey:
|
|
99
|
-
{ colKey:
|
|
100
|
-
{ colKey:
|
|
101
|
-
{ colKey:
|
|
102
|
-
{ colKey:
|
|
103
|
-
{ colKey:
|
|
104
|
-
{ colKey:
|
|
105
|
-
{ colKey:
|
|
106
|
-
{ colKey:
|
|
107
|
-
{ colKey:
|
|
102
|
+
{ colKey: "username", title: "操作人账号" },
|
|
103
|
+
{ colKey: "nickname", title: "操作人昵称" },
|
|
104
|
+
{ colKey: "module", title: "操作模块" },
|
|
105
|
+
{ colKey: "action", title: "操作类型" },
|
|
106
|
+
{ colKey: "method", title: "请求方法" },
|
|
107
|
+
{ colKey: "path", title: "请求路径" },
|
|
108
|
+
{ colKey: "ip", title: "IP地址" },
|
|
109
|
+
{ colKey: "params", title: "请求参数" },
|
|
110
|
+
{ colKey: "response", title: "响应内容" },
|
|
111
|
+
{ colKey: "duration", title: "耗时" },
|
|
112
|
+
{ colKey: "operateTime", title: "操作时间" },
|
|
113
|
+
{ colKey: "result", title: "操作结果" },
|
|
114
|
+
{ colKey: "remark", title: "备注" }
|
|
108
115
|
],
|
|
109
116
|
pagerConfig: {
|
|
110
117
|
currentPage: 1,
|
|
@@ -114,22 +121,22 @@ const $Data = $ref({
|
|
|
114
121
|
currentRow: null,
|
|
115
122
|
activeRowKeys: [],
|
|
116
123
|
filter: {
|
|
117
|
-
module:
|
|
118
|
-
action:
|
|
124
|
+
module: "",
|
|
125
|
+
action: "",
|
|
119
126
|
result: null
|
|
120
127
|
},
|
|
121
128
|
moduleOptions: [
|
|
122
|
-
{ label:
|
|
123
|
-
{ label:
|
|
124
|
-
{ label:
|
|
125
|
-
{ label:
|
|
126
|
-
{ label:
|
|
129
|
+
{ label: "管理员", value: "管理员" },
|
|
130
|
+
{ label: "角色", value: "角色" },
|
|
131
|
+
{ label: "菜单", value: "菜单" },
|
|
132
|
+
{ label: "接口", value: "接口" },
|
|
133
|
+
{ label: "字典", value: "字典" }
|
|
127
134
|
],
|
|
128
135
|
actionOptions: [
|
|
129
|
-
{ label:
|
|
130
|
-
{ label:
|
|
131
|
-
{ label:
|
|
132
|
-
{ label:
|
|
136
|
+
{ label: "新增", value: "新增" },
|
|
137
|
+
{ label: "编辑", value: "编辑" },
|
|
138
|
+
{ label: "删除", value: "删除" },
|
|
139
|
+
{ label: "查询", value: "查询" }
|
|
133
140
|
]
|
|
134
141
|
});
|
|
135
142
|
|
|
@@ -143,7 +150,7 @@ const $Method = {
|
|
|
143
150
|
async apiOperateLogList() {
|
|
144
151
|
$Data.loading = true;
|
|
145
152
|
try {
|
|
146
|
-
const res = await $Http(
|
|
153
|
+
const res = await $Http("/addon/admin/operateLog/list", {
|
|
147
154
|
page: $Data.pagerConfig.currentPage,
|
|
148
155
|
limit: $Data.pagerConfig.limit
|
|
149
156
|
});
|
|
@@ -158,7 +165,7 @@ const $Method = {
|
|
|
158
165
|
$Data.activeRowKeys = [];
|
|
159
166
|
}
|
|
160
167
|
} catch (error) {
|
|
161
|
-
MessagePlugin.error(
|
|
168
|
+
MessagePlugin.error("加载数据失败");
|
|
162
169
|
} finally {
|
|
163
170
|
$Data.loading = false;
|
|
164
171
|
}
|
|
@@ -201,22 +208,22 @@ const $Method = {
|
|
|
201
208
|
|
|
202
209
|
// 格式化时间
|
|
203
210
|
formatTime(timestamp) {
|
|
204
|
-
if (!timestamp) return
|
|
211
|
+
if (!timestamp) return "-";
|
|
205
212
|
const date = new Date(timestamp);
|
|
206
213
|
const year = date.getFullYear();
|
|
207
|
-
const month = String(date.getMonth() + 1).padStart(2,
|
|
208
|
-
const day = String(date.getDate()).padStart(2,
|
|
209
|
-
const hours = String(date.getHours()).padStart(2,
|
|
210
|
-
const minutes = String(date.getMinutes()).padStart(2,
|
|
211
|
-
const seconds = String(date.getSeconds()).padStart(2,
|
|
214
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
215
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
216
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
217
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
218
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
212
219
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
213
220
|
},
|
|
214
221
|
|
|
215
222
|
// 格式化 JSON
|
|
216
223
|
formatJson(value) {
|
|
217
|
-
if (!value) return
|
|
224
|
+
if (!value) return "-";
|
|
218
225
|
try {
|
|
219
|
-
const obj = typeof value ===
|
|
226
|
+
const obj = typeof value === "string" ? JSON.parse(value) : value;
|
|
220
227
|
return JSON.stringify(obj, null, 2);
|
|
221
228
|
} catch {
|
|
222
229
|
return value;
|
package/views/login_1/index.vue
CHANGED
|
@@ -21,7 +21,39 @@
|
|
|
21
21
|
<p class="login-subtitle">请登录您的账户</p>
|
|
22
22
|
</div>
|
|
23
23
|
|
|
24
|
-
<
|
|
24
|
+
<TForm :model="$Data.formData" :rules="$Data2.formRules" :ref="(el) => ($From.form = el)" class="login-form" :show-message="false" label-width="0">
|
|
25
|
+
<TFormItem prop="account">
|
|
26
|
+
<TInputAdornment>
|
|
27
|
+
<template #prepend>
|
|
28
|
+
<TSelect v-model="$Data.formData.loginType" :style="{ width: '110px' }" size="large" :popup-props="{ overlayClassName: 'login-type-select-popup' }">
|
|
29
|
+
<TOption value="username" label="用户名" />
|
|
30
|
+
<TOption value="email" label="邮箱" />
|
|
31
|
+
<TOption value="phone" label="手机号" />
|
|
32
|
+
</TSelect>
|
|
33
|
+
</template>
|
|
34
|
+
<TInput v-model="$Data.formData.account" :placeholder="$Data.formData.loginType === 'username' ? '请输入用户名' : $Data.formData.loginType === 'email' ? '请输入邮箱' : '请输入手机号'" size="large" clearable @enter="$Method.apiLogin">
|
|
35
|
+
<template #prefix-icon>
|
|
36
|
+
<ILucideUser />
|
|
37
|
+
</template>
|
|
38
|
+
</TInput>
|
|
39
|
+
</TInputAdornment>
|
|
40
|
+
</TFormItem>
|
|
41
|
+
|
|
42
|
+
<TFormItem prop="password">
|
|
43
|
+
<TInput v-model="$Data.formData.password" type="password" placeholder="密码" size="large" clearable @enter="$Method.apiLogin">
|
|
44
|
+
<template #prefix-icon>
|
|
45
|
+
<ILucideLock />
|
|
46
|
+
</template>
|
|
47
|
+
</TInput>
|
|
48
|
+
</TFormItem>
|
|
49
|
+
|
|
50
|
+
<div class="form-options">
|
|
51
|
+
<TCheckbox v-model="$Data.rememberMe">记住我</TCheckbox>
|
|
52
|
+
<a href="#" class="link-text">忘记密码?</a>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<TButton theme="primary" class="login-btn" size="large" block :loading="$Data.loading" @click="$Method.apiLogin"> 登录 </TButton>
|
|
56
|
+
</TForm>
|
|
25
57
|
|
|
26
58
|
<div class="login-footer">
|
|
27
59
|
<p class="copyright">© 2024 Befly. All rights reserved.</p>
|
|
@@ -32,7 +64,82 @@
|
|
|
32
64
|
</template>
|
|
33
65
|
|
|
34
66
|
<script setup>
|
|
35
|
-
import
|
|
67
|
+
import { useRouter } from "vue-router";
|
|
68
|
+
import { Form as TForm, FormItem as TFormItem, Input as TInput, Button as TButton, Checkbox as TCheckbox, InputAdornment as TInputAdornment, Select as TSelect, Option as TOption, MessagePlugin } from "tdesign-vue-next";
|
|
69
|
+
import ILucideUser from "~icons/lucide/user";
|
|
70
|
+
import ILucideLock from "~icons/lucide/lock";
|
|
71
|
+
import { $Http } from "@/plugins/http";
|
|
72
|
+
import { $Storage } from "@/plugins/storage";
|
|
73
|
+
import { hashPassword } from "befly-vite/utils/hashPassword";
|
|
74
|
+
|
|
75
|
+
definePage({
|
|
76
|
+
meta: {
|
|
77
|
+
title: "登录页",
|
|
78
|
+
order: 100
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const router = useRouter();
|
|
83
|
+
|
|
84
|
+
// 表单引用
|
|
85
|
+
const $From = $shallowRef({
|
|
86
|
+
form: null
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// 数据定义
|
|
90
|
+
const $Data = $ref({
|
|
91
|
+
loading: false,
|
|
92
|
+
rememberMe: false,
|
|
93
|
+
formData: {
|
|
94
|
+
loginType: "username",
|
|
95
|
+
account: "",
|
|
96
|
+
password: ""
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const $Data2 = $shallowRef({
|
|
101
|
+
formRules: {
|
|
102
|
+
account: [{ required: true, message: "请输入账号", trigger: "blur" }],
|
|
103
|
+
password: [{ required: true, message: "请输入密码", trigger: "blur" }]
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// 方法定义
|
|
108
|
+
const $Method = {
|
|
109
|
+
async apiLogin() {
|
|
110
|
+
try {
|
|
111
|
+
const valid = await $From.form.validate();
|
|
112
|
+
|
|
113
|
+
$Data.loading = true;
|
|
114
|
+
|
|
115
|
+
// 对密码进行 SHA-256 加密
|
|
116
|
+
const hashedPassword = await hashPassword($Data.formData.password);
|
|
117
|
+
|
|
118
|
+
const res = await $Http("/addon/admin/auth/login", {
|
|
119
|
+
loginType: $Data.formData.loginType,
|
|
120
|
+
account: $Data.formData.account,
|
|
121
|
+
password: hashedPassword
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// 先保存 token
|
|
125
|
+
$Storage.local.set("token", res.data.token);
|
|
126
|
+
|
|
127
|
+
// 如果返回用户信息,也可以存储
|
|
128
|
+
if (res.data.userInfo) {
|
|
129
|
+
$Storage.local.set("userInfo", res.data.userInfo);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
MessagePlugin.success(res.msg || "登录成功");
|
|
133
|
+
|
|
134
|
+
// 跳转到首页,路由守卫会自动加载菜单
|
|
135
|
+
await router.push("/");
|
|
136
|
+
} catch (error) {
|
|
137
|
+
MessagePlugin.error("登录失败");
|
|
138
|
+
} finally {
|
|
139
|
+
$Data.loading = false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
36
143
|
</script>
|
|
37
144
|
|
|
38
145
|
<style scoped lang="scss">
|
|
@@ -170,6 +277,88 @@ import EmailLoginForm from './components/emailLoginForm.vue';
|
|
|
170
277
|
color: var(--login-subtitle);
|
|
171
278
|
}
|
|
172
279
|
|
|
280
|
+
.login-form {
|
|
281
|
+
width: 100%;
|
|
282
|
+
|
|
283
|
+
:deep(.t-form__item) {
|
|
284
|
+
margin-bottom: 1.25rem;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
:deep(.t-form__controls) {
|
|
288
|
+
width: 100%;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
:deep(.t-input-adornment) {
|
|
292
|
+
width: 100%;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
:deep(.t-input-adornment__prepend) {
|
|
296
|
+
padding: 0;
|
|
297
|
+
border-right: 1px solid var(--login-card-border);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
:deep(.t-input) {
|
|
301
|
+
width: 100%;
|
|
302
|
+
border-radius: 8px;
|
|
303
|
+
transition: all 0.3s;
|
|
304
|
+
|
|
305
|
+
&:hover {
|
|
306
|
+
border-color: #667eea;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
&:focus-within {
|
|
310
|
+
border-color: #667eea;
|
|
311
|
+
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
:deep(.t-input__wrap) {
|
|
316
|
+
width: 100%;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.form-options {
|
|
321
|
+
display: flex;
|
|
322
|
+
justify-content: space-between;
|
|
323
|
+
align-items: center;
|
|
324
|
+
margin-bottom: 1.5rem;
|
|
325
|
+
font-size: 0.875rem;
|
|
326
|
+
|
|
327
|
+
.link-text {
|
|
328
|
+
color: var(--login-link);
|
|
329
|
+
text-decoration: none;
|
|
330
|
+
transition: color 0.3s;
|
|
331
|
+
|
|
332
|
+
&:hover {
|
|
333
|
+
color: var(--login-link-hover);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.login-btn {
|
|
339
|
+
width: 100%;
|
|
340
|
+
height: 48px;
|
|
341
|
+
border-radius: 8px;
|
|
342
|
+
font-size: 1rem;
|
|
343
|
+
font-weight: 600;
|
|
344
|
+
background: linear-gradient(135deg, var(--login-btn-gradient-start) 0%, var(--login-btn-gradient-end) 100%);
|
|
345
|
+
border: none;
|
|
346
|
+
transition: all 0.3s;
|
|
347
|
+
|
|
348
|
+
&:hover {
|
|
349
|
+
transform: translateY(-2px);
|
|
350
|
+
box-shadow: 0 8px 20px var(--login-btn-shadow);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
&:active {
|
|
354
|
+
transform: translateY(0);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
:deep(.t-button__text) {
|
|
358
|
+
color: #fff;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
173
362
|
// 响应式设计
|
|
174
363
|
@media (max-width: 1024px) {
|
|
175
364
|
.login-container {
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
<TDialog v-model:visible="$Data.visible" :header="$Prop.actionType === 'upd' ? '编辑管理员' : '添加管理员'" width="600px" :append-to-body="true" :show-footer="true" :esc-closable="false" top="10vh" @close="$Method.onClose">
|
|
3
3
|
<div class="dialog-wrapper">
|
|
4
4
|
<TForm :model="$Data.formData" label-width="80px" label-position="left" label-align="left" :rules="$Data2.formRules" :ref="(el) => ($From.form = el)">
|
|
5
|
-
<TFormItem label="角色" prop="
|
|
6
|
-
<TSelect v-model="$Data.formData.
|
|
5
|
+
<TFormItem label="角色" prop="roleCode">
|
|
6
|
+
<TSelect v-model="$Data.formData.roleCode" :options="$Data.allRoleLists" :keys="$Data.keys" placeholder="请选择角色" />
|
|
7
7
|
</TFormItem>
|
|
8
8
|
<TFormItem label="用户名" prop="username">
|
|
9
9
|
<TInput v-model="$Data.formData.username" placeholder="请输入用户名" :disabled="$Prop.actionType === 'upd'" />
|
|
@@ -45,10 +45,10 @@ import {
|
|
|
45
45
|
Radio as TRadio,
|
|
46
46
|
Button as TButton,
|
|
47
47
|
MessagePlugin
|
|
48
|
-
} from
|
|
49
|
-
import { $Http } from
|
|
50
|
-
import { fieldClear } from
|
|
51
|
-
import { hashPassword } from
|
|
48
|
+
} from "tdesign-vue-next";
|
|
49
|
+
import { $Http } from "@/plugins/http";
|
|
50
|
+
import { fieldClear } from "befly-vite/utils/fieldClear";
|
|
51
|
+
import { hashPassword } from "befly-vite/utils/hashPassword";
|
|
52
52
|
|
|
53
53
|
const $Prop = defineProps({
|
|
54
54
|
modelValue: {
|
|
@@ -57,7 +57,7 @@ const $Prop = defineProps({
|
|
|
57
57
|
},
|
|
58
58
|
actionType: {
|
|
59
59
|
type: String,
|
|
60
|
-
default:
|
|
60
|
+
default: "add"
|
|
61
61
|
},
|
|
62
62
|
rowData: {
|
|
63
63
|
type: Object,
|
|
@@ -65,7 +65,7 @@ const $Prop = defineProps({
|
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
const $Emit = defineEmits([
|
|
68
|
+
const $Emit = defineEmits(["update:modelValue", "success"]);
|
|
69
69
|
|
|
70
70
|
// 表单引用
|
|
71
71
|
const $From = $shallowRef({
|
|
@@ -77,28 +77,28 @@ const $Data = $ref({
|
|
|
77
77
|
submitting: false,
|
|
78
78
|
allRoleLists: [],
|
|
79
79
|
keys: {
|
|
80
|
-
label:
|
|
81
|
-
value:
|
|
80
|
+
label: "name",
|
|
81
|
+
value: "code"
|
|
82
82
|
},
|
|
83
83
|
formData: {
|
|
84
84
|
id: null,
|
|
85
|
-
username:
|
|
86
|
-
password:
|
|
87
|
-
nickname:
|
|
88
|
-
|
|
85
|
+
username: "",
|
|
86
|
+
password: "",
|
|
87
|
+
nickname: "",
|
|
88
|
+
roleCode: null,
|
|
89
89
|
state: 1
|
|
90
90
|
}
|
|
91
91
|
});
|
|
92
92
|
|
|
93
93
|
const $Data2 = $shallowRef({
|
|
94
94
|
formRules: {
|
|
95
|
-
username: [{ required: true, message:
|
|
95
|
+
username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
|
|
96
96
|
password: [
|
|
97
|
-
{ required: true, message:
|
|
98
|
-
{ min: 6, message:
|
|
97
|
+
{ required: true, message: "请输入密码", trigger: "blur" },
|
|
98
|
+
{ min: 6, message: "密码至少6位", trigger: "blur" }
|
|
99
99
|
],
|
|
100
|
-
|
|
101
|
-
nickname: [{ min: 2, max: 50, message:
|
|
100
|
+
roleCode: [{ required: true, message: "请选择角色", trigger: "change" }],
|
|
101
|
+
nickname: [{ min: 2, max: 50, message: "昵称长度在 2 到 50 个字符", trigger: "blur" }]
|
|
102
102
|
}
|
|
103
103
|
});
|
|
104
104
|
|
|
@@ -107,7 +107,7 @@ const $Method = {
|
|
|
107
107
|
async initData() {
|
|
108
108
|
$Method.onShow();
|
|
109
109
|
await $Method.apiRoleLists();
|
|
110
|
-
if ($Prop.actionType ===
|
|
110
|
+
if ($Prop.actionType === "upd" && $Prop.rowData.id) {
|
|
111
111
|
$Data.formData = { ...$Prop.rowData };
|
|
112
112
|
}
|
|
113
113
|
},
|
|
@@ -121,17 +121,16 @@ const $Method = {
|
|
|
121
121
|
onClose() {
|
|
122
122
|
$Data.visible = false;
|
|
123
123
|
setTimeout(() => {
|
|
124
|
-
$Emit(
|
|
124
|
+
$Emit("update:modelValue", false);
|
|
125
125
|
}, 300);
|
|
126
126
|
},
|
|
127
127
|
|
|
128
128
|
async apiRoleLists() {
|
|
129
129
|
try {
|
|
130
|
-
const result = await $Http(
|
|
130
|
+
const result = await $Http("/addon/admin/role/all");
|
|
131
131
|
$Data.allRoleLists = result.data || [];
|
|
132
132
|
} catch (error) {
|
|
133
|
-
|
|
134
|
-
MessagePlugin.error('加载角色列表失败');
|
|
133
|
+
MessagePlugin.error("加载角色列表失败");
|
|
135
134
|
}
|
|
136
135
|
},
|
|
137
136
|
|
|
@@ -141,20 +140,20 @@ const $Method = {
|
|
|
141
140
|
if (!valid) return;
|
|
142
141
|
|
|
143
142
|
$Data.submitting = true;
|
|
144
|
-
const formData = $Prop.actionType ===
|
|
143
|
+
const formData = $Prop.actionType === "add" ? fieldClear($Data.formData, { omitKeys: ["id", "state"] }) : fieldClear($Data.formData, { omitKeys: ["password"] });
|
|
145
144
|
|
|
146
145
|
// 添加管理员时,对密码进行 SHA-256 加密
|
|
147
|
-
if ($Prop.actionType ===
|
|
146
|
+
if ($Prop.actionType === "add" && formData.password) {
|
|
148
147
|
formData.password = await hashPassword(formData.password);
|
|
149
148
|
}
|
|
150
149
|
|
|
151
|
-
const result = await $Http($Prop.actionType ===
|
|
150
|
+
const result = await $Http($Prop.actionType === "upd" ? "/addon/admin/admin/upd" : "/addon/admin/admin/ins", formData);
|
|
152
151
|
|
|
153
152
|
MessagePlugin.success(result.msg);
|
|
154
|
-
$Emit(
|
|
153
|
+
$Emit("success");
|
|
155
154
|
$Method.onClose();
|
|
156
155
|
} catch (error) {
|
|
157
|
-
MessagePlugin.error(error.msg ||
|
|
156
|
+
MessagePlugin.error(error.msg || "提交失败");
|
|
158
157
|
} finally {
|
|
159
158
|
$Data.submitting = false;
|
|
160
159
|
}
|