台球开关台小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

271 lines
4.1 KiB

/**
* 客户信息相关 API
*/
import Taro from '@tarojs/taro'
import config from '../config'
import { get, post } from '../services/request'
import { CustomerDto, UpdateCustomerDto } from '../types/login'
import { normalizeCustomer } from '../utils/customerNormalize'
import { pickField, toNumber } from '../utils/apiNormalize'
import { userStore } from '../store'
export interface CustomerBalanceResult {
amount: number
}
interface ResponseResult<T = unknown> {
message: string
code: number
success: boolean
data: T
}
/**
* 根据 OpenId 获取客户信息
*/
export const getCustomerByOpenId = async (openId: string) => {
const res = await get<Record<string, unknown>>(
`/customer/byopenid/${encodeURIComponent(openId)}`
)
return { ...res, data: normalizeCustomer(res.data as Record<string, unknown>) }
}
/**
* 查询客户在指定门店的余额
*/
export const getCustomerBalance = async (openId: string, bpSn: string) => {
const res = await get<Record<string, unknown>>('/customer/balance', {
openid: openId,
bpsn: bpSn,
})
const amount = toNumber(pickField(res.data as Record<string, unknown>, 'amount'))
return { ...res, data: { amount } as CustomerBalanceResult }
}
/**
* 刷新用户资料 + 余额(有 bpSn 时)
*/
export const refreshCustomerProfile = async (openId: string, bpSn?: string) => {
const profileRes = await getCustomerByOpenId(openId)
if (profileRes.data) {
userStore.setUserInfoFromWechat(profileRes.data)
}
const storeSn = bpSn || profileRes.data?.bpSn || userStore.userInfo?.bpSn
if (storeSn) {
try {
const balanceRes = await getCustomerBalance(openId, storeSn)
userStore.setBalance(balanceRes.data.amount)
if (userStore.userInfo) {
userStore.setUserInfo({
...userStore.userInfo,
amount: balanceRes.data.amount,
})
}
} catch (e) {
console.warn('刷新余额失败:', e)
}
}
return profileRes
}
/**
* multipart 上传头像(小程序 uploadFile 仅支持 POST)
*/
const uploadCustomerWithAvatar = (
customerId: number,
dto: UpdateCustomerDto
): Promise<ResponseResult<CustomerDto>> => {
return new Promise((resolve, reject) => {
const openId = Taro.getStorageSync('openId') as string
const formData: Record<string, string> = { id: String(customerId) }
if (dto.name) formData.name = dto.name
if (dto.phone) formData.phone = dto.phone
if (dto.birthday) formData.birthday = dto.birthday
Taro.uploadFile({
url: `${config.apiPrefix}/customer/update`,
filePath: dto.avatarFilePath!,
name: 'avatarimage',
formData,
header: openId ? { 'X-OpenId': openId } : {},
success: (res) => {
try {
const body = JSON.parse(res.data) as ResponseResult<Record<string, unknown>>
if (body.success) {
resolve({ ...body, data: normalizeCustomer(body.data) })
} else {
reject(body)
}
} catch (err) {
reject(err)
}
},
fail: reject,
})
})
}
/**
* 更新客户信息(昵称、头像、手机号等)
*/
export const updateCustomer = async (customerId: number, dto: UpdateCustomerDto) => {
if (dto.avatarFilePath) {
return uploadCustomerWithAvatar(customerId, dto)
}
const body: Record<string, string> = { id: String(customerId) }
if (dto.name !== undefined) body.name = dto.name
if (dto.phone !== undefined) body.phone = dto.phone
if (dto.birthday !== undefined) body.birthday = dto.birthday
const res = await post<Record<string, unknown>>('/customer/update', body)
return { ...res, data: normalizeCustomer(res.data) }
}
/**
* @deprecated 新接口使用 multipart avatarFilePath
*/
export const readImageAsBase64 = (filePath: string): Promise<string> => {
return new Promise((resolve, reject) => {
const fs = Taro.getFileSystemManager()
fs.readFile({
filePath,
encoding: 'base64',
success: (res) => resolve(res.data as string),
fail: (err: TaroGeneral.CallbackResult) => reject(err),
})
})
}