Files
used-car-h5/components/CarCard/CarCard.vue
T
2026-01-16 09:54:29 +08:00

377 lines
8.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="car-cards" >
<view class="heard">
<view class="" @click="handleCardTap">
编号:{{item.code?item.code:'~'}}
</view>
<view v-if="ismy">
<u-icon @click="detilsfn(item)" name="edit-pen-fill" size="25" />
</view>
</view>
<view class="car-card" @click="handleCardTap">
<image class="thumb" :src="item.images_pull[0]" mode="aspectFill" />
<view class="info">
<view class="row row1">
<text class="name u-line-1">{{ item.product_name }}</text>
</view>
<view class="row row2">
<view class="kv">
<text class="k">车源地</text>
<text class="v u-line-1">{{ item.source_place }}</text>
</view>
<view class="kv">
<text class="k">车身颜色</text>
<text class="v u-line-1">{{ item.body_color }}</text>
</view>
</view>
<view class="row row3">
<view class="kv">
<text class="k">上牌时间</text>
<text class="v">{{ formatPlateTime(item.plate_time) }}</text>
</view>
<view class="kv">
<text class="k">里程</text>
<text class="v">{{ item.mileage }} <text v-if="item.mileage">Km</text> </text>
</view>
</view>
</view>
</view>
<!-- 操作区:保存 + 分享(方案A:卡片右下角悬浮) -->
<view class="card-actions">
<view class="actions-lift" @click="handleCardTap">
<text class="">创建时间:</text>
<text class="">{{ item.created_at }}</text>
</view>
<view class="right-btn">
<view class="action-btn" @tap.stop="handleToggleSave">
<u-icon name="download" size="18" />
</view>
<view class="action-btn" @tap.stop="handleShare">
<u-icon name="share" size="18" />
</view>
</view>
</view>
</view>
</template>
<script>
import { request } from '@/api/apiT.js'
export default {
name: 'CarCard',
props: {
item: {
type: Object,
required: true
},
ismy:{
default: false,
type: Boolean
},
index: {
type: Number,
default: -1
}
},
methods: {
detilsfn(item){
const id = item.id
uni.navigateTo({
url: `/pages/index/publishedit?id=${id}`
})
},
formatPlateTime(dateStr) {
return String(dateStr || '').slice(0, 7) // "2026-01"
},
pdfchanges() {
this.$emit('pdfchange')
},
handleCardTap() {
// 直接处理跳转,避免事件传递问题
if (this.item && this.item.id) {
const id = this.item.id
uni.navigateTo({
url: `/pages/index/detils?id=${id}`
})
} else {
console.error('CarCard: item or item.id is missing', this.item)
}
},
// H5 下载:用 a 标签触发
downloadByAnchor(url, filename) {
try {
const a = document.createElement('a')
a.href = url
a.download = filename || ''
a.target = '_blank'
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
} catch (e) {
// 兜底:直接打开
if (typeof window !== 'undefined') window.open(url, '_blank')
}
},
downloadpdf(item) {
request({
url: 'common/usedcar/pdf',
method: 'get',
data: { id: item.id }
}).then(res => {
if (res.data.code == 200) {
this.downloadByAnchor(res.data.data.pdf_url, res.data.data.file_name)
}
})
},
handleToggleSave() {
const item = this.item
// if (item.pdf_src && item.pdf_src != '') {
// this.downloadpdf(item)
// } else {
// 让父组件统一弹出输入框(避免列表里每个卡片都渲染一个 popup)
this.$emit('request-price', { item, index: this.index })
// }
},
buildShareLink(id) {
// 统一生成"详情页路径"
const path = `pages/index/detils?id=${id}&appid=${uni.getStorageSync('fsappid')}`
// #ifdef H5
try {
const origin = window.location.origin
// uni-app H5 默认 hash 路由
return `${origin}/${path}`
} catch (e) {
return path
}
// #endif
return path
},
isFeishuEnv() {
// 飞书/ Lark 客户端内置浏览器 UA 通常包含 Feishu / Lark
try {
const ua = (navigator.userAgent || '').toLowerCase()
return ua.includes('feishu') || ua.includes('lark')
} catch (e) {
return false
}
},
feishuShare(payload) {
// 在飞书内优先使用 tt.share
try {
if (!this.isFeishuEnv()) return false
if (!window || !window.tt || !window.h5sdk) return false
// ready 后再调用
window.h5sdk.ready(() => {
// 优先使用 shareWebContent(文档推荐的 Web App 分享能力),不支持则降级到 share
if (typeof window.tt.shareWebContent === 'function') {
window.tt.shareWebContent({
title: payload.title,
content: payload.desc,
url: payload.link,
imageUrl: payload.imageUrl,
success: () => {
uni.showToast({ title: '已唤起飞书分享', icon: 'none' })
},
fail: (err) => {
console.error('feishu shareWebContent fail:', err)
uni.showToast({ title: '分享失败,可复制链接', icon: 'none' })
}
})
} else if (typeof window.tt.share === 'function') {
window.tt.share({
title: payload.title,
desc: payload.desc,
link: payload.link,
imageUrl: payload.imageUrl,
success: () => {
uni.showToast({ title: '已唤起飞书分享', icon: 'none' })
},
fail: (err) => {
console.error('feishu share fail:', err)
uni.showToast({ title: '分享失败,可复制链接', icon: 'none' })
}
})
} else {
throw new Error('Feishu share api not available')
}
})
return true
} catch (e) {
return false
}
},
handleShare() {
const item = this.item
const title = item.product_name || '车辆详情'
const link = this.buildShareLink(item.id)
const imageUrl = (item.images_pull && item.images_pull[0]) ? item.images_pull[0] : ''
// #ifdef MP-WEIXIN
// 小程序:打开系统分享面板(需要页面 onShareAppMessage 支持)
uni.showShareMenu({ withShareTicket: true })
uni.showToast({ title: '请使用右上角分享', icon: 'none' })
// #endif
// #ifdef H5
// 1) 飞书内:优先走飞书分享
const ok = this.feishuShare({
title,
desc: title,
link,
imageUrl
})
if (ok) return
// H5:优先走 Web Share API
if (typeof navigator !== 'undefined' && navigator.share) {
navigator.share({ title, text: title, url: link }).catch(() => {})
return
}
// #endif
// 兜底:弹出操作并复制链接
uni.showActionSheet({
itemList: ['复制链接', '复制标题'],
success: (res) => {
if (res.tapIndex === 0) {
uni.setClipboardData({ data: link })
} else {
uni.setClipboardData({ data: title })
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
.heard{
padding: 5px 10px;
color: #666;
font-size: 12px;
display: flex;
align-items: center;
justify-content: space-between;
}
.car-cards {
padding-bottom: 6rpx; // 预留右下角按钮空间,避免遮挡信息
border-radius: 18rpx;
background: rgba(255, 255, 255, 0.95);
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.06);
margin-bottom: 18rpx;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
.car-card {
position: relative;
display: flex;
align-items: stretch;
padding: 18rpx;
}
/* 方案A:卡片右下角悬浮操作区 */
.card-actions {
padding: 18rpx;
display: flex;
align-items: center;
justify-content: space-between;
gap: 14rpx;
border-top: 1px solid #e1e1e1;
}
.actions-lift {
font-size: 12px;
}
.right-btn {
display: flex;
gap: 14rpx;
}
.action-btn {
width: 50rpx;
height: 50rpx;
border-radius: 999rpx;
background: rgba(255, 255, 255, 0.92);
box-shadow: 0 8rpx 18rpx rgba(0, 0, 0, 0.12);
display: flex;
align-items: center;
justify-content: center;
}
.action-btn:active {
transform: scale(0.96);
}
.thumb {
width: 190rpx;
height: 140rpx;
border-radius: 14rpx;
background: #eef2f7;
flex-shrink: 0;
}
.info {
flex: 1;
margin-left: 18rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.row {
display: flex;
align-items: center;
}
.row1 {
justify-content: space-between;
margin-bottom: 10rpx;
}
.name {
font-size: 30rpx;
font-weight: 700;
color: #111827;
max-width: 420rpx;
}
.tag {
font-size: 22rpx;
padding: 6rpx 12rpx;
border-radius: 999rpx;
background: rgba(255, 151, 47, 0.14);
color: #b45309;
flex-shrink: 0;
}
.row2,
.row3 {
justify-content: space-between;
gap: 16rpx;
}
.kv {
flex: 1;
min-width: 0;
display: flex;
align-items: baseline;
}
.k {
font-size: 22rpx;
color: #6b7280;
margin-right: 10rpx;
flex-shrink: 0;
}
.v {
font-size: 24rpx;
color: #374151;
font-weight: 600;
min-width: 0;
}
</style>