Initial commit
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
const LOCAL_API_BASE = 'http://localhost:9800'
|
||||
const PROD_API_BASE = 'https://app01.min.wooo.host'
|
||||
|
||||
export function apiBase(): string {
|
||||
if (isLocalMiniProgramDev()) return LOCAL_API_BASE
|
||||
return PROD_API_BASE
|
||||
}
|
||||
|
||||
function isLocalMiniProgramDev(): boolean {
|
||||
// #ifdef MP-WEIXIN
|
||||
try {
|
||||
const accountInfo = uni.getAccountInfoSync()
|
||||
const info = accountInfo as any
|
||||
if (info.miniProgram == null) return false
|
||||
const miniProgram = info.miniProgram as any
|
||||
if (miniProgram.envVersion == null) return false
|
||||
const envVersion = miniProgram.envVersion as string
|
||||
return envVersion == 'develop'
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
// #endif
|
||||
return false
|
||||
}
|
||||
|
||||
function errorMessage(data: any): string {
|
||||
if (data == null) return 'request failed'
|
||||
const obj = data as any
|
||||
if (obj.error != null) return obj.error as string
|
||||
return 'request failed'
|
||||
}
|
||||
|
||||
export function request(method: RequestMethod, path: string, data: any | null = null): Promise<any> {
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
uni.request<any>({
|
||||
url: apiBase() + path,
|
||||
method,
|
||||
data,
|
||||
header: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
resolve(res.data)
|
||||
return
|
||||
}
|
||||
reject(new Error(errorMessage(res.data)))
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(new Error(err.errMsg))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function get(path: string): Promise<any> {
|
||||
return request('GET' as RequestMethod, path, null)
|
||||
}
|
||||
|
||||
export function post(path: string, data: any): Promise<any> {
|
||||
return request('POST' as RequestMethod, path, data)
|
||||
}
|
||||
|
||||
export function patch(path: string, data: any): Promise<any> {
|
||||
return request('PATCH' as RequestMethod, path, data)
|
||||
}
|
||||
|
||||
export function mediaUrl(value: string | null): string {
|
||||
if (value == null || value.length == 0) return ''
|
||||
if (value.indexOf('http://') == 0 || value.indexOf('https://') == 0) return value
|
||||
if (value.indexOf('/') == 0) return apiBase() + value
|
||||
return value
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { Category, Day, Project, Slot } from './types.uts'
|
||||
import { formatDate } from './format.uts'
|
||||
import { PROJECT_PLACEHOLDER_IMAGE } from './theme.uts'
|
||||
import { mediaUrl } from './api.uts'
|
||||
|
||||
export function decorateCategories(categories: Category[]): Category[] {
|
||||
const iconMap = ['heart', 'search', 'smile', 'service', 'user']
|
||||
const imageKeys = ['daily', 'clean', 'white', 'breath', 'child']
|
||||
const result: Category[] = []
|
||||
for (let categoryIndex = 0; categoryIndex < categories.length; categoryIndex += 1) {
|
||||
const category = categories[categoryIndex]
|
||||
const rawImageKey = category.image_key == null ? '' : category.image_key as string
|
||||
const imageKey = rawImageKey.length > 0 ? rawImageKey : imageKeys[categoryIndex % imageKeys.length]
|
||||
const projects: Project[] = []
|
||||
for (let projectIndex = 0; projectIndex < category.projects.length; projectIndex += 1) {
|
||||
const project = category.projects[projectIndex]
|
||||
const rawProjectImageKey = project.image_key == null ? '' : project.image_key as string
|
||||
const rawProjectImage = project.image == null ? '' : project.image as string
|
||||
const projectImageKey = rawProjectImageKey.length > 0 ? rawProjectImageKey : imageKey
|
||||
const projectImage = rawProjectImage.length > 0 ? mediaUrl(rawProjectImage) : ''
|
||||
projects.push({
|
||||
id: project.id,
|
||||
category_id: project.category_id,
|
||||
name: project.name,
|
||||
subtitle: project.subtitle,
|
||||
price_text: project.price_text,
|
||||
image: projectImage.length > 0 ? projectImage : PROJECT_PLACEHOLDER_IMAGE,
|
||||
image_key: projectImageKey,
|
||||
sortIndex: projectIndex + 1
|
||||
} as Project)
|
||||
}
|
||||
const rawIcon = category.icon == null ? '' : category.icon as string
|
||||
result.push({
|
||||
id: category.id,
|
||||
name: category.name,
|
||||
icon: rawIcon.length > 0 ? rawIcon : iconMap[categoryIndex % iconMap.length],
|
||||
image_key: imageKey,
|
||||
projects
|
||||
} as Category)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export function fallbackCategories(): Category[] {
|
||||
return [
|
||||
{ id: 'cat_meniscus_injury', name: '半月板损伤', image_key: 'daily', projects: [] } as Category,
|
||||
{ id: 'cat_synovitis', name: '滑膜炎', image_key: 'clean', projects: [] } as Category,
|
||||
{ id: 'cat_knee_arthritis', name: '膝关节炎', image_key: 'white', projects: [] } as Category,
|
||||
{ id: 'cat_lumbar_disc_herniation', name: '腰椎间盘突出', image_key: 'breath', projects: [] } as Category,
|
||||
{ id: 'cat_lumbar_muscle_strain', name: '腰肌劳损', image_key: 'child', projects: [] } as Category,
|
||||
{ id: 'cat_lumbar_spinal_stenosis', name: '腰椎管狭窄', image_key: 'daily', projects: [] } as Category,
|
||||
{ id: 'cat_cervical_spondylosis', name: '颈椎病', image_key: 'clean', projects: [] } as Category,
|
||||
{ id: 'cat_lumbar_spondylosis', name: '腰椎病', image_key: 'white', projects: [] } as Category
|
||||
]
|
||||
}
|
||||
|
||||
export function fallbackDays(projectId: string): Day[] {
|
||||
const starts = ['09:30', '10:30', '13:00', '14:00', '18:00', '19:00', '20:00']
|
||||
const base = new Date()
|
||||
const days: Day[] = []
|
||||
for (let i = 1; i <= 21; i += 1) {
|
||||
const date = new Date(base.getFullYear(), base.getMonth(), base.getDate() + i)
|
||||
const dateText = formatDate(date)
|
||||
const dayId = scheduleDayId(projectId, dateText)
|
||||
const slots: Slot[] = []
|
||||
for (let idx = 0; idx < starts.length; idx += 1) {
|
||||
const start = starts[idx]
|
||||
slots.push({
|
||||
id: slotId(dayId, start),
|
||||
start_time: start,
|
||||
status: 'available'
|
||||
} as Slot)
|
||||
}
|
||||
days.push({
|
||||
date: dateText,
|
||||
status: 'available',
|
||||
slots
|
||||
} as Day)
|
||||
}
|
||||
return days
|
||||
}
|
||||
|
||||
function scheduleDayId(projectId: string, dateText: string): string {
|
||||
return 'day_' + projectId + '_' + compactDate(dateText)
|
||||
}
|
||||
|
||||
function slotId(dayId: string, startTime: string): string {
|
||||
return 'slot_' + dayId + '_' + startTime.replace(':', '')
|
||||
}
|
||||
|
||||
function compactDate(dateText: string): string {
|
||||
return dateText.split('-').join('')
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import { BookingDetail, Day, Slot } from './types.uts'
|
||||
|
||||
export function formatDateText(date: string): string {
|
||||
if (date.length == 0) return ''
|
||||
const parts = date.split('-')
|
||||
if (parts.length < 3) return date
|
||||
return parseInt(parts[1]).toString() + '月' + parseInt(parts[2]).toString() + '日'
|
||||
}
|
||||
|
||||
export function maskPhone(phone: string): string {
|
||||
if (phone.length < 7) return phone
|
||||
return phone.slice(0, 3) + ' **** ' + phone.slice(phone.length - 4)
|
||||
}
|
||||
|
||||
export function pad(value: number): string {
|
||||
if (value < 10) return '0' + value.toString()
|
||||
return value.toString()
|
||||
}
|
||||
|
||||
export function formatMonth(date: Date): string {
|
||||
return date.getFullYear().toString() + '-' + pad(date.getMonth() + 1)
|
||||
}
|
||||
|
||||
export function formatDate(date: Date): string {
|
||||
return date.getFullYear().toString() + '-' + pad(date.getMonth() + 1) + '-' + pad(date.getDate())
|
||||
}
|
||||
|
||||
export function timestampFromDate(dateText: string): number {
|
||||
if (dateText.length == 0) return 0
|
||||
const parts = dateText.split('-')
|
||||
if (parts.length < 3) return 0
|
||||
return new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2])).getTime()
|
||||
}
|
||||
|
||||
export function normalizeSlots(slots: Slot[]): Slot[] {
|
||||
const result: Slot[] = []
|
||||
for (let i = 0; i < slots.length; i += 1) {
|
||||
const slot = slots[i]
|
||||
result.push({
|
||||
id: slot.id,
|
||||
start_time: slot.start_time,
|
||||
status: 'available',
|
||||
statusText: '可约'
|
||||
} as Slot)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export function bookingStatusText(status: string): string {
|
||||
if (status == 'pending') return '待确认'
|
||||
if (status == 'confirmed') return '已预约'
|
||||
if (status == 'cancelled_by_user') return '已取消'
|
||||
if (status == 'cancelled_by_operator') return '已取消'
|
||||
if (status == 'completed') return '已完成'
|
||||
if (status == 'expired') return '已失效'
|
||||
return status
|
||||
}
|
||||
|
||||
export function normalizeBookings(bookings: BookingDetail[]): BookingDetail[] {
|
||||
const result: BookingDetail[] = []
|
||||
for (let i = 0; i < bookings.length; i += 1) {
|
||||
const item = bookings[i]
|
||||
const status = item.booking.status
|
||||
result.push({
|
||||
booking: item.booking,
|
||||
project: item.project,
|
||||
day: item.day,
|
||||
slot: item.slot,
|
||||
key: item.booking.id,
|
||||
dateText: formatDateText(item.day.date),
|
||||
statusText: bookingStatusText(status),
|
||||
canCancel: status == 'pending' || status == 'confirmed'
|
||||
} as BookingDetail)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export function emptyDay(): Day {
|
||||
return { date: '', status: '', slots: [] } as Day
|
||||
}
|
||||
|
||||
export function emptySlot(): Slot {
|
||||
return { id: '', start_time: '', status: '' } as Slot
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import { BookingDetail, Day, Draft, Project, Slot } from './types.uts'
|
||||
|
||||
const DRAFT_KEY = 'sf_booking_draft'
|
||||
const LAST_BOOKING_KEY = 'sf_last_booking'
|
||||
|
||||
export function emptyDraft(): Draft {
|
||||
return {
|
||||
project: null,
|
||||
day: null,
|
||||
date: '',
|
||||
slot: null,
|
||||
phone: ''
|
||||
} as Draft
|
||||
}
|
||||
|
||||
export function getDraft(): Draft {
|
||||
const raw = uni.getStorageSync(DRAFT_KEY)
|
||||
if (raw == null || raw == '') return emptyDraft()
|
||||
const draft = raw as Draft
|
||||
if (draft.phone == null) draft.phone = ''
|
||||
if (draft.date == null) draft.date = ''
|
||||
return draft
|
||||
}
|
||||
|
||||
export function saveDraft(draft: Draft): Draft {
|
||||
uni.setStorageSync(DRAFT_KEY, draft)
|
||||
return draft
|
||||
}
|
||||
|
||||
export function clearDraft(): void {
|
||||
const phone = getDraft().phone
|
||||
uni.removeStorageSync(DRAFT_KEY)
|
||||
if (phone.length > 0) {
|
||||
saveDraft({
|
||||
project: null,
|
||||
day: null,
|
||||
date: '',
|
||||
slot: null,
|
||||
phone
|
||||
} as Draft)
|
||||
}
|
||||
}
|
||||
|
||||
export function setProject(project: Project): Draft {
|
||||
const draft = getDraft()
|
||||
const next = {
|
||||
project: {
|
||||
id: project.id,
|
||||
category_id: project.category_id,
|
||||
name: project.name,
|
||||
subtitle: project.subtitle,
|
||||
price_text: project.price_text,
|
||||
image: project.image,
|
||||
image_key: project.image_key,
|
||||
sortIndex: project.sortIndex
|
||||
} as Project,
|
||||
day: null,
|
||||
date: '',
|
||||
slot: null,
|
||||
phone: draft.phone
|
||||
} as Draft
|
||||
return saveDraft(next)
|
||||
}
|
||||
|
||||
export function setSchedule(day: Day, slot: Slot): Draft {
|
||||
const draft = getDraft()
|
||||
const nextDay = {
|
||||
date: day.date,
|
||||
status: day.status,
|
||||
slots: []
|
||||
} as Day
|
||||
const nextSlot = {
|
||||
id: slot.id,
|
||||
start_time: slot.start_time,
|
||||
status: slot.status
|
||||
} as Slot
|
||||
const next = {
|
||||
project: draft.project,
|
||||
day: nextDay,
|
||||
date: nextDay.date,
|
||||
slot: nextSlot,
|
||||
phone: draft.phone
|
||||
} as Draft
|
||||
return saveDraft(next)
|
||||
}
|
||||
|
||||
export function setPhone(phone: string): Draft {
|
||||
const draft = getDraft()
|
||||
draft.phone = phone
|
||||
return saveDraft(draft)
|
||||
}
|
||||
|
||||
export function setLastBooking(detail: BookingDetail): void {
|
||||
uni.setStorageSync(LAST_BOOKING_KEY, detail)
|
||||
}
|
||||
|
||||
export function getLastBooking(): BookingDetail | null {
|
||||
const raw = uni.getStorageSync(LAST_BOOKING_KEY)
|
||||
if (raw == null || raw == '') return null
|
||||
return raw as BookingDetail
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { QuickAction } from './types.uts'
|
||||
|
||||
export const PROJECT_PLACEHOLDER_IMAGE = '/static/images/project-placeholder.svg'
|
||||
|
||||
export function quickActions(): QuickAction[] {
|
||||
return [
|
||||
{ key: 'booking', icon: '/static/icons/ico_book.svg', title: '预约时间', subtitle: '选项目 约时间' },
|
||||
{ key: 'orders', icon: '/static/icons/ico_orders.svg', title: '我的预约', subtitle: '查看预约记录' },
|
||||
{ key: 'price-query', icon: '/static/icons/ico_book.svg', title: '价格查询', subtitle: '查看项目参考价' }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
export type User = {
|
||||
id: string
|
||||
openid: string
|
||||
phone: any | null
|
||||
}
|
||||
|
||||
export type Project = {
|
||||
id: string
|
||||
category_id: string
|
||||
name: string
|
||||
subtitle: string
|
||||
price_text: string
|
||||
image?: string
|
||||
image_key?: string
|
||||
sortIndex?: number
|
||||
}
|
||||
|
||||
export type Category = {
|
||||
id: string
|
||||
name: string
|
||||
icon?: string
|
||||
image_key?: string
|
||||
projects: Project[]
|
||||
}
|
||||
|
||||
export type Day = {
|
||||
date: string
|
||||
status?: string
|
||||
slots: Slot[]
|
||||
}
|
||||
|
||||
export type Slot = {
|
||||
id: string
|
||||
start_time: string
|
||||
status: string
|
||||
statusText?: string
|
||||
}
|
||||
|
||||
export type Draft = {
|
||||
project: Project | null
|
||||
day: Day | null
|
||||
date: string
|
||||
slot: Slot | null
|
||||
phone: string
|
||||
}
|
||||
|
||||
export type Booking = {
|
||||
id: string
|
||||
status: string
|
||||
}
|
||||
|
||||
export type BookingDetail = {
|
||||
booking: Booking
|
||||
project: Project
|
||||
day: Day
|
||||
slot: Slot
|
||||
key?: string
|
||||
dateText?: string
|
||||
statusText?: string
|
||||
canCancel?: boolean
|
||||
}
|
||||
|
||||
export type QuickAction = {
|
||||
key: string
|
||||
title: string
|
||||
subtitle: string
|
||||
icon: string
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
import { apiBase, post } from './api.uts'
|
||||
import { User } from './types.uts'
|
||||
|
||||
const USER_KEY = 'sf_user'
|
||||
|
||||
export function demoUser(): User {
|
||||
const openid = generateFakeOpenID()
|
||||
return {
|
||||
id: openid,
|
||||
openid,
|
||||
phone: null
|
||||
} as User
|
||||
}
|
||||
|
||||
export function currentUser(): User | null {
|
||||
const raw = uni.getStorageSync(USER_KEY)
|
||||
if (raw == null || raw == '') return null
|
||||
return raw as User
|
||||
}
|
||||
|
||||
export function phoneFromUser(user: any | null): string {
|
||||
if (user == null) return ''
|
||||
const phone = (user as any).phone
|
||||
if (phone == null) return ''
|
||||
if (typeof phone == 'string') return phone as string
|
||||
const obj = phone as any
|
||||
if (obj.Valid == true || obj.valid == true) {
|
||||
if (obj.String != null) return obj.String as string
|
||||
if (obj.string != null) return obj.string as string
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
export function openidFromUser(user: any | null): string {
|
||||
if (user == null) return fallbackOpenID()
|
||||
const obj = user as any
|
||||
if (obj.openid != null) {
|
||||
const openid = obj.openid as string
|
||||
if (openid.length > 0) return openid
|
||||
}
|
||||
if (obj.Openid != null) {
|
||||
const openid = obj.Openid as string
|
||||
if (openid.length > 0) return openid
|
||||
}
|
||||
return fallbackOpenID()
|
||||
}
|
||||
|
||||
export function setUser(user: User): void {
|
||||
uni.setStorageSync(USER_KEY, user)
|
||||
}
|
||||
|
||||
export function bindPhoneFromEvent(event: UniEvent): Promise<any> {
|
||||
const detail = (event as any).detail as any
|
||||
const errMsg = detail != null && detail.errMsg != null ? detail.errMsg as string : ''
|
||||
console.log('[phone-auth] getPhoneNumber event', phoneAuthDetailLog(detail))
|
||||
if (errMsg.indexOf('ok') < 0) {
|
||||
console.log('[phone-auth] getPhoneNumber rejected', { errMsg })
|
||||
return Promise.reject(new Error('手机号授权未完成'))
|
||||
}
|
||||
const user = currentUser()
|
||||
const phoneCode = detail != null && detail.code != null ? detail.code as string : ''
|
||||
if (phoneCode.length == 0) {
|
||||
console.log('[phone-auth] getPhoneNumber missing code', phoneAuthDetailLog(detail))
|
||||
return Promise.reject(new Error('没有拿到手机号授权 code'))
|
||||
}
|
||||
const openid = openidFromUser(user)
|
||||
console.log('[phone-auth] backend bind start', {
|
||||
openid: maskIdentifier(openid),
|
||||
hasStoredPhone: phoneFromUser(user).length > 0,
|
||||
phoneCodeLength: phoneCode.length,
|
||||
envVersion: miniProgramEnvVersion(),
|
||||
apiBase: apiBase()
|
||||
})
|
||||
return post('/api/auth/wechat/phone', {
|
||||
openid,
|
||||
phoneCode
|
||||
}).then((res) => {
|
||||
const nextUser = (res as any).user as User
|
||||
const phone = phoneFromUser(nextUser)
|
||||
if (phone.length == 0) {
|
||||
console.log('[phone-auth] backend bind empty phone', {
|
||||
openid: maskIdentifier(openidFromUser(nextUser))
|
||||
})
|
||||
return Promise.reject(new Error('后端未返回已绑定手机号'))
|
||||
}
|
||||
setUser(nextUser)
|
||||
console.log('[phone-auth] backend bind success', {
|
||||
openid: maskIdentifier(openidFromUser(nextUser)),
|
||||
phone: maskPhoneForLog(phone)
|
||||
})
|
||||
return {
|
||||
user: nextUser,
|
||||
phone
|
||||
}
|
||||
}).catch((err) => {
|
||||
const message = err != null && (err as any).message != null ? (err as any).message as string : '手机号绑定失败'
|
||||
console.log('[phone-auth] backend bind failed', {
|
||||
openid: maskIdentifier(openid),
|
||||
message
|
||||
})
|
||||
return Promise.reject(err)
|
||||
})
|
||||
}
|
||||
|
||||
function phoneAuthDetailLog(detail: any | null): any {
|
||||
if (detail == null) {
|
||||
return {
|
||||
errMsg: '',
|
||||
hasCode: false,
|
||||
codeLength: 0,
|
||||
hasEncryptedData: false,
|
||||
hasIv: false,
|
||||
hasCloudID: false
|
||||
}
|
||||
}
|
||||
const code = detail.code != null ? detail.code as string : ''
|
||||
const encryptedData = detail.encryptedData != null ? detail.encryptedData as string : ''
|
||||
const iv = detail.iv != null ? detail.iv as string : ''
|
||||
const cloudID = detail.cloudID != null ? detail.cloudID as string : ''
|
||||
return {
|
||||
errMsg: detail.errMsg != null ? detail.errMsg as string : '',
|
||||
hasCode: code.length > 0,
|
||||
codeLength: code.length,
|
||||
hasEncryptedData: encryptedData.length > 0,
|
||||
hasIv: iv.length > 0,
|
||||
hasCloudID: cloudID.length > 0
|
||||
}
|
||||
}
|
||||
|
||||
function maskIdentifier(value: string): string {
|
||||
if (value.length <= 8) return value
|
||||
return value.slice(0, 4) + '...' + value.slice(value.length - 4)
|
||||
}
|
||||
|
||||
function maskPhoneForLog(phone: string): string {
|
||||
if (phone.length < 7) return phone
|
||||
return phone.slice(0, 3) + '****' + phone.slice(phone.length - 4)
|
||||
}
|
||||
|
||||
function fallbackOpenID(): string {
|
||||
const stored = currentUser()
|
||||
if (stored != null) {
|
||||
const obj = stored as any
|
||||
if (obj.openid != null) {
|
||||
const openid = obj.openid as string
|
||||
if (openid.length > 0) return openid
|
||||
}
|
||||
if (obj.Openid != null) {
|
||||
const openid = obj.Openid as string
|
||||
if (openid.length > 0) return openid
|
||||
}
|
||||
}
|
||||
const user = demoUser()
|
||||
setUser(user)
|
||||
return user.openid
|
||||
}
|
||||
|
||||
function generateFakeOpenID(): string {
|
||||
return 'fake_user_' + compactDateTime(new Date()) + '_' + randomFourDigits()
|
||||
}
|
||||
|
||||
function compactDateTime(date: Date): string {
|
||||
return date.getFullYear().toString()
|
||||
+ padNumber(date.getMonth() + 1, 2)
|
||||
+ padNumber(date.getDate(), 2)
|
||||
+ padNumber(date.getHours(), 2)
|
||||
+ padNumber(date.getMinutes(), 2)
|
||||
+ padNumber(date.getSeconds(), 2)
|
||||
}
|
||||
|
||||
function randomFourDigits(): string {
|
||||
return padNumber(Math.floor(Math.random() * 10000), 4)
|
||||
}
|
||||
|
||||
function padNumber(value: number, size: number): string {
|
||||
let text = value.toString()
|
||||
while (text.length < size) {
|
||||
text = '0' + text
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
function miniProgramEnvVersion(): string {
|
||||
// #ifdef MP-WEIXIN
|
||||
try {
|
||||
const accountInfo = uni.getAccountInfoSync()
|
||||
const info = accountInfo as any
|
||||
if (info.miniProgram == null) return ''
|
||||
const miniProgram = info.miniProgram as any
|
||||
if (miniProgram.envVersion == null) return ''
|
||||
return miniProgram.envVersion as string
|
||||
} catch (e) {
|
||||
return ''
|
||||
}
|
||||
// #endif
|
||||
return ''
|
||||
}
|
||||
Reference in New Issue
Block a user