diff --git a/dolphinscheduler-ui-next/src/layouts/content/components/user/use-dropdown.ts b/dolphinscheduler-ui-next/src/layouts/content/components/user/use-dropdown.ts index 549c82ca02..02455848ab 100644 --- a/dolphinscheduler-ui-next/src/layouts/content/components/user/use-dropdown.ts +++ b/dolphinscheduler-ui-next/src/layouts/content/components/user/use-dropdown.ts @@ -26,15 +26,17 @@ export function useDropDown() { const userStore = useUserStore() const handleSelect = (key: string | number, option: DropdownOption) => { - console.log(key, option) if (key === 'logout') { useLogout() + } else if (key === 'password') { + router.push({ path: 'password' }) } } const useLogout = () => { logout().then(() => { userStore.setSessionId('') + userStore.setUserInfo({}) router.push({ path: 'login' }) }) } diff --git a/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts b/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts index ad33bf64b3..2cb7d96c20 100644 --- a/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts +++ b/dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts @@ -41,6 +41,7 @@ import { SlackOutlined, EnvironmentOutlined, KeyOutlined, + SafetyOutlined, } from '@vicons/antd' export function useDataList() { @@ -208,7 +209,7 @@ export function useDataList() { { label: t('menu.token_manage'), key: 'token-manage', - icon: renderIcon(KeyOutlined), + icon: renderIcon(SafetyOutlined), }, ], }, @@ -231,6 +232,11 @@ export function useDataList() { key: 'profile', icon: renderIcon(UserOutlined), }, + { + label: t('profile.password'), + key: 'password', + icon: renderIcon(KeyOutlined), + }, { label: t('profile.logout'), key: 'logout', diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts index c6e5cf2168..e050b49e0f 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts @@ -31,6 +31,7 @@ const theme = { const profile = { profile: 'Profile', + password: 'Password', logout: 'Logout', } @@ -76,10 +77,22 @@ const home = { state: 'State', } +const password = { + edit_password: 'Edit Password', + password: 'Password', + confirm_password: 'Confirm Password', + password_tips: 'Please enter your password', + confirm_password_tips: 'Please enter your confirm password', + two_password_entries_are_inconsistent: + 'Two Password Entries Are Inconsistent', + submit: 'Submit', +} + export default { login, theme, profile, menu, home, + password, } diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts index 86661fd3aa..341ee3ff9b 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts @@ -31,6 +31,7 @@ const theme = { const profile = { profile: '用户信息', + password: '密码管理', logout: '退出登录', } @@ -76,10 +77,21 @@ const home = { state: '状态', } +const password = { + edit_password: '修改密码', + password: '密码', + confirm_password: '确认密码', + password_tips: '请输入密码', + confirm_password_tips: '请输入确认密码', + two_password_entries_are_inconsistent: '两次密码输入不一致', + submit: '提交', +} + export default { login, theme, profile, menu, home, + password, } diff --git a/dolphinscheduler-ui-next/src/router/routes.ts b/dolphinscheduler-ui-next/src/router/routes.ts index 8e799a5fcc..b09eec9365 100644 --- a/dolphinscheduler-ui-next/src/router/routes.ts +++ b/dolphinscheduler-ui-next/src/router/routes.ts @@ -46,6 +46,14 @@ const basePage: RouteRecordRaw[] = [ title: '首页', }, }, + { + path: '/password', + name: 'password', + component: components['password'], + meta: { + title: '修改密码', + }, + }, ], }, projectsPage, diff --git a/dolphinscheduler-ui-next/src/service/modules/users/types.ts b/dolphinscheduler-ui-next/src/service/modules/users/types.ts index 65a5e3477f..46ae36a52c 100644 --- a/dolphinscheduler-ui-next/src/service/modules/users/types.ts +++ b/dolphinscheduler-ui-next/src/service/modules/users/types.ts @@ -88,6 +88,15 @@ interface RegisterUserReq { userPassword: string } +interface UserInfoRes extends UserReq, IdReq { + userType: string + tenantCode?: any + queueName?: any + alertGroup?: any + createTime: string + updateTime: string +} + export { UserNameReq, UserNamesReq, @@ -103,4 +112,5 @@ export { ListAllReq, ListReq, RegisterUserReq, + UserInfoRes, } diff --git a/dolphinscheduler-ui-next/src/store/user/types.ts b/dolphinscheduler-ui-next/src/store/user/types.ts index 954be0a92d..58657ea928 100644 --- a/dolphinscheduler-ui-next/src/store/user/types.ts +++ b/dolphinscheduler-ui-next/src/store/user/types.ts @@ -15,8 +15,11 @@ * limitations under the License. */ +import type { UserInfoRes } from '@/service/modules/users/types' + interface UserState { sessionId: string + userInfo: UserInfoRes | {} } -export default UserState +export { UserState } diff --git a/dolphinscheduler-ui-next/src/store/user/user.ts b/dolphinscheduler-ui-next/src/store/user/user.ts index 00676ab510..ed933e9eb8 100644 --- a/dolphinscheduler-ui-next/src/store/user/user.ts +++ b/dolphinscheduler-ui-next/src/store/user/user.ts @@ -16,22 +16,30 @@ */ import { defineStore } from 'pinia' -import UserState from '@/store/user/types' +import type { UserState } from '@/store/user/types' +import type { UserInfoRes } from '@/service/modules/users/types' export const useUserStore = defineStore({ id: 'user', state: (): UserState => ({ sessionId: '', + userInfo: {}, }), persist: true, getters: { getSessionId(): string { return this.sessionId }, + getUserInfo(): UserInfoRes | {} { + return this.userInfo + }, }, actions: { setSessionId(sessionId: string): void { this.sessionId = sessionId }, + setUserInfo(userInfo: UserInfoRes | {}): void { + this.userInfo = userInfo + }, }, }) diff --git a/dolphinscheduler-ui-next/src/views/login/index.tsx b/dolphinscheduler-ui-next/src/views/login/index.tsx index db88412ee3..81099e1bff 100644 --- a/dolphinscheduler-ui-next/src/views/login/index.tsx +++ b/dolphinscheduler-ui-next/src/views/login/index.tsx @@ -18,14 +18,14 @@ import { defineComponent, toRefs, withKeys } from 'vue' import styles from './index.module.scss' import { NInput, NButton, NSwitch, NForm, NFormItem } from 'naive-ui' -import { useValidate } from './use-validate' +import { useForm } from './use-form' import { useTranslate } from './use-translate' import { useLogin } from './use-login' const login = defineComponent({ name: 'login', setup() { - const { state, t, locale } = useValidate() + const { state, t, locale } = useForm() const { handleChange } = useTranslate(locale) @@ -85,6 +85,9 @@ const login = defineComponent({ diff --git a/dolphinscheduler-ui-next/src/views/login/use-validate.ts b/dolphinscheduler-ui-next/src/views/login/use-form.ts similarity index 88% rename from dolphinscheduler-ui-next/src/views/login/use-validate.ts rename to dolphinscheduler-ui-next/src/views/login/use-form.ts index d4994a5497..2f47d7e130 100644 --- a/dolphinscheduler-ui-next/src/views/login/use-validate.ts +++ b/dolphinscheduler-ui-next/src/views/login/use-form.ts @@ -16,10 +16,10 @@ */ import { reactive, ref } from 'vue' -import { FormRules } from 'naive-ui' import { useI18n } from 'vue-i18n' +import type { FormRules } from 'naive-ui' -export function useValidate() { +export function useForm() { const { t, locale } = useI18n() const state = reactive({ @@ -33,7 +33,7 @@ export function useValidate() { trigger: ['input', 'blur'], validator() { if (state.loginForm.userName === '') { - return new Error(`${t('login.userName_tips')}`) + return new Error(t('login.userName_tips')) } }, }, @@ -41,7 +41,7 @@ export function useValidate() { trigger: ['input', 'blur'], validator() { if (state.loginForm.userPassword === '') { - return new Error(`${t('login.userPassword_tips')}`) + return new Error(t('login.userPassword_tips')) } }, }, diff --git a/dolphinscheduler-ui-next/src/views/login/use-login.ts b/dolphinscheduler-ui-next/src/views/login/use-login.ts index 42af42b880..8fd8231636 100644 --- a/dolphinscheduler-ui-next/src/views/login/use-login.ts +++ b/dolphinscheduler-ui-next/src/views/login/use-login.ts @@ -17,21 +17,26 @@ import { useRouter } from 'vue-router' import { login } from '@/service/modules/login' +import { getUserInfo } from '@/service/modules/users' import { useUserStore } from '@/store/user/user' -import { SessionIdRes } from '@/service/modules/login/types' import type { Router } from 'vue-router' +import type { SessionIdRes } from '@/service/modules/login/types' +import type { UserInfoRes } from '@/service/modules/users/types' export function useLogin(state: any) { const router: Router = useRouter() const userStore = useUserStore() const handleLogin = () => { - state.loginFormRef.validate((valid: any) => { + state.loginFormRef.validate(async (valid: any) => { if (!valid) { - login({ ...state.loginForm }).then((res: SessionIdRes) => { - userStore.setSessionId(res.sessionId) - router.push({ path: 'home' }) - }) + const loginRes: SessionIdRes = await login({ ...state.loginForm }) + const userInfoRes: UserInfoRes = await getUserInfo() + + await userStore.setSessionId(loginRes.sessionId) + await userStore.setUserInfo(userInfoRes) + + router.push({ path: 'home' }) } }) } diff --git a/dolphinscheduler-ui-next/src/views/password/index.tsx b/dolphinscheduler-ui-next/src/views/password/index.tsx new file mode 100644 index 0000000000..97c213a100 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/password/index.tsx @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineComponent, toRefs } from 'vue' +import { NForm, NFormItem, NButton, NInput } from 'naive-ui' +import { useForm } from './use-form' +import Card from '@/components/card' + +const password = defineComponent({ + name: 'password', + setup() { + const { state, t } = useForm() + + return { ...toRefs(state), t } + }, + render() { + const { rules, passwordForm, t, handlePasswordInput } = this + + return ( + + {{ + default: () => ( +
+ + + + + + + + + + {t('password.submit')} + +
+ ), + }} +
+ ) + }, +}) + +export default password diff --git a/dolphinscheduler-ui-next/src/views/password/use-form.ts b/dolphinscheduler-ui-next/src/views/password/use-form.ts new file mode 100644 index 0000000000..87419b554b --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/password/use-form.ts @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { reactive, ref } from 'vue' +import { useI18n } from 'vue-i18n' +import type { FormRules } from 'naive-ui' + +export function useForm() { + const { t } = useI18n() + + const state = reactive({ + passwordFormRef: ref(), + confirmPasswordItemFormRef: ref(), + passwordForm: { + password: '', + confirmPassword: '', + }, + rules: { + password: { + required: true, + message: t('password.password_tips'), + }, + confirmPassword: [ + { + required: true, + message: t('password.confirm_password_tips'), + }, + { + trigger: ['input'], + message: t('password.two_password_entries_are_inconsistent'), + validator: (rule: any, value: string): any => { + return ( + state.passwordForm.password && + state.passwordForm.password.startsWith(value) && + state.passwordForm.password.length >= value.length + ) + }, + }, + { + trigger: ['blur', 'password-input'], + message: t('password.two_password_entries_are_inconsistent'), + validator: (rule: any, value: string): any => { + return state.passwordForm.password === value + }, + }, + ], + } as FormRules, + + handlePasswordInput: () => { + if (state.passwordForm.confirmPassword) { + state.confirmPasswordItemFormRef.value.validate({ + trigger: 'password-input', + }) + } + }, + }) + + return { state, t } +}