perf: 邮箱支持保存和选择

pull/409/head
xiaojunnuo 2025-05-31 00:45:54 +08:00
parent 81282a9c88
commit f7b0b44ef6
10 changed files with 171 additions and 8 deletions

View File

@ -3,11 +3,12 @@ import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import { SysSettingsEntity } from '../entity/sys-settings.js'; import { SysSettingsEntity } from '../entity/sys-settings.js';
import { BaseSettings, SysInstallInfo, SysPrivateSettings, SysPublicSettings, SysSecret, SysSecretBackup } from './models.js'; import { BaseSettings, SysInstallInfo, SysPrivateSettings, SysPublicSettings, SysSecret, SysSecretBackup } from './models.js';
import * as _ from 'lodash-es';
import { BaseService } from '../../../basic/index.js'; import { BaseService } from '../../../basic/index.js';
import { cache, logger, setGlobalProxy } from '@certd/basic'; import { cache, logger, setGlobalProxy } from '@certd/basic';
import * as dns from 'node:dns'; import * as dns from 'node:dns';
import {mergeUtils} from "@certd/basic";
const {merge} = mergeUtils;
/** /**
* *
*/ */
@ -75,7 +76,7 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
} }
let newSetting: T = new type(); let newSetting: T = new type();
const savedSettings = await this.getSettingByKey(key); const savedSettings = await this.getSettingByKey(key);
newSetting = _.merge(newSetting, savedSettings); newSetting = merge(newSetting, savedSettings);
await this.saveSetting(newSetting); await this.saveSetting(newSetting);
cache.set(cacheKey, newSetting); cache.set(cacheKey, newSetting);
return newSetting; return newSetting;

View File

