modify:新增小程序
This commit is contained in:
270
Sale/pages/trend/trend.js
Normal file
270
Sale/pages/trend/trend.js
Normal file
@@ -0,0 +1,270 @@
|
||||
// pages/trend/trend.js
|
||||
const api = require('../../utils/request')
|
||||
const echarts = require('../../components/ec-canvas/echarts')
|
||||
|
||||
let chart = null
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 地区选项
|
||||
regions: [
|
||||
'全部', '昆明', '玉溪', '楚雄', '大理', '曲靖', '红河', '文山',
|
||||
'重庆', '成都', '广州', '南宁'
|
||||
],
|
||||
// 材质选项
|
||||
materials: [
|
||||
'全部', 'HPB300', 'HRB400', 'HRB400E', 'HRB500', 'HRB500E',
|
||||
'HRB600', 'CRB550', 'Q235', 'Q345', 'Q355'
|
||||
],
|
||||
// 时间范围选项
|
||||
dayRanges: [
|
||||
{ label: '最近 7 天', value: 7 },
|
||||
{ label: '最近 15 天', value: 15 },
|
||||
{ label: '最近 30 天', value: 30 },
|
||||
{ label: '最近 60 天', value: 60 },
|
||||
{ label: '最近 90 天', value: 90 }
|
||||
],
|
||||
// 选中的索引
|
||||
selectedRegionIndex: 0,
|
||||
selectedMaterialIndex: 0,
|
||||
selectedDayIndex: 2,
|
||||
// 加载和搜索状态
|
||||
loading: false,
|
||||
searched: false,
|
||||
hasData: false,
|
||||
// 图表实例
|
||||
ec: {
|
||||
onInit: null
|
||||
},
|
||||
// 趋势数据
|
||||
trendData: null,
|
||||
// 统计数据
|
||||
startPrice: '-',
|
||||
endPrice: '-',
|
||||
priceChange: '-'
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
// 初始化图表
|
||||
this.setData({
|
||||
ec: {
|
||||
onInit: this.initChart.bind(this)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始化图表
|
||||
*/
|
||||
initChart(canvas, width, height, res) {
|
||||
console.log('initChart 被调用', {
|
||||
hasTrendData: !!this.data.trendData,
|
||||
dates: this.data.trendData?.dates,
|
||||
prices: this.data.trendData?.prices
|
||||
})
|
||||
|
||||
if (!this.data.trendData || !this.data.trendData.dates || this.data.trendData.dates.length === 0) {
|
||||
console.log('没有趋势数据,跳过图表初始化')
|
||||
return null
|
||||
}
|
||||
|
||||
// 创建图表实例
|
||||
const chartInstance = echarts.init(canvas)
|
||||
|
||||
const option = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: this.data.trendData.dates
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [{
|
||||
data: this.data.trendData.prices,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
areaStyle: {}
|
||||
}]
|
||||
}
|
||||
|
||||
chartInstance.setOption(option)
|
||||
console.log('图表初始化完成')
|
||||
|
||||
return chartInstance
|
||||
},
|
||||
|
||||
/**
|
||||
* 地区选择改变
|
||||
*/
|
||||
onRegionChange(e) {
|
||||
const index = parseInt(e.detail.value)
|
||||
this.setData({
|
||||
selectedRegionIndex: index
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 材质选择改变
|
||||
*/
|
||||
onMaterialChange(e) {
|
||||
const index = parseInt(e.detail.value)
|
||||
this.setData({
|
||||
selectedMaterialIndex: index
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 时间范围选择改变
|
||||
*/
|
||||
onDayRangeChange(e) {
|
||||
const index = parseInt(e.detail.value)
|
||||
this.setData({
|
||||
selectedDayIndex: index
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 查询趋势
|
||||
*/
|
||||
async onQuery() {
|
||||
const {
|
||||
selectedRegionIndex,
|
||||
selectedMaterialIndex,
|
||||
selectedDayIndex,
|
||||
regions,
|
||||
materials,
|
||||
dayRanges
|
||||
} = this.data
|
||||
|
||||
const region = selectedRegionIndex === 0 ? '' : regions[selectedRegionIndex]
|
||||
const material = selectedMaterialIndex === 0 ? '' : materials[selectedMaterialIndex]
|
||||
const days = dayRanges[selectedDayIndex].value
|
||||
|
||||
// 开始加载
|
||||
this.setData({
|
||||
loading: true,
|
||||
searched: false,
|
||||
hasData: false
|
||||
})
|
||||
|
||||
try {
|
||||
// 获取趋势数据
|
||||
const trendResult = await api.getPriceTrend({
|
||||
region,
|
||||
material,
|
||||
days
|
||||
})
|
||||
|
||||
console.log('趋势数据:', trendResult)
|
||||
|
||||
const trendData = trendResult.data || []
|
||||
|
||||
if (trendData.length === 0) {
|
||||
this.setData({
|
||||
loading: false,
|
||||
searched: true,
|
||||
hasData: false
|
||||
})
|
||||
api.showError('暂无趋势数据')
|
||||
return
|
||||
}
|
||||
|
||||
// 处理数据
|
||||
const dates = []
|
||||
const prices = []
|
||||
|
||||
trendData.forEach(item => {
|
||||
const date = new Date(item.date)
|
||||
const dateStr = `${date.getMonth() + 1}/${date.getDate()}`
|
||||
dates.push(dateStr)
|
||||
prices.push(item.avgPrice || item.avg_price || 0)
|
||||
})
|
||||
|
||||
// 计算统计数据
|
||||
const startPrice = prices[0] || 0
|
||||
const endPrice = prices[prices.length - 1] || 0
|
||||
const priceChange = endPrice - startPrice
|
||||
|
||||
console.log('准备更新数据和图表', { dates, prices, startPrice, endPrice })
|
||||
|
||||
this.setData({
|
||||
trendData: {
|
||||
dates,
|
||||
prices
|
||||
},
|
||||
startPrice,
|
||||
endPrice,
|
||||
priceChange,
|
||||
loading: false,
|
||||
searched: true,
|
||||
hasData: true
|
||||
}, () => {
|
||||
// setData 回调中重新初始化图表
|
||||
console.log('setData 完成,准备重新初始化图表')
|
||||
if (chart) {
|
||||
chart.clear()
|
||||
// 重新调用 initChart
|
||||
const canvas = chart.canvas
|
||||
if (canvas) {
|
||||
chart = this.initChart(canvas, canvas.width, canvas.height)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('查询趋势失败:', error)
|
||||
this.setData({
|
||||
loading: false,
|
||||
searched: true,
|
||||
hasData: false
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 重置
|
||||
*/
|
||||
onReset() {
|
||||
this.setData({
|
||||
selectedRegionIndex: 0,
|
||||
selectedMaterialIndex: 0,
|
||||
selectedDayIndex: 2,
|
||||
searched: false,
|
||||
hasData: false,
|
||||
trendData: null,
|
||||
startPrice: '-',
|
||||
endPrice: '-',
|
||||
priceChange: '-'
|
||||
})
|
||||
|
||||
if (chart) {
|
||||
chart.clear()
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* TabBar 切换
|
||||
*/
|
||||
onTabChange(e) {
|
||||
const value = e.detail.value
|
||||
console.log('TabBar 切换:', value, '类型:', typeof value)
|
||||
|
||||
// value 可能是字符串或数字,统一处理
|
||||
const tabIndex = parseInt(value)
|
||||
|
||||
if (tabIndex === 1) {
|
||||
// 当前页,不做处理
|
||||
console.log('已在当前页,不跳转')
|
||||
return
|
||||
} else if (tabIndex === 0) {
|
||||
// 跳转到价格查询页
|
||||
console.log('跳转到价格查询页')
|
||||
wx.navigateTo({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
6
Sale/pages/trend/trend.json
Normal file
6
Sale/pages/trend/trend.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"usingComponents": {
|
||||
"ec-canvas": "../../components/ec-canvas/ec-canvas"
|
||||
},
|
||||
"navigationBarTitleText": "价格趋势"
|
||||
}
|
||||
127
Sale/pages/trend/trend.wxml
Normal file
127
Sale/pages/trend/trend.wxml
Normal file
@@ -0,0 +1,127 @@
|
||||
<!--pages/trend/trend.wxml-->
|
||||
<view class="container">
|
||||
<!-- 筛选条件区域 -->
|
||||
<view class="filter-section">
|
||||
<view class="section-title">趋势分析</view>
|
||||
|
||||
<!-- 地区选择 -->
|
||||
<view class="form-item">
|
||||
<view class="form-label">地区</view>
|
||||
<picker
|
||||
class="form-picker"
|
||||
mode="selector"
|
||||
range="{{regions}}"
|
||||
value="{{selectedRegionIndex}}"
|
||||
bindchange="onRegionChange">
|
||||
<view class="picker-text {{selectedRegionIndex === -1 ? 'placeholder' : ''}}">
|
||||
{{selectedRegionIndex === -1 ? '全部地区' : regions[selectedRegionIndex]}}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 材质选择 -->
|
||||
<view class="form-item">
|
||||
<view class="form-label">材质</view>
|
||||
<picker
|
||||
class="form-picker"
|
||||
mode="selector"
|
||||
range="{{materials}}"
|
||||
value="{{selectedMaterialIndex}}"
|
||||
bindchange="onMaterialChange">
|
||||
<view class="picker-text {{selectedMaterialIndex === -1 ? 'placeholder' : ''}}">
|
||||
{{selectedMaterialIndex === -1 ? '全部材质' : materials[selectedMaterialIndex]}}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 时间范围选择 -->
|
||||
<view class="form-item">
|
||||
<view class="form-label">时间范围</view>
|
||||
<picker
|
||||
class="form-picker"
|
||||
mode="selector"
|
||||
range="{{dayRanges}}"
|
||||
range-key="{{'label'}}"
|
||||
value="{{selectedDayIndex}}"
|
||||
bindchange="onDayRangeChange">
|
||||
<view class="picker-text {{selectedDayIndex === -1 ? 'placeholder' : ''}}">
|
||||
{{dayRanges[selectedDayIndex].label}}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<!-- 查询按钮 -->
|
||||
<view class="btn-group">
|
||||
<button
|
||||
class="btn-primary"
|
||||
bindtap="onQuery"
|
||||
loading="{{loading}}"
|
||||
disabled="{{loading}}">
|
||||
查询趋势
|
||||
</button>
|
||||
<button
|
||||
class="btn-secondary"
|
||||
bindtap="onReset"
|
||||
disabled="{{loading}}">
|
||||
重置
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 图表展示区域 -->
|
||||
<view class="chart-section" wx:if="{{hasData}}">
|
||||
<view class="chart-card">
|
||||
<view class="chart-title">价格走势图</view>
|
||||
<view class="chart-container">
|
||||
<ec-canvas id="mychart-dom-line" canvas-id="mychart-line" ec="{{ ec }}"></ec-canvas>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 数据统计卡片 -->
|
||||
<view class="stats-summary">
|
||||
<view class="stat-item">
|
||||
<view class="stat-label">起始价格</view>
|
||||
<view class="stat-value">¥{{startPrice}}</view>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<view class="stat-label">最新价格</view>
|
||||
<view class="stat-value {{priceChange >= 0 ? 'up' : 'down'}}">
|
||||
¥{{endPrice}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<view class="stat-label">价格变动</view>
|
||||
<view class="stat-value {{priceChange >= 0 ? 'up' : 'down'}}">
|
||||
{{priceChange >= 0 ? '+' : ''}}{{priceChange}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 初始提示 -->
|
||||
<view class="welcome-section" wx:if="{{!hasData && !loading}}">
|
||||
<view class="welcome-card">
|
||||
<view class="welcome-icon">📈</view>
|
||||
<view class="welcome-title">价格趋势分析</view>
|
||||
<view class="welcome-desc">选择地区和材质查看价格走势</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<view class="loading-section" wx:if="{{loading}}">
|
||||
<view class="loading-text">正在加载趋势数据...</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-section" wx:if="{{!hasData && searched && !loading}}">
|
||||
<view class="empty-icon">📊</view>
|
||||
<view class="empty-text">暂无趋势数据</view>
|
||||
<view class="empty-hint">请尝试调整查询条件</view>
|
||||
</view>
|
||||
|
||||
<!-- TDesign TabBar -->
|
||||
<t-tab-bar value="1" theme="normal" bindchange="onTabChange">
|
||||
<t-tab-bar-item value="0" icon="search" label="价格查询" />
|
||||
<t-tab-bar-item value="1" icon="chart-line" label="价格趋势" />
|
||||
</t-tab-bar>
|
||||
</view>
|
||||
222
Sale/pages/trend/trend.wxss
Normal file
222
Sale/pages/trend/trend.wxss
Normal file
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* 价格趋势页面样式
|
||||
*/
|
||||
|
||||
page {
|
||||
background-color: #f5f5f5;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
/* ========== 筛选条件区域 ========== */
|
||||
.filter-section {
|
||||
background: #fff;
|
||||
padding: 40rpx 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
border-radius: 0 0 24rpx 24rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 32rpx;
|
||||
padding-left: 16rpx;
|
||||
border-left: 6rpx solid #1890ff;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 28rpx;
|
||||
color: #595959;
|
||||
margin-bottom: 16rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-picker {
|
||||
background: #f5f5f5;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.picker-text {
|
||||
font-size: 30rpx;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.picker-text.placeholder {
|
||||
color: #bfbfbf;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.btn-primary,
|
||||
.btn-secondary {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-primary[disabled] {
|
||||
background: #d9d9d9;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #fff;
|
||||
color: #595959;
|
||||
border: 2rpx solid #d9d9d9;
|
||||
}
|
||||
|
||||
.btn-secondary[disabled] {
|
||||
border-color: #f0f0f0;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
|
||||
/* ========== 图表区域 ========== */
|
||||
.chart-section {
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.chart-card {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 24rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 500rpx;
|
||||
}
|
||||
|
||||
ec-canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* ========== 统计摘要 ========== */
|
||||
.stats-summary {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 24rpx;
|
||||
color: #8c8c8c;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.stat-value.up {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.stat-value.down {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
/* ========== 欢迎/空状态 ========== */
|
||||
.welcome-section,
|
||||
.empty-section {
|
||||
padding: 120rpx 30rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.welcome-card {
|
||||
background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
|
||||
border-radius: 24rpx;
|
||||
padding: 60rpx 40rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(82, 196, 26, 0.25);
|
||||
}
|
||||
|
||||
.welcome-icon {
|
||||
font-size: 120rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.welcome-title {
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.welcome-desc {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 120rpx;
|
||||
margin-bottom: 24rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 30rpx;
|
||||
color: #595959;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.empty-hint {
|
||||
font-size: 26rpx;
|
||||
color: #8c8c8c;
|
||||
}
|
||||
|
||||
/* ========== 加载状态 ========== */
|
||||
.loading-section {
|
||||
padding: 120rpx 30rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 28rpx;
|
||||
color: #8c8c8c;
|
||||
}
|
||||
Reference in New Issue
Block a user