diff --git a/packages/core/basic/src/utils/util.id.ts b/packages/core/basic/src/utils/util.id.ts index ca00030c..977deb30 100644 --- a/packages/core/basic/src/utils/util.id.ts +++ b/packages/core/basic/src/utils/util.id.ts @@ -1,3 +1,4 @@ import { customAlphabet } from 'nanoid'; +export const randomNumber = customAlphabet('1234567890', 4); export const simpleNanoId = customAlphabet('1234567890abcdefghijklmopqrstuvwxyz', 12); diff --git a/packages/core/pipeline/src/service/email.ts b/packages/core/pipeline/src/service/email.ts index e918e2ab..871a185b 100644 --- a/packages/core/pipeline/src/service/email.ts +++ b/packages/core/pipeline/src/service/email.ts @@ -1,5 +1,4 @@ export type EmailSend = { - userId: number; subject: string; content: string; receivers: string[]; diff --git a/packages/libs/lib-server/src/basic/constants.ts b/packages/libs/lib-server/src/basic/constants.ts index 1bac0592..598004a1 100644 --- a/packages/libs/lib-server/src/basic/constants.ts +++ b/packages/libs/lib-server/src/basic/constants.ts @@ -36,6 +36,14 @@ export const Constants = { code: 88, message: '需要VIP', }, + loginError: { + code: 2, + message: '登录失败', + }, + codeError: { + code: 3, + message: '验证码错误', + }, auth: { code: 401, message: '您还未登录或token已过期', diff --git a/packages/libs/lib-server/src/basic/exception/code-error-exception.ts b/packages/libs/lib-server/src/basic/exception/code-error-exception.ts new file mode 100644 index 00000000..cee74052 --- /dev/null +++ b/packages/libs/lib-server/src/basic/exception/code-error-exception.ts @@ -0,0 +1,10 @@ +import { Constants } from '../constants.js'; +import { BaseException } from './base-exception.js'; +/** + * 验证码异常 + */ +export class CodeErrorException extends BaseException { + constructor(message) { + super('CodeErrorException', Constants.res.codeError.code, message ? message : Constants.res.codeError.message); + } +} diff --git a/packages/libs/lib-server/src/basic/exception/common-exception.ts b/packages/libs/lib-server/src/basic/exception/common-exception.ts index c9084840..c9f98068 100644 --- a/packages/libs/lib-server/src/basic/exception/common-exception.ts +++ b/packages/libs/lib-server/src/basic/exception/common-exception.ts @@ -5,10 +5,6 @@ import { BaseException } from './base-exception.js'; */ export class CommonException extends BaseException { constructor(message) { - super( - 'CommonException', - Constants.res.error.code, - message ? message : Constants.res.error.message - ); + super('CommonException', Constants.res.error.code, message ? message : Constants.res.error.message); } } diff --git a/packages/libs/lib-server/src/system/settings/service/models.ts b/packages/libs/lib-server/src/system/settings/service/models.ts index 4cde10c2..7ef22fc5 100644 --- a/packages/libs/lib-server/src/system/settings/service/models.ts +++ b/packages/libs/lib-server/src/system/settings/service/models.ts @@ -14,7 +14,14 @@ export class SysPublicSettings extends BaseSettings { static __key__ = 'sys.public'; static __title__ = '系统公共设置'; static __access__ = 'public'; + registerEnabled = false; + passwordLoginEnabled = true; + usernameRegisterEnabled = false; + mobileRegisterEnabled = false; + smsLoginEnabled = false; + emailRegisterEnabled = false; + limitUserPipelineCount = 0; managerOtherUserPipeline = false; icpNo?: string; @@ -35,6 +42,14 @@ export class SysPrivateSettings extends BaseSettings { dnsResultOrder? = ''; commonCnameEnabled?: boolean = true; + sms?: { + type?: string; + config?: any; + } = { + type: 'aliyun', + config: {}, + }; + removeSecret() { const clone = cloneDeep(this); delete clone.jwtKey; diff --git a/packages/ui/certd-client/src/api/modules/api.basic.ts b/packages/ui/certd-client/src/api/modules/api.basic.ts index 523abb33..3f251c4e 100644 --- a/packages/ui/certd-client/src/api/modules/api.basic.ts +++ b/packages/ui/certd-client/src/api/modules/api.basic.ts @@ -25,6 +25,12 @@ export type PlusInfo = { }; export type SysPublicSetting = { registerEnabled?: boolean; + usernameRegisterEnabled?: boolean; + mobileRegisterEnabled?: boolean; + emailRegisterEnabled?: boolean; + passwordLoginEnabled?: boolean; + smsLoginEnabled?: boolean; + limitUserPipelineCount?: number; managerOtherUserPipeline?: boolean; icpNo?: string; @@ -35,6 +41,10 @@ export type SysPrivateSetting = { httpsProxy?: string; dnsResultOrder?: string; commonCnameEnabled?: boolean; + sms?: { + type?: string; + config?: any; + }; }; export type SysInstallInfo = { siteId: string; @@ -73,3 +83,19 @@ export async function bindUrl(data: any): Promise { data }); } + +export async function sendSmsCode(data: any): Promise { + return await request({ + url: "/basic/code/sendSmsCode", + method: "post", + data + }); +} + +export async function sendEmailCode(data: any): Promise { + return await request({ + url: "/basic/code/sendEmailCode", + method: "post", + data + }); +} diff --git a/packages/ui/certd-client/src/api/modules/api.user.ts b/packages/ui/certd-client/src/api/modules/api.user.ts index 6c757fa3..00a016d3 100644 --- a/packages/ui/certd-client/src/api/modules/api.user.ts +++ b/packages/ui/certd-client/src/api/modules/api.user.ts @@ -14,6 +14,13 @@ export interface LoginReq { password: string; } +export interface SmsLoginReq { + mobile: string; + phoneCode: string; + smsCode: string; + randomStr: string; +} + export interface UserInfoRes { id: string | number; username: string; @@ -52,6 +59,15 @@ export async function login(data: LoginReq): Promise { }); } +export async function loginBySms(data: SmsLoginReq): Promise { + //如果开启了登录与权限模块,则真实登录 + return await request({ + url: "/loginBySms", + method: "post", + data + }); +} + export async function mine(): Promise { if (env.PM_ENABLED === "false") { //没有开启权限模块,模拟登录 diff --git a/packages/ui/certd-client/src/store/modules/user.ts b/packages/ui/certd-client/src/store/modules/user.ts index 21d1566a..25daa6da 100644 --- a/packages/ui/certd-client/src/store/modules/user.ts +++ b/packages/ui/certd-client/src/store/modules/user.ts @@ -4,7 +4,7 @@ import router from "../../router"; import { LocalStorage } from "/src/utils/util.storage"; // @ts-ignore import * as UserApi from "/src/api/modules/api.user"; -import { RegisterReq } from "/src/api/modules/api.user"; +import { RegisterReq, SmsLoginReq } from "/src/api/modules/api.user"; // @ts-ignore import { LoginReq, UserInfoRes } from "/@/api/modules/api.user"; import { message, Modal, notification } from "ant-design-vue"; @@ -63,15 +63,20 @@ export const useUserStore = defineStore({ /** * @description: login */ - async login(params: LoginReq): Promise { + async login(loginType: string, params: LoginReq | SmsLoginReq): Promise { try { - const data = await UserApi.login(params); - const { token, expire } = data; + let loginRes: any = null; + if (loginType === "sms") { + loginRes = await UserApi.loginBySms(params as SmsLoginReq); + } else { + loginRes = await UserApi.login(params as LoginReq); + } + const { token, expire } = loginRes; // save token this.setToken(token, expire); // get user info - return await this.onLoginSuccess(data); + return await this.onLoginSuccess(loginRes); } catch (error) { return null; } diff --git a/packages/ui/certd-client/src/style/common.less b/packages/ui/certd-client/src/style/common.less index ad936aed..1a86ea69 100644 --- a/packages/ui/certd-client/src/style/common.less +++ b/packages/ui/certd-client/src/style/common.less @@ -246,7 +246,8 @@ h1, h2, h3, h4, h5, h6 { .helper { color: #aeaeae; font-size: 12px; - + margin-top:3px; + margin-bottom:3px; &.error{ color: #ff4d4f; } diff --git a/packages/ui/certd-client/src/views/framework/login/index.vue b/packages/ui/certd-client/src/views/framework/login/index.vue index 5a0cb263..794f6556 100644 --- a/packages/ui/certd-client/src/views/framework/login/index.vue +++ b/packages/ui/certd-client/src/views/framework/login/index.vue @@ -5,71 +5,68 @@ class="user-layout-login" name="custom-validation" :model="formState" - :rules="rules" v-bind="layout" @finish="handleFinish" @finish-failed="handleFinishFailed" > - - - - - - - - - - - - - - - + + + - - - - - - - - - - + + @@ -87,6 +84,9 @@ import { defineComponent, reactive, ref, toRaw, computed } from "vue"; import { useUserStore } from "/src/store/modules/user"; import { useSettingStore } from "/@/store/modules/settings"; import { utils } from "@fast-crud/fast-crud"; +import * as api from "/src/api/modules/api.basic"; +import { nanoid } from "nanoid"; +import { notification } from "ant-design-vue"; export default defineComponent({ name: "LoginPage", setup() { @@ -96,39 +96,37 @@ export default defineComponent({ const formRef = ref(); const formState = reactive({ username: "", + phoneCode: "86", mobile: "", password: "", loginType: "password", //password imgCode: "", - smsCode: "" + smsCode: "", + randomStr: "" }); const rules = { mobile: [ { required: true, - trigger: "change", - message: "请输入登录手机号" + message: "请输入手机号" } ], username: [ { required: true, - trigger: "change", message: "请输入用户名" } ], password: [ { required: true, - trigger: "change", message: "请输入登录密码" } ], smsCode: [ { required: true, - trigger: "change", message: "请输入短信验证码" } ] @@ -146,7 +144,8 @@ export default defineComponent({ utils.logger.log(values, formState); loading.value = true; try { - const userInfo = await userStore.login(toRaw(formState)); + const loginType = formState.loginType; + await userStore.login(loginType, toRaw(formState)); } finally { loading.value = false; } @@ -164,8 +163,9 @@ export default defineComponent({ const imageCodeUrl = ref(); function resetImageCode() { - let url = "/basic/code"; - imageCodeUrl.value = url + "?t=" + new Date().getTime(); + formState.randomStr = nanoid(10); + let url = "/api/basic/code/captcha"; + imageCodeUrl.value = url + "?randomStr=" + formState.randomStr; } resetImageCode(); @@ -176,8 +176,25 @@ export default defineComponent({ } return !!formState.smsCode; }); - function sendSmsCode() { - //api.sendSmsCode(); + async function sendSmsCode() { + if (!formState.mobile) { + notification.error({ message: "请输入手机号" }); + return; + } + if (!formState.imgCode) { + notification.error({ message: "请输入图片验证码" }); + return; + } + await api.sendSmsCode({ + phoneCode: formState.phoneCode, + mobile: formState.mobile, + imgCode: formState.imgCode, + randomStr: formState.randomStr + }); + smsTime.value = 60; + setInterval(() => { + smsTime.value--; + }, 1000); } const sysPublicSettings = settingStore.getSysPublic; return { @@ -207,9 +224,9 @@ export default defineComponent({ //margin: 20px !important; margin-bottom: 100px; .user-layout-login { - label { - font-size: 14px; - } + //label { + // font-size: 14px; + //} .login-title { color: @primary-color; @@ -220,9 +237,15 @@ export default defineComponent({ .getCaptcha { display: block; width: 100%; - height: 40px; } + .image-code { + height: 34px; + } + .input-right { + width: 160px; + margin-left: 10px; + } .forge-password { font-size: 14px; } @@ -230,7 +253,6 @@ export default defineComponent({ button.login-button { padding: 0 15px; font-size: 16px; - height: 40px; width: 100%; } @@ -238,7 +260,7 @@ export default defineComponent({ text-align: left; margin-top: 30px; margin-bottom: 30px; - line-height: 22px; + //line-height: 22px; .item-icon { font-size: 24px; @@ -257,8 +279,17 @@ export default defineComponent({ float: right; } } - .iconify { + .fs-icon { color: rgba(0, 0, 0, 0.45); + margin-right: 4px; + } + .ant-input-affix-wrapper { + line-height: 1.8 !important; + font-size: 14px !important; + > * { + line-height: 1.8 !important; + font-size: 14px !important; + } } } } diff --git a/packages/ui/certd-client/src/views/framework/register/index.vue b/packages/ui/certd-client/src/views/framework/register/index.vue index 77159039..babdd286 100644 --- a/packages/ui/certd-client/src/views/framework/register/index.vue +++ b/packages/ui/certd-client/src/views/framework/register/index.vue @@ -11,16 +11,63 @@ @finish="handleFinish" @finish-failed="handleFinishFailed" > - - - - - -