| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734 |
- <template>
- <view class="detail-container">
- <!-- 顶部封面图轮播 -->
- <view class="image-section">
- <swiper
- class="image-swiper"
- :indicator-dots="false"
- :circular="false"
- :autoplay="false"
- @change="onSwiperChange"
- >
- <swiper-item v-for="(image, index) in imageList" :key="index" @click="previewImage(index)">
- <image :src="image" mode="aspectFill" class="cover-image" lazy-load></image>
- </swiper-item>
- </swiper>
-
- <!-- 自定义分页指示器 -->
- <view class="custom-dots" v-if="imageList.length > 1">
- <view
- class="dot"
- :class="{ active: currentImageIndex === index }"
- v-for="(item, index) in imageList"
- :key="index"
- ></view>
- </view>
- </view>
- <!-- 标题和类型标签 -->
- <view class="title-section">
- <view class="title-content">
- <text class="product-title">{{ productInfo.title }}</text>
- <view class="type-tag" :class="productInfo.type === 0 ? 'sale' : 'purchase'">
- {{ productInfo.type === 0 ? '出售' : '收购' }}
- </view>
- </view>
- </view>
- <!-- 核心信息展示卡片 -->
- <view class="info-card">
- <view class="info-row">
- <text class="info-label">分类</text>
- <text class="info-value">{{ getDictLabel('agricultural_category',productInfo.categoryId) }}</text>
- </view>
- <view class="info-row">
- <text class="info-label">{{ productInfo.type === 0 ? '单价' : '收购价' }}</text>
- <text class="info-value price">¥{{ productInfo.price }}/{{ getDictLabel('agricultural_unit',productInfo.unit) }}</text>
- </view>
- <view class="info-row">
- <text class="info-label">数量</text>
- <text class="info-value">{{ productInfo.quantity }}{{ productInfo.unit }}</text>
- </view>
- <view class="info-row">
- <text class="info-label">所在地</text>
- <!-- <text class="info-value location">{{ productInfo.location }}</text> -->
- <LocationPicker class="info-value location"
- v-model="productInfo.location"
- mode="view"
- />
- </view>
-
- </view>
- <!-- 补充说明区域 -->
- <view class="description-card">
- <view class="card-title">
- <text>{{ productInfo.type === 0 ? '产品详情' : '收购要求' }}</text>
- </view>
- <view class="description-content">
- <text class="description-text">
- {{ productInfo.description || '无补充说明' }}
- </text>
- </view>
- </view>
- <!-- 发布者信息卡片 -->
- <view class="publisher-card">
- <view class="card-title">
- <text>发布者信息</text>
- </view>
- <view class="publisher-info">
- <view class="info-row">
- <text class="info-label">联系人</text>
- <text class="info-value">{{ productInfo.contactName }}</text>
- </view>
- <view class="info-row">
- <text class="info-label">联系电话</text>
- <text class="info-value phone">{{ productInfo.contactPhone }}</text>
- </view>
- <view class="info-row">
- <text class="info-label">发布时间</text>
- <text class="info-value">{{ productInfo.publishTime }}</text>
- </view>
- </view>
- </view>
-
- <!-- 审批意见 -->
- <view class="description-card" v-if="productInfo.status === 4">
- <view class="card-title">
- <text>审核结果</text>
- </view>
- <view class="description-content" style="border-left: 2px solid red">
- <text class="description-text" >
- {{ productInfo.remark || '无' }}
- </text>
- </view>
- </view>
- <!-- 底部操作按钮 -->
- <view class="action-buttons" v-if="shouldShowActionButtons">
- <!-- 当前用户发布的内容
- <!-- <template v-if="isOwnProduct">
- <!-- 已上架状态:显示编辑和下架
- <template v-if="productStatus === '2'">
- <!-- <button class="action-btn edit-btn" @click="editProduct">
- 编辑
- </button>
- <button class="action-btn remove-btn" @click="removeProduct">
- 下架
- </button>
- </template>
-
- <!-- 审核中状态:显示编辑和撤销
- <template v-else-if="productStatus === '1'">
- <!-- <button class="action-btn edit-btn" @click="editProduct">
- 编辑
- </button>
- <button class="action-btn cancel-btn" @click="cancelProduct">
- 撤销
- </button>
- </template>
-
- <!-- 已下架状态:不显示任何按钮
- <template v-else-if="productStatus === '3'">
- <button class="action-btn edit-btn" @click="editProduct">
- 编辑
- </button>
- <button class="action-btn cancel-btn" @click="cancelProduct">
- 发布
- </button>
- </template>
- <!-- 未通过
- <template v-else-if="productStatus === '4'">
- <button class="action-btn edit-btn" @click="editProduct">
- 编辑
- </button>
- <button class="action-btn cancel-btn" @click="cancelProduct">
- 删除
- </button>
- </template>
- </template> -->
- <!-- 当前用户发布的内容 -->
- <template v-if="isOwnProduct">
- <button
- v-for="(btn, index) in actionMap[productStatus] || []"
- :key="index"
- class="action-btn"
- :class="btn.class"
- @click="handleAction(btn.action)"
- >
- {{ btn.label }}
- </button>
- </template>
-
- <!-- 他人发布的内容 -->
- <template v-else>
- <button class="action-btn contact-btn" @click="contactPublisher">
- 立即联系
- </button>
- </template>
- </view>
- </view>
- </template>
- <script setup>
- import { ref, computed, onMounted } from 'vue'
- import LocationPicker from "@/components/common/LocationPicker.vue"
- import { getProductInfoById, editProductInfo } from '@/api/services/productInfo.js'
- import { useDict } from '@/utils/composables/useDict'
- // 使用字典
- const { dictData } = useDict(['agricultural_category', 'agricultural_unit'])
- const currentImageIndex = ref(0)
- const source = ref('') // 页面来源,myPublish表示来自我的发布页面
- const productStatus = ref('') // 产品状态:1-pending, 2-approved, 3-rejected
- const productInfo = ref({
- id: '',
- type: '0', // 0-sale: 出售, 1-purchase: 收购
- title: '',
- categoryId: '',
- price: '',
- quantity: '',
- unit: '',
- location: '',
- description: '',
- contactName: '',
- contactPhone: '',
- publishTime: '',
- images: [],
- remark: ''
- })
- const imageList = ref([])
- const isOwnProduct = ref(false) // 是否为当前用户发布的产品
- // 状态按钮映射
- const actionMap = {
- '1': [], // 审核中
- '2': [ // 已上架
- { label: '下架', class: 'remove-btn', action: 'removeProduct' }
- ],
- '3': [ // 已下架
- { label: '编辑', class: 'edit-btn', action: 'editProduct' },
- { label: '发布', class: 'cancel-btn', action: 'publishProduct' }
- ],
- '4': [ // 未通过
- { label: '编辑', class: 'edit-btn', action: 'editProduct' }
- ]
- }
- // 判断是否显示操作按钮
- const shouldShowActionButtons = computed(() => {
- if (!isOwnProduct.value) {
- // 他人发布的内容始终显示联系按钮
- return true
- } else {
- // 自己发布的内容,已下架状态不显示任何按钮
- return productStatus.value !== 'rejected'
- }
- })
- // 页面显示时刷新数据
- const onShow = () => {
- if (productInfo.value.id) {
- loadProductDetail(productInfo.value.id)
- }
- }
- // 页面加载
- onMounted(() => {
- const pages = getCurrentPages()
- const currentPage = pages[pages.length - 1]
- const options = currentPage.options
-
- if (options.id) {
- source.value = options.source || ''
- productStatus.value = options.status || ''
- loadProductDetail(options.id, options.type)
- }
- })
- const handleAction = (action) => {
- const actions = {
- editProduct,
- removeProduct,
- publishProduct,
- cancelProduct
- }
- actions[action] && actions[action]()
- }
- const getDictLabel = (dictKey, value) => {
- if (!dictData.value || !dictData.value[dictKey]) {
- return ''
- }
- const list = dictData.value[dictKey] || []
- const item = list.find(u => u.dictValue == value)
- return item ? item.dictLabel : ''
- }
- // 加载产品详情
- const loadProductDetail = (id) => {
- uni.showLoading({
- title: '加载中'
- })
-
- getProductInfoById(id).then(res => {
- if (res.data.code === 200) {
- const { data } = res.data
- productInfo.value = data
-
- // 处理图片数据
- if (productInfo.value.imageUrl) {
- try {
- imageList.value = productInfo.value.imageUrl.split(',')
- } catch (e) {
- console.error('解析图片数据失败:', e)
- imageList.value = []
- }
- } else {
- imageList.value = []
- }
- uni.hideLoading()
- } else {
- uni.showToast({
- title: res.data.msg || '获取农品信息失败',
- icon: 'none'
- })
- }
- })
-
- // 判断是否为当前用户发布的产品
- isOwnProduct.value = source.value === 'myPublish'
- }
- // 轮播图切换
- const onSwiperChange = (e) => {
- currentImageIndex.value = e.detail.current
- }
- // 预览图片
- const previewImage = (index) => {
- uni.previewImage({
- current: index,
- urls: imageList.value
- })
- }
- // 编辑产品
- const editProduct = () => {
- if (productInfo.value.type === 1) {
- // 收购信息跳转到收购编辑页面
- uni.navigateTo({
- url: `/pages/service/purchase-publish?action=edit&id=${productInfo.value.id}`
- })
- } else {
- // 销售信息跳转到销售编辑页面
- uni.navigateTo({
- url: `/pages/service/sales-publish?action=edit&id=${productInfo.value.id}&type=${productInfo.value.type}`
- })
- }
- }
- const publishProduct = () => {
- uni.showModal({
- title: '确认发布审核',
- content: `确定要发布这条信息吗?审核通过后将在${productInfo.value.type === 0 ? '销售' : '收购'}页面展示`,
- confirmText: '确认发布',
- cancelText: '取消',
- success: (res) => {
- if (res.confirm) {
- handlePublishProduct()
- }
- }
- })
- }
- // 处理发布操作
- const handlePublishProduct = () => {
- uni.showLoading({ title: '发布中...' })
- const data = {
- id: productInfo.value.id,
- status: 1 // 审核中
- }
- editProductInfo(data).then(res => {
- uni.hideLoading()
- if (res.data.code === 200) {
- uni.showToast({
- title: '发布成功',
- icon: 'success'
- })
- setTimeout(() => {
- uni.navigateBack()
- }, 1000)
- } else {
- uni.showToast({
- title: res.data.msg || '发布失败,请稍后重试',
- icon: 'none'
- })
- }
- })
- }
- // 下架产品
- const removeProduct = () => {
- uni.showModal({
- title: '确认下架',
- content: '确定要下架这条信息吗?下架后其他用户将无法查看。',
- confirmText: '确认下架',
- cancelText: '取消',
- success: (res) => {
- if (res.confirm) {
- handleRemoveProduct()
- }
- }
- })
- }
- // 处理下架操作
- const handleRemoveProduct = () => {
- uni.showLoading({ title: '下架中...' })
- const data = {
- id: productInfo.value.id,
- status: 3 // 下架
- }
- editProductInfo(data).then(res => {
- uni.hideLoading()
- if (res.data.code === 200) {
- uni.showToast({
- title: '下架成功',
- icon: 'success'
- })
- setTimeout(() => {
- uni.navigateBack()
- }, 1500)
- } else {
- uni.showToast({
- title: res.data.msg || '下架失败,请稍后重试',
- icon: 'none'
- })
- }
- })
- }
- // 联系发布者
- const contactPublisher = () => {
- const realPhone = getRealPhoneNumber()
-
- uni.showModal({
- title: '联系发布者',
- content: `确定要拨打 ${realPhone} 吗?`,
- confirmText: '拨打',
- cancelText: '取消',
- success: (res) => {
- if (res.confirm) {
- uni.makePhoneCall({
- phoneNumber: realPhone,
- fail: () => {
- uni.showToast({
- title: '拨号失败',
- icon: 'none'
- })
- }
- })
- }
- }
- })
- }
- // 撤销产品(审核中状态)
- const cancelProduct = () => {
- uni.showModal({
- title: '确认撤销',
- content: '确定要撤销这条发布信息吗?撤销后需要重新提交审核。',
- confirmText: '确认撤销',
- cancelText: '取消',
- success: (res) => {
- if (res.confirm) {
- handleCancelProduct()
- }
- }
- })
- }
- // 处理撤销操作
- const handleCancelProduct = () => {
- uni.showLoading({ title: '撤销中...' })
-
- setTimeout(() => {
- uni.hideLoading()
- uni.showToast({
- title: '撤销成功',
- icon: 'success'
- })
-
- setTimeout(() => {
- uni.navigateBack()
- }, 1500)
- }, 1000)
- }
- // 获取真实电话号码
- const getRealPhoneNumber = () => {
- return '18812341234'
- }
- // 导出 onShow 供 uni-app 使用
- defineExpose({
- onShow
- })
- </script>
- <style lang="scss">
- .detail-container {
- min-height: 100vh;
- background-color: #f5f5f5;
- padding-bottom: 120rpx;
- }
- // 顶部封面图轮播
- .image-section {
- position: relative;
- margin: 20rpx;
- border-radius: 16rpx;
- overflow: hidden;
- background-color: #fff;
- box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
- }
- .image-swiper {
- width: 100%;
- height: 500rpx;
- }
- swiper-item {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 100%;
- height: 100%;
- }
- .cover-image {
- width: 100%;
- height: 100%;
- }
- .custom-dots {
- position: absolute;
- bottom: 20rpx;
- left: 50%;
- transform: translateX(-50%);
- display: flex;
- gap: 12rpx;
- }
- .dot {
- width: 12rpx;
- height: 12rpx;
- border-radius: 6rpx;
- background-color: rgba(255, 255, 255, 0.5);
- transition: all 0.3s ease;
-
- &.active {
- background-color: #fff;
- width: 24rpx;
- }
- }
- // 标题和类型标签
- .title-section {
- margin: 0 20rpx 20rpx;
- background-color: #fff;
- border-radius: 16rpx;
- padding: 30rpx;
- box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
- }
- .title-content {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- gap: 20rpx;
- }
- .product-title {
- flex: 1;
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- line-height: 1.4;
- }
- .type-tag {
- padding: 8rpx 16rpx;
- border-radius: 20rpx;
- font-size: 24rpx;
- font-weight: bold;
- flex-shrink: 0;
-
- &.sale {
- background-color: #e8f5e8;
- color: #4CAF50;
- }
-
- &.purchase {
- background-color: #e6f7ff;
- color: #1890ff;
- }
- }
- // 信息卡片通用样式
- .info-card, .description-card, .publisher-card {
- margin: 0 20rpx 20rpx;
- background-color: #fff;
- border-radius: 16rpx;
- padding: 30rpx;
- box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
- }
- .card-title {
- font-size: 28rpx;
- font-weight: bold;
- color: #333;
- margin-bottom: 24rpx;
- padding-bottom: 16rpx;
- border-bottom: 2rpx solid #f5f5f5;
- }
- // 核心信息展示
- .info-row {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 16rpx 0;
- border-bottom: 1rpx solid #f8f8f8;
-
- &:last-child {
- border-bottom: none;
- }
- }
- .info-label {
- font-size: 28rpx;
- color: #666;
- flex-shrink: 0;
- width: 120rpx;
- }
- .info-value {
- font-size: 28rpx;
- color: #333;
- font-weight: 500;
- text-align: right;
- flex: 1;
-
- &.price {
- color: #ff6b35;
- font-weight: bold;
- font-size: 30rpx;
- }
-
- &.location {
- color: #4CAF50;
- }
-
- &.phone {
- color: #1890ff;
- }
- }
- // 补充说明区域
- .description-content {
- padding: 20rpx;
- background-color: #f8f9fa;
- border-radius: 12rpx;
- border-left: 4rpx solid #4CAF50;
- }
- .description-text {
- font-size: 26rpx;
- color: #666;
- line-height: 1.6;
- }
- // 发布者信息
- .publisher-info {
- .info-row {
- padding: 20rpx 0;
- }
- }
- // 底部操作按钮
- .action-buttons {
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- padding: 20rpx 30rpx;
- padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
- background-color: #fff;
- border-top: 1rpx solid #f0f0f0;
- display: flex;
- gap: 20rpx;
- z-index: 100;
- }
- .action-btn {
- flex: 1;
- height: 80rpx;
- border-radius: 40rpx;
- font-size: 28rpx;
- font-weight: bold;
- border: none;
- transition: all 0.3s ease;
-
- &.edit-btn {
- background-color: #fff;
- color: #4CAF50;
- border: 2rpx solid #4CAF50;
-
- &:active {
- background-color: #f0fdf4;
- }
- }
-
- &.remove-btn {
- background-color: #fff;
- color: #ff4757;
- border: 2rpx solid #ff4757;
-
- &:active {
- background-color: #fff5f5;
- }
- }
-
- &.cancel-btn {
- background-color: #fff;
- color: #fa8c16;
- border: 2rpx solid #fa8c16;
-
- &:active {
- background-color: #fff7e6;
- }
- }
-
- &.contact-btn {
- background-color: #4CAF50;
- color: #fff;
-
- &:active {
- background-color: #45a049;
- }
- }
- }
- // 防止按钮点击状态样式被覆盖
- button[disabled] {
- opacity: 0.6;
- }
- button::after {
- border: none;
- }
- </style>
|