chore: 以本地工作区为准全量快照同步 GitHub

包含小程序、管理端、soul-api、脚本与静态资源等当前本地全部已跟踪与新增文件(排除 .DS_Store 与 .obsidian)。

Made-with: Cursor
This commit is contained in:
卡若
2026-04-13 11:49:38 +08:00
parent 83375cc388
commit b5f5180654
142 changed files with 10684 additions and 2670 deletions

View File

@@ -10,13 +10,11 @@ const mpPagePopups = require('./utils/mpPagePopups.js')
const DEFAULT_APP_ID = 'wxb8bbb2b10dec74aa'
const DEFAULT_MCH_ID = '1318592501'
const DEFAULT_WITHDRAW_TMPL_ID = 'u3MbZGPRkrZIk-I7QdpwzFxnO_CeQPaCWF2FkiIablE'
// 线上正式域名(真机/体验版/正式版强制使用此地址)
// const API_BASE_URL_PROD = 'https://soulapi.quwanzhi.com'
const API_BASE_URL_PROD = 'https://souldev.quwanzhi.com'
// 线上正式 API(真机/体验版/正式版)。永平仓库默认正式域;部署前核对见 .cursor/skills/security-server-ops/SKILL.md
const API_BASE_URL_PROD = 'https://soulapi.quwanzhi.com'
// 本地开发地址(仅开发者工具模拟器生效;真机自动回退 PROD
// const API_BASE_URL_DEV = 'http://127.0.0.1:9100'
const API_BASE_URL_DEV = 'https://souldev.quwanzhi.com'
// 开发者工具默认与正式一致;若需连测服可改为 https://souldev.quwanzhi.com 或本机 http://127.0.0.1:9100
const API_BASE_URL_DEV = 'https://soulapi.quwanzhi.com'
// 运行时自动判断:非开发工具(真机/体验版/正式版)强制用 PROD避免 localhost 打进上传包导致白屏
const _isDevTools = (typeof __wxConfig !== 'undefined' && __wxConfig.platform === 'devtools')
@@ -62,7 +60,7 @@ App({
// 购买记录
purchasedSections: [],
hasFullBook: false,
// VIP 会员365天包含增值版免费与 hasFullBook=9.9 买断不同)
// VIP 会员365天包含增值版免费与 hasFullBook=365读书会权益不同)
isVip: false,
vipExpireDate: '',
@@ -570,6 +568,11 @@ App({
if (!base) return
// 本机 API 无稳定 WSS 时跳过,减少控制台报错与无效重连
if (/^(https?:\/\/)?(127\.0\.0\.1|localhost)(:\d+)?$/i.test(base)) return
try {
const h = new URL(base.startsWith('http') ? base : 'https://' + base).hostname
// 开发/预览域名未部署 WSS 时跳过(避免 DevTools 反复报 WebSocket failed
if (h === 'souldev.quwanzhi.com' || h.endsWith('.local')) return
} catch (_) {}
const wsUrl = base.replace(/^http/, 'ws') + '/ws/miniprogram'
if (this._wsHeartbeatTimer) {
clearInterval(this._wsHeartbeatTimer)
@@ -1023,10 +1026,8 @@ App({
},
success: (res) => {
const data = res.data
const rejectWithBody = (message, body) => {
const err = new Error(message)
if (body != null && typeof body === 'object') err.response = body
reject(err)
const rejectWithBody = (message) => {
reject(new Error(message))
}
if (res.statusCode === 200) {
if (data && data.success === false) {
@@ -1035,7 +1036,7 @@ App({
this.logout()
}
showError(msg)
rejectWithBody(msg, data)
rejectWithBody(msg)
return
}
resolve(data)
@@ -1044,14 +1045,12 @@ App({
if (res.statusCode === 401) {
this.logout()
showError('未授权,请重新登录')
const err = new Error('未授权')
if (data != null && typeof data === 'object') err.response = data
reject(err)
reject(new Error('未授权'))
return
}
const msg = this._getApiErrorMsg(data, res.statusCode >= 500 ? '服务器异常,请稍后重试' : '请求失败')
showError(msg)
rejectWithBody(msg, data && typeof data === 'object' ? data : undefined)
rejectWithBody(msg)
},
fail: (err) => {
const msg = (err && err.errMsg)
@@ -1090,11 +1089,9 @@ App({
if (pending[dedupKey]) return pending[dedupKey].promise
}
const promise = this._requestOnce(url, options, silent).catch(async (err) => {
const promise = this._requestOnce(url, options, silent).catch((err) => {
const msg = (err && err.message) ? err.message : '网络异常,请重试'
const next = new Error(msg)
if (err && err.response != null) next.response = err.response
throw next
throw new Error(msg)
})
if (method === 'GET') {
@@ -1408,6 +1405,22 @@ App({
return (this.globalData.readSectionIds || []).length
},
/** 最近打开过的不同章节数(含仅预览),与 getReadCount 取大用于「浏览 N 章 →365」规则 */
getBrowseDistinctChapterCount() {
try {
let list = wx.getStorageSync('recent_section_opens')
if (!Array.isArray(list)) return 0
const ids = new Set()
for (let i = 0; i < list.length; i++) {
const x = list[i]
if (x && x.id) ids.add(String(x.id))
}
return ids.size
} catch (e) {
return 0
}
},
// 获取章节总数
getTotalSections() {
return this.globalData.totalSections