import axios from 'axios'
import get from 'lodash-es/get.js'
import isDev from 'wsemi/src/isDev.mjs'
import isestr from 'wsemi/src/isestr.mjs'
import ispint from 'wsemi/src/ispint.mjs'
import iseobj from 'wsemi/src/iseobj.mjs'
import isp0int from 'wsemi/src/isp0int.mjs'
import isfun from 'wsemi/src/isfun.mjs'
import ispm from 'wsemi/src/ispm.mjs'
import cint from 'wsemi/src/cint.mjs'
import delay from 'wsemi/src/delay.mjs'
import pmConvertResolve from 'wsemi/src/pmConvertResolve.mjs'
/**
* 前端界面用之使用者登入出輔助功能函數
*
* @param {String} site 輸入專案名稱字串
* @param {Object} [opt={}] 輸入設定物件,預設{}
* @param {String} [opt.params={}] 輸入,預設{}
* @param {String} [opt.keyGlobal='___params___'] 輸入,預設'___params___'
* @param {Integer} [opt.timeWaitAnimation=0] 輸入,預設0
* @param {String} [opt.defToken='sys'] 輸入,預設'sys'
* @param {String} [opt.apiName='api'] 輸入,預設'api'
* @param {String} [opt.apiNameForVerify='getUserByToken'] 輸入,預設'getUserByToken'
* @param {Integer} [opt.retry=3] 輸入驗證token失敗重試次數整數,預設為3
* @returns {Object} 回傳輔助函數物件,可使用'parseUrl'、'getTokenFromUrl'、'getToken'、'getValue'、'getUrl'、'getApi'、'login'、'detect'、'logout'
* @example
* import wui from 'w-ui-loginout/src/WUiLoginout.mjs'
*
* function loginSuccess(data) {
* console.log('login success', data.user)
* // vo.$ui.updateConnState('已連線')
* // vo.$ui.updateUserToken(data.token)
* // vo.$ui.updateUserSelf(data.user)
* }
*
* function loginError(data) {
* console.log('login error', data)
* // vo.$ui.updateConnState(data.text)
* // vo.$ui.updateUserToken('')
* // vo.$ui.updateUserSelf(get(vo, `$store.state.userDef`))
* // vo.ready = false
* // vo.msg = data.msg
* }
*
* //login
* console.log('login...')
* let ll = wui('wperm', {
* // logIn: '{base}sso/?sid=i12-i34-i56-i78', //提供sso指定需返回之專案sid
* // logOut: '{base}sso/api/logout?token={token}',
* // checkToken: '{base}sso/api/checkToken?token={token}',
* // goSSO: '{base}sso/?token={token}',
* // goPerm: '{baseNoPort}perm/?token={token}',
* })
* ll.login({
* afterGetUser: null,
* afterLogin: null,
* loginSuccess,
* loginError,
* })
* // vo.ll = ll
*
*/
function WUiLoginout(site, opt = {}) {
//check site
if (!isestr(site)) {
throw new Error(`invalid site`)
}
//params
let params = get(opt, 'params', {})
// console.log('params', params)
//keyGlobal
let keyGlobal = get(opt, 'keyGlobal', '')
if (!isestr(keyGlobal)) {
keyGlobal = '___params___'
}
//timeWaitAnimation, 等待連線動畫展示延遲時間
let timeWaitAnimation = get(opt, 'timeWaitAnimation')
if (!ispint(timeWaitAnimation)) {
timeWaitAnimation = 0
}
//defToken
let defToken = get(opt, 'defToken', '')
if (!isestr(defToken)) {
defToken = 'sys'
}
//apiName
let apiName = get(opt, 'apiName', '')
if (!isestr(apiName)) {
apiName = 'api'
}
//apiNameForVerify
let apiNameForVerify = get(opt, 'apiNameForVerify', '')
if (!isestr(apiNameForVerify)) {
apiNameForVerify = 'getUserByToken'
}
//retry
let retry = get(opt, 'retry')
if (!isp0int(retry)) {
retry = 3
}
//urlOrigin
let urlOrigin = window.location.origin
//urlBase
let urlBase = window.location.origin + window.location.pathname
//urlOriginNoPort, urlBaseNoPort, 取代開發階段perm用IIS反向代理架設, 網址無port得取代掉
let urlOriginNoPort = urlOrigin
let urlBaseNoPort = urlBase
if (isestr(window.location.port)) {
let p = `:${window.location.port}`
urlOriginNoPort = urlOriginNoPort.replace(p, '')
urlBaseNoPort = urlBaseNoPort.replace(p, '')
}
//save, 儲存至window供全域使用
window[keyGlobal] = {
...params,
site,
origin: urlOrigin,
originNoPort: urlOriginNoPort,
base: urlBase,
baseNoPort: urlBaseNoPort,
}
//parseUrl
let parseUrl = () => {
//ulps
let ulps = new URLSearchParams(window.location.search)
// console.log('ulps', ulps, window.location.search, window.location.href)
//kp
let kp = {}
ulps.forEach((v, k) => {
// console.log(k, v)
kp[k] = v
})
// console.log('kp', kp)
return kp
}
//getTokenFromUrl
let getTokenFromUrl = () => {
//kp
let kp = parseUrl()
// console.log('kp', kp)
//token
let token = get(kp, 'token', '')
// console.log('token', token)
return token
}
//getToken
let getToken = () => {
let token = ''
if (!isestr(token)) {
token = getTokenFromUrl()
// console.log('getTokenFromUrl', token)
}
if (!isestr(token)) {
token = localStorage.getItem(`${site}:userToken`) //[localStorage:token]
// console.log('localStorage.getItem', token)
}
return token
}
//getValue
let getValue = (key) => {
let value = get(window, `${keyGlobal}.${key}`, '')
return value
}
//getUrl
let getUrl = (key) => {
let token = getToken()
let origin = get(window, `${keyGlobal}.origin`, '')
let originNoPort = get(window, `${keyGlobal}.originNoPort`, '')
let base = get(window, `${keyGlobal}.base`, '')
let baseNoPort = get(window, `${keyGlobal}.baseNoPort`, '')
let url = getValue(key)
url = url.replace('{token}', token)
url = url.replace('{origin}', origin)
url = url.replace('{originNoPort}', originNoPort)
url = url.replace('{base}', base)
url = url.replace('{baseNoPort}', baseNoPort)
return url
}
//getApi
let getApi = async(path) => {
let errTemp = null
//urlBase
let urlBase = getValue('base')
// console.log('getApi urlBase', urlBase)
//url
let url = `${urlBase}${apiName}/${path}`
// console.log('getApi url', url)
//axios
let r
await axios({
method: 'GET',
url,
})
.then((res) => {
r = res.data
// console.log('getApi then', r)
})
.catch((err) => {
// console.log('getApi catch', err)
errTemp = err.toString()
})
//check
if (errTemp !== null) {
return Promise.reject(errTemp)
}
return r
}
//login
let login = async (opt = {}) => {
//afterGetUser
let afterGetUser = get(opt, 'afterGetUser')
//afterLogin
let afterLogin = get(opt, 'afterLogin')
//loginError
let loginError = get(opt, 'loginError')
//loginSuccess
let loginSuccess = get(opt, 'loginSuccess')
//site
let site = getValue('site')
// console.log('site', site)
async function core() {
let errTemp = null
//delay, 等待連線動畫展示
await delay(timeWaitAnimation)
//check
if (!isestr(site)) {
console.log('site', site)
throw new Error(`invalid site`)
}
//token
let token = ''
if (!isestr(token)) {
token = getTokenFromUrl()
// console.log('getTokenFromUrl', token)
}
if (!isestr(token)) {
token = localStorage.getItem(`${site}:userToken`) //[localStorage:token]
// console.log('localStorage.getItem', token)
}
//check
if (isDev()) {
if (!isestr(token)) {
// console.log('use defToken', defToken)
token = defToken
}
//不能用else if, 供測試無效令牌情況
if (token === 'error') {
errTemp = {
text: '登入時無效令牌',
msg: 'invalid token',
}
return Promise.reject(errTemp)
}
}
else {
if (!isestr(token)) {
errTemp = {
text: '登入時無效令牌',
msg: 'invalid token',
}
return Promise.reject(errTemp)
}
}
// console.log('token', token)
//getApi
let data = await getApi(`${apiNameForVerify}?token=${token}`)
.catch((err) => {
errTemp = {
text: '登入時無法連線',
msg: err,
}
})
// console.log(apiNameForVerify, 'data', data, 'errTemp', errTemp)
//check
if (errTemp !== null) {
return Promise.reject(errTemp)
}
//check, 內容為權限提供, 格式用pm2resolve轉, 故提取state進行判斷
if (get(data, 'state') === 'error') {
errTemp = {
text: '登入時驗證失敗',
msg: get(data, 'msg'),
}
return Promise.reject(errTemp)
}
//user
let user = get(data, 'msg')
// console.log('user', user)
//check
if (!iseobj(user)) {
console.log('data', data)
errTemp = {
text: '登入時無法取得使用者資訊',
msg: 'invalid user',
}
return Promise.reject(errTemp)
}
//afterGetUser
if (isfun(afterGetUser)) {
let r = afterGetUser(user)
if (ispm(r)) {
r = await r
}
}
return {
token,
user,
}
}
//accdata
let state
let data
await core()
.then((res) => {
state = true
data = res
//save userToken
localStorage.setItem(`${site}:userToken`, res.token) //[localStorage:token]
})
.catch((err) => {
state = false
data = err
//clear userToken
localStorage.setItem(`${site}:userToken`, '') //[localStorage:token]
})
let accdata = {
state,
data,
}
// console.log('accdata', accdata)
//afterLogin
if (isfun(afterLogin)) {
let r = afterLogin(accdata)
if (ispm(r)) {
r = await r
}
}
//loginSuccess, loginError
if (state) {
if (isfun(loginSuccess)) {
let r = loginSuccess(data)
if (ispm(r)) {
r = await r
}
}
}
else {
if (isfun(loginError)) {
let r = loginError(data)
if (ispm(r)) {
r = await r
}
}
}
return accdata
}
//detect
let detect = async (opt = {}) => {
//timePeriod, 輪循週期(ms)
let timePeriod = get(opt, 'timePeriod')
if (!ispint(timePeriod)) {
timePeriod = 2000
}
timePeriod = cint(timePeriod)
//procCheckToken
let procCheckToken = get(opt, 'procCheckToken')
//procLogout
let procLogout = get(opt, 'procLogout')
//site
let site = getValue('site')
// console.log('site', site)
//urlCheckToken
let urlCheckToken = getUrl('checkToken')
//checkTokenCore
let checkTokenCore = async() => {
let errTemp = null
//axios
let res = await axios({
method: 'GET',
url: urlCheckToken,
})
.catch((err) => {
// console.log('urlLogOut catch', err)
errTemp = {
text: '驗證令牌時遭遇錯誤',
msg: err,
}
})
//check
if (errTemp !== null) {
return Promise.reject(errTemp)
}
return res
}
//checkToken
let checkToken = async() => {
//fun
let fun = pmConvertResolve(checkTokenCore)
//sendPkg
let r = await fun()
let n = 0
while (r.state === 'error') {
n += 1
if (n > retry) {
break
}
console.log(`retry n=${n}`)
r = await fun()
}
if (r.state === 'success') {
return r.msg
}
else {
return Promise.reject(r.msg)
}
}
let locking = false
async function core() {
let errTemp = null
//check
if (locking) {
return
}
locking = true
//輪循確認ls內token是否存在
let token = localStorage.getItem(`${site}:userToken`) //[localStorage:token]
// console.log('localStorage.getItem', token)
//check
if (!isestr(token)) {
errTemp = {
text: '令牌已清除',
msg: 'invalid token',
}
return Promise.reject(errTemp)
}
//checkToken
let res = await checkToken()
.catch((err) => {
errTemp = err
})
//check
if (errTemp !== null) {
return Promise.reject(errTemp)
}
//procCheckToken
if (isfun(procCheckToken)) {
let r = procCheckToken(res)
if (ispm(r)) {
r = await r
}
if (!r) {
errTemp = {
text: '驗證令牌失敗',
msg: res,
}
}
}
//check
if (errTemp !== null) {
return Promise.reject(errTemp)
}
locking = false
}
//setInterval
let t = setInterval(() => {
core()
.catch((err) => {
clearInterval(t)
if (isfun(procLogout)) {
procLogout(err)
}
})
}, timePeriod)
return null
}
//logout
let logout = async (opt = {}) => {
//procLogout
let procLogout = get(opt, 'procLogout')
//afterLogout
let afterLogout = get(opt, 'afterLogout')
//logoutError
let logoutError = get(opt, 'logoutError')
//logoutSuccess
let logoutSuccess = get(opt, 'logoutSuccess')
//site
let site = getValue('site')
// console.log('site', site)
async function core() {
let errTemp = null
//token
let token = getToken()
//check
if (!isestr(token)) {
errTemp = {
text: '無法取得登出用token',
msg: 'invalid token',
}
return Promise.reject(errTemp)
}
//urlLogOut
let urlLogOut = getUrl('logOut')
if (!isestr(urlLogOut)) {
errTemp = {
text: '無法取得登出用設定資訊',
msg: 'invalid urlLogOut',
}
return Promise.reject(errTemp)
}
//axios
let res = await axios({
method: 'GET',
url: urlLogOut,
})
.catch((err) => {
// console.log('urlLogOut catch', err)
errTemp = {
text: '登出時遭遇錯誤',
msg: err,
}
})
//check
if (errTemp !== null) {
return Promise.reject(errTemp)
}
//procLogout
if (isfun(procLogout)) {
let r = procLogout(res)
if (ispm(r)) {
r = await r
}
if (!r) {
errTemp = {
text: '登出失敗',
msg: res,
}
}
}
//check
if (errTemp !== null) {
return Promise.reject(errTemp)
}
return {
token,
}
}
//accdata
let state
let data
await core()
.then((res) => {
state = true
data = res
})
.catch((err) => {
state = false
data = err
})
let accdata = {
state,
data,
}
//clear userToken
localStorage.setItem(`${site}:userToken`, '') //[localStorage:token]
//afterLogout
if (isfun(afterLogout)) {
let r = afterLogout(accdata)
if (ispm(r)) {
r = await r
}
}
//logoutSuccess, logoutError
if (state) {
if (isfun(logoutSuccess)) {
let r = logoutSuccess(data)
if (ispm(r)) {
r = await r
}
}
}
else {
if (isfun(logoutError)) {
let r = logoutError(data)
if (ispm(r)) {
r = await r
}
}
}
return accdata
}
//r
let r = {
parseUrl,
getTokenFromUrl,
getToken,
getValue,
getUrl,
getApi,
login,
detect,
logout,
}
return r
}
export default WUiLoginout