UNPKG

create-iking-admin

Version:

金合技术中台脚手架

522 lines (507 loc) 16.4 kB
import { cloneDeep } from 'lodash-es' import { createDefu } from 'defu' import router from '@main/router' import { loginApi } from '@main/api/modules/login' import settingsDefault from '@main/settings' import menuApi from '@main/api/modules/menu' import { tenantApi } from '@main/api/modules/tenant' import { userApi } from '@main/api/modules/user' import useSettingsStore from './settings' import useTabbarStore from './tabbar' import useRouteStore from './route' import useMenuStore from './menu' import useSocketStore from './socket' import type { Settings } from '#/global' const useUserStore = defineStore( // 唯一ID 'user', () => { const settingsStore = useSettingsStore() const tabbarStore = useTabbarStore() const routeStore = useRouteStore() const menuStore = useMenuStore() const socketStore = useSocketStore() const account = ref(ikStore.local.getItem(ELocal.ACCOUNT) ?? '') const token = ref(ikStore.local.getItem(ELocal.TOKEN) ?? '') const failure_time = ref(ikStore.local.getItem(ELocal.FAILURE_TIME) ?? '') const permissions = ref<string[]>([]) const userInfo = ref(ikStore.local.getItem(ELocal.USER_INFO) ?? '') const pwdVisible = ref(Boolean(Number(ikStore.local.getItem(ELocal.PWD_VISIBLE) || 0))) const pwdType = ref('timeout') const settingId = ref(ikStore.local.getItem(ELocal.SETTING_ID) ?? '') const tenant = ref(ikStore.local.getItem(ELocal.TENANT) ?? '') const showTenant = ref(false) const organiza = ref(ikStore.local.getItem(ELocal.ORGANIZA) || { select: '', list: [], }) const isLogin = computed(() => { if (token.value) { return true } return false }) // 获取用户租户信息 async function queryTenant() { if (!token.value) { return null } const res = await tenantApi.queryTenantList() return res } // 获取用户信息 通过 async function getUserInfo(id: string) { if (!token.value) { return null } const { success, data } = await loginApi.getUserInfo(id) if (success) { userInfo.value = data if (!account.value) { account.value = data.name } data && ikStore.local.setItem(ELocal.USER_INFO, data) // 用户组织数据 organiza.value = { select: data.organizationIds?.[0] || '', list: data.organizations, } ikStore.local.setItem(ELocal.ORGANIZA, organiza.value) try { // 创建socket连接 socketStore.createSocket() } catch (error) { throw new Error(error) } } } // 获取字典 async function getAllDiction() { const { success, msg, data } = await menuApi.getAllDiction() if (success) { const fa: Set<string> = new Set( data.map((item: { dictCode: string }) => item?.dictCode), ) for (const i of fa) { data.push({ id: i, name: i }) } const dict: { [key: string]: any } = {} const tree = ikTree.listToTree(data, { id: 'id', pid: 'dictCode' }) for (const i of fa) { dict[i] = tree.find((f: { id: string }) => f.id === i)?.children } ikStore.local.setItem(ELocal.DICTIONARY, dict) } else { useMessage().msgWarning(msg) } } const handleLoginRes = async (res: { msg: string, data: any, success: boolean }, type: string) => { const { msg, data, success } = res if (!success) { return } if (success) { // 系统右上角用户名 account.value = data.name token.value = data.token failure_time.value = data.expire } // 更新提示修改密码框状态 updatePwdVisible(data?.passwordExpired || false) if (success && type === ELoginType.密码登录) { await ikStore.local.setItem(ELocal.TOKEN, data.token) ikStore.local.setItem(ELocal.ACCOUNT, data.name) ikStore.local.setItem( ELocal.FAILURE_TIME, new Date().getTime() + Number.parseInt(data.expire || 99999) * 1000 * 60, ) useMessage().msgSuccess(msg) } // 获取页面CSS灰度值(特殊时期页面置灰) loginApi.getPageCssFilter().then((res: any) => { ikStore.local.setItem(ELocal.GRRY, res?.data ?? 1) }) // 获取用户详细信息userInfo await getUserInfo(data.id) return res } const buildTokenAutoLoginRes = (token: string | undefined) => { return { code: 200, success: true, msg: '登录成功', pages: 0, total: 0, data: { name: '', token, expire: 0, }, } } // 登录 async function login( param: { account?: string password?: string phone?: string captcha?: string token?: string }, type: string, ) { let res: ApiModel = { msg: '', data: null, code: 0, pages: 0, success: false, total: 0, } switch (type) { case ELoginType.Token自动登录: res = buildTokenAutoLoginRes(param.token) break case ELoginType.密码登录: res = await loginApi.login( { credentialName: param.account, password: passwordEncry( param.password || '', '1234567890000000', { encode: 'hex', }, ).AES.encrypt(), }, { headers: { 'X-PASSWORD-ENCRYPT': 'encrypt', }, }, ) break case ELoginType.短信登录: // 短信登录参数 res = await loginApi.login( { phone: param.phone, smsVerifyCode: param.captcha, }, { headers: { 'X-PASSWORD-ENCRYPT': 'encrypt', }, }, ) break case ELoginType.微信登录: // 微信登录参数 res = await loginApi.login( { wechatMiniOpenId: '', }, {}, ) break case ELoginType.钉钉登录: // 钉钉登录参数 break default: break } return handleLoginRes(res, type) } // 登出 async function logout(redirect = router.currentRoute.value.fullPath) { ikStore.local.removeItem('account') ikStore.local.removeItem('token') ikStore.local.removeItem('avatar') account.value = '' token.value = '' permissions.value = [] tabbarStore.clean() routeStore.removeRoutes() // menuStore.setActived(0) router.push({ name: 'login', query: { ...(router.currentRoute.value.path !== settingsStore.settings.home.fullPath && router.currentRoute.value.name !== 'login' && { redirect }), }, }) } // 修改密码 async function editPassword(data: { password: string newpassword: string }) { await apiUser.passwordEdit(data) } // 框架已将可提供给用户配置的选项提取出来,请勿新增其他选项,不需要的选项可以在这里注释掉 const preferences = ref<Settings.all>({ app: { colorScheme: settingsDefault.app.colorScheme, lightTheme: settingsDefault.app.lightTheme, darkTheme: settingsDefault.app.darkTheme, enableProgress: settingsDefault.app.enableProgress, }, menu: { menuMode: settingsDefault.menu.menuMode, isRounded: settingsDefault.menu.isRounded, menuActiveStyle: settingsDefault.menu.menuActiveStyle, switchMainMenuAndPageJump: settingsDefault.menu.switchMainMenuAndPageJump, subMenuOnlyOneHide: settingsDefault.menu.subMenuOnlyOneHide, subMenuUniqueOpened: settingsDefault.menu.subMenuUniqueOpened, subMenuCollapse: settingsDefault.menu.subMenuCollapse, subMenuAutoCollapse: settingsDefault.menu.subMenuAutoCollapse, enableSubMenuCollapseButton: settingsDefault.menu.enableSubMenuCollapseButton, }, layout: { widthMode: settingsDefault.layout.widthMode, }, mainPage: { enableTransition: settingsDefault.mainPage.enableTransition, transitionMode: settingsDefault.mainPage.transitionMode, }, topbar: { mode: settingsDefault.topbar.mode, switchTabbarAndToolbar: settingsDefault.topbar.switchTabbarAndToolbar, }, tabbar: { style: settingsDefault.tabbar.style, enableIcon: settingsDefault.tabbar.enableIcon, enableMemory: settingsDefault.tabbar.enableMemory, }, toolbar: { breadcrumb: settingsDefault.toolbar.breadcrumb, navSearch: settingsDefault.toolbar.navSearch, fullscreen: settingsDefault.toolbar.fullscreen, pageReload: settingsDefault.toolbar.pageReload, colorScheme: settingsDefault.toolbar.colorScheme, layout: settingsDefault.toolbar.layout, }, breadcrumb: { style: settingsDefault.breadcrumb.style, enableMainMenu: settingsDefault.breadcrumb.enableMainMenu, }, }) // 此处没有使用 lodash 的 defaultsDeep 函数,而是基于 defu 库自定义了一个函数,只合并 settings 中有的属性,而不是全部合并,这样做的目的是为了排除用户历史遗留的偏好配置 const customDefaultsDeep = createDefu((obj, key, value) => { if (obj[key] === undefined) { delete obj[key] return true } if (Array.isArray(obj[key]) && Array.isArray(value)) { obj[key] = value return true } }) // isPreferencesUpdating 用于防止循环更新 let isPreferencesUpdating = false watch(preferences, (val) => { if (!settingsStore.settings.userPreferences.enable) { return } if (!isPreferencesUpdating) { isPreferencesUpdating = true settingsStore.updateSettings(cloneDeep(val)) } else { isPreferencesUpdating = false } updatePreferences(cloneDeep(val)) }, { deep: true, }) watch(() => settingsStore.settings, (val) => { if (!settingsStore.settings.userPreferences.enable) { return } if (!isPreferencesUpdating) { isPreferencesUpdating = true preferences.value = customDefaultsDeep(val, preferences.value) } else { isPreferencesUpdating = false } }, { deep: true, }) // isPreferencesInited 用于防止初始化时触发更新 let isPreferencesInited = false // 获取偏好设置 async function getPreferences() { let data: Settings.all = {} if (settingsStore.settings.userPreferences.storageTo === 'local') { if (ikStore.local.has('userPreferences')) { data = JSON.parse(ikStore.local.getItem('userPreferences') as string)[account.value] || {} } } else if (settingsStore.settings.userPreferences.storageTo === 'server') { const res = await apiUser.preferences() data = JSON.parse(res.data.preferences || '{}') as Settings.all } preferences.value = customDefaultsDeep(data, preferences.value) } // 更新偏好设置 async function updatePreferences(data: Settings.all = {}) { if (!isPreferencesInited) { isPreferencesInited = true return } if (settingsStore.settings.userPreferences.storageTo === 'local') { const userPreferencesData = ikStore.local.has('userPreferences') ? JSON.parse(ikStore.local.getItem('userPreferences') as string) : {} userPreferencesData[account.value] = data ikStore.local.setItem('userPreferences', JSON.stringify(userPreferencesData)) } else if (settingsStore.settings.userPreferences.storageTo === 'server') { await apiUser.preferencesEdit(JSON.stringify(data)) } } // 更新密码框状态 function updatePwdVisible(bool: boolean, type = 'timeout') { pwdType.value = type pwdVisible.value = Boolean(bool) ikStore.local.setItem(ELocal.PWD_VISIBLE, bool ? 1 : 0) } const queryAllDic = async () => { try { await getUserSetting() await getAllDiction() } catch (error) { useLog().warn(error) } } // 获取并应用用户配置 async function getUserSetting() { const { success, data, msg } = await userApi.getSetting() if (success && data?.configInfoList?.length) { const dataValue = data?.configInfoList?.find((item: any) => item.type === 'THEME') const sett = JSON.parse(dataValue?.value || '') if (!paramType.isObject(sett)) { console.warn('用户配置错误', sett) return } settingsStore.updateSettings(sett) settingId.value = dataValue?.id ikStore.local.setItem(ELocal.SETTING, sett) } !success && console.warn(msg) } // 保存用户配置 async function setUserSetting(config: { id?: string userId: string type: 'THEME' | 'LANGUAGE' value: string }) { const { success, msg } = await userApi.setSetting({ ...config, global: false, }) !success && console.warn(msg) try { ikStore.local.setItem(ELocal.SETTING, JSON.parse((config as any)?.configInfoList?.find((item: any) => item.type === 'THEME')?.value || '')) } catch (error) { } } function clearCache() { try { routeStore.removeRoutes() // routeStore.isGenerate = false ikStore.local.removeItem('account') ikStore.local.removeItem('token') ikStore.local.removeItem('failure_time') ikStore.local.removeItem('user_info') ikStore.local.removeItem('tenant') account.value = '' token.value = '' failure_time.value = '' permissions.value = [] tabbarStore.clean() menuStore.setActived(0) } catch (error) { throw new Error(error as string) } } const getLoginUser = async () => { await tenantApi.getLoginUser() } const autoLoginNext = async () => { const res = await queryTenant() const tenantList = ref<any>(null) if (res?.success) { tenantList.value = res?.data || null if (res?.data?.length === 1) { if (res?.data[0].normal) { ikStore.local.setItem(ELocal.TENANT, res.data[0]) tenant.value = res?.data[0] await getLoginUser() await queryAllDic() if (!showTenant.value) { // router.push(redirect.value) return } } else { showTenant.value = true } } if (res?.data?.tenantList?.length > 1) { const loginTenant = res?.data?.tenantList.find( (item: any) => item.recent === true, ) if (loginTenant) { tenant.value = loginTenant ikStore.local.setItem(ELocal.TENANT, loginTenant) await getLoginUser() await queryAllDic() if (!showTenant.value) { // router.push(redirect.value) return } } } showTenant.value = true } else { // res?.msg && msgError(res?.msg) showTenant.value = false } } async function autoLogin(token: string, to: any) { const res = await login({ token }, ELoginType.Token自动登录) await autoLoginNext() if (res?.success) { router.push(to.path) } } return { account, token, permissions, isLogin, userInfo, pwdVisible, pwdType, tenant, showTenant, organiza, login, autoLogin, logout, editPassword, updatePwdVisible, clearCache, getUserSetting, setUserSetting, queryTenant, getAllDiction, queryAllDic, } }, ) export default useUserStore