Merge branch 'main' of https://gitea.23544.com/tanxin/App.k12.Parents
This commit is contained in:
+97
-14
@@ -255,6 +255,14 @@ export type StudentGrowth = {
|
||||
records: GrowthPointRecord[]
|
||||
}
|
||||
|
||||
export type StudentPointRecordsPage = {
|
||||
records: GrowthPointRecord[]
|
||||
total: number
|
||||
pageIndex: number
|
||||
pageSize: number
|
||||
lastId: number | null
|
||||
}
|
||||
|
||||
export type LearningTaskItem = {
|
||||
id: string
|
||||
title: string
|
||||
@@ -333,6 +341,15 @@ export type StudentLearningWarningResult = {
|
||||
items: StudentLearningWarningItem[]
|
||||
}
|
||||
|
||||
const learningWarningTypeMap: { [key: number]: { title: string, level: StudentAlertLevel } } = {
|
||||
1: { title: '今日未打卡', level: 'high' },
|
||||
2: { title: '仅学无交', level: 'medium' },
|
||||
3: { title: '作业未完成', level: 'high' },
|
||||
4: { title: '攻克失败', level: 'critical' },
|
||||
5: { title: '连续 3 天未学习', level: 'high' },
|
||||
6: { title: '正确率明显下滑', level: 'medium' }
|
||||
}
|
||||
|
||||
// 验证学生二维码请求参数
|
||||
export type VerifyQRCodeParams = {
|
||||
qrCode: string
|
||||
@@ -433,26 +450,30 @@ export function apiGetStudentHomeMetrics(studentId: string, showLoading: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定学生今日学习预警。已触发预警优先,其后展示未触发规则。
|
||||
* 获取指定学生今日学习预警。已触发预警优先,其后展示未触发规则,可按数量裁剪。
|
||||
*/
|
||||
export function apiGetStudentLearningWarnings(studentId: string, showLoading: boolean = true, limit?: number): Promise<ApiResponse<StudentAlertList> | null> {
|
||||
export function apiGetStudentLearningWarnings(studentId: string, showLoading: boolean = true, limit?: number, onlyTriggered: boolean = false): Promise<ApiResponse<StudentAlertList> | null> {
|
||||
return get<StudentLearningWarningResult>(`/api/v1/ParentLearningWarning/GetTodayList?userId=${encodeURIComponent(studentId)}`, undefined, { showLoading }).then((res) => {
|
||||
if (!res || !res.data || !Array.isArray(res.data.items)) return null
|
||||
const warningData = res.data
|
||||
const triggeredItems = warningData.items.filter((item: StudentLearningWarningItem) => Boolean(item.isTriggered))
|
||||
const normalItems = warningData.items.filter((item: StudentLearningWarningItem) => !Boolean(item.isTriggered))
|
||||
const sourceItems = triggeredItems.concat(normalItems)
|
||||
const orderedItems = triggeredItems.concat(normalItems)
|
||||
const sourceItems = onlyTriggered ? triggeredItems : orderedItems
|
||||
const visibleItems = limit === undefined ? sourceItems : sourceItems.slice(0, limit)
|
||||
const list: StudentAlert[] = visibleItems.map((item: StudentLearningWarningItem, index: number) => ({
|
||||
id: `${studentId}-${item.type ?? index}`,
|
||||
level: item.isTriggered ? 'high' : 'low',
|
||||
title: item.title || '学习预警',
|
||||
content: item.description || item.statusName || '',
|
||||
occurredAt: warningData.date || '',
|
||||
isRead: !item.isTriggered,
|
||||
isTriggered: Boolean(item.isTriggered),
|
||||
statusName: item.statusName || ''
|
||||
}))
|
||||
const list: StudentAlert[] = visibleItems.map((item: StudentLearningWarningItem, index: number) => {
|
||||
const warningType = learningWarningTypeMap[Number(item.type)]
|
||||
return {
|
||||
id: `${studentId}-${item.type ?? index}`,
|
||||
level: item.isTriggered ? warningType?.level ?? 'high' : 'low',
|
||||
title: item.title || warningType?.title || '学习预警',
|
||||
content: item.description || item.statusName || '',
|
||||
occurredAt: warningData.date || '',
|
||||
isRead: !item.isTriggered,
|
||||
isTriggered: Boolean(item.isTriggered),
|
||||
statusName: item.statusName || (item.isTriggered ? '已触发' : '正常')
|
||||
}
|
||||
})
|
||||
return {
|
||||
code: res.code,
|
||||
message: res.message,
|
||||
@@ -684,7 +705,69 @@ export function apiGetStudentVocabulary(studentId: string, showLoading: boolean
|
||||
}
|
||||
|
||||
export function apiGetStudentGrowth(studentId: string, showLoading: boolean = true): Promise<ApiResponse<StudentGrowth> | null> {
|
||||
return get<StudentGrowth>(`/api/parent/growth?studentId=${studentId}`, undefined, { showLoading })
|
||||
return get<any>(`/api/v1/StudentPoints/GetStudentPointSummary/${studentId}`, undefined, { showLoading }).then((res) => {
|
||||
if (!res || !res.data) return null
|
||||
return {
|
||||
code: res.code,
|
||||
message: res.message,
|
||||
data: {
|
||||
studentId: String(res.data.userId ?? studentId),
|
||||
studentName: '',
|
||||
studentGrade: '',
|
||||
studentClass: '',
|
||||
pointsBalance: Number(res.data.totalPoints) || 0,
|
||||
level: Number(res.data.level) || 0,
|
||||
rank: Number(res.data.classRank) || 0,
|
||||
streakDays: Number(res.data.noPointDays) || 0,
|
||||
totalPoints: Number(res.data.todayPoints) || 0,
|
||||
records: []
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页获取学生积分流水。
|
||||
*/
|
||||
export function apiGetStudentPointRecords(studentId: string, pageIndex: number = 1, pageSize: number = 20, prevPageId?: number, showLoading: boolean = true): Promise<ApiResponse<StudentPointRecordsPage> | null> {
|
||||
const prevPageQuery = prevPageId === undefined || prevPageId === null ? '' : `&PrevPageId=${prevPageId}`
|
||||
return get<any>(`/api/v1/StudentPoints/GetStudentPointRecords?UserId=${studentId}&PageIndex=${pageIndex}&PageSize=${pageSize}${prevPageQuery}`, undefined, { showLoading }).then((res) => {
|
||||
if (!res || !res.data) return null
|
||||
const page = res.data
|
||||
const records: GrowthPointRecord[] = (Array.isArray(page.data) ? page.data : []).map((item: any) => ({
|
||||
id: String(item.id),
|
||||
title: item.pointMessage || '积分变动',
|
||||
timeText: formatPointRecordTime(item.bizTime),
|
||||
points: Number(item.points) || 0,
|
||||
icon: pointRecordIcon(Number(item.type))
|
||||
}))
|
||||
return {
|
||||
code: res.code,
|
||||
message: res.message,
|
||||
data: {
|
||||
records,
|
||||
total: Number(page.total) || 0,
|
||||
pageIndex: Number(page.pageIndex) || pageIndex,
|
||||
pageSize: Number(page.pageSize) || pageSize,
|
||||
lastId: page.id === null || page.id === undefined ? null : Number(page.id)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function pointRecordIcon(type: number): GrowthPointRecord['icon'] {
|
||||
if (type === 1) return 'calendar'
|
||||
if (type === 2 || type === 3) return 'assignment'
|
||||
if (type === 4) return 'streak'
|
||||
if (type === 5 || type === 6) return 'accuracy'
|
||||
if (type === 7 || type === 8) return 'mastery'
|
||||
return 'note'
|
||||
}
|
||||
|
||||
function formatPointRecordTime(value: any): string {
|
||||
if (!value) return '--'
|
||||
const text = String(value)
|
||||
return text.length >= 16 ? text.substring(5, 16).replace('T', ' ') : text
|
||||
}
|
||||
|
||||
export function apiGetStudentLearningTasks(studentId: string, showLoading: boolean = true): Promise<ApiResponse<StudentLearningTasks> | null> {
|
||||
|
||||
+42
-2
@@ -1,18 +1,24 @@
|
||||
<template>
|
||||
<view class="page-container">
|
||||
<view class="header-panel"><view class="header-back" @tap="goHome"><UniIcons type="back" class="header-back-icon"></UniIcons></view><view class="header-copy"><text class="header-title">成长激励</text><text class="header-subtitle">{{ homeStudentProfile?.name ?? growth.studentName }} · {{ homeStudentProfile?.school ?? '' }} {{ homeStudentProfile?.className ?? growth.studentClass }}</text></view><view class="header-action"><UniIcons type="person-filled" class="header-action-icon"></UniIcons></view></view>
|
||||
<scroll-view class="content-scroll" direction="vertical" scroll-y="true"><view v-if="isLoading" class="status-panel"><text class="status-text">成长数据加载中</text></view><view v-else class="content-panel"><view class="points-card"><view class="points-heading"><view class="points-copy"><text class="points-label">积分余额</text><text class="points-value">{{ growth.pointsBalance }}</text></view><view class="level-badge"><text class="level-label">等级</text><text class="level-value">Lv.{{ growth.level }}</text></view></view><view class="points-stats"><view class="points-stat"><text class="points-stat-value">{{ growth.rank }}</text><text class="points-stat-label">班级排名</text></view><view class="points-stat points-stat-middle"><text class="points-stat-value">{{ growth.streakDays }}</text><text class="points-stat-label">未能连续</text></view><view class="points-stat"><text class="points-stat-value">{{ growth.totalPoints }}</text><text class="points-stat-label">获得总量</text></view></view></view><view class="flow-card"><text class="section-title">积分流水</text><text class="section-description">记录孩子每天做了哪些正向行为</text><view class="flow-list"><view v-for="record in growth.records" :key="record.id" class="flow-item"><view class="flow-icon" :class="'flow-icon-' + record.icon"><UniIcons :type="record.icon === 'calendar' ? 'calendar' : record.icon === 'assignment' ? 'checkbox' : record.icon === 'streak' ? 'fire' : record.icon === 'accuracy' ? 'circle-filled' : record.icon === 'mastery' ? 'star-filled' : 'compose'" class="flow-icon-glyph"></UniIcons></view><view class="flow-copy"><text class="flow-title">{{ record.title }}</text><text class="flow-time">{{ record.timeText }}</text></view><text class="flow-points">+{{ record.points }}</text></view></view></view></view></scroll-view>
|
||||
<scroll-view class="content-scroll" direction="vertical" scroll-y="true" refresher-enabled="true" :refresher-triggered="isRefreshing" @refresherrefresh="refreshGrowth" @scrolltolower="loadMoreRecords"><view v-if="isLoading" class="status-panel"><text class="status-text">成长数据加载中</text></view><view v-else class="content-panel"><view class="points-card"><view class="points-heading"><view class="points-copy"><text class="points-label">总积分</text><text class="points-value">{{ growth.pointsBalance }}</text></view><view class="level-badge"><text class="level-label">等级</text><text class="level-value">Lv.{{ growth.level }}</text></view></view><view class="points-stats"><view class="points-stat"><text class="points-stat-value">{{ growth.rank }}</text><text class="points-stat-label">班级排名</text></view><view class="points-stat points-stat-middle"><text class="points-stat-value">{{ growth.streakDays }}</text><text class="points-stat-label">未获积分天数</text></view><view class="points-stat"><text class="points-stat-value">{{ growth.totalPoints }}</text><text class="points-stat-label">今日获得</text></view></view></view><view class="flow-card"><text class="section-title">积分流水</text><text class="section-description">记录孩子每天做了哪些正向行为</text><view v-if="growth.records.length === 0" class="flow-empty"><text class="flow-empty-text">暂无积分流水</text></view><view v-else class="flow-list"><view v-for="record in growth.records" :key="record.id" class="flow-item"><view class="flow-icon" :class="'flow-icon-' + record.icon"><UniIcons :type="record.icon === 'calendar' ? 'calendar' : record.icon === 'assignment' ? 'checkbox' : record.icon === 'streak' ? 'fire' : record.icon === 'accuracy' ? 'circle-filled' : record.icon === 'mastery' ? 'star-filled' : 'compose'" class="flow-icon-glyph"></UniIcons></view><view class="flow-copy"><text class="flow-title">{{ record.title }}</text><text class="flow-time">{{ record.timeText }}</text></view><text class="flow-points">{{ record.points >= 0 ? '+' : '' }}{{ record.points }}</text></view></view><view v-if="isLoadingMore" class="records-footer"><text class="records-footer-text">加载更多...</text></view><view v-else-if="!hasMoreRecords && growth.records.length > 0" class="records-footer"><text class="records-footer-text">没有更多记录</text></view></view></view></scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UniIcons from '../../uni_modules/uni-icons-x/components/uni-icons/uni-icons.uvue'
|
||||
import { apiGetStudentGrowth, apiGetStudentHomeProfile, type StudentGrowth } from '../../api/student'
|
||||
import { apiGetStudentGrowth, apiGetStudentHomeProfile, apiGetStudentPointRecords, type StudentGrowth } from '../../api/student'
|
||||
import { homeStudentProfile, selectedStudentChangeVersion, setHomeStudentProfile } from '../../store/home'
|
||||
|
||||
const growth = ref<StudentGrowth>({ studentId: '', studentName: '', studentGrade: '', studentClass: '', pointsBalance: 0, level: 0, rank: 0, streakDays: 0, totalPoints: 0, records: [] })
|
||||
const isLoading = ref(true)
|
||||
const observedStudentVersion = ref(selectedStudentChangeVersion.value)
|
||||
const isRefreshing = ref(false)
|
||||
const isLoadingMore = ref(false)
|
||||
const hasMoreRecords = ref(true)
|
||||
const recordsPageIndex = ref(1)
|
||||
const recordsLastId = ref<number | null>(null)
|
||||
const currentStudentId = ref('')
|
||||
|
||||
onLoad(() => { loadGrowth() })
|
||||
|
||||
@@ -34,12 +40,44 @@
|
||||
}
|
||||
}
|
||||
if (studentId) {
|
||||
currentStudentId.value = studentId
|
||||
const res = await apiGetStudentGrowth(studentId)
|
||||
if (res && res.data) growth.value = res.data
|
||||
await loadPointRecords(false)
|
||||
}
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
async function loadPointRecords(append: boolean) {
|
||||
if (!currentStudentId.value || isLoadingMore.value) return
|
||||
if (append && !hasMoreRecords.value) return
|
||||
if (append) isLoadingMore.value = true
|
||||
const pageIndex = append ? recordsPageIndex.value + 1 : 1
|
||||
const res = await apiGetStudentPointRecords(currentStudentId.value, pageIndex, 20, append ? recordsLastId.value ?? undefined : undefined, !append)
|
||||
if (res && res.data) {
|
||||
const records = append ? growth.value.records.concat(res.data.records) : res.data.records
|
||||
growth.value = { ...growth.value, records }
|
||||
recordsPageIndex.value = res.data.pageIndex
|
||||
recordsLastId.value = res.data.lastId
|
||||
hasMoreRecords.value = records.length < res.data.total && res.data.records.length > 0
|
||||
}
|
||||
isLoadingMore.value = false
|
||||
}
|
||||
|
||||
async function loadMoreRecords() {
|
||||
await loadPointRecords(true)
|
||||
}
|
||||
|
||||
async function refreshGrowth() {
|
||||
if (isRefreshing.value) return
|
||||
isRefreshing.value = true
|
||||
hasMoreRecords.value = true
|
||||
recordsPageIndex.value = 1
|
||||
recordsLastId.value = null
|
||||
await loadGrowth()
|
||||
isRefreshing.value = false
|
||||
}
|
||||
|
||||
function goHome() { uni.reLaunch({ url: '/pages/index/index' }) }
|
||||
</script>
|
||||
|
||||
@@ -81,4 +119,6 @@
|
||||
.flow-title { font-size: 13px; color: #242b3d; }
|
||||
.flow-time { margin-top: 3px; font-size: 10px; color: #94a0b1; }
|
||||
.flow-points { font-size: 13px; font-weight: 700; color: #f29900; }
|
||||
.flow-empty, .records-footer { display: flex; flex-direction: column; align-items: center; padding: 14px 0 4px; }
|
||||
.flow-empty-text, .records-footer-text { font-size: 11px; color: #94a0b1; }
|
||||
</style>
|
||||
|
||||
@@ -228,10 +228,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (student.value.id) {
|
||||
if (selectedId) {
|
||||
await Promise.all([
|
||||
loadStudentHomeMetrics(selectedId || student.value.id, showLoading),
|
||||
loadStudentAlerts(selectedId || student.value.id, showLoading)
|
||||
loadStudentHomeMetrics(selectedId, showLoading),
|
||||
loadStudentAlerts(selectedId, showLoading)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
+24
-123
@@ -3,14 +3,12 @@
|
||||
* 支持请求拦截、响应拦截、Loading显示、错误处理
|
||||
*/
|
||||
|
||||
// 响应数据类型
|
||||
export type ApiResponse<T> = {
|
||||
code: number
|
||||
message: string
|
||||
data: T | null
|
||||
}
|
||||
|
||||
// 请求配置类型
|
||||
export type RequestConfig = {
|
||||
url: string
|
||||
method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
|
||||
@@ -21,37 +19,19 @@ export type RequestConfig = {
|
||||
showError?: boolean
|
||||
}
|
||||
|
||||
// 基础URL配置 - 虚拟接口
|
||||
const BASE_URL = 'https://localhost:7145'
|
||||
|
||||
// 请求超时时间
|
||||
const TIMEOUT = 10000
|
||||
|
||||
// 联调前统一使用测试响应,保证所有页面流程可完整验证。
|
||||
const USE_MOCK_API = true
|
||||
|
||||
// Mock 接口模拟正常网络环境,响应延迟范围为 0 到 2 秒。
|
||||
const MOCK_RESPONSE_MAX_DELAY = 2000
|
||||
|
||||
// Loading引用计数
|
||||
let loadingCount = 0
|
||||
|
||||
/**
|
||||
* 显示Loading
|
||||
*/
|
||||
function showLoading(text: string = '加载中...') {
|
||||
loadingCount++
|
||||
if (loadingCount === 1) {
|
||||
uni.showLoading({
|
||||
title: text,
|
||||
mask: true
|
||||
})
|
||||
uni.showLoading({ title: text, mask: true })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏Loading
|
||||
*/
|
||||
function hideLoading() {
|
||||
loadingCount--
|
||||
if (loadingCount <= 0) {
|
||||
@@ -60,36 +40,19 @@ function hideLoading() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Token
|
||||
*/
|
||||
function getToken(): string {
|
||||
return uni.getStorageSync('token') as string ?? ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求拦截器 - 添加token等
|
||||
*/
|
||||
function requestInterceptor(config: RequestConfig): RequestConfig {
|
||||
// 添加完整URL
|
||||
if (!config.url.startsWith('http')) {
|
||||
config.url = BASE_URL + config.url
|
||||
}
|
||||
|
||||
// 添加请求头
|
||||
if (!config.url.startsWith('http')) config.url = BASE_URL + config.url
|
||||
|
||||
const token = getToken()
|
||||
config.header = config.header ?? {}
|
||||
config.header['Content-Type'] = 'application/json'
|
||||
|
||||
if (token) {
|
||||
config.header['Authorization'] = `Bearer ${token}`
|
||||
}
|
||||
|
||||
// 显示Loading
|
||||
if (config.showLoading !== false) {
|
||||
showLoading(config.loadingText)
|
||||
}
|
||||
|
||||
if (token) config.header['Authorization'] = `Bearer ${token}`
|
||||
|
||||
if (config.showLoading !== false) showLoading(config.loadingText)
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -97,17 +60,13 @@ function requestInterceptor(config: RequestConfig): RequestConfig {
|
||||
* 响应拦截器 - 统一处理响应
|
||||
*/
|
||||
function responseInterceptor<T>(response: any, config: RequestConfig): ApiResponse<T> | null {
|
||||
// 隐藏Loading
|
||||
if (config.showLoading !== false) {
|
||||
hideLoading()
|
||||
}
|
||||
|
||||
// HTTP状态码检查
|
||||
if (config.showLoading !== false) hideLoading()
|
||||
|
||||
if (response.statusCode !== 200) {
|
||||
handleError(response.statusCode, '网络请求失败', config.showError)
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
// 解析响应数据,兼容后端 PascalCase 与前端 camelCase 两种包装格式。
|
||||
const rawResult = response.data as any
|
||||
const result: ApiResponse<T> = {
|
||||
@@ -115,50 +74,35 @@ function responseInterceptor<T>(response: any, config: RequestConfig): ApiRespon
|
||||
message: String(rawResult?.message ?? rawResult?.Message ?? ''),
|
||||
data: (rawResult?.data ?? rawResult?.Data ?? null) as T | null
|
||||
}
|
||||
|
||||
// 业务状态码检查
|
||||
|
||||
if (result.code !== 200) {
|
||||
handleError(result.code, result.message, config.showError)
|
||||
return null
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误处理
|
||||
*/
|
||||
function handleError(code: number, message: string, showError: boolean = true) {
|
||||
console.error(`[Request Error] Code: ${code}, Message: ${message}`)
|
||||
|
||||
if (!showError) {
|
||||
return
|
||||
}
|
||||
|
||||
// 根据错误码显示不同提示
|
||||
if (!showError) return
|
||||
|
||||
let errorMsg = message
|
||||
|
||||
if (code === 401) {
|
||||
errorMsg = '登录已过期,请重新登录'
|
||||
// 清除token并跳转登录页
|
||||
uni.removeStorageSync('token')
|
||||
uni.removeStorageSync('userInfo')
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index'
|
||||
})
|
||||
uni.reLaunch({ url: '/pages/login/index' })
|
||||
} else if (code === 403) {
|
||||
errorMsg = '没有权限访问'
|
||||
} else if (code === 404) {
|
||||
errorMsg = '请求的资源不存在'
|
||||
} else if (code === 500) {
|
||||
errorMsg = '服务器错误,请稍后重试'
|
||||
} else if (code === -1) {
|
||||
errorMsg = '网络异常'
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: errorMsg,
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
|
||||
uni.showToast({ title: errorMsg, icon: 'none', duration: 2000 })
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -386,8 +330,7 @@ function createMockResponse<T>(config: RequestConfig): ApiResponse<T> {
|
||||
* 通用请求方法
|
||||
*/
|
||||
export function request<T>(config: RequestConfig): Promise<ApiResponse<T> | null> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 请求拦截
|
||||
return new Promise((resolve) => {
|
||||
const finalConfig = requestInterceptor(config)
|
||||
|
||||
if (USE_MOCK_API && !finalConfig.url.includes('/api/v1/Parents/') && !finalConfig.url.includes('/api/v1/ParentStudentToday/') && !finalConfig.url.includes('/api/v1/ParentLearningWarning/') && !finalConfig.url.includes('/api/v1/ParentStudyPack/') && !finalConfig.url.includes('/api/v1/ParentLearningReport/')) {
|
||||
@@ -408,70 +351,28 @@ export function request<T>(config: RequestConfig): Promise<ApiResponse<T> | null
|
||||
data: finalConfig.data,
|
||||
header: finalConfig.header,
|
||||
timeout: TIMEOUT,
|
||||
success: (res) => {
|
||||
// 响应拦截
|
||||
const result = responseInterceptor<T>(res, finalConfig)
|
||||
resolve(result)
|
||||
},
|
||||
success: (res) => resolve(responseInterceptor<T>(res, finalConfig)),
|
||||
fail: (err) => {
|
||||
// 隐藏Loading
|
||||
if (finalConfig.showLoading !== false) {
|
||||
hideLoading()
|
||||
}
|
||||
|
||||
// 网络错误处理
|
||||
if (finalConfig.showLoading !== false) hideLoading()
|
||||
handleError(-1, err.errMsg ?? '网络连接失败', finalConfig.showError)
|
||||
// 将网络失败转换为统一的空响应,避免页面事件中出现未处理 Promise 异常。
|
||||
resolve(null)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* GET请求
|
||||
*/
|
||||
export function get<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<ApiResponse<T> | null> {
|
||||
return request<T>({
|
||||
url,
|
||||
method: 'GET',
|
||||
data,
|
||||
...config
|
||||
})
|
||||
return request<T>({ url, method: 'GET', data, ...config })
|
||||
}
|
||||
|
||||
/**
|
||||
* POST请求
|
||||
*/
|
||||
export function post<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<ApiResponse<T> | null> {
|
||||
return request<T>({
|
||||
url,
|
||||
method: 'POST',
|
||||
data,
|
||||
...config
|
||||
})
|
||||
return request<T>({ url, method: 'POST', data, ...config })
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT请求
|
||||
*/
|
||||
export function put<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<ApiResponse<T> | null> {
|
||||
return request<T>({
|
||||
url,
|
||||
method: 'PUT',
|
||||
data,
|
||||
...config
|
||||
})
|
||||
return request<T>({ url, method: 'PUT', data, ...config })
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE请求
|
||||
*/
|
||||
export function del<T>(url: string, data?: any, config?: Partial<RequestConfig>): Promise<ApiResponse<T> | null> {
|
||||
return request<T>({
|
||||
url,
|
||||
method: 'DELETE',
|
||||
data,
|
||||
...config
|
||||
})
|
||||
return request<T>({ url, method: 'DELETE', data, ...config })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user