feat: 新增 ele 三方登录模块
							parent
							
								
									18df7fa845
								
							
						
					
					
						commit
						7a959bcca0
					
				|  | @ -0,0 +1,233 @@ | ||||||
|  | import type { VbenFormSchema } from '#/adapter/form'; | ||||||
|  | import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table'; | ||||||
|  | import type { SystemSocialClientApi } from '#/api/system/social/client'; | ||||||
|  | 
 | ||||||
|  | import { useAccess } from '@vben/access'; | ||||||
|  | 
 | ||||||
|  | import { z } from '#/adapter/form'; | ||||||
|  | import { | ||||||
|  |   CommonStatusEnum, | ||||||
|  |   DICT_TYPE, | ||||||
|  |   getDictOptions, | ||||||
|  |   SystemUserSocialTypeEnum, | ||||||
|  | } from '#/utils'; | ||||||
|  | 
 | ||||||
|  | const { hasAccessByCodes } = useAccess(); | ||||||
|  | 
 | ||||||
|  | /** 新增/修改的表单 */ | ||||||
|  | export function useFormSchema(): VbenFormSchema[] { | ||||||
|  |   return [ | ||||||
|  |     { | ||||||
|  |       fieldName: 'id', | ||||||
|  |       component: 'Input', | ||||||
|  |       dependencies: { | ||||||
|  |         triggerFields: [''], | ||||||
|  |         show: () => false, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'name', | ||||||
|  |       label: '应用名', | ||||||
|  |       component: 'Input', | ||||||
|  |       componentProps: { | ||||||
|  |         placeholder: '请输入应用名', | ||||||
|  |       }, | ||||||
|  |       rules: 'required', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'socialType', | ||||||
|  |       label: '社交平台', | ||||||
|  |       component: 'Select', | ||||||
|  |       componentProps: { | ||||||
|  |         options: getDictOptions(DICT_TYPE.SYSTEM_SOCIAL_TYPE, 'number'), | ||||||
|  |       }, | ||||||
|  |       rules: 'required', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'userType', | ||||||
|  |       label: '用户类型', | ||||||
|  |       component: 'RadioGroup', | ||||||
|  |       componentProps: { | ||||||
|  |         options: getDictOptions(DICT_TYPE.USER_TYPE, 'number'), | ||||||
|  |         buttonStyle: 'solid', | ||||||
|  |         optionType: 'button', | ||||||
|  |       }, | ||||||
|  |       rules: 'required', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'clientId', | ||||||
|  |       label: '客户端编号', | ||||||
|  |       component: 'Input', | ||||||
|  |       componentProps: { | ||||||
|  |         placeholder: '请输入客户端编号,对应各平台的 appKey', | ||||||
|  |       }, | ||||||
|  |       rules: 'required', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'clientSecret', | ||||||
|  |       label: '客户端密钥', | ||||||
|  |       component: 'Input', | ||||||
|  |       componentProps: { | ||||||
|  |         placeholder: '请输入客户端密钥,对应各平台的 appSecret', | ||||||
|  |       }, | ||||||
|  |       rules: 'required', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'agentId', | ||||||
|  |       label: 'agentId', | ||||||
|  |       component: 'Input', | ||||||
|  |       componentProps: { | ||||||
|  |         placeholder: '授权方的网页应用 ID,有则填', | ||||||
|  |       }, | ||||||
|  |       dependencies: { | ||||||
|  |         triggerFields: ['socialType'], | ||||||
|  |         show: (values) => | ||||||
|  |           values.socialType === SystemUserSocialTypeEnum.WECHAT_ENTERPRISE.type, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'status', | ||||||
|  |       label: '状态', | ||||||
|  |       component: 'RadioGroup', | ||||||
|  |       componentProps: { | ||||||
|  |         options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), | ||||||
|  |         buttonStyle: 'solid', | ||||||
|  |         optionType: 'button', | ||||||
|  |       }, | ||||||
|  |       rules: z.number().default(CommonStatusEnum.ENABLE), | ||||||
|  |     }, | ||||||
|  |   ]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 列表的搜索表单 */ | ||||||
|  | export function useGridFormSchema(): VbenFormSchema[] { | ||||||
|  |   return [ | ||||||
|  |     { | ||||||
|  |       fieldName: 'name', | ||||||
|  |       label: '应用名', | ||||||
|  |       component: 'Input', | ||||||
|  |       componentProps: { | ||||||
|  |         placeholder: '请输入应用名', | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'socialType', | ||||||
|  |       label: '社交平台', | ||||||
|  |       component: 'Select', | ||||||
|  |       componentProps: { | ||||||
|  |         options: getDictOptions(DICT_TYPE.SYSTEM_SOCIAL_TYPE, 'number'), | ||||||
|  |         placeholder: '请选择社交平台', | ||||||
|  |         allowClear: true, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'userType', | ||||||
|  |       label: '用户类型', | ||||||
|  |       component: 'Select', | ||||||
|  |       componentProps: { | ||||||
|  |         options: getDictOptions(DICT_TYPE.USER_TYPE, 'number'), | ||||||
|  |         placeholder: '请选择用户类型', | ||||||
|  |         allowClear: true, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'clientId', | ||||||
|  |       label: '客户端编号', | ||||||
|  |       component: 'Input', | ||||||
|  |       componentProps: { | ||||||
|  |         placeholder: '请输入客户端编号', | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'status', | ||||||
|  |       label: '状态', | ||||||
|  |       component: 'Select', | ||||||
|  |       componentProps: { | ||||||
|  |         options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), | ||||||
|  |         placeholder: '请选择状态', | ||||||
|  |         allowClear: true, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 列表的字段 */ | ||||||
|  | export function useGridColumns<T = SystemSocialClientApi.SocialClient>( | ||||||
|  |   onActionClick: OnActionClickFn<T>, | ||||||
|  | ): VxeTableGridOptions['columns'] { | ||||||
|  |   return [ | ||||||
|  |     { | ||||||
|  |       field: 'id', | ||||||
|  |       title: '编号', | ||||||
|  |       minWidth: 80, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'name', | ||||||
|  |       title: '应用名', | ||||||
|  |       minWidth: 120, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'socialType', | ||||||
|  |       title: '社交平台', | ||||||
|  |       minWidth: 120, | ||||||
|  |       cellRender: { | ||||||
|  |         name: 'CellDict', | ||||||
|  |         props: { type: DICT_TYPE.SYSTEM_SOCIAL_TYPE }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'userType', | ||||||
|  |       title: '用户类型', | ||||||
|  |       minWidth: 120, | ||||||
|  |       cellRender: { | ||||||
|  |         name: 'CellDict', | ||||||
|  |         props: { type: DICT_TYPE.USER_TYPE }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'clientId', | ||||||
|  |       title: '客户端编号', | ||||||
|  |       minWidth: 180, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'status', | ||||||
|  |       title: '状态', | ||||||
|  |       minWidth: 80, | ||||||
|  |       cellRender: { | ||||||
|  |         name: 'CellDict', | ||||||
|  |         props: { type: DICT_TYPE.COMMON_STATUS }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'createTime', | ||||||
|  |       title: '创建时间', | ||||||
|  |       minWidth: 180, | ||||||
|  |       formatter: 'formatDateTime', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'operation', | ||||||
|  |       title: '操作', | ||||||
|  |       minWidth: 130, | ||||||
|  |       align: 'center', | ||||||
|  |       fixed: 'right', | ||||||
|  |       cellRender: { | ||||||
|  |         attrs: { | ||||||
|  |           nameField: 'name', | ||||||
|  |           nameTitle: '社交客户端', | ||||||
|  |           onClick: onActionClick, | ||||||
|  |         }, | ||||||
|  |         name: 'CellOperation', | ||||||
|  |         options: [ | ||||||
|  |           { | ||||||
|  |             code: 'edit', | ||||||
|  |             show: hasAccessByCodes(['system:social-client:update']), | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             code: 'delete', | ||||||
|  |             show: hasAccessByCodes(['system:social-client:delete']), | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ]; | ||||||
|  | } | ||||||
|  | @ -0,0 +1,128 @@ | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import type { | ||||||
|  |   OnActionClickParams, | ||||||
|  |   VxeTableGridOptions, | ||||||
|  | } from '#/adapter/vxe-table'; | ||||||
|  | import type { SystemSocialClientApi } from '#/api/system/social/client'; | ||||||
|  | 
 | ||||||
|  | import { Page, useVbenModal } from '@vben/common-ui'; | ||||||
|  | import { Plus } from '@vben/icons'; | ||||||
|  | 
 | ||||||
|  | import { ElButton, ElLoading, ElMessage } from 'element-plus'; | ||||||
|  | 
 | ||||||
|  | import { useVbenVxeGrid } from '#/adapter/vxe-table'; | ||||||
|  | import { | ||||||
|  |   deleteSocialClient, | ||||||
|  |   getSocialClientPage, | ||||||
|  | } from '#/api/system/social/client'; | ||||||
|  | import { DocAlert } from '#/components/doc-alert'; | ||||||
|  | import { $t } from '#/locales'; | ||||||
|  | 
 | ||||||
|  | import { useGridColumns, useGridFormSchema } from './data'; | ||||||
|  | import Form from './modules/form.vue'; | ||||||
|  | 
 | ||||||
|  | const [FormModal, formModalApi] = useVbenModal({ | ||||||
|  |   connectedComponent: Form, | ||||||
|  |   destroyOnClose: true, | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | /** 刷新表格 */ | ||||||
|  | function onRefresh() { | ||||||
|  |   gridApi.query(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 创建社交客户端 */ | ||||||
|  | function onCreate() { | ||||||
|  |   formModalApi.setData(null).open(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 编辑社交客户端 */ | ||||||
|  | function onEdit(row: SystemSocialClientApi.SocialClient) { | ||||||
|  |   formModalApi.setData(row).open(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 删除社交客户端 */ | ||||||
|  | async function onDelete(row: SystemSocialClientApi.SocialClient) { | ||||||
|  |   const loadingInstance = ElLoading.service({ | ||||||
|  |     text: $t('ui.actionMessage.deleting', [row.name]), | ||||||
|  |     fullscreen: true, | ||||||
|  |   }); | ||||||
|  |   try { | ||||||
|  |     await deleteSocialClient(row.id as number); | ||||||
|  |     ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.name])); | ||||||
|  |     onRefresh(); | ||||||
|  |   } catch { | ||||||
|  |     // 发生错误时不需要做特殊处理,finally会关闭loading | ||||||
|  |   } finally { | ||||||
|  |     loadingInstance.close(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 表格操作按钮的回调函数 */ | ||||||
|  | function onActionClick({ | ||||||
|  |   code, | ||||||
|  |   row, | ||||||
|  | }: OnActionClickParams<SystemSocialClientApi.SocialClient>) { | ||||||
|  |   switch (code) { | ||||||
|  |     case 'delete': { | ||||||
|  |       onDelete(row); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |     case 'edit': { | ||||||
|  |       onEdit(row); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const [Grid, gridApi] = useVbenVxeGrid({ | ||||||
|  |   formOptions: { | ||||||
|  |     schema: useGridFormSchema(), | ||||||
|  |   }, | ||||||
|  |   gridOptions: { | ||||||
|  |     columns: useGridColumns(onActionClick), | ||||||
|  |     height: 'auto', | ||||||
|  |     keepSource: true, | ||||||
|  |     proxyConfig: { | ||||||
|  |       ajax: { | ||||||
|  |         query: async ({ page }, formValues) => { | ||||||
|  |           return await getSocialClientPage({ | ||||||
|  |             pageNo: page.currentPage, | ||||||
|  |             pageSize: page.pageSize, | ||||||
|  |             ...formValues, | ||||||
|  |           }); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     rowConfig: { | ||||||
|  |       keyField: 'id', | ||||||
|  |     }, | ||||||
|  |     toolbarConfig: { | ||||||
|  |       refresh: { code: 'query' }, | ||||||
|  |       search: true, | ||||||
|  |     }, | ||||||
|  |   } as VxeTableGridOptions<SystemSocialClientApi.SocialClient>, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <Page auto-content-height> | ||||||
|  |     <template #doc> | ||||||
|  |       <DocAlert title="三方登录" url="https://doc.iocoder.cn/social-user/" /> | ||||||
|  |     </template> | ||||||
|  | 
 | ||||||
|  |     <FormModal @success="onRefresh" /> | ||||||
|  |     <Grid table-title="社交客户端列表"> | ||||||
|  |       <template #toolbar-tools> | ||||||
|  |         <ElButton | ||||||
|  |           type="primary" | ||||||
|  |           @click="onCreate" | ||||||
|  |           v-access:code="['system:social-client:create']" | ||||||
|  |         > | ||||||
|  |           <Plus class="size-5" /> | ||||||
|  |           {{ $t('ui.actionTitle.create', ['社交客户端']) }} | ||||||
|  |         </ElButton> | ||||||
|  |       </template> | ||||||
|  |     </Grid> | ||||||
|  |   </Page> | ||||||
|  | </template> | ||||||
|  | @ -0,0 +1,89 @@ | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import type { SystemSocialClientApi } from '#/api/system/social/client'; | ||||||
|  | 
 | ||||||
|  | import { computed, ref } from 'vue'; | ||||||
|  | 
 | ||||||
|  | import { useVbenModal } from '@vben/common-ui'; | ||||||
|  | 
 | ||||||
|  | import { ElMessage } from 'element-plus'; | ||||||
|  | 
 | ||||||
|  | import { useVbenForm } from '#/adapter/form'; | ||||||
|  | import { | ||||||
|  |   createSocialClient, | ||||||
|  |   getSocialClient, | ||||||
|  |   updateSocialClient, | ||||||
|  | } from '#/api/system/social/client'; | ||||||
|  | import { $t } from '#/locales'; | ||||||
|  | 
 | ||||||
|  | import { useFormSchema } from '../data'; | ||||||
|  | 
 | ||||||
|  | const emit = defineEmits(['success']); | ||||||
|  | const formData = ref<SystemSocialClientApi.SocialClient>(); | ||||||
|  | const getTitle = computed(() => { | ||||||
|  |   return formData.value?.id | ||||||
|  |     ? $t('ui.actionTitle.edit', ['社交客户端']) | ||||||
|  |     : $t('ui.actionTitle.create', ['社交客户端']); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | const [Form, formApi] = useVbenForm({ | ||||||
|  |   commonConfig: { | ||||||
|  |     componentProps: { | ||||||
|  |       class: 'w-full', | ||||||
|  |     }, | ||||||
|  |     formItemClass: 'col-span-2', | ||||||
|  |     labelWidth: 80, | ||||||
|  |   }, | ||||||
|  |   layout: 'horizontal', | ||||||
|  |   schema: useFormSchema(), | ||||||
|  |   showDefaultActions: false, | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | const [Modal, modalApi] = useVbenModal({ | ||||||
|  |   async onConfirm() { | ||||||
|  |     const { valid } = await formApi.validate(); | ||||||
|  |     if (!valid) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     modalApi.lock(); | ||||||
|  |     // 提交表单 | ||||||
|  |     const data = | ||||||
|  |       (await formApi.getValues()) as SystemSocialClientApi.SocialClient; | ||||||
|  |     try { | ||||||
|  |       await (formData.value?.id | ||||||
|  |         ? updateSocialClient(data) | ||||||
|  |         : createSocialClient(data)); | ||||||
|  |       // 关闭并提示 | ||||||
|  |       await modalApi.close(); | ||||||
|  |       emit('success'); | ||||||
|  |       ElMessage.success($t('ui.actionMessage.operationSuccess')); | ||||||
|  |     } finally { | ||||||
|  |       modalApi.unlock(); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   async onOpenChange(isOpen: boolean) { | ||||||
|  |     if (!isOpen) { | ||||||
|  |       formData.value = undefined; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     // 加载数据 | ||||||
|  |     const data = modalApi.getData<SystemSocialClientApi.SocialClient>(); | ||||||
|  |     if (!data || !data.id) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     modalApi.lock(); | ||||||
|  |     try { | ||||||
|  |       formData.value = await getSocialClient(data.id as number); | ||||||
|  |       // 设置到 values | ||||||
|  |       await formApi.setValues(formData.value); | ||||||
|  |     } finally { | ||||||
|  |       modalApi.unlock(); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <Modal :title="getTitle"> | ||||||
|  |     <Form class="mx-4" /> | ||||||
|  |   </Modal> | ||||||
|  | </template> | ||||||
|  | @ -0,0 +1,121 @@ | ||||||
|  | import type { VbenFormSchema } from '#/adapter/form'; | ||||||
|  | import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table'; | ||||||
|  | import type { SystemSocialUserApi } from '#/api/system/social/user'; | ||||||
|  | 
 | ||||||
|  | import { useAccess } from '@vben/access'; | ||||||
|  | 
 | ||||||
|  | import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; | ||||||
|  | 
 | ||||||
|  | const { hasAccessByCodes } = useAccess(); | ||||||
|  | 
 | ||||||
|  | /** 列表的搜索表单 */ | ||||||
|  | export function useGridFormSchema(): VbenFormSchema[] { | ||||||
|  |   return [ | ||||||
|  |     { | ||||||
|  |       fieldName: 'type', | ||||||
|  |       label: '社交平台', | ||||||
|  |       component: 'Select', | ||||||
|  |       componentProps: { | ||||||
|  |         options: getDictOptions(DICT_TYPE.SYSTEM_SOCIAL_TYPE, 'number'), | ||||||
|  |         placeholder: '请选择社交平台', | ||||||
|  |         allowClear: true, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'nickname', | ||||||
|  |       label: '用户昵称', | ||||||
|  |       component: 'Input', | ||||||
|  |       componentProps: { | ||||||
|  |         placeholder: '请输入用户昵称', | ||||||
|  |         allowClear: true, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'openid', | ||||||
|  |       label: '社交 openid', | ||||||
|  |       component: 'Input', | ||||||
|  |       componentProps: { | ||||||
|  |         placeholder: '请输入社交 openid', | ||||||
|  |         allowClear: true, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       fieldName: 'createTime', | ||||||
|  |       label: '创建时间', | ||||||
|  |       component: 'RangePicker', | ||||||
|  |       componentProps: { | ||||||
|  |         ...getRangePickerDefaultProps(), | ||||||
|  |         allowClear: true, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 列表的字段 */ | ||||||
|  | export function useGridColumns<T = SystemSocialUserApi.SocialUser>( | ||||||
|  |   onActionClick: OnActionClickFn<T>, | ||||||
|  | ): VxeTableGridOptions['columns'] { | ||||||
|  |   return [ | ||||||
|  |     { | ||||||
|  |       field: 'type', | ||||||
|  |       title: '社交平台', | ||||||
|  |       minWidth: 120, | ||||||
|  |       cellRender: { | ||||||
|  |         name: 'CellDict', | ||||||
|  |         props: { type: DICT_TYPE.SYSTEM_SOCIAL_TYPE }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'openid', | ||||||
|  |       title: '社交 openid', | ||||||
|  |       minWidth: 180, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'nickname', | ||||||
|  |       title: '用户昵称', | ||||||
|  |       minWidth: 120, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'avatar', | ||||||
|  |       title: '用户头像', | ||||||
|  |       minWidth: 80, | ||||||
|  |       cellRender: { | ||||||
|  |         name: 'CellImage', | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'createTime', | ||||||
|  |       title: '创建时间', | ||||||
|  |       minWidth: 180, | ||||||
|  |       formatter: 'formatDateTime', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'updateTime', | ||||||
|  |       title: '更新时间', | ||||||
|  |       minWidth: 180, | ||||||
|  |       formatter: 'formatDateTime', | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       field: 'operation', | ||||||
|  |       title: '操作', | ||||||
|  |       minWidth: 100, | ||||||
|  |       align: 'center', | ||||||
|  |       fixed: 'right', | ||||||
|  |       cellRender: { | ||||||
|  |         attrs: { | ||||||
|  |           nameField: 'nickname', | ||||||
|  |           nameTitle: '社交用户', | ||||||
|  |           onClick: onActionClick, | ||||||
|  |         }, | ||||||
|  |         name: 'CellOperation', | ||||||
|  |         options: [ | ||||||
|  |           { | ||||||
|  |             code: 'detail', | ||||||
|  |             text: '详情', | ||||||
|  |             show: hasAccessByCodes(['system:social-user:query']), | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ]; | ||||||
|  | } | ||||||
|  | @ -0,0 +1,84 @@ | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import type { | ||||||
|  |   OnActionClickParams, | ||||||
|  |   VxeTableGridOptions, | ||||||
|  | } from '#/adapter/vxe-table'; | ||||||
|  | import type { SystemSocialUserApi } from '#/api/system/social/user'; | ||||||
|  | 
 | ||||||
|  | import { Page, useVbenModal } from '@vben/common-ui'; | ||||||
|  | 
 | ||||||
|  | import { useVbenVxeGrid } from '#/adapter/vxe-table'; | ||||||
|  | import { getSocialUserPage } from '#/api/system/social/user'; | ||||||
|  | import { DocAlert } from '#/components/doc-alert'; | ||||||
|  | 
 | ||||||
|  | import { useGridColumns, useGridFormSchema } from './data'; | ||||||
|  | import Detail from './modules/detail.vue'; | ||||||
|  | 
 | ||||||
|  | const [DetailModal, detailModalApi] = useVbenModal({ | ||||||
|  |   connectedComponent: Detail, | ||||||
|  |   destroyOnClose: true, | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | /** 刷新表格 */ | ||||||
|  | // function onRefresh() { | ||||||
|  | //   gridApi.query(); | ||||||
|  | // } | ||||||
|  | 
 | ||||||
|  | /** 查看详情 */ | ||||||
|  | function onDetail(row: SystemSocialUserApi.SocialUser) { | ||||||
|  |   detailModalApi.setData(row).open(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 表格操作按钮的回调函数 */ | ||||||
|  | function onActionClick({ | ||||||
|  |   code, | ||||||
|  |   row, | ||||||
|  | }: OnActionClickParams<SystemSocialUserApi.SocialUser>) { | ||||||
|  |   switch (code) { | ||||||
|  |     case 'detail': { | ||||||
|  |       onDetail(row); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const [Grid] = useVbenVxeGrid({ | ||||||
|  |   formOptions: { | ||||||
|  |     schema: useGridFormSchema(), | ||||||
|  |   }, | ||||||
|  |   gridOptions: { | ||||||
|  |     columns: useGridColumns(onActionClick), | ||||||
|  |     height: 'auto', | ||||||
|  |     keepSource: true, | ||||||
|  |     proxyConfig: { | ||||||
|  |       ajax: { | ||||||
|  |         query: async ({ page }, formValues) => { | ||||||
|  |           return await getSocialUserPage({ | ||||||
|  |             pageNo: page.currentPage, | ||||||
|  |             pageSize: page.pageSize, | ||||||
|  |             ...formValues, | ||||||
|  |           }); | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     rowConfig: { | ||||||
|  |       keyField: 'id', | ||||||
|  |     }, | ||||||
|  |     toolbarConfig: { | ||||||
|  |       refresh: { code: 'query' }, | ||||||
|  |       search: true, | ||||||
|  |     }, | ||||||
|  |   } as VxeTableGridOptions<SystemSocialUserApi.SocialUser>, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <Page auto-content-height> | ||||||
|  |     <template #doc> | ||||||
|  |       <DocAlert title="三方登录" url="https://doc.iocoder.cn/social-user/" /> | ||||||
|  |     </template> | ||||||
|  | 
 | ||||||
|  |     <DetailModal /> | ||||||
|  |     <Grid table-title="社交用户列表" /> | ||||||
|  |   </Page> | ||||||
|  | </template> | ||||||
|  | @ -0,0 +1,83 @@ | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import type { SystemSocialUserApi } from '#/api/system/social/user'; | ||||||
|  | 
 | ||||||
|  | import { ref } from 'vue'; | ||||||
|  | 
 | ||||||
|  | import { useVbenModal } from '@vben/common-ui'; | ||||||
|  | 
 | ||||||
|  | import { ElDescriptions, ElDescriptionsItem, ElImage } from 'element-plus'; | ||||||
|  | 
 | ||||||
|  | import { getSocialUser } from '#/api/system/social/user'; | ||||||
|  | import { DictTag } from '#/components/dict-tag'; | ||||||
|  | import { $t } from '#/locales'; | ||||||
|  | import { DICT_TYPE } from '#/utils'; | ||||||
|  | 
 | ||||||
|  | const formData = ref<SystemSocialUserApi.SocialUser>(); | ||||||
|  | 
 | ||||||
|  | const [Modal, modalApi] = useVbenModal({ | ||||||
|  |   title: $t('ui.actionTitle.detail'), | ||||||
|  |   async onOpenChange(isOpen: boolean) { | ||||||
|  |     if (!isOpen) { | ||||||
|  |       formData.value = undefined; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     // 加载数据 | ||||||
|  |     const data = modalApi.getData(); | ||||||
|  |     if (!data || !data.id) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     modalApi.lock(); | ||||||
|  |     try { | ||||||
|  |       formData.value = await getSocialUser(data.id); | ||||||
|  |     } finally { | ||||||
|  |       modalApi.unlock(); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <Modal | ||||||
|  |     title="社交用户详情" | ||||||
|  |     class="w-1/2" | ||||||
|  |     :show-cancel-button="false" | ||||||
|  |     :show-confirm-button="false" | ||||||
|  |   > | ||||||
|  |     <ElDescriptions | ||||||
|  |       :column="1" | ||||||
|  |       size="default" | ||||||
|  |       border | ||||||
|  |       class="mx-4" | ||||||
|  |       :label-width="185" | ||||||
|  |     > | ||||||
|  |       <ElDescriptionsItem label="社交平台"> | ||||||
|  |         <DictTag :type="DICT_TYPE.SYSTEM_SOCIAL_TYPE" :value="formData?.type" /> | ||||||
|  |       </ElDescriptionsItem> | ||||||
|  |       <ElDescriptionsItem label="用户昵称"> | ||||||
|  |         {{ formData?.nickname }} | ||||||
|  |       </ElDescriptionsItem> | ||||||
|  |       <ElDescriptionsItem label="用户头像"> | ||||||
|  |         <ElImage | ||||||
|  |           :src="formData?.avatar" | ||||||
|  |           :preview-src-list="formData?.avatar ? [formData.avatar] : []" | ||||||
|  |           style="width: 30px; height: 30px" | ||||||
|  |         /> | ||||||
|  |       </ElDescriptionsItem> | ||||||
|  |       <ElDescriptionsItem label="社交 token"> | ||||||
|  |         {{ formData?.token }} | ||||||
|  |       </ElDescriptionsItem> | ||||||
|  |       <ElDescriptionsItem label="原始 Token 数据"> | ||||||
|  |         {{ formData?.rawTokenInfo }} | ||||||
|  |       </ElDescriptionsItem> | ||||||
|  |       <ElDescriptionsItem label="原始 User 数据"> | ||||||
|  |         {{ formData?.rawUserInfo }} | ||||||
|  |       </ElDescriptionsItem> | ||||||
|  |       <ElDescriptionsItem label="最后一次的认证 code"> | ||||||
|  |         {{ formData?.code }} | ||||||
|  |       </ElDescriptionsItem> | ||||||
|  |       <ElDescriptionsItem label="最后一次的认证 state"> | ||||||
|  |         {{ formData?.state }} | ||||||
|  |       </ElDescriptionsItem> | ||||||
|  |     </ElDescriptions> | ||||||
|  |   </Modal> | ||||||
|  | </template> | ||||||
		Loading…
	
		Reference in New Issue
	
	 puhui999
						puhui999