feat(1.0.2):完善收费文章和免费文章的获取,优化用户体验。

developing
张帅 2 weeks ago
parent 83cacb8db8
commit e33422867f

@ -39,6 +39,7 @@ func NewArticleService(repo article.ArticleRepository,
var class_type = map[uint64]string{ var class_type = map[uint64]string{
20014: "狙击龙虎榜", 20014: "狙击龙虎榜",
20013: "九点特供",
20015: "盘中宝", 20015: "盘中宝",
20021: "风口研报", 20021: "风口研报",
20022: "公告全知道", 20022: "公告全知道",
@ -50,6 +51,7 @@ var class_type = map[uint64]string{
var class_type_reverse = map[string]uint64{ var class_type_reverse = map[string]uint64{
"狙击龙虎榜": 20014, "狙击龙虎榜": 20014,
"九点特供": 20013,
"盘中宝": 20015, "盘中宝": 20015,
"风口研报": 20021, "风口研报": 20021,
"公告全知道": 20022, "公告全知道": 20022,
@ -68,7 +70,7 @@ func (a *ArticleService) Find(ePhone string, page *page.Page, searchParams map[s
conds = append(conds, builder.Eq{"type": classCode}) conds = append(conds, builder.Eq{"type": classCode})
} }
} }
conds = append(conds, builder.And(builder.Gt{"ctime": time.Now().AddDate(0, 0, -2).Unix()})) conds = append(conds, builder.And(builder.Gt{"ctime": time.Now().AddDate(0, 0, -2).Unix()}).And(builder.Eq{"is_free": 0}))
articles := make([]*article.LianV1Article, 0) articles := make([]*article.LianV1Article, 0)
page.Content = &articles page.Content = &articles
err := a.repo.Find(page, conds) err := a.repo.Find(page, conds)
@ -211,8 +213,7 @@ func (a *ArticleService) FindFree(page *page.Page, searchParams map[string]strin
conds = append(conds, builder.Eq{"type": classCode}) conds = append(conds, builder.Eq{"type": classCode})
} }
} }
conds = append(conds, builder.And(builder.Lt{"ctime": time.Now().AddDate(0, 0, -7).Unix()})) conds = append(conds, builder.And(builder.Lt{"ctime": time.Now().AddDate(0, 0, -2).Unix()}).And(builder.Eq{"is_free": 1}))
page.PageSize = 20
articles := make([]*article.LianV1Article, 0) articles := make([]*article.LianV1Article, 0)
page.Content = &articles page.Content = &articles
err := a.repo.Find(page, conds) err := a.repo.Find(page, conds)

@ -71,7 +71,7 @@ func (r *ColumnRepositoryORM) FindByName(name string) (*column.Column, error) {
return nil, err return nil, err
} }
if !exists { if !exists {
return nil, errors.New("未找到用户") return nil, errors.New("未找到专栏")
} }
return &col, nil return &col, nil
} }

@ -1,7 +1,7 @@
<ion-app> <ion-app>
<ion-router-outlet></ion-router-outlet> <ion-router-outlet></ion-router-outlet>
<ion-tabs> <ion-tabs>
<ion-tab-bar slot="bottom"> <ion-tab-bar slot="bottom" *ngIf="showTabs">
<ion-tab-button tab="home"> <ion-tab-button tab="home">
<ion-icon name="home"></ion-icon> <ion-icon name="home"></ion-icon>
<ion-label>首页</ion-label> <ion-label>首页</ion-label>

@ -0,0 +1 @@
// ion-tab-bar

@ -1,4 +1,5 @@
import { Component } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -6,6 +7,22 @@ import { Component } from '@angular/core';
styleUrls: ['app.component.scss'], styleUrls: ['app.component.scss'],
standalone: false, standalone: false,
}) })
export class AppComponent { export class AppComponent implements OnInit {
constructor() {} showTabs = true;
constructor(private router: Router) {}
ngOnInit() {
this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
// 检查当前路由是否应该显示底部导航栏
this.showTabs = this.shouldShowTabs(event.url);
}
});
}
private shouldShowTabs(url: string): boolean {
// 在首页和我的页面显示底部导航栏
return url === '/home' || url === '/mine' || url === '/mine/login';
}
} }

