mirror of https://github.com/certd/certd
				
				
				
			perf: 邮箱支持保存和选择
							parent
							
								
									81282a9c88
								
							
						
					
					
						commit
						f7b0b44ef6
					
				| 
						 | 
				
			
			@ -3,11 +3,12 @@ import { InjectEntityModel } from '@midwayjs/typeorm';
 | 
			
		|||
import { Repository } from 'typeorm';
 | 
			
		||||
import { SysSettingsEntity } from '../entity/sys-settings.js';
 | 
			
		||||
import { BaseSettings, SysInstallInfo, SysPrivateSettings, SysPublicSettings, SysSecret, SysSecretBackup } from './models.js';
 | 
			
		||||
import * as _ from 'lodash-es';
 | 
			
		||||
 | 
			
		||||
import { BaseService } from '../../../basic/index.js';
 | 
			
		||||
import { cache, logger, setGlobalProxy } from '@certd/basic';
 | 
			
		||||
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();
 | 
			
		||||
    const savedSettings = await this.getSettingByKey(key);
 | 
			
		||||
    newSetting = _.merge(newSetting, savedSettings);
 | 
			
		||||
    newSetting = merge(newSetting, savedSettings);
 | 
			
		||||
    await this.saveSetting(newSetting);
 | 
			
		||||
    cache.set(cacheKey, newSetting);
 | 
			
		||||
    return newSetting;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ export abstract class CertApplyBasePlugin extends CertApplyBaseConvertPlugin {
 | 
			
		|||
  @TaskInput({
 | 
			
		||||
    title: "邮箱",
 | 
			
		||||
    component: {
 | 
			
		||||
      name: "a-input",
 | 
			
		||||
      name: "email-selector",
 | 
			
		||||
      vModel: "value",
 | 
			
		||||
    },
 | 
			
		||||
    rules: [{ type: "email", message: "请输入正确的邮箱" }],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			@ -14,12 +14,14 @@ import FileInput from "./file-input.vue";
 | 
			
		|||
import PemInput from "./pem-input.vue";
 | 
			
		||||
import { defineAsyncComponent } from "vue";
 | 
			
		||||
import NotificationSelector from "../views/certd/notification/notification-selector/index.vue";
 | 
			
		||||
import EmailSelector from "./email-selector/index.vue";
 | 
			
		||||
export default {
 | 
			
		||||
  install(app: any) {
 | 
			
		||||
    app.component(
 | 
			
		||||
      "CodeEditor",
 | 
			
		||||
      defineAsyncComponent(() => import("./code-editor/index.vue"))
 | 
			
		||||
    );
 | 
			
		||||
    app.component("EmailSelector", EmailSelector);
 | 
			
		||||
    app.component("NotificationSelector", NotificationSelector);
 | 
			
		||||
    app.component("PiContainer", PiContainer);
 | 
			
		||||
    app.component("TextEditable", TextEditable);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ export async function doActive(form: any) {
 | 
			
		|||
  return await request({
 | 
			
		||||
    url: "/sys/plus/active",
 | 
			
		||||
    method: "post",
 | 
			
		||||
    data: form
 | 
			
		||||
    data: form,
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -12,6 +12,6 @@ export async function getVipTrial() {
 | 
			
		|||
  return await request({
 | 
			
		||||
    url: "/sys/plus/getVipTrial",
 | 
			
		||||
    method: "post",
 | 
			
		||||
    data: {}
 | 
			
		||||
    data: {},
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,4 +17,25 @@ export class EmailController extends BaseController {
 | 
			
		|||
    await this.emailService.test(userId, receiver);
 | 
			
		||||
    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({});
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ import { SendMailOptions } from 'nodemailer';
 | 
			
		|||
import { UserSettingsService } from '../../mine/service/user-settings-service.js';
 | 
			
		||||
import { PlusService, SysSettingsService, SysSiteInfo } from '@certd/lib-server';
 | 
			
		||||
import { getEmailSettings } from '../../sys/settings/fix.js';
 | 
			
		||||
import { UserEmailSetting } from "../../mine/service/models.js";
 | 
			
		||||
 | 
			
		||||
export type EmailConfig = {
 | 
			
		||||
  host: string;
 | 
			
		||||
| 
						 | 
				
			
			@ -108,4 +109,24 @@ export class EmailService implements IEmailService {
 | 
			
		|||
      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)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,3 +26,10 @@ export class UserSiteMonitorSetting extends BaseSettings {
 | 
			
		|||
 | 
			
		||||
  notificationId?:number= 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class UserEmailSetting extends BaseSettings {
 | 
			
		||||
  static __title__ = "用户邮箱设置";
 | 
			
		||||
  static __key__ = "user.email";
 | 
			
		||||
 | 
			
		||||
  list:string[] = [];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,8 @@ import { InjectEntityModel } from "@midwayjs/typeorm";
 | 
			
		|||
import { Repository } from "typeorm";
 | 
			
		||||
import { BaseService, BaseSettings } from "@certd/lib-server";
 | 
			
		||||
import { UserSettingsEntity } from "../entity/user-settings.js";
 | 
			
		||||
import { merge } from "lodash-es";
 | 
			
		||||
 | 
			
		||||
import { mergeUtils } from "@certd/basic";
 | 
			
		||||
const {merge} = mergeUtils
 | 
			
		||||
/**
 | 
			
		||||
 * 授权
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue