This commit is contained in:
hant 2025-07-14 00:16:37 +08:00
parent a241484705
commit 90ece932c9
25 changed files with 2677 additions and 605 deletions

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

8
.idea/car_front.iml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/car_front.iml" filepath="$PROJECT_DIR$/.idea/car_front.iml" />
</modules>
</component>
</project>

19
.idea/php.xml Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -1,7 +1,8 @@
{
"pages": [
"pages/index/index",
"pages/logs/logs"
"pages/info/info",
"pages/car_new/car_new"
],
"window": {
"navigationBarTextStyle": "black",
@ -12,4 +13,4 @@
"componentFramework": "glass-easel",
"sitemapLocation": "sitemap.json",
"lazyCodeLoading": "requiredComponents"
}
}

203
pages/car_new/car_new.js Normal file
View File

@ -0,0 +1,203 @@
const request = require('../../utils/request');
Page({
data: {
carList: [],
selectedSort: 'default',
selectedBrand: '',
selectedPrice: '',
filterParams: {},
mainActiveIndex: 0,
selectedSeriesId: null,
selectedBrandLabel:"品牌",
brandTree: [],
sortOptions: [
{ text: '默认排序', value: 'default' },
{ text: '价格升序', value: 'priceAsc' },
{ text: '价格降序', value: 'priceDesc' }
],
priceOptions: [
{ text: '全部价格', value: '' },
{ text: '5万以下', value: '<5' },
{ text: '5-10万', value: '5-10'},
{ text: '10万以上', value: '>10' }
],
extendFields: [] // 筛选配置
},
onBrandClick(e) {
const index = e.detail.index;
const brand = this.data.brandTree[index];
this.setData({
mainActiveIndex: e.detail.index
});
// ✅ 如果该品牌没有子系列children
if (!brand.children || brand.children.length === 0) {
this.setData({
selectedSeriesId: null, // 没有选中的 series
selectedBrandLabel: brand.text
});
this.reloadList(); // 触发列表加载
this.selectComponent('#dropdownItemBrand').toggle(false); // 关闭下拉菜单
}
},
onSeriesSelect(e) {
const selectedId = e.detail.id;
const selectedText = e.detail.text;
this.setData({
selectedSeriesId: selectedId,
selectedBrandLabel: selectedText // ✅ 更新 dropdown 显示的值
});
this.reloadList();
this.selectComponent('#dropdownItemBrand').toggle(false); // 关闭
// TODO: 发起请求,用 selectedId 作为筛选条件
},
onSortChange(e) {
this.setData({ selectedSort: e.detail });
this.reloadList();
},
onPriceChange(e) {
this.setData({ selectedPrice: e.detail });
this.reloadList();
},
onParamChange(e) {
const value = e.detail.value;
this.setData({ selectedParam: value });
this.reloadList();
},
async reloadList() {
// TODO: 根据筛选值重新加载列表
const data = {
sort:this.data.selectedSort,
brand:this.data.selectedSeriesId,
price:this.data.selectedPrice,
attr:this.data.filterParams,
}
try {
const raw = await request({
url: '/admin/wechat/api/car',
method: 'POST',
data: data
});
this.setData({carList:raw.items})
} catch (err) {
console.error('加载品牌失败', err);
}
},
openMap() {
const { latitude, longitude, address, name } = this.data.company
wx.openLocation({
latitude,
longitude,
scale: 18,
name,
address
})
},
onLoad(){
this.loadBrandData();
},
async loadBrandData() {
try {
const raw = await request({
url: '/admin/wechat/api/select'
});
const brandTree = raw.brands.map(brand => ({
text: brand.label,
children: (brand.children || []).map(series => ({
id: series.value,
text: series.label
}))
}));
const fields = raw.extend.map(f => {
// 为 range 类型添加 start/end 临时字段
if (f.type === 'range') {
f._rangeStart = '';
f._rangeEnd = '';
} else if (f.type === 'checkbox') {
f.value = []; // 默认空数组
}
return f;
});
this.setData({ extendFields:fields });
this.setData({ brandTree });
this.reloadList();
} catch (err) {
console.error('加载品牌失败', err);
}
},
onTagToggle(e) {
const name = e.currentTarget.dataset.name;
const value = String(e.currentTarget.dataset.value);
const fields = this.data.extendFields.map(field => {
if (field.name === name) {
let list = (field.value || []).map(String);
const index = list.indexOf(value);
if (index > -1) {
list.splice(index, 1);
} else {
list.push(value);
}
field.value = list;
// ✅ 同步 checked 状态
field.options.forEach(opt => {
opt._checked = list.includes(String(opt.value));
});
}
return field;
});
this.setData({ extendFields: fields });
},
goToCarDetail(e) {
const id = e.currentTarget.dataset.id;
console.log(`/pages/info/info?id=${id}`)
wx.navigateTo({
url: `/pages/info/info?id=${id}`
});
},
onSliderChange(e) {
const name = e.currentTarget.dataset.name;
const [start, end] = e.detail;
const fields = this.data.extendFields.map(field => {
if (field.name === name) {
field._rangeStart = start;
field._rangeEnd = end;
}
return field;
});
this.setData({ extendFields: fields });
},
onExtendConfirm() {
const filterParams = {};
this.data.extendFields.forEach(field => {
if (field.type === 'checkbox') {
if (field.value?.length > 0) {
filterParams[field.name] = field.value;
}
} else if (field.type === 'range') {
if (field._rangeStart || field._rangeEnd) {
filterParams[field.name] = {
start: field._rangeStart,
end: field._rangeEnd
};
}
}
});
this.selectComponent('#dropdownItemParam').toggle(false); // 关闭
this.setData({filterParams:filterParams});
this.reloadList();
}
})

View File

@ -0,0 +1,11 @@
{
"usingComponents": {
"van-icon": "@vant/weapp/icon/index",
"van-dropdown-menu": "@vant/weapp/dropdown-menu/index",
"van-dropdown-item": "@vant/weapp/dropdown-item/index",
"van-tree-select": "@vant/weapp/tree-select/index",
"van-slider": "@vant/weapp/slider/index",
"van-tag": "@vant/weapp/tag/index",
"van-button": "@vant/weapp/button/index"
}
}

156
pages/car_new/car_new.wxml Normal file
View File

@ -0,0 +1,156 @@
<!--pages/car_new/car_new.wxml-->
<view class="sticky-filter">
<van-dropdown-menu>
<van-dropdown-item
value="{{selectedSort}}"
options="{{sortOptions}}"
bind:change="onSortChange"
/>
<van-dropdown-item id="dropdownItemBrand" title="{{selectedBrandLabel}}" use-slot>
<van-tree-select
height="400"
items="{{brandTree}}"
main-active-index="{{mainActiveIndex}}"
active-id="{{selectedSeriesId}}"
bind:click-nav="onBrandClick"
bind:click-item="onSeriesSelect"
/>
</van-dropdown-item>
<van-dropdown-item
value="{{selectedPrice}}"
options="{{priceOptions}}"
bind:change="onPriceChange"
/>
<van-dropdown-item title="参数"
use-slot
id="dropdownItemParam"
>
<view class="filter-extend">
<view wx:for="{{extendFields}}" wx:key="id" class="filter-group">
<view class="filter-label">{{item.label}}</view>
<!-- 多选项字段 -->
<view wx:if="{{item.type === 'checkbox'}}" class="filter-tags">
<view
wx:for="{{item.options}}"
wx:for-item="opt"
wx:key="index"
class="filter-tag-item"
data-name="{{item.name}}"
data-value="{{opt.value}}"
bind:tap="onTagToggle"
>
<van-tag
size="medium"
plain="{{!opt._checked}}"
>
{{opt.key}}
</van-tag>
</view>
</view>
<view wx:if="{{item.type === 'range'}}" class="filter-slider-group">
<view class="slider-label">
{{item.label}}{{item._rangeStart || item.options.start}}{{item.options.unit}} - {{item._rangeEnd || item.options.end}}{{item.options.unit}}
</view>
<van-slider
range
value="{{[item._rangeStart ? item._rangeStart : item.options.start, item._rangeEnd ? item._rangeEnd : item.options.end]}}"
min="{{item.options.start}}"
max="{{item.options.end}}"
data-name="{{item.name}}"
bind:change="onSliderChange"
/>
</view>
</view>
<van-button type="primary" block size="small" bind:tap="onExtendConfirm">确认</van-button>
</view>
</van-dropdown-item>
</van-dropdown-menu>
</view>
<!-- 汽车列表 -->
<view class="car-list">
<view wx:for="{{carList}}" wx:key="id" class="car-item car-type-{{item.car_type}}" bindtap="goToCarDetail" data-id="{{item.id}}">
<!-- 车辆类型标签 -->
<view class="car-type-badge">
<text wx:if="{{item.car_type == 1}}" class="badge-new">新车</text>
<text wx:elif="{{item.car_type == 2}}" class="badge-rent">租车</text>
<text wx:elif="{{item.car_type == 3}}" class="badge-used">二手车</text>
</view>
<image class="car-image" src="{{item.cover_image[0]}}" mode="aspectFill" />
<view class="car-info">
<view class="car-title">{{item.title}}</view>
<!-- 新车价格显示 -->
<view wx:if="{{item.car_type == 1}}" class="car-price">
<text class="price-new">¥{{item.price}}万起</text>
<text wx:if="{{item.re_price}}" class="price-old">指导价 ¥{{item.re_price}}万</text>
</view>
<!-- 租车价格显示 -->
<view wx:elif="{{item.car_type == 2}}" class="car-price">
<text class="price-rent">¥{{item.price}}/天</text>
<text wx:if="{{item.re_price}}" class="price-monthly">月租 ¥{{item.re_price}}</text>
</view>
<!-- 二手车价格显示 -->
<view wx:elif="{{item.car_type == 3}}" class="car-price">
<text class="price-used">¥{{item.price}}万</text>
<text wx:if="{{item.re_price}}" class="price-original">新车价 ¥{{item.re_price}}万</text>
</view>
<!-- 车辆特性标签 -->
<view class="car-attrs">
<!-- 新车特性 -->
<block wx:if="{{item.car_type == 1}}">
<van-tag wx:for="{{item.attr}}" wx:key="index" wx:for-item="opt" type="primary" size="mini">
{{opt}}
</van-tag>
<van-tag wx:if="{{item.is_new_model}}" type="success" size="mini">全新上市</van-tag>
<van-tag wx:if="{{item.has_discount}}" type="warning" size="mini">限时优惠</van-tag>
</block>
<!-- 租车特性 -->
<block wx:elif="{{item.car_type == 2}}">
<van-tag wx:for="{{item.attr}}" wx:key="index" wx:for-item="opt" type="success" size="mini">
{{opt}}
</van-tag>
<van-tag wx:if="{{item.available_now}}" type="primary" size="mini">现车可租</van-tag>
<van-tag wx:if="{{item.insurance_included}}" type="default" size="mini">含保险</van-tag>
</block>
<!-- 二手车特性 -->
<block wx:elif="{{item.car_type == 3}}">
<van-tag wx:for="{{item.attr}}" wx:key="index" wx:for-item="opt" type="warning" size="mini">
{{opt}}
</van-tag>
<van-tag wx:if="{{item.mileage}}" type="default" size="mini">{{item.mileage}}万公里</van-tag>
<van-tag wx:if="{{item.car_age}}" type="default" size="mini">{{item.car_age}}年车龄</van-tag>
<van-tag wx:if="{{item.certified}}" type="success" size="mini">官方认证</van-tag>
</block>
</view>
<!-- 额外信息 -->
<view class="car-extra">
<!-- 新车额外信息 -->
<text wx:if="{{item.car_type == 1 && item.dealer_name}}" class="dealer-info">{{item.dealer_name}}</text>
<!-- 租车额外信息 -->
<text wx:elif="{{item.car_type == 2 && item.pickup_location}}" class="pickup-info">取车点:{{item.pickup_location}}</text>
<!-- 二手车额外信息 -->
<view wx:elif="{{item.car_type == 3}}" class="used-car-info">
<text wx:if="{{item.first_license_date}}" class="license-date">首次上牌:{{item.first_license_date}}</text>
<text wx:if="{{item.warranty_remain}}" class="warranty-info">质保剩余:{{item.warranty_remain}}</text>
</view>
</view>
</view>
</view>
</view>

380
pages/car_new/car_new.wxss Normal file
View File

@ -0,0 +1,380 @@
/* 筛选栏样式 */
.sticky-filter {
background: #ffffff;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
overflow: hidden;
position: sticky;
top: 0;
z-index: 100;
}
/* 筛选扩展面板 */
.filter-extend {
padding: 32rpx 24rpx;
background: #ffffff;
max-height: 80vh;
overflow-y: auto;
}
.filter-group {
margin-bottom: 32rpx;
}
.filter-label {
font-size: 32rpx;
font-weight: 600;
color: #2c3e50;
margin-bottom: 16rpx;
position: relative;
padding-left: 12rpx;
}
.filter-label::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 6rpx;
height: 24rpx;
background: linear-gradient(135deg, #667eea, #764ba2);
border-radius: 3rpx;
}
/* 标签筛选样式 */
.filter-tags {
display: flex;
flex-wrap: wrap;
gap: 12rpx;
}
.filter-tag-item {
transition: all 0.3s ease;
}
.filter-tag-item:active {
transform: scale(0.95);
}
.mytag {
transition: all 0.3s ease;
border-radius: 20rpx !important;
font-size: 26rpx !important;
padding: 8rpx 16rpx !important;
border: 2rpx solid #e1e8ed !important;
}
.mytag[type="success"] {
background: linear-gradient(135deg, #11998e, #38ef7d) !important;
border-color: #11998e !important;
color: #ffffff !important;
box-shadow: 0 4rpx 12rpx rgba(17, 153, 142, 0.3);
}
/* 滑块筛选样式 */
.filter-slider-group {
padding: 24rpx;
background: #f8f9fa;
border-radius: 16rpx;
border: 2rpx solid #e9ecef;
}
.slider-label {
font-size: 28rpx;
color: #495057;
margin-bottom: 20rpx;
font-weight: 500;
text-align: center;
}
/* 确认按钮样式 */
.filter-extend .van-button {
background: linear-gradient(135deg, #667eea, #764ba2) !important;
border: none !important;
border-radius: 20rpx !important;
font-weight: 600 !important;
font-size: 32rpx !important;
padding: 20rpx 0 !important;
box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.3);
margin-top: 24rpx;
}
/* 汽车列表样式 */
.car-list {
padding: 24rpx;
padding-top: 16rpx;
}
.car-item {
background: #ffffff;
border-radius: 24rpx;
margin-bottom: 24rpx;
overflow: hidden;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.06);
transition: all 0.3s ease;
position: relative;
}
.car-item::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, transparent 0%, rgba(102, 126, 234, 0.05) 100%);
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
}
.car-item:active {
transform: translateY(-4rpx);
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.12);
}
.car-item:active::before {
opacity: 1;
}
.car-image {
width: 100%;
height: 300rpx;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
position: relative;
}
.car-info {
padding: 24rpx;
position: relative;
}
.car-title {
font-size: 32rpx;
font-weight: 700;
color: #2c3e50;
margin-bottom: 16rpx;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.car-price {
display: flex;
align-items: baseline;
gap: 12rpx;
margin-bottom: 20rpx;
}
.price-new {
font-size: 36rpx;
font-weight: 800;
background: linear-gradient(135deg, #667eea, #764ba2);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: #667eea;
}
.price-old {
font-size: 26rpx;
color: #95a5a6;
text-decoration: line-through;
position: relative;
}
.price-old::after {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 2rpx;
background: #95a5a6;
}
.car-attrs {
display: flex;
flex-wrap: wrap;
gap: 8rpx;
}
.car-attrs .van-tag {
background: linear-gradient(135deg, #ffeaa7, #fab1a0) !important;
color: #2d3436 !important;
border: none !important;
border-radius: 12rpx !important;
font-size: 22rpx !important;
padding: 6rpx 12rpx !important;
font-weight: 500 !important;
box-shadow: 0 2rpx 8rpx rgba(250, 177, 160, 0.3);
}
.car-attrs .van-tag:nth-child(2n) {
background: linear-gradient(135deg, #a8e6cf, #88d8c0) !important;
box-shadow: 0 2rpx 8rpx rgba(136, 216, 192, 0.3);
}
.car-attrs .van-tag:nth-child(3n) {
background: linear-gradient(135deg, #ffd3a5, #fd9853) !important;
box-shadow: 0 2rpx 8rpx rgba(253, 152, 83, 0.3);
}
/* 下拉菜单优化 */
.van-dropdown-menu {
border-radius: 24rpx 24rpx 0 0;
overflow: hidden;
}
.van-dropdown-menu__item {
font-weight: 500;
color: #2c3e50;
}
/* 树形选择器优化 */
.van-tree-select {
border-radius: 0 0 24rpx 24rpx;
overflow: hidden;
}
/* 响应式优化 */
@media (max-width: 750rpx) {
.company-actions {
flex-direction: column;
gap: 8rpx;
}
.company-actions .van-button {
max-width: 100%;
min-height: 64rpx;
}
.filter-tags {
justify-content: center;
}
.car-price {
flex-direction: column;
align-items: flex-start;
gap: 8rpx;
}
}
/* 更小屏幕的额外优化 */
@media (max-width: 600rpx) {
.company-actions .van-button {
font-size: 24rpx !important;
padding: 10rpx 6rpx !important;
}
.company-actions .van-button .van-icon {
font-size: 24rpx !important;
margin-right: 4rpx !important;
}
}
/* 动画效果 */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.car-item {
animation: fadeInUp 0.5s ease-out;
}
.car-item:nth-child(n+2) {
animation-delay: 0.1s;
}
.car-item:nth-child(n+3) {
animation-delay: 0.2s;
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 8rpx;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4rpx;
}
::-webkit-scrollbar-thumb {
background: linear-gradient(135deg, #667eea, #764ba2);
border-radius: 4rpx;
}
::-webkit-scrollbar-thumb:hover {
background: linear-gradient(135deg, #5a6fd8, #6a4190);
}
.car-type-badge {
position: absolute;
top: 20rpx;
right: 20rpx;
z-index: 10;
}
.badge-new {
background: linear-gradient(135deg, #1989fa, #40a9ff);
color: white;
padding: 8rpx 16rpx;
border-radius: 20rpx;
font-size: 22rpx;
font-weight: 600;
}
.badge-rent {
background: linear-gradient(135deg, #07c160, #52c41a);
color: white;
padding: 8rpx 16rpx;
border-radius: 20rpx;
font-size: 22rpx;
font-weight: 600;
}
.badge-used {
background: linear-gradient(135deg, #ff976a, #ffa940);
color: white;
padding: 8rpx 16rpx;
border-radius: 20rpx;
font-size: 22rpx;
font-weight: 600;
}
/* 租车价格 */
.car-type-2 .price-rent {
color: #07c160;
font-size: 36rpx;
font-weight: 700;
margin-right: 16rpx;
}
.car-type-2 .price-monthly {
color: #666;
font-size: 24rpx;
}
/* 二手车价格 */
.car-type-3 .price-used {
color: #ff976a;
font-size: 36rpx;
font-weight: 700;
margin-right: 16rpx;
}
.car-type-3 .price-original {
color: #999;
font-size: 24rpx;
}

View File

@ -12,185 +12,26 @@ Page({
latitude: 31.2304, // 地图坐标
longitude: 121.4737,
phone: '021-88888888'
}
},
// 跳转到新车页面
goToNewCar: function() {
wx.navigateTo({
url: '/pages/car_new/car_new'
});
},
carList: [],
selectedSort: 'default',
selectedBrand: '',
selectedPrice: '',
filterParams: {},
mainActiveIndex: 0,
selectedSeriesId: null,
selectedBrandLabel:"品牌",
brandTree: [],
sortOptions: [
{ text: '默认排序', value: 'default' },
{ text: '价格升序', value: 'priceAsc' },
{ text: '价格降序', value: 'priceDesc' }
],
priceOptions: [
{ text: '全部价格', value: '' },
{ text: '5万以下', value: '<5' },
{ text: '5-10万', value: '5-10' },
{ text: '10万以上', value: '>10' }
],
extendFields: [] // 筛选配置
},
onBrandClick(e) {
this.setData({
mainActiveIndex: e.detail.index
});
},
onSeriesSelect(e) {
const selectedId = e.detail.id;
const selectedText = e.detail.text;
this.setData({
selectedSeriesId: selectedId,
selectedBrandLabel: selectedText // ✅ 更新 dropdown 显示的值
});
this.reloadList();
this.selectComponent('#dropdownItemBrand').toggle(false); // 关闭
// TODO: 发起请求,用 selectedId 作为筛选条件
},
onSortChange(e) {
this.setData({ selectedSort: e.detail });
this.reloadList();
},
onPriceChange(e) {
this.setData({ selectedPrice: e.detail });
this.reloadList();
},
onParamChange(e) {
const value = e.detail.value;
this.setData({ selectedParam: value });
this.reloadList();
},
async reloadList() {
// TODO: 根据筛选值重新加载列表
const data = {
sort:this.data.selectedSort,
brand:this.data.selectedSeriesId,
price:this.data.selectedPrice,
attr:this.data.filterParams,
}
try {
const raw = await request({
url: '/admin/wechat/api/car',
method: 'POST',
data: data
// 跳转到租车页面
goToRental: function() {
wx.navigateTo({
url: '/pages/rental/rental'
});
this.setData({carList:raw.items})
} catch (err) {
console.error('加载品牌失败', err);
}
},
openMap() {
const { latitude, longitude, address, name } = this.data.company
wx.openLocation({
latitude,
longitude,
scale: 18,
name,
address
})
},
onLoad(){
this.loadBrandData();
},
async loadBrandData() {
try {
const raw = await request({
url: '/admin/wechat/api/select'
},
// 跳转到二手车页面
goToUsedCar: function() {
wx.navigateTo({
url: '/pages/usedcar/usedcar'
});
const brandTree = raw.brands.map(brand => ({
text: brand.label,
children: (brand.children || []).map(series => ({
id: series.value,
text: series.label
}))
}));
const fields = raw.extend.map(f => {
// 为 range 类型添加 start/end 临时字段
if (f.type === 'range') {
f._rangeStart = '';
f._rangeEnd = '';
} else if (f.type === 'checkbox') {
f.value = []; // 默认空数组
}
return f;
});
this.setData({ extendFields:fields });
this.setData({ brandTree });
this.reloadList();
} catch (err) {
console.error('加载品牌失败', err);
}
},
onTagToggle(e) {
const name = e.currentTarget.dataset.name;
const value = String(e.currentTarget.dataset.value);
const fields = this.data.extendFields.map(field => {
if (field.name === name) {
let list = (field.value || []).map(String);
const index = list.indexOf(value);
if (index > -1) {
list.splice(index, 1);
} else {
list.push(value);
}
field.value = list;
// ✅ 同步 checked 状态
field.options.forEach(opt => {
opt._checked = list.includes(String(opt.value));
});
}
return field;
});
this.setData({ extendFields: fields });
},
onSliderChange(e) {
const name = e.currentTarget.dataset.name;
const [start, end] = e.detail;
const fields = this.data.extendFields.map(field => {
if (field.name === name) {
field._rangeStart = start;
field._rangeEnd = end;
}
return field;
});
this.setData({ extendFields: fields });
},
onExtendConfirm() {
const filterParams = {};
this.data.extendFields.forEach(field => {
if (field.type === 'checkbox') {
if (field.value?.length > 0) {
filterParams[field.name] = field.value;
}
} else if (field.type === 'range') {
if (field._rangeStart || field._rangeEnd) {
filterParams[field.name] = {
start: field._rangeStart,
end: field._rangeEnd
};
}
}
});
this.selectComponent('#dropdownItemParam').toggle(false); // 关闭
this.setData({filterParams:filterParams});
this.reloadList();
}
},
})

View File

@ -1,3 +1,4 @@
<!-- 顶部轮播图 -->
<swiper autoplay="3000" circular indicator-dots class="banner">
<block wx:for="{{bannerList}}" wx:key="index">
@ -20,98 +21,53 @@
</view>
</view>
<!-- 车辆列表 -->
<!-- 筛选栏 -->
<view class="sticky-filter">
<van-dropdown-menu>
<van-dropdown-item
value="{{selectedSort}}"
options="{{sortOptions}}"
bind:change="onSortChange"
/>
<van-dropdown-item id="dropdownItemBrand" title="{{selectedBrandLabel}}" use-slot>
<van-tree-select
height="400"
items="{{brandTree}}"
main-active-index="{{mainActiveIndex}}"
active-id="{{selectedSeriesId}}"
bind:click-nav="onBrandClick"
bind:click-item="onSeriesSelect"
/>
</van-dropdown-item>
<van-dropdown-item
value="{{selectedPrice}}"
options="{{priceOptions}}"
bind:change="onPriceChange"
/>
<van-dropdown-item title="参数"
use-slot
id="dropdownItemParam"
>
<view class="filter-extend">
<view wx:for="{{extendFields}}" wx:key="id" class="filter-group">
<view class="filter-label">{{item.label}}</view>
<!-- 多选项字段 -->
<view wx:if="{{item.type === 'checkbox'}}" class="filter-tags">
<view
wx:for="{{item.options}}"
wx:for-item="opt"
wx:key="index"
class="filter-tag-item"
data-name="{{item.name}}"
data-value="{{opt.value}}"
bind:tap="onTagToggle"
>
<van-tag
class="mytag"
plain="{{!opt._checked}}"
>
{{opt.key}}
</van-tag>
</view>
</view>
<view wx:if="{{item.type === 'range'}}" class="filter-slider-group">
<view class="slider-label">
{{item.label}}{{item._rangeStart || item.options.start}}{{item.options.unit}} - {{item._rangeEnd || item.options.end}}{{item.options.unit}}
</view>
<van-slider
range
value="{{[item._rangeStart ? item._rangeStart : item.options.start, item._rangeEnd ? item._rangeEnd : item.options.end]}}"
min="{{item.options.start}}"
max="{{item.options.end}}"
data-name="{{item.name}}"
bind:change="onSliderChange"
/>
</view>
<!-- 业务模块 -->
<view class="business-modules">
<view class="module-title">车辆服务</view>
<view class="module-grid">
<view class="module-item" bindtap="goToNewCar">
<view class="module-icon">
<van-icon name="new-o" size="24px" color="#ff6b35" />
</view>
<van-button type="primary" block size="small" bind:tap="onExtendConfirm">确认</van-button>
<view class="module-text">新车</view>
<view class="module-desc">全新车辆销售</view>
</view>
</van-dropdown-item>
</van-dropdown-menu>
</view>
<!-- 汽车列表 -->
<view class="car-list">
<view wx:for="{{carList}}" wx:key="id" class="car-item">
<image class="car-image" src="{{item.cover_image[0]}}" mode="aspectFill" />
<view class="car-info">
<view class="car-title">{{item.title}}</view>
<view class="car-price">
<text class="price-new">¥{{item.price}}万</text>
<text class="price-old">¥{{item.re_price}}万</text>
<view class="module-item" bindtap="goToRental">
<view class="module-icon">
<van-icon name="coupon-o" size="24px" color="#4CAF50" />
</view>
<view class="car-attrs">
<van-tag wx:for="{{item.attr}}" wx:key="index" wx:for-item="opt">
{{opt}}
</van-tag>
<view class="module-text">租车</view>
<view class="module-desc">短期长期租赁</view>
</view>
<view class="module-item" bindtap="goToUsedCar">
<view class="module-icon">
<van-icon name="shopping-cart-o" size="24px" color="#2196F3" />
</view>
<view class="module-text">二手车</view>
<view class="module-desc">优质二手车源</view>
</view>
</view>
</view>
<!-- 热门推荐 -->
<view class="hot-recommend">
<view class="section-title">
<text>热门推荐</text>
<van-icon name="arrow" size="16px" />
</view>
<view class="recommend-list">
<view class="recommend-item" wx:for="{{hotCarList}}" wx:key="id" bindtap="goToCarDetail" data-id="{{item.id}}">
<image src="{{item.image}}" class="car-image" mode="aspectFill" />
<view class="car-info">
<view class="car-name">{{item.name}}</view>
<view class="car-price">¥{{item.price}}</view>
<view class="car-tags">
<text class="tag">{{item.year}}年</text>
<text class="tag">{{item.mileage}}万公里</text>
</view>
</view>
</view>
</view>
</view>

View File

@ -65,13 +65,14 @@ page {
gap: 12rpx;
width: 100%;
text-align: center;
justify-content: space-around;
}
.company-actions .van-button {
flex: 1;
min-width: 0; /* 允许按钮缩小 */
max-width: calc(50% - 6rpx); /* 确保不超过一半宽度 */
width: auto; /* 确保不超过一半宽度 */
background: rgba(255, 255, 255, 0.15) !important;
border: 2rpx solid rgba(255, 255, 255, 0.3) !important;
color: #ffffff !important;
@ -79,7 +80,7 @@ page {
border-radius: 16rpx !important;
font-weight: 500 !important;
font-size: 26rpx !important;
padding: 12rpx 8rpx !important;
padding: 12rpx 20rpx !important;
height: auto !important;
line-height: 1.2 !important;
white-space: nowrap;
@ -89,7 +90,7 @@ page {
}
.company-actions .van-button:hover {
background: rgba(255, 255, 255, 0.25) !important;
background: rgba(27, 24, 24, 0.25) !important;
}
/* 按钮内容样式调整 */
@ -103,322 +104,129 @@ page {
margin-right: 6rpx !important;
}
/* 筛选栏样式 */
.sticky-filter {
background: #ffffff;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
overflow: hidden;
position: sticky;
top: 0;
z-index: 100;
/* 业务模块样式 */
.business-modules {
padding: 20px;
background: #fff;
margin-bottom: 20px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
/* 筛选扩展面板 */
.filter-extend {
padding: 32rpx 24rpx;
background: #ffffff;
max-height: 80vh;
overflow-y: auto;
.module-title {
font-size: 18px;
font-weight: bold;
color: #333;
margin-bottom: 15px;
}
.filter-group {
margin-bottom: 32rpx;
}
.filter-label {
font-size: 32rpx;
font-weight: 600;
color: #2c3e50;
margin-bottom: 16rpx;
position: relative;
padding-left: 12rpx;
}
.filter-label::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 6rpx;
height: 24rpx;
background: linear-gradient(135deg, #667eea, #764ba2);
border-radius: 3rpx;
}
/* 标签筛选样式 */
.filter-tags {
.module-grid {
display: flex;
flex-wrap: wrap;
gap: 12rpx;
justify-content: space-between;
}
.filter-tag-item {
transition: all 0.3s ease;
}
.filter-tag-item:active {
transform: scale(0.95);
}
.mytag {
transition: all 0.3s ease;
border-radius: 20rpx !important;
font-size: 26rpx !important;
padding: 8rpx 16rpx !important;
border: 2rpx solid #e1e8ed !important;
}
.mytag[type="success"] {
background: linear-gradient(135deg, #11998e, #38ef7d) !important;
border-color: #11998e !important;
color: #ffffff !important;
box-shadow: 0 4rpx 12rpx rgba(17, 153, 142, 0.3);
}
/* 滑块筛选样式 */
.filter-slider-group {
padding: 24rpx;
background: #f8f9fa;
border-radius: 16rpx;
border: 2rpx solid #e9ecef;
}
.slider-label {
font-size: 28rpx;
color: #495057;
margin-bottom: 20rpx;
font-weight: 500;
.module-item {
flex: 1;
text-align: center;
}
/* 确认按钮样式 */
.filter-extend .van-button {
background: linear-gradient(135deg, #667eea, #764ba2) !important;
border: none !important;
border-radius: 20rpx !important;
font-weight: 600 !important;
font-size: 32rpx !important;
padding: 20rpx 0 !important;
box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.3);
margin-top: 24rpx;
}
/* 汽车列表样式 */
.car-list {
padding: 24rpx;
padding-top: 16rpx;
}
.car-item {
background: #ffffff;
border-radius: 24rpx;
margin-bottom: 24rpx;
overflow: hidden;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.06);
padding: 20px 10px;
border-radius: 10px;
background: #f8f9fa;
margin: 0 5px;
transition: all 0.3s ease;
position: relative;
}
.car-item::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, transparent 0%, rgba(102, 126, 234, 0.05) 100%);
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
.module-item:active {
transform: scale(0.95);
background: #e9ecef;
}
.car-item:active {
transform: translateY(-4rpx);
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.12);
.module-icon {
margin-bottom: 10px;
}
.car-item:active::before {
opacity: 1;
.module-text {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 5px;
}
.module-desc {
font-size: 12px;
color: #999;
}
/* 热门推荐样式 */
.hot-recommend {
padding: 20px;
background: #fff;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.section-title {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 18px;
font-weight: bold;
color: #333;
margin-bottom: 15px;
}
.recommend-list {
display: flex;
flex-direction: column;
gap: 15px;
}
.recommend-item {
display: flex;
padding: 15px;
border-radius: 10px;
background: #f8f9fa;
transition: all 0.3s ease;
}
.recommend-item:active {
transform: scale(0.98);
background: #e9ecef;
}
.car-image {
width: 100%;
height: 300rpx;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
position: relative;
width: 80px;
height: 60px;
border-radius: 5px;
margin-right: 15px;
}
.car-info {
padding: 24rpx;
position: relative;
flex: 1;
}
.car-title {
font-size: 32rpx;
font-weight: 700;
color: #2c3e50;
margin-bottom: 16rpx;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
.car-name {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 5px;
}
.car-price {
font-size: 18px;
color: #ff6b35;
font-weight: bold;
margin-bottom: 5px;
}
.car-tags {
display: flex;
align-items: baseline;
gap: 12rpx;
margin-bottom: 20rpx;
gap: 5px;
}
.price-new {
font-size: 36rpx;
font-weight: 800;
background: linear-gradient(135deg, #667eea, #764ba2);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: #667eea;
}
.price-old {
font-size: 26rpx;
color: #95a5a6;
text-decoration: line-through;
position: relative;
}
.price-old::after {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 2rpx;
background: #95a5a6;
}
.car-attrs {
display: flex;
flex-wrap: wrap;
gap: 8rpx;
}
.car-attrs .van-tag {
background: linear-gradient(135deg, #ffeaa7, #fab1a0) !important;
color: #2d3436 !important;
border: none !important;
border-radius: 12rpx !important;
font-size: 22rpx !important;
padding: 6rpx 12rpx !important;
font-weight: 500 !important;
box-shadow: 0 2rpx 8rpx rgba(250, 177, 160, 0.3);
}
.car-attrs .van-tag:nth-child(2n) {
background: linear-gradient(135deg, #a8e6cf, #88d8c0) !important;
box-shadow: 0 2rpx 8rpx rgba(136, 216, 192, 0.3);
}
.car-attrs .van-tag:nth-child(3n) {
background: linear-gradient(135deg, #ffd3a5, #fd9853) !important;
box-shadow: 0 2rpx 8rpx rgba(253, 152, 83, 0.3);
}
/* 下拉菜单优化 */
.van-dropdown-menu {
border-radius: 24rpx 24rpx 0 0;
overflow: hidden;
}
.van-dropdown-menu__item {
font-weight: 500;
color: #2c3e50;
}
/* 树形选择器优化 */
.van-tree-select {
border-radius: 0 0 24rpx 24rpx;
overflow: hidden;
}
/* 响应式优化 */
@media (max-width: 750rpx) {
.company-actions {
flex-direction: column;
gap: 8rpx;
}
.company-actions .van-button {
max-width: 100%;
min-height: 64rpx;
}
.filter-tags {
justify-content: center;
}
.car-price {
flex-direction: column;
align-items: flex-start;
gap: 8rpx;
}
}
/* 更小屏幕的额外优化 */
@media (max-width: 600rpx) {
.company-actions .van-button {
font-size: 24rpx !important;
padding: 10rpx 6rpx !important;
}
.company-actions .van-button .van-icon {
font-size: 24rpx !important;
margin-right: 4rpx !important;
}
}
/* 动画效果 */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.car-item {
animation: fadeInUp 0.5s ease-out;
}
.car-item:nth-child(n+2) {
animation-delay: 0.1s;
}
.car-item:nth-child(n+3) {
animation-delay: 0.2s;
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 8rpx;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4rpx;
}
::-webkit-scrollbar-thumb {
background: linear-gradient(135deg, #667eea, #764ba2);
border-radius: 4rpx;
}
::-webkit-scrollbar-thumb:hover {
background: linear-gradient(135deg, #5a6fd8, #6a4190);
.tag {
font-size: 12px;
color: #666;
background: #e9ecef;
padding: 2px 6px;
border-radius: 3px;
}

339
pages/info/info.js Normal file
View File

@ -0,0 +1,339 @@
const request = require('../../utils/request');
Page({
data: null,
onLoad(options) {
// 获取车辆ID
if (options.id) {
this.setData({
carId: options.id
});
}
// 加载车辆详情
this.loadCarDetail();
},
onShow() {
// 页面显示时刷新数据
this.refreshData();
},
onShareAppMessage() {
// 分享配置
return {
title: this.data.carDetail.title,
desc: `${this.data.carDetail.desc} - 仅售${this.data.carDetail.price}`,
path: `/pages/car-detail/car-detail?id=${this.data.carId}`,
imageUrl: this.data.carDetail.cover_image[0]
};
},
onShareTimeline() {
// 分享到朋友圈
return {
title: `${this.data.carDetail.title} - 仅售${this.data.carDetail.price}`,
imageUrl: this.data.carDetail.cover_image[0]
};
},
// 初始化数据
initializeData() {
const { carDetail } = this.data;
// 计算优惠金额
const discountAmount = (carDetail.re_price - carDetail.price).toFixed(1);
// 转换属性为数组格式
const attributesList = Object.entries(carDetail.attributes).map(([key, value]) => ({
key,
value
}));
this.setData({
discountAmount,
attributesList
});
},
// 加载车辆详情
async loadCarDetail() {
if (!this.data.carId) return;
this.setData({ loading: true });
try {
// 模拟API调用
const carDetail = await this.fetchCarDetail(this.data.carId);
console.log(carDetail)
if (carDetail) {
// 计算优惠金额
const discountAmount = (carDetail.re_price - carDetail.price).toFixed(1);
// 转换属性为数组格式
const attributesList = Object.entries(carDetail.attr).map(([key, value]) => ({
key,
value
}));
this.setData({
carDetail,
discountAmount,
attributesList
});
}
} catch (error) {
console.error('加载车辆详情失败:', error);
wx.showToast({
title: '加载失败',
icon: 'none'
});
} finally {
this.setData({ loading: false });
}
},
async fetchCarDetail(id) {
try {
const raw = await request({
url: '/admin/wechat/api/carInfo?id=' + id,
method: 'GET'
});
return raw;
} catch (err) {
console.error('加载品牌失败', err);
}
},
// 刷新数据
refreshData() {
// 可以在这里添加数据刷新逻辑
console.log('页面数据刷新');
},
// 返回上一页
goBack() {
// 检查是否有上一页
const pages = getCurrentPages();
if (pages.length > 1) {
wx.navigateBack({
delta: 1
});
} else {
// 如果没有上一页,跳转到首页
wx.redirectTo({
url: '/pages/index/index'
});
}
},
// 分享车辆
shareVehicle() {
const { carDetail } = this.data;
// 显示分享菜单
wx.showActionSheet({
itemList: ['分享给朋友', '分享到朋友圈', '复制链接'],
success: (res) => {
switch(res.tapIndex) {
case 0:
// 分享给朋友 - 由微信原生分享处理
break;
case 1:
// 分享到朋友圈
this.shareToTimeline();
break;
case 2:
// 复制链接
this.copyLink();
break;
}
}
});
},
// 分享到朋友圈
shareToTimeline() {
// 由于小程序限制,这里只能提示用户
wx.showModal({
title: '分享提示',
content: '请点击右上角菜单选择"分享到朋友圈"',
showCancel: false
});
},
// 复制链接
copyLink() {
const shareUrl = `https://yourapp.com/car-detail?id=${this.data.carId}`;
wx.setClipboardData({
data: shareUrl,
success: () => {
wx.showToast({
title: '链接已复制',
icon: 'success'
});
},
fail: () => {
wx.showToast({
title: '复制失败',
icon: 'none'
});
}
});
},
// 拨打电话
makePhoneCall(e) {
const phone = e.currentTarget.dataset.phone || this.data.contactPhone;
wx.makePhoneCall({
phoneNumber: phone,
success: () => {
console.log('拨打电话成功');
},
fail: (err) => {
console.error('拨打电话失败:', err);
wx.showToast({
title: '拨打失败',
icon: 'none'
});
}
});
},
// 打开微信咨询
openWechat() {
// 方案1: 复制微信号
const wechatId = 'car_consultant_001';
wx.showModal({
title: '微信咨询',
content: `客服微信号:${wechatId}\n点击确定复制微信号`,
success: (res) => {
if (res.confirm) {
wx.setClipboardData({
data: wechatId,
success: () => {
wx.showToast({
title: '微信号已复制',
icon: 'success'
});
}
});
}
}
});
},
// 图片预览
previewImage(e) {
const current = e.currentTarget.dataset.src;
const urls = this.data.carDetail.cover_image;
wx.previewImage({
current,
urls
});
},
// 收藏车辆
toggleFavorite() {
// 这里应该调用收藏API
wx.showToast({
title: '收藏成功',
icon: 'success'
});
},
// 查看更多图片
viewMoreImages() {
wx.navigateTo({
url: `/pages/car-images/car-images?id=${this.data.carId}`
});
},
// 查看检测报告
viewInspectionReport() {
const { carDetail } = this.data;
if (carDetail.attributes['检测状态'] === '已检测') {
wx.navigateTo({
url: `/pages/inspection-report/inspection-report?id=${this.data.carId}`
});
} else {
wx.showToast({
title: '暂无检测报告',
icon: 'none'
});
}
},
// 计算器
openCalculator() {
wx.navigateTo({
url: `/pages/loan-calculator/loan-calculator?price=${this.data.carDetail.price}`
});
},
// 预约看车
bookViewing() {
wx.navigateTo({
url: `/pages/book-viewing/book-viewing?id=${this.data.carId}`
});
},
// 举报车辆
reportVehicle() {
wx.showActionSheet({
itemList: ['价格有误', '车况描述不符', '联系方式错误', '其他问题'],
success: (res) => {
const reasons = ['价格有误', '车况描述不符', '联系方式错误', '其他问题'];
const reason = reasons[res.tapIndex];
wx.showModal({
title: '举报确认',
content: `您要举报的原因:${reason}`,
success: (modalRes) => {
if (modalRes.confirm) {
// 提交举报
this.submitReport(reason);
}
}
});
}
});
},
// 提交举报
submitReport(reason) {
// 这里应该调用举报API
wx.showToast({
title: '举报成功',
icon: 'success'
});
},
// 页面下拉刷新
onPullDownRefresh() {
this.loadCarDetail().then(() => {
wx.stopPullDownRefresh();
});
},
// 页面触底加载
onReachBottom() {
// 如果有相关推荐车辆,可以在这里加载
console.log('触底加载更多');
},
// 用户点击右上角分享
onShareAppMessage() {
return {
title: this.data.carDetail.title,
desc: `${this.data.carDetail.desc} - 仅售${this.data.carDetail.price}`,
path: `/pages/car-detail/car-detail?id=${this.data.carId}`,
imageUrl: this.data.carDetail.cover_image[0]
};
}
});

10
pages/info/info.json Normal file
View File

@ -0,0 +1,10 @@
{
"navigationBarTitleText": "车辆详情",
"usingComponents": {
"van-button": "@vant/weapp/button/index",
"van-icon": "@vant/weapp/icon/index",
"van-loading": "@vant/weapp/loading/index",
"van-overlay": "@vant/weapp/overlay/index"
},
"disableScroll": false
}

151
pages/info/info.wxml Normal file
View File

@ -0,0 +1,151 @@
<!-- car-detail.wxml -->
<view class="my_container">
<!-- 加载状态 -->
<van-overlay show="{{loading}}" z-index="100">
<view class="loading-container">
<van-loading size="24px" color="#667eea">加载中...</van-loading>
</view>
</van-overlay>
<!-- 头部图片区域 -->
<view class="hero-section">
<image
src="{{carDetail.cover_image[0]}}"
class="car-image"
mode="aspectFill"
bindtap="previewImage"
data-src="{{carDetail.cover_image[0]}}"
/>
<view class="car-desc">{{carDetail.desc}}</view>
<!-- 图片指示器 -->
<view class="image-indicator" wx:if="{{carDetail.cover_image.length > 1}}">
<text>1/{{carDetail.cover_image.length}}</text>
</view>
<!-- 更多图片按钮 -->
<view class="more-images-btn" bindtap="viewMoreImages" wx:if="{{carDetail.cover_image.length > 1}}">
<van-icon name="photo" size="16px" />
<text>查看更多</text>
</view>
</view>
<view class="car-info-card car-type-{{carDetail.car_type}}">
<view class="car-header">
<view class="car-title">{{carDetail.title}}</view>
<view class="car-type-tag">
<text wx:if="{{carDetail.car_type == 1}}" class="tag-new">新车</text>
<text wx:elif="{{carDetail.car_type == 2}}" class="tag-rent">租车</text>
<text wx:elif="{{carDetail.car_type == 3}}" class="tag-used">二手车</text>
</view>
<!-- <view class="favorite-btn" bindtap="toggleFavorite">
<van-icon name="{{carDetail.is_favorite ? 'star' : 'star-o'}}" size="20px" color="{{carDetail.is_favorite ? '#ff6b6b' : '#999'}}" />
</view> -->
</view>
<view class="car-desc">{{carDetail.desc}}</view>
<!-- 新车价格展示 -->
<view wx:if="{{carDetail.car_type == 1}}" class="price-section price-new">
<view class="price-main">
<text class="current-price">¥{{carDetail.price}}万起</text>
</view>
<text wx:if="{{carDetail.re_price}}" class="original-price">指导价 ¥{{carDetail.re_price}}万</text>
</view>
<!-- 租车价格展示 -->
<view wx:elif="{{carDetail.car_type == 2}}" class="price-section price-rent">
<view class="price-main">
<text class="current-price">¥{{carDetail.price}}/天</text>
</view>
<text wx:if="{{carDetail.re_price}}" class="monthly-price">月租 ¥{{carDetail.re_price}}</text>
</view>
<!-- 二手车价格展示 -->
<view wx:elif="{{carDetail.car_type == 3}}" class="price-section price-used">
<view class="price-main">
<text class="current-price">¥{{carDetail.price}}万</text>
</view>
<text wx:if="{{carDetail.re_price}}" class="original-price">新车价 ¥{{carDetail.re_price}}万</text>
</view>
<view class="brand-info">
<image src="{{carDetail.brand.logo}}" class="brand-logo" mode="aspectFill" />
<view class="brand-text">
<view class="brand-name">{{carDetail.brand.name}}</view>
<view class="series-name">{{carDetail.series.name}}</view>
</view>
<!-- 不同车型的操作按钮 -->
<view class="action-buttons">
<!-- 新车操作按钮 -->
<view wx:if="{{carDetail.car_type == 1}}" class="calculator-btn" bindtap="openCalculator">
<van-icon name="calculator" size="16px" />
<text>贷款计算</text>
</view>
<!-- 租车操作按钮 -->
<view wx:elif="{{carDetail.car_type == 2}}" class="rent-btn" bindtap="openRentCalculator">
<van-icon name="calendar" size="16px" />
<text>租期计算</text>
</view>
</view>
</view>
</view>
<!-- 车辆属性 -->
<view class="attributes-card">
<view class="card-title">车辆详情</view>
<view class="attributes-grid">
<view
wx:for="{{attributesList}}"
wx:key="key"
class="attribute-item {{item.key === '检测状态' ? 'status-checked' : ''}}"
bindtap="{{item.key === '检测状态' ? 'viewInspectionReport' : ''}}"
>
<view class="attribute-label">{{item.key}}</view>
<view class="attribute-value">
{{item.value}}
<van-icon wx:if="{{item.key === '检测状态' && item.value === '已检测'}}" name="arrow" size="12px" />
</view>
</view>
</view>
</view>
<!-- 联系我们 -->
<view class="contact-section">
<view class="contact-buttons">
<!-- 电话咨询 -->
<button
class="contact-btn primary"
open-type="makePhoneCall"
data-phone="{{contactPhone}}"
bindtap="makePhoneCall"
>
<van-icon name="phone" size="20px" class="btn-icon" />
<text>电话咨询</text>
</button>
<!-- 微信咨询 -->
<button
class="contact-btn secondary"
bindtap="openWechat"
>
<van-icon name="chat" size="20px" class="btn-icon" />
<text>微信咨询</text>
</button>
</view>
</view>
<!-- 底部安全区域 -->
<view class="safe-area-bottom"></view>
</view>
<!-- Toast 组件 -->
<van-toast id="van-toast" />

828
pages/info/info.wxss Normal file
View File

@ -0,0 +1,828 @@
/* car-detail.wxss */
/* 全局容器 */
.my_container {
min-height: 100vh;
background: linear-gradient(135deg, #e8e9ec80 0%, #bfbcc248 100%);
position: relative;
overflow-x: hidden;
}
/* 加载状态 */
.loading-container {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(255, 255, 255, 0.95);
border-radius: 16px;
padding: 32px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
/* 头部图片区域 */
.hero-section {
position: relative;
height: 260px;
margin: 0 16px 16px 16px;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
}
.car-image {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.car-image:active {
transform: scale(0.98);
}
.back-button {
position: absolute;
top: 20px;
left: 20px;
width: 44px;
height: 44px;
background: rgba(255, 255, 255, 0.9);
border-radius: 22px;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(10px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
.back-button:active {
transform: scale(0.95);
background: rgba(255, 255, 255, 0.8);
}
.van-button {
width: auto !important;
}
.share-button {
position: absolute;
top: 20px;
right: 20px;
width: 44px;
height: 44px;
background: rgba(255, 255, 255, 0.9);
border-radius: 22px;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(10px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
.share-button:active {
transform: scale(0.95);
background: rgba(255, 255, 255, 0.8);
}
.image-indicator {
position: absolute;
top: 20px;
right: 80px;
background: rgba(0, 0, 0, 0.6);
color: white;
padding: 6px 12px;
border-radius: 16px;
font-size: 12px;
font-weight: 500;
backdrop-filter: blur(5px);
}
.more-images-btn {
position: absolute;
bottom: 20px;
right: 20px;
background: rgba(255, 255, 255, 0.9);
border-radius: 20px;
padding: 8px 16px;
display: flex;
align-items: center;
gap: 6px;
backdrop-filter: blur(10px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
.more-images-btn text {
font-size: 14px;
color: #333;
font-weight: 500;
}
.more-images-btn:active {
transform: scale(0.95);
background: rgba(255, 255, 255, 0.8);
}
/* 车辆信息卡片 */
.car-info-card {
background: white;
margin: 0 16px 16px 16px;
border-radius: 20px;
padding: 24px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
position: relative;
overflow: hidden;
}
.car-info-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #667eea, #764ba2);
}
.car-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 12px;
}
.car-title {
font-size: 24px;
font-weight: 700;
color: #1a1a1a;
line-height: 1.3;
flex: 1;
margin-right: 16px;
}
.favorite-btn {
width: 40px;
height: 40px;
background: #f8f9fa;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.favorite-btn:active {
transform: scale(0.9);
background: #667eea;
color: white;
}
.car-desc {
font-size: 16px;
color: #666;
line-height: 1.5;
margin-bottom: 20px;
}
.price-section {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 24px;
}
.current-price {
font-size: 28px;
font-weight: 700;
color: #e74c3c;
background: linear-gradient(45deg, #e74c3c, #c0392b);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.original-price {
font-size: 16px;
color: #999;
text-decoration: line-through;
}
.discount-badge {
background: linear-gradient(45deg, #2ecc71, #27ae60);
color: white;
padding: 4px 12px;
border-radius: 16px;
font-size: 12px;
font-weight: 600;
box-shadow: 0 2px 8px rgba(46, 204, 113, 0.3);
}
.brand-info {
display: flex;
align-items: center;
gap: 12px;
background: #f8f9fa;
padding: 16px;
border-radius: 16px;
border: 1px solid #e9ecef;
}
.brand-logo {
width: 48px;
height: 48px;
border-radius: 12px;
background: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.brand-text {
flex: 1;
}
.brand-name {
font-size: 16px;
font-weight: 600;
color: #1a1a1a;
margin-bottom: 4px;
}
.series-name {
font-size: 14px;
color: #666;
}
.calculator-btn {
display: flex;
align-items: center;
gap: 6px;
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
padding: 8px 16px;
border-radius: 20px;
font-size: 14px;
font-weight: 500;
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3);
transition: all 0.3s ease;
}
.calculator-btn:active {
transform: scale(0.95);
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.4);
}
/* 车辆属性卡片 */
.attributes-card {
background: white;
margin: 0 16px 16px 16px;
border-radius: 20px;
padding: 24px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
}
.card-title {
font-size: 20px;
font-weight: 700;
color: #1a1a1a;
margin-bottom: 20px;
padding-bottom: 12px;
border-bottom: 2px solid #f1f3f4;
position: relative;
}
.card-title::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 40px;
height: 2px;
background: linear-gradient(90deg, #667eea, #764ba2);
}
.attributes-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
.attribute-item {
background: #f8f9fa;
padding: 16px;
border-radius: 12px;
border-left: 4px solid #e9ecef;
transition: all 0.3s ease;
}
.attribute-item:active {
transform: scale(0.98);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}
.status-checked {
background: linear-gradient(135deg, #e8f5e8, #f0f8f0);
border-left-color: #2ecc71;
}
.attribute-label {
font-size: 12px;
color: #666;
margin-bottom: 6px;
font-weight: 500;
}
.attribute-value {
font-size: 16px;
color: #1a1a1a;
font-weight: 600;
display: flex;
align-items: center;
justify-content: space-between;
}
/* 快捷操作 */
.quick-actions {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
margin: 0 16px 16px 16px;
}
.action-item {
background: white;
padding: 20px 12px;
border-radius: 16px;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
transition: all 0.3s ease;
}
.action-item:active {
transform: scale(0.95);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.action-item:nth-child(1) {
background: linear-gradient(135deg, #fff5f5, #ffeaea);
color: #e74c3c;
}
.action-item:nth-child(2) {
background: linear-gradient(135deg, #f0f8ff, #e6f3ff);
color: #3498db;
}
.action-item:nth-child(3) {
background: linear-gradient(135deg, #fff8e1, #ffecb3);
color: #f39c12;
}
.action-item:nth-child(4) {
background: linear-gradient(135deg, #f3e5f5, #e8d5ee);
color: #9b59b6;
}
.action-item text {
font-size: 12px;
font-weight: 600;
text-align: center;
}
/* 联系我们 */
.contact-section {
background: white;
margin: 0 16px 16px 16px;
border-radius: 20px;
padding: 24px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
}
.contact-info {
margin-bottom: 24px;
}
.contact-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 0;
border-bottom: 1px solid #f1f3f4;
}
.contact-item:last-child {
border-bottom: none;
}
.contact-item text {
font-size: 16px;
color: #333;
font-weight: 500;
}
.contact-buttons {
display: flex;
gap: 12px;
}
.contact-btn {
flex: 1;
border-radius: 24px !important;
font-weight: 600 !important;
font-size: 16px !important;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
.contact-btn.primary {
background: linear-gradient(45deg, #667eea, #764ba2) !important;
border: none !important;
}
.contact-btn.secondary {
background: linear-gradient(45deg, #2ecc71, #27ae60) !important;
border: none !important;
}
.contact-btn:active {
transform: scale(0.98);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
/* 底部安全区域 */
.safe-area-bottom {
height: 34px;
background: transparent;
}
/* 响应式优化 */
@media (max-width: 375px) {
.attributes-grid {
grid-template-columns: 1fr;
}
.quick-actions {
grid-template-columns: repeat(2, 1fr);
}
.car-title {
font-size: 22px;
}
.current-price {
font-size: 24px;
}
}
/* 动画效果 */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.car-info-card,
.attributes-card,
.contact-section {
animation: fadeInUp 0.6s ease-out;
}
.car-info-card {
animation-delay: 0.1s;
}
.attributes-card {
animation-delay: 0.2s;
}
.quick-actions {
animation: fadeInUp 0.6s ease-out;
animation-delay: 0.3s;
}
.contact-section {
animation-delay: 0.4s;
}
/* 毛玻璃效果增强 */
.back-button,
.share-button,
.more-images-btn {
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
}
/* 悬浮效果 */
.car-info-card,
.attributes-card,
.contact-section {
transform: translateY(0);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.car-info-card:hover,
.attributes-card:hover,
.contact-section:hover {
transform: translateY(-2px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.12);
}
/* 渐变文字效果 */
.brand-name {
background: linear-gradient(45deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
/* 自定义滚动条 */
::-webkit-scrollbar {
width: 4px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: linear-gradient(45deg, #667eea, #764ba2);
border-radius: 2px;
}
::-webkit-scrollbar-thumb:hover {
background: linear-gradient(45deg, #764ba2, #667eea);
}
/* 车辆信息卡片 */
.car-info-card {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin: 20rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
position: relative;
overflow: hidden;
}
/* 不同车型的顶部装饰条 */
.car-type-1::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 8rpx;
background: linear-gradient(90deg, #1989fa, #40a9ff);
}
.car-type-2::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 8rpx;
background: linear-gradient(90deg, #07c160, #52c41a);
}
.car-type-3::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 8rpx;
background: linear-gradient(90deg, #ff976a, #ffa940);
}
/* 车辆头部信息 */
.car-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 20rpx;
}
.car-title {
font-size: 36rpx;
font-weight: 700;
color: #333;
flex: 1;
margin-right: 20rpx;
line-height: 1.4;
}
.car-type-tag {
margin-right: 20rpx;
}
.tag-new {
background: linear-gradient(135deg, #1989fa, #40a9ff);
color: white;
padding: 8rpx 16rpx;
border-radius: 16rpx;
font-size: 22rpx;
font-weight: 600;
}
.tag-rent {
background: linear-gradient(135deg, #07c160, #52c41a);
color: white;
padding: 8rpx 16rpx;
border-radius: 16rpx;
font-size: 22rpx;
font-weight: 600;
}
.tag-used {
background: linear-gradient(135deg, #ff976a, #ffa940);
color: white;
padding: 8rpx 16rpx;
border-radius: 16rpx;
font-size: 22rpx;
font-weight: 600;
}
.favorite-btn {
padding: 8rpx;
border-radius: 50%;
background: rgba(0, 0, 0, 0.05);
}
.car-desc {
font-size: 28rpx;
color: #666;
line-height: 1.6;
margin-bottom: 30rpx;
}
/* 价格区域 */
.price-section {
margin-bottom: 30rpx;
padding: 30rpx;
border-radius: 16rpx;
position: relative;
}
/* 新车价格样式 */
.price-new {
background: linear-gradient(135deg, rgba(25, 137, 250, 0.1), rgba(64, 169, 255, 0.05));
border: 2rpx solid rgba(25, 137, 250, 0.2);
}
.price-new .current-price {
font-size: 48rpx;
font-weight: 700;
color: #1989fa;
margin-right: 20rpx;
}
.price-new .original-price {
font-size: 28rpx;
color: #999;
text-decoration: line-through;
}
.price-new .discount-badge {
background: #ff4d4f;
color: white;
padding: 6rpx 12rpx;
border-radius: 12rpx;
font-size: 22rpx;
font-weight: 600;
}
/* 租车价格样式 */
.price-rent {
background: linear-gradient(135deg, rgba(7, 193, 96, 0.1), rgba(82, 196, 26, 0.05));
border: 2rpx solid rgba(7, 193, 96, 0.2);
}
.price-rent .current-price {
font-size: 48rpx;
font-weight: 700;
color: #07c160;
margin-right: 20rpx;
}
.price-rent .monthly-price {
font-size: 28rpx;
color: #666;
}
.rent-options {
display: flex;
gap: 20rpx;
margin-top: 20rpx;
}
.rent-option {
background: rgba(255, 255, 255, 0.8);
padding: 12rpx 20rpx;
border-radius: 12rpx;
text-align: center;
flex: 1;
}
.option-label {
font-size: 24rpx;
color: #666;
display: block;
margin-bottom: 4rpx;
}
.option-price {
font-size: 28rpx;
font-weight: 600;
color: #07c160;
}
/* 二手车价格样式 */
.price-used {
background: linear-gradient(135deg, rgba(255, 151, 106, 0.1), rgba(255, 169, 64, 0.05));
border: 2rpx solid rgba(255, 151, 106, 0.2);
}
.price-used .current-price {
font-size: 48rpx;
font-weight: 700;
color: #ff976a;
margin-right: 20rpx;
}
.price-used .original-price {
font-size: 28rpx;
color: #999;
}
.value-info {
display: flex;
align-items: center;
gap: 16rpx;
margin-top: 20rpx;
}
.value-badge {
background: #52c41a;
color: white;
padding: 6rpx 12rpx;
border-radius: 12rpx;
font-size: 22rpx;
font-weight: 600;
}
.depreciation-rate {
font-size: 24rpx;
color: #666;
background: rgba(255, 255, 255, 0.8);
padding: 6rpx 12rpx;
border-radius: 12rpx;
}
.used-car-details {
display: flex;
gap: 20rpx;
margin-top: 20rpx;
}
.detail-item {
flex: 1;
text-align: center;
background: rgba(255, 255, 255, 0.8);
padding: 16rpx;
border-radius: 12rpx;
}
.detail-label {
font-size: 24rpx;
color: #666;
display: block;
margin-bottom: 4rpx;
}
.detail-value {
font-size: 28rpx;
font-weight: 600;
color: #333;
}
/* 价格提示 */
.price-tips {
text-align: center;
}
.tip-text {
font-size: 24rpx;
color: #999;
font-style: italic;
}

View File

@ -1,18 +0,0 @@
// logs.js
const util = require('../../utils/util.js')
Page({
data: {
logs: []
},
onLoad() {
this.setData({
logs: (wx.getStorageSync('logs') || []).map(log => {
return {
date: util.formatTime(new Date(log)),
timeStamp: log
}
})
})
}
})

View File

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

View File

@ -1,6 +0,0 @@
<!--logs.wxml-->
<scroll-view class="scrollarea" scroll-y type="list">
<block wx:for="{{logs}}" wx:key="timeStamp" wx:for-item="log">
<view class="log-item">{{index + 1}}. {{log.date}}</view>
</block>
</scroll-view>

View File

@ -1,16 +0,0 @@
page {
height: 100vh;
display: flex;
flex-direction: column;
}
.scrollarea {
flex: 1;
overflow-y: hidden;
}
.log-item {
margin-top: 20rpx;
text-align: center;
}
.log-item:last-child {
padding-bottom: env(safe-area-inset-bottom);
}

View File

@ -18,7 +18,7 @@
"disablePlugins": [],
"outputPath": ""
},
"compileWorklet": false,
"compileWorklet": true,
"uglifyFileName": false,
"uploadWithSourceMap": true,
"packNpmManually": false,

View File

@ -3,7 +3,7 @@
"projectname": "car_front",
"setting": {
"compileHotReLoad": true,
"urlCheck": true,
"urlCheck": false,
"coverView": true,
"lazyloadPlaceholderEnable": false,
"skylineRenderEnable": false,

View File

@ -3,6 +3,7 @@ const BASE_URL = 'https://car.cherrybless.com'; // 👈 换成你的后端地址
function request({ url, method = 'GET', data = {}, header = {} }) {
const token = '';
return new Promise((resolve, reject) => {
wx.request({
url: BASE_URL + url,

View File

@ -14,6 +14,388 @@ const formatNumber = n => {
return n[1] ? n : `0${n}`
}
/**
* 格式化价格显示
* @param {number} price - 价格
* @returns {string} 格式化后的价格
*/
export function formatPrice(price) {
if (!price) return '0';
return price.toFixed(1);
}
/**
* 计算优惠金额
* @param {number} originalPrice - 原价
* @param {number} currentPrice - 现价
* @returns {number} 优惠金额
*/
export function calculateDiscount(originalPrice, currentPrice) {
if (!originalPrice || !currentPrice) return 0;
return Math.max(0, originalPrice - currentPrice);
}
/**
* 车龄计算
* @param {string} year - 年份
* @returns {string} 车龄描述
*/
export function calculateCarAge(year) {
if (!year) return '未知';
const currentYear = new Date().getFullYear();
const age = currentYear - parseInt(year);
if (age <= 0) return '新车';
if (age === 1) return '1年';
return `${age}`;
}
/**
* 里程数格式化
* @param {number} mileage - 里程数公里
* @returns {string} 格式化后的里程数
*/
export function formatMileage(mileage) {
if (!mileage) return '0公里';
if (mileage < 1000) {
return `${mileage}公里`;
} else if (mileage < 10000) {
return `${(mileage / 1000).toFixed(1)}千公里`;
} else {
return `${(mileage / 10000).toFixed(1)}万公里`;
}
}
/**
* 验证手机号
* @param {string} phone - 手机号
* @returns {boolean} 是否有效
*/
export function validatePhone(phone) {
const phoneReg = /^1[3-9]\d{9}$/;
return phoneReg.test(phone);
}
/**
* 图片加载错误处理
* @param {string} src - 图片源
* @param {string} fallback - 备用图片
* @returns {string} 处理后的图片源
*/
export function handleImageError(src, fallback = '/images/car-placeholder.png') {
return src || fallback;
}
/**
* 分享配置生成
* @param {Object} carDetail - 车辆详情
* @param {string} carId - 车辆ID
* @returns {Object} 分享配置
*/
export function generateShareConfig(carDetail, carId) {
return {
title: carDetail.title || '精品二手车',
desc: `${carDetail.desc || '车况优良'} - 仅售${formatPrice(carDetail.price)}`,
path: `/pages/car-detail/car-detail?id=${carId}`,
imageUrl: carDetail.cover_image?.[0] || '/images/share-default.png'
};
}
/**
* 本地存储操作
*/
export const storage = {
/**
* 保存浏览记录
* @param {Object} carInfo - 车辆信息
*/
saveBrowseHistory(carInfo) {
try {
const history = this.getBrowseHistory();
const existingIndex = history.findIndex(item => item.id === carInfo.id);
if (existingIndex !== -1) {
history.splice(existingIndex, 1);
}
history.unshift({
id: carInfo.id,
title: carInfo.title,
price: carInfo.price,
cover_image: carInfo.cover_image?.[0],
browse_time: Date.now()
});
// 只保留最近50条记录
if (history.length > 50) {
history.splice(50);
}
wx.setStorageSync('browse_history', history);
} catch (error) {
console.error('保存浏览记录失败:', error);
}
},
/**
* 获取浏览记录
* @returns {Array} 浏览记录列表
*/
getBrowseHistory() {
try {
return wx.getStorageSync('browse_history') || [];
} catch (error) {
console.error('获取浏览记录失败:', error);
return [];
}
},
/**
* 保存收藏
* @param {Object} carInfo - 车辆信息
*/
saveFavorite(carInfo) {
try {
const favorites = this.getFavorites();
const existingIndex = favorites.findIndex(item => item.id === carInfo.id);
if (existingIndex === -1) {
favorites.unshift({
id: carInfo.id,
title: carInfo.title,
price: carInfo.price,
cover_image: carInfo.cover_image?.[0],
favorite_time: Date.now()
});
wx.setStorageSync('favorites', favorites);
return true;
}
return false;
} catch (error) {
console.error('保存收藏失败:', error);
return false;
}
},
/**
* 取消收藏
* @param {string} carId - 车辆ID
*/
removeFavorite(carId) {
try {
const favorites = this.getFavorites();
const filteredFavorites = favorites.filter(item => item.id !== carId);
wx.setStorageSync('favorites', filteredFavorites);
return true;
} catch (error) {
console.error('取消收藏失败:', error);
return false;
}
},
/**
* 获取收藏列表
* @returns {Array} 收藏列表
*/
getFavorites() {
try {
return wx.getStorageSync('favorites') || [];
} catch (error) {
console.error('获取收藏列表失败:', error);
return [];
}
},
/**
* 检查是否已收藏
* @param {string} carId - 车辆ID
* @returns {boolean} 是否已收藏
*/
isFavorite(carId) {
const favorites = this.getFavorites();
return favorites.some(item => item.id === carId);
}
};
/**
* API 请求封装
*/
export const api = {
/**
* 获取车辆详情
* @param {string} carId - 车辆ID
* @returns {Promise} API响应
*/
getCarDetail(carId) {
return new Promise((resolve, reject) => {
wx.request({
url: `${getApp().globalData.apiUrl}/cars/${carId}`,
method: 'GET',
header: {
'Authorization': getApp().globalData.token
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(new Error(res.data.message || '获取车辆详情失败'));
}
},
fail: (error) => {
reject(error);
}
});
});
},
/**
* 提交举报
* @param {string} carId - 车辆ID
* @param {string} reason - 举报原因
* @returns {Promise} API响应
*/
submitReport(carId, reason) {
return new Promise((resolve, reject) => {
wx.request({
url: `${getApp().globalData.apiUrl}/reports`,
method: 'POST',
header: {
'Authorization': getApp().globalData.token,
'Content-Type': 'application/json'
},
data: {
car_id: carId,
reason: reason,
report_time: Date.now()
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(new Error(res.data.message || '举报提交失败'));
}
},
fail: (error) => {
reject(error);
}
});
});
},
/**
* 预约看车
* @param {Object} bookingData - 预约数据
* @returns {Promise} API响应
*/
bookViewing(bookingData) {
return new Promise((resolve, reject) => {
wx.request({
url: `${getApp().globalData.apiUrl}/bookings`,
method: 'POST',
header: {
'Authorization': getApp().globalData.token,
'Content-Type': 'application/json'
},
data: bookingData,
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(new Error(res.data.message || '预约失败'));
}
},
fail: (error) => {
reject(error);
}
});
});
}
};
/**
* 用户行为追踪
*/
export const analytics = {
/**
* 记录页面访问
* @param {string} carId - 车辆ID
* @param {string} source - 访问来源
*/
trackPageView(carId, source = 'direct') {
try {
// 这里可以接入第三方统计服务
console.log('页面访问:', { carId, source, timestamp: Date.now() });
} catch (error) {
console.error('统计记录失败:', error);
}
},
/**
* 记录用户操作
* @param {string} action - 操作类型
* @param {Object} params - 操作参数
*/
trackUserAction(action, params = {}) {
try {
console.log('用户操作:', { action, params, timestamp: Date.now() });
} catch (error) {
console.error('操作记录失败:', error);
}
}
};
/**
* 错误处理
*/
export const errorHandler = {
/**
* 显示错误提示
* @param {string} message - 错误信息
* @param {string} type - 错误类型
*/
showError(message, type = 'toast') {
switch (type) {
case 'toast':
wx.showToast({
title: message,
icon: 'none',
duration: 2000
});
break;
case 'modal':
wx.showModal({
title: '提示',
content: message,
showCancel: false
});
break;
}
},
/**
* 处理网络错误
* @param {Error} error - 错误对象
*/
handleNetworkError(error) {
let message = '网络错误,请稍后重试';
if (error.errMsg) {
if (error.errMsg.includes('timeout')) {
message = '请求超时,请检查网络连接';
} else if (error.errMsg.includes('fail')) {
message = '网络连接失败,请检查网络设置';
}
}
this.showError(message);
}
};
module.exports = {
formatTime
}