Files
smt-used-car-h5/pages/index/myPublishpro.vue
T
2026-03-12 16:47:27 +08:00

687 lines
16 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="page">
<!-- 列表 -->
<z-paging ref="paging" v-model="list" @query="queryList" empty-view-text="暂无发布数据!">
<template #top>
<!-- 搜索抓取 -->
<view class="dcd-search">
<u-search v-model="urls" placeholder="请输入抓取链接" :show-action="false" shape="round"></u-search>
<view class="bind-btn" @tap.stop="onBindByName">抓取</view>
</view>
</template>
<!-- 顶部:标题 + 搜索(放到底部) -->
<view class="page-head">
<view class="head-search">
<u-search
v-model="keyword"
placeholder="请输入关键词"
:show-action="false"
shape="round"
@change="onKeywordChange"
@search="onSearch"
@clear="onSearch"
/>
<view class="statussearch" @click="show=true">
<text class="year-text">{{status_name || '状态'}}</text>
<u-icon name="arrow-down" size="14" color="#999"></u-icon>
</view>
</view>
<u-picker :show="show" :columns="columns" keyName="label" @confirm="onstatus" @cancel="show = false"></u-picker>
</view>
<view class="list-wrap">
<uni-swipe-action-item
v-for="item in list"
:key="item.id"
:right-options="options1"
@click="swipeClick($event, item)"
>
<CarCardPro
:item="item"
:ismy="true"
@pdfchange="onSearch"
@restchange="onSearch"
/>
</uni-swipe-action-item>
</view>
</z-paging>
<!-- 抓取信息弹出层 -->
<uni-popup ref="crawlDialog" type="dialog">
<view class="crawl-dialog">
<view class="crawl-title">抓取信息</view>
<view class="crawl-content" v-if="crawlLoading">
<view class="crawl-loading">正在抓取中...</view>
</view>
<view class="crawl-content" v-else-if="crawlData">
<view class="crawl-item">
<view class="crawl-label">车辆名称</view>
<u-input v-model="crawlForm.product_name" placeholder="请输入车辆名称" border="none" :custom-style="inputStyle"></u-input>
</view>
<view class="crawl-item">
<view class="crawl-label">价格</view>
<u-input v-model="crawlForm.price" placeholder="请输入价格" type="number" border="none" :custom-style="inputStyle"></u-input>
</view>
<view class="crawl-item">
<view class="crawl-label">车源地</view>
<u-input v-model="crawlForm.source_place" placeholder="请输入车源地" border="none" :custom-style="inputStyle"></u-input>
</view>
<view class="crawl-item">
<view class="crawl-label">上牌时间</view>
<u-input v-model="crawlForm.plate_time" placeholder="请输入上牌时间" border="none" :custom-style="inputStyle"></u-input>
</view>
<view class="crawl-item">
<view class="crawl-label">排量</view>
<u-input v-model="crawlForm.displacement" placeholder="请输入排量" border="none" :custom-style="inputStyle"></u-input>
</view>
<view class="crawl-item">
<view class="crawl-label">功率</view>
<u-input v-model="crawlForm.power" placeholder="请输入功率" border="none" :custom-style="inputStyle"></u-input>
</view>
<view class="crawl-item">
<view class="crawl-label">车身颜色</view>
<u-input v-model="crawlForm.body_color" placeholder="请输入车身颜色" border="none" :custom-style="inputStyle"></u-input>
</view>
<view class="crawl-item">
<view class="crawl-label">里程</view>
<u-input v-model="crawlForm.mileage" placeholder="请输入里程" type="number" border="none" :custom-style="inputStyle"></u-input>
</view>
<view class="crawl-item">
<view class="crawl-label">车况描述</view>
<u-textarea v-model="crawlForm.condition_desc" placeholder="请输入车况描述" border="none" :custom-style="textareaStyle"></u-textarea>
</view>
<view class="crawl-item" v-if="crawlData.image_pull && crawlData.image_pull.length > 0">
<view class="crawl-label">图片</view>
<view class="crawl-images">
<image
v-for="(img, idx) in crawlData.image_pull"
:key="idx"
:src="img"
mode="aspectFill"
class="crawl-image"
/>
</view>
</view>
</view>
<view class="crawl-actions">
<view class="crawl-btn crawl-confirm1" @tap="closeCrawlDialog">关闭</view>
<view class="crawl-btn crawl-confirm" @tap="handleFetchConfirm">保存</view>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import { request } from '@/api/apiT.js'
import CarCardPro from '@/components/CarCardPro/CarCardPro.vue'
export default {
components: {
CarCardPro
},
data() {
return {
urls:'',
show: false,
status_id: '',
status_name: '',
crawlData: null,
crawlLoading: false,
crawlForm: {
product_name: '',
price: '',
source_place: '',
plate_time: '',
displacement: '',
power: '',
body_color: '',
mileage: '',
condition_desc: ''
},
inputStyle: {
background: '#f5f5f5',
borderRadius: '8rpx',
padding: '16rpx 20rpx'
},
textareaStyle: {
background: '#f5f5f5',
borderRadius: '8rpx',
padding: '16rpx 20rpx',
minHeight: '120rpx'
},
keyword: '',
page: 1,
pageSize: 10,
list: [],
columns: [
[
{ label: '全部', value: '' },
{ label: '待审核', value: 0 },
{ label: '通过', value: 1 },
{ label: '拒绝', value: 2 },
{ label: '推送中', value: 3 },
{ label: '推送成功', value: 4 },
{ label: '推送失败', value: 5 }
]
],
options1: [
{
text: '编辑',
style: {
backgroundColor: '#007aff'
}
},
{
text: '删除',
style: {
backgroundColor: '#dd524d'
}
}
]
}
},
onLoad(options) {
// 接收从其他页面传来的参数
if (options.keyword) {
this.keyword = options.keyword
}
// 首次加载数据
this.$nextTick(() => {
this.onSearch()
})
},
methods: {
// 获取列表数据
queryList(pageNo, pageSize) {
// 调用专业发布列表接口
request({
url: 'common/usedcardetail/list',
method: 'get',
data: {
scene: 'self', // 只看自己的发布
page: pageNo,
limit: pageSize,
keyword: this.keyword || '',
status: this.status_id || ''
}
}).then(res => {
if (res.data.code === 200) {
const data = res.data.data || {}
this.$refs.paging.complete(data.records || [])
} else {
this.$refs.paging.complete([])
uni.showToast({
title: res.data.message || '获取数据失败',
icon: 'none'
})
}
}).catch(err => {
console.error('[list error]', err)
this.$refs.paging.complete([])
uni.showToast({
title: '获取数据失败',
icon: 'none'
})
})
},
// 搜索
onSearch() {
this.$refs.paging.reload()
},
// 关键词变化(防抖)
onKeywordChange(val) {
this.keyword = val
// 防抖:300ms 内持续输入只触发一次
if (this._kwTimer) clearTimeout(this._kwTimer)
this._kwTimer = setTimeout(() => {
this.onSearch()
}, 300)
},
// 状态筛选
onstatus(e) {
const item = e.value[0]
this.status_id = item.value
this.status_name = item.label
this.show = false
this.onSearch()
},
// 滑动操作
swipeClick(e, item) {
if (e.content.text === '编辑') {
// 跳转到供应商发布编辑页面
uni.navigateTo({
url: '/pages/index/publisheditPro?id=' + item.id
})
} else if (e.content.text === '删除') {
// 删除确认
uni.showModal({
title: '提示',
content: '确定要删除这条发布吗?',
success: (res) => {
if (res.confirm) {
this.deleteItem(item)
}
}
})
}
},
// 删除发布
deleteItem(item) {
uni.showLoading({ title: '删除中...' })
request({
url: 'common/usedcardetail/delete',
method: 'post',
data: { id: item.id }
}).then(res => {
uni.hideLoading()
if (res.data.code === 200) {
uni.showToast({
title: '删除成功',
icon: 'success'
})
// 刷新列表
this.onSearch()
} else {
uni.showToast({
title: res.data.message || '删除失败',
icon: 'none'
})
}
}).catch(err => {
uni.hideLoading()
console.error('[delete error]', err)
uni.showToast({
title: '删除失败',
icon: 'none'
})
})
},
// 抓取链接
onBindByName() {
if (!this.urls || !this.urls.trim()) {
uni.showToast({ title: '请输入抓取链接', icon: 'none' })
return
}
this.crawlLoading = true
this.crawlData = null
this.$nextTick(() => {
this.$refs.crawlDialog && this.$refs.crawlDialog.open()
})
request({
url: 'common/usedcardetail/crawl',
method: 'post',
data: { url: this.urls }
}).then(res => {
this.crawlLoading = false
if (res.data.code == 200) {
this.crawlData = res.data.data || res.data
// 填充表单数据
this.crawlForm = {
product_name: this.crawlData.product_name || '',
price: this.crawlData.price || '',
source_place: this.crawlData.source_place || '',
plate_time: this.crawlData.plate_time || '',
displacement: this.crawlData.displacement || '',
power: this.crawlData.power || '',
body_color: this.crawlData.body_color || '',
mileage: this.crawlData.mileage || '',
condition_desc: this.crawlData.condition_desc || ''
}
uni.showToast({ title: res.data.message, icon: 'success' })
} else {
uni.showToast({ title: res.data.message || '抓取失败', icon: 'none' })
this.crawlData = null
}
}).catch(err => {
this.crawlLoading = false
this.crawlData = null
uni.showToast({ title: '抓取失败', icon: 'none' })
})
},
// 关闭抓取弹窗
closeCrawlDialog() {
this.$refs.crawlDialog && this.$refs.crawlDialog.close()
this.crawlData = null
this.crawlLoading = false
this.urls = ''
// 清空表单
this.crawlForm = {
product_name: '',
price: '',
source_place: '',
plate_time: '',
displacement: '',
power: '',
body_color: '',
mileage: '',
condition_desc: ''
}
},
// 确认保存抓取数据
handleFetchConfirm() {
const formData = {
...this.crawlData, // 所有抓取接口返回的原始数据
product_name: this.crawlForm.product_name,
price: this.crawlForm.price,
source_place: this.crawlForm.source_place,
plate_time: this.crawlForm.plate_time,
displacement: this.crawlForm.displacement,
power: this.crawlForm.power,
body_color: this.crawlForm.body_color,
condition_desc: this.crawlForm.condition_desc,
mileage: this.crawlForm.mileage
}
uni.showLoading({ title: '保存中...' })
request({
url: 'common/usedcardetail/crawl/store',
method: 'post',
data: formData
}).then(res => {
uni.hideLoading()
if (res.data.code === 200) {
uni.showToast({
title: res.data.message || '保存成功',
icon: 'success'
})
this.$refs.crawlDialog && this.$refs.crawlDialog.close()
this.crawlData = null
this.crawlLoading = false
this.urls = ''
// 清空表单
this.crawlForm = {
product_name: '',
price: '',
source_place: '',
plate_time: '',
displacement: '',
power: '',
body_color: '',
mileage: '',
condition_desc: ''
}
// 刷新列表
setTimeout(() => {
this.$refs.paging && this.$refs.paging.reload()
}, 1000)
} else {
uni.showToast({
title: res.data.message || '保存失败',
icon: 'none'
})
}
}).catch(err => {
uni.hideLoading()
console.error('[save error]', err)
uni.showToast({
title: '保存失败,请稍后重试',
icon: 'none'
})
})
},
// 保存抓取数据
saveCrawlDialog() {
function formatCnYearMonth(str) {
const match = str.match(/(\d{4})年(\d{1,2})月/)
if (!match) return str
const year = match[1]
const month = match[2].padStart(2, '0')
return `${year}-${month}-01`
}
const payload = {
...this.crawlData,
plate_time: formatCnYearMonth(this.crawlData.plate_time),
// images 数组 => "url1,url2,url3"
images: (this.crawlData.images || [])
.map(s => String(s || '').trim())
.filter(Boolean)
.join(',')
}
request({
url: 'common/usedcardetail/store',
method: 'post',
data: payload
}).then(res => {
this.$refs.crawlDialog && this.$refs.crawlDialog.close()
this.crawlData = null
this.crawlLoading = false
this.urls = ''
uni.showToast({
title: res.data.message || '保存成功',
icon: 'none'
})
setTimeout(() => {
this.$refs.paging && this.$refs.paging.reload()
}, 1000)
})
}
}
}
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #F8F8F8;
/* #ifdef H5 */
padding-bottom: calc(100rpx + env(safe-area-inset-bottom));
/* #endif */
}
/* 抓取搜索区域 */
.dcd-search {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
background: #fff;
}
.bind-btn {
padding: 8px 24px;
background: #3F435B;
color: #fff;
border-radius: 8px;
font-size: 28rpx;
white-space: nowrap;
cursor: pointer;
}
.bind-btn:active {
opacity: 0.8;
}
/* 搜索区域(放到底部) */
.page-head {
position: fixed;
width: 100%;
bottom: 0;
left: 0;
z-index: 99;
}
.head-search {
display: flex;
align-items: center;
gap: 10px;
background: rgba(255, 255, 255, 1);
border-radius: 18rpx;
padding: 20rpx 10px;
box-shadow: 0 10rpx 28rpx rgba(0, 0, 0, 0.06);
}
.statussearch {
border: 1px solid #eae9e9;
border-radius: 4px;
padding: 4px 8px;
font-size: 24rpx;
display: flex;
align-items: center;
gap: 6px;
}
.year-text {
font-size: 26rpx;
color: #333;
}
.list-wrap {
padding: 20rpx 24rpx;
padding-bottom: 120rpx;
}
/* 列表项过渡动画 */
.list-wrap >>> .uni-swipe {
margin-bottom: 20rpx;
border-radius: 16rpx;
overflow: hidden;
background: #fff;
}
.list-wrap >>> .uni-swipe_button_group {
display: flex;
}
.list-wrap >>> .uni-swipe_box {
background: #fff;
}
/* 空状态样式 */
:deep(.z-paging-empty-view) {
padding-top: 200rpx !important;
}
:deep(.z-paging-empty-view-text) {
font-size: 28rpx;
color: #999;
margin-top: 20rpx;
}
/* 加载更多样式 */
:deep(.z-paging-loading-more-text) {
font-size: 26rpx;
color: #999;
padding: 20rpx 0;
}
/* 抓取信息弹出层样式 */
.crawl-dialog {
width: 680rpx;
max-height: 80vh;
background: #fff;
border-radius: 24rpx;
padding: 28rpx;
box-sizing: border-box;
overflow: hidden;
display: flex;
flex-direction: column;
}
.crawl-title {
font-size: 36rpx;
font-weight: 600;
color: #111;
margin-bottom: 30rpx;
text-align: center;
}
.crawl-content {
flex: 1;
overflow-y: auto;
max-height: 60vh;
}
.crawl-loading {
text-align: center;
padding: 60rpx 0;
font-size: 28rpx;
color: #999;
}
.crawl-item {
margin-bottom: 24rpx;
padding-bottom: 24rpx;
border-bottom: 1px solid #f0f0f0;
}
.crawl-item:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.crawl-label {
font-size: 26rpx;
color: #999;
margin-bottom: 12rpx;
}
.crawl-value {
font-size: 30rpx;
color: #333;
word-break: break-all;
line-height: 1.6;
}
.crawl-images {
display: flex;
flex-wrap: wrap;
gap: 12rpx;
margin-top: 12rpx;
}
.crawl-image {
width: 180rpx;
height: 180rpx;
border-radius: 12rpx;
background: #f5f5f5;
}
.crawl-actions {
display: flex;
gap: 18rpx;
margin-top: 30rpx;
padding-top: 30rpx;
border-top: 1px solid #f0f0f0;
}
.crawl-btn {
flex: 1;
height: 84rpx;
border-radius: 18rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
}
.crawl-confirm1 {
border: 1px solid #3F435B;
font-weight: 600;
}
.crawl-confirm {
background: #3F435B;
color: #fff;
font-weight: 600;
}
</style>