@befly-addon/admin 1.8.4 → 1.8.6
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/adminViews/403_1/index.vue +9 -10
- package/adminViews/config/dict/components/edit.vue +30 -33
- package/adminViews/config/dict/index.vue +64 -63
- package/adminViews/config/dictType/components/edit.vue +29 -32
- package/adminViews/config/dictType/index.vue +43 -43
- package/adminViews/config/system/components/edit.vue +69 -67
- package/adminViews/config/system/index.vue +44 -54
- package/adminViews/index/components/userInfo.vue +67 -77
- package/adminViews/log/email/index.vue +92 -103
- package/adminViews/log/login/index.vue +31 -45
- package/adminViews/log/operate/index.vue +44 -59
- package/adminViews/login_1/index.vue +24 -31
- package/adminViews/people/admin/components/edit.vue +57 -69
- package/adminViews/people/admin/index.vue +32 -33
- package/adminViews/permission/api/index.vue +52 -62
- package/adminViews/permission/menu/index.vue +43 -53
- package/adminViews/permission/role/components/api.vue +164 -168
- package/adminViews/permission/role/components/edit.vue +39 -44
- package/adminViews/permission/role/components/menu.vue +139 -150
- package/adminViews/permission/role/index.vue +53 -53
- package/adminViews/tsconfig.json +14 -0
- package/package.json +3 -3
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<PagedTableDetail class="page-email page-table" :columns="$Data.columns" :endpoints="$Data.endpoints" :table-slot-names="['sendResult', 'sendTime']">
|
|
3
3
|
<template #toolLeft>
|
|
4
|
-
<TButton theme="primary" @click="
|
|
4
|
+
<TButton theme="primary" @click="openSendDialog">
|
|
5
5
|
<template #icon>
|
|
6
6
|
<ILucideSend />
|
|
7
7
|
</template>
|
|
8
8
|
发送邮件
|
|
9
9
|
</TButton>
|
|
10
|
-
<TButton variant="outline" @click="
|
|
10
|
+
<TButton variant="outline" @click="onVerify">
|
|
11
11
|
<template #icon>
|
|
12
12
|
<ILucideCheckCircle />
|
|
13
13
|
</template>
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
</template>
|
|
17
17
|
|
|
18
18
|
<template #toolRight="scope">
|
|
19
|
-
<TButton shape="circle" @click="
|
|
19
|
+
<TButton shape="circle" @click="onReload(scope.reload)">
|
|
20
20
|
<template #icon>
|
|
21
21
|
<ILucideRotateCw />
|
|
22
22
|
</template>
|
|
@@ -29,17 +29,17 @@
|
|
|
29
29
|
</template>
|
|
30
30
|
|
|
31
31
|
<template #sendTime="{ row }">
|
|
32
|
-
{{
|
|
32
|
+
{{ formatTime(row.sendTime) }}
|
|
33
33
|
</template>
|
|
34
34
|
|
|
35
35
|
<template #detail="scope">
|
|
36
|
-
<DetailPanel :data="scope.
|
|
36
|
+
<DetailPanel :data="scope.row" :fields="$Data.columns">
|
|
37
37
|
<template #sendResult="slotScope">
|
|
38
38
|
<TTag v-if="slotScope.value === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
|
|
39
39
|
<TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
|
|
40
40
|
</template>
|
|
41
41
|
<template #sendTime="slotScope">
|
|
42
|
-
{{
|
|
42
|
+
{{ formatTime(slotScope.value) }}
|
|
43
43
|
</template>
|
|
44
44
|
<template #content="slotScope">
|
|
45
45
|
<div class="email-content" v-html="slotScope.value"></div>
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
</template>
|
|
49
49
|
|
|
50
50
|
<template #dialogs="scope">
|
|
51
|
-
<
|
|
51
|
+
<PageDialog v-model="$Data.sendDialogVisible" title="发送邮件" :confirm-loading="$Data.sending" @confirm="(context) => onSend(scope.reload, context)" @cancel="onCancelSend" @close="onCancelSend">
|
|
52
52
|
<TForm :ref="(el) => ($From.sendForm = el)" :data="$Data.sendForm" :rules="$Data.sendRules" label-width="80px">
|
|
53
53
|
<TFormItem label="收件人" name="to">
|
|
54
54
|
<TInput v-model="$Data.sendForm.to" placeholder="请输入收件人邮箱" />
|
|
@@ -62,26 +62,21 @@
|
|
|
62
62
|
<TFormItem label="内容" name="content">
|
|
63
63
|
<TTextarea v-model="$Data.sendForm.content" placeholder="请输入邮件内容(支持HTML)" :autosize="{ minRows: 6, maxRows: 12 }" />
|
|
64
64
|
</TFormItem>
|
|
65
|
-
<TFormItem>
|
|
66
|
-
<TSpace>
|
|
67
|
-
<TButton theme="primary" :loading="$Data.sending" @click="$Method.onSend(scope.reload)">发送</TButton>
|
|
68
|
-
<TButton variant="outline" @click="$Method.onCancelSend">取消</TButton>
|
|
69
|
-
</TSpace>
|
|
70
|
-
</TFormItem>
|
|
71
65
|
</TForm>
|
|
72
|
-
</
|
|
66
|
+
</PageDialog>
|
|
73
67
|
</template>
|
|
74
|
-
</
|
|
68
|
+
</PagedTableDetail>
|
|
75
69
|
</template>
|
|
76
70
|
|
|
77
71
|
<script setup lang="ts">
|
|
78
|
-
import { Button as TButton,
|
|
72
|
+
import { Button as TButton, Form as TForm, FormItem as TFormItem, Input as TInput, MessagePlugin, Space as TSpace, Tag as TTag, Textarea as TTextarea } from "tdesign-vue-next";
|
|
79
73
|
import ILucideRotateCw from "~icons/lucide/rotate-cw";
|
|
80
74
|
import ILucideSend from "~icons/lucide/send";
|
|
81
75
|
import ILucideCheckCircle from "~icons/lucide/check-circle";
|
|
82
|
-
import
|
|
76
|
+
import PageDialog from "@/components/pageDialog.vue";
|
|
77
|
+
import DetailPanel from "@/components/detailPanel.vue";
|
|
83
78
|
import { $Http } from "@/plugins/http";
|
|
84
|
-
import
|
|
79
|
+
import PagedTableDetail from "@/components/pagedTableDetail.vue";
|
|
85
80
|
import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
|
|
86
81
|
|
|
87
82
|
const $From = $shallowRef({
|
|
@@ -95,21 +90,14 @@ const $Data = $ref({
|
|
|
95
90
|
{ colKey: "toEmail", title: "收件人" },
|
|
96
91
|
{ colKey: "subject", title: "主题" },
|
|
97
92
|
{ colKey: "sendTime", title: "发送时间" },
|
|
98
|
-
{ colKey: "sendResult", title: "发送结果" }
|
|
99
|
-
]),
|
|
100
|
-
detailFields: [
|
|
101
|
-
{ colKey: "username", title: "发送人账号" },
|
|
102
|
-
{ colKey: "nickname", title: "发送人昵称" },
|
|
103
|
-
{ colKey: "toEmail", title: "收件人" },
|
|
104
|
-
{ colKey: "ccEmail", title: "抄送" },
|
|
105
|
-
{ colKey: "bccEmail", title: "密送" },
|
|
106
|
-
{ colKey: "subject", title: "主题" },
|
|
107
|
-
{ colKey: "content", title: "内容" },
|
|
108
|
-
{ colKey: "sendTime", title: "发送时间" },
|
|
109
93
|
{ colKey: "sendResult", title: "发送结果" },
|
|
110
|
-
{ colKey: "
|
|
111
|
-
{ colKey: "
|
|
112
|
-
|
|
94
|
+
{ colKey: "nickname", title: "发送人昵称", detail: true },
|
|
95
|
+
{ colKey: "ccEmail", title: "抄送", detail: true },
|
|
96
|
+
{ colKey: "bccEmail", title: "密送", detail: true },
|
|
97
|
+
{ colKey: "content", title: "内容", detail: true },
|
|
98
|
+
{ colKey: "messageId", title: "消息ID", detail: true },
|
|
99
|
+
{ colKey: "failReason", title: "失败原因", detail: true }
|
|
100
|
+
]),
|
|
113
101
|
endpoints: {
|
|
114
102
|
list: {
|
|
115
103
|
path: "/addon/admin/email/logList",
|
|
@@ -131,85 +119,86 @@ const $Data = $ref({
|
|
|
131
119
|
}
|
|
132
120
|
});
|
|
133
121
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
reload({ keepSelection: true });
|
|
138
|
-
},
|
|
122
|
+
function onReload(reload: (options: { keepSelection?: boolean }) => void): void {
|
|
123
|
+
reload({ keepSelection: true });
|
|
124
|
+
}
|
|
139
125
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
126
|
+
function onCancelSend(): void {
|
|
127
|
+
$Data.sendDialogVisible = false;
|
|
128
|
+
}
|
|
143
129
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
},
|
|
130
|
+
function openSendDialog(): void {
|
|
131
|
+
$Data.sendForm = {
|
|
132
|
+
to: "",
|
|
133
|
+
cc: "",
|
|
134
|
+
subject: "",
|
|
135
|
+
content: ""
|
|
136
|
+
};
|
|
137
|
+
$Data.sendDialogVisible = true;
|
|
138
|
+
}
|
|
154
139
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (valid !== true) return;
|
|
159
|
-
|
|
160
|
-
$Data.sending = true;
|
|
161
|
-
try {
|
|
162
|
-
const res = await $Http.post("/addon/admin/email/send", {
|
|
163
|
-
to: $Data.sendForm.to,
|
|
164
|
-
subject: $Data.sendForm.subject,
|
|
165
|
-
content: $Data.sendForm.content,
|
|
166
|
-
cc: $Data.sendForm.cc || undefined,
|
|
167
|
-
isHtml: true
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
if (res.code === 0) {
|
|
171
|
-
MessagePlugin.success("发送成功");
|
|
172
|
-
$Data.sendDialogVisible = false;
|
|
173
|
-
if (reload) {
|
|
174
|
-
reload({ keepSelection: false, resetPage: true });
|
|
175
|
-
}
|
|
176
|
-
} else {
|
|
177
|
-
MessagePlugin.error(res.msg || "发送失败");
|
|
178
|
-
}
|
|
179
|
-
} catch (error) {
|
|
180
|
-
MessagePlugin.error("发送失败");
|
|
181
|
-
} finally {
|
|
182
|
-
$Data.sending = false;
|
|
183
|
-
}
|
|
184
|
-
},
|
|
140
|
+
type PageDialogEventContext = {
|
|
141
|
+
close: () => void;
|
|
142
|
+
};
|
|
185
143
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
144
|
+
async function onSend(reload: ((options: { keepSelection?: boolean; resetPage?: boolean }) => void) | null, context?: PageDialogEventContext): Promise<void> {
|
|
145
|
+
const valid = await $From.sendForm?.validate();
|
|
146
|
+
if (valid !== true) return;
|
|
147
|
+
|
|
148
|
+
$Data.sending = true;
|
|
149
|
+
try {
|
|
150
|
+
const res = await $Http.post("/addon/admin/email/send", {
|
|
151
|
+
to: $Data.sendForm.to,
|
|
152
|
+
subject: $Data.sendForm.subject,
|
|
153
|
+
content: $Data.sendForm.content,
|
|
154
|
+
cc: $Data.sendForm.cc || undefined,
|
|
155
|
+
isHtml: true
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
if (res.code === 0) {
|
|
159
|
+
MessagePlugin.success("发送成功");
|
|
160
|
+
if (context && typeof context.close === "function") {
|
|
161
|
+
context.close();
|
|
192
162
|
} else {
|
|
193
|
-
|
|
163
|
+
$Data.sendDialogVisible = false;
|
|
164
|
+
}
|
|
165
|
+
if (reload) {
|
|
166
|
+
reload({ keepSelection: false, resetPage: true });
|
|
194
167
|
}
|
|
195
|
-
}
|
|
196
|
-
MessagePlugin.error("
|
|
168
|
+
} else {
|
|
169
|
+
MessagePlugin.error(res.msg || "发送失败");
|
|
197
170
|
}
|
|
198
|
-
}
|
|
171
|
+
} catch (error) {
|
|
172
|
+
MessagePlugin.error("发送失败");
|
|
173
|
+
} finally {
|
|
174
|
+
$Data.sending = false;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
199
177
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
178
|
+
async function onVerify(): Promise<void> {
|
|
179
|
+
try {
|
|
180
|
+
const res = await $Http.post("/addon/admin/email/verify");
|
|
181
|
+
if (res.code === 0) {
|
|
182
|
+
MessagePlugin.success("邮件服务配置正常");
|
|
183
|
+
} else {
|
|
184
|
+
MessagePlugin.error(res.msg || "配置异常");
|
|
185
|
+
}
|
|
186
|
+
} catch (error) {
|
|
187
|
+
MessagePlugin.error("验证失败");
|
|
211
188
|
}
|
|
212
|
-
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function formatTime(timestamp: unknown): string {
|
|
192
|
+
if (!timestamp) return "-";
|
|
193
|
+
const date = new Date(timestamp as never);
|
|
194
|
+
const year = date.getFullYear();
|
|
195
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
196
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
197
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
198
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
199
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
200
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
201
|
+
}
|
|
213
202
|
</script>
|
|
214
203
|
|
|
215
204
|
<style scoped lang="scss">
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<PagedTableDetail class="page-login-log page-table" :columns="$Data.columns" :endpoints="$Data.endpoints" :table-slot-names="['loginResult', 'loginTime', 'deviceType']">
|
|
3
3
|
<template #toolRight="scope">
|
|
4
|
-
<TButton shape="circle" @click="
|
|
4
|
+
<TButton shape="circle" @click="onReload(scope.reload)">
|
|
5
5
|
<template #icon>
|
|
6
6
|
<ILucideRotateCw />
|
|
7
7
|
</template>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
</template>
|
|
15
15
|
|
|
16
16
|
<template #loginTime="{ row }">
|
|
17
|
-
{{
|
|
17
|
+
{{ formatTime(row.loginTime) }}
|
|
18
18
|
</template>
|
|
19
19
|
|
|
20
20
|
<template #deviceType="{ row }">
|
|
@@ -22,27 +22,27 @@
|
|
|
22
22
|
</template>
|
|
23
23
|
|
|
24
24
|
<template #detail="scope">
|
|
25
|
-
<DetailPanel :data="scope.
|
|
25
|
+
<DetailPanel :data="scope.row" :fields="$Data.columns">
|
|
26
26
|
<template #loginResult="slotScope">
|
|
27
27
|
<TTag v-if="slotScope.value === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
|
|
28
28
|
<TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
|
|
29
29
|
</template>
|
|
30
30
|
<template #loginTime="slotScope">
|
|
31
|
-
{{
|
|
31
|
+
{{ formatTime(slotScope.value) }}
|
|
32
32
|
</template>
|
|
33
33
|
<template #deviceType="slotScope">
|
|
34
34
|
<TTag shape="round" variant="light-outline">{{ slotScope.value || "desktop" }}</TTag>
|
|
35
35
|
</template>
|
|
36
36
|
</DetailPanel>
|
|
37
37
|
</template>
|
|
38
|
-
</
|
|
38
|
+
</PagedTableDetail>
|
|
39
39
|
</template>
|
|
40
40
|
|
|
41
41
|
<script setup lang="ts">
|
|
42
42
|
import { Button as TButton, Tag as TTag } from "tdesign-vue-next";
|
|
43
43
|
import ILucideRotateCw from "~icons/lucide/rotate-cw";
|
|
44
|
-
import DetailPanel from "@/components/
|
|
45
|
-
import
|
|
44
|
+
import DetailPanel from "@/components/detailPanel.vue";
|
|
45
|
+
import PagedTableDetail from "@/components/pagedTableDetail.vue";
|
|
46
46
|
import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
|
|
47
47
|
|
|
48
48
|
// 响应式数据
|
|
@@ -54,26 +54,16 @@ const $Data = $ref({
|
|
|
54
54
|
{ colKey: "osName", title: "操作系统" },
|
|
55
55
|
{ colKey: "deviceType", title: "设备类型" },
|
|
56
56
|
{ colKey: "loginTime", title: "登录时间" },
|
|
57
|
-
{ colKey: "loginResult", title: "登录结果" }
|
|
58
|
-
]),
|
|
59
|
-
// 详情面板显示更多字段
|
|
60
|
-
detailFields: [
|
|
61
|
-
{ colKey: "username", title: "用户名" },
|
|
62
|
-
{ colKey: "nickname", title: "昵称" },
|
|
63
|
-
{ colKey: "ip", title: "登录IP" },
|
|
64
|
-
{ colKey: "browserName", title: "浏览器" },
|
|
65
|
-
{ colKey: "browserVersion", title: "浏览器版本" },
|
|
66
|
-
{ colKey: "osName", title: "操作系统" },
|
|
67
|
-
{ colKey: "osVersion", title: "系统版本" },
|
|
68
|
-
{ colKey: "deviceType", title: "设备类型" },
|
|
69
|
-
{ colKey: "deviceVendor", title: "设备厂商" },
|
|
70
|
-
{ colKey: "deviceModel", title: "设备型号" },
|
|
71
|
-
{ colKey: "engineName", title: "渲染引擎" },
|
|
72
|
-
{ colKey: "cpuArchitecture", title: "CPU架构" },
|
|
73
|
-
{ colKey: "loginTime", title: "登录时间" },
|
|
74
57
|
{ colKey: "loginResult", title: "登录结果" },
|
|
75
|
-
{ colKey: "
|
|
76
|
-
|
|
58
|
+
{ colKey: "nickname", title: "昵称", detail: true },
|
|
59
|
+
{ colKey: "browserVersion", title: "浏览器版本", detail: true },
|
|
60
|
+
{ colKey: "osVersion", title: "系统版本", detail: true },
|
|
61
|
+
{ colKey: "deviceVendor", title: "设备厂商", detail: true },
|
|
62
|
+
{ colKey: "deviceModel", title: "设备型号", detail: true },
|
|
63
|
+
{ colKey: "engineName", title: "渲染引擎", detail: true },
|
|
64
|
+
{ colKey: "cpuArchitecture", title: "CPU架构", detail: true },
|
|
65
|
+
{ colKey: "failReason", title: "失败原因", detail: true }
|
|
66
|
+
]),
|
|
77
67
|
endpoints: {
|
|
78
68
|
list: {
|
|
79
69
|
path: "/addon/admin/loginLog/list",
|
|
@@ -82,25 +72,21 @@ const $Data = $ref({
|
|
|
82
72
|
}
|
|
83
73
|
});
|
|
84
74
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
reload({ keepSelection: true });
|
|
89
|
-
},
|
|
75
|
+
function onReload(reload: (options: { keepSelection?: boolean }) => void): void {
|
|
76
|
+
reload({ keepSelection: true });
|
|
77
|
+
}
|
|
90
78
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
};
|
|
79
|
+
function formatTime(timestamp: unknown): string {
|
|
80
|
+
if (!timestamp) return "-";
|
|
81
|
+
const date = new Date(timestamp as never);
|
|
82
|
+
const year = date.getFullYear();
|
|
83
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
84
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
85
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
86
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
87
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
88
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
89
|
+
}
|
|
104
90
|
</script>
|
|
105
91
|
|
|
106
92
|
<style scoped lang="scss">
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<PagedTableDetail 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="
|
|
4
|
+
<TSelect v-model="$Data.filter.module" placeholder="操作模块" clearable style="width: 150px" @change="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="
|
|
7
|
+
<TSelect v-model="$Data.filter.action" placeholder="操作类型" clearable style="width: 150px" @change="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="
|
|
10
|
+
<TSelect v-model="$Data.filter.result" placeholder="操作结果" clearable style="width: 120px" @change="handleFilter(scope.reload)">
|
|
11
11
|
<TOption label="成功" :value="1" />
|
|
12
12
|
<TOption label="失败" :value="0" />
|
|
13
13
|
</TSelect>
|
|
14
14
|
</template>
|
|
15
15
|
|
|
16
16
|
<template #toolRight="scope">
|
|
17
|
-
<TButton shape="circle" @click="
|
|
17
|
+
<TButton shape="circle" @click="onReload(scope.reload)">
|
|
18
18
|
<template #icon>
|
|
19
19
|
<ILucideRotateCw />
|
|
20
20
|
</template>
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
</template>
|
|
28
28
|
|
|
29
29
|
<template #operateTime="{ row }">
|
|
30
|
-
{{
|
|
30
|
+
{{ formatTime(row.operateTime) }}
|
|
31
31
|
</template>
|
|
32
32
|
|
|
33
33
|
<template #duration="{ row }">
|
|
@@ -39,33 +39,33 @@
|
|
|
39
39
|
</template>
|
|
40
40
|
|
|
41
41
|
<template #detail="scope">
|
|
42
|
-
<DetailPanel :data="scope.
|
|
42
|
+
<DetailPanel :data="scope.row" :fields="$Data.columns">
|
|
43
43
|
<template #result="slotScope">
|
|
44
44
|
<TTag v-if="slotScope.value === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
|
|
45
45
|
<TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
|
|
46
46
|
</template>
|
|
47
47
|
<template #operateTime="slotScope">
|
|
48
|
-
{{
|
|
48
|
+
{{ formatTime(slotScope.value) }}
|
|
49
49
|
</template>
|
|
50
50
|
<template #duration="slotScope">
|
|
51
51
|
<TTag shape="round" :theme="slotScope.value > 1000 ? 'warning' : 'default'" variant="light-outline">{{ slotScope.value }}ms</TTag>
|
|
52
52
|
</template>
|
|
53
53
|
<template #params="slotScope">
|
|
54
|
-
<pre class="json-content">{{
|
|
54
|
+
<pre class="json-content">{{ formatJson(slotScope.value) }}</pre>
|
|
55
55
|
</template>
|
|
56
56
|
<template #response="slotScope">
|
|
57
|
-
<pre class="json-content">{{
|
|
57
|
+
<pre class="json-content">{{ formatJson(slotScope.value) }}</pre>
|
|
58
58
|
</template>
|
|
59
59
|
</DetailPanel>
|
|
60
60
|
</template>
|
|
61
|
-
</
|
|
61
|
+
</PagedTableDetail>
|
|
62
62
|
</template>
|
|
63
63
|
|
|
64
64
|
<script setup lang="ts">
|
|
65
65
|
import { Button as TButton, Option as TOption, Select as TSelect, Tag as TTag } from "tdesign-vue-next";
|
|
66
66
|
import ILucideRotateCw from "~icons/lucide/rotate-cw";
|
|
67
|
-
import DetailPanel from "@/components/
|
|
68
|
-
import
|
|
67
|
+
import DetailPanel from "@/components/detailPanel.vue";
|
|
68
|
+
import PagedTableDetail from "@/components/pagedTableDetail.vue";
|
|
69
69
|
import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
|
|
70
70
|
|
|
71
71
|
// 响应式数据
|
|
@@ -78,23 +78,13 @@ const $Data = $ref({
|
|
|
78
78
|
{ colKey: "ip", title: "IP地址", width: 130 },
|
|
79
79
|
{ colKey: "duration", title: "耗时", width: 100 },
|
|
80
80
|
{ colKey: "operateTime", title: "操作时间", width: 170 },
|
|
81
|
-
{ colKey: "result", title: "结果", width: 80 }
|
|
81
|
+
{ colKey: "result", title: "结果", width: 80 },
|
|
82
|
+
{ colKey: "nickname", title: "操作人昵称", detail: true },
|
|
83
|
+
{ colKey: "method", title: "请求方法", detail: true },
|
|
84
|
+
{ colKey: "params", title: "请求参数", detail: true },
|
|
85
|
+
{ colKey: "response", title: "响应内容", detail: true },
|
|
86
|
+
{ colKey: "remark", title: "备注", detail: true }
|
|
82
87
|
]),
|
|
83
|
-
detailFields: [
|
|
84
|
-
{ colKey: "username", title: "操作人账号" },
|
|
85
|
-
{ colKey: "nickname", title: "操作人昵称" },
|
|
86
|
-
{ colKey: "module", title: "操作模块" },
|
|
87
|
-
{ colKey: "action", title: "操作类型" },
|
|
88
|
-
{ colKey: "method", title: "请求方法" },
|
|
89
|
-
{ colKey: "path", title: "请求路径" },
|
|
90
|
-
{ colKey: "ip", title: "IP地址" },
|
|
91
|
-
{ colKey: "params", title: "请求参数" },
|
|
92
|
-
{ colKey: "response", title: "响应内容" },
|
|
93
|
-
{ colKey: "duration", title: "耗时" },
|
|
94
|
-
{ colKey: "operateTime", title: "操作时间" },
|
|
95
|
-
{ colKey: "result", title: "操作结果" },
|
|
96
|
-
{ colKey: "remark", title: "备注" }
|
|
97
|
-
],
|
|
98
88
|
endpoints: {
|
|
99
89
|
list: {
|
|
100
90
|
path: "/addon/admin/operateLog/list",
|
|
@@ -132,40 +122,35 @@ const $Data = $ref({
|
|
|
132
122
|
]
|
|
133
123
|
});
|
|
134
124
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
reload({ keepSelection: false, resetPage: true });
|
|
139
|
-
},
|
|
125
|
+
function handleFilter(reload: (options: { keepSelection?: boolean; resetPage?: boolean }) => void): void {
|
|
126
|
+
reload({ keepSelection: false, resetPage: true });
|
|
127
|
+
}
|
|
140
128
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
129
|
+
function onReload(reload: (options: { keepSelection?: boolean }) => void): void {
|
|
130
|
+
reload({ keepSelection: true });
|
|
131
|
+
}
|
|
144
132
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
},
|
|
133
|
+
function formatTime(timestamp: unknown): string {
|
|
134
|
+
if (!timestamp) return "-";
|
|
135
|
+
const date = new Date(timestamp as never);
|
|
136
|
+
const year = date.getFullYear();
|
|
137
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
138
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
139
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
140
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
141
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
142
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
143
|
+
}
|
|
157
144
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return value;
|
|
166
|
-
}
|
|
145
|
+
function formatJson(value: unknown): string {
|
|
146
|
+
if (!value) return "-";
|
|
147
|
+
try {
|
|
148
|
+
const obj = typeof value === "string" ? JSON.parse(value) : value;
|
|
149
|
+
return JSON.stringify(obj, null, 2);
|
|
150
|
+
} catch {
|
|
151
|
+
return String(value);
|
|
167
152
|
}
|
|
168
|
-
}
|
|
153
|
+
}
|
|
169
154
|
</script>
|
|
170
155
|
|
|
171
156
|
<style scoped lang="scss">
|