修复:解决测试发现的问题
This commit is contained in:
@@ -7,8 +7,8 @@ export const ENV = process.env.NODE_ENV || 'development';
|
|||||||
*/
|
*/
|
||||||
const BASE_URL_MAP = {
|
const BASE_URL_MAP = {
|
||||||
development: {
|
development: {
|
||||||
MAIN: 'http://192.168.110.100:9300/pb/',
|
MAIN: 'http://192.168.110.100:9300/pb/', // 张川川
|
||||||
// MAIN: 'https://global.nuttyreading.com/',
|
// MAIN: 'https://global.nuttyreading.com/', // 线上
|
||||||
// PAYMENT: 'https://dev-pay.example.com', // 暂时用不到
|
// PAYMENT: 'https://dev-pay.example.com', // 暂时用不到
|
||||||
// CDN: 'https://cdn-dev.example.com', // 暂时用不到
|
// CDN: 'https://cdn-dev.example.com', // 暂时用不到
|
||||||
},
|
},
|
||||||
@@ -24,6 +24,6 @@ export const APP_INFO = {
|
|||||||
VERSION_CODE: '1.0.0', // APP 版本号,可能升级的时候会用,这里需要再确定?
|
VERSION_CODE: '1.0.0', // APP 版本号,可能升级的时候会用,这里需要再确定?
|
||||||
}
|
}
|
||||||
|
|
||||||
export const REQUEST_TIMEOUT = 15000;
|
export const REQUEST_TIMEOUT = 30000;
|
||||||
|
|
||||||
export const SERVICE_MAP = (BASE_URL_MAP as any)[ENV] ?? BASE_URL_MAP.development;
|
export const SERVICE_MAP = (BASE_URL_MAP as any)[ENV] ?? BASE_URL_MAP.development;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// 片段示例 - requestInterceptor 更稳健的写法
|
|
||||||
import type { IRequestOptions } from '../types'
|
import type { IRequestOptions } from '../types'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
import { APP_INFO } from '@/api/config'
|
import { APP_INFO } from '@/api/config'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// api/interceptors/response.ts
|
|
||||||
import type { IApiResponse } from '../types';
|
import type { IApiResponse } from '../types';
|
||||||
|
import { t } from '@/utils/i18n'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 响应拦截器:严格兼容原项目返回约定
|
* 响应拦截器:严格兼容原项目返回约定
|
||||||
@@ -12,23 +12,24 @@ import type { IApiResponse } from '../types';
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function handleAuthExpired() {
|
function handleAuthExpired() {
|
||||||
// 清空本地登录信息(保持与原项目一致)
|
// 清空本地登录信息
|
||||||
try {
|
try {
|
||||||
uni.removeStorageSync('userInfo');
|
uni.removeStorageSync('userInfo');
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
// 跳转 login,与原项目保持一致的路径
|
// 跳转 login,与原项目保持一致的路径
|
||||||
// 在小程序/APP/H5 情况下原项目分别做了适配,简单通用处理如下:
|
uni.showToast({ title: t('global.loginExpired'), icon: 'none' });
|
||||||
uni.showToast({ title: '登录失效,请重新登录', icon: 'none' });
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.navigateTo({ url: '/pages/login/login' });
|
uni.reLaunch({ url: '/pages/login/login' });
|
||||||
}, 600);
|
}, 600);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function responseInterceptor(res: UniApp.RequestSuccessCallbackResult) {
|
export function responseInterceptor(res: UniApp.RequestSuccessCallbackResult) {
|
||||||
// 先处理非 200 的 http 状态
|
// 先处理非 200 的 http 状态
|
||||||
if (res.statusCode && res.statusCode !== 200) {
|
if (res.statusCode && res.statusCode !== 200) {
|
||||||
const msg = `网络错误(${res.statusCode})`;
|
const msg = `${t('global.networkConnectionError')} (${res.statusCode})`;
|
||||||
uni.showToast({ title: msg, icon: 'none' });
|
setTimeout(() => {
|
||||||
|
uni.showToast({ title: msg, icon: 'none' });
|
||||||
|
}, 10);
|
||||||
return Promise.reject({ statusCode: res.statusCode, errMsg: msg, response: res });
|
return Promise.reject({ statusCode: res.statusCode, errMsg: msg, response: res });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,17 +60,17 @@ export function responseInterceptor(res: UniApp.RequestSuccessCallbackResult) {
|
|||||||
if (code === '401' || code === 401) {
|
if (code === '401' || code === 401) {
|
||||||
// 触发登出流程
|
// 触发登出流程
|
||||||
handleAuthExpired();
|
handleAuthExpired();
|
||||||
return Promise.reject({ statusCode: 0, errMsg: '登录失效', data: httpData });
|
return Promise.reject({ statusCode: 0, errMsg: t('global.loginExpired'), data: httpData });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 原项目还将 1000,1001,1100,402 等视作需要强制登录
|
// 原项目还将 1000,1001,1100,402 等视作需要强制登录
|
||||||
if (code === '1000' || code === '1001' || code === 1000 || code === 1001 || code === 1100 || code === '402' || code === 402) {
|
if (code === '1000' || code === '1001' || code === 1000 || code === 1001 || code === 1100 || code === '402' || code === 402) {
|
||||||
handleAuthExpired();
|
handleAuthExpired();
|
||||||
return Promise.reject({ statusCode: 0, errMsg: message || '请登录', data: httpData });
|
return Promise.reject({ statusCode: 0, errMsg: message || t('global.loginExpired'), data: httpData });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 其他后端业务错误:toast 并 reject
|
// 其他后端业务错误:toast 并 reject
|
||||||
const errMsg = message || '请求异常';
|
const errMsg = message || t('global.requestException');
|
||||||
if (errMsg) {
|
if (errMsg) {
|
||||||
uni.showToast({ title: errMsg, icon: 'none' });
|
uni.showToast({ title: errMsg, icon: 'none' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// api/modules/auth.ts
|
|
||||||
import { mainClient } from '@/api/clients/main'
|
import { mainClient } from '@/api/clients/main'
|
||||||
import type { IApiResponse } from '@/api/types'
|
import type { IApiResponse } from '@/api/types'
|
||||||
import type { IUserInfo, ILoginResponse } from '@/types/user'
|
import type { ILoginResponse } from '@/types/user'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证码登录/注册
|
* 验证码登录/注册
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { requestInterceptor } from './interceptors/request';
|
|||||||
import { responseInterceptor } from './interceptors/response';
|
import { responseInterceptor } from './interceptors/response';
|
||||||
import type { IRequestOptions, ICreateClientConfig } from './types';
|
import type { IRequestOptions, ICreateClientConfig } from './types';
|
||||||
import { REQUEST_TIMEOUT } from './config';
|
import { REQUEST_TIMEOUT } from './config';
|
||||||
|
import { t } from '@/utils/i18n'
|
||||||
|
|
||||||
export function createRequestClient(cfg: ICreateClientConfig) {
|
export function createRequestClient(cfg: ICreateClientConfig) {
|
||||||
const baseURL = cfg.baseURL;
|
const baseURL = cfg.baseURL;
|
||||||
@@ -17,14 +18,22 @@ export function createRequestClient(cfg: ICreateClientConfig) {
|
|||||||
header: options.header || {},
|
header: options.header || {},
|
||||||
};
|
};
|
||||||
|
|
||||||
// run request interceptor to mutate headers, etc.
|
// 运行请求拦截器,修改 headers 等
|
||||||
const intercepted = requestInterceptor(final as IRequestOptions);
|
const intercepted = requestInterceptor(final as IRequestOptions);
|
||||||
|
|
||||||
|
// 全局处理请求 loading
|
||||||
|
const loading = !cfg.loading ? true : cfg.loading // 接口请求参数不传loading,默认显示loading
|
||||||
|
loading && uni.showLoading()
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
uni.request({
|
uni.request({
|
||||||
...intercepted,
|
...intercepted,
|
||||||
|
complete() {
|
||||||
|
// 请求完成关闭 loading
|
||||||
|
loading && uni.hideLoading()
|
||||||
|
},
|
||||||
success(res: any) {
|
success(res: any) {
|
||||||
// delegate to response interceptor
|
// 委托给响应拦截器处理
|
||||||
responseInterceptor(res)
|
responseInterceptor(res)
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
resolve(r as any);
|
resolve(r as any);
|
||||||
@@ -34,7 +43,7 @@ export function createRequestClient(cfg: ICreateClientConfig) {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
fail(err: any) {
|
fail(err: any) {
|
||||||
uni.showToast({ title: '网络连接失败', icon: 'none' });
|
uni.showToast({ title: t('global.networkConnectionError'), icon: 'none' });
|
||||||
reject(err);
|
reject(err);
|
||||||
},
|
},
|
||||||
} as any);
|
} as any);
|
||||||
|
|||||||
1
api/types.d.ts
vendored
1
api/types.d.ts
vendored
@@ -22,4 +22,5 @@ export interface IRequestOptions extends UniApp.RequestOptions {
|
|||||||
export interface ICreateClientConfig {
|
export interface ICreateClientConfig {
|
||||||
baseURL: string;
|
baseURL: string;
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
|
loading?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,10 @@
|
|||||||
"tips": "Tips",
|
"tips": "Tips",
|
||||||
"searchNoResult": "No search results found",
|
"searchNoResult": "No search results found",
|
||||||
"more": "More",
|
"more": "More",
|
||||||
"dataNull": "No data available"
|
"dataNull": "No data available",
|
||||||
|
"networkConnectionError": "Network connection error.",
|
||||||
|
"loginExpired": "Login expired. Please log in again.",
|
||||||
|
"requestException": "Request exception"
|
||||||
},
|
},
|
||||||
"tabar.course": "COURSE",
|
"tabar.course": "COURSE",
|
||||||
"tabar.book": "EBOOK",
|
"tabar.book": "EBOOK",
|
||||||
@@ -130,6 +133,7 @@
|
|||||||
"sex": "Gender",
|
"sex": "Gender",
|
||||||
"male": "Male",
|
"male": "Male",
|
||||||
"female": "Female",
|
"female": "Female",
|
||||||
|
"secrecy": "Secrecy",
|
||||||
"avatar": "Avatar",
|
"avatar": "Avatar",
|
||||||
"changeAvatar": "Change Avatar",
|
"changeAvatar": "Change Avatar",
|
||||||
"setAvatar": "Set Avatar",
|
"setAvatar": "Set Avatar",
|
||||||
|
|||||||
@@ -13,7 +13,10 @@
|
|||||||
"tips": "提示",
|
"tips": "提示",
|
||||||
"searchNoResult": "暂无搜索结果",
|
"searchNoResult": "暂无搜索结果",
|
||||||
"more": "更多",
|
"more": "更多",
|
||||||
"dataNull": "暂无数据"
|
"dataNull": "暂无数据",
|
||||||
|
"networkConnectionError": "网络连接错误。",
|
||||||
|
"loginExpired": "登录失效,请重新登录。",
|
||||||
|
"requestException": "请求异常"
|
||||||
},
|
},
|
||||||
"tabar.course": "课程",
|
"tabar.course": "课程",
|
||||||
"tabar.book": "图书",
|
"tabar.book": "图书",
|
||||||
@@ -131,6 +134,7 @@
|
|||||||
"sex": "性别",
|
"sex": "性别",
|
||||||
"male": "男",
|
"male": "男",
|
||||||
"female": "女",
|
"female": "女",
|
||||||
|
"secrecy": "保密",
|
||||||
"avatar": "头像",
|
"avatar": "头像",
|
||||||
"changeAvatar": "更换头像",
|
"changeAvatar": "更换头像",
|
||||||
"setAvatar": "设置头像",
|
"setAvatar": "设置头像",
|
||||||
|
|||||||
@@ -33,7 +33,8 @@
|
|||||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||||
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
|
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
|
||||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||||
"<uses-permission android:name=\"android.permission.READ_MEDIA_IMAGES\"/>"
|
"<uses-permission android:name=\"android.permission.READ_MEDIA_IMAGES\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>"
|
||||||
],
|
],
|
||||||
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ],
|
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ],
|
||||||
"minSdkVersion" : 23,
|
"minSdkVersion" : 23,
|
||||||
|
|||||||
@@ -128,7 +128,7 @@
|
|||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<wd-button type="primary" custom-class="buy-btn" @click="handlePurchase">
|
<wd-button type="primary" block @click="handlePurchase">
|
||||||
{{ $t('bookDetails.buy') }}
|
{{ $t('bookDetails.buy') }}
|
||||||
</wd-button>
|
</wd-button>
|
||||||
</view>
|
</view>
|
||||||
@@ -222,15 +222,12 @@ function initScrollHeight() {
|
|||||||
// 加载书籍详情
|
// 加载书籍详情
|
||||||
async function loadBookInfo() {
|
async function loadBookInfo() {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({ title: t('global.loading') })
|
|
||||||
const res = await bookApi.getBookInfo(bookId.value)
|
const res = await bookApi.getBookInfo(bookId.value)
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
if (res.bookInfo) {
|
if (res.bookInfo) {
|
||||||
bookInfo.value = res.bookInfo
|
bookInfo.value = res.bookInfo
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading()
|
|
||||||
console.error('Failed to load book info:', error)
|
console.error('Failed to load book info:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -531,6 +528,7 @@ function goToDetail(id: number) {
|
|||||||
&.buy-full {
|
&.buy-full {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 0 30rpx;
|
padding: 0 30rpx;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -330,7 +330,6 @@ const getBooksByLabel = async (
|
|||||||
labelId: number,
|
labelId: number,
|
||||||
type: 'activity' | 'category'
|
type: 'activity' | 'category'
|
||||||
) => {
|
) => {
|
||||||
uni.showLoading({ title: t('common.loading') })
|
|
||||||
try {
|
try {
|
||||||
const res = await homeApi.getBooksByLabel(labelId)
|
const res = await homeApi.getBooksByLabel(labelId)
|
||||||
if (type === 'activity') {
|
if (type === 'activity') {
|
||||||
@@ -348,8 +347,6 @@ const getBooksByLabel = async (
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取图书列表失败:', error)
|
console.error('获取图书列表失败:', error)
|
||||||
} finally {
|
|
||||||
uni.hideLoading()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -130,11 +130,9 @@ async function loadBookInfo() {
|
|||||||
// 加载章节列表
|
// 加载章节列表
|
||||||
async function loadChapterList() {
|
async function loadChapterList() {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({ title: t('global.loading') })
|
|
||||||
const res = await bookApi.getBookChapter({
|
const res = await bookApi.getBookChapter({
|
||||||
bookId: bookId.value
|
bookId: bookId.value
|
||||||
})
|
})
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
if (res.chapterList && res.chapterList.length > 0) {
|
if (res.chapterList && res.chapterList.length > 0) {
|
||||||
chapterList.value = res.chapterList
|
chapterList.value = res.chapterList
|
||||||
@@ -142,7 +140,6 @@ async function loadChapterList() {
|
|||||||
nullText.value = t('common.data_null')
|
nullText.value = t('common.data_null')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading()
|
|
||||||
nullText.value = t('common.data_null')
|
nullText.value = t('common.data_null')
|
||||||
console.error('Failed to load chapter list:', error)
|
console.error('Failed to load chapter list:', error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,8 +258,6 @@ async function loadBookInfo() {
|
|||||||
// 加载章节列表
|
// 加载章节列表
|
||||||
async function loadChapterList() {
|
async function loadChapterList() {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({ title: t('common.loading') })
|
|
||||||
|
|
||||||
const res = await bookApi.getBookChapter({
|
const res = await bookApi.getBookChapter({
|
||||||
bookId: bookId.value
|
bookId: bookId.value
|
||||||
})
|
})
|
||||||
@@ -269,8 +267,6 @@ async function loadChapterList() {
|
|||||||
if (res.chapterList && res.chapterList.length > 0) {
|
if (res.chapterList && res.chapterList.length > 0) {
|
||||||
chapterList.value = res.chapterList
|
chapterList.value = res.chapterList
|
||||||
|
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
// 加载当前章节内容
|
// 加载当前章节内容
|
||||||
if (currentChapterIndex.value < chapterList.value.length) {
|
if (currentChapterIndex.value < chapterList.value.length) {
|
||||||
const currentChapter = chapterList.value[currentChapterIndex.value]
|
const currentChapter = chapterList.value[currentChapterIndex.value]
|
||||||
@@ -280,14 +276,12 @@ async function loadChapterList() {
|
|||||||
playChapter(currentChapter)
|
playChapter(currentChapter)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '章节列表为空',
|
title: '章节列表为空',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading()
|
|
||||||
console.error('Failed to load chapter list:', error)
|
console.error('Failed to load chapter list:', error)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '加载章节失败',
|
title: '加载章节失败',
|
||||||
@@ -298,9 +292,7 @@ async function loadChapterList() {
|
|||||||
|
|
||||||
// 加载章节内容(带音频时间点)
|
// 加载章节内容(带音频时间点)
|
||||||
async function loadChapterContent(chapterId: number) {
|
async function loadChapterContent(chapterId: number) {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({ title: t('common.loading') })
|
|
||||||
|
|
||||||
console.log('加载章节内容, chapterId:', chapterId)
|
console.log('加载章节内容, chapterId:', chapterId)
|
||||||
const res = await bookApi.getChapterContentListen(chapterId)
|
const res = await bookApi.getChapterContentListen(chapterId)
|
||||||
console.log('章节内容响应:', res)
|
console.log('章节内容响应:', res)
|
||||||
@@ -327,11 +319,8 @@ async function loadChapterContent(chapterId: number) {
|
|||||||
console.log('章节内容为空')
|
console.log('章节内容为空')
|
||||||
currentContent.value = '暂无内容'
|
currentContent.value = '暂无内容'
|
||||||
}
|
}
|
||||||
|
|
||||||
uni.hideLoading()
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to load chapter content:', error)
|
console.error('Failed to load chapter content:', error)
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '加载内容失败',
|
title: '加载内容失败',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
@@ -364,7 +353,6 @@ function playChapter(chapter: IChapter) {
|
|||||||
|
|
||||||
if (audioContext.value) {
|
if (audioContext.value) {
|
||||||
console.log('设置音频源:', chapter.voices)
|
console.log('设置音频源:', chapter.voices)
|
||||||
uni.showLoading({ title: t('common.readAudio') })
|
|
||||||
|
|
||||||
audioContext.value.src = chapter.voices
|
audioContext.value.src = chapter.voices
|
||||||
audioContext.value.playbackRate = playbackRate.value
|
audioContext.value.playbackRate = playbackRate.value
|
||||||
@@ -372,7 +360,6 @@ function playChapter(chapter: IChapter) {
|
|||||||
// 监听音频准备就绪
|
// 监听音频准备就绪
|
||||||
audioContext.value.onCanplay(() => {
|
audioContext.value.onCanplay(() => {
|
||||||
console.log('音频准备就绪')
|
console.log('音频准备就绪')
|
||||||
uni.hideLoading()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
audioContext.value.play()
|
audioContext.value.play()
|
||||||
|
|||||||
0
pages/book/order.vue
Normal file
0
pages/book/order.vue
Normal file
@@ -2,12 +2,27 @@
|
|||||||
<view class="reader-page" :class="themeClass">
|
<view class="reader-page" :class="themeClass">
|
||||||
<!-- 顶部标题栏 (可隐藏) -->
|
<!-- 顶部标题栏 (可隐藏) -->
|
||||||
<view class="reader-header" :style="{ top: notchHeight + 'px' }">
|
<view class="reader-header" :style="{ top: notchHeight + 'px' }">
|
||||||
<wd-icon name="arrow-left" size="20px" @click="goBack" />
|
<wd-icon name="arrow-left" size="20px" @click="onPageBack" />
|
||||||
<text class="chapter-title">{{ currentChapterTitle }}</text>
|
<text class="chapter-title">{{ currentChapterTitle }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 阅读内容区域 -->
|
<!-- 阅读内容区域 -->
|
||||||
<view class="reader-content" @click="toggleControls">
|
<view class="reader-content" @click="toggleControls">
|
||||||
|
<!-- 仿真翻页 -->
|
||||||
|
<!-- <view class="content-wrapper">
|
||||||
|
<nx-turn
|
||||||
|
:initPage="0"
|
||||||
|
:pageCount="4"
|
||||||
|
>
|
||||||
|
<template v-slot:page-content="{ page }">
|
||||||
|
<text>{{ page }}</text>
|
||||||
|
</template>
|
||||||
|
<template v-slot:next-page-content="{ page }">
|
||||||
|
<text>{{ page }}</text>
|
||||||
|
</template>
|
||||||
|
</nx-turn>
|
||||||
|
</view> -->
|
||||||
|
|
||||||
<!-- 左右翻页模式 -->
|
<!-- 左右翻页模式 -->
|
||||||
<view
|
<view
|
||||||
v-if="readMode === 'page'"
|
v-if="readMode === 'page'"
|
||||||
@@ -37,9 +52,9 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 页码指示器 -->
|
<!-- 页码指示器 -->
|
||||||
<view v-show="showControls" class="page-indicator">
|
<!-- <view v-show="showControls" class="page-indicator">
|
||||||
{{ currentPage }} / {{ totalPages }}
|
{{ currentPage }} / {{ totalPages }}
|
||||||
</view>
|
</view> -->
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 上下滚动模式 -->
|
<!-- 上下滚动模式 -->
|
||||||
@@ -99,8 +114,6 @@
|
|||||||
<wd-icon v-if="isLocked(index)" name="lock" size="20px" />
|
<wd-icon v-if="isLocked(index)" name="lock" size="20px" />
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
<!-- 底部占位 -->
|
|
||||||
<view class="setting-ooter-placeholder"></view>
|
|
||||||
</view>
|
</view>
|
||||||
</wd-popup>
|
</wd-popup>
|
||||||
|
|
||||||
@@ -165,13 +178,11 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 底部占位 -->
|
|
||||||
<view class="setting-ooter-placeholder"></view>
|
|
||||||
</wd-popup>
|
</wd-popup>
|
||||||
|
|
||||||
<!-- 空状态 -->
|
<!-- 空状态 -->
|
||||||
<view v-if="chapterList.length === 0 && !loading" class="empty-state">
|
<view v-if="chapterList.length === 0 && !loading" class="empty-state">
|
||||||
<text>{{ nullStatus }}</text>
|
<text>{{ $t('common.data_null') }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -183,6 +194,7 @@ import { useI18n } from 'vue-i18n'
|
|||||||
import { useBookStore } from '@/stores/book'
|
import { useBookStore } from '@/stores/book'
|
||||||
import { bookApi } from '@/api/modules/book'
|
import { bookApi } from '@/api/modules/book'
|
||||||
import type { IChapter, IChapterContent, IReadProgress } from '@/types/book'
|
import type { IChapter, IChapterContent, IReadProgress } from '@/types/book'
|
||||||
|
import { onPageBack } from '@/utils/index'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const bookStore = useBookStore()
|
const bookStore = useBookStore()
|
||||||
@@ -199,7 +211,6 @@ const currentChapterIndex = ref(0)
|
|||||||
const currentChapterId = ref(0)
|
const currentChapterId = ref(0)
|
||||||
const currentContentId = ref(0)
|
const currentContentId = ref(0)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const nullStatus = ref('')
|
|
||||||
|
|
||||||
// 阅读设置
|
// 阅读设置
|
||||||
const fontSizeLevel = ref(1)
|
const fontSizeLevel = ref(1)
|
||||||
@@ -260,7 +271,6 @@ const currentChapterTitle = computed(() => {
|
|||||||
return chapter.chapter + (chapter.content ? ' - ' + chapter.content : '')
|
return chapter.chapter + (chapter.content ? ' - ' + chapter.content : '')
|
||||||
})
|
})
|
||||||
|
|
||||||
// 生命周期
|
|
||||||
onLoad((options: any) => {
|
onLoad((options: any) => {
|
||||||
if (options.bookId) bookId.value = Number(options.bookId)
|
if (options.bookId) bookId.value = Number(options.bookId)
|
||||||
if (options.isBuy) isBuy.value = options.isBuy
|
if (options.isBuy) isBuy.value = options.isBuy
|
||||||
@@ -290,20 +300,23 @@ onShow(() => {
|
|||||||
}, 300)
|
}, 300)
|
||||||
} else {
|
} else {
|
||||||
currentPage.value = 1
|
currentPage.value = 1
|
||||||
calculatePages()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initHeights()
|
initHeights()
|
||||||
|
calculatePages()
|
||||||
})
|
})
|
||||||
|
|
||||||
onHide(() => {
|
onHide(() => {
|
||||||
saveProgress()
|
saveProgress()
|
||||||
|
console.log('onHide')
|
||||||
})
|
})
|
||||||
|
|
||||||
onBackPress(() => {
|
onBackPress(() => {
|
||||||
saveProgress()
|
saveProgress()
|
||||||
|
console.log('onBackPress')
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -313,7 +326,7 @@ function initHeights() {
|
|||||||
const windowHeight = systemInfo.windowHeight
|
const windowHeight = systemInfo.windowHeight
|
||||||
|
|
||||||
// 翻页模式高度
|
// 翻页模式高度
|
||||||
const math = Math.floor((windowHeight - (notchHeight.value + 130)) / lineHeight.value)
|
const math = Math.floor((windowHeight - (notchHeight.value + 80)) / lineHeight.value)
|
||||||
wrapHeight.value = math * lineHeight.value
|
wrapHeight.value = math * lineHeight.value
|
||||||
|
|
||||||
// 滚动模式高度
|
// 滚动模式高度
|
||||||
@@ -359,11 +372,8 @@ async function loadChapterList() {
|
|||||||
|
|
||||||
// 默认加载第一章
|
// 默认加载第一章
|
||||||
await loadChapterContent(chapterList.value[0].id, 0)
|
await loadChapterContent(chapterList.value[0].id, 0)
|
||||||
} else {
|
|
||||||
nullStatus.value = t('common.data_null')
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
nullStatus.value = t('common.data_null')
|
|
||||||
console.error('Failed to load chapter list:', error)
|
console.error('Failed to load chapter list:', error)
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
@@ -373,9 +383,7 @@ async function loadChapterList() {
|
|||||||
// 加载章节内容
|
// 加载章节内容
|
||||||
async function loadChapterContent(chapterId: number, index: number) {
|
async function loadChapterContent(chapterId: number, index: number) {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({ title: t('global.loading') })
|
|
||||||
const res = await bookApi.getChapterContent(chapterId)
|
const res = await bookApi.getChapterContent(chapterId)
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
if (res.contentPage && res.contentPage.length > 0) {
|
if (res.contentPage && res.contentPage.length > 0) {
|
||||||
contentList.value = res.contentPage
|
contentList.value = res.contentPage
|
||||||
@@ -402,7 +410,6 @@ async function loadChapterContent(chapterId: number, index: number) {
|
|||||||
catalogVisible.value = false
|
catalogVisible.value = false
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading()
|
|
||||||
console.error('Failed to load chapter content:', error)
|
console.error('Failed to load chapter content:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -524,6 +531,7 @@ function toggleControls() {
|
|||||||
function showCatalog() {
|
function showCatalog() {
|
||||||
catalogVisible.value = true
|
catalogVisible.value = true
|
||||||
settingsVisible.value = false
|
settingsVisible.value = false
|
||||||
|
showControls.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭目录
|
// 关闭目录
|
||||||
@@ -534,9 +542,9 @@ function closeCatalog() {
|
|||||||
|
|
||||||
// 显示设置
|
// 显示设置
|
||||||
function showSettings() {
|
function showSettings() {
|
||||||
console.log('currentLanguage', currentLanguage.value)
|
|
||||||
settingsVisible.value = true
|
settingsVisible.value = true
|
||||||
catalogVisible.value = false
|
catalogVisible.value = false
|
||||||
|
showControls.value = false
|
||||||
}
|
}
|
||||||
// 关闭设置
|
// 关闭设置
|
||||||
function closeSettings() {
|
function closeSettings() {
|
||||||
@@ -615,21 +623,12 @@ const changeBookLanguage = (language: any) => {
|
|||||||
|
|
||||||
// 保存进度
|
// 保存进度
|
||||||
async function saveProgress() {
|
async function saveProgress() {
|
||||||
if (isBuy.value === '0') {
|
try {
|
||||||
try {
|
await bookApi.saveReadProgress(bookId.value, currentChapterId.value, currentContentId.value)
|
||||||
await bookApi.saveReadProgress(bookId.value, currentChapterId.value, currentContentId.value)
|
} catch (error) {
|
||||||
} catch (error) {
|
console.error('Failed to save progress:', error)
|
||||||
console.error('Failed to save progress:', error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回
|
|
||||||
function goBack() {
|
|
||||||
uni.navigateTo({
|
|
||||||
url: '/pages/book/detail?id=' + bookId.value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -885,10 +884,5 @@ function goBack() {
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 底部占位 */
|
|
||||||
.setting-ooter-placeholder {
|
|
||||||
height: 55px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -181,9 +181,7 @@ async function loadComments() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
uni.showLoading({ title: t('global.loading') })
|
|
||||||
const res = await bookApi.getBookComments(bookId.value, page.value.current, page.value.limit)
|
const res = await bookApi.getBookComments(bookId.value, page.value.current, page.value.limit)
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
commentsCount.value = res.commentsCount || 0
|
commentsCount.value = res.commentsCount || 0
|
||||||
|
|
||||||
@@ -194,7 +192,6 @@ async function loadComments() {
|
|||||||
nullText.value = t('common.data_null')
|
nullText.value = t('common.data_null')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading()
|
|
||||||
nullText.value = t('common.data_null')
|
nullText.value = t('common.data_null')
|
||||||
console.error('Failed to load comments:', error)
|
console.error('Failed to load comments:', error)
|
||||||
}
|
}
|
||||||
@@ -472,7 +469,7 @@ function toggleEmoji() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.editor {
|
.editor {
|
||||||
border: 1rpx solid #ddd;
|
border: 1px solid #ddd;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 200rpx;
|
min-height: 200rpx;
|
||||||
height: 200rpx;
|
height: 200rpx;
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view class="container">
|
|
||||||
<no-data></no-data>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
title: this.$t('')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
@@ -192,16 +192,13 @@ const getCode = async () => {
|
|||||||
if (!isEmailVerified(email.value)) return
|
if (!isEmailVerified(email.value)) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
uni.showLoading()
|
|
||||||
await commonApi.sendMailCaptcha(email.value)
|
await commonApi.sendMailCaptcha(email.value)
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: t('login.sendCodeSuccess'),
|
title: t('login.sendCodeSuccess'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
getCodeState()
|
getCodeState()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading()
|
|
||||||
console.error('Send code error:', error)
|
console.error('Send code error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,9 +265,7 @@ const onSubmit = async () => {
|
|||||||
if (!isPasswordMatch()) return
|
if (!isPasswordMatch()) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
uni.showLoading()
|
|
||||||
await resetPassword(email.value, code.value, password.value)
|
await resetPassword(email.value, code.value, password.value)
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: t('global.tips'),
|
title: t('global.tips'),
|
||||||
@@ -281,7 +276,6 @@ const onSubmit = async () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading()
|
|
||||||
console.error('Reset password error:', error)
|
console.error('Reset password error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,11 +115,11 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 游客体验 -->
|
<!-- 游客体验 -->
|
||||||
<view class="youke-l">
|
<!-- <view class="youke-l">
|
||||||
<view @click="onPageJump('/pages/visitor/visitor')">
|
<view @click="onPageJump('/pages/visitor/visitor')">
|
||||||
{{ $t('login.noLogin') }}
|
{{ $t('login.noLogin') }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view> -->
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 用户协议弹窗 -->
|
<!-- 用户协议弹窗 -->
|
||||||
@@ -357,16 +357,13 @@ const onSetCode = async () => {
|
|||||||
if (!isEmailVerified(email.value)) return false
|
if (!isEmailVerified(email.value)) return false
|
||||||
|
|
||||||
try {
|
try {
|
||||||
uni.showLoading()
|
|
||||||
await commonApi.sendMailCaptcha(email.value)
|
await commonApi.sendMailCaptcha(email.value)
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: t('login.sendCodeSuccess'),
|
title: t('login.sendCodeSuccess'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
getCodeState()
|
getCodeState()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading()
|
|
||||||
submitClickNum.value++ // 发送验证码失败时增加提交点击次数
|
submitClickNum.value++ // 发送验证码失败时增加提交点击次数
|
||||||
console.error('Send code error:', error)
|
console.error('Send code error:', error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,10 +36,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view> -->
|
</view> -->
|
||||||
<wd-cell-group border class="contact-info">
|
<wd-cell-group border class="contact-info">
|
||||||
<wd-cell :title="$t('user.hotline')" clickable @click="handlePhoneCall">
|
<wd-cell :title="$t('user.hotline')" clickable icon="call" value="022-24142321" @click="handlePhoneCall"></wd-cell>
|
||||||
022-24142321
|
|
||||||
<img src="/static/icon/tel.png" width="23" height="23" />
|
|
||||||
</wd-cell>
|
|
||||||
<!-- <wd-cell :title="$t('user.wechat')" value="yilujiankangkefu" clickable @click="handlePhoneCall" /> -->
|
<!-- <wd-cell :title="$t('user.wechat')" value="yilujiankangkefu" clickable @click="handlePhoneCall" /> -->
|
||||||
</wd-cell-group>
|
</wd-cell-group>
|
||||||
|
|
||||||
@@ -86,7 +83,7 @@ const getAppVersion = () => {
|
|||||||
* 拨打电话
|
* 拨打电话
|
||||||
*/
|
*/
|
||||||
const handlePhoneCall = () => {
|
const handlePhoneCall = () => {
|
||||||
makePhoneCall('022-24142321', t('user.hotline'), t)
|
makePhoneCall('022-24142321', t('user.hotline'))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<wd-select-picker
|
<wd-select-picker
|
||||||
v-model="form.type"
|
v-model="form.type"
|
||||||
type="radio"
|
type="radio"
|
||||||
|
style="border-bottom: 1px solid #ddd;"
|
||||||
:columns="issueTypeOptions"
|
:columns="issueTypeOptions"
|
||||||
:placeholder="$t('common.pleaseSelect')"
|
:placeholder="$t('common.pleaseSelect')"
|
||||||
:show-confirm="false"
|
:show-confirm="false"
|
||||||
@@ -227,8 +228,6 @@ const handleSubmit = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
uni.showLoading()
|
|
||||||
|
|
||||||
// 处理图片
|
// 处理图片
|
||||||
if (imageUrl.value.length > 0) {
|
if (imageUrl.value.length > 0) {
|
||||||
form.value.image = imageUrl.value.join(',')
|
form.value.image = imageUrl.value.join(',')
|
||||||
@@ -236,8 +235,6 @@ const handleSubmit = async () => {
|
|||||||
|
|
||||||
// 提交反馈
|
// 提交反馈
|
||||||
await submitFeedback(form.value)
|
await submitFeedback(form.value)
|
||||||
|
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: t('global.tips'),
|
title: t('global.tips'),
|
||||||
@@ -265,7 +262,6 @@ const handleSubmit = async () => {
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('提交反馈失败:', error)
|
console.error('提交反馈失败:', error)
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: t('user.feedbackFailed'),
|
title: t('user.feedbackFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="user-page">
|
<view class="user-page" :style="{ paddingTop: getNotchHeight() + 30 + 'px' }">
|
||||||
<!-- 设置图标 -->
|
<!-- 设置图标 -->
|
||||||
<view class="settings-icon" @click="goSettings">
|
<view class="settings-icon" :style="{ top: getNotchHeight() + 30 + 'px' }" @click="goSettings">
|
||||||
<wd-icon name="setting1" size="24px" color="#666" />
|
<wd-icon name="setting1" size="24px" color="#666" />
|
||||||
<text>{{ $t('user.settings') }}</text>
|
<text>{{ $t('user.settings') }}</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -27,7 +27,8 @@
|
|||||||
<!-- VIP订阅卡片 -->
|
<!-- VIP订阅卡片 -->
|
||||||
<view class="vip-card-section">
|
<view class="vip-card-section">
|
||||||
<view class="vip-card">
|
<view class="vip-card">
|
||||||
<view v-if="vipInfo.id" class="vip-info">
|
用户VIP功能重写中。。。
|
||||||
|
<!-- <view v-if="vipInfo.id" class="vip-info">
|
||||||
<text class="label">{{ $t('user.vip') }}</text>
|
<text class="label">{{ $t('user.vip') }}</text>
|
||||||
<text class="value">{{ vipInfo.endTime ? vipInfo.endTime.split(' ')[0] : '' }}</text>
|
<text class="value">{{ vipInfo.endTime ? vipInfo.endTime.split(' ')[0] : '' }}</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -38,7 +39,16 @@
|
|||||||
@click="goSubscribe"
|
@click="goSubscribe"
|
||||||
>
|
>
|
||||||
{{ $t('user.subscribe') }}
|
{{ $t('user.subscribe') }}
|
||||||
</wd-button>
|
</wd-button> -->
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 我的资产 -->
|
||||||
|
<view class="vip-card-section wallet-section">
|
||||||
|
<view class="vip-card wallet_l">
|
||||||
|
我的资产功能重写中。。。
|
||||||
|
<!-- <text class="wallet_title">{{$t('my.coin')}}<uni-icons type="help" size="19" color="#666"></uni-icons></text>
|
||||||
|
<text class="wallet_count">{{userMes.peanutCoin}}</text> -->
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -65,6 +75,7 @@ import { useUserStore } from '@/stores/user'
|
|||||||
import { getUserInfo, getVipInfo } from '@/api/modules/user'
|
import { getUserInfo, getVipInfo } from '@/api/modules/user'
|
||||||
import type { IVipInfo } from '@/types/user'
|
import type { IVipInfo } from '@/types/user'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { getNotchHeight } from '@/utils/system'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
@@ -205,13 +216,11 @@ $theme-color: #54a966;
|
|||||||
.user-page {
|
.user-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background-color: #f7faf9;
|
background-color: #f7faf9;
|
||||||
padding-top: 130rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-icon {
|
.settings-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 40rpx;
|
right: 20px;
|
||||||
top: 60rpx;
|
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -98,11 +98,9 @@ async function loadBookList() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loading.value = true
|
loading.value = true
|
||||||
uni.showLoading({ title: t('global.loading') })
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await bookApi.getMyBooks(page.value.current, page.value.limit)
|
const res = await bookApi.getMyBooks(page.value.current, page.value.limit)
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
if (res.page && res.page.records) {
|
if (res.page && res.page.records) {
|
||||||
total.value = res.page.total
|
total.value = res.page.total
|
||||||
@@ -115,7 +113,6 @@ async function loadBookList() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading()
|
|
||||||
console.error('Failed to load book list:', error)
|
console.error('Failed to load book list:', error)
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
|||||||
@@ -112,13 +112,8 @@ const getData = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
uni.showLoading({
|
|
||||||
title: t('common.loading')
|
|
||||||
})
|
|
||||||
|
|
||||||
const res = await getOrderList(page.value.current, page.value.limit)
|
const res = await getOrderList(page.value.current, page.value.limit)
|
||||||
|
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
if (res.orders && res.orders.records) {
|
if (res.orders && res.orders.records) {
|
||||||
total.value = res.orders.total
|
total.value = res.orders.total
|
||||||
@@ -139,7 +134,6 @@ const getData = async () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取订单列表失败:', error)
|
console.error('获取订单列表失败:', error)
|
||||||
uni.hideLoading()
|
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
@click="editField(field)"
|
@click="editField(field)"
|
||||||
>
|
>
|
||||||
<view class="value-wrapper">
|
<view class="value-wrapper">
|
||||||
<text v-if="userInfo[field.key]" class="value">
|
<text v-if="userInfo[field.key] || userInfo[field.key] === 0" class="value">
|
||||||
{{ formatValue(field, userInfo[field.key]) }}
|
{{ formatValue(field, userInfo[field.key]) }}
|
||||||
</text>
|
</text>
|
||||||
<text v-else class="placeholder">{{ $t('user.notSet') }}</text>
|
<text v-else class="placeholder">{{ $t('user.notSet') }}</text>
|
||||||
@@ -163,7 +163,8 @@ const fields = computed(() => [
|
|||||||
// 性别选项
|
// 性别选项
|
||||||
const sexOptions = [
|
const sexOptions = [
|
||||||
{ label: t('user.male'), value: 1 },
|
{ label: t('user.male'), value: 1 },
|
||||||
{ label: t('user.female'), value: 2 }
|
{ label: t('user.female'), value: 0 },
|
||||||
|
{ label: t('user.secrecy'), value: 2 },
|
||||||
]
|
]
|
||||||
|
|
||||||
// 编辑相关
|
// 编辑相关
|
||||||
@@ -198,10 +199,8 @@ const avatarUrl = ref('')
|
|||||||
*/
|
*/
|
||||||
const userInfo = ref<any>({}) // 用户信息
|
const userInfo = ref<any>({}) // 用户信息
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
uni.showLoading()
|
|
||||||
try {
|
try {
|
||||||
const res = await getUserInfo()
|
const res = await getUserInfo()
|
||||||
uni.hideLoading()
|
|
||||||
if (res.result) {
|
if (res.result) {
|
||||||
userStore.setUserInfo(res.result)
|
userStore.setUserInfo(res.result)
|
||||||
userInfo.value = res.result
|
userInfo.value = res.result
|
||||||
@@ -216,7 +215,22 @@ const getData = async () => {
|
|||||||
*/
|
*/
|
||||||
const formatValue = (field: any, value: any) => {
|
const formatValue = (field: any, value: any) => {
|
||||||
if (field.key === 'sex') {
|
if (field.key === 'sex') {
|
||||||
return value === 1 ? t('user.male') : t('user.female')
|
let result = null
|
||||||
|
switch(value) {
|
||||||
|
case 1:
|
||||||
|
result = t('user.male')
|
||||||
|
break
|
||||||
|
case 0:
|
||||||
|
result = t('user.female')
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
result = t('user.secrecy')
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
result = null
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
if (field.key === 'password') {
|
if (field.key === 'password') {
|
||||||
return '******'
|
return '******'
|
||||||
@@ -385,8 +399,6 @@ const handleSubmit = async () => {
|
|||||||
const key = currentField.value?.key
|
const key = currentField.value?.key
|
||||||
|
|
||||||
try {
|
try {
|
||||||
uni.showLoading()
|
|
||||||
|
|
||||||
// 构建更新数据对象
|
// 构建更新数据对象
|
||||||
let updateData: any = Object.assign({}, userInfo.value)
|
let updateData: any = Object.assign({}, userInfo.value)
|
||||||
|
|
||||||
@@ -394,7 +406,6 @@ const handleSubmit = async () => {
|
|||||||
case 'email':
|
case 'email':
|
||||||
// 更新邮箱
|
// 更新邮箱
|
||||||
if (!editForm.value.email || !editForm.value.code) {
|
if (!editForm.value.email || !editForm.value.code) {
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: t('user.pleaseInputCode'),
|
title: t('user.pleaseInputCode'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
@@ -407,7 +418,6 @@ const handleSubmit = async () => {
|
|||||||
case 'password':
|
case 'password':
|
||||||
// 更新密码
|
// 更新密码
|
||||||
if (!passwordOk.value) {
|
if (!passwordOk.value) {
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: passwordNote.value,
|
title: passwordNote.value,
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
@@ -415,7 +425,6 @@ const handleSubmit = async () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (editForm.value.password !== editForm.value.confirmPassword) {
|
if (editForm.value.password !== editForm.value.confirmPassword) {
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: t('user.passwordNotMatch'),
|
title: t('user.passwordNotMatch'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
@@ -429,7 +438,6 @@ const handleSubmit = async () => {
|
|||||||
// 更新头像
|
// 更新头像
|
||||||
console.log('avatarUrl.value:', avatarUrl.value)
|
console.log('avatarUrl.value:', avatarUrl.value)
|
||||||
if (!avatarUrl.value) {
|
if (!avatarUrl.value) {
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: t('common.pleaseSelect') + t('user.avatar'),
|
title: t('common.pleaseSelect') + t('user.avatar'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
@@ -444,8 +452,7 @@ const handleSubmit = async () => {
|
|||||||
|
|
||||||
case 'sex':
|
case 'sex':
|
||||||
// 更新性别
|
// 更新性别
|
||||||
const sexValue = editValue.value === 2 ? 0 : editValue.value
|
updateData.sex = editValue.value
|
||||||
updateData.sex = sexValue
|
|
||||||
await updateUserInfo(updateData)
|
await updateUserInfo(updateData)
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -463,7 +470,6 @@ const handleSubmit = async () => {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: t('user.updateSuccess'),
|
title: t('user.updateSuccess'),
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
@@ -477,7 +483,6 @@ const handleSubmit = async () => {
|
|||||||
}, 500)
|
}, 500)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('更新失败:', error)
|
console.error('更新失败:', error)
|
||||||
uni.hideLoading()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -142,13 +142,7 @@ const getPlatform = () => {
|
|||||||
*/
|
*/
|
||||||
const getPackages = async () => {
|
const getPackages = async () => {
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
|
||||||
title: t('common.loading')
|
|
||||||
})
|
|
||||||
|
|
||||||
const res = await getVipPackages()
|
const res = await getVipPackages()
|
||||||
|
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
if (res.sysDictDatas && res.sysDictDatas.length > 0) {
|
if (res.sysDictDatas && res.sysDictDatas.length > 0) {
|
||||||
packages.value = res.sysDictDatas
|
packages.value = res.sysDictDatas
|
||||||
@@ -163,7 +157,6 @@ const getPackages = async () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取套餐列表失败:', error)
|
console.error('获取套餐列表失败:', error)
|
||||||
uni.hideLoading()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,10 +239,6 @@ const handleSubscribe = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
uni.showLoading({
|
|
||||||
title: t('common.loading')
|
|
||||||
})
|
|
||||||
|
|
||||||
// 创建订单
|
// 创建订单
|
||||||
const orderData = {
|
const orderData = {
|
||||||
paymentMethod: paymentMethod.value,
|
paymentMethod: paymentMethod.value,
|
||||||
@@ -273,7 +262,6 @@ const handleSubscribe = async () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('创建订单失败:', error)
|
console.error('创建订单失败:', error)
|
||||||
uni.hideLoading()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,7 +271,6 @@ const handleSubscribe = async () => {
|
|||||||
const initiateGooglePay = async () => {
|
const initiateGooglePay = async () => {
|
||||||
// TODO: 集成 Google Pay SDK
|
// TODO: 集成 Google Pay SDK
|
||||||
// 这里需要使用 sn-googlepay5 插件
|
// 这里需要使用 sn-googlepay5 插件
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: 'Google Pay 功能开发中',
|
title: 'Google Pay 功能开发中',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
@@ -295,7 +282,6 @@ const initiateGooglePay = async () => {
|
|||||||
*/
|
*/
|
||||||
const initiateIAP = async () => {
|
const initiateIAP = async () => {
|
||||||
// TODO: 集成 IAP SDK
|
// TODO: 集成 IAP SDK
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: 'IAP 功能开发中',
|
title: 'IAP 功能开发中',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
|
|||||||
@@ -91,20 +91,14 @@ const getData = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
uni.showLoading({
|
|
||||||
title: t('common.loading')
|
|
||||||
})
|
|
||||||
|
|
||||||
const res = await getTransactionList(userStore.userInfo.id)
|
const res = await getTransactionList(userStore.userInfo.id)
|
||||||
|
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
if (res.transactionDetailsList && res.transactionDetailsList.length > 0) {
|
if (res.transactionDetailsList && res.transactionDetailsList.length > 0) {
|
||||||
transactionList.value = res.transactionDetailsList
|
transactionList.value = res.transactionDetailsList
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取交易记录失败:', error)
|
console.error('获取交易记录失败:', error)
|
||||||
uni.hideLoading()
|
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { t } from '@/utils/i18n'
|
||||||
/**
|
/**
|
||||||
* 页面跳转
|
* 页面跳转
|
||||||
*/
|
*/
|
||||||
@@ -7,10 +8,17 @@ export const onPageJump = (path: string) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面返回
|
||||||
|
*/
|
||||||
|
export const onPageBack = () => {
|
||||||
|
uni.navigateBack()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拨打电话
|
* 拨打电话
|
||||||
*/
|
*/
|
||||||
export const makePhoneCall = (phoneNumber: string, title: string, t: Function) => {
|
export const makePhoneCall = (phoneNumber: string, title: string) => {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: title,
|
title: title,
|
||||||
content: phoneNumber,
|
content: phoneNumber,
|
||||||
|
|||||||
@@ -51,4 +51,12 @@ export const getNavbarHeight2 = () => {
|
|||||||
|
|
||||||
const totalHeight = statusBarHeight.value + navBarHeight
|
const totalHeight = statusBarHeight.value + navBarHeight
|
||||||
navbarHeight.value = totalHeight + 'px'
|
navbarHeight.value = totalHeight + 'px'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取屏幕刘海高度
|
||||||
|
*/
|
||||||
|
export const getNotchHeight = () => {
|
||||||
|
const systemInfo = uni.getSystemInfoSync()
|
||||||
|
return systemInfo.safeArea?.top || 0
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user