@ -8,7 +8,7 @@ export abstract class CertApplyBasePlugin extends CertApplyBaseConvertPlugin {
@TaskInput({ @TaskInput({
title: "邮箱", title: "邮箱",
component: { component: {
name: "a-input", name: "email-selector",
vModel: "value", vModel: "value",
}, },
rules: [{ type: "email", message: "请输入正确的邮箱" }], rules: [{ type: "email", message: "请输入正确的邮箱" }],

View File

@ -0,0 +1,29 @@
import { request } from "/src/api/service";
export async function EmailList() {
return await request({
url: "/mine/email/list",
method: "post",
data: {},
});
}
export async function EmailDelete(email: string) {
return await request({
url: "/mine/email/delete",
method: "post",
data: {
email: email,
},
});
}
export async function EmailAdd(email: string) {
return await request({
url: "/mine/email/add",
method: "post",
data: {
email: email,
},
});
}

View File

@ -0,0 +1,82 @@
<template>
<a-select :options="emails">
<template #option="{ value: val }">
<div class="flex flex-row w-full">
<span class="flex-1">{{ val }}</span>
<fs-icon class="ml-5" icon="ion:close" @click="deleteItem(val)"></fs-icon>
</div>
</template>
<template #dropdownRender="{ menuNode: menu }">
<v-nodes :vnodes="menu" />
<a-divider style="margin: 4px 0" />
<div class="w-full flex flex-row p-5">
<a-input ref="inputRef" v-model:value="newEmail" class="flex-1" placeholder="添加新邮箱" @keydown.enter="addItem" />
<a-button class="ml-5" type="primary" @click="addItem">
<template #icon>
<plus-outlined />
</template>
添加邮箱
</a-button>
</div>
</template>
</a-select>
</template>
<script lang="ts" setup>
import { defineComponent, onMounted, ref } from "vue";
import * as api from "./api";
import { Modal, notification } from "ant-design-vue";
const props = defineProps<{}>();
const VNodes = defineComponent({
props: {
vnodes: {
type: Object,
required: true,
},
},
render() {
return this.vnodes;
},
});
const newEmail = ref("");
const emails = ref([]);
onMounted(async () => {
const list = await api.EmailList();
emails.value = list.map((item: string) => {
return {
value: item,
};
});
});
async function addItem() {
const email = newEmail.value;
//
if (!/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(newEmail.value)) {
notification.error({
message: "请填写正确的邮箱地址",
});
return;
}
await api.EmailAdd(email);
emails.value.push({
value: email,
label: email,
});
newEmail.value = "";
}
async function deleteItem(value: string) {
Modal.confirm({
title: "删除邮箱",
content: "确定要删除此邮箱吗?",
onOk: async () => {
await api.EmailDelete(value);
emails.value = emails.value.filter(item => item.value !== value);
},
});
}
</script>

View File

@ -14,12 +14,14 @@ import FileInput from "./file-input.vue";
import PemInput from "./pem-input.vue"; import PemInput from "./pem-input.vue";
import { defineAsyncComponent } from "vue"; import { defineAsyncComponent } from "vue";
import NotificationSelector from "../views/certd/notification/notification-selector/index.vue"; import NotificationSelector from "../views/certd/notification/notification-selector/index.vue";
import EmailSelector from "./email-selector/index.vue";
export default { export default {
install(app: any) { install(app: any) {
app.component( app.component(
"CodeEditor", "CodeEditor",
defineAsyncComponent(() => import("./code-editor/index.vue")) defineAsyncComponent(() => import("./code-editor/index.vue"))
); );
app.component("EmailSelector", EmailSelector);
app.component("NotificationSelector", NotificationSelector); app.component("NotificationSelector", NotificationSelector);
app.component("PiContainer", PiContainer); app.component("PiContainer", PiContainer);
app.component("TextEditable", TextEditable); app.component("TextEditable", TextEditable);

View File

@ -4,7 +4,7 @@ export async function doActive(form: any) {
return await request({ return await request({
url: "/sys/plus/active", url: "/sys/plus/active",
method: "post", method: "post",
data: form data: form,
}); });
} }
@ -12,6 +12,6 @@ export async function getVipTrial() {
return await request({ return await request({
url: "/sys/plus/getVipTrial", url: "/sys/plus/getVipTrial",
method: "post", method: "post",
data: {} data: {},
}); });
} }

View File

@ -17,4 +17,25 @@ export class EmailController extends BaseController {
await this.emailService.test(userId, receiver); await this.emailService.test(userId, receiver);
return this.ok({}); return this.ok({});
} }
@Post('/list', { summary: Constants.per.authOnly })
public async list() {
const userId = super.getUserId();
const res = await this.emailService.list(userId);
return this.ok(res);
}
@Post('/add', { summary: Constants.per.authOnly })
public async add(@Body('email') email) {
const userId = super.getUserId();
await this.emailService.add(userId, email);
return this.ok({});
}
@Post('/delete', { summary: Constants.per.authOnly })
public async delete(@Body('email') email) {
const userId = super.getUserId();
await this.emailService.delete(userId, email);
return this.ok({});
}
} }

View File

@ -10,6 +10,7 @@ import { SendMailOptions } from 'nodemailer';
import { UserSettingsService } from '../../mine/service/user-settings-service.js'; import { UserSettingsService } from '../../mine/service/user-settings-service.js';
import { PlusService, SysSettingsService, SysSiteInfo } from '@certd/lib-server'; import { PlusService, SysSettingsService, SysSiteInfo } from '@certd/lib-server';
import { getEmailSettings } from '../../sys/settings/fix.js'; import { getEmailSettings } from '../../sys/settings/fix.js';
import { UserEmailSetting } from "../../mine/service/models.js";
export type EmailConfig = { export type EmailConfig = {
host: string; host: string;
@ -108,4 +109,24 @@ export class EmailService implements IEmailService {
content: '测试邮件,from certd', content: '测试邮件,from certd',
}); });
} }
async list(userId: any) {
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId,UserEmailSetting)
return userEmailSetting.list;
}
async delete(userId: any, email: string) {
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId,UserEmailSetting)
userEmailSetting.list = userEmailSetting.list.filter(item=>item !== email);
await this.settingsService.saveSetting(userId,userEmailSetting)
}
async add(userId: any, email: string) {
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId,UserEmailSetting)
//如果已存在
if(userEmailSetting.list.includes(email)){
return
}
userEmailSetting.list.unshift(email)
await this.settingsService.saveSetting(userId,userEmailSetting)
}
} }

View File

@ -26,3 +26,10 @@ export class UserSiteMonitorSetting extends BaseSettings {
notificationId?:number= 0; notificationId?:number= 0;
} }
export class UserEmailSetting extends BaseSettings {
static __title__ = "用户邮箱设置";
static __key__ = "user.email";
list:string[] = [];
}

View File

@ -3,8 +3,8 @@ import { InjectEntityModel } from "@midwayjs/typeorm";
import { Repository } from "typeorm"; import { Repository } from "typeorm";
import { BaseService, BaseSettings } from "@certd/lib-server"; import { BaseService, BaseSettings } from "@certd/lib-server";
import { UserSettingsEntity } from "../entity/user-settings.js"; import { UserSettingsEntity } from "../entity/user-settings.js";
import { merge } from "lodash-es"; import { mergeUtils } from "@certd/basic";
const {merge} = mergeUtils
/** /**
* *
*/ */