@befly-addon/admin 1.8.2 → 1.8.4

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.
@@ -1,103 +1,95 @@
1
1
  <template>
2
- <div class="page-email page-table">
3
- <div class="main-tool">
4
- <div class="left">
5
- <TButton theme="primary" @click="$Method.openSendDialog">
6
- <template #icon>
7
- <ILucideSend />
8
- </template>
9
- 发送邮件
10
- </TButton>
11
- <TButton variant="outline" @click="$Method.onVerify">
12
- <template #icon>
13
- <ILucideCheckCircle />
14
- </template>
15
- 验证配置
16
- </TButton>
17
- </div>
18
- <div class="right">
19
- <TButton shape="circle" @click="$Method.handleRefresh">
20
- <template #icon>
21
- <ILucideRotateCw />
22
- </template>
23
- </TButton>
24
- </div>
25
- </div>
26
-
27
- <div class="main-content">
28
- <div class="main-table">
29
- <TTable :data="$Data.tableData" :columns="$Data.columns" :loading="$Data.loading" :active-row-keys="$Data.activeRowKeys" row-key="id" height="100%" active-row-type="single" @active-change="$Method.onActiveChange">
30
- <template #sendResult="{ row }">
31
- <TTag v-if="row.sendResult === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
32
- <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
33
- </template>
34
- <template #sendTime="{ row }">
35
- {{ $Method.formatTime(row.sendTime) }}
36
- </template>
37
- </TTable>
38
- </div>
39
-
40
- <div class="main-detail">
41
- <DetailPanel :data="$Data.currentRow" :fields="$Data.detailFields">
42
- <template #sendResult="{ value }">
43
- <TTag v-if="value === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
44
- <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
45
- </template>
46
- <template #sendTime="{ value }">
47
- {{ $Method.formatTime(value) }}
48
- </template>
49
- <template #content="{ value }">
50
- <div class="email-content" v-html="value"></div>
51
- </template>
52
- </DetailPanel>
53
- </div>
54
- </div>
55
-
56
- <div class="main-page">
57
- <TPagination :current-page="$Data.pagerConfig.currentPage" :page-size="$Data.pagerConfig.limit" :total="$Data.pagerConfig.total" @current-change="$Method.onPageChange" @page-size-change="$Method.handleSizeChange" />
58
- </div>
59
-
60
- <!-- 发送邮件弹框 -->
61
- <TDialog v-model:visible="$Data.sendDialogVisible" header="发送邮件" :footer="false" width="600px">
62
- <TForm ref="sendFormRef" :data="$Data.sendForm" :rules="$Data.sendRules" label-width="80px">
63
- <TFormItem label="收件人" name="to">
64
- <TInput v-model="$Data.sendForm.to" placeholder="请输入收件人邮箱" />
65
- </TFormItem>
66
- <TFormItem label="抄送" name="cc">
67
- <TInput v-model="$Data.sendForm.cc" placeholder="多个邮箱用逗号分隔(可选)" />
68
- </TFormItem>
69
- <TFormItem label="主题" name="subject">
70
- <TInput v-model="$Data.sendForm.subject" placeholder="请输入邮件主题" />
71
- </TFormItem>
72
- <TFormItem label="内容" name="content">
73
- <TTextarea v-model="$Data.sendForm.content" placeholder="请输入邮件内容(支持HTML)" :autosize="{ minRows: 6, maxRows: 12 }" />
74
- </TFormItem>
75
- <TFormItem>
76
- <TSpace>
77
- <TButton theme="primary" :loading="$Data.sending" @click="$Method.onSend">发送</TButton>
78
- <TButton variant="outline" @click="$Data.sendDialogVisible = false">取消</TButton>
79
- </TSpace>
80
- </TFormItem>
81
- </TForm>
82
- </TDialog>
83
- </div>
2
+ <PagedTableDetailPage class="page-email page-table" :columns="$Data.columns" :endpoints="$Data.endpoints" :table-slot-names="['sendResult', 'sendTime']">
3
+ <template #toolLeft>
4
+ <TButton theme="primary" @click="$Method.openSendDialog">
5
+ <template #icon>
6
+ <ILucideSend />
7
+ </template>
8
+ 发送邮件
9
+ </TButton>
10
+ <TButton variant="outline" @click="$Method.onVerify">
11
+ <template #icon>
12
+ <ILucideCheckCircle />
13
+ </template>
14
+ 验证配置
15
+ </TButton>
16
+ </template>
17
+
18
+ <template #toolRight="scope">
19
+ <TButton shape="circle" @click="$Method.onReload(scope.reload)">
20
+ <template #icon>
21
+ <ILucideRotateCw />
22
+ </template>
23
+ </TButton>
24
+ </template>
25
+
26
+ <template #sendResult="{ row }">
27
+ <TTag v-if="row.sendResult === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
28
+ <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
29
+ </template>
30
+
31
+ <template #sendTime="{ row }">
32
+ {{ $Method.formatTime(row.sendTime) }}
33
+ </template>
34
+
35
+ <template #detail="scope">
36
+ <DetailPanel :data="scope.currentRow" :fields="$Data.detailFields">
37
+ <template #sendResult="slotScope">
38
+ <TTag v-if="slotScope.value === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
39
+ <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
40
+ </template>
41
+ <template #sendTime="slotScope">
42
+ {{ $Method.formatTime(slotScope.value) }}
43
+ </template>
44
+ <template #content="slotScope">
45
+ <div class="email-content" v-html="slotScope.value"></div>
46
+ </template>
47
+ </DetailPanel>
48
+ </template>
49
+
50
+ <template #dialogs="scope">
51
+ <TDialog v-model:visible="$Data.sendDialogVisible" header="发送邮件" :footer="false" width="600px">
52
+ <TForm :ref="(el) => ($From.sendForm = el)" :data="$Data.sendForm" :rules="$Data.sendRules" label-width="80px">
53
+ <TFormItem label="收件人" name="to">
54
+ <TInput v-model="$Data.sendForm.to" placeholder="请输入收件人邮箱" />
55
+ </TFormItem>
56
+ <TFormItem label="抄送" name="cc">
57
+ <TInput v-model="$Data.sendForm.cc" placeholder="多个邮箱用逗号分隔(可选)" />
58
+ </TFormItem>
59
+ <TFormItem label="主题" name="subject">
60
+ <TInput v-model="$Data.sendForm.subject" placeholder="请输入邮件主题" />
61
+ </TFormItem>
62
+ <TFormItem label="内容" name="content">
63
+ <TTextarea v-model="$Data.sendForm.content" placeholder="请输入邮件内容(支持HTML)" :autosize="{ minRows: 6, maxRows: 12 }" />
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
+ </TForm>
72
+ </TDialog>
73
+ </template>
74
+ </PagedTableDetailPage>
84
75
  </template>
