Files
JiaZhiQianYan/pages/concept/historicalTimeline/historicalTimeline.vue
2026-01-04 18:13:05 +08:00

638 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view>
<navBar leftText="历史时间轴" :hideNavBg="true"></navBar>
<image class="topBg absolute" src="/static/image/index/conceptTopBg.png" mode="widthFix"></image>
<view class="timelineTitle fixed" :style="'top: '+navH+'px;'">{{conceptName}}- 历史时间轴</view>
<view class="dateStatisticsC fixed" :style="'top: '+contentTop+'px;'">
<view class="dateC">
<view class="yearMonthC flex">
<view class="btn" @click="clickPreMonth()">
<image class="icon" src="/static/icon/home/conceptCenter/pre.png" mode="widthFix"></image>
</view>
<view class="yearMonth flex1">
<picker mode="date" fields="month" @change="monthChange">
{{selectMonth}}
</picker>
</view>
<view class="btn" @click="clickNextMonth()">
<image class="icon" src="/static/icon/home/conceptCenter/next.png" mode="widthFix"></image>
</view>
</view>
<view class="weekList flex">
<view class="item flex1" v-for="(item,index) in weekList" :key="index">{{item}}</view>
</view>
<view class="monthDateList flexWrap">
<view class="item flexColumnCenter" v-for="(item,index) in monthDateList[selectMonthIndex]" :key="index" @click="clickSelectDate(item)">
<block v-if="item.date==selectDateStr">
<view :class="'date select '+(item.avg_change_pct?(getRateUpOrDown(item.avg_change_pct)?'down':'up'):'')">
{{item.day}}
<view v-if="item.avg_change_pct" class="chg">{{getChgRateStr(item.avg_change_pct)}}%</view>
</view>
</block>
<block v-else>
<block v-if="!item.isCurrentMonth">
<view class="date notCurrentMonth">{{item.day}}</view>
</block>
<block v-else>
<view :class="'date '+(item.avg_change_pct?(getRateUpOrDown(item.avg_change_pct)?'down':'up'):'')">
{{item.day}}
<view v-if="item.avg_change_pct" :class="'chg '+(getRateUpOrDown(item.avg_change_pct)?'down':'up')">{{getChgRateStr(item.avg_change_pct)}}%</view>
</view>
</block>
</block>
</view>
</view>
</view>
<view class="statisticsC">
<view class="date">{{selectDateStr}}统计</view>
<view v-if="chgStockData&&chgStockData.avg_change_pct" class="chgStockNumC flex">
<view class="chgC flex flex1">
<view class="title">涨跌幅</view>
<image v-if="getRateUpOrDown(chgStockData.avg_change_pct)" class="icon" src="/static/icon/home/conceptCenter/chgDown.png" mode="widthFix"></image>
<image v-else class="icon" src="/static/icon/home/conceptCenter/chgUp.png" mode="widthFix"></image>
<view :class="'chg '+(getRateUpOrDown(chgStockData.avg_change_pct)?'down':'up')">{{getChgRateStr(chgStockData.avg_change_pct)}}%</view>
</view>
<view class="stockNumC flex flex1">
<view class="title">统计股票</view>
<view class="stockNum">{{chgStockData.stock_count}} 只股票</view>
</view>
</view>
<view class="newsReportC flex">
<image class="icon" src="/static/icon/home/conceptCenter/newsReport.png" mode="widthFix"></image>
<text class="news">{{newsList.length}} 条新闻 · </text>
<text class="report" decode>&nbsp{{reportList.length}} 份研报</text>
</view>
<view class="list">
<view class="item" v-for="(item,index) in newsList" :key="index" @click="clickNewsItem(item)">
<view class="flex">
<view class="type news">新闻</view>
<view class="title flex1">{{item.title}}</view>
</view>
<view class="content">{{item.detail}}</view>
</view>
<view class="item" v-for="(item,index) in reportList" :key="index">
<view class="flex">
<view class="type report">研报</view>
<view class="title flex1">{{item.report_title}}</view>
</view>
<view class="content">坚定看好锂电材料建议继续加配坚定六氟添加剂关注隔膜更加坚定的看好六氟下游传导如期</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { inject } from 'vue';
import { conceptNews, conceptReport, priceTimeline } from '@/request/api';
import { getChgRateStr, getRateUpOrDown } from '@/utils/util';
export default {
data() {
return {
navH:inject('navHeight'),
contentTop:'',
conceptId:'', //概念id
conceptName:'',
weekList:['一','二','三','四','五','六','日'],
monthDateList:[],
selectMonthIndex:0, //选中月份下标
selectMonth:'', //选中年月
selectDateStr:'', //选中日期
startDateStr:'', //开始日期
endDateStr:'', //结束日期
chgStockData:null, //涨跌幅和股票数据
newsList:[], //新闻数据
reportList:[], //研报数据
getRateUpOrDown:getRateUpOrDown,
getChgRateStr:getChgRateStr,
}
},
onLoad(e) {
this.contentTop = this.navH + 70/750*inject('windowWidth')
let currentDate = new Date();
// 获取当前年份
let currentYear = currentDate.getFullYear();
let currentMonth = currentDate.getMonth()+1;
let currentDay = currentDate.getDate();
this.selectMonthIndex = 20*12+currentMonth-1
this.selectMonth = currentYear+'年'+currentMonth+'月'
//开始日期默认为当前月份第一天
this.startDateStr = currentYear+'-'+(currentMonth>9?currentMonth:('0'+currentMonth))+'-'+'01'
//结束日期默认为当前日期
this.endDateStr = this.selectDateStr = currentYear+'-'+(currentMonth>9?currentMonth:('0'+currentMonth))+'-'+(currentDay>9?currentDay:('0'+currentDay))
// this.getYesterdayDateData()
this.generateMonthDateListData()
if (e.id) {
this.conceptId = e.id
this.getTimelineData()
}
},
methods: {
/**
* 获取当前时间前一天的数据
*/
getYesterdayDateData()
{
let currentDate = new Date();
let selectDate = new Date(currentDate)
selectDate.setDate(selectDate.getDate()-1)
let selectYear = selectDate.getFullYear();
let selectMonth = selectDate.getMonth()+1;
let selectDay = selectDate.getDate();
this.selectDateStr = selectYear+'-'+(selectMonth>9?selectMonth:('0'+selectMonth))+'-'+(selectDay>9?selectDay:('0'+selectDay))
},
/**
* 生成日期数组
*/
generateMonthDateListData()
{
let currentDate = new Date();
// 获取当前年份
let currentYear = currentDate.getFullYear();
let currentMonth = currentDate.getMonth()+1;
let currentDay = currentDate.getDate();
let monthDateList = []
for (var i = currentYear-20; i < currentYear+20; i++) {
for (var j = 0; j < 12; j++) {
let date = new Date(i,j+1,0)
let firstDayOfMonth = new Date(i,j+1,0);
firstDayOfMonth.setDate(1);
//获取当前月天数
let currentMonthDay = date.getDate()
let firstDayWeek = firstDayOfMonth.getDay() || 7
let daysOfMonth = []
for (var k = 1; k <= currentMonthDay; k++) {
let newDate = new Date(i,j+1,0)
newDate.setDate(k); // 设置日期为当前月的相应日期
let newMonth = newDate.getMonth()+1
let newDay = newDate.getDate()
let time = newDate.getTime()
let date = i+'-'+(newMonth>9?newMonth:('0'+newMonth))+'-'+(newDay>9?newDay:('0'+newDay))
daysOfMonth.push({date:date,year:i,month:newMonth,day:newDay,isToday:(i==currentYear&&newMonth==currentMonth&&newDay==currentDay)?true:false,isCurrentMonth:true,isLastDay:newDay==currentMonthDay?true:false,timestamp:time});
}
for (var k = 0; k < firstDayWeek-1; k++) {
//获取上月天数
let year = i
let month = j
if(j<1)
{
year = i - 1
month = 12
}
let lastMonthDay = new Date(year, month, 0).getDate()
//获取上月日期
let newDate = new Date(year,month-1,lastMonthDay-k)
let newMonth = newDate.getMonth()+1
let newDay = newDate.getDate()
let time = newDate.getTime()
let date = year+'-'+(newMonth>9?newMonth:('0'+newMonth))+'-'+(newDay>9?newDay:('0'+newDay))
daysOfMonth.unshift({date:date,year:year,month:newMonth,day:newDay,isToday:false,isCurrentMonth:false,isLastDay:false,timestamp:time});
}
// 下一个月的第一天
let nextMonthFirstDay = new Date(i, j+1, 1);
// 然后减去一天就是当前月的最后一天
let lastDayOfMonth = new Date(nextMonthFirstDay - (24 * 60 * 60 * 1000)); // 减去一天的毫秒数
let lastDayWeek = lastDayOfMonth.getDay() || 7; // 返回0星期天到6星期六
for (var k = 1; k < 8-lastDayWeek; k++) {
let year = i
let month = j
if(month>11)
{
month = 0
year ++
}
//获取下月日期
let newDate = new Date(year,month + 1,k)
let newMonth = newDate.getMonth()+1
let newDay = newDate.getDate()
let time = newDate.getTime()
let date = year+'-'+(newMonth>9?newMonth:('0'+newMonth))+'-'+(newDay>9?newDay:('0'+newDay))
daysOfMonth.push({date:date,year:year,month:newMonth,day:newDay,isToday:false,isCurrentMonth:false,isLastDay:false,timestamp:time});
}
monthDateList.push(daysOfMonth)
}
}
this.monthDateList = monthDateList
},
/**
* 点击上个月
*/
clickPreMonth()
{
if(this.selectMonthIndex>0)
{
this.selectMonthIndex --
let monthList = this.monthDateList[this.selectMonthIndex]
let year = ''
let month = ''
for (let item of monthList) {
if(item.isCurrentMonth)
{
year = item.year
month = item.month
break
}
}
let lastDay = ''
for (let item of monthList) {
if(item.isLastDay)
{
lastDay = item.day
break
}
}
this.selectMonth = year+'年'+month+'月'
this.startDateStr = year+'-'+(month>9?month:('0'+month))+'-'+'01'
this.endDateStr = year+'-'+(month>9?month:('0'+month))+'-'+lastDay
this.getTimelineData()
}
},
/**
* 点击下个月
*/
clickNextMonth()
{
if(this.selectMonthIndex<this.monthDateList.length-1)
{
this.selectMonthIndex ++
let monthList = this.monthDateList[this.selectMonthIndex]
let year = ''
let month = ''
for (let item of monthList) {
if(item.isCurrentMonth)
{
year = item.year
month = item.month
break
}
}
let lastDay = ''
for (let item of monthList) {
if(item.isLastDay)
{
lastDay = item.day
break
}
}
this.selectMonth = year+''+month+''
this.startDateStr = year+'-'+(month>9?month:('0'+month))+'-'+'01'
this.endDateStr = year+'-'+(month>9?month:('0'+month))+'-'+lastDay
this.getTimelineData()
}
},
monthChange(e)
{
let currentDate = new Date();
//当前年份
let currentYear = currentDate.getFullYear()
//选中年月
let yearMonth = e.detail.value
let selectYear = parseInt(yearMonth.split('-')[0])
let selectMonth = parseInt(yearMonth.split('-')[1])
this.selectMonthIndex = (selectYear - (currentYear - 20))*12+selectMonth-1
this.selectMonth = selectYear+'年'+selectMonth+'月'
this.startDateStr = selectYear+'-'+(selectMonth>9?selectMonth:('0'+selectMonth))+'-'+'01'
let lastDayOfMonth = new Date(selectYear, selectMonth, 0);
this.endDateStr = selectYear+'-'+(selectMonth>9?selectMonth:('0'+selectMonth))+'-'+lastDayOfMonth.getDate()
this.getTimelineData()
},
/**
* 点击选择开始日期和结束日期
* @param {Object} item
*/
clickSelectDate(item)
{
if (this.selectDateStr!=item.date){
this.selectDateStr = item.date
this.chgStockData = item
this.getNewsData()
this.getReportData()
}
},
/**
* 点击查看新闻详情
* @param {Object} item
*/
clickNewsItem(item) {
uni.navigateTo({
url:'/pages/concept/conceptNewsDetails/conceptNewsDetails?info='+encodeURIComponent(JSON.stringify(item))
})
},
/**
* 获取时间序列数据
*/
getTimelineData()
{
let param = {start_date:this.startDateStr,end_date:this.endDateStr}
priceTimeline(this.conceptId,param).then(res=>{
if(res.timeseries)
{
this.conceptName = res.concept_name
let timeseries = res.timeseries
let monthList = this.monthDateList[this.selectMonthIndex]
for (let item of monthList) {
for (let item1 of timeseries) {
if (item.date==item1.trade_date) {
item.avg_change_pct = item1.avg_change_pct
item.stock_count = item1.stock_count
if(item.date==this.selectDateStr){
this.chgStockData = item
}
}
}
}
this.getNewsData()
this.getReportData()
}
}).catch(error=>{
})
},
/**
* 获取新闻数据
*/
getNewsData()
{
let param = {query:this.conceptName,end_date:this.selectDateStr,exact_match:1,top_k:100}
conceptNews(param).then(res=>{
this.newsList = res
}).catch(error=>{
})
},
/**
* 获取时间序列数据
*/
getReportData()
{
let param = {query:this.conceptName,start_date:this.selectDateStr,mode:'text',exact_match:1}
conceptReport(param).then(res=>{
this.reportList = res.data.results
}).catch(error=>{
})
}
}
}
</script>
<style lang="less">
page
{
background-color: #070707;
}
.topBg
{
top: 0;
left: 0;
width: 100%;
height: auto;
}
.timelineTitle
{
background-color: #FFF9F5;
left: 0;
right: 0;
margin: 0 25rpx;
padding: 30rpx 27rpx 0;
border-radius: 10rpx 10rpx 0 0;
font-size: 28rpx;
font-weight: bold;
color: #2B2B2B;
}
.dateStatisticsC
{
background-color: #FFF9F5;
left: 0;
right: 0;
bottom: 86rpx;
margin: 0 25rpx;
padding: 24rpx 25rpx 0;
border-radius: 0 0 10rpx 10rpx;
overflow-y: scroll;
.dateC
{
background-color: white;
box-shadow: 0 5rpx 10rpx 0 rgba(127,127,127,0.1);
border-radius: 10rpx;
padding: 30rpx 25rpx 0;
.yearMonthC
{
background-color: #F7F7F7;
height: 70rpx;
border-radius: 35rpx;
.btn
{
padding: 0 52rpx;
.icon
{
width: 13rpx;
height: auto;
}
}
.yearMonth
{
font-size: 32rpx;
font-weight: 500;
color: #070707;
text-align: center;
}
}
.weekList
{
.item
{
margin-right: 13rpx;
line-height: 72rpx;
font-size: 26rpx;
font-weight: 500;
color: #A7A7A7;
text-align: center;
}
}
.monthDateList
{
.item
{
margin-bottom: 12rpx;
width: calc(100%/7);
.date
{
background-color: #f8f8f8;
padding: 4rpx 0;
width: calc(100% - 10rpx);
height: 72rpx;
border-radius: 10rpx;
font-size: 26rpx;
font-weight: bold;
color: #2A2A2A;
text-align: center;
.chg
{
font-size: 18rpx;
}
.chg.up
{
color: #EC3440;
}
.chg.down
{
color: #38A169;
}
}
.date.up
{
background-color: #FFD6D9;
}
.date.down
{
background-color: #CEF1DE;
}
.date.select.up
{
background-color: #EC3440;
color: white;
.chg
{
color: white;
}
}
.date.select.down
{
background-color: #38A169;
color: white;
.chg
{
color: white;
}
}
.date.notCurrentMonth
{
background-color: #FCFCFC;
color: #999;
}
}
}
}
.statisticsC
{
background-color: white;
margin-top: 20rpx;
padding: 28rpx 20rpx 0;
border-radius: 10rpx;
.date
{
font-size: 30rpx;
font-weight: 500;
text-align: center;
}
.chgStockNumC
{
margin-top: 36rpx;
padding: 0 13rpx 28rpx;
border-bottom: solid 1rpx #EDEDED;
font-size: 26rpx;
.title
{
margin-right: 18rpx;
font-weight: 500;
color: #94979C;
}
.chgC
{
.icon
{
margin-right: 9rpx;
width: 17rpx;
height: auto;
}
.chg
{
font-weight: bold;
}
.chg.up
{
color: #EC3440;
}
.chg.down
{
color: #38A169;
}
}
.stockNum
{
font-weight: bold;
color: #070707;
}
}
.newsReportC
{
padding-top: 20rpx;
font-size: 28rpx;
font-weight: bold;
.icon
{
margin-right: 20rpx;
width: 24rpx;
height: auto;
}
.news
{
color: #FF7723;
}
.report
{
color: #333;
}
}
.list
{
.item
{
padding: 30rpx 0;
border-bottom: solid 1rpx #EDEDED;
.type
{
margin-right: 18rpx;
padding: 0 9rpx;
line-height: 40rpx;
border-radius: 5rpx;
font-size: 22rpx;
font-weight: 500;
}
.type.news
{
background-color: #F2C367;
color: #070707;
}
.type.report
{
background-color: #3D3F3C;
color: #F2C367;
}
.title
{
font-size: 26rpx;
font-weight: bold;
color: #070707;
}
.content
{
margin-top: 20rpx;
font-size: 24rpx;
font-weight: 500;
color: #333;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
}
}
</style>