You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@seatunnel.apache.org by zh...@apache.org on 2022/07/27 09:16:16 UTC

[incubator-seatunnel] branch dev updated: [Feat][UI] Add the modal in the user manage. (#2277)

This is an automated email from the ASF dual-hosted git repository.

zhongjiajie pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-seatunnel.git


The following commit(s) were added to refs/heads/dev by this push:
     new d82bf5dce [Feat][UI] Add the modal in the user manage. (#2277)
d82bf5dce is described below

commit d82bf5dcef941de4b66507b13d63cb728b730dee
Author: songjianet <17...@qq.com>
AuthorDate: Wed Jul 27 17:16:12 2022 +0800

    [Feat][UI] Add the modal in the user manage. (#2277)
---
 seatunnel-ui/src/components/modal/index.tsx        | 113 +++++++++++++++
 seatunnel-ui/src/locales/en_US/data-pipes.ts       |   2 +-
 seatunnel-ui/src/locales/en_US/index.ts            |   2 +
 .../src/{utils/index.ts => locales/en_US/modal.ts} |  11 +-
 seatunnel-ui/src/locales/en_US/user-manage.ts      |   8 +-
 seatunnel-ui/src/utils/index.ts                    |   4 +-
 seatunnel-ui/src/utils/{index.ts => regex.ts}      |  10 +-
 .../src/views/data-pipes/list/use-table.ts         |  10 +-
 .../views/user-manage/list/components/modal.tsx    | 156 +++++++++++++++++++++
 .../views/user-manage/list/components/use-modal.ts |  69 +++++++++
 seatunnel-ui/src/views/user-manage/list/index.tsx  |  35 ++++-
 .../src/views/user-manage/list/use-table.ts        |  18 ++-
 12 files changed, 406 insertions(+), 32 deletions(-)

diff --git a/seatunnel-ui/src/components/modal/index.tsx b/seatunnel-ui/src/components/modal/index.tsx
new file mode 100644
index 000000000..4bf22cb88
--- /dev/null
+++ b/seatunnel-ui/src/components/modal/index.tsx
@@ -0,0 +1,113 @@
+/*
+ * 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, PropType, renderSlot } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { NModal, NCard, NButton, NSpace } from 'naive-ui'
+
+const props = {
+  show: {
+    type: Boolean as PropType<boolean>,
+    default: false
+  },
+  title: {
+    type: String as PropType<string>,
+    required: true
+  },
+  cancelText: {
+    type: String as PropType<string>
+  },
+  cancelShow: {
+    type: Boolean as PropType<boolean>,
+    default: true
+  },
+  confirmText: {
+    type: String as PropType<string>
+  },
+  confirmClassName: {
+    type: String as PropType<string>,
+    default: ''
+  },
+  cancelClassName: {
+    type: String as PropType<string>,
+    default: ''
+  },
+  confirmDisabled: {
+    type: Boolean as PropType<boolean>,
+    default: false
+  },
+  confirmLoading: {
+    type: Boolean as PropType<boolean>,
+    default: false
+  }
+}
+
+const Modal = defineComponent({
+  name: 'Modal',
+  props,
+  emits: ['cancel', 'confirm'],
+  setup(props, ctx) {
+    const { t } = useI18n()
+
+    const onCancel = () => {
+      ctx.emit('cancel')
+    }
+
+    const onConfirm = () => {
+      ctx.emit('confirm')
+    }
+
+    return { t, onCancel, onConfirm }
+  },
+  render() {
+    const { $slots, t, onCancel, onConfirm, confirmDisabled, confirmLoading } =
+      this
+
+    return (
+      <NModal
+        v-model={[this.show, 'show']}
+        mask-closable={false}
+        style={{ width: '600px' }}
+      >
+        <NCard title={this.title} contentStyle={{ overflowY: 'auto' }}>
+          {{
+            default: () => renderSlot($slots, 'default'),
+            footer: () => (
+              <NSpace justify='end'>
+                {this.cancelShow && (
+                  <NButton quaternary size='small' onClick={onCancel}>
+                    {this.cancelText || t('modal.cancel')}
+                  </NButton>
+                )}
+                <NButton
+                  size='small'
+                  onClick={onConfirm}
+                  disabled={confirmDisabled}
+                  loading={confirmLoading}
+                >
+                  {this.confirmText || t('modal.confirm')}
+                </NButton>
+              </NSpace>
+            )
+          }}
+        </NCard>
+      </NModal>
+    )
+  }
+})
+
+export default Modal
diff --git a/seatunnel-ui/src/locales/en_US/data-pipes.ts b/seatunnel-ui/src/locales/en_US/data-pipes.ts
index efe98e980..b1109701b 100644
--- a/seatunnel-ui/src/locales/en_US/data-pipes.ts
+++ b/seatunnel-ui/src/locales/en_US/data-pipes.ts
@@ -32,4 +32,4 @@ export default {
   edite: 'Edite',
   publish: 'Publish',
   delete: 'Delete'
-}
\ No newline at end of file
+}
diff --git a/seatunnel-ui/src/locales/en_US/index.ts b/seatunnel-ui/src/locales/en_US/index.ts
index 5be91f960..34e0c821b 100644
--- a/seatunnel-ui/src/locales/en_US/index.ts
+++ b/seatunnel-ui/src/locales/en_US/index.ts
@@ -17,12 +17,14 @@
 
 import login from '@/locales/en_US/login'
 import menu from '@/locales/en_US/menu'
+import modal from '@/locales/en_US/modal'
 import user_manage from '@/locales/en_US/user-manage'
 import data_pipes from '@/locales/en_US/data-pipes'
 
 export default {
   login,
   menu,
+  modal,
   user_manage,
   data_pipes
 }
diff --git a/seatunnel-ui/src/utils/index.ts b/seatunnel-ui/src/locales/en_US/modal.ts
similarity index 87%
copy from seatunnel-ui/src/utils/index.ts
copy to seatunnel-ui/src/locales/en_US/modal.ts
index 3a7285d70..3c17d1dd4 100644
--- a/seatunnel-ui/src/utils/index.ts
+++ b/seatunnel-ui/src/locales/en_US/modal.ts
@@ -15,12 +15,7 @@
  * limitations under the License.
  */
 
-import mapping from './mapping'
-import trim from './trim'
-
-const utils = {
-  mapping,
-  trim
+export default {
+  cancel: 'Cancel',
+  confirm: 'Confirm'
 }
-
-export default utils
diff --git a/seatunnel-ui/src/locales/en_US/user-manage.ts b/seatunnel-ui/src/locales/en_US/user-manage.ts
index 7ad4ca183..d48d5df36 100644
--- a/seatunnel-ui/src/locales/en_US/user-manage.ts
+++ b/seatunnel-ui/src/locales/en_US/user-manage.ts
@@ -27,5 +27,11 @@ export default {
   enable: 'Enable',
   disable: 'Disable',
   edite: 'Edite',
-  delete: 'Delete'
+  delete: 'Delete',
+  active: 'Active',
+  inactive: 'Inactive',
+  password: 'Password',
+  model_validate_tips: 'Required Fields',
+  username_tips: 'Required fields, number, letter case, 50 characters',
+  password_tips: 'Required fields, number, letter case, 6 characters'
 }
diff --git a/seatunnel-ui/src/utils/index.ts b/seatunnel-ui/src/utils/index.ts
index 3a7285d70..8f15672b9 100644
--- a/seatunnel-ui/src/utils/index.ts
+++ b/seatunnel-ui/src/utils/index.ts
@@ -17,10 +17,12 @@
 
 import mapping from './mapping'
 import trim from './trim'
+import regex from './regex'
 
 const utils = {
   mapping,
-  trim
+  trim,
+  regex
 }
 
 export default utils
diff --git a/seatunnel-ui/src/utils/index.ts b/seatunnel-ui/src/utils/regex.ts
similarity index 85%
copy from seatunnel-ui/src/utils/index.ts
copy to seatunnel-ui/src/utils/regex.ts
index 3a7285d70..c660e8d12 100644
--- a/seatunnel-ui/src/utils/index.ts
+++ b/seatunnel-ui/src/utils/regex.ts
@@ -15,12 +15,8 @@
  * limitations under the License.
  */
 
-import mapping from './mapping'
-import trim from './trim'
-
-const utils = {
-  mapping,
-  trim
+const regex = {
+  email: /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/ // support Chinese mailbox
 }
 
-export default utils
+export default regex
diff --git a/seatunnel-ui/src/views/data-pipes/list/use-table.ts b/seatunnel-ui/src/views/data-pipes/list/use-table.ts
index e78e13fd1..8f7c2b2c0 100644
--- a/seatunnel-ui/src/views/data-pipes/list/use-table.ts
+++ b/seatunnel-ui/src/views/data-pipes/list/use-table.ts
@@ -68,15 +68,9 @@ export function useTable() {
                 h(
                   NDropdown,
                   {
-                    options: [
-                      { key: 'delete', label: t('data_pipes.delete') }
-                    ]
+                    options: [{ key: 'delete', label: t('data_pipes.delete') }]
                   },
-                  h(
-                    NIcon,
-                    {},
-                    h(EllipsisOutlined)
-                  )
+                  h(NIcon, {}, h(EllipsisOutlined))
                 )
               )
             ]
diff --git a/seatunnel-ui/src/views/user-manage/list/components/modal.tsx b/seatunnel-ui/src/views/user-manage/list/components/modal.tsx
new file mode 100644
index 000000000..121022085
--- /dev/null
+++ b/seatunnel-ui/src/views/user-manage/list/components/modal.tsx
@@ -0,0 +1,156 @@
+/*
+ * 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, getCurrentInstance, toRefs } from 'vue'
+import {
+  NForm,
+  NFormItem,
+  NInput,
+  NRadioGroup,
+  NRadio,
+  NIcon,
+  NSpace,
+  NTooltip
+} from 'naive-ui'
+import { useI18n } from 'vue-i18n'
+import { BulbOutlined } from '@vicons/antd'
+import { useUserManageModal } from './use-modal'
+import Modal from '@/components/modal'
+import type { PropType } from 'vue'
+
+const props = {
+  showModal: {
+    type: Boolean as PropType<boolean>,
+    default: false
+  },
+  status: {
+    type: Number as PropType<number>,
+    default: 0
+  },
+  row: {
+    type: Object as PropType<any>,
+    default: {}
+  }
+}
+
+const UserManageModal = defineComponent({
+  props,
+  emits: ['cancelModal', 'confirmModal'],
+  setup(props, ctx) {
+    const { t } = useI18n()
+    const { state, handleValidate } = useUserManageModal(props, ctx)
+    const trim = getCurrentInstance()?.appContext.config.globalProperties.trim
+
+    const handleCancel = () => {
+      if (props.status === 0) {
+      }
+      ctx.emit('cancelModal', props.showModal)
+    }
+
+    const handleConfirm = () => {
+      handleValidate(props.status)
+    }
+
+    return { t, ...toRefs(state), trim, handleCancel, handleConfirm }
+  },
+  render() {
+    return (
+      <Modal
+        title={
+          this.status === 0
+            ? this.t('user_manage.create')
+            : this.t('user_manage.edite')
+        }
+        show={this.showModal}
+        onCancel={this.handleCancel}
+        onConfirm={this.handleConfirm}
+        confirmDisabled={!this.model.username || !this.model.password}
+      >
+        {{
+          default: () => (
+            <NForm model={this.model} rules={this.rules} ref='userManageForm'>
+              <NFormItem label={this.t('user_manage.username')} path='username'>
+                <NSpace align='center'>
+                  <NInput
+                    clearable
+                    maxlength='50'
+                    show-count
+                    allowInput={this.trim}
+                    style={{ width: '510px' }}
+                    v-model={[this.model.username, 'value']}
+                  />
+                  <NTooltip placement='right' trigger='hover'>
+                    {{
+                      default: () => (
+                        <span>{this.t('user_manage.username_tips')}</span>
+                      ),
+                      trigger: () => (
+                        <NIcon size='20' style={{ cursor: 'pointer' }}>
+                          <BulbOutlined />
+                        </NIcon>
+                      )
+                    }}
+                  </NTooltip>
+                </NSpace>
+              </NFormItem>
+              <NFormItem label={this.t('user_manage.password')} path='password'>
+                <NSpace align='center'>
+                  <NInput
+                    clearable
+                    type='password'
+                    maxlength='6'
+                    show-count
+                    allowInput={this.trim}
+                    style={{ width: '510px' }}
+                    v-model={[this.model.password, 'value']}
+                  />
+                  <NTooltip placement='right' trigger='hover'>
+                    {{
+                      default: () => (
+                        <span>{this.t('user_manage.password_tips')}</span>
+                      ),
+                      trigger: () => (
+                        <NIcon size='20' style={{ cursor: 'pointer' }}>
+                          <BulbOutlined />
+                        </NIcon>
+                      )
+                    }}
+                  </NTooltip>
+                </NSpace>
+              </NFormItem>
+              <NFormItem label={this.t('user_manage.email')} path='email'>
+                <NInput
+                  clearable
+                  allowInput={this.trim}
+                  v-model={[this.model.email, 'value']}
+                />
+              </NFormItem>
+              <NFormItem label={this.t('user_manage.state')} path='state'>
+                <NRadioGroup v-model={[this.model.state, 'value']}>
+                  <NRadio value={0}>{this.t('user_manage.active')}</NRadio>
+                  <NRadio value={1}>{this.t('user_manage.inactive')}</NRadio>
+                </NRadioGroup>
+              </NFormItem>
+            </NForm>
+          )
+        }}
+      </Modal>
+    )
+  }
+})
+
+export default UserManageModal
diff --git a/seatunnel-ui/src/views/user-manage/list/components/use-modal.ts b/seatunnel-ui/src/views/user-manage/list/components/use-modal.ts
new file mode 100644
index 000000000..7175152d3
--- /dev/null
+++ b/seatunnel-ui/src/views/user-manage/list/components/use-modal.ts
@@ -0,0 +1,69 @@
+/*
+ * 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, SetupContext } from 'vue'
+import { useI18n } from 'vue-i18n'
+import utils from '@/utils'
+
+export function useUserManageModal(
+  props: any,
+  ctx: SetupContext<('cancelModal' | 'confirmModal')[]>
+) {
+  const { t } = useI18n()
+  const state = reactive({
+    userManageForm: ref(),
+    model: {
+      id: ref(),
+      username: ref(''),
+      password: ref(''),
+      email: ref(''),
+      state: ref(0)
+    },
+    rules: {
+      username: {
+        required: true,
+        trigger: ['input', 'blur'],
+        message: t('user_manage.model_validate_tips')
+      },
+      password: {
+        required: true,
+        trigger: ['input', 'blur'],
+        message: t('user_manage.model_validate_tips')
+      },
+      email: {
+        trigger: ['input', 'blur'],
+        validator() {
+          if (state.model.email && !utils.regex.email.test(state.model.email)) {
+            return new Error(t('user_manage.model_validate_tips'))
+          }
+        }
+      }
+    }
+  })
+
+  const handleValidate = (status: number) => {
+    state.userManageForm.validate((errors: any) => {
+      if (!errors) {
+        ctx.emit('confirmModal', props.showModal)
+      } else {
+        return
+      }
+    })
+  }
+
+  return { state, handleValidate }
+}
diff --git a/seatunnel-ui/src/views/user-manage/list/index.tsx b/seatunnel-ui/src/views/user-manage/list/index.tsx
index d1f5a09e3..c85c65d7a 100644
--- a/seatunnel-ui/src/views/user-manage/list/index.tsx
+++ b/seatunnel-ui/src/views/user-manage/list/index.tsx
@@ -19,17 +19,37 @@ import { defineComponent, toRefs, onMounted } from 'vue'
 import { NSpace, NCard, NButton, NDataTable, NPagination } from 'naive-ui'
 import { useI18n } from 'vue-i18n'
 import { useTable } from './use-table'
+import UserManageModal from './components/modal'
 
 const UserManageList = defineComponent({
   setup() {
     const { t } = useI18n()
     const { state, createColumns } = useTable()
 
+    const handleModal = () => {
+      state.showModal = true
+      state.status = 0
+    }
+
+    const handleCancelModal = () => {
+      state.showModal = false
+    }
+
+    const handleConfirmModal = () => {
+      state.showModal = false
+    }
+
     onMounted(() => {
       createColumns(state)
     })
 
-    return { t, ...toRefs(state) }
+    return {
+      t,
+      ...toRefs(state),
+      handleModal,
+      handleCancelModal,
+      handleConfirmModal
+    }
   },
   render() {
     return (
@@ -37,14 +57,16 @@ const UserManageList = defineComponent({
         <NCard title={this.t('user_manage.user_manage')}>
           {{
             'header-extra': () => (
-              <NButton>{this.t('user_manage.create')}</NButton>
+              <NButton onClick={this.handleModal}>
+                {this.t('user_manage.create')}
+              </NButton>
             )
           }}
         </NCard>
         <NCard>
           <NSpace vertical>
             <NDataTable
-              loading={this.loadingRef}
+              loading={this.loading}
               columns={this.columns}
               data={this.tableData}
             />
@@ -60,6 +82,13 @@ const UserManageList = defineComponent({
             </NSpace>
           </NSpace>
         </NCard>
+        <UserManageModal
+          showModal={this.showModal}
+          status={this.status}
+          row={this.row}
+          onCancelModal={this.handleCancelModal}
+          onConfirmModal={this.handleConfirmModal}
+        />
       </NSpace>
     )
   }
diff --git a/seatunnel-ui/src/views/user-manage/list/use-table.ts b/seatunnel-ui/src/views/user-manage/list/use-table.ts
index 736fe1204..bb0fa4dfa 100644
--- a/seatunnel-ui/src/views/user-manage/list/use-table.ts
+++ b/seatunnel-ui/src/views/user-manage/list/use-table.ts
@@ -28,7 +28,9 @@ export function useTable() {
     pageSize: ref(10),
     totalPage: ref(1),
     row: {},
-    loadingRef: ref(false)
+    loading: ref(false),
+    showModal: ref(false),
+    status: ref(0)
   })
 
   const createColumns = (state: any) => {
@@ -56,11 +58,15 @@ export function useTable() {
       {
         title: t('user_manage.operation'),
         key: 'operation',
-        render: () =>
+        render: (row: any) =>
           h(NSpace, null, {
             default: () => [
               h(NButton, { text: true }, t('user_manage.enable')),
-              h(NButton, { text: true }, t('user_manage.edite')),
+              h(
+                NButton,
+                { text: true, onClick: () => handleEdite(row) },
+                t('user_manage.edite')
+              ),
               h(NButton, { text: true }, t('user_manage.delete'))
             ]
           })
@@ -68,5 +74,11 @@ export function useTable() {
     ]
   }
 
+  const handleEdite = (row: any) => {
+    state.showModal = true
+    state.status = 1
+    state.row = row
+  }
+
   return { state, createColumns }
 }