Browse Source

[Feature][UI Next] Add token manage. (#8105)

3.0.0/version-upgrade
songjianet 3 years ago committed by GitHub
parent
commit
759fcb8e11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      dolphinscheduler-ui-next/src/locales/modules/en_US.ts
  2. 17
      dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
  3. 8
      dolphinscheduler-ui-next/src/router/modules/security.ts
  4. 18
      dolphinscheduler-ui-next/src/service/modules/token/index.ts
  5. 21
      dolphinscheduler-ui-next/src/service/modules/token/types.ts
  6. 2
      dolphinscheduler-ui-next/src/service/modules/users/index.ts
  7. 28
      dolphinscheduler-ui-next/src/service/modules/users/types.ts
  8. 6
      dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/alarm-group-modal.tsx
  9. 4
      dolphinscheduler-ui-next/src/views/security/alarm-group-manage/index.tsx
  10. 2
      dolphinscheduler-ui-next/src/views/security/environment-manage/components/environment-modal.tsx
  11. 207
      dolphinscheduler-ui-next/src/views/security/token-manage/components/token-modal.tsx
  12. 164
      dolphinscheduler-ui-next/src/views/security/token-manage/components/use-modal.ts
  13. 43
      dolphinscheduler-ui-next/src/views/security/token-manage/index.module.scss
  14. 158
      dolphinscheduler-ui-next/src/views/security/token-manage/index.tsx
  15. 192
      dolphinscheduler-ui-next/src/views/security/token-manage/use-table.ts

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

@ -372,6 +372,23 @@ const security = {
environment_config_tips: 'Please enter your environment config',
environment_description_tips: 'Please enter your environment description',
worker_group_tips: 'Please select worker group'
},
token: {
create_token: 'Create Token',
edit_token: 'Edit Token',
search_tips: 'Please enter keywords',
user: 'User',
user_tips: 'Please select user',
token: 'Token',
token_tips: 'Please enter your token',
expiration_time: 'Expiration Time',
expiration_time_tips: 'Please select expiration time',
create_time: 'Create Time',
update_time: 'Update Time',
operation: 'Operation',
edit: 'Edit',
delete: 'Delete',
delete_confirm: 'Delete?'
}
}

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

@ -372,6 +372,23 @@ const security = {
environment_config_tips: '请输入环境配置',
environment_description_tips: '请输入环境描述',
worker_group_tips: '请选择Worker分组'
},
token: {
create_token: '创建令牌',
edit_token: '编辑令牌',
search_tips: '请输入关键词',
user: '用户',
user_tips: '请选择用户',
token: '令牌',
token_tips: '请输入令牌',
expiration_time: '失效时间',
expiration_time_tips: '请选择失效时间',
create_time: '创建时间',
update_time: '更新时间',
operation: '操作',
edit: '编辑',
delete: '删除',
delete_confirm: '确定删除吗?'
}
}

8
dolphinscheduler-ui-next/src/router/modules/security.ts

@ -76,6 +76,14 @@ export default {
meta: {
title: '环境管理'
}
},
{
path: '/security/token-manage',
name: 'token-manage',
component: components['token-manage'],
meta: {
title: '令牌管理管理'
}
}
]
}

18
dolphinscheduler-ui-next/src/service/modules/token/index.ts

