@befly-addon/admin 1.8.2 → 1.8.5

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,130 +1,109 @@
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
+ <PagedTableDetail class="page-email page-table" :columns="$Data.columns" :endpoints="$Data.endpoints" :table-slot-names="['sendResult', 'sendTime']">
3
+ <template #toolLeft>
4
+ <TButton theme="primary" @click="openSendDialog">
5
+ <template #icon>
6
+ <ILucideSend />
7
+ </template>
8
+ 发送邮件
9
+ </TButton>
10
+ <TButton variant="outline" @click="onVerify">
11
+ <template #icon>
12
+ <ILucideCheckCircle />
13
+ </template>
14
+ 验证配置
15
+ </TButton>
16
+ </template>
17
+
18
+ <template #toolRight="scope">
19
+ <TButton shape="circle" @click="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
+ {{ formatTime(row.sendTime) }}
33
+ </template>
34
+
35
+ <template #detail="scope">
36
+ <DetailPanel :data="scope.row" :fields="$Data.columns">
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
+ {{ 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
+ <PageDialog v-model="$Data.sendDialogVisible" title="发送邮件" :confirm-loading="$Data.sending" @confirm="(context) => onSend(scope.reload, context)" @cancel="onCancelSend" @close="onCancelSend">
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
+ </TForm>
66
+ </PageDialog>
67
+ </template>
68
+ </PagedTableDetail>
84
69
  </template>
85
70
 
86
71
  <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";
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";
88
73
  import ILucideRotateCw from "~icons/lucide/rotate-cw";
89
74
  import ILucideSend from "~icons/lucide/send";
90
75
  import ILucideCheckCircle from "~icons/lucide/check-circle";
91
- import DetailPanel from "@/components/DetailPanel.vue";
76
+ import PageDialog from "@/components/pageDialog.vue";
77
+ import DetailPanel from "@/components/detailPanel.vue";
92
78
  import { $Http } from "@/plugins/http";
79
+ import PagedTableDetail from "@/components/pagedTableDetail.vue";
93
80
  import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
94
81
 
95
- const sendFormRef = $ref(null);
82
+ const $From = $shallowRef({
83
+ sendForm: null
84
+ });
96
85
 
97
86
  // 响应式数据
98
87
  const $Data = $ref({
99
- tableData: [],
100
- loading: false,
101
88
  columns: withDefaultColumns([
102
89
  { colKey: "username", title: "发送人", fixed: "left" },
103
90
  { colKey: "toEmail", title: "收件人" },
104
91
  { colKey: "subject", title: "主题" },
105
92
  { colKey: "sendTime", title: "发送时间" },
106
- { colKey: "sendResult", title: "发送结果" }
107
- ]),
108
- detailFields: [
109
- { colKey: "username", title: "发送人账号" },
110
- { colKey: "nickname", title: "发送人昵称" },
111
- { colKey: "toEmail", title: "收件人" },
112
- { colKey: "ccEmail", title: "抄送" },
113
- { colKey: "bccEmail", title: "密送" },
114
- { colKey: "subject", title: "主题" },
115
- { colKey: "content", title: "内容" },
116
- { colKey: "sendTime", title: "发送时间" },
117
93
  { colKey: "sendResult", title: "发送结果" },
118
- { colKey: "messageId", title: "消息ID" },
119
- { colKey: "failReason", title: "失败原因" }
120
- ],
121
- pagerConfig: {
122
- currentPage: 1,
123
- limit: 30,
124
- total: 0
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
+ ]),
101
+ endpoints: {
102
+ list: {
103
+ path: "/addon/admin/email/logList",
104
+ dropValues: [""]
105
+ }
125
106
  },
126
- currentRow: null,
127
- activeRowKeys: [],
128
107
  sendDialogVisible: false,
129
108
  sending: false,
130
109
  sendForm: {
@@ -140,141 +119,86 @@ const $Data = $ref({
140
119
  }
141
120
  });
142
121
 
143
- // 方法
144
- const $Method = {
145
- async initData() {
146
- await $Method.apiEmailLogList();
147
- },
148
-
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
- }
178
- },
122
+ function onReload(reload: (options: { keepSelection?: boolean }) => void): void {
123
+ reload({ keepSelection: true });
124
+ }
179
125
 
180
- // 打开发送弹框
181
- openSendDialog() {
182
- $Data.sendForm = {
183
- to: "",
184
- cc: "",
185
- subject: "",
186
- content: ""
187
- };
188
- $Data.sendDialogVisible = true;
189
- },
126
+ function onCancelSend(): void {
127
+ $Data.sendDialogVisible = false;
128
+ }
190
129
 
191
- // 发送邮件
192
- async onSend() {
193
- const valid = await sendFormRef?.validate();
194
- if (valid !== true) return;
130
+ function openSendDialog(): void {
131
+ $Data.sendForm = {
132
+ to: "",
133
+ cc: "",
134
+ subject: "",
135
+ content: ""
136
+ };
137
+ $Data.sendDialogVisible = true;
138
+ }
195
139
 
196
- $Data.sending = true;
197
- try {
198
- const res = await $Http.post("/addon/admin/email/send", {
199
- to: $Data.sendForm.to,
200
- subject: $Data.sendForm.subject,
201
- content: $Data.sendForm.content,
202
- cc: $Data.sendForm.cc || undefined,
203
- isHtml: true
204
- });
140
+ type PageDialogEventContext = {
141
+ close: () => void;
142
+ };
205
143
 
206
- if (res.code === 0) {
207
- MessagePlugin.success("发送成功");
208
- $Data.sendDialogVisible = false;
209
- $Method.apiEmailLogList();
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();
210
162
  } else {
211
- MessagePlugin.error(res.msg || "发送失败");
163
+ $Data.sendDialogVisible = false;
212
164
  }
213
- } catch (error) {
214
- MessagePlugin.error("发送失败");
215
- } finally {
216
- $Data.sending = false;
217
- }
218
- },
219
-
220
- // 验证配置
221
- async onVerify() {
222
- try {
223
- const res = await $Http.post("/addon/admin/email/verify");
224
- if (res.code === 0) {
225
- MessagePlugin.success("邮件服务配置正常");
226
- } else {
227
- MessagePlugin.error(res.msg || "配置异常");
165
+ if (reload) {
166
+ reload({ keepSelection: false, resetPage: true });
228
167
  }
229
- } catch (error) {
230
- MessagePlugin.error("验证失败");
168
+ } else {
169
+ MessagePlugin.error(res.msg || "发送失败");
231
170
  }
232
- },
233
-
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
- },
171
+ } catch (error) {
172
+ MessagePlugin.error("发送失败");
173
+ } finally {
174
+ $Data.sending = false;
175
+ }
176
+ }
251
177
 
252
- // 高亮行变化
253
- onActiveChange(value, context) {
254
- if (value.length === 0 && $Data.activeRowKeys.length > 0) {
255
- return;
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 || "配置异常");
256
185
  }
257
- $Data.activeRowKeys = value;
258
- if (context.activeRowList && context.activeRowList.length > 0) {
259
- $Data.currentRow = context.activeRowList[0].row;
260
- }
261
- },
262
-
263
- // 格式化时间
264
- formatTime(timestamp) {
265
- if (!timestamp) return "-";
266
- const date = new Date(timestamp);
267
- const year = date.getFullYear();
268
- const month = String(date.getMonth() + 1).padStart(2, "0");
269
- const day = String(date.getDate()).padStart(2, "0");
270
- const hours = String(date.getHours()).padStart(2, "0");
271
- const minutes = String(date.getMinutes()).padStart(2, "0");
272
- const seconds = String(date.getSeconds()).padStart(2, "0");
273
- return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
186
+ } catch (error) {
187
+ MessagePlugin.error("验证失败");
274
188
  }
275
- };
189
+ }
276
190
 
277
- $Method.initData();
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
+ }
278
202
  </script>
279
203
 
280
204
  <style scoped lang="scss">