This commit is contained in:
lukaijie
2026-04-01 12:11:29 +08:00
parent d379861349
commit 9a90476cdc
6 changed files with 223 additions and 72 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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 (
<CommonButton
key={buttonName}
key={`${buttonType}-${index}-${buttonName || 'btn'}`}
className={classNames('common-button', buttonClassName)}
plain
text={buttonName}
text={displayText}
onClick={this.handleFooterButtonClick.bind(this, buttonType)}
size='small'
// height={this.buttonHeight()}

View File

@@ -16,12 +16,14 @@ import {
cleanWeapp,
VERSION_PLATFORM,
VERSION_STANDARD,
isIos
isIos,
normalizeWebappRecord
} from '@/utils'
import { SpToast, SpModal } from '@/components'
import { connect } from 'react-redux'
import S from '@/spx'
import { syncCompanyIdFromUrl } from '@/utils/companySync'
import './index.scss'
@connect(({ planSelection }) => ({
@@ -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 {
<View className='title'>常用功能</View>
<View className='list'>
{/* {apis.items == 1 && VERSION_PLATFORM && ( */}
{apis.items == 1 && VERSION_STANDARD && (
{/* {apis.items == 1 && VERSION_STANDARD && (
<View className='item' onClick={() => navigateTo('/pages/good/list')}>
<View>
<Image className='img' src={require('@/assets/imgs/index/good.png')}></Image>
</View>
<View className='subtitle'>商品管理</View>
</View>
)}
)} */}
{apis.order == 1 && (
<View className='item' onClick={this.goOrderPageHandle}>
<View>
@@ -405,21 +421,21 @@ class Index extends Component {
<View className='subtitle'>商品查询</View>
</View>
)} */}
{VERSION_STANDARD && (
<View
className='item'
onClick={() => {
wx.miniProgram.navigateTo({
url: `/subpages/dianwu/cashier?token=${S.getAuthToken()}&distributor_id=${distributor_id}`
})
}}
>
<View className='img_'>
<Image className='img' src={require('@/assets/imgs/icon_cashier.png')}></Image>
</View>
<View className='subtitle'>收银台</View>
{/* {VERSION_STANDARD && ( */}
<View
className='item'
onClick={() => {
wx.miniProgram.navigateTo({
url: `/subpages/dianwu/cashier?token=${S.getAuthToken()}&distributor_id=${distributor_id}`
})
}}
>
<View className='img_'>
<Image className='img' src={require('@/assets/imgs/icon_cashier.png')}></Image>
</View>
)}
<View className='subtitle'>收银台</View>
</View>
{/* )} */}
{/* {VERSION_STANDARD && (
<View
className='item'

88
src/utils/companySync.js Normal file
View File

@@ -0,0 +1,88 @@
/**
* H5 首次进入时,路由参数里的 company_id 可能尚未写入 storage
* 而 componentDidMount 里的 qwsdk.register 会早于 componentDidShow导致 config 等接口缺少 companyId。
*
* 同步来源(按序尝试):
* 1. window.location 的 search / hash 内查询串history / hash 路由)
* 2. Taro getCurrentInstance().router.paramsbrowser 模式下参数常在路由里)
* 3. URL 中 tokenJWTpayload 内的 company_idquery 被改写时兜底)
*/
import Taro, { getCurrentInstance } from '@tarojs/taro'
export function getCompanyIdFromUrl() {
if (typeof window === 'undefined') return ''
try {
const { search, hash } = window.location
const fromSearch = new URLSearchParams(search || '')
let id = fromSearch.get('company_id') || fromSearch.get('companyId') || ''
// hash 形如 #/pages/index?company_id=xx 或 #/?company_id=xx
if (!id && hash) {
const qInHash = hash.indexOf('?')
if (qInHash >= 0) {
const hp = new URLSearchParams(hash.slice(qInHash + 1))
id = hp.get('company_id') || hp.get('companyId') || ''
}
}
return id || ''
} catch (e) {
return ''
}
}
/** 从当前页路由取 company_idTaro 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
}

View File

@@ -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() {