feat(auth): refactor mini program login flows

This commit is contained in:
lzh
2026-03-15 16:14:58 +08:00
parent dcc5c38e96
commit 95519045b9
9 changed files with 548 additions and 248 deletions

3
env/.env.production vendored
View File

@@ -8,3 +8,6 @@ VITE_SHOW_SOURCEMAP = false
# 后台请求地址
VITE_SERVER_BASEURL = 'https://viewshanghai.com/admin-api'
VITE_UPLOAD_BASEURL = 'https://viewshanghai.com/admin-api'
# 验证码的开关
VITE_APP_CAPTCHA_ENABLE=true

View File

@@ -41,6 +41,7 @@ export interface AuthRegisterReqVO {
export interface AuthSmsLoginReqVO {
mobile: string
code: string
captchaVerification?: string
}
/** 发送短信验证码 Request VO */
@@ -122,27 +123,43 @@ export function logout() {
return http.post<void>('/system/auth/logout')
}
// TODO @芋艿:三方登录
/**
* 获取微信登录凭证
* @returns Promise 包含微信登录凭证(code)
*/
export function getWxCode() {
return new Promise<UniApp.LoginRes>((resolve, reject) => {
/** 微信小程序一键登录 Request VO */
export interface AuthWeixinMiniAppLoginReqVO {
phoneCode: string
loginCode: string
state: string
}
/** 社交快捷登录 Request VO */
export interface AuthSocialLoginReqVO {
type: number
code: string
state: string
}
/** 获取微信小程序 login code */
export function getWxLoginCode(): Promise<string> {
return new Promise((resolve, reject) => {
uni.login({
provider: 'weixin',
success: res => resolve(res),
fail: err => reject(new Error(err)),
success: (res) => {
if (!res.code) {
reject(new Error('未获取到有效的微信登录凭证,请重试'))
return
}
resolve(res.code)
},
fail: err => reject(new Error(err.errMsg)),
})
})
}
// TODO @芋艿:三方登录
/**
* 微信登录
* @param params 微信登录参数包含code
* @returns Promise 包含登录结果
*/
export function wxLogin(data: { code: string }) {
return http.post<IAuthLoginRes>('/auth/wxLogin', data)
/** 社交快捷登录(已绑定用户) */
export function socialLogin(data: AuthSocialLoginReqVO) {
return http.post<IAuthLoginRes>('/system/auth/social-login', data)
}
/** 微信小程序一键登录(手机号匹配) */
export function weixinMiniAppLogin(data: AuthWeixinMiniAppLoginReqVO) {
return http.post<IAuthLoginRes>('/system/auth/weixin-mini-app-login', data)
}

View File

@@ -0,0 +1,124 @@
<template>
<view class="sms-login-panel">
<AuthInput
v-model="form.mobile"
placeholder="请输入手机号"
icon="phone"
type="number"
:maxlength="11"
/>
<CodeInput
v-model="form.code"
:mobile="form.mobile"
:scene="21"
:before-send="validateTenant"
/>
<view v-if="captchaEnabled">
<Verify
ref="verifyRef"
:captcha-type="captchaType"
explain="向右滑动完成验证"
:img-size="{ width: '300px', height: '150px' }"
mode="pop"
@success="handleVerifySuccess"
/>
</view>
<view class="auth-btn-wrapper" style="margin-top: 40rpx">
<wd-button block :loading="loading" custom-class="auth-btn" @click="handleSubmit">
</wd-button>
</view>
</view>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { useTokenStore } from '@/store/token'
import { redirectAfterLogin } from '@/utils'
import { isMobile } from '@/utils/validator'
import AuthInput from './auth-input.vue'
import CodeInput from './code-input.vue'
import Verify from './verifition/verify.vue'
defineOptions({
name: 'SmsLoginPanel',
})
const props = defineProps<{
agreed: boolean
redirectUrl?: string
validateTenant: () => boolean
}>()
const toast = useToast()
const loading = ref(false)
const verifyRef = ref()
const captchaEnabled = import.meta.env.VITE_APP_CAPTCHA_ENABLE === 'true'
const captchaType = ref('blockPuzzle')
const form = reactive({
mobile: '',
code: '',
captchaVerification: '',
})
async function handleSubmit() {
if (!props.agreed) {
toast.warning('请先阅读并同意用户协议和隐私政策')
return
}
if (!props.validateTenant()) {
return
}
if (!form.mobile) {
toast.warning('请输入手机号')
return
}
if (!isMobile(form.mobile)) {
toast.warning('请输入正确的手机号')
return
}
if (!form.code) {
toast.warning('请输入验证码')
return
}
if (!captchaEnabled) {
await handleVerifySuccess({})
return
}
verifyRef.value?.show()
}
async function handleVerifySuccess(params: { captchaVerification?: string }) {
loading.value = true
try {
form.captchaVerification = params?.captchaVerification || ''
const tokenStore = useTokenStore()
await tokenStore.login({ type: 'sms', ...form })
redirectAfterLogin(props.redirectUrl)
} finally {
loading.value = false
}
}
</script>
<style lang="scss" scoped>
@import '../styles/auth.scss';
</style>
<style lang="scss">
.sms-login-panel .auth-btn {
background: linear-gradient(to right, #fbbf24, #f97316) !important;
border: none !important;
border-radius: 24rpx !important;
height: 100rpx !important;
font-size: 34rpx !important;
font-weight: 700 !important;
letter-spacing: 8rpx !important;
box-shadow: 0 12rpx 40rpx rgba(249, 115, 22, 0.25) !important;
}
</style>

View File

@@ -0,0 +1,139 @@
<template>
<view class="username-login-panel">
<AuthInput
v-model="form.username"
placeholder="请输入用户名"
icon="user"
/>
<AuthInput
v-model="form.password"
placeholder="请输入密码"
icon="lock-on"
type="password"
/>
<view v-if="captchaEnabled">
<Verify
ref="verifyRef"
:captcha-type="captchaType"
explain="向右滑动完成验证"
:img-size="{ width: '300px', height: '150px' }"
mode="pop"
@success="handleVerifySuccess"
/>
</view>
<view class="auth-links">
<text class="auth-link" @click="$emit('forget-password')">
忘记密码
</text>
</view>
<view class="auth-btn-wrapper">
<wd-button block :loading="loading" custom-class="auth-btn" @click="handleSubmit">
</wd-button>
</view>
</view>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { useTokenStore } from '@/store/token'
import { redirectAfterLogin } from '@/utils'
import AuthInput from './auth-input.vue'
import Verify from './verifition/verify.vue'
defineOptions({
name: 'UsernameLoginPanel',
})
const props = defineProps<{
agreed: boolean
redirectUrl?: string
validateTenant: () => boolean
}>()
defineEmits<{
'forget-password': []
}>()
const toast = useToast()
const loading = ref(false)
const verifyRef = ref()
const captchaEnabled = import.meta.env.VITE_APP_CAPTCHA_ENABLE === 'true'
const captchaType = ref('blockPuzzle')
const form = reactive({
username: import.meta.env.VITE_APP_DEFAULT_LOGIN_USERNAME || '',
password: import.meta.env.VITE_APP_DEFAULT_LOGIN_PASSWORD || '',
captchaVerification: '',
})
async function handleSubmit() {
if (!props.agreed) {
toast.warning('请先阅读并同意用户协议和隐私政策')
return
}
if (!props.validateTenant()) {
return
}
if (!form.username) {
toast.warning('请输入用户名')
return
}
if (!form.password) {
toast.warning('请输入密码')
return
}
if (!captchaEnabled) {
await handleVerifySuccess({})
return
}
verifyRef.value?.show()
}
async function handleVerifySuccess(params: { captchaVerification?: string }) {
loading.value = true
try {
form.captchaVerification = params?.captchaVerification || ''
const tokenStore = useTokenStore()
await tokenStore.login({ type: 'username', ...form })
redirectAfterLogin(props.redirectUrl)
} finally {
loading.value = false
}
}
</script>
<style lang="scss" scoped>
@import '../styles/auth.scss';
.auth-links {
display: flex;
justify-content: flex-end;
align-items: center;
margin-bottom: 32rpx;
}
.auth-link {
font-size: 26rpx;
color: #f97316;
font-weight: 600;
}
</style>
<style lang="scss">
.username-login-panel .auth-btn {
background: linear-gradient(to right, #fbbf24, #f97316) !important;
border: none !important;
border-radius: 24rpx !important;
height: 100rpx !important;
font-size: 34rpx !important;
font-weight: 700 !important;
letter-spacing: 8rpx !important;
box-shadow: 0 12rpx 40rpx rgba(249, 115, 22, 0.25) !important;
}
</style>

View File

@@ -0,0 +1,140 @@
<template>
<view>
<view v-if="!needPhoneAuth" class="auth-btn-wrapper" style="margin-top: 40rpx">
<view class="wechat-btn" @click="handleWechatLogin">
<wd-icon name="chat" size="22px" color="#07c160" />
<text class="wechat-btn__text">微信一键登录</text>
</view>
</view>
<view v-else class="wx-phone-auth">
<view class="wx-phone-auth__tip">
<text>检测到当前账号未绑定手机号请先完成微信手机号授权</text>
</view>
<view class="auth-btn-wrapper" style="margin-top: 20rpx">
<button
class="wx-phone-btn"
open-type="getPhoneNumber"
:loading="loading"
@getphonenumber="handleGetPhoneNumber"
>
微信手机号一键登录
</button>
</view>
<view class="auth-btn-wrapper" style="margin-top: 16rpx">
<wd-button block type="text" @click="needPhoneAuth = false">
返回重试
</wd-button>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { getWxLoginCode } from '@/api/login'
import { useTokenStore } from '@/store/token'
import { redirectAfterLogin } from '@/utils'
defineOptions({
name: 'WechatLoginPanel',
})
const props = defineProps<{
agreed: boolean
redirectUrl?: string
validateTenant: () => boolean
}>()
const toast = useToast()
const loading = ref(false)
const needPhoneAuth = ref(false)
async function handleWechatLogin() {
if (!props.agreed) {
toast.warning('请先阅读并同意用户协议和隐私政策')
return
}
if (!props.validateTenant()) {
return
}
loading.value = true
try {
const code = await getWxLoginCode()
const state = Date.now().toString()
const tokenStore = useTokenStore()
await tokenStore.socialLogin({ type: 34, code, state })
redirectAfterLogin(props.redirectUrl)
} catch (error: any) {
if (error?.code === 1002000005) {
needPhoneAuth.value = true
}
} finally {
loading.value = false
}
}
async function handleGetPhoneNumber(e: any) {
if (e.detail.errMsg !== 'getPhoneNumber:ok') {
toast.warning('未获取到手机号授权,无法继续登录')
return
}
loading.value = true
try {
const phoneCode = e.detail.code
const loginCode = await getWxLoginCode()
const state = Date.now().toString()
const tokenStore = useTokenStore()
await tokenStore.weixinMiniAppLogin({ phoneCode, loginCode, state })
redirectAfterLogin(props.redirectUrl)
} finally {
loading.value = false
}
}
</script>
<style lang="scss" scoped>
@import '../styles/auth.scss';
.wechat-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 20rpx;
background: #d6f5e0;
border: 1rpx solid #b8edca;
border-radius: 24rpx;
height: 100rpx;
width: 100%;
&__text {
font-size: 30rpx;
color: #07c160;
font-weight: 600;
}
}
.wx-phone-auth__tip {
text-align: center;
font-size: 26rpx;
color: #9c9b99;
margin-top: 40rpx;
}
.wx-phone-btn {
width: 100%;
height: 100rpx;
line-height: 100rpx;
background: linear-gradient(to right, #07c160, #06ad56);
color: #fff;
border: none;
border-radius: 24rpx;
font-size: 34rpx;
font-weight: 700;
letter-spacing: 4rpx;
box-shadow: 0 12rpx 40rpx rgba(7, 193, 96, 0.25);
}
</style>

View File

@@ -3,116 +3,50 @@
<Header />
<view class="form-container">
<!-- Tab 切换器 -->
<view class="tab-switcher">
<view
class="tab-item" :class="[activeTab === 'sms' ? 'tab-item--active' : '']"
@click="activeTab = 'sms'"
v-for="tab in tabs"
:key="tab.value"
class="tab-item"
:class="[activeTab === tab.value ? 'tab-item--active' : '']"
@click="activeTab = tab.value"
>
快捷登录
</view>
<view
class="tab-item" :class="[activeTab === 'username' ? 'tab-item--active' : '']"
@click="activeTab = 'username'"
>
账号登录
{{ tab.label }}
</view>
</view>
<!-- 共享租户选择器 -->
<TenantPicker ref="tenantPickerRef" />
<!-- 快捷登录面板 -->
<view v-show="activeTab === 'sms'">
<AuthInput
v-model="smsForm.mobile"
placeholder="请输入手机号"
icon="phone"
type="number"
:maxlength="11"
/>
<CodeInput
v-model="smsForm.code"
:mobile="smsForm.mobile"
:scene="21"
:before-send="validateBeforeSend"
/>
<view v-if="captchaEnabled">
<Verify
ref="smsVerifyRef"
:captcha-type="captchaType"
explain="向右滑动完成验证"
:img-size="{ width: '300px', height: '150px' }"
mode="pop"
@success="smsVerifySuccess"
<view v-if="isMpWeixin && activeTab === 'wechat'" class="login-panel login-panel--wechat">
<WechatLoginPanel
:agreed="agreed"
:redirect-url="redirectUrl"
:validate-tenant="validateTenant"
/>
</view>
<view class="auth-btn-wrapper" style="margin-top: 40rpx">
<wd-button block :loading="smsLoading" custom-class="auth-btn" @click="handleSmsLogin">
</wd-button>
</view>
<!-- "或"分割线 -->
<view class="social-divider">
<view class="social-divider__line" />
<text class="social-divider__text"></text>
<view class="social-divider__line" />
</view>
<!-- 微信授权登录按钮 -->
<view class="wechat-btn" @click="handleWechatLogin">
<wd-icon name="chat" size="22px" color="#07c160" />
<text class="wechat-btn__text">微信授权登录</text>
</view>
</view>
<!-- 账号登录面板 -->
<view v-show="activeTab === 'username'">
<AuthInput
v-model="usernameForm.username"
placeholder="请输入用户名"
icon="user"
/>
<AuthInput
v-model="usernameForm.password"
placeholder="请输入密码"
icon="lock-on"
type="password"
/>
<view v-if="captchaEnabled">
<Verify
ref="usernameVerifyRef"
:captcha-type="captchaType"
explain="向右滑动完成验证"
:img-size="{ width: '300px', height: '150px' }"
mode="pop"
@success="usernameVerifySuccess"
<view v-if="!isMpWeixin && activeTab === 'sms'" class="login-panel login-panel--sms">
<SmsLoginPanel
:agreed="agreed"
:redirect-url="redirectUrl"
:validate-tenant="validateTenant"
/>
</view>
<view class="auth-links">
<text class="auth-link" @click="goToForgetPassword">
忘记密码
</text>
<view v-if="activeTab === 'username'" class="login-panel login-panel--username">
<UsernameLoginPanel
:agreed="agreed"
:redirect-url="redirectUrl"
:validate-tenant="validateTenant"
@forget-password="goToForgetPassword"
/>
</view>
<view class="auth-btn-wrapper">
<wd-button block :loading="usernameLoading" custom-class="auth-btn" @click="handleUsernameLogin">
</wd-button>
</view>
</view>
<!-- 底部协议区 -->
<view class="agreement">
<view class="agreement__checkbox" :class="[agreed ? 'agreement__checkbox--checked' : '']" @click="agreed = !agreed">
<wd-icon v-if="agreed" name="check-bold" size="18rpx" color="#fff" />
</view>
<text class="agreement__text">登录即表同意</text>
<text class="agreement__text">登录即表同意</text>
<text class="agreement__link" @click="goToAgreement">用户协议</text>
<text class="agreement__text"></text>
<text class="agreement__link" @click="goToPrivacy">隐私政策</text>
@@ -122,17 +56,15 @@
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { isMpWeixin } from '@uni-helper/uni-env'
import { computed, ref } from 'vue'
import { FORGET_PASSWORD_PAGE } from '@/router/config'
import { useTokenStore } from '@/store/token'
import { ensureDecodeURIComponent, redirectAfterLogin } from '@/utils'
import { isMobile } from '@/utils/validator'
import AuthInput from './components/auth-input.vue'
import CodeInput from './components/code-input.vue'
import { ensureDecodeURIComponent } from '@/utils'
import Header from './components/header.vue'
import SmsLoginPanel from './components/sms-login-panel.vue'
import TenantPicker from './components/tenant-picker.vue'
import Verify from './components/verifition/verify.vue'
import UsernameLoginPanel from './components/username-login-panel.vue'
import WechatLoginPanel from './components/wechat-login-panel.vue'
defineOptions({
name: 'LoginPage',
@@ -144,32 +76,24 @@ definePage({
},
})
const toast = useToast()
type LoginTab = 'wechat' | 'sms' | 'username'
const redirectUrl = ref<string>()
const tenantPickerRef = ref<InstanceType<typeof TenantPicker>>()
const captchaEnabled = import.meta.env.VITE_APP_CAPTCHA_ENABLE === 'true'
const captchaType = ref('blockPuzzle')
const agreed = ref(false)
const activeTab = ref<LoginTab>(isMpWeixin ? 'wechat' : 'sms')
// Tab 状态
const activeTab = ref<'sms' | 'username'>('sms')
// === 快捷登录(短信验证码) ===
const smsLoading = ref(false)
const smsVerifyRef = ref()
const smsForm = reactive({
mobile: '',
code: '',
captchaVerification: '',
})
// === 账号登录 ===
const usernameLoading = ref(false)
const usernameVerifyRef = ref()
const usernameForm = reactive({
username: import.meta.env.VITE_APP_DEFAULT_LOGIN_USERNAME || '',
password: import.meta.env.VITE_APP_DEFAULT_LOGIN_PASSWORD || '',
captchaVerification: '',
const tabs = computed(() => {
if (isMpWeixin) {
return [
{ label: '微信登录', value: 'wechat' as const },
{ label: '账号登录', value: 'username' as const },
]
}
return [
{ label: '快捷登录', value: 'sms' as const },
{ label: '账号登录', value: 'username' as const },
]
})
onLoad((options) => {
@@ -178,85 +102,14 @@ onLoad((options) => {
}
})
function validateBeforeSend(): boolean {
function validateTenant(): boolean {
return tenantPickerRef.value?.validate() ?? false
}
// --- 快捷登录逻辑 ---
async function handleSmsLogin() {
if (!tenantPickerRef.value?.validate())
return
if (!smsForm.mobile) {
toast.warning('请输入手机号')
return
}
if (!isMobile(smsForm.mobile)) {
toast.warning('请输入正确的手机号')
return
}
if (!smsForm.code) {
toast.warning('请输入验证码')
return
}
if (!captchaEnabled) {
await smsVerifySuccess({})
} else {
smsVerifyRef.value.show()
}
}
async function smsVerifySuccess(params: any) {
smsLoading.value = true
try {
const tokenStore = useTokenStore()
smsForm.captchaVerification = params.captchaVerification
await tokenStore.login({ type: 'sms', ...smsForm })
redirectAfterLogin(redirectUrl.value)
} finally {
smsLoading.value = false
}
}
// --- 账号登录逻辑 ---
async function handleUsernameLogin() {
if (!tenantPickerRef.value?.validate())
return
if (!usernameForm.username) {
toast.warning('请输入用户名')
return
}
if (!usernameForm.password) {
toast.warning('请输入密码')
return
}
if (!captchaEnabled) {
await usernameVerifySuccess({})
} else {
usernameVerifyRef.value.show()
}
}
async function usernameVerifySuccess(params: any) {
usernameLoading.value = true
try {
const tokenStore = useTokenStore()
usernameForm.captchaVerification = params.captchaVerification
await tokenStore.login({ type: 'username', ...usernameForm })
redirectAfterLogin(redirectUrl.value)
} finally {
usernameLoading.value = false
}
}
// --- 导航 ---
function goToForgetPassword() {
uni.navigateTo({ url: FORGET_PASSWORD_PAGE })
}
function handleWechatLogin() {
toast.info('微信登录功能开发中')
}
function goToAgreement() {
uni.navigateTo({ url: '/pages-core/user/settings/agreement/index' })
}
@@ -268,4 +121,18 @@ function goToPrivacy() {
<style lang="scss" scoped>
@import './styles/auth.scss';
.login-panel--sms,
.login-panel--username {
:deep(.auth-btn) {
background: linear-gradient(to right, #fbbf24, #f97316) !important;
border: none !important;
border-radius: 24rpx !important;
height: 100rpx !important;
font-size: 34rpx !important;
font-weight: 700 !important;
letter-spacing: 8rpx !important;
box-shadow: 0 12rpx 40rpx rgba(249, 115, 22, 0.25) !important;
}
}
</style>

View File

@@ -211,6 +211,31 @@
}
}
// 微信手机号授权区域
.wx-phone-auth {
&__tip {
text-align: center;
font-size: 26rpx;
color: #9c9b99;
margin-top: 40rpx;
}
}
// 微信手机号授权按钮(原生 button
.wx-phone-btn {
width: 100%;
height: 100rpx;
line-height: 100rpx;
background: linear-gradient(to right, #07c160, #06ad56);
color: #fff;
border: none;
border-radius: 24rpx;
font-size: 34rpx;
font-weight: 700;
letter-spacing: 4rpx;
box-shadow: 0 12rpx 40rpx rgba(7, 193, 96, 0.25);
}
// 底部协议区
.agreement {
display: flex;

View File

@@ -3,6 +3,8 @@ import type {
AuthLoginReqVO,
AuthRegisterReqVO,
AuthSmsLoginReqVO,
AuthSocialLoginReqVO,
AuthWeixinMiniAppLoginReqVO,
ILoginForm,
} from '@/api/login'
import type { IAuthLoginRes } from '@/api/types/login'
@@ -13,8 +15,8 @@ import {
login as _login,
logout as _logout,
refreshToken as _refreshToken,
wxLogin as _wxLogin,
getWxCode,
socialLogin as _socialLogin,
weixinMiniAppLogin as _weixinMiniAppLogin,
register,
smsLogin,
} from '@/api/login'
@@ -160,38 +162,20 @@ export const useTokenStore = defineStore(
}
}
/**
* 微信登录
* 有的时候后端会用一个接口返回token和用户信息有的时候会分开2个接口一个获取token一个获取用户信息
* 各有利弊看业务场景和系统复杂度这里使用2个接口返回的来模拟
* @returns 登录结果
*/
const wxLogin = async () => {
try {
// 获取微信小程序登录的code
const code = await getWxCode()
console.log('微信登录-code: ', code)
const res = await _wxLogin(code)
console.log('微信登录-res: ', res)
/** 微信静默登录(已绑定用户) */
const socialLogin = async (params: AuthSocialLoginReqVO) => {
const res = await _socialLogin(params)
await _postLogin(res)
// 注释 by 芋艿:使用 wd-toast 替代
// uni.showToast({
// title: '登录成功',
// icon: 'success',
// })
toast.success('登录成功')
return res
}
catch (error) {
console.error('微信登录失败:', error)
// 注释 by 芋艿:使用 wd-toast 替代
// uni.showToast({
// title: '微信登录失败,请重试',
// icon: 'error',
// })
toast.error('微信登录失败,请重试')
throw error
}
/** 微信小程序一键登录(手机号匹配) */
const weixinMiniAppLogin = async (params: AuthWeixinMiniAppLoginReqVO) => {
const res = await _weixinMiniAppLogin(params)
await _postLogin(res)
toast.success('登录成功')
return res
}
/**
@@ -318,7 +302,8 @@ export const useTokenStore = defineStore(
return {
// 核心API方法
login,
wxLogin,
socialLogin,
weixinMiniAppLogin,
logout,
// 认证状态判断(最常用的)

View File

@@ -124,8 +124,8 @@ export function getEnvBaseUrl() {
// # 有些同学可能需要在微信小程序里面根据 develop、trial、release 分别设置上传地址,参考代码如下。
// TODO @芋艿:这个后续也要调整。
const VITE_SERVER_BASEURL__WEIXIN_DEVELOP = 'http://192.168.0.104:48080/admin-api'
const VITE_SERVER_BASEURL__WEIXIN_TRIAL = 'http://192.168.0.104:48080/admin-api'
const VITE_SERVER_BASEURL__WEIXIN_RELEASE = 'http://192.168.0.104:48080/admin-api'
const VITE_SERVER_BASEURL__WEIXIN_TRIAL = 'https://viewshanghai.com/admin-api'
const VITE_SERVER_BASEURL__WEIXIN_RELEASE = 'https://viewshanghai.com/admin-api'
// 微信小程序端环境区分
if (isMpWeixin) {