85
76
 
86
77
  <script setup lang="ts">
87
- import { Button as TButton, Table as TTable, Tag as TTag, Pagination as TPagination, Dialog as TDialog, Form as TForm, FormItem as TFormItem, Input as TInput, Textarea as TTextarea, Space as TSpace, MessagePlugin } from "tdesign-vue-next";
78
+ import { Button as TButton, Dialog as TDialog, Form as TForm, FormItem as TFormItem, Input as TInput, MessagePlugin, Space as TSpace, Tag as TTag, Textarea as TTextarea } from "tdesign-vue-next";
88
79
  import ILucideRotateCw from "~icons/lucide/rotate-cw";
89
80
  import ILucideSend from "~icons/lucide/send";
90
81
  import ILucideCheckCircle from "~icons/lucide/check-circle";
91
82
  import DetailPanel from "@/components/DetailPanel.vue";
92
83
  import { $Http } from "@/plugins/http";
84
+ import PagedTableDetailPage from "@/components/PagedTableDetailPage.vue";
93
85
  import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
94
86
 
95
- const sendFormRef = $ref(null);
87
+ const $From = $shallowRef({
88
+ sendForm: null
89
+ });
96
90
 
97
91
  // 响应式数据
98
92
  const $Data = $ref({
99
- tableData: [],
100
- loading: false,
101
93
  columns: withDefaultColumns([
102
94
  { colKey: "username", title: "发送人", fixed: "left" },
103
95
  { colKey: "toEmail", title: "收件人" },
@@ -118,13 +110,12 @@ const $Data = $ref({
118
110
  { colKey: "messageId", title: "消息ID" },
119
111
  { colKey: "failReason", title: "失败原因" }
120
112
  ],
121
- pagerConfig: {
122
- currentPage: 1,
123
- limit: 30,
124
- total: 0
113
+ endpoints: {
114
+ list: {
115
+ path: "/addon/admin/email/logList",
116
+ dropValues: [""]
117
+ }
125
118
  },
126
- currentRow: null,
127
- activeRowKeys: [],
128
119
  sendDialogVisible: false,
129
120
  sending: false,
130
121
  sendForm: {
@@ -142,39 +133,12 @@ const $Data = $ref({
142
133
 
143
134
  // 方法
144
135
  const $Method = {
145
- async initData() {
146
- await $Method.apiEmailLogList();
136
+ onReload(reload) {
137
+ reload({ keepSelection: true });
147
138
  },
148
139
 
149
- // 加载邮件日志列表
150
- async apiEmailLogList() {
151
- $Data.loading = true;
152
- try {
153
- const res = await $Http.post(
154
- "/addon/admin/email/logList",
155
- {
156
- page: $Data.pagerConfig.currentPage,
157
- limit: $Data.pagerConfig.limit
158
- },
159
- {
160
- dropValues: [""]
161
- }
162
- );
163
- $Data.tableData = res.data.lists || [];
164
- $Data.pagerConfig.total = res.data.total || 0;
165
-
166
- if ($Data.tableData.length > 0) {
167
- $Data.currentRow = $Data.tableData[0];
168
- $Data.activeRowKeys = [$Data.tableData[0].id];
169
- } else {
170
- $Data.currentRow = null;
171
- $Data.activeRowKeys = [];
172
- }
173
- } catch (error) {
174
- MessagePlugin.error("加载数据失败");
175
- } finally {
176
- $Data.loading = false;
177
- }
140
+ onCancelSend() {
141
+ $Data.sendDialogVisible = false;
178
142
  },
179
143
 
180
144
  // 打开发送弹框
@@ -189,8 +153,8 @@ const $Method = {
189
153
  },
190
154
 
191
155
  // 发送邮件
192
- async onSend() {
193
- const valid = await sendFormRef?.validate();
156
+ async onSend(reload) {
157
+ const valid = await $From.sendForm?.validate();
194
158
  if (valid !== true) return;
195
159
 
196
160
  $Data.sending = true;
@@ -206,7 +170,9 @@ const $Method = {
206
170
  if (res.code === 0) {
207
171
  MessagePlugin.success("发送成功");
208
172
  $Data.sendDialogVisible = false;
209
- $Method.apiEmailLogList();
173
+ if (reload) {
174
+ reload({ keepSelection: false, resetPage: true });
175
+ }
210
176
  } else {
211
177
  MessagePlugin.error(res.msg || "发送失败");
212
178
  }
@@ -231,35 +197,6 @@ const $Method = {
231
197
  }
232
198
  },
233
199
 
234
- // 刷新
235
- handleRefresh() {
236
- $Method.apiEmailLogList();
237
- },
238
-
239
- // 分页改变
240
- onPageChange(currentPage) {
241
- $Data.pagerConfig.currentPage = currentPage;
242
- $Method.apiEmailLogList();
243
- },
244
-
245
- // 每页条数改变
246
- handleSizeChange(pageSize) {
247
- $Data.pagerConfig.limit = pageSize;
248
- $Data.pagerConfig.currentPage = 1;
249
- $Method.apiEmailLogList();
250
- },
251
-
252
- // 高亮行变化
253
- onActiveChange(value, context) {
254
- if (value.length === 0 && $Data.activeRowKeys.length > 0) {
255
- return;
256
- }
257
- $Data.activeRowKeys = value;
258
- if (context.activeRowList && context.activeRowList.length > 0) {
259
- $Data.currentRow = context.activeRowList[0].row;
260
- }
261
- },
262
-
263
200
  // 格式化时间
264
201
  formatTime(timestamp) {
265
202
  if (!timestamp) return "-";
@@ -273,8 +210,6 @@ const $Method = {
273
210
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
274
211
  }
275
212
  };
276
-
277
- $Method.initData();
278
213
  </script>
279
214
 
280
215
  <style scoped lang="scss">
@@ -1,65 +1,52 @@
1
1
  <template>
2
- <div class="page-login-log page-table">
3
- <div class="main-tool">
4
- <div class="left"></div>
5
- <div class="right">
6
- <TButton shape="circle" @click="$Method.handleRefresh">
7
- <template #icon>
8
- <ILucideRotateCw />
9
- </template>
10
- </TButton>
11
- </div>
12
- </div>
2
+ <PagedTableDetailPage class="page-login-log page-table" :columns="$Data.columns" :endpoints="$Data.endpoints" :table-slot-names="['loginResult', 'loginTime', 'deviceType']">
3
+ <template #toolRight="scope">
4
+ <TButton shape="circle" @click="$Method.onReload(scope.reload)">
5
+ <template #icon>
6
+ <ILucideRotateCw />
7
+ </template>
8
+ </TButton>
9
+ </template>
13
10
 
14
- <div class="main-content">
15
- <div class="main-table">
16
- <TTable :data="$Data.tableData" :columns="$Data.columns" :loading="$Data.loading" :active-row-keys="$Data.activeRowKeys" row-key="id" height="100%" active-row-type="single" @active-change="$Method.onActiveChange">
17
- <template #loginResult="{ row }">
18
- <TTag v-if="row.loginResult === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
19
- <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
20
- </template>
21
- <template #loginTime="{ row }">
22
- {{ $Method.formatTime(row.loginTime) }}
23
- </template>
24
- <template #deviceType="{ row }">
25
- <TTag shape="round" variant="light-outline">{{ row.deviceType || "desktop" }}</TTag>
26
- </template>
27
- </TTable>
28
- </div>
11
+ <template #loginResult="{ row }">
12
+ <TTag v-if="row.loginResult === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
13
+ <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
14
+ </template>
29
15
 
30
- <div class="main-detail">
31
- <DetailPanel :data="$Data.currentRow" :fields="$Data.detailFields">
32
- <template #loginResult="{ value }">
33
- <TTag v-if="value === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
34
- <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
35
- </template>
36
- <template #loginTime="{ value }">
37
- {{ $Method.formatTime(value) }}
38
- </template>
39
- <template #deviceType="{ value }">
40
- <TTag shape="round" variant="light-outline">{{ value || "desktop" }}</TTag>
41
- </template>
42
- </DetailPanel>
43
- </div>
44
- </div>
16
+ <template #loginTime="{ row }">
17
+ {{ $Method.formatTime(row.loginTime) }}
18
+ </template>
45
19
 
46
- <div class="main-page">
47
- <TPagination :current-page="$Data.pagerConfig.currentPage" :page-size="$Data.pagerConfig.limit" :total="$Data.pagerConfig.total" @current-change="$Method.onPageChange" @page-size-change="$Method.handleSizeChange" />
48
- </div>
49
- </div>
20
+ <template #deviceType="{ row }">
21
+ <TTag shape="round" variant="light-outline">{{ row.deviceType || "desktop" }}</TTag>
22
+ </template>
23
+
24
+ <template #detail="scope">
25
+ <DetailPanel :data="scope.currentRow" :fields="$Data.detailFields">
26
+ <template #loginResult="slotScope">
27
+ <TTag v-if="slotScope.value === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
28
+ <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
29
+ </template>
30
+ <template #loginTime="slotScope">
31
+ {{ $Method.formatTime(slotScope.value) }}
32
+ </template>
33
+ <template #deviceType="slotScope">
34
+ <TTag shape="round" variant="light-outline">{{ slotScope.value || "desktop" }}</TTag>
35
+ </template>
36
+ </DetailPanel>
37
+ </template>
38
+ </PagedTableDetailPage>
50
39
  </template>
51
40
 
52
41
  <script setup lang="ts">
53
- import { Button as TButton, Table as TTable, Tag as TTag, Pagination as TPagination, MessagePlugin } from "tdesign-vue-next";
42
+ import { Button as TButton, Tag as TTag } from "tdesign-vue-next";
54
43
  import ILucideRotateCw from "~icons/lucide/rotate-cw";
55
44
  import DetailPanel from "@/components/DetailPanel.vue";
56
- import { $Http } from "@/plugins/http";
45
+ import PagedTableDetailPage from "@/components/PagedTableDetailPage.vue";
57
46
  import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
58
47
 
59
48
  // 响应式数据
60
49
  const $Data = $ref({
61
- tableData: [],
62
- loading: false,
63
50
  columns: withDefaultColumns([
64
51
  { colKey: "username", title: "用户名", fixed: "left" },
65
52
  { colKey: "ip", title: "登录IP" },
@@ -87,80 +74,18 @@ const $Data = $ref({
87
74
  { colKey: "loginResult", title: "登录结果" },
88
75
  { colKey: "failReason", title: "失败原因" }
89
76
  ],
90
- pagerConfig: {
91
- currentPage: 1,
92
- limit: 30,
93
- total: 0
94
- },
95
- currentRow: null,
96
- activeRowKeys: []
77
+ endpoints: {
78
+ list: {
79
+ path: "/addon/admin/loginLog/list",
80
+ dropValues: [""]
81
+ }
82
+ }
97
83
  });
98
84
 
99
85
  // 方法
100
86
  const $Method = {
101
- async initData() {
102
- await $Method.apiLoginLogList();
103
- },
104
-
105
- // 加载登录日志列表
106
- async apiLoginLogList() {
107
- $Data.loading = true;
108
- try {
109
- const res = await $Http.post(
110
- "/addon/admin/loginLog/list",
111
- {
112
- page: $Data.pagerConfig.currentPage,
113
- limit: $Data.pagerConfig.limit
114
- },
115
- {
116
- dropValues: [""]
117
- }
118
- );
119
- $Data.tableData = res.data.lists || [];
120
- $Data.pagerConfig.total = res.data.total || 0;
121
-
122
- // 自动高亮第一行
123
- if ($Data.tableData.length > 0) {
124
- $Data.currentRow = $Data.tableData[0];
125
- $Data.activeRowKeys = [$Data.tableData[0].id];
126
- } else {
127
- $Data.currentRow = null;
128
- $Data.activeRowKeys = [];
129
- }
130
- } catch (error) {
131
- MessagePlugin.error("加载数据失败");
132
- } finally {
133
- $Data.loading = false;
134
- }
135
- },
136
-
137
- // 刷新
138
- handleRefresh() {
139
- $Method.apiLoginLogList();
140
- },
141
-
142
- // 分页改变
143
- onPageChange(currentPage) {
144
- $Data.pagerConfig.currentPage = currentPage;
145
- $Method.apiLoginLogList();
146
- },
147
-
148
- // 每页条数改变
149
- handleSizeChange(pageSize) {
150
- $Data.pagerConfig.limit = pageSize;
151
- $Data.pagerConfig.currentPage = 1;
152
- $Method.apiLoginLogList();
153
- },
154
-
155
- // 高亮行变化
156
- onActiveChange(value, context) {
157
- if (value.length === 0 && $Data.activeRowKeys.length > 0) {
158
- return;
159
- }
160
- $Data.activeRowKeys = value;
161
- if (context.activeRowList && context.activeRowList.length > 0) {
162
- $Data.currentRow = context.activeRowList[0].row;
163
- }
87
+ onReload(reload) {
88
+ reload({ keepSelection: true });
164
89
  },
165
90
 
166
91
  // 格式化时间
@@ -176,8 +101,6 @@ const $Method = {
176
101
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
177
102
  }
178
103
  };
179
-
180
- $Method.initData();
181
104
  </script>
182
105
 
183
106
  <style scoped lang="scss">