登录页面
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import Taro from '@tarojs/taro';
|
||||
import { ClientApp } from '@dukang/shared-types';
|
||||
import { goLogin } from './auth-nav';
|
||||
|
||||
function resolveApiBase(): string {
|
||||
const origin =
|
||||
@@ -52,7 +53,7 @@ export function isLoggedIn(): boolean {
|
||||
}
|
||||
|
||||
export function redirectToLogin() {
|
||||
Taro.navigateTo({ url: '/pages/login/index' });
|
||||
goLogin();
|
||||
}
|
||||
|
||||
export function logout() {
|
||||
@@ -119,4 +120,5 @@ export type UserProfile = {
|
||||
id: string;
|
||||
phone?: string | null;
|
||||
nickname?: string | null;
|
||||
avatarUrl?: string | null;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import Taro from '@tarojs/taro';
|
||||
|
||||
const TAB_PAGES = new Set([
|
||||
'/pages/home/index',
|
||||
'/pages/stores/index',
|
||||
'/pages/benefit/index',
|
||||
'/pages/mine/index',
|
||||
]);
|
||||
|
||||
function currentPagePath(): string {
|
||||
const pages = Taro.getCurrentPages();
|
||||
const cur = pages[pages.length - 1] as
|
||||
| { route?: string; options?: Record<string, string | undefined> }
|
||||
| undefined;
|
||||
if (!cur?.route) return '';
|
||||
const path = cur.route.startsWith('/') ? cur.route : `/${cur.route}`;
|
||||
if (path.includes('/pages/login/')) return '';
|
||||
const opts = cur.options ?? {};
|
||||
const qs = Object.entries(opts)
|
||||
.filter(([, v]) => v != null && v !== '')
|
||||
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)
|
||||
.join('&');
|
||||
return qs ? `${path}?${qs}` : path;
|
||||
}
|
||||
|
||||
/** 跳转登录页;默认带回当前页作为 return */
|
||||
export function goLogin(returnPath?: string) {
|
||||
const returnTo = returnPath ?? currentPagePath();
|
||||
const url = returnTo
|
||||
? `/pages/login/index?return=${encodeURIComponent(returnTo)}`
|
||||
: '/pages/login/index';
|
||||
Taro.navigateTo({ url }).catch(() => {
|
||||
Taro.redirectTo({ url });
|
||||
});
|
||||
}
|
||||
|
||||
/** 登录成功后回到 return 页,或回退 / 首页 */
|
||||
export function finishLoginNavigate(returnTo?: string) {
|
||||
const raw = (returnTo || '').trim();
|
||||
const target = raw ? decodeURIComponent(raw) : '';
|
||||
const pathOnly = target.split('?')[0];
|
||||
|
||||
if (pathOnly && TAB_PAGES.has(pathOnly)) {
|
||||
Taro.switchTab({ url: pathOnly });
|
||||
return;
|
||||
}
|
||||
if (pathOnly && pathOnly.startsWith('/pages/')) {
|
||||
Taro.redirectTo({ url: target }).catch(() => {
|
||||
Taro.reLaunch({ url: pathOnly });
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const pages = Taro.getCurrentPages();
|
||||
if (pages.length > 1) {
|
||||
Taro.navigateBack();
|
||||
return;
|
||||
}
|
||||
Taro.switchTab({ url: '/pages/home/index' });
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import { useMemo } from 'react';
|
||||
import Taro from '@tarojs/taro';
|
||||
|
||||
export type NavBarMetrics = {
|
||||
/** 状态栏高度(刘海/灵动岛上方) */
|
||||
statusBarHeight: number;
|
||||
/** 导航栏总高度 = 状态栏 + 内容区 */
|
||||
navBarHeight: number;
|
||||
/** 标题栏内容区高度(与胶囊对齐) */
|
||||
navContentHeight: number;
|
||||
/** 右侧留白,避免与微信胶囊按钮重叠 */
|
||||
navBarPaddingRight: number;
|
||||
};
|
||||
|
||||
const H5_FALLBACK: NavBarMetrics = {
|
||||
statusBarHeight: 0,
|
||||
navBarHeight: 56,
|
||||
navContentHeight: 56,
|
||||
navBarPaddingRight: 16,
|
||||
};
|
||||
|
||||
const WEAPP_FALLBACK: NavBarMetrics = {
|
||||
statusBarHeight: 20,
|
||||
navBarHeight: 64,
|
||||
navContentHeight: 44,
|
||||
navBarPaddingRight: 96,
|
||||
};
|
||||
|
||||
/** 计算小程序自定义导航栏尺寸(对齐微信胶囊按钮) */
|
||||
export function getNavBarMetrics(): NavBarMetrics {
|
||||
if (process.env.TARO_ENV === 'h5') {
|
||||
return H5_FALLBACK;
|
||||
}
|
||||
|
||||
try {
|
||||
const win = Taro.getWindowInfo?.() ?? Taro.getSystemInfoSync();
|
||||
const menu = Taro.getMenuButtonBoundingClientRect();
|
||||
const statusBarHeight = win.statusBarHeight ?? WEAPP_FALLBACK.statusBarHeight;
|
||||
const navContentHeight =
|
||||
menu.height > 0
|
||||
? (menu.top - statusBarHeight) * 2 + menu.height
|
||||
: WEAPP_FALLBACK.navContentHeight;
|
||||
const navBarHeight = statusBarHeight + navContentHeight;
|
||||
const navBarPaddingRight =
|
||||
menu.width > 0
|
||||
? Math.max(win.windowWidth - menu.left + 8, 16)
|
||||
: WEAPP_FALLBACK.navBarPaddingRight;
|
||||
|
||||
return {
|
||||
statusBarHeight,
|
||||
navBarHeight,
|
||||
navContentHeight,
|
||||
navBarPaddingRight,
|
||||
};
|
||||
} catch {
|
||||
return WEAPP_FALLBACK;
|
||||
}
|
||||
}
|
||||
|
||||
export function useNavBarMetrics(): NavBarMetrics {
|
||||
return useMemo(() => getNavBarMetrics(), []);
|
||||
}
|
||||
|
||||
/** 仅注入 CSS 变量,供 PageShell / sticky 子元素使用(不加 height/padding) */
|
||||
export function pageShellCssVars(metrics: NavBarMetrics): Record<string, string> {
|
||||
return {
|
||||
'--nav-bar-height': `${metrics.navBarHeight}px`,
|
||||
'--nav-content-height': `${metrics.navContentHeight}px`,
|
||||
'--nav-status-bar-height': `${metrics.statusBarHeight}px`,
|
||||
'--nav-padding-right': `${metrics.navBarPaddingRight}px`,
|
||||
};
|
||||
}
|
||||
|
||||
/** 顶栏自身样式:statusBar padding + 总高 + 右侧胶囊避让 */
|
||||
export function navBarStyle(metrics: NavBarMetrics): Record<string, string | number> {
|
||||
return {
|
||||
paddingTop: `${metrics.statusBarHeight}px`,
|
||||
height: `${metrics.navBarHeight}px`,
|
||||
paddingRight: `${metrics.navBarPaddingRight}px`,
|
||||
...pageShellCssVars(metrics),
|
||||
};
|
||||
}
|
||||
@@ -30,4 +30,16 @@ export function getProductImages(source?: ProductImageSource | null): string[] {
|
||||
return PRODUCT_IMAGE_FALLBACK ? [PRODUCT_IMAGE_FALLBACK] : [];
|
||||
}
|
||||
|
||||
/** 详情页顶部轮播 */
|
||||
export function getProductCarouselImages(source?: ProductImageSource | null): string[] {
|
||||
const carousel = uniqueUrls(source?.carouselUrls ?? []);
|
||||
if (carousel.length > 0) return carousel;
|
||||
return getProductImages(source);
|
||||
}
|
||||
|
||||
/** 详情页图文长图 */
|
||||
export function getProductDetailImages(source?: ProductImageSource | null): string[] {
|
||||
return uniqueUrls(source?.detailImageUrls ?? []);
|
||||
}
|
||||
|
||||
export const FALLBACK_CITY_CODE = '410100';
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { WechatLoginResult } from '@dukang/shared-types';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { request } from './api';
|
||||
|
||||
/** 小程序微信授权登录:Taro.login → /auth/login/wechat */
|
||||
export async function loginWithWechat(): Promise<WechatLoginResult> {
|
||||
const res = await Taro.login();
|
||||
if (!res.code) {
|
||||
throw new Error(res.errMsg || '微信登录失败,未获取到 code');
|
||||
}
|
||||
return request<WechatLoginResult>('/auth/login/wechat', {
|
||||
method: 'POST',
|
||||
data: { code: res.code, platform: 'mini' },
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user