维修,意见反馈页面增加图片上传

This commit is contained in:
zjf committed 2025-07-01 11:16:49 +08:00
1 parent 2b22a30f85
commit 4d46759694
3 files changed
+135 -6

No files matched your search

+31 -1
View File
@@ -6,6 +6,15 @@
</view>
<view class="detail-content">
<view class="content-text">{{ detail.description }}</view>
<view v-if="imageList.length" class="image-list">
<image
v-for="(img, idx) in imageList"
:key="idx"
:src="img.startsWith('http') ? img : filePath(img)"
class="feedback-img"
mode="aspectFill"
/>
</view>
</view>
<view class="detail-footer">
<text class="create-time">提交时间:{{ formatTime(detail.createTime) }}</text>
@@ -14,9 +23,10 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ref, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import meetingRoomApi from '@/sheep/api/meetingRoom'
import { filePath } from '@/sheep/utils/file'
const detail = ref<any>({})
const typeOptions = ref<{ value: string; label: string }[]>([])
@@ -72,6 +82,12 @@ function formatTime(time: string) {
return new Date(time).toLocaleString()
}
// 计算图片数组
const imageList = computed(() => {
if (!detail.value.picUrl) return []
return detail.value.picUrl.split(',').filter(Boolean)
})
onLoad(async (options: any) => {
await loadTypeOptions()
const id = options.id
@@ -214,4 +230,18 @@ onLoad(async (options: any) => {
color: #999;
}
}
.image-list {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
margin-top: 16rpx;
}
.feedback-img {
width: 180rpx;
height: 180rpx;
border-radius: 8rpx;
background: #f7f8fa;
object-fit: cover;
}
</style>
+73 -4
View File
@@ -32,6 +32,19 @@
<view class="label">联系方式</view>
<input v-model="contact" placeholder="手机号或邮箱(选填)" class="contact-input" />
</view>
<view class="form-item">
<view class="label">图片上传</view>
<tm-upload-photo
v-model="uploadList"
:maxCount="6"
url="/api/admin/sys-file/upload"
:header="uploadHeader"
:show-upload-list="true"
:width="180"
:height="180"
imgKey="url"
/>
</view>
<button @click="submitFeedback" class="submit-btn" :disabled="!canSubmit">
提交反馈
</button>
@@ -41,7 +54,10 @@
<!-- 我的反馈列表 -->
<view class="feedback-list">
<view class="list-title">我的反馈</view>
<view v-if="feedbackList.length === 0" class="empty-tip">
<view v-if="error" class="error-tip">
加载失败,请 <text class="retry-btn" @click="refreshList">重试</text>
</view>
<view v-else-if="feedbackList.length === 0" class="empty-tip">
暂无反馈记录
</view>
<view v-else>
@@ -58,7 +74,15 @@
<view class="item-content">
<view class="item-title">{{ item.title }}</view>
<view class="item-desc">{{ item.description }}</view>
<image v-if="item.picUrl" :src="item.picUrl" class="item-img" mode="aspectFill" />
<view v-if="item.picUrl" class="image-list">
<image
v-for="(img, idx) in item.picUrl.split(',').filter(Boolean)"
:key="idx"
:src="filePath(img)"
class="item-img"
mode="aspectFill"
/>
</view>
</view>
<view class="item-footer">
<text class="time">{{ formatTime(item.createTime) }}</text>
@@ -75,6 +99,8 @@
import { ref, onMounted, computed, watch, nextTick } from 'vue'
import meetingRoomApi from '@/sheep/api/meetingRoom'
import { onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app'
import { filePath } from '@/sheep/utils/file'
import { useDefaultHeader } from '@/sheep/hooks/use-token'
const typeOptions = ref<{ value: string; label: string }[]>([])
const typeIndex = ref(0)
@@ -87,6 +113,9 @@ const page = ref(1)
const pageSize = 5
const hasMore = ref(true)
const loading = ref(false)
const error = ref(false)
const uploadList = ref<any[]>([])
const uploadHeader = ref({})
const canSubmit = computed(() => {
return title.value.trim() && description.value.trim()
@@ -150,11 +179,23 @@ async function submitFeedback() {
try {
uni.showLoading({ title: '提交中...' })
let picUrlArr: any[] = []
uploadList.value.forEach(item => {
if (item.response) {
try {
const res = JSON.parse(item.response)
if (res.code === 0 && res.data && res.data.url) {
picUrlArr.push(res.data.url)
}
} catch {}
}
})
const data = {
title: title.value.trim(),
type: typeOptions.value[typeIndex.value].value,
description: description.value.trim(),
contact: contact.value.trim()
contact: contact.value.trim(),
picUrl: picUrlArr.join(',')
}
const response: any = await meetingRoomApi.submitFeedback(data)
uni.hideLoading()
@@ -165,6 +206,7 @@ async function submitFeedback() {
description.value = ''
contact.value = ''
typeIndex.value = 0
uploadList.value = []
// 刷新列表
loadFeedbackList()
} else {
@@ -185,6 +227,7 @@ function viewDetail(item: any) {
async function loadFeedbackList(isLoadMore = false, autoFill = false) {
if (loading.value || (!hasMore.value && isLoadMore)) return
loading.value = true
error.value = false
try {
const response: any = await meetingRoomApi.getFeedbackList({
current: page.value,
@@ -199,7 +242,15 @@ async function loadFeedbackList(isLoadMore = false, autoFill = false) {
}
hasMore.value = records.length === pageSize
if (hasMore.value) page.value += 1
} else {
error.value = true
hasMore.value = false
uni.showToast({ title: response.msg || '加载失败', icon: 'none' })
}
} catch (e) {
error.value = true
hasMore.value = false
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
loading.value = false
// H5端自动补齐:只有 autoFill=true 时才自动补齐
@@ -248,6 +299,7 @@ onPullDownRefresh(() => {
})
onMounted(() => {
uploadHeader.value = useDefaultHeader()
loadTypeOptions().then(() => {
if (activeTab.value === 1) {
refreshList()
@@ -365,6 +417,17 @@ onMounted(() => {
font-weight: bold;
margin-bottom: 24rpx;
}
.error-tip {
text-align: center;
color: #f56c6c;
font-size: 28rpx;
padding: 60rpx 0;
}
.retry-btn {
color: #007aff;
text-decoration: underline;
cursor: pointer;
}
.empty-tip {
text-align: center;
color: #999;
@@ -446,12 +509,18 @@ onMounted(() => {
-webkit-line-clamp: 2;
overflow: hidden;
}
.image-list {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
margin-top: 8rpx;
}
.item-img {
width: 120rpx;
height: 120rpx;
border-radius: 8rpx;
margin-top: 8rpx;
background: #f7f8fa;
object-fit: cover;
}
}
.item-footer {
+31 -1
View File
@@ -25,6 +25,15 @@
<text class="label">故障描述:</text>
<text class="description">{{ detail.description }}</text>
</view>
<view v-if="imageList.length" class="image-list">
<image
v-for="(img, idx) in imageList"
:key="idx"
:src="filePath(img)"
class="repair-img"
mode="aspectFill"
/>
</view>
</view>
<view v-if="detail.repairResult" class="result-section">
@@ -40,9 +49,10 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ref, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import meetingRoomApi from '@/sheep/api/meetingRoom'
import { filePath } from "@/sheep/utils/file"
const detail = ref<any>({})
@@ -95,6 +105,12 @@ function formatTime(time: string) {
return new Date(time).toLocaleString()
}
// 计算图片数组
const imageList = computed(() => {
if (!detail.value.picUrl) return []
return detail.value.picUrl.split(',').filter(Boolean)
})
onLoad(async (options: any) => {
const id = options.id
if (!id) return
@@ -249,4 +265,18 @@ onLoad(async (options: any) => {
color: #999;
}
}
.image-list {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
margin-top: 16rpx;
}
.repair-img {
width: 180rpx;
height: 180rpx;
border-radius: 8rpx;
background: #f7f8fa;
object-fit: cover;
}
</style>