befly-admin-ui 1.10.1 → 1.10.2
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/components/detailPanel.vue +52 -54
- package/components/pageDialog.vue +131 -117
- package/components/pageTableDetail.vue +381 -402
- package/layouts/default.vue +212 -215
- package/package.json +2 -2
- package/views/config/dict/components/edit.vue +83 -60
- package/views/config/dict/index.vue +51 -55
- package/views/config/dictType/components/edit.vue +81 -57
- package/views/config/dictType/index.vue +37 -39
- package/views/config/system/components/edit.vue +97 -86
- package/views/config/system/index.vue +35 -37
- package/views/index/components/addonList.vue +14 -11
- package/views/index/components/environmentInfo.vue +25 -22
- package/views/index/components/operationLogs.vue +20 -16
- package/views/index/components/performanceMetrics.vue +24 -21
- package/views/index/components/serviceStatus.vue +26 -22
- package/views/index/components/systemNotifications.vue +24 -19
- package/views/index/components/systemOverview.vue +368 -385
- package/views/index/components/systemResources.vue +22 -19
- package/views/index/components/userInfo.vue +56 -56
- package/views/log/email/index.vue +96 -85
- package/views/log/error/index.vue +111 -117
- package/views/log/login/index.vue +15 -13
- package/views/log/operate/index.vue +31 -31
- package/views/login_1/index.vue +50 -32
- package/views/people/admin/components/edit.vue +1 -1
- package/views/people/admin/index.vue +27 -28
- package/views/permission/api/index.vue +44 -45
- package/views/permission/menu/index.vue +35 -35
- package/views/permission/role/components/api.vue +143 -144
- package/views/permission/role/components/edit.vue +74 -52
- package/views/permission/role/components/menu.vue +119 -121
- package/views/permission/role/index.vue +47 -49
- package/views/resource/gallery/index.vue +77 -78
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<PageTableDetail class="page-error-log page-table" :columns="$Data.columns" :endpoints="$Data.endpoints" :table-slot-names="['errorType', 'reportTime', 'firstReportTime', 'source', 'message', 'hitCount', 'deviceType']">
|
|
3
3
|
<template #toolLeft="scope">
|
|
4
|
-
<TInput v-model="$Data.filter.keyword" clearable placeholder="搜索页面/产品/消息/类型" style="width: 220px" @enter="handleFilter(scope.reload)" @clear="handleFilter(scope.reload)">
|
|
4
|
+
<TInput v-model="$Data.filter.keyword" clearable placeholder="搜索页面/产品/消息/类型" style="width: 220px" @enter="$Method.handleFilter(scope.reload)" @clear="$Method.handleFilter(scope.reload)">
|
|
5
5
|
<template #suffix-icon>
|
|
6
6
|
<SearchIcon />
|
|
7
7
|
</template>
|
|
8
8
|
</TInput>
|
|
9
|
-
<TSelect v-model="$Data.filter.errorType" clearable placeholder="错误类型" style="width: 150px" @change="handleFilter(scope.reload)">
|
|
9
|
+
<TSelect v-model="$Data.filter.errorType" clearable placeholder="错误类型" style="width: 150px" @change="$Method.handleFilter(scope.reload)">
|
|
10
10
|
<TOption label="Vue" value="vue" />
|
|
11
11
|
<TOption label="Window" value="window" />
|
|
12
12
|
<TOption label="Promise" value="promise" />
|
|
13
13
|
<TOption label="Unknown" value="unknown" />
|
|
14
14
|
</TSelect>
|
|
15
|
-
<TSelect v-model="$Data.filter.source" clearable placeholder="来源" style="width: 140px" @change="handleFilter(scope.reload)">
|
|
15
|
+
<TSelect v-model="$Data.filter.source" clearable placeholder="来源" style="width: 140px" @change="$Method.handleFilter(scope.reload)">
|
|
16
16
|
<TOption label="Admin" value="admin" />
|
|
17
17
|
</TSelect>
|
|
18
|
-
<TInput v-model="$Data.filter.productName" clearable placeholder="产品名称" style="width: 160px" @enter="handleFilter(scope.reload)" @clear="handleFilter(scope.reload)" />
|
|
19
|
-
<TInput v-model="$Data.filter.productCode" clearable placeholder="产品代号" style="width: 160px" @enter="handleFilter(scope.reload)" @clear="handleFilter(scope.reload)" />
|
|
20
|
-
<TInput v-model="$Data.filter.productVersion" clearable placeholder="产品版本" style="width: 160px" @enter="handleFilter(scope.reload)" @clear="handleFilter(scope.reload)" />
|
|
21
|
-
<TSelect v-model="$Data.filter.deviceType" clearable placeholder="设备类型" style="width: 140px" @change="handleFilter(scope.reload)">
|
|
18
|
+
<TInput v-model="$Data.filter.productName" clearable placeholder="产品名称" style="width: 160px" @enter="$Method.handleFilter(scope.reload)" @clear="$Method.handleFilter(scope.reload)" />
|
|
19
|
+
<TInput v-model="$Data.filter.productCode" clearable placeholder="产品代号" style="width: 160px" @enter="$Method.handleFilter(scope.reload)" @clear="$Method.handleFilter(scope.reload)" />
|
|
20
|
+
<TInput v-model="$Data.filter.productVersion" clearable placeholder="产品版本" style="width: 160px" @enter="$Method.handleFilter(scope.reload)" @clear="$Method.handleFilter(scope.reload)" />
|
|
21
|
+
<TSelect v-model="$Data.filter.deviceType" clearable placeholder="设备类型" style="width: 140px" @change="$Method.handleFilter(scope.reload)">
|
|
22
22
|
<TOption label="桌面端" value="desktop" />
|
|
23
23
|
<TOption label="移动端" value="mobile" />
|
|
24
24
|
<TOption label="平板" value="tablet" />
|
|
25
25
|
<TOption label="电视" value="smarttv" />
|
|
26
26
|
</TSelect>
|
|
27
|
-
<TInput v-model="$Data.filter.browserName" clearable placeholder="浏览器" style="width: 160px" @enter="handleFilter(scope.reload)" @clear="handleFilter(scope.reload)" />
|
|
28
|
-
<TInput v-model="$Data.filter.osName" clearable placeholder="操作系统" style="width: 160px" @enter="handleFilter(scope.reload)" @clear="handleFilter(scope.reload)" />
|
|
27
|
+
<TInput v-model="$Data.filter.browserName" clearable placeholder="浏览器" style="width: 160px" @enter="$Method.handleFilter(scope.reload)" @clear="$Method.handleFilter(scope.reload)" />
|
|
28
|
+
<TInput v-model="$Data.filter.osName" clearable placeholder="操作系统" style="width: 160px" @enter="$Method.handleFilter(scope.reload)" @clear="$Method.handleFilter(scope.reload)" />
|
|
29
29
|
</template>
|
|
30
30
|
|
|
31
31
|
<template #errorType="{ row }">
|
|
32
|
-
<TTag shape="round" :theme="getErrorTheme(row.errorType)" variant="light-outline">{{ formatErrorType(row.errorType) }}</TTag>
|
|
32
|
+
<TTag shape="round" :theme="$Method.getErrorTheme(row.errorType)" variant="light-outline">{{ $Method.formatErrorType(row.errorType) }}</TTag>
|
|
33
33
|
</template>
|
|
34
34
|
|
|
35
35
|
<template #reportTime="{ row }">
|
|
36
|
-
{{ formatTime(row.reportTime) }}
|
|
36
|
+
{{ $Method.formatTime(row.reportTime) }}
|
|
37
37
|
</template>
|
|
38
38
|
|
|
39
39
|
<template #firstReportTime="{ row }">
|
|
40
|
-
{{ formatTime(row.firstReportTime) }}
|
|
40
|
+
{{ $Method.formatTime(row.firstReportTime) }}
|
|
41
41
|
</template>
|
|
42
42
|
|
|
43
43
|
<template #source="{ row }">
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
</template>
|
|
50
50
|
|
|
51
51
|
<template #deviceType="{ row }">
|
|
52
|
-
<TTag shape="round" variant="light-outline">{{ formatDeviceType(row.deviceType) }}</TTag>
|
|
52
|
+
<TTag shape="round" variant="light-outline">{{ $Method.formatDeviceType(row.deviceType) }}</TTag>
|
|
53
53
|
</template>
|
|
54
54
|
|
|
55
55
|
<template #message="{ row }">
|
|
@@ -59,13 +59,13 @@
|
|
|
59
59
|
<template #detail="scope">
|
|
60
60
|
<DetailPanel :data="scope.row" :fields="$Data.columns">
|
|
61
61
|
<template #errorType="slotScope">
|
|
62
|
-
<TTag shape="round" :theme="getErrorTheme(slotScope.value)" variant="light-outline">{{ formatErrorType(slotScope.value) }}</TTag>
|
|
62
|
+
<TTag shape="round" :theme="$Method.getErrorTheme(slotScope.value)" variant="light-outline">{{ $Method.formatErrorType(slotScope.value) }}</TTag>
|
|
63
63
|
</template>
|
|
64
64
|
<template #reportTime="slotScope">
|
|
65
|
-
{{ formatTime(slotScope.value) }}
|
|
65
|
+
{{ $Method.formatTime(slotScope.value) }}
|
|
66
66
|
</template>
|
|
67
67
|
<template #firstReportTime="slotScope">
|
|
68
|
-
{{ formatTime(slotScope.value) }}
|
|
68
|
+
{{ $Method.formatTime(slotScope.value) }}
|
|
69
69
|
</template>
|
|
70
70
|
<template #source="slotScope">
|
|
71
71
|
<TTag shape="round" variant="light-outline">{{ slotScope.value || "admin" }}</TTag>
|
|
@@ -74,16 +74,16 @@
|
|
|
74
74
|
<TTag shape="round" theme="warning" variant="light-outline">{{ slotScope.value || 1 }} 次</TTag>
|
|
75
75
|
</template>
|
|
76
76
|
<template #deviceType="slotScope">
|
|
77
|
-
<TTag shape="round" variant="light-outline">{{ formatDeviceType(slotScope.value) }}</TTag>
|
|
77
|
+
<TTag shape="round" variant="light-outline">{{ $Method.formatDeviceType(slotScope.value) }}</TTag>
|
|
78
78
|
</template>
|
|
79
79
|
<template #detail="slotScope">
|
|
80
80
|
<div class="detail-actions">
|
|
81
|
-
<TButton theme="primary" variant="outline" size="small" @click="handleCopyDetail(scope.row.detail)">复制详情</TButton>
|
|
82
|
-
<TButton theme="default" variant="outline" size="small" @click="toggleDetailExpand(scope.row.id)">
|
|
83
|
-
{{ isDetailExpanded(scope.row.id) ? "收起详情" : "展开详情" }}
|
|
81
|
+
<TButton theme="primary" variant="outline" size="small" @click="$Method.handleCopyDetail(scope.row.detail)">复制详情</TButton>
|
|
82
|
+
<TButton theme="default" variant="outline" size="small" @click="$Method.toggleDetailExpand(scope.row.id)">
|
|
83
|
+
{{ $Method.isDetailExpanded(scope.row.id) ? "收起详情" : "展开详情" }}
|
|
84
84
|
</TButton>
|
|
85
85
|
</div>
|
|
86
|
-
<pre class="detail-content" :class="{ expanded: isDetailExpanded(scope.row.id) }">{{ formatDetail(slotScope.value) }}</pre>
|
|
86
|
+
<pre class="detail-content" :class="{ expanded: $Method.isDetailExpanded(scope.row.id) }">{{ $Method.formatDetail(slotScope.value) }}</pre>
|
|
87
87
|
</template>
|
|
88
88
|
</DetailPanel>
|
|
89
89
|
</template>
|
|
@@ -169,121 +169,115 @@ const $Data = reactive({
|
|
|
169
169
|
detailExpandedId: 0
|
|
170
170
|
});
|
|
171
171
|
|
|
172
|
-
|
|
173
|
-
reload
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const nextId = Number(id || 0);
|
|
182
|
-
|
|
183
|
-
if (Number($Data.detailExpandedId) === nextId) {
|
|
184
|
-
$Data.detailExpandedId = 0;
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
$Data.detailExpandedId = nextId;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
async function handleCopyDetail(value) {
|
|
192
|
-
const text = formatDetail(value);
|
|
193
|
-
if (text === "-") {
|
|
194
|
-
MessagePlugin.warning("暂无可复制的错误详情");
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
try {
|
|
199
|
-
await navigator.clipboard.writeText(text);
|
|
200
|
-
MessagePlugin.success("错误详情已复制");
|
|
201
|
-
} catch (_error) {
|
|
202
|
-
MessagePlugin.error("复制失败,请检查浏览器剪贴板权限");
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function getErrorTheme(errorType) {
|
|
207
|
-
if (errorType === "vue") {
|
|
208
|
-
return "danger";
|
|
209
|
-
}
|
|
172
|
+
const $Method = {
|
|
173
|
+
handleFilter(reload) {
|
|
174
|
+
reload({ keepSelection: false, resetPage: true });
|
|
175
|
+
},
|
|
176
|
+
isDetailExpanded(id) {
|
|
177
|
+
return Number($Data.detailExpandedId) === Number(id || 0);
|
|
178
|
+
},
|
|
179
|
+
toggleDetailExpand(id) {
|
|
180
|
+
const nextId = Number(id || 0);
|
|
210
181
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
182
|
+
if (Number($Data.detailExpandedId) === nextId) {
|
|
183
|
+
$Data.detailExpandedId = 0;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
214
186
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
187
|
+
$Data.detailExpandedId = nextId;
|
|
188
|
+
},
|
|
189
|
+
async handleCopyDetail(value) {
|
|
190
|
+
const text = $Method.formatDetail(value);
|
|
191
|
+
if (text === "-") {
|
|
192
|
+
MessagePlugin.warning("暂无可复制的错误详情");
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
218
195
|
|
|
219
|
-
|
|
220
|
-
|
|
196
|
+
try {
|
|
197
|
+
await navigator.clipboard.writeText(text);
|
|
198
|
+
MessagePlugin.success("错误详情已复制");
|
|
199
|
+
} catch (_error) {
|
|
200
|
+
MessagePlugin.error("复制失败,请检查浏览器剪贴板权限");
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
getErrorTheme(errorType) {
|
|
204
|
+
if (errorType === "vue") {
|
|
205
|
+
return "danger";
|
|
206
|
+
}
|
|
221
207
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
208
|
+
if (errorType === "promise") {
|
|
209
|
+
return "warning";
|
|
210
|
+
}
|
|
226
211
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
212
|
+
if (errorType === "window") {
|
|
213
|
+
return "primary";
|
|
214
|
+
}
|
|
230
215
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
216
|
+
return "default";
|
|
217
|
+
},
|
|
218
|
+
formatErrorType(errorType) {
|
|
219
|
+
if (errorType === "vue") {
|
|
220
|
+
return "Vue";
|
|
221
|
+
}
|
|
234
222
|
|
|
235
|
-
|
|
236
|
-
|
|
223
|
+
if (errorType === "window") {
|
|
224
|
+
return "Window";
|
|
225
|
+
}
|
|
237
226
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
227
|
+
if (errorType === "promise") {
|
|
228
|
+
return "Promise";
|
|
229
|
+
}
|
|
242
230
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
231
|
+
return errorType || "Unknown";
|
|
232
|
+
},
|
|
233
|
+
formatDeviceType(deviceType) {
|
|
234
|
+
if (deviceType === "desktop") {
|
|
235
|
+
return "桌面端";
|
|
236
|
+
}
|
|
246
237
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
238
|
+
if (deviceType === "mobile") {
|
|
239
|
+
return "移动端";
|
|
240
|
+
}
|
|
250
241
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
242
|
+
if (deviceType === "tablet") {
|
|
243
|
+
return "平板";
|
|
244
|
+
}
|
|
254
245
|
|
|
255
|
-
|
|
256
|
-
|
|
246
|
+
if (deviceType === "smarttv") {
|
|
247
|
+
return "电视";
|
|
248
|
+
}
|
|
257
249
|
|
|
258
|
-
|
|
259
|
-
|
|
250
|
+
return deviceType || "Unknown";
|
|
251
|
+
},
|
|
252
|
+
formatTime(timestamp) {
|
|
253
|
+
const value = Number(timestamp || 0);
|
|
260
254
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
255
|
+
if (!value) {
|
|
256
|
+
return "-";
|
|
257
|
+
}
|
|
264
258
|
|
|
265
|
-
|
|
259
|
+
const date = new Date(value);
|
|
266
260
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
261
|
+
if (Number.isNaN(date.getTime())) {
|
|
262
|
+
return "-";
|
|
263
|
+
}
|
|
270
264
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
265
|
+
const year = date.getFullYear();
|
|
266
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
267
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
268
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
269
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
270
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
271
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
272
|
+
},
|
|
273
|
+
formatDetail(value) {
|
|
274
|
+
if (!value) {
|
|
275
|
+
return "-";
|
|
276
|
+
}
|
|
279
277
|
|
|
280
|
-
|
|
281
|
-
if (!value) {
|
|
282
|
-
return "-";
|
|
278
|
+
return String(value);
|
|
283
279
|
}
|
|
284
|
-
|
|
285
|
-
return String(value);
|
|
286
|
-
}
|
|
280
|
+
};
|
|
287
281
|
</script>
|
|
288
282
|
|
|
289
283
|
<style scoped lang="scss">
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
</template>
|
|
7
7
|
|
|
8
8
|
<template #loginTime="{ row }">
|
|
9
|
-
{{ formatTime(row.loginTime) }}
|
|
9
|
+
{{ $Method.formatTime(row.loginTime) }}
|
|
10
10
|
</template>
|
|
11
11
|
|
|
12
12
|
<template #deviceType="{ row }">
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
<TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
|
|
21
21
|
</template>
|
|
22
22
|
<template #loginTime="slotScope">
|
|
23
|
-
{{ formatTime(slotScope.value) }}
|
|
23
|
+
{{ $Method.formatTime(slotScope.value) }}
|
|
24
24
|
</template>
|
|
25
25
|
<template #deviceType="slotScope">
|
|
26
26
|
<TTag shape="round" variant="light-outline">{{ slotScope.value || "desktop" }}</TTag>
|
|
@@ -65,17 +65,19 @@ const $Data = reactive({
|
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
68
|
+
const $Method = {
|
|
69
|
+
formatTime(timestamp) {
|
|
70
|
+
if (!timestamp) return "-";
|
|
71
|
+
const date = new Date(timestamp);
|
|
72
|
+
const year = date.getFullYear();
|
|
73
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
74
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
75
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
76
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
77
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
78
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
79
81
|
</script>
|
|
80
82
|
|
|
81
83
|
<style scoped lang="scss">
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<PageTableDetail class="page-operate-log page-table" :columns="$Data.columns" :endpoints="$Data.endpoints" :table-slot-names="['result', 'operateTime', 'duration', 'action']">
|
|
3
3
|
<template #toolLeft="scope">
|
|
4
|
-
<TSelect v-model="$Data.filter.module" placeholder="操作模块" clearable style="width: 150px" @change="handleFilter(scope.reload)">
|
|
4
|
+
<TSelect v-model="$Data.filter.module" placeholder="操作模块" clearable style="width: 150px" @change="$Method.handleFilter(scope.reload)">
|
|
5
5
|
<TOption v-for="item in $Data.moduleOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
6
6
|
</TSelect>
|
|
7
|
-
<TSelect v-model="$Data.filter.action" placeholder="操作类型" clearable style="width: 150px" @change="handleFilter(scope.reload)">
|
|
7
|
+
<TSelect v-model="$Data.filter.action" placeholder="操作类型" clearable style="width: 150px" @change="$Method.handleFilter(scope.reload)">
|
|
8
8
|
<TOption v-for="item in $Data.actionOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
9
9
|
</TSelect>
|
|
10
|
-
<TSelect v-model="$Data.filter.result" placeholder="操作结果" clearable style="width: 120px" @change="handleFilter(scope.reload)">
|
|
10
|
+
<TSelect v-model="$Data.filter.result" placeholder="操作结果" clearable style="width: 120px" @change="$Method.handleFilter(scope.reload)">
|
|
11
11
|
<TOption label="成功" :value="1" />
|
|
12
12
|
<TOption label="失败" :value="0" />
|
|
13
13
|
</TSelect>
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
</template>
|
|
20
20
|
|
|
21
21
|
<template #operateTime="{ row }">
|
|
22
|
-
{{ formatTime(row.operateTime) }}
|
|
22
|
+
{{ $Method.formatTime(row.operateTime) }}
|
|
23
23
|
</template>
|
|
24
24
|
|
|
25
25
|
<template #duration="{ row }">
|
|
@@ -37,16 +37,16 @@
|
|
|
37
37
|
<TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
|
|
38
38
|
</template>
|
|
39
39
|
<template #operateTime="slotScope">
|
|
40
|
-
{{ formatTime(slotScope.value) }}
|
|
40
|
+
{{ $Method.formatTime(slotScope.value) }}
|
|
41
41
|
</template>
|
|
42
42
|
<template #duration="slotScope">
|
|
43
43
|
<TTag shape="round" :theme="slotScope.value > 1000 ? 'warning' : 'default'" variant="light-outline">{{ slotScope.value }}ms</TTag>
|
|
44
44
|
</template>
|
|
45
45
|
<template #params="slotScope">
|
|
46
|
-
<pre class="json-content">{{ formatJson(slotScope.value) }}</pre>
|
|
46
|
+
<pre class="json-content">{{ $Method.formatJson(slotScope.value) }}</pre>
|
|
47
47
|
</template>
|
|
48
48
|
<template #response="slotScope">
|
|
49
|
-
<pre class="json-content">{{ formatJson(slotScope.value) }}</pre>
|
|
49
|
+
<pre class="json-content">{{ $Method.formatJson(slotScope.value) }}</pre>
|
|
50
50
|
</template>
|
|
51
51
|
</DetailPanel>
|
|
52
52
|
</template>
|
|
@@ -114,31 +114,31 @@ const $Data = reactive({
|
|
|
114
114
|
]
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
reload
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
117
|
+
const $Method = {
|
|
118
|
+
handleFilter(reload) {
|
|
119
|
+
reload({ keepSelection: false, resetPage: true });
|
|
120
|
+
},
|
|
121
|
+
formatTime(timestamp) {
|
|
122
|
+
if (!timestamp) return "-";
|
|
123
|
+
const date = new Date(timestamp);
|
|
124
|
+
const year = date.getFullYear();
|
|
125
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
126
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
127
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
128
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
129
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
130
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
131
|
+
},
|
|
132
|
+
formatJson(value) {
|
|
133
|
+
if (!value) return "-";
|
|
134
|
+
try {
|
|
135
|
+
const obj = typeof value === "string" ? JSON.parse(value) : value;
|
|
136
|
+
return JSON.stringify(obj, null, 2);
|
|
137
|
+
} catch {
|
|
138
|
+
return String(value);
|
|
139
|
+
}
|
|
140
140
|
}
|
|
141
|
-
}
|
|
141
|
+
};
|
|
142
142
|
</script>
|
|
143
143
|
|
|
144
144
|
<style scoped lang="scss">
|
package/views/login_1/index.vue
CHANGED
|
@@ -20,7 +20,18 @@
|
|
|
20
20
|
<h2 class="login-title">欢迎回来</h2>
|
|
21
21
|
</div>
|
|
22
22
|
|
|
23
|
-
<TForm
|
|
23
|
+
<TForm
|
|
24
|
+
:model="$Data.formData"
|
|
25
|
+
:rules="$Const.formRules"
|
|
26
|
+
:ref="
|
|
27
|
+
(value) => {
|
|
28
|
+
$From.formRef = value;
|
|
29
|
+
}
|
|
30
|
+
"
|
|
31
|
+
class="login-form"
|
|
32
|
+
:show-message="false"
|
|
33
|
+
label-width="0"
|
|
34
|
+
>
|
|
24
35
|
<TFormItem prop="account">
|
|
25
36
|
<TInputAdornment>
|
|
26
37
|
<template #prepend>
|
|
@@ -30,7 +41,7 @@
|
|
|
30
41
|
<TOption value="phone" label="手机号" />
|
|
31
42
|
</TSelect>
|
|
32
43
|
</template>
|
|
33
|
-
<TInput v-model="$Data.formData.account" :placeholder="$Data.formData.loginType === 'username' ? '请输入用户名' : $Data.formData.loginType === 'email' ? '请输入邮箱' : '请输入手机号'" size="large" clearable @enter="apiLogin">
|
|
44
|
+
<TInput v-model="$Data.formData.account" :placeholder="$Data.formData.loginType === 'username' ? '请输入用户名' : $Data.formData.loginType === 'email' ? '请输入邮箱' : '请输入手机号'" size="large" clearable @enter="$Method.apiLogin">
|
|
34
45
|
<template #prefix-icon>
|
|
35
46
|
<UserIcon />
|
|
36
47
|
</template>
|
|
@@ -39,7 +50,7 @@
|
|
|
39
50
|
</TFormItem>
|
|
40
51
|
|
|
41
52
|
<TFormItem prop="password">
|
|
42
|
-
<TInput v-model="$Data.formData.password" type="password" placeholder="密码" size="large" clearable @enter="apiLogin">
|
|
53
|
+
<TInput v-model="$Data.formData.password" type="password" placeholder="密码" size="large" clearable @enter="$Method.apiLogin">
|
|
43
54
|
<template #prefix-icon>
|
|
44
55
|
<LockOnIcon />
|
|
45
56
|
</template>
|
|
@@ -51,7 +62,7 @@
|
|
|
51
62
|
<a href="#" class="link-text">忘记密码?</a>
|
|
52
63
|
</div>
|
|
53
64
|
|
|
54
|
-
<TButton theme="primary" class="login-btn" size="large" block :loading="$Data.loading" @click="apiLogin">登录</TButton>
|
|
65
|
+
<TButton theme="primary" class="login-btn" size="large" block :loading="$Data.loading" @click="$Method.apiLogin">登录</TButton>
|
|
55
66
|
</TForm>
|
|
56
67
|
|
|
57
68
|
<div class="login-footer">
|
|
@@ -63,7 +74,7 @@
|
|
|
63
74
|
</template>
|
|
64
75
|
|
|
65
76
|
<script setup>
|
|
66
|
-
import { reactive
|
|
77
|
+
import { reactive } from "vue";
|
|
67
78
|
import { useRouter } from "vue-router";
|
|
68
79
|
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
80
|
import { LockOnIcon, UserIcon } from "tdesign-icons-vue-next";
|
|
@@ -74,16 +85,21 @@ import { $Store } from "@/plugins/store.js";
|
|
|
74
85
|
|
|
75
86
|
const router = useRouter();
|
|
76
87
|
|
|
77
|
-
const
|
|
88
|
+
const $Const = {
|
|
89
|
+
formRules: {
|
|
90
|
+
account: [{ required: true, message: "请输入账号", trigger: "blur" }],
|
|
91
|
+
password: [{ required: true, message: "请输入密码", trigger: "blur" }]
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const $From = {
|
|
96
|
+
formRef: null
|
|
97
|
+
};
|
|
78
98
|
|
|
79
99
|
// 数据定义
|
|
80
100
|
const $Data = reactive({
|
|
81
101
|
loading: false,
|
|
82
102
|
rememberMe: false,
|
|
83
|
-
formRules: {
|
|
84
|
-
account: [{ required: true, message: "请输入账号", trigger: "blur" }],
|
|
85
|
-
password: [{ required: true, message: "请输入密码", trigger: "blur" }]
|
|
86
|
-
},
|
|
87
103
|
formData: {
|
|
88
104
|
loginType: "username",
|
|
89
105
|
account: "",
|
|
@@ -91,36 +107,38 @@ const $Data = reactive({
|
|
|
91
107
|
}
|
|
92
108
|
});
|
|
93
109
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
110
|
+
const $Method = {
|
|
111
|
+
async apiLogin() {
|
|
112
|
+
try {
|
|
113
|
+
if ($From.formRef === null) {
|
|
114
|
+
MessagePlugin.error("表单未就绪");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
100
117
|
|
|
101
|
-
|
|
118
|
+
await $From.formRef.validate();
|
|
102
119
|
|
|
103
|
-
|
|
120
|
+
$Data.loading = true;
|
|
104
121
|
|
|
105
|
-
|
|
122
|
+
const hashedPassword = await hashPassword($Data.formData.password);
|
|
106
123
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
124
|
+
const res = await $Http("/core/auth/login", {
|
|
125
|
+
loginType: $Data.formData.loginType,
|
|
126
|
+
account: $Data.formData.account,
|
|
127
|
+
password: hashedPassword
|
|
128
|
+
});
|
|
112
129
|
|
|
113
|
-
|
|
130
|
+
$Store.local.set($Config.tokenName, res.data.token);
|
|
114
131
|
|
|
115
|
-
|
|
132
|
+
MessagePlugin.success(res.msg || "登录成功");
|
|
116
133
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
134
|
+
await router.push($Config.homePath);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
MessagePlugin.error(error.msg || error.message || "登录失败");
|
|
137
|
+
} finally {
|
|
138
|
+
$Data.loading = false;
|
|
139
|
+
}
|
|
122
140
|
}
|
|
123
|
-
}
|
|
141
|
+
};
|
|
124
142
|
</script>
|
|
125
143
|
|
|
126
144
|
<style scoped lang="scss">
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
MessagePlugin
|
|
39
39
|
} from "tdesign-vue-next";
|
|
40
40
|
import PageDialog from "befly-admin-ui/components/pageDialog.vue";
|
|
41
|
-
import { $Http } from "@/plugins/http";
|
|
41
|
+
import { $Http } from "@/plugins/http.js";
|
|
42
42
|
import { fieldClear } from "befly-admin-ui/utils/fieldClear";
|
|
43
43
|
import { hashPassword } from "befly-admin-ui/utils/hashPassword";
|
|
44
44
|
|