Skip to content

Commit 6b9524a

Browse files
committed
feat(文章列表): 添加免费试听文章列表请求功能
refactor(前端): 优化产品卡片点击处理和样式 style(弹窗组件): 统一信息弹窗样式和主题适配 feat(下载功能): 为电子书和听书添加下载选项
1 parent 1e8e941 commit 6b9524a

8 files changed

Lines changed: 600 additions & 101 deletions

File tree

backend/services/article.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package services
22

3+
import "strings"
4+
35
// ArticleDetail article content
46
// GET query params token,sign,appid
57
type ArticleDetail struct {
@@ -178,12 +180,39 @@ func (s *Service) ArticleList(id, chapterID string, count, maxID int, reverse bo
178180
return
179181
}
180182
defer body.Close()
181-
if err = handleJSONParse(body, &list); err != nil {
183+
if err = handleJSONParse(body, &list); err == nil {
184+
return
185+
}
186+
187+
if !shouldFallbackToFreeArticleList(err) {
188+
return
189+
}
190+
191+
freeBody, freeErr := s.reqFreeArticleList(id, chapterID, count, maxID, reverse)
192+
if freeErr != nil {
193+
return list, freeErr
194+
}
195+
defer freeBody.Close()
196+
if err = handleJSONParse(freeBody, &list); err != nil {
182197
return
183198
}
184199
return
185200
}
186201

202+
func shouldFallbackToFreeArticleList(err error) bool {
203+
if err == nil {
204+
return false
205+
}
206+
msg := err.Error()
207+
if strings.Contains(msg, "401 Unauthorized") ||
208+
strings.Contains(msg, "404 NotFound") ||
209+
strings.Contains(msg, "400 BadRequest") ||
210+
strings.Contains(msg, "496 NoCertificate") {
211+
return false
212+
}
213+
return strings.Contains(msg, "errMsg:")
214+
}
215+
187216
// ArticleInfo get article info
188217
// enid article enid, aType 1-course article, 2-odob article
189218
func (s *Service) ArticleInfo(enid string, aType int) (info *ArticleInfo, err error) {

backend/services/requester.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,23 @@ func (s *Service) reqArticleList(ID, chapterID string, count, maxID int, reverse
155155
return handleHTTPResponse(resp, err)
156156
}
157157

158+
// reqFreeArticleList 请求免费试听文章列表
159+
// chapterID = "" 获取所有的文章列表,否则只获取该章节的文章列表
160+
func (s *Service) reqFreeArticleList(ID, chapterID string, count, maxID int, reverse bool) (io.ReadCloser, error) {
161+
resp, err := s.client.R().
162+
SetBody(map[string]interface{}{
163+
"chapter_id": chapterID,
164+
"count": count,
165+
"detail_id": ID,
166+
"max_id": maxID,
167+
"max_order_num": 0,
168+
"reverse": reverse,
169+
"since_id": 0,
170+
"since_order_num": 0,
171+
}).Post("/pc/bauhinia/pc/class/free_article_list")
172+
return handleHTTPResponse(resp, err)
173+
}
174+
158175
// reqArticleCommentList 请求文章热门留言列表
159176
// enId 文章 ID
160177
// sort like-最热 create-最新

frontend/src/components/AudioInfo.vue

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
<template>
2-
<el-dialog v-model="dialogVisible" width="75%" :before-close="closeDialog">
2+
<el-dialog
3+
v-model="dialogVisible"
4+
width="75%"
5+
:before-close="closeDialog"
6+
class="info-dialog audio-info-dialog"
7+
destroy-on-close
8+
>
39
<template #header="{titleId, titleClass }">
410
<div class="my-header">
511
<h4 :id="titleId" :class="titleClass">{{audioInfo.detail.title}}</h4>
@@ -21,12 +27,12 @@
2127
</el-col>
2228
<el-col :span="16">
2329
<p style="margin: 0;font-size: medium;">{{ audioInfo.detail.agency_detail.qcg_member_name }}</p>
24-
<span style="color: #909399;">解读书本{{ audioInfo.detail.agency_detail.book_count }}本 | 被学习{{ audioInfo.detail.agency_detail.uv }}次</span>
30+
<span class="meta-text">解读书本{{ audioInfo.detail.agency_detail.book_count }}本 | 被学习{{ audioInfo.detail.agency_detail.uv }}次</span>
2531
</el-col>
2632
</el-row>
2733
<el-row :gutter="0" >
2834
<p class="author-info" v-html="audioInfo.detail.agency_detail.intro?.replaceAll('\n','<br/>')"></p><br />
29-
<span style="color:#ff6b00">{{ audioInfo.detail.audio_price }}元</span>
35+
<span class="price">{{ audioInfo.detail.audio_price }}元</span>
3036
<el-tag class="ml-2" type="warning" v-if="audioInfo.detail.is_vip == true" round>
3137
<el-icon><HotWater /></el-icon>会员免费</el-tag>
3238
<el-tag class="ml-2" type="info" v-if="audioInfo.detail.in_bookrack == true" round>
@@ -65,7 +71,7 @@
6571
<div class="book-intro" style="text-align:left">
6672
<div v-for="item in audioInfo.detail.topic_summary" :key="item.id">
6773
<h3>{{ item.title}}</h3>
68-
<p v-html="item.sub_title?.replaceAll('\n','<br/>')" style="color: #909399;"></p>
74+
<p class="meta-text" v-html="item.sub_title?.replaceAll('\n','<br/>')"></p>
6975
</div>
7076
</div>
7177
</el-card>
@@ -78,11 +84,7 @@ import { ref, reactive, onMounted } from 'vue'
7884
import { ElMessage } from 'element-plus'
7985
import { AudioDetail } from '../../wailsjs/go/backend/App'
8086
import { services } from '../../wailsjs/go/models'
81-
import { repeat } from 'lodash'
8287
import { secondToHour,timestampToDate } from '../utils/utils'
83-
import { useRouter } from 'vue-router'
84-
85-
const router = useRouter()
8688
const dialogVisible = ref(false)
8789
8890
let audioInfo = reactive(new services.AudioInfoResp)
@@ -106,7 +108,6 @@ onMounted(() => {
106108
107109
const getAudioInfo = async (enid: string) => {
108110
await AudioDetail(enid).then((info) => {
109-
console.log(info)
110111
Object.assign(audioInfo, info)
111112
openDialog()
112113
}).catch((error) => {
@@ -128,7 +129,42 @@ const closeDialog = () => {
128129
129130
</script>
130131

131-
<style scoped>
132+
<style scoped lang="scss">
133+
.audio-info-dialog {
134+
:deep(.el-dialog__header) {
135+
margin-right: 0;
136+
padding: 20px 24px;
137+
border-bottom: 1px solid var(--border-soft);
138+
}
139+
140+
:deep(.el-dialog__body) {
141+
padding: 0;
142+
}
143+
}
144+
145+
.my-header {
146+
display: flex;
147+
flex-direction: column;
148+
gap: 12px;
149+
150+
h4 {
151+
margin: 0;
152+
font-size: 20px;
153+
font-weight: 600;
154+
color: var(--text-primary);
155+
line-height: 1.4;
156+
}
157+
}
158+
159+
.meta-text {
160+
color: var(--text-tertiary) !important;
161+
}
162+
163+
.price {
164+
color: var(--accent-color) !important;
165+
font-weight: 600;
166+
}
167+
132168
.card-header.el-row {
133169
height: 100%;
134170
}
@@ -162,27 +198,32 @@ const closeDialog = () => {
162198
.section-info{
163199
display: flex;
164200
flex-wrap: wrap;
201+
margin: 20px 0;
165202
}
166203
.section-info .item-content {
167204
position: relative;
168205
text-align: center;
169206
min-width: 24%;
170207
margin-bottom: 15px;
171-
border-left: 1px solid #d8d8d8;
208+
border-left: 1px solid var(--border-soft);
209+
210+
&:first-child {
211+
border-left: none;
212+
}
172213
}
173214
.item-content span {
174215
display: block;
175216
}
176217
177218
.item-content .info-value {
178219
font-size: 16px;
179-
color: #333;
220+
color: var(--text-primary);
180221
letter-spacing: 0;
181222
line-height: 28px;
182223
}
183224
184225
.item-content .info-text {
185-
color: #666;
226+
color: var(--text-secondary);
186227
line-height: 16px;
187228
font-size: 12px;
188229
letter-spacing: 0;
@@ -199,8 +240,8 @@ const closeDialog = () => {
199240
/* height: 32px; */
200241
border-radius: 8px;
201242
font-weight: bold;
202-
border-color: #ff6b00;
203-
background-color: #ff6b00;
204-
color: #fff;
243+
border-color: var(--accent-color);
244+
background-color: var(--accent-color);
245+
color: #fff !important;
205246
}
206-
</style>
247+
</style>

0 commit comments

Comments
 (0)