chore: format

This commit is contained in:
xiaojunnuo
2026-05-31 01:41:33 +08:00
parent acd440106b
commit 4b57a0d729
557 changed files with 12530 additions and 14039 deletions
@@ -1,41 +1,41 @@
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
export const GROUP_TYPE_SITE = 'site';
export const GROUP_TYPE_SITE = "site";
@Entity('cd_group')
@Entity("cd_group")
export class GroupEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({ name: 'user_id', comment: '用户id' })
@Column({ name: "user_id", comment: "用户id" })
userId: number;
@Column({ name: 'name', comment: '分组名称' })
@Column({ name: "name", comment: "分组名称" })
name: string;
@Column({ name: 'icon', comment: '图标' })
@Column({ name: "icon", comment: "图标" })
icon: string;
@Column({ name: 'favorite', comment: '收藏' })
@Column({ name: "favorite", comment: "收藏" })
favorite: boolean;
@Column({ name: 'type', comment: '类型', length: 512 })
@Column({ name: "type", comment: "类型", length: 512 })
type: string;
@Column({ name: 'project_id', comment: '项目Id' })
@Column({ name: "project_id", comment: "项目Id" })
projectId: number;
@Column({
name: 'create_time',
comment: '创建时间',
default: () => 'CURRENT_TIMESTAMP',
name: "create_time",
comment: "创建时间",
default: () => "CURRENT_TIMESTAMP",
})
createTime: Date;
@Column({
name: 'update_time',
comment: '修改时间',
default: () => 'CURRENT_TIMESTAMP',
name: "update_time",
comment: "修改时间",
default: () => "CURRENT_TIMESTAMP",
})
updateTime: Date;
}
@@ -12,15 +12,14 @@ export class CaptchaService {
@Inject()
addonGetterService: AddonGetterService;
async getCaptcha(captchaAddonId?: number) {
if (!captchaAddonId) {
const settings = await this.sysSettingsService.getPublicSettings();
captchaAddonId = settings.captchaAddonId ?? 0;
}
const addon: ICaptchaAddon = await this.addonGetterService.getAddonById(captchaAddonId, true, 0,null, {
const addon: ICaptchaAddon = await this.addonGetterService.getAddonById(captchaAddonId, true, 0, null, {
type: "captcha",
name: "image"
name: "image",
});
if (!addon) {
throw new Error("验证码插件还未配置");
@@ -28,8 +27,7 @@ export class CaptchaService {
return await addon.getCaptcha();
}
async doValidate(opts: { form: any, must?: boolean, captchaAddonId?: number,req:CaptchaRequest }) {
async doValidate(opts: { form: any; must?: boolean; captchaAddonId?: number; req: CaptchaRequest }) {
if (!opts.captchaAddonId) {
const settings = await this.sysSettingsService.getPublicSettings();
opts.captchaAddonId = settings.captchaAddonId ?? 0;
@@ -46,13 +44,11 @@ export class CaptchaService {
if (!opts.form) {
throw new Error("请输入验证码");
}
const res = await addon.onValidate(opts.form,opts.req);
const res = await addon.onValidate(opts.form, opts.req);
if (!res) {
throw new Error("验证码错误");
}
return true;
}
}
@@ -1,11 +1,11 @@
import { cache, isDev, randomNumber, simpleNanoId } from '@certd/basic';
import { AccessService, AccessSysGetter, CodeErrorException, SysSettingsService } from '@certd/lib-server';
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { ISmsService } from '../sms/api.js';
import { SmsServiceFactory } from '../sms/factory.js';
import { cache, isDev, randomNumber, simpleNanoId } from "@certd/basic";
import { AccessService, AccessSysGetter, CodeErrorException, SysSettingsService } from "@certd/lib-server";
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
import { ISmsService } from "../sms/api.js";
import { SmsServiceFactory } from "../sms/factory.js";
import { CaptchaService } from "./captcha-service.js";
import { EmailService } from './email-service.js';
import { CaptchaRequest } from '../../../plugins/plugin-captcha/api.js';
import { EmailService } from "./email-service.js";
import { CaptchaRequest } from "../../../plugins/plugin-captcha/api.js";
// {data: '<svg.../svg>', text: 'abcd'}
/**
@@ -24,32 +24,30 @@ export class CodeService {
@Inject()
captchaService: CaptchaService;
async checkCaptcha(body:any,req:CaptchaRequest) {
return await this.captchaService.doValidate({form:body,req});
async checkCaptcha(body: any, req: CaptchaRequest) {
return await this.captchaService.doValidate({ form: body, req });
}
/**
*/
async sendSmsCode(
phoneCode = '86',
phoneCode = "86",
mobile: string,
opts?: {
duration?: number,
verificationType?: string,
verificationCodeLength?: number,
},
duration?: number;
verificationType?: string;
verificationCodeLength?: number;
}
) {
if (!mobile) {
throw new Error('手机号不能为空');
throw new Error("手机号不能为空");
}
const verificationCodeLength = Math.floor(Math.max(Math.min(opts?.verificationCodeLength || 4, 8), 4));
const verificationCodeLength = Math.floor(Math.max(Math.min(opts?.verificationCodeLength || 4, 8), 4));
const duration = Math.floor(Math.max(Math.min(opts?.duration || 5, 15), 1));
const sysSettings = await this.sysSettingsService.getPrivateSettings();
if (!sysSettings.sms?.config?.accessId) {
throw new Error('当前站点还未配置短信');
throw new Error("当前站点还未配置短信");
}
const smsType = sysSettings.sms.type;
const smsConfig = sysSettings.sms.config;
@@ -66,7 +64,7 @@ export class CodeService {
phoneCode,
});
const key = this.buildSmsCodeKey(phoneCode, mobile, opts?.verificationType);
const key = this.buildSmsCodeKey(phoneCode, mobile, opts?.verificationType);
cache.set(key, smsCode, {
ttl: duration * 60 * 1000, //5分钟
});
@@ -81,38 +79,38 @@ export class CodeService {
async sendEmailCode(
email: string,
opts?: {
duration?: number,
verificationType?: string,
verificationCodeLength?: number,
},
duration?: number;
verificationType?: string;
verificationCodeLength?: number;
}
) {
if (!email) {
throw new Error('Email不能为空');
throw new Error("Email不能为空");
}
const verificationCodeLength = Math.floor(Math.max(Math.min(opts?.verificationCodeLength || 4, 8), 4));
const verificationCodeLength = Math.floor(Math.max(Math.min(opts?.verificationCodeLength || 4, 8), 4));
const duration = Math.floor(Math.max(Math.min(opts?.duration || 5, 15), 1));
const code = randomNumber(verificationCodeLength);
const templateData = {
code, duration,
code,
duration,
title: "验证码",
content:`您的验证码是${code},请勿泄露`,
notificationType: "registerCode"
}
if (opts?.verificationType === 'forgotPassword') {
templateData.title = '找回密码';
templateData.notificationType = "forgotPassword"
content: `您的验证码是${code},请勿泄露`,
notificationType: "registerCode",
};
if (opts?.verificationType === "forgotPassword") {
templateData.title = "找回密码";
templateData.notificationType = "forgotPassword";
}
await this.emailService.sendByTemplate({
type: templateData.notificationType,
data: templateData,
receivers: [email],
type: templateData.notificationType,
data: templateData,
receivers: [email],
});
const key = this.buildEmailCodeKey(email,opts?.verificationType);
const key = this.buildEmailCodeKey(email, opts?.verificationType);
cache.set(key, code, {
ttl: duration * 60 * 1000, //5分钟
});
@@ -122,44 +120,43 @@ export class CodeService {
/**
* checkSms
*/
async checkSmsCode(opts: { mobile: string; phoneCode: string; smsCode: string; verificationType?: string; throwError: boolean; maxErrorCount?: number }) {
async checkSmsCode(opts: { mobile: string; phoneCode: string; smsCode: string; verificationType?: string; throwError: boolean; maxErrorCount?: number }) {
const key = this.buildSmsCodeKey(opts.phoneCode, opts.mobile, opts.verificationType);
return this.checkValidateCode("sms",key, opts.smsCode, opts.throwError, opts.maxErrorCount);
return this.checkValidateCode("sms", key, opts.smsCode, opts.throwError, opts.maxErrorCount);
}
buildSmsCodeKey(phoneCode: string, mobile: string, verificationType?: string) {
return ['sms', verificationType, phoneCode, mobile].filter(item => !!item).join(':');
return ["sms", verificationType, phoneCode, mobile].filter(item => !!item).join(":");
}
buildEmailCodeKey(email: string, verificationType?: string) {
return ['email', verificationType, email].filter(item => !!item).join(':');
return ["email", verificationType, email].filter(item => !!item).join(":");
}
checkValidateCode(type:string,key: string, userCode: string, throwError = true, maxErrorCount = 3) {
checkValidateCode(type: string, key: string, userCode: string, throwError = true, maxErrorCount = 3) {
// 记录异常次数key
if (isDev() && userCode==="1234567") {
if (isDev() && userCode === "1234567") {
return true;
}
const err_num_key = key + ':err_num';
const err_num_key = key + ":err_num";
//验证邮件验证码
const code = cache.get(key);
if (code == null || code !== userCode) {
let maxRetryCount = false;
if (!!code && maxErrorCount > 0) {
const err_num = cache.get(err_num_key) || 0
if(err_num >= maxErrorCount - 1) {
const err_num = cache.get(err_num_key) || 0;
if (err_num >= maxErrorCount - 1) {
maxRetryCount = true;
cache.delete(key);
cache.delete(err_num_key);
} else {
cache.set(err_num_key, err_num + 1, {
ttl: 30 * 60 * 1000
ttl: 30 * 60 * 1000,
});
}
}
if (throwError) {
const label = type ==='sms' ? '手机' : '邮箱';
throw new CodeErrorException(!maxRetryCount ? `${label}验证码错误`: `${label}验证码错误请获取新的验证码`);
const label = type === "sms" ? "手机" : "邮箱";
throw new CodeErrorException(!maxRetryCount ? `${label}验证码错误` : `${label}验证码错误请获取新的验证码`);
}
return false;
}
@@ -169,8 +166,8 @@ export class CodeService {
}
checkEmailCode(opts: { validateCode: string; email: string; verificationType?: string; throwError: boolean; maxErrorCount?: number }) {
const key = this.buildEmailCodeKey(opts.email, opts.verificationType);
return this.checkValidateCode('email',key, opts.validateCode, opts.throwError, opts.maxErrorCount);
const key = this.buildEmailCodeKey(opts.email, opts.verificationType);
return this.checkValidateCode("email", key, opts.validateCode, opts.throwError, opts.maxErrorCount);
}
compile(templateString: string) {
@@ -183,11 +180,10 @@ export class CodeService {
);
}
buildValidationValueKey(code:string) {
buildValidationValueKey(code: string) {
return `validationValue:${code}`;
}
setValidationValue(value:any) {
setValidationValue(value: any) {
const randomCode = simpleNanoId(12);
const key = this.buildValidationValueKey(randomCode);
cache.set(key, value, {
@@ -195,7 +191,7 @@ export class CodeService {
});
return randomCode;
}
getValidationValue(code:string) {
getValidationValue(code: string) {
return cache.get(this.buildValidationValueKey(code));
}
}
@@ -1,18 +1,18 @@
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
import type { EmailSend, EmailSendByTemplateReq } from '@certd/pipeline';
import { IEmailService } from '@certd/pipeline';
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
import type { EmailSend, EmailSendByTemplateReq } from "@certd/pipeline";
import { IEmailService } from "@certd/pipeline";
import { logger } from '@certd/basic';
import { isComm, isPlus } from '@certd/plus-core';
import { logger } from "@certd/basic";
import { isComm, isPlus } from "@certd/plus-core";
import nodemailer from 'nodemailer';
import { SendMailOptions } from 'nodemailer';
import { UserSettingsService } from '../../mine/service/user-settings-service.js';
import { AddonService, PlusService, SysEmailConf, SysInstallInfo, SysSettingsService, SysSiteInfo } from '@certd/lib-server';
import { getEmailSettings } from '../../sys/settings/fix.js';
import nodemailer from "nodemailer";
import { SendMailOptions } from "nodemailer";
import { UserSettingsService } from "../../mine/service/user-settings-service.js";
import { AddonService, PlusService, SysEmailConf, SysInstallInfo, SysSettingsService, SysSiteInfo } from "@certd/lib-server";
import { getEmailSettings } from "../../sys/settings/fix.js";
import { UserEmailSetting } from "../../mine/service/models.js";
import { AddonGetterService } from '../../pipeline/service/addon-getter-service.js';
import { EmailContent, ITemplateProvider } from '../../../plugins/plugin-template/api.js';
import { AddonGetterService } from "../../pipeline/service/addon-getter-service.js";
import { EmailContent, ITemplateProvider } from "../../../plugins/plugin-template/api.js";
export type EmailConfig = {
host: string;
@@ -43,12 +43,11 @@ export class EmailService implements IEmailService {
@Inject()
addonGetterService: AddonGetterService;
@Inject()
addonService: AddonService
addonService: AddonService;
async sendByPlus(email: EmailSend) {
if (!isPlus()) {
throw new Error('plus not enabled');
throw new Error("plus not enabled");
}
/**
@@ -63,13 +62,13 @@ export class EmailService implements IEmailService {
/**
*/
async send(email: EmailSend) {
logger.info('sendEmail', email);
logger.info("sendEmail", email);
if (!email.receivers || email.receivers.length === 0) {
throw new Error('收件人不能为空');
throw new Error("收件人不能为空");
}
let sysTitle = 'Certd';
let sysTitle = "Certd";
if (isComm()) {
const siteInfo = await this.sysSettingsService.getSetting<SysSiteInfo>(SysSiteInfo);
if (siteInfo) {
@@ -79,11 +78,10 @@ export class EmailService implements IEmailService {
let subject = email.subject;
if (!subject) {
logger.error(new Error('邮件标题不能为空'));
logger.error(new Error("邮件标题不能为空"));
subject = `邮件标题为空,请联系管理员排查`;
}
if (!subject.includes(`${sysTitle}`)) {
subject = `${sysTitle}${subject}`;
}
@@ -96,27 +94,25 @@ export class EmailService implements IEmailService {
//自动使用plus发邮件
return await this.sendByPlus(email);
}
throw new Error('邮件服务器还未设置');
throw new Error("邮件服务器还未设置");
}
if (emailConf.usePlus && isPlus()) {
return await this.sendByPlus(email);
}
await this.sendByCustom(emailConf, email, sysTitle);
logger.info('sendEmail complete: ', email);
logger.info("sendEmail complete: ", email);
}
private async sendByCustom(emailConfig: EmailConfig, email: EmailSend, sysTitle: string) {
const transporter = nodemailer.createTransport(emailConfig);
let from = `${sysTitle} <${emailConfig.sender}>`;
if (emailConfig.sender.includes('<')) {
if (emailConfig.sender.includes("<")) {
from = emailConfig.sender;
}
const mailOptions = {
from: from,
to: email.receivers.join(', '), // list of receivers
to: email.receivers.join(", "), // list of receivers
subject: email.subject,
text: email.content,
html: email.html,
@@ -129,8 +125,8 @@ export class EmailService implements IEmailService {
await this.sendByTemplate({
type: "common",
data: {
title: '测试邮件,from certd',
content: '测试邮件,from certd',
title: "测试邮件,from certd",
content: "测试邮件,from certd",
url: await this.getTestEmailUrl(),
},
receivers: [receiver],
@@ -147,41 +143,41 @@ export class EmailService implements IEmailService {
}
async list(userId: any) {
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId,null, UserEmailSetting)
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId, null, UserEmailSetting);
return userEmailSetting.list;
}
async delete(userId: any, email: string) {
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId, null, UserEmailSetting)
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId, null, UserEmailSetting);
userEmailSetting.list = userEmailSetting.list.filter(item => item !== email);
await this.settingsService.saveSetting(userId, null, userEmailSetting)
await this.settingsService.saveSetting(userId, null, userEmailSetting);
}
async add(userId: any, email: string) {
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId, null, UserEmailSetting)
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId, null, UserEmailSetting);
//如果已存在
if (userEmailSetting.list.includes(email)) {
return
return;
}
userEmailSetting.list.unshift(email)
await this.settingsService.saveSetting(userId, null, userEmailSetting)
userEmailSetting.list.unshift(email);
await this.settingsService.saveSetting(userId, null, userEmailSetting);
}
async sendByTemplate(req: EmailSendByTemplateReq) {
let content = null
let content = null;
const emailConf = await this.sysSettingsService.getSetting<SysEmailConf>(SysEmailConf);
const template = emailConf?.templates?.[req.type]
if (isPlus() && template && template.addonId) {
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getAddonById(template.addonId, true, 0,null)
const template = emailConf?.templates?.[req.type];
if (isPlus() && template && template.addonId) {
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getAddonById(template.addonId, true, 0, null);
if (addon) {
content = await addon.buildContent({ data: req.data })
content = await addon.buildContent({ data: req.data });
}
}
if (isPlus() && !content ) {
if (isPlus() && !content) {
//看看有没有通用模版
if (emailConf?.templates?.common && emailConf?.templates?.common.addonId) {
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getAddonById(emailConf.templates.common.addonId, true, 0,null)
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getAddonById(emailConf.templates.common.addonId, true, 0, null);
if (addon) {
content = await addon.buildContent({ data: req.data })
content = await addon.buildContent({ data: req.data });
}
}
}
@@ -189,21 +185,21 @@ export class EmailService implements IEmailService {
// 没有找到模版,使用默认模版
if (!content) {
try {
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getBlank("emailTemplate", req.type)
content = await addon.buildDefaultContent({ data: req.data })
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getBlank("emailTemplate", req.type);
content = await addon.buildDefaultContent({ data: req.data });
} catch (e) {
// 对应的通知类型模版可能没有注册或者开发
}
}
if (!content) {
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getBlank("emailTemplate", "common")
content = await addon.buildDefaultContent({ data: req.data })
const addon: ITemplateProvider<EmailContent> = await this.addonGetterService.getBlank("emailTemplate", "common");
content = await addon.buildDefaultContent({ data: req.data });
}
return await this.send({
...content,
receivers: req.receivers,
attachments: req.attachments,
})
});
}
}
@@ -1,9 +1,9 @@
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { BaseService } from '@certd/lib-server';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { merge } from 'lodash-es';
import { GroupEntity } from '../entity/group.js';
import { Provide, Scope, ScopeEnum } from "@midwayjs/core";
import { BaseService } from "@certd/lib-server";
import { InjectEntityModel } from "@midwayjs/typeorm";
import { Repository } from "typeorm";
import { merge } from "lodash-es";
import { GroupEntity } from "../entity/group.js";
@Provide()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
@@ -18,7 +18,7 @@ export class GroupService extends BaseService<GroupEntity> {
async add(bean: any) {
if (!bean.type) {
throw new Error('type is required');
throw new Error("type is required");
}
bean = merge(
{
@@ -1,50 +1,50 @@
import { logger } from "@certd/basic"
import { logger } from "@certd/basic";
export class BackTaskExecutor {
tasks: Record<string, Record<string, BackTask>> = {}
tasks: Record<string, Record<string, BackTask>> = {};
start(task: BackTask) {
const type = task.type || 'default'
const type = task.type || "default";
if (!this.tasks[type]) {
this.tasks[type] = {}
this.tasks[type] = {};
}
const oldTask = this.tasks[type][task.key]
if (oldTask ){
const oldTask = this.tasks[type][task.key];
if (oldTask) {
if (oldTask.status === "running") {
throw new Error(`任务 ${task.title} 正在运行中`)
throw new Error(`任务 ${task.title} 正在运行中`);
}
this.clear(type, task.key);
}
this.tasks[type][task.key] = task
this.tasks[type][task.key] = task;
this.run(task);
}
get(type: string, key: string) {
if (!this.tasks[type]) {
this.tasks[type] = {}
this.tasks[type] = {};
}
return this.tasks[type][key]
return this.tasks[type][key];
}
removeIsEnd(type: string, key: string) {
const task = this.tasks[type]?.[key]
const task = this.tasks[type]?.[key];
if (task && task.status !== "running") {
this.clear(type, key);
}
}
clear(type: string, key: string) {
const task = this.tasks[type]?.[key]
const task = this.tasks[type]?.[key];
if (task) {
task.clearTimeout();
delete this.tasks[type][key]
delete this.tasks[type][key];
}
}
private async run(task: BackTask) {
const type = task.type || 'default'
const type = task.type || "default";
if (task.status === "running") {
throw new Error(`任务 ${type}${task.key} 正在运行中`)
throw new Error(`任务 ${type}${task.key} 正在运行中`);
}
task.startTime = Date.now();
task.clearTimeout();
@@ -54,84 +54,78 @@ export class BackTaskExecutor {
} catch (e) {
logger.error(`任务 ${task.title}[${type}-${task.key}] 执行失败`, e.message);
task.status = "failed";
task.addError(e.message)
task.addError(e.message);
} finally {
task.endTime = Date.now();
task.status = "done";
task.setTimeoutId(setTimeout(() => {
this.clear(type, task.key);
}, 24 * 60 * 60 * 1000));
task.setTimeoutId(
setTimeout(() => {
this.clear(type, task.key);
}, 24 * 60 * 60 * 1000)
);
delete task.run;
}
}
}
export class BackTask {
type: string;
key: string;
title: string;
total: number = 0;
current: number = 0;
skip: number = 0;
total = 0;
current = 0;
skip = 0;
startTime: number;
endTime: number;
status: string = "pending";
status = "pending";
errors?: string[] = [];
private _timeoutId?: NodeJS.Timeout;
private _run: (task: BackTask) => Promise<void>;
constructor(opts: {
type: string,
key: string, title: string, run: (task: BackTask) => Promise<void>
}) {
const { key, title, run, type } = opts
this.type = type
constructor(opts: { type: string; key: string; title: string; run: (task: BackTask) => Promise<void> }) {
const { key, title, run, type } = opts;
this.type = type;
this.key = key;
this.title = title;
this._run = run;
Object.defineProperty(this, '_run', {
Object.defineProperty(this, "_run", {
enumerable: false,
value: this._run
})
Object.defineProperty(this, '_timeoutId', {
enumerable: false,
value: null
})
Object.defineProperty(this, 'progress', {
get: ()=> {
return this.getProgress()
},
enumerable: true, // 关键:设置为可枚举
configurable: true
value: this._run,
});
Object.defineProperty(this, 'successCount', {
get: ()=> {
return this.getSuccessCount()
Object.defineProperty(this, "_timeoutId", {
enumerable: false,
value: null,
});
Object.defineProperty(this, "progress", {
get: () => {
return this.getProgress();
},
enumerable: true, // 关键:设置为可枚举
configurable: true
})
Object.defineProperty(this, 'errorCount', {
get: ()=> {
return this.getErrorCount()
enumerable: true, // 关键:设置为可枚举
configurable: true,
});
Object.defineProperty(this, "successCount", {
get: () => {
return this.getSuccessCount();
},
enumerable: true, // 关键:设置为可枚举
configurable: true
})
Object.defineProperty(this, 'skipCount', {
get: ()=> {
return this.getSkipCount()
enumerable: true, // 关键:设置为可枚举
configurable: true,
});
Object.defineProperty(this, "errorCount", {
get: () => {
return this.getErrorCount();
},
enumerable: true, // 关键:设置为可枚举
configurable: true
})
enumerable: true, // 关键:设置为可枚举
configurable: true,
});
Object.defineProperty(this, "skipCount", {
get: () => {
return this.getSkipCount();
},
enumerable: true, // 关键:设置为可枚举
configurable: true,
});
}
async run(task: BackTask) {
@@ -145,7 +139,6 @@ export class BackTask {
}
}
setTimeoutId(timeoutId: NodeJS.Timeout) {
this.clearTimeout();
this._timeoutId = timeoutId;
@@ -155,34 +148,33 @@ export class BackTask {
this.total = total;
}
incrementCurrent() {
this.current++
this.current++;
}
addError(error: string) {
logger.error(error)
this.errors.push(error)
logger.error(error);
this.errors.push(error);
}
getErrorCount() {
return this.errors.length
return this.errors.length;
}
getSkipCount() {
return this.skip
return this.skip;
}
getSuccessCount() {
return this.current - this.errors.length
return this.current - this.errors.length;
}
getProgress() {
return (this.current * 1.0 / this.total * 100.0);
return ((this.current * 1.0) / this.total) * 100.0;
}
incrementSkip() {
this.skip++
this.skip++;
}
}
export const taskExecutor = new BackTaskExecutor();
export const taskExecutor = new BackTaskExecutor();
@@ -1,6 +1,6 @@
import { logger } from '@certd/basic';
import { ISmsService, PluginInputs, SmsPluginCtx } from './api.js';
import { AliyunAccess, AliyunClient } from '../../../plugins/plugin-lib/aliyun/index.js';
import { logger } from "@certd/basic";
import { ISmsService, PluginInputs, SmsPluginCtx } from "./api.js";
import { AliyunAccess, AliyunClient } from "../../../plugins/plugin-lib/aliyun/index.js";
export type AliyunSmsConfig = {
accessId: string;
@@ -11,30 +11,30 @@ export type AliyunSmsConfig = {
export class AliyunSmsService implements ISmsService {
static getDefine() {
return {
name: 'aliyun',
desc: '阿里云短信服务',
name: "aliyun",
desc: "阿里云短信服务",
input: {
accessId: {
title: '阿里云授权',
title: "阿里云授权",
component: {
name: 'access-selector',
type: 'aliyun',
name: "access-selector",
type: "aliyun",
},
required: true,
},
signName: {
title: '签名',
title: "签名",
component: {
name: 'a-input',
vModel: 'value',
name: "a-input",
vModel: "value",
},
required: true,
},
codeTemplateId: {
title: '验证码模板Id',
title: "验证码模板Id",
component: {
name: 'a-input',
vModel: 'value',
name: "a-input",
vModel: "value",
},
required: true,
},
@@ -55,8 +55,8 @@ export class AliyunSmsService implements ISmsService {
await aliyunClinet.init({
accessKeyId: access.accessKeyId,
accessKeySecret: access.accessKeySecret,
endpoint: 'https://dysmsapi.aliyuncs.com',
apiVersion: '2017-05-25',
endpoint: "https://dysmsapi.aliyuncs.com",
apiVersion: "2017-05-25",
});
const smsConfig = this.ctx.config;
const phoneNumber = phoneCode + mobile;
@@ -67,6 +67,6 @@ export class AliyunSmsService implements ISmsService {
TemplateParam: `{"code":"${code}"}`,
};
await aliyunClinet.request('SendSms', params);
await aliyunClinet.request("SendSms", params);
}
}
@@ -1,4 +1,4 @@
import { FormItemProps, IAccessService } from '@certd/pipeline';
import { FormItemProps, IAccessService } from "@certd/pipeline";
export interface ISmsService {
sendSmsCode(opts: { mobile: string; code: string; phoneCode: string }): Promise<void>;
@@ -1,4 +1,3 @@
export class SmsServiceFactory {
static async createSmsService(type: string) {
const cls = await this.GetClassByType(type);
@@ -7,17 +6,17 @@ export class SmsServiceFactory {
static async GetClassByType(type: string) {
switch (type) {
case 'aliyun':
const {AliyunSmsService} = await import("./aliyun-sms.js")
case "aliyun":
const { AliyunSmsService } = await import("./aliyun-sms.js");
return AliyunSmsService;
case 'yfysms':
const {YfySmsService} = await import("./yfy-sms.js")
case "yfysms":
const { YfySmsService } = await import("./yfy-sms.js");
return YfySmsService;
case 'tencent':
const {TencentSmsService} = await import("./tencent-sms.js")
case "tencent":
const { TencentSmsService } = await import("./tencent-sms.js");
return TencentSmsService;
default:
throw new Error('不支持的短信服务类型');
throw new Error("不支持的短信服务类型");
}
}
@@ -1,5 +1,5 @@
import { TencentAccess } from '../../../plugins/plugin-lib/tencent/access.js';
import {ISmsService, PluginInputs, SmsPluginCtx} from './api.js';
import { TencentAccess } from "../../../plugins/plugin-lib/tencent/access.js";
import { ISmsService, PluginInputs, SmsPluginCtx } from "./api.js";
export type TencentSmsConfig = {
accessId: string;
@@ -12,53 +12,53 @@ export type TencentSmsConfig = {
export class TencentSmsService implements ISmsService {
static getDefine() {
return {
name: 'tencent',
desc: '腾讯云短信服务',
name: "tencent",
desc: "腾讯云短信服务",
input: {
accessId: {
title: '腾讯云授权',
title: "腾讯云授权",
component: {
name: 'access-selector',
type: 'tencent',
name: "access-selector",
type: "tencent",
},
required: true,
},
region: {
title: '区域',
value:"ap-beijing",
title: "区域",
value: "ap-beijing",
component: {
name: 'a-select',
vModel: 'value',
options:[
{value:"ap-beijing",label:"华北地区(北京)"},
{value:"ap-guangzhou",label:"华南地区(广州)"},
{value:"ap-nanjing",label:"华东地区(南京)"},
]
name: "a-select",
vModel: "value",
options: [
{ value: "ap-beijing", label: "华北地区(北京)" },
{ value: "ap-guangzhou", label: "华南地区(广州)" },
{ value: "ap-nanjing", label: "华东地区(南京)" },
],
},
helper:"随便选一个",
helper: "随便选一个",
required: true,
},
signName: {
title: '签名',
title: "签名",
component: {
name: 'a-input',
vModel: 'value',
name: "a-input",
vModel: "value",
},
required: true,
},
appId: {
title: '应用ID',
title: "应用ID",
component: {
name: 'a-input',
vModel: 'value',
name: "a-input",
vModel: "value",
},
required: true,
},
codeTemplateId: {
title: '验证码模板Id',
title: "验证码模板Id",
component: {
name: 'a-input',
vModel: 'value',
name: "a-input",
vModel: "value",
},
required: true,
},
@@ -72,13 +72,11 @@ export class TencentSmsService implements ISmsService {
this.ctx = ctx;
}
async getClient() {
const sdk = await import('tencentcloud-sdk-nodejs/tencentcloud/services/sms/v20210111/index.js');
const sdk = await import("tencentcloud-sdk-nodejs/tencentcloud/services/sms/v20210111/index.js");
const client = sdk.v20210111.Client;
const access = await this.ctx.accessService.getById<TencentAccess>(this.ctx.config.accessId);
// const region = this.region;
const clientConfig = {
credential: {
@@ -102,15 +100,11 @@ export class TencentSmsService implements ISmsService {
const client = await this.getClient();
const smsConfig = this.ctx.config;
const params = {
"PhoneNumberSet": [
`+${phoneCode}${mobile}`
],
"SmsSdkAppId": smsConfig.appId,
"TemplateId": smsConfig.codeTemplateId,
"SignName": smsConfig.signName,
"TemplateParamSet": [
code
]
PhoneNumberSet: [`+${phoneCode}${mobile}`],
SmsSdkAppId: smsConfig.appId,
TemplateId: smsConfig.codeTemplateId,
SignName: smsConfig.signName,
TemplateParamSet: [code],
};
const ret = await client.SendSms(params);
this.checkRet(ret);
@@ -118,7 +112,7 @@ export class TencentSmsService implements ISmsService {
checkRet(ret: any) {
if (!ret || ret.Error) {
throw new Error('执行失败:' + ret.Error.Code + ',' + ret.Error.Message);
throw new Error("执行失败:" + ret.Error.Code + "," + ret.Error.Message);
}
}
}
@@ -1,6 +1,6 @@
import { http, utils } from '@certd/basic';
import { ISmsService, PluginInputs, SmsPluginCtx } from './api.js';
import { YfySmsAccess } from '../../../plugins/plugin-plus/yidun/access-sms.js';
import { http, utils } from "@certd/basic";
import { ISmsService, PluginInputs, SmsPluginCtx } from "./api.js";
import { YfySmsAccess } from "../../../plugins/plugin-plus/yidun/access-sms.js";
export type YfySmsConfig = {
accessId: string;
@@ -10,22 +10,22 @@ export type YfySmsConfig = {
export class YfySmsService implements ISmsService {
static getDefine() {
return {
name: 'yfysms',
desc: '易发云短信',
name: "yfysms",
desc: "易发云短信",
input: {
accessId: {
title: '易发云短信授权',
title: "易发云短信授权",
component: {
name: 'access-selector',
type: 'yfysms',
name: "access-selector",
type: "yfysms",
},
required: true,
},
signName: {
title: '签名',
title: "签名",
component: {
name: 'a-input',
vModel: 'value',
name: "a-input",
vModel: "value",
},
required: true,
},
@@ -44,10 +44,10 @@ export class YfySmsService implements ISmsService {
const access = await this.ctx.accessService.getById<YfySmsAccess>(this.ctx.config.accessId);
const res = await http.request({
url: 'http://sms.yfyidc.cn/sms/',
method: 'post',
url: "http://sms.yfyidc.cn/sms/",
method: "post",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
"Content-Type": "application/x-www-form-urlencoded",
},
data: {
/**
@@ -75,40 +75,40 @@ export class YfySmsService implements ISmsService {
* 9 用户已封禁
* 10 未实名认证
*/
let message = '';
let message = "";
switch (res) {
case 1:
message = '余额不足';
message = "余额不足";
break;
case 2:
message = '用户不存在';
message = "用户不存在";
break;
case 3:
message = 'KEY错误';
message = "KEY错误";
break;
case 4:
message = '发送失败';
message = "发送失败";
break;
case 5:
message = '签名不存在';
message = "签名不存在";
break;
case 6:
message = '签名审核未通过';
message = "签名审核未通过";
break;
case 7:
message = '当前发信短信已达到上限';
message = "当前发信短信已达到上限";
break;
case 8:
message = '有违规词';
message = "有违规词";
break;
case 9:
message = '用户已封禁';
message = "用户已封禁";
break;
case 10:
message = '未实名认证';
message = "未实名认证";
break;
default:
message = '未知错误';
message = "未知错误";
}
throw new Error(`发送短信失败:${message}`);
}