mirror of
https://github.com/KingHWJ/WeReadBoard.git
synced 2026-11-03 18:24:58 +08:00
feat(web): v2 看板前端接入真实数据接口
前端样式完全沿用 2.0 设计稿,仅替换数据来源。 - templates/index.html 改用设计稿 DOM 结构与类名,引用 styles.css + weapi.js + app.js - static/css/styles.css 引入 2.0 设计稿样式 - static/js/weapi.js 新增,封装 /api/v2/* 调用为全局 WeApi - static/js/app.js 重写:保留设计稿全部渲染函数与 CSS 类名, 数据源由 demo-data.js 静态假数据改为真实接口, 补充异步加载器、加载/错误状态机与重试按钮 - static/js/demo-data.js 保留为设计稿原始假数据对照
This commit is contained in:
1 parent
a114f3f407
commit
8af75454a4
5 files changed
+804
-1441
No files matched your search
@@ -0,0 +1,125 @@
|
||||
/* ==========================================================================
|
||||
阅间 · 数据层(v2)
|
||||
--------------------------------------------------------------------------
|
||||
把后端 /api/v2/* 接口封装成前端可直接使用的数据结构。
|
||||
设计稿(Design Demo)原本使用 demo-data.js 里的静态示例数据,
|
||||
这里替换为真实接口调用,字段名与设计稿保持一致。
|
||||
========================================================================== */
|
||||
(function (global) {
|
||||
'use strict';
|
||||
|
||||
const BASE = '/api/v2';
|
||||
|
||||
async function request(path, params) {
|
||||
const url = new URL(BASE + path, global.location.origin);
|
||||
Object.entries(params || {}).forEach(([key, value]) => {
|
||||
if (value !== undefined && value !== null && value !== '') url.searchParams.set(key, value);
|
||||
});
|
||||
const response = await fetch(url.toString(), { headers: { Accept: 'application/json' } });
|
||||
let payload = null;
|
||||
try {
|
||||
payload = await response.json();
|
||||
} catch (error) {
|
||||
payload = null;
|
||||
}
|
||||
if (!response.ok) {
|
||||
const message = (payload && (payload.error || payload.detail)) || `请求失败(${response.status})`;
|
||||
const err = new Error(message);
|
||||
err.status = response.status;
|
||||
err.payload = payload;
|
||||
throw err;
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
/* ------------------------------ 工具函数 ------------------------------ */
|
||||
|
||||
function durationText(seconds) {
|
||||
const total = Math.max(0, Math.round(Number(seconds) || 0));
|
||||
const hours = Math.floor(total / 3600);
|
||||
const minutes = Math.round((total % 3600) / 60);
|
||||
return hours ? `${hours}小时${minutes}分钟` : `${minutes}分钟`;
|
||||
}
|
||||
|
||||
function percentText(value) {
|
||||
const num = Number(value) || 0;
|
||||
return `${num}%`;
|
||||
}
|
||||
|
||||
/* ------------------------------ 接口封装 ------------------------------ */
|
||||
|
||||
const WeApi = {
|
||||
durationText,
|
||||
percentText,
|
||||
|
||||
status() {
|
||||
return request('/status');
|
||||
},
|
||||
|
||||
/**
|
||||
* 书架数据
|
||||
* @param {string} tab all|reading|done|wish
|
||||
* @param {{keyword?:string, limit?:number, offset?:number, progress?:boolean}} options
|
||||
*/
|
||||
shelf(tab, options) {
|
||||
const opts = options || {};
|
||||
return request('/shelf', {
|
||||
tab: tab || 'all',
|
||||
keyword: opts.keyword || '',
|
||||
limit: opts.limit,
|
||||
offset: opts.offset,
|
||||
progress: opts.progress ? 1 : 0,
|
||||
});
|
||||
},
|
||||
|
||||
dashboard(period) {
|
||||
return request('/dashboard', { period: period || 'week' });
|
||||
},
|
||||
|
||||
notebooks() {
|
||||
return request('/notebooks');
|
||||
},
|
||||
|
||||
/** bookId 传 'all' 时聚合笔记最多的前 limit 本 */
|
||||
notes(bookId, limit) {
|
||||
return request('/notes', { book_id: bookId, limit: limit });
|
||||
},
|
||||
|
||||
book(bookId) {
|
||||
return request('/book/' + encodeURIComponent(bookId));
|
||||
},
|
||||
|
||||
reviews(bookId, type, count) {
|
||||
return request(`/book/${encodeURIComponent(bookId)}/reviews`, { type: type || 0, count: count || 10 });
|
||||
},
|
||||
|
||||
highlights(bookId, chapterUid) {
|
||||
return request(`/book/${encodeURIComponent(bookId)}/highlights`, { chapter_uid: chapterUid || 0 });
|
||||
},
|
||||
|
||||
underlineThoughts(bookId, chapterUid, range) {
|
||||
return request(`/book/${encodeURIComponent(bookId)}/underline-thoughts`, {
|
||||
chapter_uid: chapterUid,
|
||||
range: range,
|
||||
});
|
||||
},
|
||||
|
||||
thought(reviewId) {
|
||||
return request('/thought/' + encodeURIComponent(reviewId));
|
||||
},
|
||||
|
||||
archives() {
|
||||
return request('/archives');
|
||||
},
|
||||
|
||||
recommend(maxIdx) {
|
||||
return request('/recommend', { maxIdx: maxIdx || 0 });
|
||||
},
|
||||
|
||||
search(keyword, scope) {
|
||||
return request('/search', { keyword: keyword, scope: scope || 'books' });
|
||||
},
|
||||
};
|
||||
|
||||
global.WeApi = WeApi;
|
||||
})(window);
|
||||
Reference in new issue
Block a user