@ -15,10 +15,8 @@ export class AuthInterceptor implements HttpInterceptor {
//从请求头获取token //从请求头获取token
intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
console.log(token)
let authHeader = req.headers; let authHeader = req.headers;
if (token != null && tokenNotExpired()) { if (token != null && tokenNotExpired()) {
console.log("is valid")
const bearer = AuthConfigConsts.HEADER_PREFIX_BEARER + token; const bearer = AuthConfigConsts.HEADER_PREFIX_BEARER + token;
authHeader = authHeader.set(AuthConfigConsts.DEFAULT_HEADER_NAME, bearer); authHeader = authHeader.set(AuthConfigConsts.DEFAULT_HEADER_NAME, bearer);
const authReq = req.clone({headers: authHeader}); const authReq = req.clone({headers: authHeader});

@ -26,6 +26,15 @@
<!-- 文章内容 --> <!-- 文章内容 -->
<div class="article-content" [innerHTML]="article!.content"></div> <div class="article-content" [innerHTML]="article!.content"></div>
<div class="stocks-content">
<span class="sc-title">相关个股:</span>
<span class="sc-content">{{ article?.stocks != '' ? article?.stocks : '暂无' }}</span>
</div>
<div class="public-content">
<span class="pb-title">路诚声明:</span>
<span class="pb-content">文章内容仅供参考,不构成投资建议。投资都据此操作,风险自担。</span>
</div>
<app-lc-fixed-bar></app-lc-fixed-bar> <app-lc-fixed-bar></app-lc-fixed-bar>
</ion-content> </ion-content>

@ -60,3 +60,40 @@ ion-back-button {
} }
} }
} }
.stocks-content {
display: flex;
flex-direction: row;
align-content: center;
margin-bottom: 24px;
.sc-title {
font-size: 12px;
color: #8B8D93;
font-weight: 500;
margin-right: 10px;
}
.sc-content {
font-size: 12px;
color: #1D1E22;
font-weight: 500;
}
}
.public-content {
display: flex;
flex-direction: row;
align-content: center;
margin-bottom: 24px;
span{
opacity: 0.75;
font-size: 12px;
color: #8B8D93;
font-weight: 400;
}
.pb-title {
width: 60px;
}
.pb-content {
}
}

