调整 发布

This commit is contained in:
浅念
2026-03-12 16:48:21 +08:00
parent 41b7588062
commit bc81b16419
9 changed files with 441 additions and 64 deletions
+306 -24
View File
@@ -11,14 +11,17 @@
<el-option label="待审核" :value="0" />
<el-option label="审核通过" :value="1" />
<el-option label="审核拒绝" :value="2" />
<el-option label="抓取成功" :value="3" />
<el-option label="推送成功" :value="4" />
<el-option label="推送失败" :value="5" />
</el-select>
</el-form-item>
</div>
</div>
<div class="boxshadow">
<!-- <div style="text-align: right; padding: 12px 0">
<el-button type="primary" @click="goToAdd"> 新增发布 </el-button>
</div> -->
<div style="text-align: right; padding: 12px 0">
<el-button type="primary" @click="fetchpublishfn"> 抓取 </el-button>
</div>
<ArtTable
ref="tableRef"
row-key="id"
@@ -65,7 +68,14 @@
<template #default="scope">
<ElRow>
<el-button link @click="showDialog('detail', scope.row)"> 详情 </el-button>
<el-button link type="primary" @click="editFn(scope.row)"> 编辑 </el-button>
<el-button
link
type="primary"
@click="editFn(scope.row)"
v-if="scope.row.status === 0 || scope.row.status === 2"
>
编辑
</el-button>
<el-button link type="success" @click="showAuditRecords(scope.row)"> 审核记录 </el-button>
<el-button link type="danger" @click="deleteFn(scope.row)"> 删除 </el-button>
</ElRow>
@@ -110,7 +120,7 @@
</div>
</el-descriptions-item>
<!-- FAQ 展示 -->
<el-descriptions-item label="FAQ 问答" :span="2" v-if="detailData.faqs && detailData.faqs.length">
<!-- <el-descriptions-item label="FAQ 问答" :span="2" v-if="detailData.faqs && detailData.faqs.length">
<div class="faq-display">
<div v-for="(faq, index) in detailData.faqs" :key="index" class="faq-item">
<div class="faq-question">
@@ -123,7 +133,7 @@
</div>
</div>
</div>
</el-descriptions-item>
</el-descriptions-item> -->
<!-- 产品图 -->
<el-descriptions-item label="产品图" :span="2">
<div
@@ -305,14 +315,15 @@
<MultiFileUpload
v-model="editAttachmentFileList"
upload-text="点击上传附件"
hint-text="支持多个文件上传"
hint-text="仅支持单个文件上传"
:max-count="1"
:action-image-uplode="uploadActionFile"
@change="handleEditAttachmentChange"
/>
</el-form-item>
</ElCol>
<!-- FAQ 编辑 -->
<ElCol :sm="24" :md="24" :lg="24">
<!-- <ElCol :sm="24" :md="24" :lg="24">
<el-form-item label="FAQ 问答">
<div class="faq-container">
<div v-for="(faq, index) in editForm.faqs" :key="index" class="faq-item">
@@ -344,7 +355,7 @@
</el-button>
</div>
</el-form-item>
</ElCol>
</ElCol> -->
</ElRow>
</el-form>
</el-scrollbar>
@@ -452,6 +463,97 @@
</template>
</el-dialog>
<!-- 抓取弹窗 -->
<el-dialog
v-model="fetchDialogVisible"
title="抓取数据"
width="800px"
:close-on-click-modal="false"
>
<div class="fetch-dialog-content">
<el-form :model="fetchForm" label-width="70px" style="margin-bottom: 20px; display: flex">
<el-form-item label="抓取链接">
<el-input
v-model="fetchForm.url"
placeholder="请输入要抓取的链接"
clearable
style="width: 100%"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleFetch" :loading="fetchLoading">抓取</el-button>
</el-form-item>
</el-form>
<!-- 抓取结果显示 -->
<div v-if="fetchLoading" class="fetch-loading">
<el-icon class="is-loading"><Loading /></el-icon>
<span style="margin-left: 8px">正在抓取中...</span>
</div>
<el-form v-else-if="fetchData" :model="fetchForm" label-width="100px" class="fetch-result-form">
<ElRow :gutter="12">
<ElCol :sm="24" :md="12" :lg="12">
<el-form-item label="产品名称">
<el-input v-model="fetchForm.product_name" placeholder="请输入产品名称" />
</el-form-item>
</ElCol>
<ElCol :sm="24" :md="12" :lg="12">
<el-form-item label="车价(¥)">
<el-input v-model="fetchForm.price" placeholder="请输入车价" />
</el-form-item>
</ElCol>
<ElCol :sm="24" :md="12" :lg="12">
<el-form-item label="车源地">
<el-input v-model="fetchForm.source_place" placeholder="请输入车源地" />
</el-form-item>
</ElCol>
<ElCol :sm="24" :md="12" :lg="12">
<el-form-item label="上牌时间">
<el-input v-model="fetchForm.plate_time" placeholder="请输入上牌时间" />
</el-form-item>
</ElCol>
<ElCol :sm="24" :md="12" :lg="12">
<el-form-item label="排量">
<el-input v-model="fetchForm.displacement" placeholder="请输入排量" />
</el-form-item>
</ElCol>
<ElCol :sm="24" :md="12" :lg="12">
<el-form-item label="里程(Km)">
<el-input v-model="fetchForm.mileage" placeholder="请输入里程" />
</el-form-item>
</ElCol>
<ElCol :sm="24" :md="12" :lg="12">
<el-form-item label="马力">
<el-input v-model="fetchForm.power" placeholder="请输入马力" />
</el-form-item>
</ElCol>
<ElCol :sm="24" :md="12" :lg="12">
<el-form-item label="车身颜色">
<el-input v-model="fetchForm.body_color" placeholder="请输入车身颜色" />
</el-form-item>
</ElCol>
<ElCol :sm="24" :md="24" :lg="24">
<el-form-item label="车况介绍">
<el-input
v-model="fetchForm.condition_desc"
type="textarea"
:rows="3"
placeholder="请输入车况介绍"
/>
</el-form-item>
</ElCol>
</ElRow>
</el-form>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="fetchDialogVisible = false">关 闭</el-button>
<el-button type="primary" @click="handleFetchConfirm" :disabled="!fetchData">确认添加</el-button>
</span>
</template>
</el-dialog>
<!-- 图片预览组件 -->
<ElImageViewer
v-if="showImageViewer1"
@@ -475,11 +577,13 @@
ElMessage,
ElMessageBox,
ElLoading,
ElRow,
ElCol,
type FormInstance,
type FormRules,
type UploadFile
} from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import { Plus, Loading, User, ArrowRight } from '@element-plus/icons-vue'
import { manageService } from '@/api/adminApi'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
@@ -545,7 +649,8 @@
body_color: string
condition_desc: string
mileage: string
images: string[]
images: string[] // 用于显示(images_pull)
original_images: string[] // 用于保存提交(原始 images)
intro_video: string[]
attachment: { name: string; src: string }[]
faqs: FAQItem[]
@@ -571,6 +676,7 @@
condition_desc: '',
mileage: '',
images: [],
original_images: [],
intro_video: [],
attachment: [],
faqs: [{ question: '', answer: '' }],
@@ -647,9 +753,14 @@
const showImageViewer1 = ref(false)
const viewerIndex = ref(0)
const currentPdfFiles = ref('')
const imgList = computed(() =>
parsePreviewList(detailData.value?.images_pull || detailData.value?.images || [])
)
const fetchImgList = ref<string[]>([])
const imgList = computed(() => {
// 如果抓取弹窗打开且有图片,显示抓取的图片
if (fetchDialogVisible.value && fetchImgList.value.length > 0) {
return fetchImgList.value
}
return parsePreviewList(detailData.value?.images_pull || detailData.value?.images || [])
})
const handleAvatarClick1 = (index: string) => {
if (index !== null && index !== undefined) {
@@ -688,7 +799,10 @@
const statusMap: Record<number, string> = {
0: '待审核',
1: '审核通过',
2: '审核拒绝'
2: '审核拒绝',
3: '推送中',
4: '推送成功',
5: '推送失败'
}
return statusMap[status] || '未知'
}
@@ -697,7 +811,10 @@
const colorMap: Record<number, 'success' | 'warning' | 'danger' | 'info'> = {
0: 'warning',
1: 'success',
2: 'danger'
2: 'danger',
3: 'info',
4: 'success',
5: 'danger'
}
return colorMap[status] || 'info'
}
@@ -709,7 +826,10 @@
const colorMap: Record<number, 'success' | 'warning' | 'danger' | 'info'> = {
0: 'warning',
1: 'success',
2: 'danger'
2: 'danger',
3: 'info',
4: 'success',
5: 'danger'
}
return colorMap[status] || 'info'
}
@@ -792,15 +912,19 @@
editForm.condition_desc = res.condition_desc || ''
editForm.mileage = res.mileage || ''
// 处理图片
const images = parsePreviewList(res.images_pull || res.images || [])
editForm.images = images
editImageFileList.value = images.map((url, idx) => ({
// 处理图片:images_pull 用于显示,images 用于保存
const displayImages = parsePreviewList(res.images_pull || res.images || [])
const saveImages = parsePreviewList(res.images || [])
editForm.images = displayImages // 用于显示
editForm.original_images = saveImages // 用于保存提交
editImageFileList.value = displayImages.map((url, idx) => ({
name: `image_${idx}`,
url,
status: 'success' as const,
uid: idx,
response: { file_url: url, file_name: url }
response: { file_url: url, file_name: saveImages[idx] || url }
}))
// 处理视频
@@ -965,6 +1089,7 @@
if (fileName && !editForm.images.includes(fileName)) {
editForm.images.push(fileName)
editForm.original_images.push(fileName)
}
editImageFileList.value = fileList as UploadFileWithResponse[]
loadingInstance.value?.close()
@@ -975,7 +1100,10 @@
const fileName = resp?.file_name || resp?.data?.file_name || ''
if (fileName) {
const idx = editForm.images.indexOf(fileName)
if (idx > -1) editForm.images.splice(idx, 1)
if (idx > -1) {
editForm.images.splice(idx, 1)
editForm.original_images.splice(idx, 1)
}
}
editImageFileList.value = fileList as UploadFileWithResponse[]
}
@@ -1076,7 +1204,7 @@
body_color: editForm.body_color,
condition_desc: editForm.condition_desc,
mileage: editForm.mileage,
images: editForm.images.map((s) => String(s || '').trim()).filter(Boolean).join(','),
images: editForm.original_images.map((s) => String(s || '').trim()).filter(Boolean).join(','),
intro_video: editForm.intro_video.map((s) => String(s || '').trim()).filter(Boolean).join(','),
attachment: editForm.attachment,
faqs: validFaqs.length > 0 ? validFaqs : undefined,
@@ -1179,6 +1307,129 @@
getWorkList()
}
// 抓取相关
const fetchDialogVisible = ref(false)
const fetchForm = reactive({
url: '',
product_name: '',
price: '',
source_place: '',
plate_time: '',
displacement: '',
power: '',
body_color: '',
condition_desc: '',
mileage: ''
})
const fetchLoading = ref(false)
const fetchData = ref<any>(null)
// 打开抓取弹窗
const fetchpublishfn = () => {
fetchDialogVisible.value = true
fetchForm.url = ''
fetchForm.product_name = ''
fetchForm.price = ''
fetchForm.source_place = ''
fetchForm.plate_time = ''
fetchForm.displacement = ''
fetchForm.power = ''
fetchForm.body_color = ''
fetchForm.condition_desc = ''
fetchForm.mileage = ''
fetchData.value = null
fetchImgList.value = []
}
// 执行抓取
const handleFetch = async () => {
if (!fetchForm.url || !fetchForm.url.trim()) {
ElMessage.warning('请输入抓取链接')
return
}
fetchLoading.value = true
fetchData.value = null
try {
const res: any = await request.post({
url: '/common/usedcardetail/crawl',
params: { url: fetchForm.url.trim() }
})
fetchData.value = res?.data || res || {}
// 填充表单数据
fetchForm.product_name = fetchData.value.product_name || ''
fetchForm.price = fetchData.value.price || ''
fetchForm.source_place = fetchData.value.source_place || ''
fetchForm.plate_time = fetchData.value.plate_time || ''
fetchForm.displacement = fetchData.value.displacement || ''
fetchForm.power = fetchData.value.power || ''
fetchForm.body_color = fetchData.value.body_color || ''
fetchForm.condition_desc = fetchData.value.condition_desc || ''
fetchForm.mileage = fetchData.value.mileage || ''
// 处理图片列表用于预览
fetchImgList.value = parsePreviewList(fetchData.value.image_pull || fetchData.value.image || [])
ElMessage.success(res?.message || '抓取成功')
console.log('抓取接口返回数据:', fetchData.value)
} catch (error: any) {
console.error('抓取失败:', error)
fetchData.value = null
ElMessage.error(error?.message || '抓取失败,请稍后重试')
} finally {
fetchLoading.value = false
}
}
// 确认添加抓取的数据
// 确认添加抓取的数据
const handleFetchConfirm = async () => {
// 合并抓取接口返回的原始数据和用户修改的数据
const formData = {
...fetchData.value, // 保存所有抓取接口返回的原始数据
// 用表单中修改的值替换对应字段
product_name: fetchForm.product_name,
price: fetchForm.price,
source_place: fetchForm.source_place,
plate_time: fetchForm.plate_time,
displacement: fetchForm.displacement,
power: fetchForm.power,
body_color: fetchForm.body_color,
condition_desc: fetchForm.condition_desc,
mileage: fetchForm.mileage
}
console.log('保存抓取数据:', formData)
try {
const res: any = await request.post({
url: '/common/usedcardetail/crawl/store',
params: formData
})
ElMessage.success(res?.message)
fetchDialogVisible.value = false
getWorkList() // 刷新列表
} catch (error: any) {
console.error('保存抓取数据失败:', error)
ElMessage.error(error?.message || '保存失败,请稍后重试')
}
}
// 抓取图片预览点击
const handleFetchAvatarClick = (index: number) => {
viewerIndex.value = index
showImageViewer.value = true
}
// 格式化年月(如:2024年01月 -> 2024-01-01)
function formatCnYearMonth(str: string) {
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`
}
onMounted(() => {
getWorkList()
})
@@ -1470,4 +1721,35 @@
}
}
}
// 抓取弹窗样式
.fetch-dialog-content {
.fetch-loading {
display: flex;
align-items: center;
justify-content: center;
padding: 40px 0;
color: #909399;
}
.fetch-result {
.thumb-list {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.avatarimg {
width: 60px;
height: 60px;
object-fit: cover;
border-radius: 4px;
cursor: pointer;
transition: opacity 0.2s;
&:hover {
opacity: 0.8;
}
}
}
}
</style>