refactor: 项目架构重构 - 目录标准化 + 清理冗余
- 目录重命名: backend/wdkj-server/ → server/, frontend/ai-dimension/ → client/ - 删除 20+ 冗余文件(WDKJ 旧脚本、Windows 脚本、过时文档、设计稿) - 更新 package.json 元数据(移除 wdkj 命名) - 完善三级 .gitignore(根 + server + client) - 重写 README.md 和 CHANGELOG.md - 工具脚本移至 scripts/
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* 宇之然AI维度 — API 工具
|
||||
* 后端地址:wdkj.yuzhiran.com.cn (生产) / 127.0.0.1:3001 (开发)
|
||||
*/
|
||||
|
||||
const BASE_URL = 'https://wdkj.yuzhiran.com.cn'
|
||||
const DEV_URL = 'http://127.0.0.1:3001'
|
||||
|
||||
// 生产环境使用域名(SSL 已续期)
|
||||
const API_BASE = 'https://wdkj.yuzhiran.com.cn'
|
||||
|
||||
/**
|
||||
* 通用请求封装
|
||||
*/
|
||||
async function request(method, path, data = null, token = null) {
|
||||
const url = `${API_BASE}${path}`
|
||||
const headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
if (token) {
|
||||
headers['Authorization'] = `Bearer ${token}`
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await uni.request({
|
||||
url,
|
||||
method,
|
||||
data,
|
||||
header: headers,
|
||||
timeout: 15000
|
||||
})
|
||||
|
||||
const body = res.data
|
||||
if (body.success) {
|
||||
return body.data
|
||||
}
|
||||
throw new Error(body.error || '请求失败')
|
||||
} catch (err) {
|
||||
console.error(`[API] ${method} ${path} failed:`, err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证相关
|
||||
*/
|
||||
export const authApi = {
|
||||
/** 微信小程序登录 */
|
||||
login: (code, userInfo) =>
|
||||
request('POST', '/api/auth/login', { code, userInfo }),
|
||||
|
||||
/** H5 密码登录 */
|
||||
h5Login: (username, password) =>
|
||||
request('POST', '/api/auth/user/login', { username, password }),
|
||||
|
||||
/** H5 注册 */
|
||||
register: (username, password, nickName) =>
|
||||
request('POST', '/api/auth/user/register', { username, password, nickName }),
|
||||
|
||||
/** 获取当前用户 */
|
||||
me: (token) =>
|
||||
request('GET', '/api/auth/me', null, token),
|
||||
}
|
||||
|
||||
/**
|
||||
* 知识库
|
||||
*/
|
||||
export const knowledgeApi = {
|
||||
/** 获取知识列表 */
|
||||
list: (params = {}) => {
|
||||
const query = Object.entries(params)
|
||||
.filter(([_, v]) => v !== undefined && v !== null)
|
||||
.map(([k, v]) => `${k}=${v}`)
|
||||
.join('&')
|
||||
return request('GET', `/api/knowledge${query ? '?' + query : ''}`)
|
||||
},
|
||||
|
||||
/** 获取知识详情 */
|
||||
detail: (id) =>
|
||||
request('GET', `/api/knowledge/${id}`),
|
||||
|
||||
/** 收藏知识 */
|
||||
collect: (id, token) =>
|
||||
request('POST', `/api/knowledge/${id}/collect`, null, token),
|
||||
|
||||
/** 取消收藏 */
|
||||
uncollect: (id, token) =>
|
||||
request('DELETE', `/api/knowledge/collect/${id}`, null, token),
|
||||
|
||||
/** 获取收藏列表 */
|
||||
collected: (token) =>
|
||||
request('GET', '/api/knowledge/collected', null, token),
|
||||
|
||||
/** 获取维度问答 */
|
||||
questions: (dim) =>
|
||||
request('GET', `/api/knowledge/${dim}/questions`),
|
||||
|
||||
/** 搜索知识 */
|
||||
search: (q, options = {}) => {
|
||||
const params = { q, ...options }
|
||||
const query = Object.entries(params)
|
||||
.filter(([_, v]) => v !== undefined && v !== null)
|
||||
.map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
|
||||
.join('&')
|
||||
return request('GET', `/api/knowledge/search${query ? '?' + query : ''}`)
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* AI 问答
|
||||
*/
|
||||
export const aiChatApi = {
|
||||
/** 获取配额 */
|
||||
quota: (token) =>
|
||||
request('GET', '/api/ai-chat/quota', null, token),
|
||||
|
||||
/** 提问 */
|
||||
ask: (question, dimension = 'general', token) =>
|
||||
request('POST', '/api/ai-chat/ask', { question, dimension }, token),
|
||||
|
||||
/** 分享获得次数 */
|
||||
shareGain: (token) =>
|
||||
request('POST', '/api/ai-chat/share-gain', null, token),
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户相关
|
||||
*/
|
||||
export const userApi = {
|
||||
/** 获取用户进度 */
|
||||
progress: (token) =>
|
||||
request('GET', '/api/user/progress', null, token),
|
||||
|
||||
/** 保存进度 */
|
||||
saveProgress: (data, token) =>
|
||||
request('POST', '/api/user/progress', data, token),
|
||||
|
||||
/** 排行榜 */
|
||||
leaderboard: (dim = null) =>
|
||||
request('GET', `/api/user/leaderboard${dim ? '?dim=' + dim : ''}`),
|
||||
|
||||
/** 获取成就 */
|
||||
achievements: (token) =>
|
||||
request('GET', '/api/user/achievements', null, token),
|
||||
|
||||
/** 用户统计 */
|
||||
stats: (token) =>
|
||||
request('GET', '/api/user/stats', null, token),
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付相关
|
||||
*/
|
||||
export const paymentApi = {
|
||||
/** 获取商品列表 */
|
||||
products: () =>
|
||||
request('GET', '/api/payment/products'),
|
||||
|
||||
/** 创建订单 */
|
||||
createOrder: (productId, token) =>
|
||||
request('POST', '/api/payment/create-order', { productId }, token),
|
||||
}
|
||||
|
||||
/**
|
||||
* 趋势资讯
|
||||
*/
|
||||
export const trendApi = {
|
||||
/** 获取趋势列表 */
|
||||
list: (params = {}) => {
|
||||
const query = Object.entries(params)
|
||||
.filter(([_, v]) => v !== undefined && v !== null)
|
||||
.map(([k, v]) => `${k}=${v}`)
|
||||
.join('&')
|
||||
return request('GET', `/api/trend${query ? '?' + query : ''}`)
|
||||
},
|
||||
|
||||
/** 获取趋势详情 */
|
||||
detail: (id) =>
|
||||
request('GET', `/api/trend/${id}`),
|
||||
}
|
||||
|
||||
/**
|
||||
* 意见反馈
|
||||
*/
|
||||
export const feedbackApi = {
|
||||
/** 提交反馈 */
|
||||
create: (data, token) =>
|
||||
request('POST', '/api/feedback', data, token),
|
||||
/** 我的反馈列表 */
|
||||
my: (token) =>
|
||||
request('GET', '/api/feedback/my', null, token),
|
||||
}
|
||||
|
||||
export default {
|
||||
auth: authApi,
|
||||
knowledge: knowledgeApi,
|
||||
aiChat: aiChatApi,
|
||||
user: userApi,
|
||||
payment: paymentApi,
|
||||
trend: trendApi,
|
||||
feedback: feedbackApi
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* 维度配置 — 5 个 AI 维度的元数据
|
||||
* 修改这里可以调整维度名称、颜色、图标等
|
||||
*/
|
||||
|
||||
export const DIMENSIONS = [
|
||||
{
|
||||
id: 1,
|
||||
key: 'origin',
|
||||
name: 'AI 起源',
|
||||
icon: '🌅',
|
||||
desc: '人工智能的诞生——从图灵测试到第一代探索者',
|
||||
color: 'var(--dim1-color)',
|
||||
bg: 'var(--dim1-bg)',
|
||||
iconBg: 'var(--dim1-icon-bg)',
|
||||
border: 'var(--dim1-border)',
|
||||
glow: 'var(--dim1-glow)',
|
||||
articleCount: 12,
|
||||
quizCount: 4
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
key: 'development',
|
||||
name: 'AI 发展',
|
||||
icon: '📈',
|
||||
desc: '技术跃迁之路——深度学习、Transformer 和前沿突破',
|
||||
color: 'var(--dim2-color)',
|
||||
bg: 'var(--dim2-bg)',
|
||||
iconBg: 'var(--dim2-icon-bg)',
|
||||
border: 'var(--dim2-border)',
|
||||
glow: 'var(--dim2-glow)',
|
||||
articleCount: 18,
|
||||
quizCount: 6
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
key: 'current',
|
||||
name: 'AI 当前',
|
||||
icon: '🌐',
|
||||
desc: '2026 年 AI 世界——大模型、Agent、人形机器人',
|
||||
color: 'var(--dim3-color)',
|
||||
bg: 'var(--dim3-bg)',
|
||||
iconBg: 'var(--dim3-icon-bg)',
|
||||
border: 'var(--dim3-border)',
|
||||
glow: 'var(--dim3-glow)',
|
||||
articleCount: 15,
|
||||
quizCount: 5
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
key: 'learning',
|
||||
name: 'AI 学习',
|
||||
icon: '🛠',
|
||||
desc: '动手学 AI——提示词、微调、RAG 和实用工具',
|
||||
color: 'var(--dim4-color)',
|
||||
bg: 'var(--dim4-bg)',
|
||||
iconBg: 'var(--dim4-icon-bg)',
|
||||
border: 'var(--dim4-border)',
|
||||
glow: 'var(--dim4-glow)',
|
||||
articleCount: 20,
|
||||
quizCount: 8
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
key: 'trend',
|
||||
name: 'AI 趋势',
|
||||
icon: '🔥',
|
||||
desc: '前沿动态——每日 AI 新闻、产品和趋势洞察',
|
||||
color: 'var(--dim5-color)',
|
||||
bg: 'var(--dim5-bg)',
|
||||
iconBg: 'var(--dim5-icon-bg)',
|
||||
border: 'var(--dim5-border)',
|
||||
glow: 'var(--dim5-glow)',
|
||||
articleCount: 0,
|
||||
quizCount: 0,
|
||||
isFull: true // 跨列
|
||||
}
|
||||
]
|
||||
|
||||
/** 按维度 ID 查找 */
|
||||
export function getDimension(id) {
|
||||
return DIMENSIONS.find(d => d.id === id)
|
||||
}
|
||||
|
||||
/** 按维度 key 查找 */
|
||||
export function getDimensionByKey(key) {
|
||||
return DIMENSIONS.find(d => d.key === key)
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 全局错误处理
|
||||
* 在 main.js 中调用 initErrorHandler()
|
||||
*/
|
||||
|
||||
export function initErrorHandler() {
|
||||
// 捕获未处理的 Promise rejection
|
||||
uni.onUnhandledRejection((res) => {
|
||||
console.error('[Global Error]', res.reason)
|
||||
uni.showToast({ title: '操作失败,请重试', icon: 'none' })
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 网络请求拦截器
|
||||
* 增强版 request 函数,带全局错误处理
|
||||
*/
|
||||
async function request(method, path, data = null, token = null, options = {}) {
|
||||
const BASE_URL = 'https://wdkj.yuzhiran.com.cn'
|
||||
const DEV_URL = 'http://127.0.0.1:3001'
|
||||
const isDev = import.meta.env.DEV
|
||||
const API_BASE = isDev ? DEV_URL : BASE_URL
|
||||
|
||||
const url = `${API_BASE}${path}`
|
||||
const headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
if (token) {
|
||||
headers['Authorization'] = `Bearer ${token}`
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await uni.request({
|
||||
url,
|
||||
method,
|
||||
data,
|
||||
header: headers,
|
||||
timeout: options.timeout || 15000
|
||||
})
|
||||
|
||||
// 统一错误处理
|
||||
if (res.statusCode >= 400) {
|
||||
throw new Error(res.data?.error || `请求失败 (${res.statusCode})`)
|
||||
}
|
||||
|
||||
const body = res.data
|
||||
if (body && body.success) {
|
||||
return body.data
|
||||
}
|
||||
throw new Error(body?.error || '请求失败')
|
||||
} catch (err) {
|
||||
// 网络错误
|
||||
if (err.errMsg && err.errMsg.includes('timeout')) {
|
||||
throw new Error('网络超时,请检查网络')
|
||||
}
|
||||
if (err.errMsg && err.errMsg.includes('fail')) {
|
||||
throw new Error('网络连接失败')
|
||||
}
|
||||
console.error(`[API Error] ${method} ${path}:`, err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
export default request
|
||||
Reference in New Issue
Block a user