@ -44,8 +44,24 @@ export function queryAccessTokenByUser(params: UserReq): any {
export function updateToken(data: UpdateTokenReq): any {
return axios({
url: '/access-tokens',
url: `/access-tokens/${data.id}`,
method: 'put',
data
})
}
export function deleteToken(id: number): any {
return axios({
url: `/access-tokens/${id}`,
method: 'delete',
params: { id }
})
}
export function generateToken(data: TokenReq): any {
return axios({
url: `/access-tokens/generate`,
method: 'post',
data
})
}

21
dolphinscheduler-ui-next/src/service/modules/token/types.ts

@ -48,4 +48,23 @@ interface UpdateTokenReq extends TokenReq {
userType?: string
}
export { ListReq, TokenReq, UserReq, UpdateTokenReq }
interface TokenItem {
id: number
userId: number
token: string
expireTime: string
createTime: string
updateTime: string
userName: string
}
interface TokenRes {
totalList: TokenItem[]
total: number
totalPage: number
pageSize: number
currentPage: number
start: number
}
export { ListReq, TokenReq, UserReq, UpdateTokenReq, TokenItem, TokenRes }

2
dolphinscheduler-ui-next/src/service/modules/users/index.ts

@ -127,7 +127,7 @@ export function listUser(): any {
})
}
export function listAll(params: ListAllReq): any {
export function listAll(params?: ListAllReq): any {
return axios({
url: '/users/list-all',
method: 'get',

28
dolphinscheduler-ui-next/src/service/modules/users/types.ts

@ -28,10 +28,10 @@ interface AlertGroupIdReq {
}
interface UserReq {
email: string
tenantId: number
userName: string
userPassword: string
email?: string
tenantId?: number
userName?: string
userPassword?: string
phone?: string
queue?: string
state?: number
@ -97,6 +97,23 @@ interface UserInfoRes extends UserReq, IdReq {
updateTime: string
}
interface UserListRes {
id: number
userName: string
userPassword: string
email: string
phone: string
userType: string
tenantId: number
state: number
tenantCode?: any
queueName?: any
alertGroup?: any
queue: string
createTime: string
updateTime: string
}
export {
UserNameReq,
UserNamesReq,
@ -112,5 +129,6 @@ export {
ListAllReq,
ListReq,
RegisterUserReq,
UserInfoRes
UserInfoRes,
UserListRes
}

6
dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/alert-group-modal.tsx → dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/alarm-group-modal.tsx

@ -21,8 +21,8 @@ import { NForm, NFormItem, NInput, NSelect } from 'naive-ui'
import { useModal } from './use-modal'
import { useI18n } from 'vue-i18n'
const AlertGroupModal = defineComponent({
name: 'YarnQueueModal',
const AlarmGroupModal = defineComponent({
name: 'AlarmGroupModal',
props: {
showModalRef: {
type: Boolean as PropType<boolean>,
@ -163,4 +163,4 @@ const AlertGroupModal = defineComponent({
}
})
export default AlertGroupModal
export default AlarmGroupModal

4
dolphinscheduler-ui-next/src/views/security/alarm-group-manage/index.tsx

@ -28,7 +28,7 @@ import { SearchOutlined } from '@vicons/antd'
import { useI18n } from 'vue-i18n'
import { useTable } from './use-table'
import Card from '@/components/card'
import AlertGroupModal from './components/alert-group-modal'
import AlarmGroupModal from './components/alarm-group-modal'
import styles from './index.module.scss'
const alarmGroupManage = defineComponent({
@ -143,7 +143,7 @@ const alarmGroupManage = defineComponent({
/>
</div>
</Card>
<AlertGroupModal
<AlarmGroupModal
showModalRef={this.showModalRef}
statusRef={this.statusRef}
row={this.row}

2
dolphinscheduler-ui-next/src/views/security/environment-manage/components/environment-modal.tsx

@ -35,7 +35,7 @@ const envConfigPlaceholder =
'export HADOOP_CLASSPATH=`hadoop classpath`\n'
const EnvironmentModal = defineComponent({
name: 'YarnQueueModal',
name: 'EnvironmentModal',
props: {
showModalRef: {
type: Boolean as PropType<boolean>,

207
dolphinscheduler-ui-next/src/views/security/token-manage/components/token-modal.tsx

@ -0,0 +1,207 @@
/*
* 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, toRefs, watch } from 'vue'
import Modal from '@/components/modal'
import {
NForm,
NFormItem,
NInput,
NSelect,
NDatePicker,
NButton,
NIcon,
NSpace
} from 'naive-ui'
import { ReloadOutlined } from '@vicons/antd'
import { useModal } from './use-modal'
import { useI18n } from 'vue-i18n'
import { useUserStore } from '@/store/user/user'
import { subDays } from 'date-fns'
import type { UserInfoRes } from '@/service/modules/users/types'
const TokenModal = defineComponent({
name: 'TokenModal',
props: {
showModalRef: {
type: Boolean as PropType<boolean>,
default: false
},
statusRef: {
type: Number as PropType<number>,
default: 0
},
row: {
type: Object as PropType<any>,
default: {}
}
},
emits: ['cancelModal', 'confirmModal'],
setup(props, ctx) {
const { variables, handleValidate, getListData, getToken } = useModal(
props,
ctx
)
const { t } = useI18n()
const userStore = useUserStore()
const cancelModal = () => {
if (props.statusRef === 0) {
variables.model.userId =
(userStore.getUserInfo as UserInfoRes).userType === 'GENERAL_USER'
? (userStore.getUserInfo as UserInfoRes).id
: ''
variables.model.expireTime = Date.now()
variables.model.token = ''
}
ctx.emit('cancelModal', props.showModalRef)
}
const confirmModal = () => {
handleValidate(props.statusRef)
}
watch(
() => props.showModalRef,
() => {
props.showModalRef &&
(userStore.getUserInfo as UserInfoRes).userType !== 'GENERAL_USER' &&
getListData()
}
)
watch(
() => props.statusRef,
() => {
if (props.statusRef === 0) {
variables.model.userId =
(userStore.getUserInfo as UserInfoRes).userType === 'GENERAL_USER'
? (userStore.getUserInfo as UserInfoRes).id
: ''
variables.model.expireTime = Date.now()
variables.model.token = ''
} else {
variables.model.id = props.row.id
variables.model.userId = props.row.userId
variables.model.expireTime = new Date(props.row.expireTime).getTime()
variables.model.token = props.row.token
}
}
)
watch(
() => props.row,
() => {
variables.model.id = props.row.id
variables.model.userId = props.row.userId
variables.model.expireTime = new Date(props.row.expireTime).getTime()
variables.model.token = props.row.token
}
)
return {
t,
...toRefs(variables),
cancelModal,
confirmModal,
getToken,
userStore
}
},
render() {
const { t, getToken, userStore } = this
return (
<div>
<Modal
title={
this.statusRef === 0
? t('security.token.create_token')
: t('security.token.edit_token')
}
show={this.showModalRef}
onCancel={this.cancelModal}
onConfirm={this.confirmModal}
confirmDisabled={
!this.model.userId || !this.model.expireTime || !this.model.token
}
>
{{
default: () => (
<NForm
model={this.model}
rules={this.rules}
ref='alertGroupFormRef'
>
<NFormItem
label={t('security.token.expiration_time')}
path='expireTime'
>
<NDatePicker
is-date-disabled={(ts: any) => ts < subDays(new Date(), 1)}
style={{ width: '100%' }}
type='datetime'
clearable
v-model={[this.model.expireTime, 'value']}
/>
</NFormItem>
{(userStore.getUserInfo as UserInfoRes).userType !==
'GENERAL_USER' && (
<NFormItem label={t('security.token.user')} path='userId'>
<NSelect
filterable
placeholder={t('security.token.user_tips')}
options={this.model.generalOptions}
v-model={[this.model.userId, 'value']}
/>
</NFormItem>
)}
<NFormItem label={t('security.token.token')} path='token'>
<NSpace>
<NInput
style={{ width: '504px' }}
disabled
placeholder={t('security.token.token_tips')}
v-model={[this.model.token, 'value']}
/>
<NButton
strong
secondary
circle
type='info'
onClick={() => getToken()}
>
{{
icon: () => (
<NIcon>
<ReloadOutlined />
</NIcon>
)
}}
</NButton>
</NSpace>
</NFormItem>
</NForm>
)
}}
</Modal>
</div>
)
}
})
export default TokenModal

164
dolphinscheduler-ui-next/src/views/security/token-manage/components/use-modal.ts

@ -0,0 +1,164 @@
/*
* 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 { useUserStore } from '@/store/user/user'
import { useAsyncState } from '@vueuse/core'
import { format } from 'date-fns'
import { queryAlertPluginInstanceList } from '@/service/modules/alert-plugin'
import { listAll } from '@/service/modules/users'
import {
generateToken,
createToken,
updateToken
} from '@/service/modules/token'
import type { AlertPluginItem } from '@/service/modules/alert-plugin/types'
import type { UserListRes } from '@/service/modules/users/types'
import type { UserInfoRes } from '@/service/modules/users/types'
export function useModal(
props: any,
ctx: SetupContext<('cancelModal' | 'confirmModal')[]>
) {
const { t } = useI18n()
const userStore = useUserStore()
const variables = reactive({
alertGroupFormRef: ref(),
model: {
id: ref<number>(-1),
userId: ref(
(userStore.getUserInfo as UserInfoRes).userType === 'GENERAL_USER'
? (userStore.getUserInfo as UserInfoRes).id
: ''
),
expireTime: ref(Date.now()),
token: ref(''),
generalOptions: []
},
rules: {
userId: {
required: true,
trigger: ['input', 'blur'],
validator() {
if (variables.model.userId === '') {
return new Error(t('security.token.user_tips'))
}
}
},
expireTime: {
required: true,
trigger: ['input', 'blur'],
validator() {
console.log(variables.model.expireTime)
if (!variables.model.expireTime) {
return new Error(t('security.token.expiration_time_tips'))
}
}
},
token: {
required: true,
trigger: ['input', 'blur'],
validator() {
if (variables.model.token === '') {
return new Error(t('security.token.token_tips'))
}
}
}
}
})
const getListData = () => {
const { state } = useAsyncState(
listAll().then((res: Array<UserListRes>) => {
variables.model.generalOptions = res.map(
(item): { label: string; value: number } => {
return {
label: item.userName,
value: item.id
}
}
) as any
}),
{}
)
return state
}
const getToken = () => {
const data = {
userId: (userStore.getUserInfo as UserInfoRes).id,
expireTime: format(variables.model.expireTime, 'yyyy-MM-dd HH:mm:ss')
}
useAsyncState(
generateToken(data).then((res: string) => {
variables.model.token = res
}),
{}
)
}
const handleValidate = (statusRef: number) => {
variables.alertGroupFormRef.validate((errors: any) => {
if (!errors) {
statusRef === 0 ? submitTokenModal() : updateTokenModal()
} else {
return
}
})
}
const submitTokenModal = () => {
const data = {
userId: Number(variables.model.userId),
expireTime: format(variables.model.expireTime, 'yyyy-MM-dd HH:mm:ss'),
token: variables.model.token
}
createToken(data).then(() => {
variables.model.userId =
(userStore.getUserInfo as UserInfoRes).userType === 'GENERAL_USER'
? (userStore.getUserInfo as UserInfoRes).id
: ''
variables.model.expireTime = Date.now()
variables.model.token = ''
ctx.emit('confirmModal', props.showModalRef)
})
}
const updateTokenModal = () => {
const data = {
id: variables.model.id,
userId: Number(variables.model.userId),
expireTime: format(variables.model.expireTime, 'yyyy-MM-dd HH:mm:ss'),
token: variables.model.token
}
updateToken(data).then(() => {
ctx.emit('confirmModal', props.showModalRef)
})
}
return {
variables,
handleValidate,
getListData,
getToken
}
}

43
dolphinscheduler-ui-next/src/views/security/token-manage/index.module.scss

@ -0,0 +1,43 @@
/*
* 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.
*/
.search-card {
display: flex;
justify-content: space-between;
align-items: center;
.box {
display: flex;
justify-content: flex-end;
align-items: center;
width: 300px;
button {
margin-left: 10px;
}
}
}
.table-card {
margin-top: 8px;
.pagination {
margin-top: 20px;
display: flex;
justify-content: center;
}
}

158
dolphinscheduler-ui-next/src/views/security/token-manage/index.tsx

@ -0,0 +1,158 @@
/*
* 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, onMounted, toRefs, watch } from 'vue'
import {
NButton,
NCard,
NDataTable,
NIcon,
NInput,
NPagination
} from 'naive-ui'
import { SearchOutlined } from '@vicons/antd'
import { useI18n } from 'vue-i18n'
import { useTable } from './use-table'
import Card from '@/components/card'
import TokenModal from './components/token-modal'
import styles from './index.module.scss'
const tokenManage = defineComponent({
name: 'token-manage',
setup() {
const { t } = useI18n()
const { variables, getTableData, createColumns } = useTable()
const requestData = () => {
getTableData({
pageSize: variables.pageSize,
pageNo: variables.page,
searchVal: variables.searchVal
})
}
const onUpdatePageSize = () => {
variables.page = 1
requestData()
}
const onSearch = () => {
variables.page = 1
requestData()
}
const handleModalChange = () => {
variables.showModalRef = true
variables.statusRef = 0
}
const onCancelModal = () => {
variables.showModalRef = false
}
const onConfirmModal = () => {
variables.showModalRef = false
requestData()
}
onMounted(() => {
createColumns(variables)
requestData()
})
watch(useI18n().locale, () => {
createColumns(variables)
})
return {
t,
...toRefs(variables),
requestData,
onCancelModal,
onConfirmModal,
onUpdatePageSize,
handleModalChange,
onSearch
}
},
render() {
const {
t,
requestData,
onUpdatePageSize,
onCancelModal,
onConfirmModal,
handleModalChange,
onSearch
} = this
return (
<div>
<NCard>
<div class={styles['search-card']}>
<div>
<NButton size='small' type='primary' onClick={handleModalChange}>
{t('security.token.create_token')}
</NButton>
</div>
<div class={styles.box}>
<NInput
size='small'
clearable
v-model={[this.searchVal, 'value']}
placeholder={t('security.token.search_tips')}
/>
<NButton size='small' type='primary' onClick={onSearch}>
{{
icon: () => (
<NIcon>
<SearchOutlined />
</NIcon>
)
}}
</NButton>
</div>
</div>
</NCard>
<Card class={styles['table-card']}>
<NDataTable columns={this.columns} data={this.tableData} />
<div class={styles.pagination}>
<NPagination
v-model:page={this.page}
v-model:page-size={this.pageSize}
page-count={this.totalPage}
show-size-picker
page-sizes={[10, 30, 50]}
show-quick-jumper
onUpdatePage={requestData}
onUpdatePageSize={onUpdatePageSize}
/>
</div>
</Card>
<TokenModal
showModalRef={this.showModalRef}
statusRef={this.statusRef}
row={this.row}
onCancelModal={onCancelModal}
onConfirmModal={onConfirmModal}
/>
</div>
)
}
})
export default tokenManage

192
dolphinscheduler-ui-next/src/views/security/token-manage/use-table.ts

@ -0,0 +1,192 @@
/*
* 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 { useAsyncState } from '@vueuse/core'
import { reactive, h, ref } from 'vue'
import { format } from 'date-fns'
import { NButton, NPopconfirm, NSpace, NTooltip } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import {
queryAlertGroupListPaging,
delAlertGroupById
} from '@/service/modules/alert-group'
import { DeleteOutlined, EditOutlined } from '@vicons/antd'
import { queryAccessTokenList, deleteToken } from '@/service/modules/token'
import type { AlarmGroupRes } from '@/service/modules/alert-group/types'
import type { TokenRes } from '@/service/modules/token/types'
export function useTable() {
const { t } = useI18n()
const handleEdit = (row: any) => {
variables.showModalRef = true
variables.statusRef = 1
variables.row = row
}
const createColumns = (variables: any) => {
variables.columns = [
{
title: '#',
key: 'index'
},
{
title: t('security.token.user'),
key: 'userName'
},
{
title: t('security.token.token'),
key: 'token'
},
{
title: t('security.token.expiration_time'),
key: 'expireTime'
},
{
title: t('security.token.create_time'),
key: 'createTime'
},
{
title: t('security.token.update_time'),
key: 'updateTime'
},
{
title: t('security.token.operation'),
key: 'operation',
render(row: any) {
return h(NSpace, null, {
default: () => [
h(
NTooltip,
{},
{
trigger: () =>
h(
NButton,
{
circle: true,
type: 'info',
size: 'small',
onClick: () => {
handleEdit(row)
}
},
{
icon: () => h(EditOutlined)
}
),
default: () => t('security.token.edit')
}
),
h(
NPopconfirm,
{
onPositiveClick: () => {
handleDelete(row)
}
},
{
trigger: () =>
h(
NTooltip,
{},
{
trigger: () =>
h(
NButton,
{
circle: true,
type: 'error',
size: 'small'
},
{
icon: () => h(DeleteOutlined)
}
),
default: () => t('security.token.delete')
}
),
default: () => t('security.token.delete_confirm')
}
)
]
})
}
}
]
}
const variables = reactive({
columns: [],
tableData: [],
page: ref(1),
pageSize: ref(10),
searchVal: ref(null),
totalPage: ref(1),
showModalRef: ref(false),
statusRef: ref(0),
row: {}
})
const handleDelete = (row: any) => {
deleteToken(row.id).then(() => {
getTableData({
pageSize: variables.pageSize,
pageNo:
variables.tableData.length === 1 && variables.page > 1
? variables.page - 1
: variables.page,
searchVal: variables.searchVal
})
})
}
const getTableData = (params: any) => {
const { state } = useAsyncState(
queryAccessTokenList({ ...params }).then((res: TokenRes) => {
variables.tableData = res.totalList.map((item, index) => {
item.expireTime = format(
new Date(item.expireTime),
'yyyy-MM-dd HH:mm:ss'
)
item.createTime = format(
new Date(item.createTime),
'yyyy-MM-dd HH:mm:ss'
)
item.updateTime = format(
new Date(item.updateTime),
'yyyy-MM-dd HH:mm:ss'
)
return {
index: index + 1,
...item
}
}) as any
variables.totalPage = res.totalPage
}),
{}
)
return state
}
return {
variables,
getTableData,
createColumns
}
}
Loading…
Cancel
Save