维修,意见反馈页面完善

This commit is contained in:
zjf committed 2025-06-30 19:59:50 +08:00
1 parent bc43f88e52
commit 2b22a30f85
4 files changed
+190 -121

No files matched your search

+4 -4
View File
@@ -17,17 +17,17 @@ VITE_PWD_ENC_KEY='pigxpigxpigxpigx'
VITE_OAUTH2_APP_CLIENT='mini:mini'
# --------------------------- 开发环境 api地址 ----------------------------------
VITE_APP_DEV_SERVICE = https://stgl.pj.gov.cn/api # 域名线上
#VITE_APP_DEV_SERVICE = https://stgl.pj.gov.cn/api # 域名线上
#VITE_APP_DEV_SERVICE = http://59.202.170.152:81/api # 信创线上
# VITE_APP_DEV_SERVICE = http://192.168.101.150:9999 # 邓-本地
# VITE_APP_DEV_SERVICE = http://127.0.0.1:9999 # 邓-本地
VITE_APP_DEV_SERVICE = http://127.0.0.1:9999 # 邓-本地
# VITE_APP_DEV_SERVICE = http://123.157.250.162:8089/api # 测试线上
# --------------------------- 开发环境 图片访问基础地址 ---------------------------
VITE_IMAGE_DEV_PATH = https://stgl.pj.gov.cn/api # 域名线上
#VITE_IMAGE_DEV_PATH = https://stgl.pj.gov.cn/api # 域名线上
#VITE_IMAGE_DEV_PATH = http://59.202.170.152:81/api # 信创线上
# VITE_IMAGE_DEV_PATH = http://192.168.101.150:9999 # 邓-43本地
# VITE_IMAGE_DEV_PATH = http://127.0.0.1:9999
VITE_IMAGE_DEV_PATH = http://127.0.0.1:9999
# VITE_IMAGE_DEV_PATH = http://123.157.250.162:8089/api # 测试线上
# --------------------------- 生产环境 api地址 ----------------------------------
+2
View File
@@ -464,6 +464,7 @@
{
"path": "feedback/index",
"style": {
"enablePullDownRefresh": true,
"navigationBarTitleText": "意见反馈"
}
},
@@ -476,6 +477,7 @@
{
"path": "repair/index",
"style": {
"enablePullDownRefresh": true,
"navigationBarTitleText": "维修上报"
}
},
+75 -25
View File
@@ -72,8 +72,9 @@
</template>
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
import { ref, onMounted, computed, watch, nextTick } from 'vue'
import meetingRoomApi from '@/sheep/api/meetingRoom'
import { onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app'
const typeOptions = ref<{ value: string; label: string }[]>([])
const typeIndex = ref(0)
@@ -82,6 +83,10 @@ const description = ref('')
const contact = ref('')
const feedbackList = ref<any[]>([])
const activeTab = ref(0)
const page = ref(1)
const pageSize = 5
const hasMore = ref(true)
const loading = ref(false)
const canSubmit = computed(() => {
return title.value.trim() && description.value.trim()
@@ -92,7 +97,7 @@ async function loadTypeOptions() {
const res: any = await meetingRoomApi.getFeedbackType()
if (res.data && Array.isArray(res.data.data)) {
typeOptions.value = res.data.data.map(item => ({
value: item.id,
value: item.value,
label: item.label
}))
}
@@ -120,24 +125,16 @@ function getTypeClass(type: string) {
return classMap[type] || 'type-other'
}
function getStatusText(status: string) {
const statusMap: Record<string, string> = {
'1': '待处理',
'2': '处理中',
'3': '已处理',
'4': '已关闭'
}
return statusMap[status] || '未知'
function getStatusText(status: string | number) {
if (status === 1 || status === '1') return '已处理'
// 只要不是1都显示未处理
return '未处理'
}
function getStatusClass(status: string) {
const classMap: Record<string, string> = {
'1': 'status-pending',
'2': 'status-processing',
'3': 'status-completed',
'4': 'status-closed'
}
return classMap[status] || 'status-pending'
function getStatusClass(status: string | number) {
if (status === 1 || status === '1') return 'status-completed'
// 只要不是1都用未处理样式
return 'status-pending'
}
function formatTime(time: string) {
@@ -185,23 +182,76 @@ function viewDetail(item: any) {
})
}
async function loadFeedbackList() {
async function loadFeedbackList(isLoadMore = false, autoFill = false) {
if (loading.value || (!hasMore.value && isLoadMore)) return
loading.value = true
try {
const response: any = await meetingRoomApi.getFeedbackList({
current: 1,
size: 20
current: page.value,
size: pageSize
})
if (response.code === 0 && response.data) {
feedbackList.value = response.data.records || []
const records = response.data.records || []
if (isLoadMore) {
feedbackList.value = feedbackList.value.concat(records)
} else {
feedbackList.value = records
}
hasMore.value = records.length === pageSize
if (hasMore.value) page.value += 1
}
} finally {
loading.value = false
// H5端自动补齐:只有 autoFill=true 时才自动补齐
if (autoFill) {
await nextTick()
if (hasMore.value) {
const listDom = document.querySelector('.feedback-list')
if (listDom && listDom.scrollHeight <= window.innerHeight) {
await loadFeedbackList(true, true)
}
}
}
} catch (error) {
console.error('加载反馈列表失败:', error)
}
}
function refreshList() {
page.value = 1
hasMore.value = true
loadFeedbackList(false, true)
}
// 监听页面触底事件,下拉加载更多
onReachBottom(() => {
if (activeTab.value === 1) {
loadFeedbackList(true, false)
}
})
// 切换tab时重置分页并刷新
watch(activeTab, (val) => {
if (val === 1) {
refreshList()
}
})
onPullDownRefresh(() => {
if (activeTab.value === 1) {
page.value = 1
hasMore.value = true
loadFeedbackList(false, true).then(() => {
uni.stopPullDownRefresh()
})
} else {
uni.stopPullDownRefresh()
}
})
onMounted(() => {
loadTypeOptions().then(() => {
loadFeedbackList()
if (activeTab.value === 1) {
refreshList()
}
})
})
</script>
+109 -92
View File
@@ -30,10 +30,14 @@
</view>
<view class="form-item">
<view class="label">图片</view>
<view class="image-upload">
<image v-if="picUrl" :src="picUrl" class="feedback-img" mode="aspectFill" @click="previewImage" />
<view v-else class="upload-btn" @click="chooseImage">上传图片</view>
</view>
<tm-upload-photo
v-model="uploadFileUrl"
:url="'/api/admin/sys-file/upload'"
:maxCount="5"
:maxFileSize="1024 * 1024"
:beforeComplete="beforeComplete"
:header="header"
/>
</view>
<view class="form-item">
<view class="label">故障描述</view>
@@ -93,8 +97,11 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { ref, computed, onMounted, watch, nextTick } from 'vue'
import { onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app'
import meetingRoomApi from '@/sheep/api/meetingRoom'
import { hooks } from '@@/index'
import { filePath } from '@/sheep/utils/file'
const typeOptions = [
{ value: 1, label: '电气设备' },
@@ -116,9 +123,15 @@ const title = ref('')
const location = ref('')
const description = ref('')
const dateFound = ref('')
const picUrl = ref('')
const uploadFileUrl = ref<any[]>([])
const repairList = ref<any[]>([])
const activeTab = ref(0)
const page = ref(1)
const pageSize = 5
const hasMore = ref(true)
const loading = ref(false)
const repairForm = ref<any>(null)
const header = ref({})
const canSubmit = computed(() => {
return title.value.trim() && location.value.trim() && description.value.trim() && dateFound.value
@@ -136,54 +149,9 @@ function onDateChange(e: any) {
dateFound.value = e.detail.value
}
function chooseImage() {
uni.chooseImage({
count: 1,
success: (res) => {
if (res.tempFilePaths && res.tempFilePaths.length > 0) {
picUrl.value = res.tempFilePaths[0]
}
}
})
}
function previewImage() {
if (picUrl.value) {
uni.previewImage({
urls: [picUrl.value]
})
}
}
async function uploadImageIfNeeded() {
if (!picUrl.value || picUrl.value.startsWith('http')) {
return picUrl.value
}
return new Promise<string>((resolve, reject) => {
uni.uploadFile({
url: '/file/upload',
filePath: picUrl.value,
name: 'file',
success: (res) => {
try {
const data = JSON.parse(res.data)
if (data.code === 0 && data.data && data.data.url) {
resolve(data.data.url)
} else {
uni.showToast({ title: '图片上传失败', icon: 'none' })
reject()
}
} catch {
uni.showToast({ title: '图片上传失败', icon: 'none' })
reject()
}
},
fail: () => {
uni.showToast({ title: '图片上传失败', icon: 'none' })
reject()
}
})
})
function beforeComplete(uploadFile: any) {
const res = JSON.parse(uploadFile.data)
return res.code == 0
}
function getTypeLabel(type: number) {
@@ -202,24 +170,16 @@ function getTypeClass(type: number) {
return classMap[type] || 'type-other'
}
function getStatusText(status: string) {
const statusMap: Record<string, string> = {
'1': '待处理',
'2': '处理中',
'3': '已完成',
'4': '已取消'
}
return statusMap[status] || '未知'
function getStatusText(status: string | number) {
if (status === 1 || status === '1') return '已处理'
// 只要不是1都显示未处理
return '未处理'
}
function getStatusClass(status: string) {
const classMap: Record<string, string> = {
'1': 'status-pending',
'2': 'status-processing',
'3': 'status-completed',
'4': 'status-cancelled'
}
return classMap[status] || 'status-pending'
function getStatusClass(status: string | number) {
if (status === 1 || status === '1') return 'status-completed'
// 只要不是1都用未处理样式
return 'status-pending'
}
function formatTime(time: string) {
@@ -232,41 +192,43 @@ async function submitRepair() {
uni.showToast({ title: '请填写完整信息', icon: 'none' })
return
}
// 收集所有上传成功图片的 url
let picUrl: string[] = []
if (uploadFileUrl.value.length > 0) {
uploadFileUrl.value.forEach(item => {
if (item.response) {
try {
const res = JSON.parse(item.response)
if (res.code === 0 && res.data && res.data.url) {
picUrl.push(res.data.url)
}
} catch {}
}
})
}
try {
uni.showLoading({ title: '提交中...' })
let uploadedPicUrl = picUrl.value
if (picUrl.value && !picUrl.value.startsWith('http')) {
uploadedPicUrl = await uploadImageIfNeeded()
}
const data = {
title: title.value.trim(),
picUrl: uploadedPicUrl,
picUrl: picUrl.join(','),
description: description.value.trim(),
dateFound: dateFound.value,
location: location.value.trim(),
urgency: String(urgencyOptions[urgencyIndex.value].value),
maintainType: typeOptions[typeIndex.value].value
}
const response: any = await meetingRoomApi.submitRepair(data)
uni.hideLoading()
if (response.code === 0) {
uni.showToast({ title: '提交成功', icon: 'success' })
// 清空表单
title.value = ''
location.value = ''
description.value = ''
dateFound.value = ''
picUrl.value = ''
uploadFileUrl.value = []
typeIndex.value = 0
urgencyIndex.value = 0
// 刷新列表
loadRepairList()
} else {
@@ -284,23 +246,78 @@ function viewDetail(item: any) {
})
}
async function loadRepairList() {
async function loadRepairList(isLoadMore = false, autoFill = false) {
if (loading.value || (!hasMore.value && isLoadMore)) return
loading.value = true
let requestSuccess = false
try {
const response: any = await meetingRoomApi.getRepairList({
current: 1,
size: 20
current: page.value,
size: pageSize
})
if (response.code === 0 && response.data) {
repairList.value = response.data.records || []
const records = response.data.records || []
if (isLoadMore) {
repairList.value = repairList.value.concat(records)
} else {
repairList.value = records
}
hasMore.value = records.length === pageSize
if (hasMore.value) page.value += 1
requestSuccess = true
}
} catch (e) {
hasMore.value = false // 网络/接口异常,阻止递归
} finally {
loading.value = false
// 只有请求成功时才自动补齐
if (autoFill && requestSuccess) {
await nextTick()
if (hasMore.value) {
const listDom = document.querySelector('.repair-list')
if (listDom && listDom.scrollHeight <= window.innerHeight) {
await loadRepairList(true, true)
}
}
}
} catch (error) {
console.error('加载维修记录失败:', error)
}
}
function refreshRepairList() {
page.value = 1
hasMore.value = true
loadRepairList(false, true)
}
onReachBottom(() => {
if (activeTab.value === 1) {
loadRepairList(true, false)
}
})
onPullDownRefresh(() => {
if (activeTab.value === 1) {
page.value = 1
hasMore.value = true
loadRepairList(false, true).then(() => {
uni.stopPullDownRefresh()
})
} else {
uni.stopPullDownRefresh()
}
})
watch(activeTab, (val) => {
if (val === 1) {
refreshRepairList()
}
})
onMounted(() => {
loadRepairList()
header.value = hooks.useDefaultHeader()
if (activeTab.value === 1) {
refreshRepairList()
}
})
</script>