Browse Source

[Feature][UI Next] Add profile function. (#7858)

* [Feature][UI Next] Add profile function.
* Update .env
3.0.0/version-upgrade
songjianet 3 years ago committed by GitHub
parent
commit
30cf030ad9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      dolphinscheduler-ui-next/src/components/card/index.tsx
  2. 13
      dolphinscheduler-ui-next/src/components/modal/index.tsx
  3. 0
      dolphinscheduler-ui-next/src/layouts/content/components/locales/index.module.scss
  4. 26
      dolphinscheduler-ui-next/src/layouts/content/components/locales/index.tsx
  5. 9
      dolphinscheduler-ui-next/src/layouts/content/components/locales/use-dropdown.ts
  6. 6
      dolphinscheduler-ui-next/src/layouts/content/components/navbar/index.tsx
  7. 2
      dolphinscheduler-ui-next/src/layouts/content/components/sidebar/index.tsx
  8. 17
      dolphinscheduler-ui-next/src/layouts/content/index.tsx
  9. 8
      dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts
  10. 19
      dolphinscheduler-ui-next/src/locales/modules/en_US.ts
  11. 17
      dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
  12. 20
      dolphinscheduler-ui-next/src/store/locales/locales.ts
  13. 8
      dolphinscheduler-ui-next/src/store/locales/types.ts
  14. 2
      dolphinscheduler-ui-next/src/utils/index.ts
  15. 22
      dolphinscheduler-ui-next/src/utils/regex.ts
  16. 20
      dolphinscheduler-ui-next/src/views/login/index.tsx
  17. 9
      dolphinscheduler-ui-next/src/views/login/use-translate.ts
  18. 94
      dolphinscheduler-ui-next/src/views/profile/index.tsx
  19. 1
      dolphinscheduler-ui-next/src/views/profile/info.tsx
  20. 75
      dolphinscheduler-ui-next/src/views/profile/use-form.ts
  21. 5
      dolphinscheduler-ui-next/src/views/profile/use-profile.ts
  22. 30
      dolphinscheduler-ui-next/src/views/profile/use-update.ts
  23. 31
      dolphinscheduler-ui-next/src/views/profile/use-userinfo.ts

5
dolphinscheduler-ui-next/src/components/card/index.tsx

@ -27,7 +27,10 @@ const contentStyle = {
}
const props = {
title: String as PropType<string>,
title: {
type: String as PropType<string>,
required: true,
},
}
const Card = defineComponent({

13
dolphinscheduler-ui-next/src/components/modal/index.tsx

@ -35,6 +35,10 @@ const props = {
confirmText: {
type: String as PropType<string>,
},
confirmDisabled: {
type: Boolean as PropType<boolean>,
default: false,
},
}
const Modal = defineComponent({
@ -55,7 +59,7 @@ const Modal = defineComponent({
return { t, onCancel, onConfirm }
},
render() {
const { $slots, t, onCancel, onConfirm } = this
const { $slots, t, onCancel, onConfirm, confirmDisabled } = this
return (
<NModal
@ -71,7 +75,12 @@ const Modal = defineComponent({
<NButton quaternary size='small' onClick={onCancel}>
{this.cancelText || t('modal.cancel')}
</NButton>
<NButton type='info' size='small' onClick={onConfirm}>
<NButton
type='info'
size='small'
onClick={onConfirm}
disabled={confirmDisabled}
>
{this.confirmText || t('modal.confirm')}
</NButton>
</div>

0
dolphinscheduler-ui-next/src/layouts/content/components/language/index.module.scss → dolphinscheduler-ui-next/src/layouts/content/components/locales/index.module.scss

26
dolphinscheduler-ui-next/src/layouts/content/components/language/index.tsx → dolphinscheduler-ui-next/src/layouts/content/components/locales/index.tsx

@ -15,28 +15,28 @@
* limitations under the License.
*/
import { defineComponent, ref, PropType, onMounted } from 'vue'
import { defineComponent, ref, PropType } from 'vue'
import { NDropdown, NIcon, NButton } from 'naive-ui'
import styles from './index.module.scss'
import { DownOutlined } from '@vicons/antd'
import { useDropDown } from './use-dropdown'
import { useLanguageStore } from '@/store/language/language'
import { useLocalesStore } from '@/store/locales/locales'
const Language = defineComponent({
name: 'Language',
const Locales = defineComponent({
name: 'Locales',
props: {
languageOptions: {
localesOptions: {
type: Array as PropType<any>,
default: [],
},
},
setup(props) {
const languageStore = useLanguageStore()
const lang = ref()
lang.value = languageStore.getLang
const chooseVal = ref(props.languageOptions.filter((item: { key: string }) => item.key === lang.value)[0].label)
const localesStore = useLocalesStore()
const chooseVal = ref(
props.localesOptions.filter(
(item: { key: string }) => item.key === localesStore.getLocales
)[0].label
)
const { handleSelect } = useDropDown(chooseVal)
return { handleSelect, chooseVal }
@ -46,7 +46,7 @@ const Language = defineComponent({
<NDropdown
trigger='hover'
show-arrow
options={this.languageOptions}
options={this.localesOptions}
on-select={this.handleSelect}
>
<NButton text>
@ -60,4 +60,4 @@ const Language = defineComponent({
},
})
export default Language
export default Locales

9
dolphinscheduler-ui-next/src/layouts/content/components/language/use-dropdown.ts → dolphinscheduler-ui-next/src/layouts/content/components/locales/use-dropdown.ts

@ -17,17 +17,18 @@
import { DropdownOption } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { useLanguageStore } from '@/store/language/language'
import { useLocalesStore } from '@/store/locales/locales'
import type { Locales } from '@/store/locales/types'
export function useDropDown(chooseVal: any) {
const { locale } = useI18n()
const languageStore = useLanguageStore()
const localesStore = useLocalesStore()
const handleSelect = (key: string | number, option: DropdownOption) => {
// console.log(key, option)
chooseVal.value = option.label
locale.value = key as string
languageStore.setLang(locale.value)
locale.value = key as Locales
localesStore.setLocales(locale.value as Locales)
}
return {
handleSelect,

6
dolphinscheduler-ui-next/src/layouts/content/components/navbar/index.tsx

@ -19,7 +19,7 @@ import { defineComponent, PropType } from 'vue'
import styles from './index.module.scss'
import { NMenu } from 'naive-ui'
import Logo from '../logo'
import Language from '../language'
import Locales from '../locales'
import User from '../user'
import Theme from '../theme'
import { useMenuClick } from './use-menuClick'
@ -32,7 +32,7 @@ const Navbar = defineComponent({
type: Array as PropType<any>,
default: [],
},
languageOptions: {
localesOptions: {
type: Array as PropType<any>,
default: [],
},
@ -59,7 +59,7 @@ const Navbar = defineComponent({
</div>
<div class={styles.settings}>
<Theme />
<Language languageOptions={this.languageOptions} />
<Locales localesOptions={this.localesOptions} />
<User profileOptions={this.profileOptions} />
</div>
</div>

2
dolphinscheduler-ui-next/src/layouts/content/components/sidebar/index.tsx

@ -59,7 +59,7 @@ const Sidebar = defineComponent({
/>
</NLayoutSider>
)
}
},
})
export default Sidebar

17
dolphinscheduler-ui-next/src/layouts/content/index.tsx

@ -21,22 +21,18 @@ import NavBar from './components/navbar'
import SideBar from './components/sidebar'
import { useDataList } from './use-dataList'
import { useMenuStore } from '@/store/menu/menu'
import { useLanguageStore } from '@/store/language/language'
import { useLocalesStore } from '@/store/locales/locales'
import { useI18n } from 'vue-i18n'
const Content = defineComponent({
name: 'Content',
setup() {
const menuStore = useMenuStore()
const { locale } = useI18n()
const languageStore = useLanguageStore()
const lang = ref()
lang.value = languageStore.getLang
const localesStore = useLocalesStore()
const { state, changeMenuOption, changeHeaderMenuOptions } = useDataList()
locale.value = lang.value
locale.value = localesStore.getLocales
onMounted(() => {
menuStore.setMenuKey('home')
@ -54,7 +50,8 @@ const Content = defineComponent({
const genSideMenu = (state: any) => {
const key = menuStore.getMenuKey
state.sideMenuOptions =
state.menuOptions.filter((menu: { key: string }) => menu.key === key)[0].children || []
state.menuOptions.filter((menu: { key: string }) => menu.key === key)[0]
.children || []
state.isShowSide = state.sideMenuOptions.length !== 0
}
@ -67,7 +64,7 @@ const Content = defineComponent({
...toRefs(state),
menuStore,
changeMenuOption,
getSideMenuOptions
getSideMenuOptions,
}
},
render() {
@ -77,7 +74,7 @@ const Content = defineComponent({
<NavBar
onHandleMenuClick={this.getSideMenuOptions}
headerMenuOptions={this.headerMenuOptions}
languageOptions={this.languageOptions}
localesOptions={this.localesOptions}
profileOptions={this.userDropdownOptions}
/>
</NLayoutHeader>

8
dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts

@ -51,7 +51,7 @@ export function useDataList() {
return () => h(NIcon, null, { default: () => h(icon) })
}
const languageOptions = [
const localesOptions = [
{
label: 'English',
key: 'en_US',
@ -82,11 +82,11 @@ export function useDataList() {
const state = reactive({
isShowSide: false,
languageOptions,
localesOptions,
userDropdownOptions,
menuOptions: [],
headerMenuOptions: [],
sideMenuOptions: []
sideMenuOptions: [],
})
const changeMenuOption = (state: any) => {
@ -270,6 +270,6 @@ export function useDataList() {
return {
state,
changeHeaderMenuOptions,
changeMenuOption
changeMenuOption,
}
}

19
dolphinscheduler-ui-next/src/locales/modules/en_US.ts

@ -24,6 +24,11 @@ const login = {
login: 'Login',
}
const modal = {
cancel: 'Cancel',
confirm: 'Confirm',
}
const theme = {
light: 'Light',
dark: 'Dark',
@ -84,7 +89,7 @@ const 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',
'Two password entries are inconsistent',
submit: 'Submit',
}
@ -94,13 +99,25 @@ const profile = {
username: 'Username',
email: 'Email',
phone: 'Phone',
state: 'State',
permission: 'Permission',
create_time: 'Create Time',
update_time: 'Update Time',
administrator: 'Administrator',
ordinary_user: 'Ordinary User',
edit_profile: 'Edit Profile',
username_tips: 'Please enter your username',
email_tips: 'Please enter your email',
email_correct_tips: 'Please enter your email in the correct format',
phone_tips: 'Please enter your phone',
state_tips: 'Please choose your state',
enable: 'Enable',
disable: 'Disable',
}
export default {
login,
modal,
theme,
userDropdown,
menu,

17
dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts

@ -24,6 +24,11 @@ const login = {
login: '登录',
}
const modal = {
cancel: '取消',
confirm: '确定',
}
const theme = {
light: '浅色',
dark: '深色',
@ -93,13 +98,25 @@ const profile = {
username: '用户名',
email: '邮箱',
phone: '手机',
state: '状态',
permission: '权限',
create_time: '创建时间',
update_time: '更新时间',
administrator: '管理员',
ordinary_user: '普通用户',
edit_profile: '编辑用户',
username_tips: '请输入用户名',
email_tips: '请输入邮箱',
email_correct_tips: '请输入正确格式的邮箱',
phone_tips: '请输入手机号',
state_tips: '请选择状态',
enable: '启用',
disable: '禁用',
}
export default {
login,
modal,
theme,
userDropdown,
menu,

20
dolphinscheduler-ui-next/src/store/language/language.ts → dolphinscheduler-ui-next/src/store/locales/locales.ts

@ -16,24 +16,22 @@
*/
import { defineStore } from 'pinia'
import LanguageStore from './types'
import { useStorage } from '@vueuse/core'
import { ref } from 'vue'
import { LocalesStore, Locales } from './types'
export const useLanguageStore = defineStore({
export const useLocalesStore = defineStore({
id: 'language',
state: (): LanguageStore => ({
storageLang: ref('')
state: (): LocalesStore => ({
locales: 'zh_CN',
}),
persist: true,
getters: {
getLang(): string | null {
return window.localStorage.getItem('lang')
getLocales(): Locales {
return this.locales
},
},
actions: {
setLang(lang: string): void {
this.storageLang = useStorage('lang', lang)
this.storageLang = lang
setLocales(lang: Locales): void {
this.locales = lang
},
},
})

8
dolphinscheduler-ui-next/src/store/language/types.ts → dolphinscheduler-ui-next/src/store/locales/types.ts

@ -15,10 +15,10 @@
* limitations under the License.
*/
import { Ref } from 'vue'
type Locales = 'zh_CN' | 'en_US'
interface LanguageStore {
storageLang: Ref
interface LocalesStore {
locales: Locales
}
export default LanguageStore
export { LocalesStore, Locales }

2
dolphinscheduler-ui-next/src/utils/index.ts

@ -16,9 +16,11 @@
*/
import mapping from './mapping'
import regex from './regex'
const utils = {
mapping,
regex,
}
export default utils

22
dolphinscheduler-ui-next/src/utils/regex.ts

@ -0,0 +1,22 @@
/*
* 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.
*/
const regex = {
email: /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/, // support Chinese mailbox
}
export default regex

20
dolphinscheduler-ui-next/src/views/login/index.tsx

@ -15,33 +15,23 @@
* limitations under the License.
*/
import { defineComponent, ref, toRefs, withKeys, onMounted } from 'vue'
import { defineComponent, toRefs, withKeys } from 'vue'
import styles from './index.module.scss'
import { NInput, NButton, NSwitch, NForm, NFormItem } from 'naive-ui'
import { useForm } from './use-form'
import { useTranslate } from './use-translate'
import { useLogin } from './use-login'
import { useLanguageStore } from '@/store/language/language'
import { useLocalesStore } from '@/store/locales/locales'
const login = defineComponent({
name: 'login',
setup() {
const { state, t, locale } = useForm()
const languageStore = useLanguageStore()
const lang = ref()
lang.value = languageStore.getLang
const { handleChange } = useTranslate(locale)
const { handleLogin } = useLogin(state)
const localesStore = useLocalesStore()
onMounted(() => {
// console.log('login', lang)
handleChange(lang.value)
})
return { t, handleChange, handleLogin, ...toRefs(state), lang }
return { t, handleChange, handleLogin, ...toRefs(state), localesStore }
},
render() {
return (
@ -49,7 +39,7 @@ const login = defineComponent({
<div class={styles['language-switch']}>
<NSwitch
onUpdateValue={this.handleChange}
default-value={this.lang}
default-value={this.localesStore.getLocales}
checked-value='en_US'
unchecked-value='zh_CN'
>

9
dolphinscheduler-ui-next/src/views/login/use-translate.ts

@ -16,14 +16,15 @@
*/
import { WritableComputedRef } from 'vue'
import { useLanguageStore } from '@/store/language/language'
import { useLocalesStore } from '@/store/locales/locales'
import type { Locales } from '@/store/locales/types'
export function useTranslate(locale: WritableComputedRef<string>) {
const languageStore = useLanguageStore()
const localesStore = useLocalesStore()
const handleChange = (value: string) => {
const handleChange = (value: Locales) => {
locale.value = value
languageStore.setLang(value)
localesStore.setLocales(value)
}
return {
handleChange,

94
dolphinscheduler-ui-next/src/views/profile/index.tsx

@ -15,33 +15,113 @@
* limitations under the License.
*/
import { defineComponent } from 'vue'
import { useI18n } from 'vue-i18n'
import { NButton } from 'naive-ui'
import { defineComponent, onMounted, ref, toRefs } from 'vue'
import { useForm } from './use-form'
import {
NButton,
NForm,
NFormItem,
NInput,
NRadioGroup,
NRadio,
} from 'naive-ui'
import { useUserinfo } from './use-userinfo'
import { useUpdate } from './use-update'
import Card from '@/components/card'
import Modal from '@/components/modal'
import Info from './info'
import utils from '@/utils'
const profile = defineComponent({
name: 'profile',
setup() {
const { t } = useI18n()
let showModalRef = ref(false)
const { state, t } = useForm()
const { handleUpdate } = useUpdate(state)
const { getUserInfo } = useUserinfo()
return { t }
onMounted(async () => {
await getUserInfo()
})
const onCancel = () => {
showModalRef.value = false
}
const onConfirm = async () => {
showModalRef.value = false
await handleUpdate()
await getUserInfo()
}
return { ...toRefs(state), showModalRef, t, onCancel, onConfirm }
},
render() {
const { t } = this
const { t, onCancel, onConfirm } = this
return (
<div>
<Card title={t('profile.profile')}>
{{
default: () => <Info />,
'header-extra': () => (
<NButton type='info' size='small'>
<NButton
type='info'
size='small'
onClick={() => (this.showModalRef = !this.showModalRef)}
>
{t('profile.edit')}
</NButton>
),
}}
</Card>
<Modal
title={t('profile.edit_profile')}
show={this.showModalRef}
onCancel={onCancel}
onConfirm={onConfirm}
confirmDisabled={
!this.profileForm.username ||
!this.profileForm.email ||
!utils.regex.email.test(this.profileForm.email)
}
>
{{
default: () => (
<NForm rules={this.rules} ref='profileFormRef'>
<NFormItem label={t('profile.username')} path='username'>
<NInput
v-model={[this.profileForm.username, 'value']}
placeholder={t('profile.username_tips')}
/>
</NFormItem>
<NFormItem label={t('profile.email')} path='email'>
<NInput
v-model={[this.profileForm.email, 'value']}
placeholder={t('profile.email_tips')}
/>
</NFormItem>
<NFormItem label={t('profile.phone')} path='phone'>
<NInput
v-model={[this.profileForm.phone, 'value']}
placeholder={t('profile.phone_tips')}
/>
</NFormItem>
<NFormItem label={t('profile.state')} path='state'>
<NRadioGroup v-model={[this.profileForm.state, 'value']}>
{[
{ value: 1, label: t('profile.enable') },
{ value: 0, label: t('profile.disable') },
].map((item) => {
return <NRadio value={item.value}>{item.label}</NRadio>
})}
</NRadioGroup>
</NFormItem>
</NForm>
),
}}
</Modal>
</div>
)
},
})

1
dolphinscheduler-ui-next/src/views/profile/info.tsx

@ -21,7 +21,6 @@ import styles from './info.module.scss'
const Info = defineComponent({
name: 'Info',
setup() {},
render() {
const { infoOptions } = useProfile()

75
dolphinscheduler-ui-next/src/views/profile/use-form.ts

@ -0,0 +1,75 @@
/*
* 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, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useUserStore } from '@/store/user/user'
import utils from '@/utils'
import type { FormRules } from 'naive-ui'
import type { UserInfoRes } from '@/service/modules/users/types'
export function useForm() {
const { t, locale } = useI18n()
const userInfo = useUserStore().userInfo as UserInfoRes
const state = reactive({
profileFormRef: ref(),
profileForm: {
username: userInfo.userName,
email: userInfo.email,
phone: userInfo.phone,
state: userInfo.state,
},
rules: {
username: {
trigger: ['input', 'blur'],
required: true,
validator() {
if (state.profileForm.username === '') {
return new Error(t('profile.username_tips'))
}
},
},
email: {
trigger: ['input', 'blur'],
required: true,
validator() {
if (state.profileForm.email === '') {
return new Error(t('profile.email_tips'))
} else if (!utils.regex.email.test(state.profileForm.email)) {
return new Error(t('profile.email_correct_tips'))
}
},
},
} as FormRules,
})
watch(userInfo, () => {
state.profileForm = {
username: userInfo.userName,
email: userInfo.email,
phone: userInfo.phone,
state: userInfo.state,
}
})
return {
state,
t,
locale,
}
}

5
dolphinscheduler-ui-next/src/views/profile/use-profile.ts

@ -36,7 +36,10 @@ export function useProfile() {
infoOptions.value.push({ key: t('profile.phone'), value: userInfo.phone })
infoOptions.value.push({
key: t('profile.permission'),
value: userInfo.userName,
value:
userInfo.userType === 'ADMIN_USER'
? t('profile.administrator')
: t('profile.ordinary_user'),
})
infoOptions.value.push({
key: t('profile.create_time'),

30
dolphinscheduler-ui-next/src/views/profile/use-update.ts

@ -14,3 +14,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { updateUser } from '@/service/modules/users'
import { useUserStore } from '@/store/user/user'
import type { UserInfoRes } from '@/service/modules/users/types'
export function useUpdate(state: any) {
const userStore = useUserStore()
const userInfo = userStore.userInfo as UserInfoRes
const handleUpdate = () => {
state.profileFormRef.validate(async (valid: any) => {
if (!valid) {
await updateUser({
userPassword: '',
id: userInfo.id,
userName: state.profileForm.username,
tenantId: userInfo.tenantId,
email: state.profileForm.email,
phone: state.profileForm.phone,
state: state.profileForm.state,
queue: userInfo.queue,
})
}
})
}
return {
handleUpdate,
}
}

31
dolphinscheduler-ui-next/src/views/profile/use-userinfo.ts

@ -0,0 +1,31 @@
/*
* 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 { useUserStore } from '@/store/user/user'
import { getUserInfo as getUserInfoApi } from '@/service/modules/users'
import type { UserInfoRes } from '@/service/modules/users/types'
export function useUserinfo() {
const userStore = useUserStore()
const getUserInfo = async () => {
const userInfoRes: UserInfoRes = await getUserInfoApi()
await userStore.setUserInfo(userInfoRes)
}
return { getUserInfo }
}
Loading…
Cancel
Save