feat: 完成全部接口替换为新后端接口
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { fetchAgeRecommendations } from '../../services/site-api';
|
||||
import { resolvePreviewUrl } from '../../config/assets';
|
||||
import { appSharePageMethods } from '../../base/pageMixin';
|
||||
import { AGE_BANDS, AgeBandKey } from '../../core/data/difficulty';
|
||||
import { parseMiniProgramUrl } from '../../utils/index';
|
||||
@@ -91,24 +93,17 @@ async function fetchAgeRecommended(
|
||||
ageKey: AgeBandKey,
|
||||
): Promise<RecommendedItemView[]> {
|
||||
try {
|
||||
const res = await wx.cloud.callFunction({
|
||||
name: 'ageRecommendedQuery',
|
||||
data: { ageKey },
|
||||
});
|
||||
const payload = (res && (res.result as any)) || null;
|
||||
if (!payload?.success) return [];
|
||||
const items = (payload.data?.items || []) as any[];
|
||||
const response = await fetchAgeRecommendations(ageKey);
|
||||
const items = response.items;
|
||||
return items
|
||||
.map((it) => ({
|
||||
title: String(it.title || ''),
|
||||
image: String(it.previewImg || ''),
|
||||
image: resolvePreviewUrl(it.previewImg),
|
||||
subtitle: String(it.subtitle || ''),
|
||||
ageBand: String(it.ageBand || it.ageRange || ''),
|
||||
difficulty: toDifficultyLabel(
|
||||
it.difficultyLabel || it.difficulty || '',
|
||||
),
|
||||
ageBand: `${it.ageMin}-${it.ageMax}岁`,
|
||||
difficulty: toDifficultyLabel(it.difficulty || ''),
|
||||
path: String(it.path || ''),
|
||||
worksheetId: String(it.worksheetId || ''),
|
||||
worksheetId: String(it.id || ''),
|
||||
}))
|
||||
.filter((it) => it.title);
|
||||
} catch (e) {
|
||||
@@ -174,8 +169,7 @@ Page({
|
||||
onTapCard(e: WechatMiniprogram.CustomEvent) {
|
||||
const detail = (e.detail || {}) as { title?: string; path?: string };
|
||||
const path =
|
||||
detail.path ||
|
||||
(e.currentTarget.dataset.path as string | undefined);
|
||||
detail.path || (e.currentTarget.dataset.path as string | undefined);
|
||||
const title =
|
||||
detail.title ||
|
||||
(e.currentTarget.dataset.title as string | undefined);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { resolvePreviewUrl } from '../../config/assets';
|
||||
import type { ApiCategory, ApiWorksheet } from '../../services/content-api';
|
||||
|
||||
export interface CategoryTab {
|
||||
@@ -95,7 +96,7 @@ export function buildCategoryDataset(
|
||||
title: row.title,
|
||||
subtitle: row.subtitle,
|
||||
icon: icons.get(row.category) || '📄',
|
||||
previewImg: row.previewImg || '',
|
||||
previewImg: resolvePreviewUrl(row.previewImg),
|
||||
ageBand: `${row.ageMin}-${row.ageMax}岁`,
|
||||
difficultyLabel: DIFFICULTY_LABELS[row.difficulty - 1] || '基础',
|
||||
path: row.path,
|
||||
|
||||
@@ -222,6 +222,9 @@ Page({
|
||||
this.setData({
|
||||
favoriteList: records.map((r) => mapFavoriteToItem(r)),
|
||||
});
|
||||
} catch {
|
||||
this.setData({ favoriteList: [] });
|
||||
wx.showToast({ title: '收藏加载失败,请重试', icon: 'none' });
|
||||
} finally {
|
||||
this.setData({ favLoading: false });
|
||||
}
|
||||
@@ -232,6 +235,9 @@ Page({
|
||||
try {
|
||||
const records = await getDownloadLogs(1, DOWNLOAD_HISTORY_MAX);
|
||||
this.setData({ downloadSections: groupDownloadsByDate(records) });
|
||||
} catch {
|
||||
this.setData({ downloadSections: [] });
|
||||
wx.showToast({ title: '下载记录加载失败,请重试', icon: 'none' });
|
||||
} finally {
|
||||
this.setData({ dlLoading: false });
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { publicAssetUrl } from '../../config/assets';
|
||||
import { CATEGORY_LIST_WITH_ALL } from '../../core/data/categories';
|
||||
import { AGE_BANDS } from '../../core/data/difficulty';
|
||||
import { CategoryId } from '../../core/models/category';
|
||||
@@ -91,8 +92,9 @@ export const HOME_DAILY_CHECKIN_ITEMS: HomeDisplayItem[] = [
|
||||
ageBand: '5-8岁',
|
||||
difficulty: '基础',
|
||||
icon: '📝',
|
||||
previewImg:
|
||||
'cloud://cloud1-9gifs7a2756e2c87.636c-cloud1-9gifs7a2756e2c87-1351593184/assets/previews/chinese/hanzi-daily-checkin.jpg',
|
||||
previewImg: publicAssetUrl(
|
||||
'assets/previews/chinese/hanzi-daily-checkin.jpg',
|
||||
),
|
||||
path: '/chinesePages/handwritingSheet/handwritingSheet?id=hanzi-daily-checkin',
|
||||
available: true,
|
||||
},
|
||||
@@ -104,8 +106,7 @@ export const HOME_DAILY_CHECKIN_ITEMS: HomeDisplayItem[] = [
|
||||
ageBand: '6-8岁',
|
||||
difficulty: '基础',
|
||||
icon: '🔤',
|
||||
previewImg:
|
||||
'cloud://cloud1-9gifs7a2756e2c87.636c-cloud1-9gifs7a2756e2c87-1351593184/assets/previews/pinyin/pinyin-daily.jpg',
|
||||
previewImg: publicAssetUrl('assets/previews/pinyin/pinyin-daily.jpg'),
|
||||
path: '/pinyinPages/pinyinDictation/pinyinDictation?id=pinyin-daily',
|
||||
available: true,
|
||||
},
|
||||
@@ -117,8 +118,9 @@ export const HOME_DAILY_CHECKIN_ITEMS: HomeDisplayItem[] = [
|
||||
ageBand: '6-8岁',
|
||||
difficulty: '基础',
|
||||
icon: '🔠',
|
||||
previewImg:
|
||||
'cloud://cloud1-9gifs7a2756e2c87.636c-cloud1-9gifs7a2756e2c87-1351593184/assets/previews/english/letter-tracing-daily-checkin.jpg',
|
||||
previewImg: publicAssetUrl(
|
||||
'assets/previews/english/letter-tracing-daily-checkin.jpg',
|
||||
),
|
||||
path: '/englishPages/letterTracing/letterTracing?id=letter-tracing-daily-checkin',
|
||||
available: true,
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { resolvePreviewUrl } from '../../config/assets';
|
||||
import { appSharePageMethods } from '../../base/pageMixin';
|
||||
import { NAV_INNER_PX } from '../../utils/navMetrics';
|
||||
import {
|
||||
@@ -52,6 +53,7 @@ const TAB_BAR_PATHS = new Set([
|
||||
function toItemView(item: HomeDisplayItem): HomeDisplayItemView {
|
||||
return {
|
||||
...item,
|
||||
previewImg: resolvePreviewUrl(item.previewImg),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -218,11 +220,11 @@ Page({
|
||||
void this.initData();
|
||||
},
|
||||
|
||||
async initData() {
|
||||
wx.showLoading({ title: '加载中', mask: false });
|
||||
async initData(override?: PageConfigData) {
|
||||
if (!override) wx.showLoading({ title: '加载中', mask: false });
|
||||
|
||||
const app = getApp<IAppOption>();
|
||||
const config = await app.getPageConfig();
|
||||
const config = override || (await app.getPageConfig());
|
||||
|
||||
let homeData: HomeDisplayDataset;
|
||||
|
||||
@@ -249,13 +251,26 @@ Page({
|
||||
searchPlaceholder: homeData.searchPlaceholder,
|
||||
tabs,
|
||||
ageBands,
|
||||
activeAgeBand: homeData.ageBands[0]?.key || '3-4',
|
||||
activeAgeBand:
|
||||
override &&
|
||||
homeData.ageBands.some(
|
||||
(band) => band.key === this.data.activeAgeBand,
|
||||
)
|
||||
? this.data.activeAgeBand
|
||||
: homeData.ageBands[0]?.key || '3-4',
|
||||
activeTab: tabs.some((tab) => tab.id === this.data.activeTab)
|
||||
? this.data.activeTab
|
||||
: 'all',
|
||||
heroSwiperCurrent: Math.min(
|
||||
this.data.heroSwiperCurrent,
|
||||
Math.max(0, homeData.featured.length - 1),
|
||||
),
|
||||
featuredItems: homeData.featured.map(toItemView),
|
||||
hotRecommends: homeData.hot.slice(0, 3).map(toItemView),
|
||||
sections,
|
||||
});
|
||||
|
||||
wx.hideLoading();
|
||||
if (!override) wx.hideLoading();
|
||||
},
|
||||
|
||||
// ── Tab & Navigation ──
|
||||
|
||||
@@ -123,7 +123,7 @@ page {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.profile-hero__stat+.profile-hero__stat {
|
||||
.profile-hero__stat + .profile-hero__stat {
|
||||
margin-left: 32rpx;
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ page {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.profile-grid__cell+.profile-grid__cell {
|
||||
.profile-grid__cell + .profile-grid__cell {
|
||||
margin-left: 32rpx;
|
||||
}
|
||||
|
||||
@@ -461,4 +461,16 @@ page {
|
||||
|
||||
.profile-editor__action--disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
/* 仅在账户恢复需要用户主动确认时展示,正常静默登录不出现。 */
|
||||
.profile-account-restart {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: @section-gap-xs;
|
||||
border-radius: @radius-xl;
|
||||
background: @bg-white;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { uploadAsset, memberStats } from '../../services/member-api';
|
||||
import { getUser as getServerUser, startAccount } from '../../utils/auth';
|
||||
import { disablePageShareMenu } from '../../base/pageMixin';
|
||||
import { APP_VERSION } from '../../config/config';
|
||||
import { getDownloadLogCount } from '../../utils/downloadLogs';
|
||||
import { getFavoriteCount } from '../../utils/favorites';
|
||||
import {
|
||||
getCachedUser,
|
||||
getUser,
|
||||
@@ -22,6 +22,8 @@ Page({
|
||||
draftNickName: '',
|
||||
draftAvatarUrl: '/assets/imgs/doodle-head.png',
|
||||
isSavingProfile: false,
|
||||
serverAccountActionRequired: false,
|
||||
isStartingAccount: false,
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
@@ -35,17 +37,52 @@ Page({
|
||||
},
|
||||
|
||||
onShow() {
|
||||
void this.checkServerAccount();
|
||||
this.syncUserInfoFromApp();
|
||||
void this.refreshStats();
|
||||
},
|
||||
|
||||
/** 正常登录始终静默;账户不存在时才展示用户主动重新开始的入口。 */
|
||||
async checkServerAccount() {
|
||||
try {
|
||||
await getServerUser();
|
||||
this.setData({ serverAccountActionRequired: false });
|
||||
} catch (error) {
|
||||
const reason = (error as { reason?: string }).reason;
|
||||
this.setData({
|
||||
serverAccountActionRequired:
|
||||
reason === 'ACCOUNT_NOT_FOUND' ||
|
||||
reason === 'ACCOUNT_RESTART_REQUIRED',
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
async onStartServerAccount() {
|
||||
if (this.data.isStartingAccount) return;
|
||||
this.setData({ isStartingAccount: true });
|
||||
try {
|
||||
await startAccount();
|
||||
this.setData({ serverAccountActionRequired: false });
|
||||
wx.showToast({ title: '账户已就绪', icon: 'success' });
|
||||
} catch {
|
||||
wx.showToast({ title: '账户暂不可用,请稍后重试', icon: 'none' });
|
||||
} finally {
|
||||
this.setData({ isStartingAccount: false });
|
||||
}
|
||||
},
|
||||
|
||||
async syncUserInfoFromApp() {
|
||||
const app = getApp<IAppOption>();
|
||||
const cachedUser = app.globalData.user || getCachedUser();
|
||||
|
||||
if (cachedUser) {
|
||||
this.applyUserInfo(cachedUser);
|
||||
}
|
||||
if (cachedUser) this.applyUserInfo(cachedUser);
|
||||
else
|
||||
this.setData({
|
||||
userName: '微信用户',
|
||||
avatarUrl: this.DEFAULT_AVATAR_URL,
|
||||
printCount: 0,
|
||||
favoriteCount: 0,
|
||||
});
|
||||
|
||||
try {
|
||||
const latestUser = await getUser();
|
||||
@@ -69,13 +106,11 @@ Page({
|
||||
|
||||
async refreshStats() {
|
||||
try {
|
||||
const [printCount, favoriteCount] = await Promise.all([
|
||||
getDownloadLogCount(),
|
||||
getFavoriteCount(),
|
||||
]);
|
||||
const stats = await memberStats();
|
||||
const { downloadCount: printCount, favoriteCount } = stats;
|
||||
this.setData({ printCount, favoriteCount });
|
||||
} catch (e) {
|
||||
console.error('refreshStats failed', e);
|
||||
} catch {
|
||||
this.setData({ printCount: 0, favoriteCount: 0 });
|
||||
}
|
||||
},
|
||||
|
||||
@@ -121,12 +156,12 @@ Page({
|
||||
this.setData({ isSavingProfile: true });
|
||||
|
||||
try {
|
||||
const avatarUrl = await this.persistAvatarIfNeeded(
|
||||
const avatarAssetId = await this.persistAvatarIfNeeded(
|
||||
this.data.draftAvatarUrl,
|
||||
);
|
||||
const user = await updateUserProfile({
|
||||
nickName,
|
||||
avatarUrl,
|
||||
avatarAssetId,
|
||||
});
|
||||
|
||||
this.applyUserInfo(user);
|
||||
@@ -140,24 +175,11 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
async persistAvatarIfNeeded(avatarUrl: string): Promise<string> {
|
||||
if (!avatarUrl) return avatarUrl;
|
||||
if (
|
||||
avatarUrl.startsWith('cloud://') ||
|
||||
avatarUrl.startsWith('http://') ||
|
||||
avatarUrl.startsWith('https://')
|
||||
) {
|
||||
return avatarUrl;
|
||||
}
|
||||
|
||||
async persistAvatarIfNeeded(avatarUrl: string): Promise<string | null> {
|
||||
const user = await getUser();
|
||||
const cloudPath = `user-avatars/${user._id}-${Date.now()}.png`;
|
||||
const uploadRes = await wx.cloud.uploadFile({
|
||||
cloudPath,
|
||||
filePath: avatarUrl,
|
||||
});
|
||||
|
||||
return uploadRes.fileID;
|
||||
if (!avatarUrl || avatarUrl === this.DEFAULT_AVATAR_URL) return null;
|
||||
if (avatarUrl === user.avatarUrl) return user.avatarAssetId || null;
|
||||
return (await uploadAsset(avatarUrl, 'avatar')).id;
|
||||
},
|
||||
|
||||
onGoToDownloads() {
|
||||
|
||||
@@ -38,6 +38,19 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
wx:if="{{serverAccountActionRequired}}"
|
||||
class="profile-account-restart">
|
||||
<text>账户需要重新开始使用</text>
|
||||
<button
|
||||
size="mini"
|
||||
loading="{{isStartingAccount}}"
|
||||
disabled="{{isStartingAccount}}"
|
||||
bindtap="onStartServerAccount">
|
||||
开始使用账户
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 双格入口 -->
|
||||
<view class="profile-grid">
|
||||
<view class="profile-grid__cell" bindtap="onGoToFavorites">
|
||||
|
||||
Reference in New Issue
Block a user