diff --git a/src/api/req.js b/src/api/req.js index 4c6053c..ffc146b 100644 --- a/src/api/req.js +++ b/src/api/req.js @@ -8,6 +8,7 @@ import qs from 'qs' import S from '@/spx' import { isAlipay, isWeixin, isFromWebapp } from '@/utils' import log from '@/utils/log' +import { syncCompanyIdFromUrl } from '@/utils/companySync' import { HTTP_STATUS } from './consts' const isWeb = true @@ -142,6 +143,9 @@ class API { } intereptorReq(params) { + // 保证首屏 API(如企微 jssdk config)能带上路由中的 company_id + syncCompanyIdFromUrl() + const { url, data, header = {}, method = 'GET' } = params const { company_id, appid } = this.options const methodIsGet = method.toLowerCase() === 'get' @@ -174,9 +178,8 @@ class API { } if (isFromWebapp()) { - // if (!query.company_id) { - query.company_id = S.get('WEBAPP', true).company_id - //} + const web = S.get('WEBAPP', true) || {} + query.company_id = web.company_id || web.companyId || Taro.getStorageSync('company_id') } else { query.company_id = Taro.getStorageSync('company_id') } @@ -201,12 +204,28 @@ class API { } intereptorRes(res) { - const { data, statusCode, config } = res - const { showError = true } = config + if (!res || typeof res !== 'object') { + return Promise.reject(this.reqError(res, '请求响应异常')) + } + const { data, statusCode, config = {} } = res + const { showError = true } = config || {} if (statusCode == HTTP_STATUS.SUCCESS) { - const { status_code } = data.data + if (!data || typeof data !== 'object') { + if (showError) { + this.errorToast({ message: '服务返回数据为空' }) + } + return Promise.reject(this.reqError(res, '服务返回数据为空')) + } + const inner = data.data + if (inner === undefined || inner === null || typeof inner !== 'object') { + if (showError) { + this.errorToast({ message: '服务返回数据格式异常' }) + } + return Promise.reject(this.reqError(res, '服务返回数据格式异常')) + } + const { status_code } = inner if (!status_code) { - return data.data + return inner } else { // status_code 不为0,表示有错误 if (showError) { @@ -217,7 +236,7 @@ class API { } if (statusCode === HTTP_STATUS.UNAUTHORIZED) { - if ((data.data && data.data.status_code) === HTTP_STATUS.USER_FORBIDDEN) { + if (data?.data?.status_code === HTTP_STATUS.USER_FORBIDDEN) { if (showError) { this.errorToast(data) } @@ -297,7 +316,7 @@ class API { res.config = options if ( res.statusCode === HTTP_STATUS.UNAUTHORIZED && - (res.data.data && res.data.data.code) === HTTP_STATUS.TOKEN_NEEDS_REFRESH && + res?.data?.data?.code === HTTP_STATUS.TOKEN_NEEDS_REFRESH && S.getAuthToken() ) { // token失效时重造请求,并刷新token @@ -353,7 +372,8 @@ class API { // console.log('reqError.res', res) // console.log('reqError.msg', msg) // if (res && res.statusCode) Taro.navigateTo('pages/auth/login') - const errMsg = (res.data && res.data.message) || msg + const errMsg = + (res && res.data && (res.data.message || res.data.data?.message)) || msg || '请求失败' const err = new Error(errMsg) err.res = res return err diff --git a/src/app.js b/src/app.js index 25ee0ab..e9824a2 100644 --- a/src/app.js +++ b/src/app.js @@ -9,6 +9,7 @@ import { Provider } from 'react-redux' import { SAPP, SAPPPay, SAPPShare } from './muiApp' import configStore from './store' import { cleanWeapp, isFromWebapp, isIos } from '@/utils' +import { syncCompanyIdFromUrl } from '@/utils/companySync' import '@/muiApp/index.scss' import 'default-passive-events' import S from '@/spx' @@ -71,6 +72,8 @@ class App extends Component { } componentDidShow(options) { + syncCompanyIdFromUrl() + const { company_id } = options const { userAgent } = window.navigator console.log('userAgent', userAgent) diff --git a/src/components/sp-page-components/page-action-buttons/index.js b/src/components/sp-page-components/page-action-buttons/index.js index eba4219..9059b0e 100644 --- a/src/components/sp-page-components/page-action-buttons/index.js +++ b/src/components/sp-page-components/page-action-buttons/index.js @@ -80,13 +80,19 @@ class PageActionButtons extends PureComponent { return buttons.map((button, index) => { const buttonType = button.type const buttonName = button.name + // 改价入口(markdown):在图标/文案前统一展示「改价」 + let displayText = buttonName + if (buttonType === 'markdown') { + const raw = (buttonName || '').trim() + displayText = raw.includes('改价') ? raw : `改价${raw}` + } return ( ({ @@ -61,47 +63,53 @@ class Index extends Component { } componentDidMount() { - // const { href } = window.location - // if (S.getAuthToken()) { - // qwsdk.register({ - // url: href - // }) - // } + const { href } = window.location + if (S.getAuthToken()) { + qwsdk.register({ + url: href + }) + } } async componentDidShow() { + syncCompanyIdFromUrl() setWeapp() if (isFromWebapp()) { - const { app_id, app_type, company_id, openid, unionid, token } = S.get('WEBAPP', true) - // let data + const { app_id, app_type, company_id, openid, unionid, token } = normalizeWebappRecord( + S.get('WEBAPP', true) + ) + let data if (token) { S.setAuthToken(token) - // const { href, origin, search } = window.location - // const sdkAuthUrlIos = Taro.getStorageSync('sdk_auth_url_ios') - // console.log('sdkAuthUrlIos:', sdkAuthUrlIos) - // qwsdk.register({ - // url: isIos() ? `${sdkAuthUrlIos}` : href - // }) + if (company_id != null && company_id !== '') { + Taro.setStorageSync('company_id', String(company_id)) + } + const { href, origin, search } = window.location + const sdkAuthUrlIos = Taro.getStorageSync('sdk_auth_url_ios') + console.log('sdkAuthUrlIos:', sdkAuthUrlIos) + qwsdk.register({ + url: isIos() ? `${sdkAuthUrlIos}` : href + }) + } + if (!S.getAuthToken()) { + data = await api.weapp.is_bind({ + app_id, + app_type, + company_id, + openid, + unionid + }) + // if (company_id) { + // Taro.setStorageSync('company_id', company_id) + // } + if (data.token) { + S.setAuthToken(data.token) + const { href } = window.location + qwsdk.register({ + url: href + }) + } } - // if (!S.getAuthToken()) { - // data = await api.weapp.is_bind({ - // app_id, - // app_type, - // company_id, - // openid, - // unionid - // }) - // // if (company_id) { - // // Taro.setStorageSync('company_id', company_id) - // // } - // if (data.token) { - // S.setAuthToken(data.token) - // const { href } = window.location - // qwsdk.register({ - // url: href - // }) - // } - // } } else { const { href } = window.location const { company_id } = getCurrentInstance().router.params || {} @@ -109,11 +117,13 @@ class Index extends Component { if (company_id) { Taro.setStorageSync('company_id', company_id) } - console.log('page_index:componentDidMount:qwsdk.register1', href) + if (S.getAuthToken()) { + qwsdk.register({ url: href }) + } } this.getConfig() - this.salesman() + // this.salesman() } async salesman() { @@ -136,11 +146,17 @@ class Index extends Component { async getConfig() { let { distributor_id } = this.props.planSelection if (distributor_id != null) { - const result = await api.home.getStatistics({ shop_id: distributor_id, is_app: 1 }) - this.setState({ - realTimeData: result.today_data, - apis: result.apis - }) + try { + const result = await api.home.getStatistics({ shop_id: distributor_id, is_app: 1 }) + this.setState({ + realTimeData: result?.today_data ?? this.state.realTimeData, + apis: result?.apis ?? {}, + loading: false + }) + } catch (e) { + console.log('getConfig', e) + this.setState({ loading: false }) + } } else { Taro.redirectTo({ url: `/pages/planSelection/index` }) } @@ -344,14 +360,14 @@ class Index extends Component { 常用功能 {/* {apis.items == 1 && VERSION_PLATFORM && ( */} - {apis.items == 1 && VERSION_STANDARD && ( + {/* {apis.items == 1 && VERSION_STANDARD && ( navigateTo('/pages/good/list')}> 商品管理 - )} + )} */} {apis.order == 1 && ( @@ -405,21 +421,21 @@ class Index extends Component { 商品查询 )} */} - {VERSION_STANDARD && ( - { - wx.miniProgram.navigateTo({ - url: `/subpages/dianwu/cashier?token=${S.getAuthToken()}&distributor_id=${distributor_id}` - }) - }} - > - - - - 收银台 + {/* {VERSION_STANDARD && ( */} + { + wx.miniProgram.navigateTo({ + url: `/subpages/dianwu/cashier?token=${S.getAuthToken()}&distributor_id=${distributor_id}` + }) + }} + > + + - )} + 收银台 + + {/* )} */} {/* {VERSION_STANDARD && ( = 0) { + const hp = new URLSearchParams(hash.slice(qInHash + 1)) + id = hp.get('company_id') || hp.get('companyId') || '' + } + } + + return id || '' + } catch (e) { + return '' + } +} + +/** 从当前页路由取 company_id(Taro H5 browser 模式常用) */ +export function getCompanyIdFromRouter() { + try { + const router = getCurrentInstance()?.router + const p = router?.params || {} + const id = p.company_id || p.companyId + return id != null && id !== '' ? String(id) : '' + } catch (e) { + return '' + } +} + +/** 解析 JWT payload(仅解码,不校验签名),读 company_id */ +function decodeJwtPayload(token) { + if (!token || typeof token !== 'string') return null + const parts = token.split('.') + if (parts.length < 2) return null + try { + const b64 = parts[1].replace(/-/g, '+').replace(/_/g, '/') + const pad = b64.length % 4 + const padded = pad ? b64 + '='.repeat(4 - pad) : b64 + return JSON.parse(atob(padded)) + } catch (e) { + return null + } +} + +/** 入口 URL 形如 ?token=eyJ...&company_id=38 时,有时 company_id 未进路由参数,可从 JWT claims 取 */ +export function getCompanyIdFromJwtInSearch() { + if (typeof window === 'undefined') return '' + try { + const token = new URLSearchParams(window.location.search || '').get('token') + if (!token) return '' + const payload = decodeJwtPayload(token.trim()) + if (!payload) return '' + const id = payload.company_id ?? payload.companyId + return id != null && id !== '' ? String(id) : '' + } catch (e) { + return '' + } +} + +export function syncCompanyIdFromUrl() { + let id = getCompanyIdFromUrl() + if (!id) { + id = getCompanyIdFromRouter() + } + if (!id) { + id = getCompanyIdFromJwtInSearch() + } + if (id) { + Taro.setStorageSync('company_id', id) + } + return id +} diff --git a/src/utils/index.js b/src/utils/index.js index 85706c8..2f6d6fa 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -84,6 +84,11 @@ export function getCurrentRoute() { export function setWeapp() { const { params: webappParams } = getCurrentInstance().router || { params: {} } console.log('===setWeapp', webappParams) + // 微商城入口 URL 常带 company_id,与 in_shop_wechat 无关也要落盘(接口依赖 Taro storage 的 company_id) + const wid = webappParams.company_id || webappParams.companyId + if (wid != null && wid !== '') { + Taro.setStorageSync('company_id', String(wid)) + } if (webappParams && webappParams.in_shop_wechat) { S.set('WEBAPP', webappParams, true) } @@ -93,10 +98,23 @@ export function cleanWeapp() { S.delete('WEBAPP', true) S.logout() } -/** 判断是否从webapp跳转而来 */ +export function normalizeWebappRecord(raw) { + if (raw == null) return {} + if (typeof raw === 'string') { + try { + return JSON.parse(raw) + } catch (e) { + return {} + } + } + return raw +} + +/** 判断是否从webapp跳转而来(兼容字符串 true 与布尔 true) */ export function isFromWebapp() { - const webappParams = S.get('WEBAPP', true) - return webappParams.in_shop_wechat === 'true' + const webappParams = normalizeWebappRecord(S.get('WEBAPP', true)) + const v = webappParams.in_shop_wechat + return v === true || v === 'true' || v === 1 || v === '1' } export function getThemeStyle() {