/** * 客户信息相关 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 { message: string code: number success: boolean data: T } /** * 根据 OpenId 获取客户信息 */ export const getCustomerByOpenId = async (openId: string) => { const res = await get>( `/customer/byopenid/${encodeURIComponent(openId)}` ) return { ...res, data: normalizeCustomer(res.data as Record) } } /** * 查询客户在指定门店的余额 */ export const getCustomerBalance = async (openId: string, bpSn: string) => { const res = await get>('/customer/balance', { openid: openId, bpsn: bpSn, }) const amount = toNumber(pickField(res.data as Record, '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> => { return new Promise((resolve, reject) => { const openId = Taro.getStorageSync('openId') as string const formData: Record = { 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> 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 = { 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>('/customer/update', body) return { ...res, data: normalizeCustomer(res.data) } } /** * @deprecated 新接口使用 multipart avatarFilePath */ export const readImageAsBase64 = (filePath: string): Promise => { 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), }) }) }