mirror of https://github.com/certd/certd
perf: 首页新增修改密码提示
parent
61d6b06c56
commit
0772d3b3fd
|
@ -4,6 +4,7 @@ import { FormItemProps, HistoryResult, Pipeline } from "../dt/index.js";
|
||||||
import { HttpClient, ILogger, utils } from "@certd/basic";
|
import { HttpClient, ILogger, utils } from "@certd/basic";
|
||||||
import * as _ from "lodash-es";
|
import * as _ from "lodash-es";
|
||||||
import { IEmailService } from "../service/index.js";
|
import { IEmailService } from "../service/index.js";
|
||||||
|
import { isPlus } from "@certd/plus-core";
|
||||||
|
|
||||||
export type NotificationBody = {
|
export type NotificationBody = {
|
||||||
userId?: number;
|
userId?: number;
|
||||||
|
@ -65,9 +66,17 @@ export type NotificationContext = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export abstract class BaseNotification implements INotification {
|
export abstract class BaseNotification implements INotification {
|
||||||
|
define!: NotificationDefine;
|
||||||
ctx!: NotificationContext;
|
ctx!: NotificationContext;
|
||||||
http!: HttpClient;
|
http!: HttpClient;
|
||||||
logger!: ILogger;
|
logger!: ILogger;
|
||||||
|
|
||||||
|
async doSend(body: NotificationBody) {
|
||||||
|
if (this.define.needPlus && !isPlus()) {
|
||||||
|
body.content = `${body.content}\n\n注意:此通知渠道已调整为专业版功能,后续版本将不再支持发送,请尽快修改或升级为专业版`;
|
||||||
|
}
|
||||||
|
return await this.send(body);
|
||||||
|
}
|
||||||
abstract send(body: NotificationBody): Promise<void>;
|
abstract send(body: NotificationBody): Promise<void>;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
@ -77,6 +86,9 @@ export abstract class BaseNotification implements INotification {
|
||||||
this.http = ctx.http;
|
this.http = ctx.http;
|
||||||
this.logger = ctx.logger;
|
this.logger = ctx.logger;
|
||||||
}
|
}
|
||||||
|
setDefine = (define: NotificationDefine) => {
|
||||||
|
this.define = define;
|
||||||
|
};
|
||||||
|
|
||||||
async onRequest(req: NotificationRequestHandleReq) {
|
async onRequest(req: NotificationRequestHandleReq) {
|
||||||
if (!req.action) {
|
if (!req.action) {
|
||||||
|
@ -98,7 +110,7 @@ export abstract class BaseNotification implements INotification {
|
||||||
}
|
}
|
||||||
|
|
||||||
async onTestRequest() {
|
async onTestRequest() {
|
||||||
await this.send({
|
await this.doSend({
|
||||||
userId: 0,
|
userId: 0,
|
||||||
title: "【Certd】测试通知,标题长度测试、测试、测试",
|
title: "【Certd】测试通知,标题长度测试、测试、测试",
|
||||||
content: "测试通知",
|
content: "测试通知",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
import { Decorator } from "../decorator/index.js";
|
import { Decorator } from "../decorator/index.js";
|
||||||
import * as _ from "lodash-es";
|
import * as _ from "lodash-es";
|
||||||
import { notificationRegistry } from "./registry.js";
|
import { notificationRegistry } from "./registry.js";
|
||||||
import { NotificationBody, NotificationContext, NotificationDefine, NotificationInputDefine, NotificationInstanceConfig } from "./api.js";
|
import { BaseNotification, NotificationBody, NotificationContext, NotificationDefine, NotificationInputDefine, NotificationInstanceConfig } from "./api.js";
|
||||||
|
import { isPlus } from "@certd/plus-core";
|
||||||
|
|
||||||
// 提供一个唯一 key
|
// 提供一个唯一 key
|
||||||
export const NOTIFICATION_CLASS_KEY = "pipeline:notification";
|
export const NOTIFICATION_CLASS_KEY = "pipeline:notification";
|
||||||
|
@ -43,6 +44,7 @@ export async function newNotification(type: string, input: any, ctx: Notificatio
|
||||||
if (register == null) {
|
if (register == null) {
|
||||||
throw new Error(`notification ${type} not found`);
|
throw new Error(`notification ${type} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const plugin = new register.target();
|
const plugin = new register.target();
|
||||||
for (const key in input) {
|
for (const key in input) {
|
||||||
|
@ -51,12 +53,16 @@ export async function newNotification(type: string, input: any, ctx: Notificatio
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
throw new Error("ctx is required");
|
throw new Error("ctx is required");
|
||||||
}
|
}
|
||||||
|
plugin.setDefine(register.define);
|
||||||
plugin.setCtx(ctx);
|
plugin.setCtx(ctx);
|
||||||
await plugin.onInstance();
|
await plugin.onInstance();
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sendNotification(opts: { config: NotificationInstanceConfig; ctx: NotificationContext; body: NotificationBody }) {
|
export async function sendNotification(opts: { config: NotificationInstanceConfig; ctx: NotificationContext; body: NotificationBody }) {
|
||||||
const notification = await newNotification(opts.config.type, opts.config.setting, opts.ctx);
|
const notification: BaseNotification = await newNotification(opts.config.type, opts.config.setting, opts.ctx);
|
||||||
await notification.send(opts.body);
|
if (notification.define.needPlus && !isPlus()) {
|
||||||
|
opts.body.content = `${opts.body.content}\n\n注意:此通知渠道已调整为专业版功能,后续版本将不再支持发送,请尽快修改或升级为专业版`;
|
||||||
|
}
|
||||||
|
await notification.doSend(opts.body);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ export interface UserInfoRes {
|
||||||
nickName: string;
|
nickName: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
roleIds: number[];
|
roleIds: number[];
|
||||||
|
isWeak?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LoginRes {
|
export interface LoginRes {
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
<template>
|
||||||
|
<a-button v-if="showButton" type="primary" @click="open">修改密码</a-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { CrudOptions, useColumns, useFormWrapper } from "@fast-crud/fast-crud";
|
||||||
|
import * as api from "/@/views/certd/mine/api";
|
||||||
|
import { notification } from "ant-design-vue";
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
showButton: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
let passwordFormRef = ref();
|
||||||
|
|
||||||
|
const validatePass1 = async (rule: any, value: any) => {
|
||||||
|
if (value === "") {
|
||||||
|
throw new Error("请输入密码");
|
||||||
|
}
|
||||||
|
const formData = passwordFormRef.value.getFormData();
|
||||||
|
if (formData.confirmNewPassword !== "") {
|
||||||
|
passwordFormRef.value.formRef.formRef.validateFields(["confirmNewPassword"]);
|
||||||
|
}
|
||||||
|
if (formData.password === formData.newPassword) {
|
||||||
|
throw new Error("新密码不能和旧密码相同");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const validatePass2 = async (rule: any, value: any) => {
|
||||||
|
if (value === "") {
|
||||||
|
throw new Error("请再次输入密码");
|
||||||
|
} else if (value !== passwordFormRef.value.getFormData().newPassword) {
|
||||||
|
throw new Error("两次输入密码不一致!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const { openDialog } = useFormWrapper();
|
||||||
|
const { buildFormOptions } = useColumns();
|
||||||
|
const passwordFormOptions: CrudOptions = {
|
||||||
|
form: {
|
||||||
|
col: {
|
||||||
|
span: 24
|
||||||
|
},
|
||||||
|
wrapper: {
|
||||||
|
title: "修改密码",
|
||||||
|
width: "500px"
|
||||||
|
},
|
||||||
|
async doSubmit({ form }) {
|
||||||
|
await api.changePassword(form);
|
||||||
|
},
|
||||||
|
async afterSubmit() {
|
||||||
|
notification.success({ message: "修改成功" });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
password: {
|
||||||
|
title: "旧密码",
|
||||||
|
type: "password",
|
||||||
|
form: {
|
||||||
|
rules: [{ required: true, message: "请输入旧密码" }]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
newPassword: {
|
||||||
|
title: "新密码",
|
||||||
|
type: "password",
|
||||||
|
form: {
|
||||||
|
rules: [
|
||||||
|
{ required: true, message: "请输入确认密码" },
|
||||||
|
//@ts-ignore
|
||||||
|
{ validator: validatePass1, trigger: "blur" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confirmNewPassword: {
|
||||||
|
title: "确认新密码",
|
||||||
|
type: "password",
|
||||||
|
form: {
|
||||||
|
rules: [
|
||||||
|
{ required: true, message: "请输入确认密码" },
|
||||||
|
//@ts-ignore
|
||||||
|
{ validator: validatePass2, trigger: "blur" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function open(opts: { password: "" }) {
|
||||||
|
const formOptions = buildFormOptions(passwordFormOptions);
|
||||||
|
formOptions.newInstance = true; //新实例打开
|
||||||
|
passwordFormRef.value = await openDialog(formOptions);
|
||||||
|
passwordFormRef.value.setFormData({
|
||||||
|
password: opts.password
|
||||||
|
});
|
||||||
|
console.log(passwordFormRef.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const scope = ref({
|
||||||
|
open: open
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose(scope.value);
|
||||||
|
</script>
|
|
@ -16,7 +16,7 @@
|
||||||
<a-descriptions-item label="邮箱">{{ userInfo.email }}</a-descriptions-item>
|
<a-descriptions-item label="邮箱">{{ userInfo.email }}</a-descriptions-item>
|
||||||
<a-descriptions-item label="手机号">{{ userInfo.phoneCode }}{{ userInfo.mobile }}</a-descriptions-item>
|
<a-descriptions-item label="手机号">{{ userInfo.phoneCode }}{{ userInfo.mobile }}</a-descriptions-item>
|
||||||
<a-descriptions-item label="修改密码">
|
<a-descriptions-item label="修改密码">
|
||||||
<a-button type="primary" @click="changePassword">修改密码</a-button>
|
<change-password-button :show-button="true"> </change-password-button>
|
||||||
</a-descriptions-item>
|
</a-descriptions-item>
|
||||||
</a-descriptions>
|
</a-descriptions>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,8 +26,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import * as api from "./api";
|
import * as api from "./api";
|
||||||
import { Ref, ref } from "vue";
|
import { Ref, ref } from "vue";
|
||||||
import { CrudOptions, useColumns, useFormWrapper } from "@fast-crud/fast-crud";
|
import ChangePasswordButton from "/@/views/certd/mine/change-password-button.vue";
|
||||||
import { notification } from "ant-design-vue";
|
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "UserProfile"
|
name: "UserProfile"
|
||||||
|
@ -39,79 +38,4 @@ const getUserInfo = async () => {
|
||||||
userInfo.value = await api.getMineInfo();
|
userInfo.value = await api.getMineInfo();
|
||||||
};
|
};
|
||||||
getUserInfo();
|
getUserInfo();
|
||||||
|
|
||||||
let passwordFormRef = ref();
|
|
||||||
|
|
||||||
const validatePass1 = async (rule: any, value: any) => {
|
|
||||||
if (value === "") {
|
|
||||||
throw new Error("请输入密码");
|
|
||||||
}
|
|
||||||
if (passwordFormRef.value.getFormData().confirmNewPassword !== "") {
|
|
||||||
passwordFormRef.value.formRef.formRef.validateFields(["confirmNewPassword"]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const validatePass2 = async (rule: any, value: any) => {
|
|
||||||
if (value === "") {
|
|
||||||
throw new Error("请再次输入密码");
|
|
||||||
} else if (value !== passwordFormRef.value.getFormData().newPassword) {
|
|
||||||
throw new Error("两次输入密码不一致!");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { openDialog } = useFormWrapper();
|
|
||||||
const { buildFormOptions } = useColumns();
|
|
||||||
const passwordFormOptions: CrudOptions = {
|
|
||||||
form: {
|
|
||||||
col: {
|
|
||||||
span: 24
|
|
||||||
},
|
|
||||||
wrapper: {
|
|
||||||
title: "修改密码",
|
|
||||||
width: "500px"
|
|
||||||
},
|
|
||||||
async doSubmit({ form }) {
|
|
||||||
await api.changePassword(form);
|
|
||||||
},
|
|
||||||
async afterSubmit() {
|
|
||||||
notification.success({ message: "修改成功" });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
columns: {
|
|
||||||
password: {
|
|
||||||
title: "旧密码",
|
|
||||||
type: "password",
|
|
||||||
form: {
|
|
||||||
rules: [{ required: true, message: "请输入旧密码" }]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
newPassword: {
|
|
||||||
title: "新密码",
|
|
||||||
type: "password",
|
|
||||||
form: {
|
|
||||||
rules: [
|
|
||||||
{ required: true, message: "请输入确认密码" },
|
|
||||||
//@ts-ignore
|
|
||||||
{ validator: validatePass1, trigger: "blur" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
confirmNewPassword: {
|
|
||||||
title: "确认新密码",
|
|
||||||
type: "password",
|
|
||||||
form: {
|
|
||||||
rules: [
|
|
||||||
{ required: true, message: "请输入确认密码" },
|
|
||||||
//@ts-ignore
|
|
||||||
{ validator: validatePass2, trigger: "blur" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
async function changePassword() {
|
|
||||||
const formOptions = buildFormOptions(passwordFormOptions);
|
|
||||||
formOptions.newInstance = true; //新实例打开
|
|
||||||
passwordFormRef.value = await openDialog(formOptions);
|
|
||||||
console.log(passwordFormRef.value);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -121,8 +121,9 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
||||||
|
|
||||||
if (!immediate) {
|
if (!immediate) {
|
||||||
form.body = {};
|
form.body = {};
|
||||||
|
if (define.needPlus) {
|
||||||
mitter.emit("openVipModal");
|
mitter.emit("openVipModal");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!form.name || form.name === lastTitle) {
|
if (!form.name || form.name === lastTitle) {
|
||||||
|
|
|
@ -2,12 +2,33 @@
|
||||||
<fs-page class="home—index">
|
<fs-page class="home—index">
|
||||||
<!-- <page-content />-->
|
<!-- <page-content />-->
|
||||||
<dashboard-user />
|
<dashboard-user />
|
||||||
|
<change-password-button ref="changePasswordButtonRef" :show-button="false"></change-password-button>
|
||||||
</fs-page>
|
</fs-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// import PageContent from "./content/index.vue";
|
|
||||||
import DashboardUser from "./dashboard/index.vue";
|
import DashboardUser from "./dashboard/index.vue";
|
||||||
|
import { useUserStore } from "/@/store/modules/user";
|
||||||
|
import ChangePasswordButton from "/@/views/certd/mine/change-password-button.vue";
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import { Modal } from "ant-design-vue";
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const changePasswordButtonRef = ref();
|
||||||
|
onMounted(() => {
|
||||||
|
if (userStore.getUserInfo.isWeak === true) {
|
||||||
|
Modal.info({
|
||||||
|
title: "修改密码",
|
||||||
|
content: "为了您的账户安全,请立即修改密码",
|
||||||
|
onOk: () => {
|
||||||
|
changePasswordButtonRef.value.open({
|
||||||
|
password: "123456"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
okText: "立即修改"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.home—index {
|
.home—index {
|
||||||
|
|
|
@ -16,6 +16,11 @@ export class MineController extends BaseController {
|
||||||
public async info() {
|
public async info() {
|
||||||
const userId = this.getUserId();
|
const userId = this.getUserId();
|
||||||
const user = await this.userService.info(userId);
|
const user = await this.userService.info(userId);
|
||||||
|
const isWeak = await this.userService.checkPassword('123456', user.password, user.passwordVersion);
|
||||||
|
if (isWeak) {
|
||||||
|
//@ts-ignore
|
||||||
|
user.isWeak = true;
|
||||||
|
}
|
||||||
user.roleIds = await this.roleService.getRoleIdsByUserId(userId);
|
user.roleIds = await this.roleService.getRoleIdsByUserId(userId);
|
||||||
delete user.password;
|
delete user.password;
|
||||||
return this.ok(user);
|
return this.ok(user);
|
||||||
|
|
|
@ -79,12 +79,7 @@ export class RoleController extends CrudController<RoleService> {
|
||||||
* @param permissionIds
|
* @param permissionIds
|
||||||
*/
|
*/
|
||||||
@Post('/authz', { summary: 'sys:auth:role:edit' })
|
@Post('/authz', { summary: 'sys:auth:role:edit' })
|
||||||
async authz(
|
async authz(@Body('roleId') roleId, @Body('permissionIds') permissionIds) {
|
||||||
@Body('roleId')
|
|
||||||
roleId,
|
|
||||||
@Body('permissionIds')
|
|
||||||
permissionIds
|
|
||||||
) {
|
|
||||||
await this.service.authz(roleId, permissionIds);
|
await this.service.authz(roleId, permissionIds);
|
||||||
return this.ok(null);
|
return this.ok(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,9 @@ export class AnPushNotification extends BaseNotification {
|
||||||
channel: this.channel,
|
channel: this.channel,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
await this.http.request(config);
|
const res = await this.http.request(config);
|
||||||
|
if (res.code != 200) {
|
||||||
|
throw new Error('发送失败:' + res.msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue