详情
This commit is contained in:
parent
a241484705
commit
90ece932c9
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal 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
8
.idea/car_front.iml
Normal 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
8
.idea/modules.xml
Normal 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
19
.idea/php.xml
Normal 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
6
.idea/vcs.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
5
app.json
5
app.json
|
|
@ -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
203
pages/car_new/car_new.js
Normal 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();
|
||||
}
|
||||
})
|
||||
11
pages/car_new/car_new.json
Normal file
11
pages/car_new/car_new.json
Normal 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
156
pages/car_new/car_new.wxml
Normal 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
380
pages/car_new/car_new.wxss
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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();
|
||||
}
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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
339
pages/info/info.js
Normal 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
10
pages/info/info.json
Normal 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
151
pages/info/info.wxml
Normal 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
828
pages/info/info.wxss
Normal 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;
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"usingComponents": {
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
"disablePlugins": [],
|
||||
"outputPath": ""
|
||||
},
|
||||
"compileWorklet": false,
|
||||
"compileWorklet": true,
|
||||
"uglifyFileName": false,
|
||||
"uploadWithSourceMap": true,
|
||||
"packNpmManually": false,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"projectname": "car_front",
|
||||
"setting": {
|
||||
"compileHotReLoad": true,
|
||||
"urlCheck": true,
|
||||
"urlCheck": false,
|
||||
"coverView": true,
|
||||
"lazyloadPlaceholderEnable": false,
|
||||
"skylineRenderEnable": false,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
382
utils/util.js
382
utils/util.js
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user