feat: 我的、设置、打印指南页面开发完成
This commit is contained in:
@@ -18,6 +18,8 @@ export type CategoryItem = {
|
||||
downloads: number;
|
||||
/** 列表底部展示的日期(静态数据用 id 派生稳定值) */
|
||||
date: string;
|
||||
/** 最后更新时间(云端数据用于排序) */
|
||||
updatedAt?: string;
|
||||
};
|
||||
|
||||
export type CategoryGroup = {
|
||||
|
||||
@@ -17,6 +17,13 @@ type CategoryDataset = {
|
||||
}>;
|
||||
};
|
||||
|
||||
const DIFFICULTY_LABELS: Record<number, string> = {
|
||||
1: '入门',
|
||||
2: '基础',
|
||||
3: '进阶',
|
||||
4: '挑战',
|
||||
};
|
||||
|
||||
const SIDEBAR_TABS: CategoryTab[] = CATEGORY_LIST_WITH_ALL.map(
|
||||
({ id, name, icon }) => ({
|
||||
id,
|
||||
@@ -33,9 +40,74 @@ const TAB_BAR_PATHS = new Set([
|
||||
'/pages/profile/profile',
|
||||
]);
|
||||
|
||||
// Page-level mutable state (shared across methods, set once on load)
|
||||
// Page-level mutable state (shared across methods)
|
||||
let _categoryData: CategoryDataset | null = null;
|
||||
|
||||
/** 将云端 worksheet 原始数据转换为 CategoryItem */
|
||||
function toDisplayItem(raw: Record<string, any>): CategoryItem {
|
||||
const difficulty = (Number(raw.difficulty) || 2) as 1 | 2 | 3 | 4;
|
||||
const ageMin = Number(raw.ageMin) || 0;
|
||||
const ageMax = Number(raw.ageMax) || 0;
|
||||
return {
|
||||
id: String(raw._id || ''),
|
||||
title: String(raw.title || ''),
|
||||
subtitle: String(raw.subtitle || ''),
|
||||
previewImg: String(raw.previewImg || ''),
|
||||
ageBand: `${ageMin}-${ageMax}岁`,
|
||||
ageMin,
|
||||
ageMax,
|
||||
difficulty,
|
||||
difficultyLabel: DIFFICULTY_LABELS[difficulty] || '基础',
|
||||
path: String(raw.path || ''),
|
||||
available: true,
|
||||
likes: Number(raw.likes) || 0,
|
||||
downloads: Number(raw.downloads) || 0,
|
||||
date: raw.updatedAt
|
||||
? new Date(raw.updatedAt).toISOString().slice(0, 10)
|
||||
: new Date().toISOString().slice(0, 10),
|
||||
updatedAt: raw.updatedAt ? String(raw.updatedAt) : '',
|
||||
};
|
||||
}
|
||||
|
||||
/** 排序:updatedAt 最新的 2 个置顶,其余按 downloads 降序 */
|
||||
function sortWorksheets(items: CategoryItem[]): CategoryItem[] {
|
||||
const byTime = [...items].sort(
|
||||
(a, b) =>
|
||||
new Date(b.updatedAt || '').getTime() -
|
||||
new Date(a.updatedAt || '').getTime(),
|
||||
);
|
||||
const recent = byTime.slice(0, 2);
|
||||
const recentIds = new Set(recent.map((w) => w.id));
|
||||
const rest = byTime
|
||||
.filter((w) => !recentIds.has(w.id))
|
||||
.sort((a, b) => (b.downloads || 0) - (a.downloads || 0));
|
||||
return [...recent, ...rest];
|
||||
}
|
||||
|
||||
/** 将云端 worksheet 数组按分类分组,构建 CategoryDataset */
|
||||
function buildCategoryDataFromCloud(
|
||||
rawList: Record<string, any>[],
|
||||
): CategoryDataset {
|
||||
const itemsByCategory: Record<string, CategoryItem[]> = {};
|
||||
for (const raw of rawList) {
|
||||
const item = toDisplayItem(raw);
|
||||
const cat = String(raw.category || '');
|
||||
if (!itemsByCategory[cat]) itemsByCategory[cat] = [];
|
||||
itemsByCategory[cat].push(item);
|
||||
}
|
||||
|
||||
const categories = CATEGORY_LIST_WITH_ALL.filter((c) => c.id !== 'all').map(
|
||||
(cat) => ({
|
||||
id: cat.id,
|
||||
name: cat.name,
|
||||
icon: cat.icon,
|
||||
items: sortWorksheets(itemsByCategory[cat.id] || []),
|
||||
}),
|
||||
);
|
||||
|
||||
return { searchPlaceholder: '搜索练习纸...', categories };
|
||||
}
|
||||
|
||||
function buildAllItems(): CategoryItem[] {
|
||||
if (!_categoryData) return [];
|
||||
const items: CategoryItem[] = [];
|
||||
@@ -44,7 +116,7 @@ function buildAllItems(): CategoryItem[] {
|
||||
items.push({ ...item });
|
||||
}
|
||||
}
|
||||
return items;
|
||||
return sortWorksheets(items);
|
||||
}
|
||||
|
||||
function getItemsByCategory(categoryId: string): CategoryItem[] {
|
||||
@@ -69,7 +141,7 @@ function filterByKeyword(
|
||||
}
|
||||
|
||||
// Skeleton placeholder items for loading state
|
||||
const SKELETON_ITEMS = Array.from({ length: 4 }, (_, i) => ({
|
||||
const SKELETON_ITEMS = Array.from({ length: 6 }, (_, i) => ({
|
||||
id: `skeleton-${i}`,
|
||||
title: '\u00A0',
|
||||
subtitle: '\u00A0',
|
||||
@@ -87,45 +159,45 @@ Page({
|
||||
loading: true,
|
||||
},
|
||||
|
||||
_defaultCategoryId: 'all',
|
||||
|
||||
onLoad(options: Record<string, string>) {
|
||||
void this.initData(options);
|
||||
if (options.id && options.id !== 'all') {
|
||||
this._defaultCategoryId = options.id;
|
||||
this.setData({ activeCategoryId: options.id });
|
||||
}
|
||||
},
|
||||
|
||||
async initData(options: Record<string, string>) {
|
||||
wx.showLoading({ title: '加载中', mask: false });
|
||||
onShow() {
|
||||
_categoryData = null;
|
||||
this.setData({ displayItems: SKELETON_ITEMS, loading: true });
|
||||
void this.loadWorksheets();
|
||||
},
|
||||
|
||||
const app = getApp<IAppOption>();
|
||||
const config = await app.getPageConfig();
|
||||
async loadWorksheets() {
|
||||
try {
|
||||
const res = await wx.cloud.callFunction({
|
||||
name: 'worksheetsQuery',
|
||||
data: { status: 'active' },
|
||||
});
|
||||
const result = (res?.result as any) || {};
|
||||
if (!result.success) throw new Error(result.message || '查询失败');
|
||||
|
||||
// Use cloud config if available, otherwise fallback to local static data
|
||||
if (config?.category?.categories?.length) {
|
||||
_categoryData = {
|
||||
searchPlaceholder:
|
||||
config.category.searchPlaceholder || '搜索练习纸...',
|
||||
categories: config.category.categories.map((cat) => ({
|
||||
id: cat.id,
|
||||
name: cat.name,
|
||||
icon: cat.icon,
|
||||
items: (cat.items || []).map(
|
||||
(raw) => raw as unknown as CategoryItem,
|
||||
),
|
||||
})),
|
||||
};
|
||||
} else {
|
||||
_categoryData = buildCategoryDataFromCloud(result.data || []);
|
||||
} catch {
|
||||
_categoryData = CATEGORY_DATA;
|
||||
}
|
||||
|
||||
const activeId = options.id && options.id !== 'all' ? options.id : 'all';
|
||||
const activeId = this.data.activeCategoryId || this._defaultCategoryId;
|
||||
const items = getItemsByCategory(activeId);
|
||||
const filtered = filterByKeyword(items, this.data.searchKeyword);
|
||||
|
||||
this.setData({
|
||||
loading: false,
|
||||
searchPlaceholder: _categoryData.searchPlaceholder,
|
||||
activeCategoryId: activeId,
|
||||
displayItems: items,
|
||||
displayItems: filtered,
|
||||
});
|
||||
|
||||
wx.hideLoading();
|
||||
},
|
||||
|
||||
onTapCategory(e: WechatMiniprogram.TouchEvent) {
|
||||
|
||||
@@ -243,7 +243,7 @@
|
||||
|
||||
.fav-cta__btn {
|
||||
margin-top: 32rpx;
|
||||
padding: 22rpx 64rpx;
|
||||
padding: 24rpx 52rpx;
|
||||
border-radius: 999rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
@@ -425,7 +425,7 @@
|
||||
.fav-empty__sub {
|
||||
font-size: 26rpx;
|
||||
color: @text-secondary;
|
||||
margin-bottom: 40rpx;
|
||||
margin-bottom: 32rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,11 +31,15 @@
|
||||
aria-hidden="true"></text>
|
||||
</view>
|
||||
<view wx:elif="{{favoriteList.length === 0}}" class="fav-empty">
|
||||
<text class="fav-empty__emoji">🦆</text>
|
||||
<text class="fav-empty__msg">鸭丫还没找到收藏呢</text>
|
||||
<toy-icon
|
||||
name="mood-empty"
|
||||
size="100rpx"
|
||||
color="#b3ac9f"
|
||||
class="fav-empty__icon" />
|
||||
<text class="fav-empty__msg">还没找到收藏呢</text>
|
||||
<text class="fav-empty__sub">去发现好玩的练习纸吧~</text>
|
||||
<button class="fav-empty__btn" bindtap="onDiscoverTap">
|
||||
去发现
|
||||
<button class="fav-cta__btn" bindtap="onDiscoverTap">
|
||||
去发现页看看
|
||||
</button>
|
||||
</view>
|
||||
<view wx:elif="{{favoriteList.length > 0}}" class="fav-list">
|
||||
@@ -112,14 +116,15 @@
|
||||
<view
|
||||
wx:elif="{{downloadSections.length === 0}}"
|
||||
class="fav-empty">
|
||||
<van-icon
|
||||
name="clock"
|
||||
size="120rpx"
|
||||
<toy-icon
|
||||
name="mood-empty"
|
||||
size="100rpx"
|
||||
color="#b3ac9f"
|
||||
class="fav-empty__icon" />
|
||||
<text class="fav-empty__msg">暂无下载记录</text>
|
||||
<button class="fav-empty__btn" bindtap="onDiscoverTap">
|
||||
去发现
|
||||
<text class="fav-empty__sub">去发现好玩的练习纸吧~</text>
|
||||
<button class="fav-cta__btn" bindtap="onDiscoverTap">
|
||||
去发现页看看
|
||||
</button>
|
||||
</view>
|
||||
<view wx:elif="{{downloadSections.length > 0}}" class="fav-dl">
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
<swiper
|
||||
class="home-hero-swiper"
|
||||
previous-margin="100rpx"
|
||||
next-margin="100rpx"
|
||||
previous-margin="80rpx"
|
||||
next-margin="80rpx"
|
||||
circular="{{featuredItems.length > 1 && !loading}}"
|
||||
autoplay="{{!loading}}"
|
||||
interval="{{4000}}"
|
||||
@@ -200,8 +200,7 @@
|
||||
path="{{item.path}}"
|
||||
data-title="{{item.title}}"
|
||||
data-path="{{item.path}}"
|
||||
bindtap="onTapCard"
|
||||
/>
|
||||
bindtap="onTapCard" />
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
"backgroundColor": "#F8F0E0",
|
||||
"usingComponents": {
|
||||
"van-icon": "@vant/weapp/icon/index",
|
||||
"nav-bar": "../../components3.0/nav-bar/nav-bar"
|
||||
"van-popup": "@vant/weapp/popup/index",
|
||||
"nav-bar": "../../components3.0/nav-bar/nav-bar",
|
||||
"toy-icon": "../../toy/icon/icon"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ page {
|
||||
}
|
||||
|
||||
.profile-hero__avatar {
|
||||
width: 256rpx;
|
||||
height: 256rpx;
|
||||
width: 224rpx;
|
||||
height: 224rpx;
|
||||
border-radius: 50%;
|
||||
border: 8rpx solid @bg-white;
|
||||
background: @bg-gray;
|
||||
@@ -98,7 +98,7 @@ page {
|
||||
|
||||
.profile-hero__name {
|
||||
margin-top: 32rpx;
|
||||
font-size: 40rpx;
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: @text-title;
|
||||
text-align: center;
|
||||
@@ -116,7 +116,7 @@ page {
|
||||
.profile-hero__stat {
|
||||
flex: 1;
|
||||
background: @bg-header;
|
||||
border-radius: @radius;
|
||||
border-radius: 48rpx;
|
||||
border: 1rpx solid rgba(124, 118, 106, 0.12);
|
||||
padding: 32rpx 24rpx;
|
||||
text-align: center;
|
||||
@@ -321,4 +321,144 @@ page {
|
||||
color: @text-secondary;
|
||||
letter-spacing: 0.2em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.profile-editor-popup {
|
||||
border-radius: 40rpx 40rpx 0 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.profile-editor {
|
||||
overflow-y: auto;
|
||||
padding: 32rpx 40rpx;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
background: @bg-white;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.profile-editor__header {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.profile-editor__title {
|
||||
display: block;
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: @text-title;
|
||||
}
|
||||
|
||||
.profile-editor__desc {
|
||||
display: block;
|
||||
margin-top: 12rpx;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.5;
|
||||
color: @text-secondary;
|
||||
}
|
||||
|
||||
.profile-editor__avatar-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
|
||||
.profile-editor__avatar-button {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.profile-editor__avatar-button::after {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.profile-editor__avatar {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
border-radius: 50%;
|
||||
background: @bg-gray;
|
||||
border: 2rpx dashed fade(@text-secondary, 30%);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.profile-editor__avatar-placeholder {
|
||||
width: 120rpx;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.4;
|
||||
color: @text-secondary;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.profile-editor__avatar-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.profile-editor__field {
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
|
||||
.profile-editor__label {
|
||||
display: block;
|
||||
margin-bottom: 16rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: @text-title;
|
||||
}
|
||||
|
||||
.profile-editor__input {
|
||||
width: 100%;
|
||||
height: 96rpx;
|
||||
padding: 0 28rpx;
|
||||
border-radius: 24rpx;
|
||||
background: @bg-header;
|
||||
border: 1rpx solid rgba(124, 118, 106, 0.12);
|
||||
box-sizing: border-box;
|
||||
font-size: 30rpx;
|
||||
color: @text-title;
|
||||
}
|
||||
|
||||
.profile-editor__actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 24rpx;
|
||||
padding-top: 20rpx;
|
||||
}
|
||||
|
||||
.profile-editor__action {
|
||||
height: 92rpx;
|
||||
border-radius: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.profile-editor__action--ghost {
|
||||
background: @bg-header;
|
||||
color: @text-title;
|
||||
border: 1rpx solid rgba(124, 118, 106, 0.12);
|
||||
}
|
||||
|
||||
.profile-editor__action--primary {
|
||||
background: @brand;
|
||||
color: @text-selected-btn;
|
||||
box-shadow: @shadow;
|
||||
}
|
||||
|
||||
.profile-editor__action--disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
@@ -1,31 +1,154 @@
|
||||
import { getTodayDownloadCount } from '../../utils/downloadPrint';
|
||||
import { getDownloadLogCount } from '../../utils/downloadLogs';
|
||||
import { getFavoriteCount } from '../../utils/favorites';
|
||||
import {
|
||||
getCachedUser,
|
||||
getUser,
|
||||
type UserInfo,
|
||||
updateUserProfile,
|
||||
} from '../../utils/auth';
|
||||
|
||||
Page({
|
||||
DEFAULT_AVATAR_URL: '/assets/imgs/doodle-head.png',
|
||||
data: {
|
||||
userName: '微信用户',
|
||||
avatarUrl: '',
|
||||
printCount: 0,
|
||||
favoriteCount: 0,
|
||||
version: '',
|
||||
isDevEnv: false,
|
||||
version: '3.0.0',
|
||||
showProfileEditor: false,
|
||||
draftNickName: '',
|
||||
draftAvatarUrl: '/assets/imgs/doodle-head.png',
|
||||
isSavingProfile: false,
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
const info = wx.getAccountInfoSync();
|
||||
const version = info.miniProgram.version || '开发版';
|
||||
const isDevEnv = info.miniProgram.envVersion === 'develop';
|
||||
this.setData({ version, isDevEnv });
|
||||
this.syncUserInfoFromApp();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.refreshStats();
|
||||
this.syncUserInfoFromApp();
|
||||
void this.refreshStats();
|
||||
},
|
||||
|
||||
refreshStats() {
|
||||
const printCount = getTodayDownloadCount();
|
||||
// 收藏数待与收藏页数据源打通后接入
|
||||
const favoriteCount = 0;
|
||||
this.setData({ printCount, favoriteCount });
|
||||
async syncUserInfoFromApp() {
|
||||
const app = getApp<IAppOption>();
|
||||
const cachedUser = app.globalData.user || getCachedUser();
|
||||
|
||||
if (cachedUser) {
|
||||
this.applyUserInfo(cachedUser);
|
||||
}
|
||||
|
||||
try {
|
||||
const latestUser = await getUser();
|
||||
this.applyUserInfo(latestUser);
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败', error);
|
||||
}
|
||||
},
|
||||
|
||||
applyUserInfo(user: UserInfo) {
|
||||
const userName = user.nickName?.trim() || '微信用户';
|
||||
const avatarUrl =
|
||||
user.avatarUrl || (this as any).DEFAULT_AVATAR_URL || '';
|
||||
this.setData({
|
||||
userName,
|
||||
avatarUrl,
|
||||
draftNickName: userName === '微信用户' ? '' : userName,
|
||||
draftAvatarUrl: avatarUrl,
|
||||
});
|
||||
},
|
||||
|
||||
async refreshStats() {
|
||||
try {
|
||||
const [printCount, favoriteCount] = await Promise.all([
|
||||
getDownloadLogCount(),
|
||||
getFavoriteCount(),
|
||||
]);
|
||||
this.setData({ printCount, favoriteCount });
|
||||
} catch (e) {
|
||||
console.error('refreshStats failed', e);
|
||||
}
|
||||
},
|
||||
|
||||
onOpenProfileEditor() {
|
||||
this.setData({
|
||||
showProfileEditor: true,
|
||||
draftNickName:
|
||||
this.data.userName === '微信用户' ? '' : this.data.userName,
|
||||
draftAvatarUrl: this.data.avatarUrl,
|
||||
});
|
||||
},
|
||||
|
||||
onCloseProfileEditor() {
|
||||
if (this.data.isSavingProfile) return;
|
||||
this.setData({ showProfileEditor: false });
|
||||
},
|
||||
|
||||
onChooseAvatar(e: WechatMiniprogram.CustomEvent<{ avatarUrl?: string }>) {
|
||||
const avatarUrl = e.detail?.avatarUrl || '';
|
||||
if (!avatarUrl) return;
|
||||
this.setData({ draftAvatarUrl: avatarUrl });
|
||||
},
|
||||
|
||||
onNicknameInput(e: WechatMiniprogram.CustomEvent<{ value: string }>) {
|
||||
const nickName = (e.detail?.value || '').trim();
|
||||
this.setData({ draftNickName: nickName });
|
||||
},
|
||||
|
||||
async onSubmitProfile() {
|
||||
if (this.data.isSavingProfile) return;
|
||||
|
||||
const nickName = this.data.draftNickName.trim();
|
||||
if (!nickName) {
|
||||
wx.showToast({ title: '请输入昵称', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.data.draftAvatarUrl) {
|
||||
wx.showToast({ title: '请选择头像', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
this.setData({ isSavingProfile: true });
|
||||
|
||||
try {
|
||||
const avatarUrl = await this.persistAvatarIfNeeded(
|
||||
this.data.draftAvatarUrl,
|
||||
);
|
||||
const user = await updateUserProfile({
|
||||
nickName,
|
||||
avatarUrl,
|
||||
});
|
||||
|
||||
this.applyUserInfo(user);
|
||||
this.setData({ showProfileEditor: false });
|
||||
wx.showToast({ title: '资料已更新', icon: 'success' });
|
||||
} catch (error) {
|
||||
console.error('更新用户资料失败', error);
|
||||
wx.showToast({ title: '更新失败,请稍后重试', icon: 'none' });
|
||||
} finally {
|
||||
this.setData({ isSavingProfile: false });
|
||||
}
|
||||
},
|
||||
|
||||
async persistAvatarIfNeeded(avatarUrl: string): Promise<string> {
|
||||
if (!avatarUrl) return avatarUrl;
|
||||
if (
|
||||
avatarUrl.startsWith('cloud://') ||
|
||||
avatarUrl.startsWith('http://') ||
|
||||
avatarUrl.startsWith('https://')
|
||||
) {
|
||||
return avatarUrl;
|
||||
}
|
||||
|
||||
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;
|
||||
},
|
||||
|
||||
onGoToDownloads() {
|
||||
@@ -47,7 +170,7 @@ Page({
|
||||
},
|
||||
|
||||
onGoToSettings() {
|
||||
wx.showToast({ title: '功能开发中', icon: 'none' });
|
||||
wx.navigateTo({ url: '/supportPages/settings/settings' });
|
||||
},
|
||||
|
||||
onGoToDebug() {
|
||||
|
||||
@@ -8,19 +8,14 @@
|
||||
<view class="profile-hero__tint"></view>
|
||||
<view class="profile-hero__avatar-wrap">
|
||||
<view class="profile-hero__avatar">
|
||||
<text
|
||||
class="profile-hero__avatar-emoji"
|
||||
wx:if="{{!avatarUrl}}"
|
||||
>🦆</text
|
||||
>
|
||||
<image
|
||||
wx:else
|
||||
class="profile-hero__avatar-img"
|
||||
src="{{avatarUrl}}"
|
||||
mode="aspectFill" />
|
||||
</view>
|
||||
<view
|
||||
class="profile-hero__edit-badge"
|
||||
bindtap="onOpenProfileEditor"
|
||||
aria-role="button"
|
||||
aria-label="编辑头像">
|
||||
<van-icon name="edit" size="28rpx" color="#6c5a00" />
|
||||
@@ -73,9 +68,13 @@
|
||||
</view>
|
||||
<text class="profile-row__label">打印指南</text>
|
||||
</view>
|
||||
<text class="profile-row__chevron">›</text>
|
||||
<toy-icon
|
||||
class="profile-row__chevron"
|
||||
name="arrow-right"
|
||||
size="40rpx"
|
||||
color="#9a958b" />
|
||||
</view>
|
||||
<view class="profile-row" bindtap="onGoToFeedback">
|
||||
<!-- <view class="profile-row" bindtap="onGoToFeedback">
|
||||
<view class="profile-row__left">
|
||||
<view class="profile-row__icon-bg">
|
||||
<van-icon
|
||||
@@ -85,8 +84,12 @@
|
||||
</view>
|
||||
<text class="profile-row__label">提交反馈</text>
|
||||
</view>
|
||||
<text class="profile-row__chevron">›</text>
|
||||
</view>
|
||||
<toy-icon
|
||||
class="profile-row__chevron"
|
||||
name="arrow-right"
|
||||
size="40rpx"
|
||||
color="#9a958b" />
|
||||
</view> -->
|
||||
<view class="profile-row" bindtap="onGoToSettings">
|
||||
<view class="profile-row__left">
|
||||
<view class="profile-row__icon-bg">
|
||||
@@ -97,7 +100,11 @@
|
||||
</view>
|
||||
<text class="profile-row__label">设置</text>
|
||||
</view>
|
||||
<text class="profile-row__chevron">›</text>
|
||||
<toy-icon
|
||||
class="profile-row__chevron"
|
||||
name="arrow-right"
|
||||
size="40rpx"
|
||||
color="#9a958b" />
|
||||
</view>
|
||||
<view
|
||||
wx:if="{{isDevEnv}}"
|
||||
@@ -109,9 +116,13 @@
|
||||
</view>
|
||||
<text class="profile-row__label">Debug 工具</text>
|
||||
</view>
|
||||
<text class="profile-row__chevron">›</text>
|
||||
<toy-icon
|
||||
class="profile-row__chevron"
|
||||
name="arrow-right"
|
||||
size="40rpx"
|
||||
color="#9a958b" />
|
||||
</view>
|
||||
<view
|
||||
<!-- <view
|
||||
class="profile-row profile-row--last"
|
||||
bindtap="onGoToAbout">
|
||||
<view class="profile-row__left">
|
||||
@@ -123,12 +134,16 @@
|
||||
</view>
|
||||
<text class="profile-row__label">关于涂鸦丫</text>
|
||||
</view>
|
||||
<text class="profile-row__chevron">›</text>
|
||||
</view>
|
||||
<toy-icon
|
||||
class="profile-row__chevron"
|
||||
name="arrow-right"
|
||||
size="40rpx"
|
||||
color="#9a958b" />
|
||||
</view> -->
|
||||
</view>
|
||||
|
||||
<!-- 专业版推广(Stitch 深色卡) -->
|
||||
<view class="profile-upsell" bindtap="onGoToPremium">
|
||||
<!-- <view class="profile-upsell" bindtap="onGoToPremium">
|
||||
<van-icon
|
||||
name="gem-o"
|
||||
class="profile-upsell__deco"
|
||||
@@ -141,13 +156,73 @@
|
||||
>
|
||||
<view class="profile-upsell__btn">立即升级</view>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<view class="profile-version">
|
||||
<text class="profile-version__text"
|
||||
>Doodle Mini v{{version}}</text
|
||||
>
|
||||
<text class="profile-version__text">涂鸦丫 v{{version}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<van-popup
|
||||
show="{{showProfileEditor}}"
|
||||
position="bottom"
|
||||
round
|
||||
safe-area-inset-bottom="{{false}}"
|
||||
custom-class="profile-editor-popup"
|
||||
bind:close="onCloseProfileEditor">
|
||||
<view class="profile-editor">
|
||||
<view class="profile-editor__header">
|
||||
<text class="profile-editor__title">完善资料</text>
|
||||
<text class="profile-editor__desc"
|
||||
>选择头像并填写昵称后保存</text
|
||||
>
|
||||
</view>
|
||||
|
||||
<view class="profile-editor__avatar-section">
|
||||
<button
|
||||
class="profile-editor__avatar-button"
|
||||
open-type="chooseAvatar"
|
||||
bindchooseavatar="onChooseAvatar">
|
||||
<view class="profile-editor__avatar">
|
||||
<text
|
||||
class="profile-editor__avatar-placeholder"
|
||||
wx:if="{{!draftAvatarUrl}}"
|
||||
>选择头像</text
|
||||
>
|
||||
<image
|
||||
wx:else
|
||||
class="profile-editor__avatar-img"
|
||||
src="{{draftAvatarUrl}}"
|
||||
mode="aspectFill" />
|
||||
</view>
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<view class="profile-editor__field">
|
||||
<text class="profile-editor__label">昵称</text>
|
||||
<input
|
||||
class="profile-editor__input"
|
||||
type="nickname"
|
||||
placeholder="请输入昵称"
|
||||
maxlength="20"
|
||||
value="{{draftNickName}}"
|
||||
bindblur="onNicknameInput"
|
||||
bindinput="onNicknameInput" />
|
||||
</view>
|
||||
|
||||
<view class="profile-editor__actions">
|
||||
<view
|
||||
class="profile-editor__action profile-editor__action--ghost"
|
||||
bindtap="onCloseProfileEditor">
|
||||
取消
|
||||
</view>
|
||||
<view
|
||||
class="profile-editor__action profile-editor__action--primary {{isSavingProfile ? 'profile-editor__action--disabled' : ''}}"
|
||||
bindtap="onSubmitProfile">
|
||||
{{isSavingProfile ? '保存中...' : '保存'}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</van-popup>
|
||||
</view>
|
||||
|
||||
Reference in New Issue
Block a user