modify:新增小程序

This commit is contained in:
ECRZ
2026-01-06 18:00:43 +08:00
parent 498fa0e915
commit da4a055c1c
47 changed files with 7321 additions and 61 deletions

188
Sale/pages/index/CLAUDE.md Normal file
View File

@@ -0,0 +1,188 @@
[根目录](../../CLAUDE.md) > [pages](../) > **index**
---
# pages/index - 主页模块
> 最后更新2026-01-06 15:26:54
---
## 变更记录 (Changelog)
### 2026-01-06
- 初始化模块文档
- 识别为用户信息展示模板页面,需改造为价格查询功能
---
## 模块职责
当前状态:**微信小程序模板主页**,展示用户头像与昵称信息。
**目标职责**(需实现):
- 作为钢材价格查询的入口页面
- 提供搜索条件选择(地区、材质、规格、日期)
- 展示价格查询结果列表
- 跳转到价格趋势详情页面
---
## 入口与启动
### 页面路径
- **注册路径**`pages/index/index`(在 `app.json` 中注册)
- **物理路径**`pages/index/index.js`
- **访问方式**:小程序启动时的首页
### 生命周期
```javascript
Page({
onLoad() { }, // 页面加载
onReady() { }, // 页面初次渲染完成
onShow() { } // 页面显示
})
```
---
## 对外接口
### 页面跳转接口
- **跳转到日志页**`bindViewTap()` 方法
```javascript
wx.navigateTo({
url: '../logs/logs'
})
```
### 用户信息接口
- **获取用户头像**`onChooseAvatar(e)`
- **输入昵称**`onInputChange(e)`
- **获取用户资料**`getUserProfile(e)`(已废弃,推荐使用 `chooseAvatar`
---
## 关键依赖与配置
### 依赖文件
| 文件 | 用途 |
|------|------|
| `index.js` | 页面逻辑 |
| `index.wxml` | 页面结构 |
| `index.wxss` | 页面样式 |
| `index.json` | 页面配置(当前为空) |
### 外部依赖
- 微信小程序基础库 2.10.4+
- 无外部 npm 包依赖
### 配置文件
```json
// index.json当前为空对象
{}
```
---
## 数据模型
### 当前数据结构
```javascript
data: {
motto: 'Hello World',
userInfo: {
avatarUrl: 'https://mmbiz.qpic.cn/...',
nickName: ''
},
hasUserInfo: false,
canIUseGetUserProfile: wx.canIUse('getUserProfile'),
canIUseNicknameComp: wx.canIUse('input.type.nickname')
}
```
### 建议的数据结构(改造后)
```javascript
data: {
regions: ['昆明', '玉溪', '大理', '楚雄'], // 地区列表
materials: ['HPB300', 'HRB400', 'HRB500E'], // 材质列表
selectedRegion: '', // 选中的地区
selectedMaterial: '', // 选中的材质
selectedDate: '', // 选中的日期
priceList: [], // 查询结果
loading: false, // 加载状态
errorMessage: '' // 错误信息
}
```
---
## 测试与质量
### 测试覆盖
- **手动测试**:可在微信开发者工具中测试用户头像/昵称功能
- **单元测试**:暂无
- **快照测试**:暂无
### 已知问题
1. 当前页面为模板代码,未实现实际业务功能
2. 缺少价格查询相关逻辑
3. 缺少 API 调用封装
---
## 常见问题 (FAQ)
### Q: 如何改造为价格查询页面?
A: 建议步骤:
1. 删除用户信息相关代码
2. 添加搜索表单(地区、材质、日期选择器)
3. 实现查询按钮点击事件
4. 调用 `/api/prices/search` 接口
5. 展示查询结果列表
### Q: 如何调用后端 API
A: 使用 `wx.request()`,参考示例:
```javascript
wx.request({
url: 'http://localhost:3000/api/prices/search',
data: {
region: this.data.selectedRegion,
material: this.data.selectedMaterial,
date: this.data.selectedDate
},
success: (res) => {
this.setData({
priceList: res.data.data
})
}
})
```
---
## 相关文件清单
```
pages/index/
├── index.js # 页面逻辑50 行)
├── index.wxml # 页面结构28 行)
├── index.wxss # 页面样式
├── index.json # 页面配置
└── CLAUDE.md # 本文档
```
---
## 下一步建议
1. **重构 UI**:设计简洁的价格查询界面
2. **封装 API**:在 `utils` 中创建 `api.js` 封装请求方法
3. **添加图表**:集成 ECharts 或使用 Canvas 绘制价格趋势图
4. **优化体验**:添加加载动画、空状态提示、错误处理
---
**模块状态**:待开发
**优先级**:高
**预估工作量**4-6 小时

413
Sale/pages/index/index.js Normal file
View File

@@ -0,0 +1,413 @@
// pages/index/index.js
const api = require('../../utils/request')
Page({
data: {
// 地区选项 (对象格式)
regions: [
{ label: '昆明', value: '昆明' },
{ label: '玉溪', value: '玉溪' },
{ label: '楚雄', value: '楚雄' },
{ label: '大理', value: '大理' },
{ label: '曲靖', value: '曲靖' },
{ label: '红河', value: '红河' },
{ label: '文山', value: '文山' },
{ label: '重庆', value: '重庆' },
{ label: '成都', value: '成都' },
{ label: '广州', value: '广州' },
{ label: '南宁', value: '南宁' }
],
// 材质选项 (对象格式)
materials: [
{ label: '全部', value: '' },
{ label: 'HPB300', value: 'HPB300' },
{ label: 'HRB400', value: 'HRB400' },
{ label: 'HRB400E', value: 'HRB400E' },
{ label: 'HRB500', value: 'HRB500' },
{ label: 'HRB500E', value: 'HRB500E' },
{ label: 'HRB600', value: 'HRB600' },
{ label: 'CRB550', value: 'CRB550' },
{ label: 'Q235', value: 'Q235' },
{ label: 'Q345', value: 'Q345' },
{ label: 'Q355', value: 'Q355' }
],
// 品名选项 (对象格式)
partsnames: [
{ label: '全部', value: '' },
{ label: '高线', value: '高线' },
{ label: '螺纹钢', value: '螺纹钢' },
{ label: '盘螺', value: '盘螺' },
{ label: '工字钢', value: '工字钢' },
{ label: '槽钢', value: '槽钢' },
{ label: '角钢', value: '角钢' },
{ label: 'H型钢', value: 'H型钢' },
{ label: '钢板', value: '钢板' },
{ label: '卷板', value: '卷板' },
{ label: '中厚板', value: '中厚板' }
],
// 选中的值
selectedRegion: '',
selectedMaterial: '',
selectedPartsname: '',
// 显示的文本
regionText: '请选择地区',
materialText: '请选择材质 (可选)',
partsnameText: '全部',
// 选中的日期
selectedDate: '',
// 今天日期
today: '',
// 加载状态
loading: false,
// 是否已搜索
searched: false,
// 查询结果
priceList: [],
total: 0,
// 统计信息
stats: null,
// Picker 显示状态
regionPickerVisible: false,
materialPickerVisible: false,
partsnamePickerVisible: false,
datePickerVisible: false,
// Picker value (数组形式)
regionPickerValue: [],
materialPickerValue: [],
partsnamePickerValue: []
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
// 设置今天日期
const today = this.formatDate(new Date())
this.setData({ today })
// 测试 API 连接
this.testApiConnection()
},
/**
* 测试 API 连接
*/
async testApiConnection() {
try {
const res = await api.checkHealth()
console.log('API 连接成功:', res)
} catch (error) {
console.error('API 连接失败:', error)
api.showError('API 服务连接失败,请确保后端服务已启动')
}
},
/**
* 显示地区选择器
*/
showRegionPicker() {
this.setData({ regionPickerVisible: true })
},
/**
* 显示材质选择器
*/
showMaterialPicker() {
this.setData({ materialPickerVisible: true })
},
/**
* 显示品名选择器
*/
showPartsnamePicker() {
this.setData({ partsnamePickerVisible: true })
},
/**
* 显示日期选择器
*/
showDatePicker() {
this.setData({ datePickerVisible: true })
},
/**
* Picker 选择改变
*/
onPickerChange(e) {
const { key } = e.currentTarget.dataset
const { value } = e.detail
console.log('Picker change:', { key, value })
// 根据 key 设置对应的文本和值
if (key === 'region') {
const region = this.data.regions.find(item => item.value === value[0])
this.setData({
regionPickerVisible: false,
regionPickerValue: value,
selectedRegion: value[0] || '',
regionText: region ? region.label : '请选择地区'
})
} else if (key === 'material') {
const material = this.data.materials.find(item => item.value === value[0])
this.setData({
materialPickerVisible: false,
materialPickerValue: value,
selectedMaterial: value[0] || '',
materialText: material ? material.label : '请选择材质 (可选)'
})
} else if (key === 'partsname') {
const partsname = this.data.partsnames.find(item => item.value === value[0])
this.setData({
partsnamePickerVisible: false,
partsnamePickerValue: value,
selectedPartsname: value[0] || '',
partsnameText: partsname ? partsname.label : '全部'
})
}
},
/**
* Picker 取消选择
*/
onPickerCancel(e) {
const { key } = e.currentTarget.dataset
console.log('Picker cancel:', key)
if (key === 'region') {
this.setData({ regionPickerVisible: false })
} else if (key === 'material') {
this.setData({ materialPickerVisible: false })
} else if (key === 'partsname') {
this.setData({ partsnamePickerVisible: false })
} else if (key === 'date') {
this.setData({ datePickerVisible: false })
}
},
/**
* 日期选择确认
*/
onDateConfirm(e) {
const { value } = e.detail
this.setData({
selectedDate: value,
datePickerVisible: false
})
},
/**
* 日期选择取消
*/
onDatePickerCancel() {
this.setData({
datePickerVisible: false
})
},
/**
* 查询价格
*/
async onSearch() {
const {
selectedRegion,
selectedMaterial,
selectedPartsname,
selectedDate
} = this.data
// 验证必填项
if (!selectedRegion) {
api.showError('请选择地区')
return
}
// 开始加载
this.setData({
loading: true,
searched: false
})
try {
// 构建搜索参数
const searchParams = {
region: selectedRegion,
pageSize: 100
}
// 添加可选参数
if (selectedMaterial) searchParams.material = selectedMaterial
if (selectedPartsname) searchParams.partsname = selectedPartsname
if (selectedDate) searchParams.startDate = selectedDate
// 如果选择了日期,设置结束日期
if (selectedDate) {
searchParams.endDate = selectedDate
}
console.log('查询参数:', searchParams)
// 调用搜索接口
const searchResult = await api.searchPrices(searchParams)
console.log('查询结果:', searchResult)
// 获取统计数据
const statsParams = {
region: selectedRegion,
material: selectedMaterial
}
if (selectedDate) {
statsParams.startDate = selectedDate
statsParams.endDate = selectedDate
} else {
statsParams.days = 30
}
const statsResult = await api.getPriceStats(statsParams)
console.log('==================== 统计结果 ====================')
console.log('完整响应:', statsResult)
console.log('success:', statsResult.success)
console.log('data:', statsResult.data)
console.log('data 类型:', typeof statsResult.data)
console.log('data 字段:', Object.keys(statsResult.data || {}))
console.log('JSON 数据:', JSON.stringify(statsResult.data, null, 2))
console.log('====================================================')
// 更新数据
const priceList = searchResult.data || []
const total = searchResult.total || searchResult.pagination?.total || priceList.length || 0
// 格式化日期字段
const formattedList = priceList.map(item => {
let dateStr = ''
if (item.price_date) {
const date = new Date(item.price_date)
dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
}
return {
...item,
price_date_str: dateStr
}
})
this.setData({
priceList: formattedList,
total,
stats: statsResult.data || null,
searched: true,
loading: false
})
// 显示结果提示
if (searchResult.data && searchResult.data.length > 0) {
api.showSuccess(`查询成功,共找到 ${searchResult.data.length} 条数据`)
}
} catch (error) {
console.error('查询失败:', error)
this.setData({
loading: false,
searched: true,
priceList: [],
total: 0,
stats: null
})
// API 错误已在 request.js 中处理
}
},
/**
* 重置表单
*/
onReset() {
this.setData({
selectedRegion: '',
selectedMaterial: '',
selectedPartsname: '',
regionText: '请选择地区',
materialText: '请选择材质 (可选)',
partsnameText: '全部',
regionPickerValue: [],
materialPickerValue: [],
partsnamePickerValue: [],
selectedDate: '',
searched: false,
priceList: [],
total: 0,
stats: null
})
},
/**
* 查看价格详情
*/
onPriceDetail(e) {
const item = e.currentTarget.dataset.item
// 格式化日期
const formatDate = (dateStr) => {
if (!dateStr) return '-'
const date = new Date(dateStr)
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
}
// 构建详情信息
let detail = `地区:${item.price_region || '-'}\n`
detail += `品名:${item.partsname_name || '-'}\n`
detail += `材质:${item.goods_material || '-'}\n`
if (item.goods_spec) {
detail += `规格:${item.goods_spec}\n`
}
const price = item.hang_price || item.make_price || '-'
detail += `价格:¥${price}\n`
detail += `日期:${formatDate(item.price_date)}\n`
if (item.price_source) {
detail += `来源:${item.price_source}\n`
}
if (item.productarea_name) {
detail += `产地:${item.productarea_name}\n`
}
detail += `单位:元/吨`
wx.showModal({
title: '价格详情',
content: detail,
showCancel: false,
confirmText: '关闭'
})
},
/**
* 格式化日期为 YYYY-MM-DD
*/
formatDate(date) {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
},
/**
* TabBar 切换
*/
onTabChange(e) {
const value = e.detail.value
console.log('TabBar 切换:', value, '类型:', typeof value)
// value 可能是字符串或数字,统一处理
const tabIndex = parseInt(value)
if (tabIndex === 0) {
// 当前页,不做处理
console.log('已在当前页,不跳转')
return
} else if (tabIndex === 1) {
// 跳转到价格趋势页
console.log('跳转到价格趋势页')
wx.navigateTo({
url: '/pages/trend/trend'
})
}
}
})

View File

@@ -0,0 +1,4 @@
{
"usingComponents": {
}
}

215
Sale/pages/index/index.wxml Normal file
View File

@@ -0,0 +1,215 @@
<!--pages/index/index.wxml-->
<view class="container">
<!-- 搜索表单区域 -->
<view class="search-section">
<view class="section-title">价格查询</view>
<!-- 地区选择 -->
<view class="form-item">
<t-cell-group>
<t-cell title="地区" note="{{regionText}}" arrow hover bindtap="showRegionPicker" required />
</t-cell-group>
</view>
<!-- 材质选择 -->
<view class="form-item">
<t-cell-group>
<t-cell title="材质" note="{{materialText}}" arrow hover bindtap="showMaterialPicker" />
</t-cell-group>
</view>
<!-- 品名选择 -->
<view class="form-item">
<t-cell-group>
<t-cell title="品名" note="{{partsnameText}}" arrow hover bindtap="showPartsnamePicker" />
</t-cell-group>
</view>
<!-- 日期选择 -->
<view class="form-item">
<t-cell-group>
<t-cell title="日期" note="{{selectedDate || '请选择日期 (可选)'}}" hover bindtap="showDatePicker" />
</t-cell-group>
</view>
<!-- 查询按钮 -->
<view class="btn-group">
<t-button
theme="primary"
size="large"
bindtap="onSearch"
loading="{{loading}}"
disabled="{{loading}}"
block>
查询价格
</t-button>
<t-button
theme="default"
size="large"
variant="outline"
bindtap="onReset"
disabled="{{loading}}"
block>
重置
</t-button>
</view>
</view>
<!-- 加载状态 -->
<t-loading theme="circular" loading="{{loading}}" text="加载中..." wx:if="{{loading}}"></t-loading>
<!-- 查询结果区域 -->
<view class="result-section" wx:if="{{searched && !loading}}">
<!-- 统计信息卡片 -->
<view
wx:if="{{stats && stats.count > 0}}"
class="stats-card">
<view class="stats-title">价格统计</view>
<view class="stats-grid">
<view class="stats-item">
<view class="stats-label">数据量</view>
<view class="stats-value">{{stats.count}} 条</view>
</view>
<view class="stats-item">
<view class="stats-label">平均价</view>
<view class="stats-value avg">¥{{stats.avgPrice}}</view>
</view>
<view class="stats-item">
<view class="stats-label">最低价</view>
<view class="stats-value min">¥{{stats.minPrice}}</view>
</view>
<view class="stats-item">
<view class="stats-label">最高价</view>
<view class="stats-value max">¥{{stats.maxPrice}}</view>
</view>
</view>
<t-divider></t-divider>
<view class="stats-trend" wx:if="{{stats.trend}}">
<text>价格趋势:</text>
<t-tag
theme="{{stats.trend === 'up' ? 'danger' : stats.trend === 'down' ? 'success' : 'default'}}"
variant="light"
size="small">
{{stats.trend === 'up' ? '↑ 上涨' : stats.trend === 'down' ? '↓ 下跌' : '→ 平稳'}}
</t-tag>
<text class="trend-rate" wx:if="{{stats.changeRate}}">{{stats.changeRate}}</text>
</view>
</view>
<!-- 价格列表 -->
<view class="price-list">
<view class="list-header">
<text wx:if="{{priceList.length > 0}}">共找到 {{total}} 条结果</text>
<text wx:else>暂无数据</text>
</view>
<!-- 价格卡片 -->
<view
class="price-card"
wx:for="{{priceList}}"
wx:key="id"
bindtap="onPriceDetail"
data-item="{{item}}">
<view class="price-main">
<view class="price-info">
<text class="price-region">{{item.price_region}}</text>
<text class="price-separator">·</text>
<text class="price-material">{{item.goods_material}}</text>
<text class="price-spec" wx:if="{{item.goods_spec}}">({{item.goods_spec}})</text>
</view>
<view class="price-value">¥{{item.hang_price || item.make_price}}</view>
</view>
<view class="price-sub">
<text class="price-date">{{item.price_date_str || item.price_date}}</text>
<t-tag wx:if="{{item.price_source}}" theme="primary" variant="light" size="small">{{item.price_source}}</t-tag>
<t-tag wx:if="{{item.productarea_name}}" theme="success" variant="light" size="small">{{item.productarea_name}}</t-tag>
</view>
</view>
<!-- 空状态 -->
<t-empty
wx:if="{{priceList.length === 0}}"
icon="search"
description="未找到相关价格数据"
tips="请尝试调整查询条件">
</t-empty>
</view>
</view>
<!-- 初始提示 -->
<view class="welcome-section" wx:if="{{!searched && !loading}}">
<view class="welcome-card">
<view class="welcome-icon">📊</view>
<view class="welcome-title">钢材价格查询</view>
<view class="welcome-desc">请选择地区和材质查询钢材价格信息</view>
</view>
<view class="features">
<view class="feature-item">
<view class="feature-icon">📊</view>
<view class="feature-text">实时价格</view>
</view>
<view class="feature-item">
<view class="feature-icon">📈</view>
<view class="feature-text">趋势分析</view>
</view>
<view class="feature-item">
<view class="feature-icon">🔍</view>
<view class="feature-text">多维筛选</view>
</view>
</view>
</view>
<!-- Picker 选择器 -->
<t-picker
visible="{{regionPickerVisible}}"
value="{{regionPickerValue}}"
data-key="region"
title="选择地区"
cancelBtn="取消"
confirmBtn="确认"
usingCustomNavbar
bindchange="onPickerChange"
bindcancel="onPickerCancel">
<t-picker-item options="{{regions}}"></t-picker-item>
</t-picker>
<t-picker
visible="{{materialPickerVisible}}"
value="{{materialPickerValue}}"
data-key="material"
title="选择材质"
cancelBtn="取消"
confirmBtn="确认"
usingCustomNavbar
bindchange="onPickerChange"
bindcancel="onPickerCancel">
<t-picker-item options="{{materials}}"></t-picker-item>
</t-picker>
<t-picker
visible="{{partsnamePickerVisible}}"
value="{{partsnamePickerValue}}"
data-key="partsname"
title="选择品名"
cancelBtn="取消"
confirmBtn="确认"
usingCustomNavbar
bindchange="onPickerChange"
bindcancel="onPickerCancel">
<t-picker-item options="{{partsnames}}"></t-picker-item>
</t-picker>
<t-date-time-picker
visible="{{datePickerVisible}}"
value="{{selectedDate}}"
mode="date"
end="{{today}}"
bind:confirm="onDateConfirm"
bind:cancel="onDatePickerCancel" />
<!-- TDesign TabBar -->
<t-tab-bar value="0" 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>

275
Sale/pages/index/index.wxss Normal file
View File

@@ -0,0 +1,275 @@
/**
* 钢材价格查询页面样式
* 使用 TDesign 组件库 + 自定义样式
*/
page {
background-color: #f5f5f5;
height: 100%;
}
.container {
width: 100%;
min-height: 100vh;
padding-bottom: 120rpx;
box-sizing: border-box;
}
/* ========== 搜索表单区域 ========== */
.search-section {
padding: 40rpx 30rpx;
margin-bottom: 20rpx;
}
.section-title {
font-size: 36rpx;
font-weight: bold;
color: #1a1a1a;
margin-bottom: 32rpx;
padding-left: 16rpx;
border-left: 6rpx solid #0052D9;
}
.form-item {
margin-bottom: 24rpx;
}
.btn-group {
display: flex;
gap: 20rpx;
margin-top: 40rpx;
}
/* ========== 加载状态 ========== */
t-loading {
margin: 40rpx 0;
}
/* ========== 查询结果区域 ========== */
.result-section {
padding: 0 30rpx;
width: 100%;
box-sizing: border-box;
}
/* 统计卡片 */
.stats-card {
background: #fff;
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 24rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
box-sizing: border-box;
}
.stats-title {
font-size: 28rpx;
font-weight: bold;
color: #1a1a1a;
margin-bottom: 20rpx;
padding-left: 8rpx;
}
.stats-grid {
display: flex;
flex-wrap: wrap;
gap: 12rpx;
}
.stats-item {
flex: 0 0 calc(100% - 6rpx);
background: #fafafa;
padding: 20rpx 16rpx;
border-radius: 8rpx;
text-align: center;
box-sizing: border-box;
min-height: 120rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.stats-label {
font-size: 24rpx;
color: #8c8c8c;
margin-bottom: 8rpx;
}
.stats-value {
font-size: 28rpx;
font-weight: bold;
color: #1a1a1a;
word-break: keep-all;
white-space: nowrap;
}
.stats-value.avg {
color: #0052D9;
}
.stats-value.min {
color: #52c41a;
}
.stats-value.max {
color: #ff4d4f;
}
.stats-trend {
margin-top: 16rpx;
padding-top: 16rpx;
border-top: 1rpx solid #f0f0f0;
font-size: 26rpx;
color: #595959;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
gap: 6rpx;
flex-wrap: wrap;
}
.trend-rate {
color: #8c8c8c;
font-size: 24rpx;
}
/* 价格列表 */
.price-list {
background: #fff;
border-radius: 16rpx;
padding: 24rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
margin-bottom: 24rpx;
}
.list-header {
font-size: 26rpx;
color: #8c8c8c;
margin-bottom: 16rpx;
padding: 0 8rpx;
}
.price-card {
background: #fff;
border-radius: 12rpx;
padding: 24rpx;
margin-bottom: 16rpx;
border: 1rpx solid #f0f0f0;
transition: all 0.3s;
}
.price-card:active {
background: #fafafa;
transform: scale(0.98);
}
.price-main {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
}
.price-info {
flex: 1;
display: flex;
align-items: center;
flex-wrap: wrap;
}
.price-region {
font-size: 30rpx;
font-weight: bold;
color: #1a1a1a;
margin-right: 8rpx;
}
.price-separator {
color: #d9d9d9;
margin: 0 8rpx;
}
.price-material {
font-size: 30rpx;
color: #1a1a1a;
font-weight: 500;
}
.price-spec {
font-size: 26rpx;
color: #8c8c8c;
margin-left: 8rpx;
}
.price-value {
font-size: 36rpx;
font-weight: bold;
color: #ff4d4f;
}
.price-sub {
display: flex;
align-items: center;
gap: 16rpx;
font-size: 24rpx;
}
.price-date {
color: #595959;
}
/* ========== 欢迎区域 ========== */
.welcome-section {
padding: 60rpx 30rpx;
}
.welcome-card {
background: linear-gradient(135deg, #0052D9 0%, #003C9E 100%);
border-radius: 24rpx;
padding: 60rpx 40rpx;
text-align: center;
box-shadow: 0 8rpx 24rpx rgba(0, 82, 217, 0.25);
margin-bottom: 40rpx;
}
.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);
}
.features {
display: flex;
justify-content: space-around;
background: #fff;
border-radius: 16rpx;
padding: 40rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
}
.feature-item {
text-align: center;
}
.feature-icon {
font-size: 56rpx;
margin-bottom: 12rpx;
}
.feature-text {
font-size: 26rpx;
color: #595959;
}