create-iking-admin
Version:
金合技术中台脚手架
522 lines (507 loc) • 16.4 kB
text/typescript
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