@ -3,6 +3,7 @@ import {Article} from "../../../shared/model/article";
import {AlertController, NavController, ToastController} from "@ionic/angular"; import {AlertController, NavController, ToastController} from "@ionic/angular";
import {getGiftCount, getUser, useGiftCount} from "../../../mine/mine.service"; import {getGiftCount, getUser, useGiftCount} from "../../../mine/mine.service";
import {HomeService} from "../../home.service"; import {HomeService} from "../../home.service";
import {Router} from "@angular/router";
import {debounceTime, Subject, takeUntil} from "rxjs"; import {debounceTime, Subject, takeUntil} from "rxjs";
@ -22,7 +23,8 @@ export class ArticleItemComponent implements OnInit,AfterViewInit {
private alertCtrl: AlertController, private alertCtrl: AlertController,
private cdr: ChangeDetectorRef, private cdr: ChangeDetectorRef,
private toastCtrl: ToastController, private toastCtrl: ToastController,
private homeService: HomeService) { private homeService: HomeService,
private router: Router) {
} }
ngOnInit() { ngOnInit() {
@ -39,7 +41,21 @@ export class ArticleItemComponent implements OnInit,AfterViewInit {
this.alertCtrl.create({ this.alertCtrl.create({
header: '提示', header: '提示',
message: '请先登录后再进行操作', message: '请先登录后再进行操作',
buttons: ['确定'] buttons: [
{
text: '取消',
role: 'cancel'
},
{
text: '去登录',
handler: () => {
// 保存当前路径并跳转到登录页
this.navCtrl.navigateForward('/mine/login', {
state: { returnUrl: this.router.url }
});
}
}
]
}).then(alert => alert.present()); }).then(alert => alert.present());
} else { } else {
this.homeService.getArticlePrice(this.article.eventId).subscribe((res) => { this.homeService.getArticlePrice(this.article.eventId).subscribe((res) => {
@ -50,7 +66,6 @@ export class ArticleItemComponent implements OnInit,AfterViewInit {
} }
this.username = res.username this.username = res.username
}) })
} }
getFreeReadCount():number{ getFreeReadCount():number{
@ -121,7 +136,7 @@ export class ArticleItemComponent implements OnInit,AfterViewInit {
} }
detail() { detail() {
if (this.article.unlock && this.article.stocks != "" && this.article.content != "") { if (this.article.unlock && this.article.content != "") {
this.navCtrl.navigateForward('/home/article-detail', { this.navCtrl.navigateForward('/home/article-detail', {
state: {article: this.article} state: {article: this.article}
}); });

@ -28,7 +28,7 @@ export class ColumnDescribePage implements OnInit {
const iconMap: { [key: string]: string } = { const iconMap: { [key: string]: string } = {
'盘中宝': 'pzb.png', '盘中宝': 'pzb.png',
'风口研报': 'fkyb.png', '风口研报': 'fkyb.png',
'狙击龙虎榜': 'jjlhb.png', '狙击龙虎榜': 'lhb.png',
'电报解读': 'dbjd.png', '电报解读': 'dbjd.png',
'财联社早知道': 'clzzd.png', '财联社早知道': 'clzzd.png',
'研选': 'yx.png', '研选': 'yx.png',

@ -41,10 +41,14 @@
</ion-content> </ion-content>
<!-- 底部固定按钮 --> <!-- 底部固定按钮 -->
<div class="fixed-bottom" *ngIf="!column?.unlock"> <ion-footer *ngIf="!column?.unlock">
<ion-toolbar class="footer-toolbar">
<div class="fixed-bottom">
<div class="price"> <div class="price">
<p class="p1">盘中宝</p> <p class="p1">盘中宝</p>
<p class="p2">重磅信息挖掘</p> <p class="p2">重磅信息挖掘</p>
</div> </div>
<button class="buy-btn" (click)="onBuyClick()">立即订购</button> <button class="buy-btn" (click)="onBuyClick()">立即订购</button>
</div> </div>
</ion-toolbar>
</ion-footer>

@ -132,18 +132,21 @@
} }
} }
.footer-toolbar {
--padding-start: 0;
--padding-end: 0;
--padding-top: 0;
--padding-bottom: 0;
--background: linear-gradient(90deg, #474D5D 0%, #333742 75%);
}
.fixed-bottom { .fixed-bottom {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 60px;
background: linear-gradient(90deg, #474D5D 0%, #333742 75%);
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
z-index: 1000; height: 60px;
padding-left: 16px; padding-left: 16px;
.price { .price {
text-align: center; text-align: center;
display: flex; display: flex;

@ -1,9 +1,11 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { ModalController, NavController, AlertController } from "@ionic/angular"; import { ModalController, NavController, AlertController } from "@ionic/angular";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { HomeService } from '../home.service'; import { HomeService } from '../home.service';
import { Column } from '../../shared/model/column'; import { Column } from '../../shared/model/column';
import { getUser } from "../../mine/mine.service"; import { getUser } from "../../mine/mine.service";
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-special-column', selector: 'app-special-column',
@ -11,9 +13,10 @@ import { getUser } from "../../mine/mine.service";
styleUrls: ['./special-column.page.scss'], styleUrls: ['./special-column.page.scss'],
standalone: false, standalone: false,
}) })
export class SpecialColumnPage implements OnInit { export class SpecialColumnPage implements OnInit, OnDestroy {
name: string = "" name: string = ""
column!: Column; column: Column | null = null;
private destroy$ = new Subject<void>();
constructor( constructor(
private navCtrl: NavController, private navCtrl: NavController,
@ -33,32 +36,54 @@ export class SpecialColumnPage implements OnInit {
ngOnInit() { ngOnInit() {
} }
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
getColumnData() { getColumnData() {
this.homeService.getColumnByName(this.name).subscribe(data => { this.homeService.getColumnByName(this.name)
.pipe(takeUntil(this.destroy$))
.subscribe(data => {
this.column = data; this.column = data;
}) })
} }
onBuyClick() { onBuyClick() {
// 检查用户是否已登录 // 检查用户是否已登录
getUser().subscribe(user => { getUser().pipe(takeUntil(this.destroy$)).subscribe((res)=>{
if (!user?.username) { if(res.username == "") {
// 未登录,显示提示框 // 未登录,显示提示框
this.alertCtrl.create({ this.alertCtrl.create({
header: '提示', header: '提示',
message: '请先登录后再进行操作', message: '请先登录后再进行操作',
buttons: ['确定'] buttons: [
}).then(alert => alert.present()); {
return; text: '取消',
role: 'cancel'
},
{
text: '去登录',
handler: () => {
// 保存当前路径并跳转到登录页
this.navCtrl.navigateForward('/mine/login', {
state: { returnUrl: this.router.url }
});
} }
}
]
}).then(alert => alert.present());
} else {
// 已登录,获取价格并跳转到购买页面 // 已登录,获取价格并跳转到购买页面
this.getColumnPrice(); this.getColumnPrice();
}); }
})
} }
getColumnPrice() { getColumnPrice() {
this.homeService.getColumnPrice(this.column.id).subscribe((res)=>{ this.homeService.getColumnPrice(this.column!.id)
.pipe(takeUntil(this.destroy$))
.subscribe((res)=>{
this.navCtrl.navigateForward('/home/column-buy', { this.navCtrl.navigateForward('/home/column-buy', {
state: { column: this.column, price: res } state: { column: this.column, price: res }
}); });

@ -17,6 +17,7 @@ import {
SlideRef SlideRef
} from "go-captcha-angular"; } from "go-captcha-angular";
import {CaptchaModalComponent} from "../component/captcha-modal/captcha-modal.component"; import {CaptchaModalComponent} from "../component/captcha-modal/captcha-modal.component";
@Component({ @Component({
selector: 'app-login', selector: 'app-login',
templateUrl: './login.page.html', templateUrl: './login.page.html',
@ -32,6 +33,7 @@ export class LoginPage implements OnInit, OnDestroy,AfterViewInit {
private countdown = 60; private countdown = 60;
private timer: any; private timer: any;
private verifyToken: string | null = null; private verifyToken: string | null = null;
private returnUrl: string | null = null;
constructor( constructor(
private fb: FormBuilder, private fb: FormBuilder,
@ -47,6 +49,12 @@ export class LoginPage implements OnInit, OnDestroy,AfterViewInit {
password: [''], password: [''],
smsCode: [''] smsCode: ['']
}); });
// 获取返回路径
const navigation = this.router.getCurrentNavigation();
if (navigation?.extras?.state?.['returnUrl']) {
this.returnUrl = navigation.extras.state['returnUrl'];
}
} }
ngOnInit() { ngOnInit() {
@ -59,8 +67,6 @@ export class LoginPage implements OnInit, OnDestroy,AfterViewInit {
this.stopCountdown() ; this.stopCountdown() ;
} }
private createForm() { private createForm() {
// 根据登录类型动态设置验证器 // 根据登录类型动态设置验证器
this.loginForm.get('password')?.setValidators( this.loginForm.get('password')?.setValidators(
@ -73,7 +79,6 @@ export class LoginPage implements OnInit, OnDestroy,AfterViewInit {
// 显示滑动验证码 // 显示滑动验证码
showSlideVerify(type: 'sms' | 'password') { showSlideVerify(type: 'sms' | 'password') {
const phone = this.loginForm.get('phone')?.value; const phone = this.loginForm.get('phone')?.value;
if (!phone || !this.loginForm.get('phone')?.valid) { if (!phone || !this.loginForm.get('phone')?.valid) {
@ -103,7 +108,6 @@ export class LoginPage implements OnInit, OnDestroy,AfterViewInit {
} }
}) })
}) })
}); });
} }
@ -155,8 +159,13 @@ export class LoginPage implements OnInit, OnDestroy,AfterViewInit {
loginRequest.subscribe({ loginRequest.subscribe({
next: (response) => { next: (response) => {
this.showToast('登录成功'); this.showToast('登录成功');
localStorage.setItem("token",response) localStorage.setItem("token",response);
this.navCtrl.back() // 如果有返回路径,则导航到该路径
if (this.returnUrl) {
this.router.navigateByUrl(this.returnUrl);
} else {
this.navCtrl.back();
}
}, },
error: (error) => { error: (error) => {
let errorMessage = '登录失败,请重试'; let errorMessage = '登录失败,请重试';

Loading…
Cancel
Save