diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts index e0f0d34ab4..b26fd0ded5 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts +++ b/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?' } } diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts index d456a8131b..c5f4264b9e 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts +++ b/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: '确定删除吗?' } } diff --git a/dolphinscheduler-ui-next/src/router/modules/security.ts b/dolphinscheduler-ui-next/src/router/modules/security.ts index 521d9a3ac1..359e932029 100644 --- a/dolphinscheduler-ui-next/src/router/modules/security.ts +++ b/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: '令牌管理管理' + } } ] } diff --git a/dolphinscheduler-ui-next/src/service/modules/token/index.ts b/dolphinscheduler-ui-next/src/service/modules/token/index.ts index e7b94379a6..69a898d0ff 100644 --- a/dolphinscheduler-ui-next/src/service/modules/token/index.ts +++ b/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 + }) +} diff --git a/dolphinscheduler-ui-next/src/service/modules/token/types.ts b/dolphinscheduler-ui-next/src/service/modules/token/types.ts index 98bc1f9b7d..b4456bc2fb 100644 --- a/dolphinscheduler-ui-next/src/service/modules/token/types.ts +++ b/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 } diff --git a/dolphinscheduler-ui-next/src/service/modules/users/index.ts b/dolphinscheduler-ui-next/src/service/modules/users/index.ts index 2b52b1971c..1e9157161c 100644 --- a/dolphinscheduler-ui-next/src/service/modules/users/index.ts +++ b/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', diff --git a/dolphinscheduler-ui-next/src/service/modules/users/types.ts b/dolphinscheduler-ui-next/src/service/modules/users/types.ts index eef7b59a4f..95b4a9f1d9 100644 --- a/dolphinscheduler-ui-next/src/service/modules/users/types.ts +++ b/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 } diff --git a/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/alert-group-modal.tsx b/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/alarm-group-modal.tsx similarity index 98% rename from dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/alert-group-modal.tsx rename to dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/alarm-group-modal.tsx index ffe457afb7..dcfcb4c46b 100644 --- a/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/components/alert-group-modal.tsx +++ b/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, @@ -163,4 +163,4 @@ const AlertGroupModal = defineComponent({ } }) -export default AlertGroupModal +export default AlarmGroupModal diff --git a/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/index.tsx b/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/index.tsx index 4ee81d6a78..c57d10b52c 100644 --- a/dolphinscheduler-ui-next/src/views/security/alarm-group-manage/index.tsx +++ b/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({ /> - , diff --git a/dolphinscheduler-ui-next/src/views/security/token-manage/components/token-modal.tsx b/dolphinscheduler-ui-next/src/views/security/token-manage/components/token-modal.tsx new file mode 100644 index 0000000000..e0abcf9447 --- /dev/null +++ b/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, + default: false + }, + statusRef: { + type: Number as PropType, + default: 0 + }, + row: { + type: Object as PropType, + 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 ( +
+ + {{ + default: () => ( + + + ts < subDays(new Date(), 1)} + style={{ width: '100%' }} + type='datetime' + clearable + v-model={[this.model.expireTime, 'value']} + /> + + {(userStore.getUserInfo as UserInfoRes).userType !== + 'GENERAL_USER' && ( + + + + )} + + + + getToken()} + > + {{ + icon: () => ( + + + + ) + }} + + + + + ) + }} + +
+ ) + } +}) + +export default TokenModal diff --git a/dolphinscheduler-ui-next/src/views/security/token-manage/components/use-modal.ts b/dolphinscheduler-ui-next/src/views/security/token-manage/components/use-modal.ts new file mode 100644 index 0000000000..811ceea2f8 --- /dev/null +++ b/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(-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) => { + 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 + } +} diff --git a/dolphinscheduler-ui-next/src/views/security/token-manage/index.module.scss b/dolphinscheduler-ui-next/src/views/security/token-manage/index.module.scss new file mode 100644 index 0000000000..de6cf70c65 --- /dev/null +++ b/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; + } +} diff --git a/dolphinscheduler-ui-next/src/views/security/token-manage/index.tsx b/dolphinscheduler-ui-next/src/views/security/token-manage/index.tsx new file mode 100644 index 0000000000..5c723d6d34 --- /dev/null +++ b/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 ( +
+ +
+
+ + {t('security.token.create_token')} + +
+
+ + + {{ + icon: () => ( + + + + ) + }} + +
+
+
+ + +
+ +
+
+ +
+ ) + } +}) + +export default tokenManage diff --git a/dolphinscheduler-ui-next/src/views/security/token-manage/use-table.ts b/dolphinscheduler-ui-next/src/views/security/token-manage/use-table.ts new file mode 100644 index 0000000000..cf6584ef7c --- /dev/null +++ b/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 + } +}