对接在线报修接口

This commit is contained in:
zhouyanli
2026-04-29 17:39:55 +08:00
parent 46c9f6dacc
commit d183cb00c0
8 changed files with 356 additions and 143 deletions

View File

@@ -96,8 +96,29 @@ export const addActivityLive = (id, data) =>{
export const signinActivityLive = (id, data) =>{
return post(`/api/resident/activity/${id}/signin`, data)
}
// ==============在线报修========
// 添加报修工单
export const addQueryRepair = (data) =>{
return post("/repairOrder/addRepair",data)
}
// 获取公共维修项目列表
export const getRepairProjectList = (data) =>{
return get("/repairOrder/list",data)
}
// 获取报修列表
export const getQueryRepair = (data) =>{
return get("/repairOrder/queryRepair",data)
}
// 获取房屋列表
export const getHouseList = (data) =>{
return get('/api/resident/my/house/list',data)
}
// 通用文件上传
export const uploadImage = () => {
return upload('');
}
// 上传单张图片(请根据后端实际地址修改)
export const uploadFile = (filePath) => {
return upload(filePath, '/common/upload');
}

View File

@@ -143,6 +143,7 @@ const handleLogin = () => {
// 存当前绑定的小区ID0 表示未绑定
const currentVillageId = res.data.currentVillageId || 0;
uni.setStorageSync('currentVillageId', currentVillageId);
uni.setStorageSync('userId',res.data.userId)
}
uni.hideLoading();
uni.showToast({ title: '登录成功', icon: 'success' });

View File

@@ -66,88 +66,103 @@
<view class="repair-item" v-for="(item, index) in repairList" :key="index">
<!-- 标题和状态 -->
<view class="item-header">
<text class="item-title">标题标题标题</text>
<text class="item-title">{{ item.title || '报修' }}</text>
<text class="item-status" :class="item.statusClass">{{ item.status }}</text>
</view>
<!-- 标签 -->
<view class="item-tags">
<text class="tag">公共报修</text>
<text class="tag">路灯</text>
<view class="item-tags" v-if="item.repairTypeName || item.category">
<text class="tag" v-if="item.repairTypeName">{{ item.repairTypeName }}</text>
<text class="tag" v-if="item.category">{{ item.category }}</text>
</view>
<!-- 内容 -->
<view class="item-content">
{{ item.content }}
{{ item.content || item.description || '' }}
</view>
<!-- 图片占位 -->
<view class="item-imgs">
<view class="img-placeholder" v-for="(i,index) in item.imageList" :key="index">
<!-- <uni-icons type="image" size="20" color="#ccc"></uni-icons> -->
<image :src="i.img" style="width: 100%;height: 100%;"></image>
<view class="item-imgs" v-if="item.imageList && item.imageList.length">
<view class="img-placeholder" v-for="(img, idx) in item.imageList" :key="idx">
<image :src="typeof img === 'string' ? img : img.img" style="width: 100%;height: 100%;"></image>
</view>
</view>
<!-- 时间和详情 -->
<view class="item-footer">
<text class="item-time">{{ item.time }}</text>
<text class="item-time">{{ item.time || item.createTime || '' }}</text>
<text class="detail-btn" @click="goDetail(item)">报修详情</text>
</view>
</view>
<!-- 空状态 -->
<view v-if="repairList.length === 0" class="empty-state">
<uni-icons type="info" size="30" color="#ccc"></uni-icons>
<text class="empty-text">暂无数据</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue';
import { ref, watch } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { getQueryRepair } from '../api/api.js';
// 报修类型public:公共报修personal:个人报修)
const activeType = ref('public');
// 报修状态pending:待派单assigned:已派单completed:已完成)
const activeStatus = ref('pending');
// 模拟报修列表数据根据activeStatus过滤
const repairList = computed(() => {
let statusText = ""
let statusClass = ""
if(activeStatus.value === 'pending'){
statusText = '待派单',
statusClass = 'pending'
} else if(activeStatus.value === 'assigned'){
statusText = '已派单',
statusClass = 'assigned'
}else{
statusText = '已完成',
statusClass = 'completed'
const repairList = ref([]);
const loading = ref(false);
// 状态映射
const statusMap = {
pending: { text: '待派单', class: 'pending', value: '0' },
assigned: { text: '已派单', class: 'assigned', value: '1' },
completed: { text: '已完成', class: 'completed', value: '2' }
};
// 获取报修列表
const fetchRepairList = async () => {
const villageId = uni.getStorageSync('currentVillageId');
if (!villageId || villageId === '0') {
uni.showToast({ title: '请先选择小区', icon: 'none' });
return;
}
// 原始数据
const mockData = [
{
status: statusText,
statusClass: statusClass,
content: '1栋楼下道路路灯不亮并且有的亮度不够请物业公司及时更换防止发生意外事故。',
time: '2023-08-01 10:05:46',
imageList:[
{img:'http://47.104.199.163:9090/images/repair/house1.png'},
{img:'http://47.104.199.163:9090/images/repair/house2.png'},
{img:'http://47.104.199.163:9090/images/repair/house3.png'},
]
},
{
status: statusText,
statusClass: statusClass,
content: '西门的门禁不好用了,草坪有好多的草,话题也应高擦了',
time: '2025-08-01 10:05:46',
imageList:[
{img:'http://47.104.199.163:9090/images/repair/house1.png'},
{img:'http://47.104.199.163:9090/images/repair/house2.png'},
{img:'http://47.104.199.163:9090/images/repair/house3.png'},
]
loading.value = true;
try {
const statusInfo = statusMap[activeStatus.value];
const params = {
villageId,
// 报修类型0-公共报修1-个人报修(按后端实际字段调整)
projectType: activeType.value === 'public' ? '0' : '1',
// 状态0-待派单1-已派单2-已完成(按后端实际字段调整)
problemStatus: statusInfo.value
};
const res = await getQueryRepair(params);
if (res.code === 200) {
// 按后端实际返回结构调整
const list = res.data|| [];
repairList.value = list.map(item => ({
...item,
status: statusInfo.text,
statusClass: statusInfo.class
}));
} else {
uni.showToast({ title: res.msg || '获取失败', icon: 'none' });
}
];
return mockData;
} catch (e) {
uni.showToast({ title: '网络异常', icon: 'none' });
} finally {
loading.value = false;
}
};
// 监听状态变化自动刷新
watch(activeStatus, () => {
fetchRepairList();
});
function publicClick(){
@@ -183,6 +198,10 @@ const goDetail = (item) => {
url: `/pageSubPack/online-repair/repairDetail?item = ${itemStr}`
});
};
onLoad(() => {
fetchRepairList();
});
</script>
<style scoped>
@@ -391,6 +410,20 @@ const goDetail = (item) => {
justify-content: center;
margin-right: 8px;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
}
.empty-text {
font-size: 32rpx;
color: #999;
margin-top: 20rpx;
margin-bottom: 10rpx;
}
/* 底部时间和详情 */
.item-footer {

View File

@@ -5,7 +5,7 @@
<text class="label">报修房屋</text>
<view class="value" @click="goToSelectHouse">
{{ houseName || '请选择房屋' }}
<text class="switch" v-if="houseName">切换</text>
<!-- <text class="switch" v-if="houseName">切换</text> -->
<uni-icons type="arrowright" size="16"></uni-icons>
</view>
</view>
@@ -148,10 +148,12 @@ import { ref,computed,onMounted} from 'vue'
import {
onLoad, onUnload
} from '@dcloudio/uni-app'
import { addQueryRepair, uploadFile } from '../api/api.js'
import moment from 'moment/moment'
// 选中的房屋/项目名称
const houseName = ref('')
const houseId = ref('')
const projectName = ref('')
// 表单数据
@@ -159,7 +161,7 @@ const form = ref({
title: '',
desc: '',
phone: '',
datetime: '2023-08-01 15:30', // 默认时间(匹配截图)
datetime: '', // 默认时间
images: []
})
@@ -167,7 +169,7 @@ const form = ref({
const timePopupRef = ref(null)
// 初始时间()
const selectedTime = ref(moment().hour(9).minute(30).second(0));
// 选择的时间(弹窗中预览)
// 选择的时间
const tempTime = ref(moment().hour(9).minute(30).second(0));
// ========== 时间选择列数据 ==========
@@ -240,6 +242,8 @@ const confirmTime = () => {
// 拼接选中的时间
const selectedDateTime = `${selectedDate.value} ${selectedHour.value}:${selectedMinute.value}`;
selectedTime.value = moment(selectedDateTime, 'YYYY-MM-DD HH:mm');
// 给表单赋值
form.value.datetime = selectedTime.value.format('YYYY-MM-DD HH:mm')
// 关闭弹窗
closeTimePopup();
@@ -332,6 +336,7 @@ onLoad(() => {
// 监听选择房屋事件
uni.$on('selectHouse', (data) => {
houseName.value = data.name
houseId.value = data.id
})
// 监听选择维修项目事件
uni.$on('selectProject', (data) => {
@@ -348,7 +353,7 @@ onUnload(() => {
// 跳转到选择房屋页
const goToSelectHouse = () => {
uni.navigateTo({
url: '/pageSubPack/online-repair/selectHouse'
url: `/pageSubPack/online-repair/selectHouse?houseId=${houseId.value}`
})
}
@@ -398,8 +403,26 @@ const deleteImage = (index) => {
form.value.images.splice(index, 1)
}
// 上传图片到服务器
const uploadImages = async () => {
const uploadedUrls = []
for (const path of form.value.images) {
if (path.startsWith('http')) {
uploadedUrls.push(path)
continue
}
try {
const res = await uploadFile(path)
uploadedUrls.push(res.data || res.msg || '')
} catch (e) {
console.error('图片上传失败', e)
}
}
return uploadedUrls
}
// 表单提交
const submitForm = () => {
const submitForm = async () => {
// 校验
if (!houseName.value) {
uni.showToast({ title: '请选择报修房屋', icon: 'none' })
@@ -426,16 +449,46 @@ const submitForm = () => {
return
}
// 提交逻辑(替换为你的接口)
const villageId = uni.getStorageSync('currentVillageId')
if (!villageId || villageId === '0') {
uni.showToast({ title: '请先选择小区', icon: 'none' })
return
}
uni.showLoading({ title: '提交中...' })
setTimeout(() => {
uni.hideLoading()
try {
const imageUrls = await uploadImages()
const userId = uni.getStorageSync('userId')
const params = {
villageId,
houseId: houseId.value,
maintenanceItemId: projectId.value,
title: form.value.title,
problem: form.value.desc,
residentId: userId,
orderDate: form.value.datetime,
phone: form.value.phone,
problemImageUrl: imageUrls.join(','),
projectType: '1',
problemStatus: ''
}
const res = await addQueryRepair(params)
if (res.code === 200) {
uni.showToast({ title: '提交成功', icon: 'success' })
// 重置表单
// form.value = { title: '', desc: '', phone: '', datetime: '', images: [] }
// houseName.value = ''
// projectName.value = ''
}, 1000)
form.value = { title: '', desc: '', phone: '', datetime: '', images: [] }
houseName.value = ''
projectName.value = ''
uni.navigateBack({ delta: 1 })
} else {
uni.showToast({ title: res.msg || '提交失败', icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '网络异常', icon: 'none' })
} finally {
uni.hideLoading()
}
}
</script>

View File

@@ -17,7 +17,7 @@
v-for="item in categoryList"
:key="item.id"
>
{{ item.name }}
{{ item.projectName }}
</view>
</scroll-view>
@@ -30,7 +30,7 @@
v-for="item in currentProjectList"
:key="item.id"
>
{{ item.name }}
{{ item.projectName }}
</view>
</scroll-view>
</view>
@@ -42,39 +42,50 @@
<script setup>
import { ref, computed } from 'vue'
// import { uniShowToast, uniNavigateBack } from '@dcloudio/uni-app'
import { onLoad } from '@dcloudio/uni-app'
import { getRepairProjectList } from '../api/api.js'
// 分类列表(匹配截图:家具/电路/水暖/门频/电器)
const categoryList = ref([
{ id: 1, name: '家具' },
{ id: 2, name: '电路' },
{ id: 3, name: '水暖' },
{ id: 4, name: '门频' },
{ id: 5, name: '电器' }
])
// 分类列表
const categoryList = ref([])
// 项目列表(匹配截图:床/沙发/柜子/椅子等)
const projectList = ref([
{ id: 101, categoryId: 1, name: '床' },
{ id: 102, categoryId: 1, name: '沙发' },
{ id: 103, categoryId: 1, name: '柜子' },
{ id: 104, categoryId: 1, name: '椅子' },
{ id: 201, categoryId: 2, name: '插座' },
{ id: 202, categoryId: 2, name: '开关' },
{ id: 301, categoryId: 3, name: '水龙头' },
{ id: 302, categoryId: 3, name: '水管' }
])
// 项目列表
const projectList = ref([])
// 选中状态
const activeCategory = ref(1) // 默认选中家具
const activeCategory = ref(1)
const selectedProject = ref({}) // 选中的项目
const searchKey = ref('')
// 从接口获取个人报修项目列表
const fetchProjectList = async () => {
try {
const res = await getRepairProjectList({ projectType: '1' })
if (res.code === 200) {
const data = res.data || []
categoryList.value = data.map(item => ({ id: item.id, projectName: item.projectName }))
projectList.value = data.flatMap(item =>
(item.children || []).map(child => ({
id: child.id,
categoryId: item.id,
projectName: child.projectName
}))
)
activeCategory.value = categoryList.value[0]?.id || 1
}
} catch (e) {
uni.showToast({ title: '获取项目列表失败', icon: 'none' })
}
}
onLoad(() => {
fetchProjectList()
})
// 筛选当前分类的项目
const currentProjectList = computed(() => {
let list = projectList.value.filter(item => item.categoryId === activeCategory.value)
if (searchKey.value) {
list = list.filter(item => item.name.includes(searchKey.value))
list = list.filter(item => item.projectName.includes(searchKey.value))
}
return list
})
@@ -98,10 +109,10 @@ const confirmSelect = () => {
}
// 获取分类名称
const categoryName = categoryList.value.find(c => c.id === activeCategory.value).name
const categoryName = categoryList.value.find(c => c.id === activeCategory.value).projectName
// 传递给表单页
uni.$emit('selectProject', {
name: `${categoryName}-${selectedProject.value.name}`
name: `${categoryName}-${selectedProject.value.projectName}`
})
uni.navigateBack({ delta: 1 })

View File

@@ -57,10 +57,11 @@
<script setup>
import { ref } from 'vue'
import{onLoad} from "@dcloudio/uni-app"
// import { onLoad, uniShowToast, uniNavigateBack, uniChooseImage, uniUploadFile } from '@dcloudio/uni-app'
import { addQueryRepair, uploadFile } from '../api/api.js'
// 接收上个页面传的维修项目
const repairProject = ref('')
const projectId = ref('')
// 表单数据
const form = ref({
@@ -75,6 +76,9 @@ onLoad((options) => {
if (options.category && options.project) {
repairProject.value = `${options.category}-${options.project}`
}
if (options.projectId) {
projectId.value = options.projectId
}
})
// 返回选择项目页
@@ -98,17 +102,6 @@ const chooseImage = () => {
const tempFilePaths = res.tempFilePaths
form.value.images = [...form.value.images, ...tempFilePaths]
// 【可选】如果需要上传到服务器,取消下面注释
// tempFilePaths.forEach(path => {
// uni.uploadFile({
// url: '你的上传接口地址',
// filePath: path,
// name: 'file',
// success: (uploadRes) => {
// console.log('上传成功', uploadRes)
// }
// })
// })
}
})
}
@@ -118,8 +111,27 @@ const deleteImage = (index) => {
form.value.images.splice(index, 1)
}
// 上传图片到服务器
const uploadImages = async () => {
const uploadedUrls = []
for (const path of form.value.images) {
if (path.startsWith('http')) {
uploadedUrls.push(path)
continue
}
try {
const res = await uploadFile(path)
// 根据后端实际返回结构调整字段名
uploadedUrls.push(res.data || res.msg || '')
} catch (e) {
console.error('图片上传失败', e)
}
}
return uploadedUrls
}
// 表单提交
const submitForm = () => {
const submitForm = async () => {
// 表单校验
if (!repairProject.value) {
uni.showToast({ title: '请选择维修项目', icon: 'none' })
@@ -138,19 +150,49 @@ const submitForm = () => {
return
}
// 提交数据(替换成你的接口)
const villageId = uni.getStorageSync('currentVillageId')
if (!villageId || villageId === '0') {
uni.showToast({ title: '请先选择小区', icon: 'none' })
return
}
uni.showLoading({ title: '提交中...' })
// 模拟接口请求
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '提交成功', icon: 'success' })
try {
// 先上传图片
const imageUrls = await uploadImages()
const userId = uni.getStorageSync('userId')
// 提交成功后重置表单/返回上一页
const params = {
villageId,
maintenanceItemId:projectId.value,
title: form.value.title,
problem: form.value.desc,
residentId:userId,//人员id
// repairTypeName: repairProject.value,
phone: form.value.phone,
problemImageUrl: imageUrls.join(','),
projectType: '0',
problemStatus:''
}
const res = await addQueryRepair(params)
if (res.code === 200) {
uni.showToast({ title: '提交成功', icon: 'success' })
form.value = { title: '', desc: '', phone: '', images: [] }
// 或返回上一页
uni.navigateBack({ delta: 3 })
}, 1000)
repairProject.value = ''
// uni.navigateBack({ delta: 2 })
uni.navigateTo({
url:'/pageSubPack/online-repair/onlineRepair'
})
} else {
uni.showToast({ title: res.msg || '提交失败', icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '网络异常', icon: 'none' })
} finally {
uni.hideLoading()
}
}
</script>

View File

@@ -17,7 +17,7 @@
v-for="item in categoryList"
:key="item.id"
>
{{ item.name }}
{{ item.projectName }}
</view>
</scroll-view>
@@ -29,7 +29,7 @@
v-for="item in currentProjectList"
:key="item.id"
>
{{ item.name }}
{{ item.projectName }}
</view>
</scroll-view>
</view>
@@ -38,24 +38,43 @@
<script setup>
import { ref, computed } from 'vue'
// import { uniNavigateTo } from '@dcloudio/uni-app'
import { onLoad } from '@dcloudio/uni-app'
import { getRepairProjectList } from '../api/api.js'
// 分类列表
const categoryList = ref([
{ id: 1, name: '基础设施' },
{ id: 2, name: '电子设施' }
])
const categoryList = ref([])
// 所有项目数据
const projectList = ref([
{ id: 101, categoryId: 1, name: '路灯' },
{ id: 102, categoryId: 1, name: '楼层指示灯' },
{ id: 103, categoryId: 2, name: '应急出口灯' },
{ id: 104, categoryId: 1, name: '草坪灯' }
])
const projectList = ref([])
// 选中的分类
const activeCategory = ref(1)
// 从接口获取维修项目列表
const fetchProjectList = async () => {
try {
const res = await getRepairProjectList({ projectType: '0' })
if (res.code === 200) {
const data = res.data || []
// 兼容后端嵌套格式 [{id, name, children: [{id, name}]}]
categoryList.value = data.map(item => ({ id: item.id, projectName: item.projectName }))
projectList.value = data.flatMap(item =>
(item.children || []).map(child => ({
id: child.id,
categoryId: item.id,
projectName: child.projectName
}))
)
activeCategory.value = categoryList.value[0]?.id || 1
}
} catch (e) {
uni.showToast({ title: '获取项目列表失败', icon: 'none' })
}
}
onLoad(() => {
fetchProjectList()
})
// 搜索关键词
const searchKey = ref('')
@@ -63,7 +82,7 @@ const searchKey = ref('')
const currentProjectList = computed(() => {
let list = projectList.value.filter(item => item.categoryId === activeCategory.value)
if (searchKey.value) {
list = list.filter(item => item.name.includes(searchKey.value))
list = list.filter(item => item.projectName.includes(searchKey.value))
}
return list
})
@@ -76,10 +95,10 @@ const selectCategory = (item) => {
// 选择项目并跳转到维修项目填写页
const selectProject = (item) => {
// 获取分类名称
const categoryName = categoryList.value.find(c => c.id === item.categoryId)?.name
const categoryName = categoryList.value.find(c => c.id === item.categoryId)?.projectName
// 跳转并传参
uni.navigateTo({
url: `/pageSubPack/online-repair/publicRepair?category=${categoryName}&project=${item.name}`
url: `/pageSubPack/online-repair/publicRepair?category=${categoryName}&project=${item.projectName}&projectId=${item.id}`
})
}
</script>

View File

@@ -9,10 +9,10 @@
v-for="item in houseList"
:key="item.id"
>
<image src="http://47.104.199.163:9090/images/repair/house.png" style="width: 60rpx;height: 60rpx;"></image>
<image src="http://47.104.199.163:9090/images/repair/house.png" style="width: 48rpx;height: 48rpx;"></image>
<view class="house-name">
{{ item.community }}
<view class="house-detail">{{ item.address }}</view>
{{ item.villageName }}
<view class="house-detail">{{ item.houseType }}</view>
</view>
<uni-icons type="checkbox-filled" size="20" color="#007aff" v-if="selectedHouse.id === item.id"></uni-icons>
@@ -26,17 +26,49 @@
<script setup>
import { ref } from 'vue'
// import { uniShowToast, uniNavigateBack } from '@dcloudio/uni-app'
import { onLoad } from '@dcloudio/uni-app'
import { getHouseList } from '../api/api.js'
// 房屋列表数据
const houseList = ref([
{ id: 1, community: '桂花园(别墅)', address: '2号楼2幢' },
{ id: 2, community: '安泰翡翠城', address: '11号楼5单元1801' },
{ id: 3, community: '碧桂园新城·时代之光', address: '3号楼' }
])
const houseList = ref([])
// 选中的房屋
const selectedHouse = ref(houseList.value[0]) // 默认选中第一个
const selectedHouse = ref({})
// 分页参数
const pageNum = ref(1)
const pageSize = ref(10)
// 预传入的房屋ID从表单页带过来
const preSelectedHouseId = ref('')
// 获取房屋列表
const fetchHouseList = async () => {
try {
const res = await getHouseList({ pageNum: pageNum.value, pageSize: pageSize.value })
if (res.code === 200) {
const list = res.rows || []
houseList.value = list
if (houseList.value.length > 0) {
if (preSelectedHouseId.value) {
const found = houseList.value.find(item => String(item.id) === String(preSelectedHouseId.value))
selectedHouse.value = found || houseList.value[0]
} else {
selectedHouse.value = houseList.value[0]
}
}
}
} catch (e) {
uni.showToast({ title: '获取房屋列表失败', icon: 'none' })
}
}
onLoad((options) => {
if (options.houseId) {
preSelectedHouseId.value = options.houseId
}
fetchHouseList()
})
// 选择房屋
const selectHouse = (item) => {
@@ -52,7 +84,8 @@ const confirmSelect = () => {
// 把选中的房屋信息传给表单页通过uni.$emit
uni.$emit('selectHouse', {
name: `${selectedHouse.value.community} ${selectedHouse.value.address}`
id: selectedHouse.value.id,
name: `${selectedHouse.value.villageName} ${selectedHouse.value.houseType}`
})
// 返回上一页