替换图片并删掉本地图片,代码分包
This commit is contained in:
@@ -0,0 +1,408 @@
|
||||
<template>
|
||||
<view class="repair-page">
|
||||
<view class="status_bar"></view>
|
||||
<!-- 顶部导航栏 -->
|
||||
<view class="nav-bar">
|
||||
<view class="nav-left" @tap="goBack">
|
||||
<image src="http://47.104.199.163:9090/images/home/arr-left.png" style="width: 48rpx; height: 48rpx;"></image>
|
||||
</view>
|
||||
<view class="nav-title">在线报修</view>
|
||||
<view class="nav-right"></view>
|
||||
</view>
|
||||
|
||||
<!-- 报修类型Tab -->
|
||||
<view class="repair-type-tabs">
|
||||
<view
|
||||
class="type-tab"
|
||||
:class="{ active: activeType === 'public' }"
|
||||
@click="publicClick"
|
||||
style="margin-right: 20rpx;"
|
||||
>
|
||||
<image src="http://47.104.199.163:9090/images/repair/publicRepair.png" style="width: 100%;height: 100%;"></image>
|
||||
<!-- <uni-icons type="staff" size="24" color="#fff"></uni-icons> -->
|
||||
<!-- <text class="type-text">公共报修</text> -->
|
||||
</view>
|
||||
<view
|
||||
class="type-tab"
|
||||
:class="{ active: activeType === 'personal' }"
|
||||
@click="personalClick"
|
||||
>
|
||||
<image src="http://47.104.199.163:9090/images/repair/personalRepair.png" style="width: 100%;height: 100%;"></image>
|
||||
<!-- <uni-icons type="person" size="24" color="#fff"></uni-icons> -->
|
||||
<!-- <text class="type-text">个人报修</text> -->
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view style="margin: 14px 0px;">
|
||||
<text class="repair-title">报修记录</text>
|
||||
</view>
|
||||
|
||||
<!-- 报修记录状态Tab -->
|
||||
<view class="record-status-tabs">
|
||||
<text
|
||||
class="status-tab"
|
||||
:class="{ active: activeStatus === 'pending' }"
|
||||
@click="activeStatus = 'pending'" >
|
||||
待派单
|
||||
</text>
|
||||
<text
|
||||
class="status-tab"
|
||||
:class="{ active: activeStatus === 'assigned' }"
|
||||
@click="activeStatus = 'assigned'"
|
||||
>
|
||||
已派单
|
||||
</text>
|
||||
<text
|
||||
class="status-tab"
|
||||
:class="{ active: activeStatus === 'completed' }"
|
||||
@click="activeStatus = 'completed'"
|
||||
>
|
||||
已完成
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<!-- 报修列表 -->
|
||||
<view class="repair-list">
|
||||
<view class="repair-item" v-for="(item, index) in repairList" :key="index">
|
||||
<!-- 标题和状态 -->
|
||||
<view class="item-header">
|
||||
<text class="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>
|
||||
|
||||
<!-- 内容 -->
|
||||
<view class="item-content">
|
||||
{{ item.content }}
|
||||
</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>
|
||||
</view>
|
||||
|
||||
<!-- 时间和详情 -->
|
||||
<view class="item-footer">
|
||||
<text class="item-time">{{ item.time }}</text>
|
||||
<text class="detail-btn" @click="goDetail(item)">报修详情</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
// 报修类型(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 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'},
|
||||
]
|
||||
}
|
||||
];
|
||||
return mockData;
|
||||
});
|
||||
|
||||
function publicClick(){
|
||||
activeType.value = 'public'
|
||||
uni.navigateTo({
|
||||
url:"/pageSubPack/online-repair/publicRepair"
|
||||
})
|
||||
};
|
||||
function personalClick(){
|
||||
activeType.value = 'personal'
|
||||
uni.navigateTo({
|
||||
url:"/pageSubPack/online-repair/personalRepair"
|
||||
})
|
||||
}
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
if(uni.getStorageSync('sourcePage') === "index"){
|
||||
uni.switchTab({
|
||||
url:"/pages/index/index"
|
||||
})
|
||||
}else if(uni.getStorageSync('sourcePage') === "serviceIndex"){
|
||||
uni.switchTab({
|
||||
url:"/pages/serviceIndex/serviceIndex"
|
||||
})
|
||||
}
|
||||
uni.removeStorageSync('sourcePage')
|
||||
|
||||
}
|
||||
// 跳转报修详情
|
||||
const goDetail = (item) => {
|
||||
// const itemStr = encodeURIComponent(JSON.stringify(item))
|
||||
uni.navigateTo({
|
||||
url: `/pageSubPack/online-repair/repairDetail?item = ${encodeURIComponent(JSON.stringify(item))}`
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 页面整体样式 */
|
||||
.repair-page {
|
||||
background: linear-gradient(to bottom left, #E2F0FF 0%, #f9f9f9 50%);
|
||||
min-height: 100vh;
|
||||
padding: 0 40rpx;
|
||||
}
|
||||
.status_bar {
|
||||
height: 32px;
|
||||
width: 100%;
|
||||
}
|
||||
/* 顶部导航栏 */
|
||||
.nav-bar {
|
||||
height: 90rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
/* padding: 0 30rpx; */
|
||||
color: #fff;
|
||||
position: sticky;
|
||||
top: 44px;
|
||||
z-index: 100;
|
||||
margin-bottom: 20px;
|
||||
/* box-shadow: 0 4rpx 12rpx rgba(0, 122, 255, 0.2); */
|
||||
}
|
||||
|
||||
.nav-left {
|
||||
width: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
padding: 0 20rpx;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.nav-right {
|
||||
width: 60rpx;
|
||||
}
|
||||
/* 报修类型Tab */
|
||||
.repair-type-tabs {
|
||||
display: flex;
|
||||
/* background-color: #fff; */
|
||||
/* padding: 10px; */
|
||||
}
|
||||
.type-tab {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100px;
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
.type-tab.active {
|
||||
background: linear-gradient(135deg, #1E88E5 0%, #64B5F6 100%);
|
||||
}
|
||||
.type-tab:not(.active) {
|
||||
background: linear-gradient(135deg, #4DB6AC 0%, #80CBC4 100%);
|
||||
}
|
||||
.type-text {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.repair-title{
|
||||
color: #222222;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 报修状态Tab */
|
||||
.record-status-tabs {
|
||||
display: flex;
|
||||
/* background-color: #fff; */
|
||||
/* margin-top: 10px; */
|
||||
/* padding: 0 15px; */
|
||||
}
|
||||
.status-tab {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
font-size: 15px;
|
||||
color: #666;
|
||||
position: relative;
|
||||
}
|
||||
.status-tab.active {
|
||||
color: #2F77FD;
|
||||
font-weight: bold;
|
||||
}
|
||||
.status-tab.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 20%;
|
||||
transform: translateX(-50%);
|
||||
width: 45px;
|
||||
height: 4px;
|
||||
border-radius: 4rpx;
|
||||
background-color: #1E88E5;
|
||||
}
|
||||
|
||||
/* 报修列表 */
|
||||
.repair-list {
|
||||
padding: 28rpx 0rpx;
|
||||
}
|
||||
.repair-item {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* 列表项头部 */
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.item-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
padding-right: 20rpx;
|
||||
}
|
||||
.item-status {
|
||||
font-size: 14px;
|
||||
}
|
||||
.item-status.pending {
|
||||
/* 待派单-红色 */
|
||||
color: #ffffff;
|
||||
background-color: #E34D59;
|
||||
border-radius: 20rpx;
|
||||
font-size: 12px;
|
||||
line-height: 22px;
|
||||
padding: 0px 10px;
|
||||
}
|
||||
.item-status.assigned {
|
||||
/* 已派单-绿色 */
|
||||
color: #ffffff;
|
||||
background-color: #09C2BD;
|
||||
border-radius: 20rpx;
|
||||
font-size: 12px;
|
||||
line-height: 22px;
|
||||
padding: 0px 10px;
|
||||
}
|
||||
.item-status.completed{
|
||||
color: #ffffff;
|
||||
background-color: #2F77FD;
|
||||
border-radius: 20rpx;
|
||||
font-size: 12px;
|
||||
line-height: 22px;
|
||||
padding: 0px 10px;
|
||||
}
|
||||
|
||||
/* 标签 */
|
||||
.item-tags {
|
||||
/* display: flex; */
|
||||
/* gap: 8px; */
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.tag {
|
||||
/* background-color: #e3f2fd; */
|
||||
color: #999999;
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #999999;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/* 内容 */
|
||||
.item-content {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 10px;
|
||||
/* background-color: #d7e4f5; */
|
||||
}
|
||||
|
||||
/* 图片占位 */
|
||||
.item-imgs {
|
||||
display: flex;
|
||||
/* gap: 12px; */
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.img-placeholder {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/* 底部时间和详情 */
|
||||
.item-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.item-time {
|
||||
color: #999;
|
||||
}
|
||||
.detail-btn {
|
||||
color: #1E88E5;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,639 @@
|
||||
<template>
|
||||
<view class="form-container">
|
||||
<!-- 报修房屋 -->
|
||||
<view class="form-item">
|
||||
<text class="label">报修房屋</text>
|
||||
<view class="value" @click="goToSelectHouse">
|
||||
{{ houseName || '请选择房屋' }}
|
||||
<text class="switch" v-if="houseName">切换</text>
|
||||
<uni-icons type="arrowright" size="16"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 维修项目 -->
|
||||
<view class="form-item">
|
||||
<text class="label">维修项目</text>
|
||||
<view class="value" @click="goToSelectProject">
|
||||
{{ projectName || '请选择维修项目' }}
|
||||
<uni-icons type="arrowright" size="16"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 标题 -->
|
||||
<view class="form-item">
|
||||
<text class="label">标题</text>
|
||||
<uni-easyinput v-model="form.title" placeholder="请输入内容" :inputBorder="false"></uni-easyinput>
|
||||
</view>
|
||||
|
||||
<!-- 问题描述 -->
|
||||
<view class="form-item-wenti">
|
||||
<text class="label">问题描述</text>
|
||||
<uni-easyinput v-model="form.desc" placeholder="请描述你的问题" type="textarea"></uni-easyinput>
|
||||
</view>
|
||||
|
||||
<!-- 手机号 -->
|
||||
<view class="form-item">
|
||||
<text class="label">手机号</text>
|
||||
<uni-easyinput type="number" v-model="form.phone" placeholder="请输入手机号" :inputBorder="false"></uni-easyinput>
|
||||
</view>
|
||||
|
||||
<!-- 预约时间 -->
|
||||
<view class="form-item time-item" @click="openTimePopup">
|
||||
<text class="label">预约时间</text>
|
||||
<text class="value time-value">{{ showTimeText }}</text>
|
||||
</view>
|
||||
<!-- <view class="form-item">
|
||||
<text class="label">预约时间</text>
|
||||
<view class="value" @click="">
|
||||
<uni-datetime-picker type="datetime" v-model="form.datetime" @change="changeTime" />
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 问题照片 -->
|
||||
<view class="form-item-wenti">
|
||||
<text class="label">问题照片</text>
|
||||
<view class="upload-wrap">
|
||||
<!-- 已上传图片 -->
|
||||
<view class="upload-item" v-for="(img, index) in form.images" :key="index">
|
||||
<image :src="img" mode="aspectFill" @click="previewImage(img)"></image>
|
||||
<uni-icons type="close" size="16" @click="deleteImage(index)"></uni-icons>
|
||||
</view>
|
||||
<!-- 上传按钮 -->
|
||||
<view class="upload-btn" @click="chooseImage">
|
||||
<uni-icons type="plus" size="24"></uni-icons>
|
||||
<text>上传照片</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<button class="submit-btn" @click="submitForm">提交</button>
|
||||
|
||||
<!-- 时间选择弹窗 -->
|
||||
<uni-popup ref="timePopupRef" type="bottom" :mask-click="false" border-radius="16rpx">
|
||||
<view class="time-popup-container">
|
||||
<!-- 弹窗头部:取消 + 标题 + 确认 -->
|
||||
<view class="time-popup-header">
|
||||
<text class="cancel-btn" @click="closeTimePopup">取消</text>
|
||||
<text class="popup-title">预约时间({{ tempTime.format('YYYY-MM-DD HH:mm') }})</text>
|
||||
<text class="confirm-btn" @click="confirmTime">确认</text>
|
||||
</view>
|
||||
|
||||
<!-- 时间选择列:日期 | 小时 | 分钟 -->
|
||||
<view class="time-selector">
|
||||
<!-- 日期列 -->
|
||||
<scroll-view
|
||||
class="time-column"
|
||||
scroll-y
|
||||
:scroll-top="dateScrollTop"
|
||||
@scroll="onDateScroll"
|
||||
scroll-with-animation
|
||||
>
|
||||
<view
|
||||
class="time-item"
|
||||
:class="{ active: dateItem.value === selectedDate }"
|
||||
v-for="(dateItem, index) in dateList"
|
||||
:key="index"
|
||||
@click="selectDate(index)"
|
||||
>
|
||||
{{ dateItem.value }}{{dateItem.label}}
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 小时列 -->
|
||||
<scroll-view
|
||||
class="time-column"
|
||||
scroll-y
|
||||
:scroll-top="hourScrollTop"
|
||||
@scroll="onHourScroll"
|
||||
scroll-with-animation
|
||||
>
|
||||
<view
|
||||
class="time-item"
|
||||
:class="{ active: hourItem.time === selectedHour }"
|
||||
v-for="(hourItem, index) in hourList"
|
||||
:key="index"
|
||||
@click="selectHour(index)"
|
||||
>
|
||||
{{ hourItem.time }}点
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 分钟列 -->
|
||||
<scroll-view
|
||||
class="time-column"
|
||||
scroll-y
|
||||
:scroll-top="minuteScrollTop"
|
||||
@scroll="onMinuteScroll"
|
||||
scroll-with-animation
|
||||
>
|
||||
<view
|
||||
class="time-item"
|
||||
:class="{ active: minuteItem.minute === selectedMinute }"
|
||||
v-for="(minuteItem, index) in minuteList"
|
||||
:key="index"
|
||||
@click="selectMinute(index)"
|
||||
>
|
||||
{{ minuteItem.minute }}分
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref,computed,onMounted} from 'vue'
|
||||
import {
|
||||
onLoad, onUnload
|
||||
} from '@dcloudio/uni-app'
|
||||
import moment from 'moment/moment'
|
||||
|
||||
// 选中的房屋/项目名称
|
||||
const houseName = ref('')
|
||||
const projectName = ref('')
|
||||
|
||||
// 表单数据
|
||||
const form = ref({
|
||||
title: '',
|
||||
desc: '',
|
||||
phone: '',
|
||||
datetime: '2023-08-01 15:30', // 默认时间(匹配截图)
|
||||
images: []
|
||||
})
|
||||
|
||||
// ========== 基础数据 ==========
|
||||
const timePopupRef = ref(null)
|
||||
// 初始时间()
|
||||
const selectedTime = ref(moment().hour(9).minute(30).second(0));
|
||||
// 选择的时间(弹窗中预览)
|
||||
const tempTime = ref(moment().hour(9).minute(30).second(0));
|
||||
|
||||
// ========== 时间选择列数据 ==========
|
||||
// 日期列表(今天、明天、后天)
|
||||
const dateList = ref([
|
||||
{ label: '(今天)', value: moment().format('YYYY-MM-DD') },
|
||||
{ label: '(明天)', value: moment().add(1, 'day').format('YYYY-MM-DD') },
|
||||
{ label: '(后天)', value: moment().add(2, 'day').format('YYYY-MM-DD') }
|
||||
]);
|
||||
// 小时列表()
|
||||
const hourList = ref([
|
||||
{time: moment().hours(8).format('HH')},
|
||||
{time:moment().hours(9).format('HH')},
|
||||
{time:moment().hours(10).format('HH')},
|
||||
{time:moment().hours(11).format('HH')},
|
||||
{time:moment().hours(13).format('HH')},
|
||||
{time:moment().hours(14).format('HH')},
|
||||
{time:moment().hours(15).format('HH')},
|
||||
{time:moment().hours(16).format('HH')},
|
||||
{time:moment().hours(17).format('HH')},
|
||||
{time:moment().hours(18).format('HH')},
|
||||
]);
|
||||
// 分钟列表()
|
||||
const minuteList = ref([
|
||||
{minute:moment().minute(0).format('mm')},
|
||||
{minute:moment().minute(30).format('mm')}
|
||||
]);
|
||||
|
||||
// ========== 选中状态 ==========
|
||||
const selectedDate = ref(dateList.value[0].value);
|
||||
const selectedHour = ref(hourList.value[1].time); // 默认选中8点
|
||||
const selectedMinute = ref(minuteList.value[1].minute); // 默认选中00分
|
||||
|
||||
// ========== 滚动配置 ==========
|
||||
const itemHeight = 80; // 每个时间项的高度(rpx)
|
||||
const dateScrollTop = ref(0 * itemHeight); // 初始选中明天
|
||||
const hourScrollTop = ref(1 * itemHeight); // 初始选中9点
|
||||
const minuteScrollTop = ref(1 * itemHeight); // 初始选中00分
|
||||
|
||||
// ========== 显示文本 ==========
|
||||
const showTimeText = computed(() => {
|
||||
return selectedTime.value.format('YYYY-MM-DD HH:mm');
|
||||
});
|
||||
|
||||
// ========== Popup 操作 ==========
|
||||
// 打开时间弹窗
|
||||
const openTimePopup = () => {
|
||||
// 打开前同步临时时间为当前选中时间
|
||||
tempTime.value = moment(selectedTime.value);
|
||||
selectedDate.value = tempTime.value.format('YYYY-MM-DD');
|
||||
selectedHour.value = tempTime.value.format('HH');
|
||||
selectedMinute.value = tempTime.value.format('mm');
|
||||
|
||||
// 同步滚动位置
|
||||
syncScrollPosition();
|
||||
// 打开uni-popup
|
||||
if(timePopupRef.value){
|
||||
timePopupRef.value.open();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// 关闭时间弹窗
|
||||
const closeTimePopup = () => {
|
||||
timePopupRef.value.close();
|
||||
};
|
||||
|
||||
// 确认选择时间
|
||||
const confirmTime = () => {
|
||||
// 拼接选中的时间
|
||||
const selectedDateTime = `${selectedDate.value} ${selectedHour.value}:${selectedMinute.value}`;
|
||||
selectedTime.value = moment(selectedDateTime, 'YYYY-MM-DD HH:mm');
|
||||
// 关闭弹窗
|
||||
closeTimePopup();
|
||||
|
||||
// 提示
|
||||
uni.showToast({
|
||||
title: `已选择 ${selectedTime.value.format('MM月DD日 HH:mm')}`,
|
||||
icon: 'none'
|
||||
});
|
||||
};
|
||||
|
||||
// ========== 滚动/点击选择逻辑 ==========
|
||||
// 同步滚动位置
|
||||
const syncScrollPosition = () => {
|
||||
// 日期滚动位置
|
||||
const dateIndex = dateList.value.findIndex(item => item.value === selectedDate.value);
|
||||
dateScrollTop.value = dateIndex * itemHeight;
|
||||
|
||||
// 小时滚动位置
|
||||
const hourIndex = hourList.value.findIndex(item => item.time === selectedHour.value);
|
||||
hourScrollTop.value = hourIndex * itemHeight;
|
||||
|
||||
// 分钟滚动位置
|
||||
const minuteIndex = minuteList.value.findIndex(item => item.minute === selectedMinute.value);
|
||||
minuteScrollTop.value = minuteIndex * itemHeight;
|
||||
};
|
||||
|
||||
// 选择日期(点击)
|
||||
const selectDate = (index) => {
|
||||
selectedDate.value = dateList.value[index].value;
|
||||
dateScrollTop.value = index * itemHeight;
|
||||
updateTempTime();
|
||||
};
|
||||
|
||||
// 选择小时(点击)
|
||||
const selectHour = (index) => {
|
||||
selectedHour.value = hourList.value[index].time;
|
||||
hourScrollTop.value = index * itemHeight;
|
||||
updateTempTime();
|
||||
};
|
||||
|
||||
// 选择分钟(点击)
|
||||
const selectMinute = (index) => {
|
||||
selectedMinute.value = minuteList.value[index].minute;
|
||||
minuteScrollTop.value = index * itemHeight;
|
||||
updateTempTime();
|
||||
};
|
||||
|
||||
// 滚动日期列(滑动)
|
||||
const onDateScroll = (e) => {
|
||||
const index = Math.round(e.detail.scrollTop / itemHeight);
|
||||
if (index >= 0 && index < dateList.value.length) {
|
||||
selectedDate.value = dateList.value[index].value;
|
||||
updateTempTime();
|
||||
}
|
||||
};
|
||||
|
||||
// 滚动小时列(滑动)
|
||||
const onHourScroll = (e) => {
|
||||
const index = Math.round(e.detail.scrollTop / itemHeight);
|
||||
if (index >= 0 && index < hourList.value.length) {
|
||||
selectedHour.value = hourList.value[index].time;
|
||||
updateTempTime();
|
||||
}
|
||||
};
|
||||
|
||||
// 滚动分钟列(滑动)
|
||||
const onMinuteScroll = (e) => {
|
||||
const index = Math.round(e.detail.scrollTop / itemHeight);
|
||||
minuteScrollTop.value = index * itemHeight;
|
||||
if (index >= 0 && index < minuteList.value.length) {
|
||||
selectedMinute.value = minuteList.value[index].minute;
|
||||
updateTempTime();
|
||||
}
|
||||
};
|
||||
|
||||
// 更新临时时间(弹窗预览)
|
||||
const updateTempTime = () => {
|
||||
tempTime.value = moment(`${selectedDate.value} ${selectedHour.value}:${selectedMinute.value}`, 'YYYY-MM-DD HH:mm');
|
||||
};
|
||||
|
||||
// ========== 初始化 ==========
|
||||
onMounted(() => {
|
||||
syncScrollPosition();
|
||||
});
|
||||
|
||||
|
||||
|
||||
// 页面加载时监听事件
|
||||
onLoad(() => {
|
||||
// 监听选择房屋事件
|
||||
uni.$on('selectHouse', (data) => {
|
||||
houseName.value = data.name
|
||||
})
|
||||
// 监听选择维修项目事件
|
||||
uni.$on('selectProject', (data) => {
|
||||
projectName.value = data.name
|
||||
})
|
||||
})
|
||||
|
||||
// 页面销毁移除监听
|
||||
onUnload(() => {
|
||||
uni.$off('selectHouse')
|
||||
uni.$off('selectProject')
|
||||
})
|
||||
|
||||
// 跳转到选择房屋页
|
||||
const goToSelectHouse = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pageSubPack/online-repair/selectHouse'
|
||||
})
|
||||
}
|
||||
|
||||
// 跳转到选择维修项目页
|
||||
const goToSelectProject = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pageSubPack/online-repair/personalSelectPoject'
|
||||
})
|
||||
}
|
||||
|
||||
// 选择预约时间
|
||||
const changeTime = () =>{
|
||||
|
||||
}
|
||||
// const chooseDateTime = () => {
|
||||
// uni.datePicker({
|
||||
// type: 'datetime',
|
||||
// value: form.value.datetime,
|
||||
// success: (res) => {
|
||||
// form.value.datetime = res.value
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
// 选择图片
|
||||
const chooseImage = () => {
|
||||
uni.chooseImage({
|
||||
count: 3,
|
||||
sizeType: ['original', 'compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
form.value.images = [...form.value.images, ...res.tempFilePaths]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 预览图片
|
||||
const previewImage = (url) => {
|
||||
uni.previewImage({
|
||||
urls: form.value.images,
|
||||
current: url
|
||||
})
|
||||
}
|
||||
|
||||
// 删除图片
|
||||
const deleteImage = (index) => {
|
||||
form.value.images.splice(index, 1)
|
||||
}
|
||||
|
||||
// 表单提交
|
||||
const submitForm = () => {
|
||||
// 校验
|
||||
if (!houseName.value) {
|
||||
uni.showToast({ title: '请选择报修房屋', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!projectName.value) {
|
||||
uni.showToast({ title: '请选择维修项目', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!form.value.title) {
|
||||
uni.showToast({ title: '请输入问题标题', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!form.value.desc) {
|
||||
uni.showToast({ title: '请输入问题描述', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!/^1[3-9]\d{9}$/.test(form.value.phone)) {
|
||||
uni.showToast({ title: '请输入正确的手机号', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!form.value.datetime) {
|
||||
uni.showToast({ title: '请选择预约时间', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 提交逻辑(替换为你的接口)
|
||||
uni.showLoading({ title: '提交中...' })
|
||||
setTimeout(() => {
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '提交成功', icon: 'success' })
|
||||
// 重置表单
|
||||
// form.value = { title: '', desc: '', phone: '', datetime: '', images: [] }
|
||||
// houseName.value = ''
|
||||
// projectName.value = ''
|
||||
}, 1000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.form-container {
|
||||
padding: 15px;
|
||||
background: #fff;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.form-item {
|
||||
display: flex;
|
||||
margin-bottom: 30rpx;
|
||||
align-items: flex-start;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.label {
|
||||
width: 140rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 80rpx;
|
||||
}
|
||||
|
||||
.value {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 80rpx;
|
||||
text-align: right;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.time-value {
|
||||
color: #000;
|
||||
}
|
||||
.input, .textarea {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.textarea {
|
||||
min-height: 160rpx;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
.form-item-wenti {
|
||||
margin-bottom: 20px;
|
||||
/* border-bottom: 1px solid #eee; */
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
/* .label {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
display: block;
|
||||
}
|
||||
.value {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 0;
|
||||
} */
|
||||
.switch {
|
||||
font-size: 12px;
|
||||
color: #007aff;
|
||||
margin-right: 5px;
|
||||
}
|
||||
input, textarea {
|
||||
font-size: 14px;
|
||||
width: 100%;
|
||||
padding: 8px 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
textarea {
|
||||
resize: none;
|
||||
}
|
||||
.upload-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.upload-item {
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
.upload-item image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.upload-item uni-icons {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
right: -5px;
|
||||
background: #ff3b30;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
padding: 2px;
|
||||
}
|
||||
.upload-btn {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
border-radius: 8px;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
font-size: 16px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/* ========== uni-popup 时间选择器样式 ========== */
|
||||
.time-popup-container {
|
||||
background-color: #fff;
|
||||
border-top-left-radius: 16rpx;
|
||||
border-top-right-radius: 16rpx;
|
||||
}
|
||||
|
||||
/* 弹窗头部 */
|
||||
.time-popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 30rpx;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
font-size: 28rpx;
|
||||
color: #007aff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 时间选择器容器 */
|
||||
.time-selector {
|
||||
display: flex;
|
||||
height: 400rpx;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
/* 单个时间列 */
|
||||
.time-column {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 时间项 */
|
||||
.time-item {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 选中项样式(高亮) */
|
||||
.time-item.active {
|
||||
color: #007aff;
|
||||
font-weight: 600;
|
||||
background-color: #d0d0d0;
|
||||
}
|
||||
|
||||
.time-item.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
/* width: 80%; */
|
||||
/* height: 1px; */
|
||||
background-color: #d0d0d0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<view class="project-container">
|
||||
<!-- 搜索框 -->
|
||||
<view class="search-bar">
|
||||
<input type="text" placeholder="请输入关键字搜索" v-model="searchKey" />
|
||||
<uni-icons type="search" size="18"></uni-icons>
|
||||
</view>
|
||||
|
||||
<!-- 分类+项目 -->
|
||||
<view class="category-wrap">
|
||||
<!-- 左侧分类 -->
|
||||
<scroll-view scroll-y class="category-left">
|
||||
<view
|
||||
class="category-item"
|
||||
:class="{ active: activeCategory === item.id }"
|
||||
@click="selectCategory(item)"
|
||||
v-for="item in categoryList"
|
||||
:key="item.id"
|
||||
>
|
||||
{{ item.name }}
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 右侧项目 -->
|
||||
<scroll-view scroll-y class="category-right">
|
||||
<view
|
||||
class="project-item"
|
||||
:class="{ active: selectedProject.id === item.id }"
|
||||
@click="selectProject(item)"
|
||||
v-for="item in currentProjectList"
|
||||
:key="item.id"
|
||||
>
|
||||
{{ item.name }}
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 确认按钮 -->
|
||||
<button class="confirm-btn" @click="confirmSelect">确认</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
// import { uniShowToast, uniNavigateBack } from '@dcloudio/uni-app'
|
||||
|
||||
// 分类列表(匹配截图:家具/电路/水暖/门频/电器)
|
||||
const categoryList = ref([
|
||||
{ id: 1, name: '家具' },
|
||||
{ id: 2, name: '电路' },
|
||||
{ id: 3, name: '水暖' },
|
||||
{ id: 4, name: '门频' },
|
||||
{ id: 5, name: '电器' }
|
||||
])
|
||||
|
||||
// 项目列表(匹配截图:床/沙发/柜子/椅子等)
|
||||
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 activeCategory = ref(1) // 默认选中家具
|
||||
const selectedProject = ref({}) // 选中的项目
|
||||
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))
|
||||
}
|
||||
return list
|
||||
})
|
||||
|
||||
// 选择分类
|
||||
const selectCategory = (item) => {
|
||||
activeCategory.value = item.id
|
||||
selectedProject.value = {} // 切换分类清空选中项目
|
||||
}
|
||||
|
||||
// 选择项目
|
||||
const selectProject = (item) => {
|
||||
selectedProject.value = item
|
||||
}
|
||||
|
||||
// 确认选择
|
||||
const confirmSelect = () => {
|
||||
if (!selectedProject.value.id) {
|
||||
uni.showToast({ title: '请选择维修项目', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 获取分类名称
|
||||
const categoryName = categoryList.value.find(c => c.id === activeCategory.value).name
|
||||
// 传递给表单页
|
||||
uni.$emit('selectProject', {
|
||||
name: `${categoryName}-${selectedProject.value.name}`
|
||||
})
|
||||
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.project-container {
|
||||
padding: 15px;
|
||||
height: 100vh;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
}
|
||||
.search-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 10px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.search-bar input {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
}
|
||||
.category-wrap {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.category-left {
|
||||
width: 80px;
|
||||
height: 100%;
|
||||
background: #f8f8f8;
|
||||
border-radius: 6px 0 0 6px;
|
||||
}
|
||||
.category-item {
|
||||
padding: 12px 10px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.category-item.active {
|
||||
background: #fff;
|
||||
color: #007aff;
|
||||
font-weight: bold;
|
||||
}
|
||||
.category-right {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
border-radius: 0 6px 6px 0;
|
||||
padding: 10px;
|
||||
}
|
||||
.project-item {
|
||||
padding: 12px 10px;
|
||||
font-size: 14px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.project-item.active {
|
||||
color: #007aff;
|
||||
font-weight: bold;
|
||||
}
|
||||
.confirm-btn {
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,245 @@
|
||||
<template>
|
||||
<view class="form-container">
|
||||
<!-- 维修项目展示 -->
|
||||
<view class="form-item">
|
||||
<text class="label">维修项目</text>
|
||||
<view class="value" @click="goBackSelect">
|
||||
<view>
|
||||
<text v-if="!repairProject">请选择项目</text>
|
||||
{{ repairProject }}
|
||||
</view>
|
||||
<uni-icons type="arrowright" size="16"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 标题输入 -->
|
||||
<view class="form-item">
|
||||
<text class="label">标题</text>
|
||||
<!-- <input type="text" placeholder="请输入问题标题" v-model="form.title" /> -->
|
||||
<uni-easyinput v-model="form.title" placeholder="请输入内容" :inputBorder="false"></uni-easyinput>
|
||||
</view>
|
||||
|
||||
<!-- 问题描述 -->
|
||||
<view class="form-item-wenti">
|
||||
<text class="label">问题描述</text>
|
||||
<!-- <textarea placeholder="请输入问题内容" v-model="form.desc" rows="5" ></textarea> -->
|
||||
<uni-easyinput v-model="form.desc" placeholder="请描述你的问题" type="textarea"></uni-easyinput>
|
||||
</view>
|
||||
|
||||
<!-- 手机号 -->
|
||||
<view class="form-item">
|
||||
<text class="label">手机号</text>
|
||||
<uni-easyinput type="number" v-model="form.phone" placeholder="请输入手机号" :inputBorder="false"></uni-easyinput>
|
||||
</view>
|
||||
|
||||
<!-- 图片上传 -->
|
||||
<view class="form-item-wenti">
|
||||
<text class="label">问题照片</text>
|
||||
<view class="upload-wrap">
|
||||
<!-- 已上传图片 -->
|
||||
<view class="upload-item" v-for="(img, index) in form.images" :key="index">
|
||||
<image :src="img" mode="aspectFill"></image>
|
||||
<uni-icons type="close" size="16" @click="deleteImage(index)"></uni-icons>
|
||||
</view>
|
||||
<!-- 上传按钮 -->
|
||||
<view class="upload-btn" @click="chooseImage">
|
||||
<uni-icons type="plus" size="24"></uni-icons>
|
||||
<text>上传照片</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<button class="submit-btn" @click="submitForm">提交</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import{onLoad} from "@dcloudio/uni-app"
|
||||
// import { onLoad, uniShowToast, uniNavigateBack, uniChooseImage, uniUploadFile } from '@dcloudio/uni-app'
|
||||
|
||||
// 接收上个页面传的维修项目
|
||||
const repairProject = ref('')
|
||||
|
||||
// 表单数据
|
||||
const form = ref({
|
||||
title: '',
|
||||
desc: '',
|
||||
phone: '',
|
||||
images: [] // 图片列表
|
||||
})
|
||||
|
||||
// 页面加载时获取传参
|
||||
onLoad((options) => {
|
||||
if (options.category && options.project) {
|
||||
repairProject.value = `${options.category}-${options.project}`
|
||||
}
|
||||
})
|
||||
|
||||
// 返回选择项目页
|
||||
const goBackSelect = () => {
|
||||
uni.navigateTo({
|
||||
url:"/pageSubPack/online-repair/repairSelect"
|
||||
})
|
||||
// uni.navigateBack({
|
||||
// delta: 1
|
||||
// })
|
||||
}
|
||||
|
||||
// 选择图片
|
||||
const chooseImage = () => {
|
||||
uni.chooseImage({
|
||||
count: 3, // 最多选3张
|
||||
sizeType: ['original', 'compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
// 临时文件路径
|
||||
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)
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 删除图片
|
||||
const deleteImage = (index) => {
|
||||
form.value.images.splice(index, 1)
|
||||
}
|
||||
|
||||
// 表单提交
|
||||
const submitForm = () => {
|
||||
// 表单校验
|
||||
if (!repairProject.value) {
|
||||
uni.showToast({ title: '请选择维修项目', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!form.value.title) {
|
||||
uni.showToast({ title: '请输入问题标题', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!form.value.desc) {
|
||||
uni.showToast({ title: '请输入问题描述', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!/^1[3-9]\d{9}$/.test(form.value.phone)) {
|
||||
uni.showToast({ title: '请输入正确的手机号', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 提交数据(替换成你的接口)
|
||||
uni.showLoading({ title: '提交中...' })
|
||||
|
||||
// 模拟接口请求
|
||||
setTimeout(() => {
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '提交成功', icon: 'success' })
|
||||
|
||||
// 提交成功后重置表单/返回上一页
|
||||
// form.value = { title: '', desc: '', phone: '', images: [] }
|
||||
// 或返回上一页
|
||||
uni.navigateBack({ delta: 3 })
|
||||
}, 1000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.form-container {
|
||||
padding: 15px;
|
||||
background: #fff;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.form-item-wenti {
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.form-item {
|
||||
display: flex;
|
||||
margin-bottom: 30rpx;
|
||||
align-items: flex-start;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.label {
|
||||
width: 140rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 80rpx;
|
||||
}
|
||||
|
||||
.value {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 80rpx;
|
||||
text-align: right;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.input, .textarea {
|
||||
font-size: 14px;
|
||||
width: 100%;
|
||||
padding: 8px 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.textarea {
|
||||
resize: none;
|
||||
}
|
||||
.upload-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.upload-item {
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
.upload-item image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.upload-item uni-icons {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
right: -5px;
|
||||
background: #ff3b30;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
padding: 2px;
|
||||
}
|
||||
.upload-btn {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
border-radius: 6px;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,273 @@
|
||||
<template>
|
||||
<view class="repair-detail-container">
|
||||
|
||||
<!-- 维修流程模块 -->
|
||||
<view class="info-section">
|
||||
<!-- <uni-section title="维修流程" type="line" style="margin-bottom: 20rpx;"> -->
|
||||
<view class="section-title">维修流程</view>
|
||||
<uni-row class="demo-uni-row" :width="nvueWidth">
|
||||
<uni-col :span="12">
|
||||
<up-steps :current="currentStep" direction="column" space="30" active-color="#007aff">
|
||||
<up-steps-item title="待处理" desc="提交报修成功"></up-steps-item>
|
||||
<up-steps-item title="已派单" desc="维修师傅已接单"></up-steps-item>
|
||||
<up-steps-item title="已完成" desc="维修完成"></up-steps-item>
|
||||
</up-steps>
|
||||
</uni-col>
|
||||
<uni-col :span="12">
|
||||
<view class="step-time">2026-03-24 09:30:38</view>
|
||||
<view class="step-time">2026-03-26 09:30:38</view>
|
||||
<view class="step-time-3">2026-03-28 09:30:38</view>
|
||||
</uni-col>
|
||||
</uni-row>
|
||||
|
||||
<!-- </uni-section> -->
|
||||
</view>
|
||||
|
||||
<!-- 报修信息模块 -->
|
||||
<view class="info-section">
|
||||
<!-- <uni-section title="报修信息" type="line" style="margin-bottom: 20rpx;"> -->
|
||||
<view class="section-title">报修信息</view>
|
||||
<view class="info-item">
|
||||
<view class="info-label">报修房屋</view>
|
||||
<view class="info-value">{{repairInfo.house}}</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-label">维修项目</view>
|
||||
<view class="info-value">{{repairInfo.project}}</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-label">标题</view>
|
||||
<view class="info-value">{{repairInfo.title}}</view>
|
||||
</view>
|
||||
<view class="info-item-desc">
|
||||
<view class="info-label">问题描述</view>
|
||||
<view class="info-value multi-line">{{repairInfo.description}}</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-label">手机号</view>
|
||||
<view class="info-value">{{repairInfo.phone}}</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-label">报修时间</view>
|
||||
<view class="info-value">{{repairInfo.time}}</view>
|
||||
</view>
|
||||
<view class="info-item-desc">
|
||||
<view class="info-label">问题照片</view>
|
||||
<view class="photo-container">
|
||||
<view class="photo-item" v-for="(item, index) in 2" :key="index">
|
||||
<uni-icons type="plusempty" size="24" color="#ccc"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- </uni-section> -->
|
||||
</view>
|
||||
|
||||
<!-- 联系物业按钮 -->
|
||||
<view class="btn-container">
|
||||
<button class="contact-btn" @click="contactProperty">联系物业</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref
|
||||
} from 'vue'
|
||||
import {
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app'
|
||||
|
||||
// 步骤条当前激活的步骤(0=待处理,1=已派单,2=已完成)
|
||||
const currentStep = ref(2)
|
||||
const nvueWidth = ref('300')
|
||||
|
||||
// 报修信息数据
|
||||
const repairInfo = ref({
|
||||
house: '桂花园(别墅) 2号楼2层',
|
||||
project: '照明-路灯',
|
||||
title: '1栋楼下道路灯不亮了',
|
||||
description: '1栋楼下道路路灯不亮,并且有的亮度不够,请物业公司及时更换,防止发生意外事故。',
|
||||
phone: '15688888888',
|
||||
time: '2023-08-01 15:30'
|
||||
})
|
||||
|
||||
onLoad((option) => {
|
||||
const decodeStr = decodeURIComponent(JSON.stringify(option))
|
||||
// let item = JSON.parse(decodeStr)
|
||||
// repairInfo.value = optionStr
|
||||
console.log('item', decodeStr)
|
||||
const status = decodeStr.statusClass
|
||||
// console.log('status',status)
|
||||
switch (status) {
|
||||
case 'pending': //待处理
|
||||
currentStep.value = 0
|
||||
break
|
||||
case 'assignde':
|
||||
currentStep.value = 1
|
||||
break
|
||||
case 'completed':
|
||||
currentStep.value = 2
|
||||
break
|
||||
default:
|
||||
currentStep.value = 0
|
||||
}
|
||||
})
|
||||
|
||||
// 联系物业按钮点击事件
|
||||
const contactProperty = () => {
|
||||
uni.showToast({
|
||||
title: '正在联系物业...',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.repair-detail-container {
|
||||
padding: 16px;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.process-section,
|
||||
.info-section {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 13px;
|
||||
margin-bottom: 16px;
|
||||
/* margin-top: 20rpx; */
|
||||
}
|
||||
|
||||
.repair-steps-container {
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.step-time {
|
||||
height: 54px;
|
||||
line-height: 54px;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
/* font-size: 22rpx;
|
||||
color: #999;
|
||||
text-align: right;
|
||||
margin-top: 5rpx; */
|
||||
}
|
||||
.step-time-3{
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* -------- */
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.slot-title {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.slot-desc {
|
||||
font-size: 10px;
|
||||
|
||||
}
|
||||
|
||||
/* .step-time {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
} */
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
padding: 12px 0;
|
||||
/* border-bottom: 1px solid #f0f0f0; */
|
||||
}
|
||||
.info-item-desc {
|
||||
/* display: flex; */
|
||||
padding: 12px 0;
|
||||
/* border-bottom: 1px solid #f0f0f0; */
|
||||
}
|
||||
|
||||
.info-section.active {
|
||||
color: #007AFF;
|
||||
/* font-weight: 500; */
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
width: 80px;
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
flex: 1;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.multi-line {
|
||||
white-space: pre-wrap;
|
||||
line-height: 1.5;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 8rpx;
|
||||
padding: 30rpx;
|
||||
margin: 30rpx 0;
|
||||
}
|
||||
|
||||
.photo-container {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.photo-item {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.contact-btn {
|
||||
background-color: #007AFF;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
height: 48px;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.contact-btn::after {
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<view class="select-container">
|
||||
<!-- 搜索框 -->
|
||||
<view class="search-bar">
|
||||
<input type="text" placeholder="请输入关键字搜索" v-model="searchKey" />
|
||||
<uni-icons type="search" size="18"></uni-icons>
|
||||
</view>
|
||||
|
||||
<!-- 分类选择 -->
|
||||
<view class="category-wrap">
|
||||
<!-- 左侧分类 -->
|
||||
<scroll-view scroll-y class="category-left">
|
||||
<view
|
||||
class="category-item"
|
||||
:class="{ active: activeCategory === item.id }"
|
||||
@click="selectCategory(item)"
|
||||
v-for="item in categoryList"
|
||||
:key="item.id"
|
||||
>
|
||||
{{ item.name }}
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 右侧项目 -->
|
||||
<scroll-view scroll-y class="category-right">
|
||||
<view
|
||||
class="project-item"
|
||||
@click="selectProject(item)"
|
||||
v-for="item in currentProjectList"
|
||||
:key="item.id"
|
||||
>
|
||||
{{ item.name }}
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
// import { uniNavigateTo } from '@dcloudio/uni-app'
|
||||
|
||||
// 分类列表
|
||||
const categoryList = ref([
|
||||
{ id: 1, name: '基础设施' },
|
||||
{ id: 2, name: '电子设施' }
|
||||
])
|
||||
|
||||
// 所有项目数据
|
||||
const projectList = ref([
|
||||
{ id: 101, categoryId: 1, name: '路灯' },
|
||||
{ id: 102, categoryId: 1, name: '楼层指示灯' },
|
||||
{ id: 103, categoryId: 2, name: '应急出口灯' },
|
||||
{ id: 104, categoryId: 1, name: '草坪灯' }
|
||||
])
|
||||
|
||||
// 选中的分类
|
||||
const activeCategory = ref(1)
|
||||
// 搜索关键词
|
||||
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))
|
||||
}
|
||||
return list
|
||||
})
|
||||
|
||||
// 选择分类
|
||||
const selectCategory = (item) => {
|
||||
activeCategory.value = item.id
|
||||
}
|
||||
|
||||
// 选择项目并跳转到维修项目填写页
|
||||
const selectProject = (item) => {
|
||||
// 获取分类名称
|
||||
const categoryName = categoryList.value.find(c => c.id === item.categoryId)?.name
|
||||
// 跳转并传参
|
||||
uni.navigateTo({
|
||||
url: `/pageSubPack/online-repair/publicRepair?category=${categoryName}&project=${item.name}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.select-container {
|
||||
padding: 10px;
|
||||
height: 100vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.search-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 10px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.search-bar input {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
}
|
||||
.category-wrap {
|
||||
display: flex;
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
.category-left {
|
||||
width: 120px;
|
||||
height: 100%;
|
||||
background: #f8f8f8;
|
||||
border-radius: 6px 0 0 6px;
|
||||
}
|
||||
.category-item {
|
||||
padding: 15px 10px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.category-item.active {
|
||||
background: #fff;
|
||||
color: #007aff;
|
||||
font-weight: bold;
|
||||
}
|
||||
.category-right {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
border-radius: 0 6px 6px 0;
|
||||
padding: 10px;
|
||||
}
|
||||
.project-item {
|
||||
padding: 12px 10px;
|
||||
font-size: 14px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.project-item:active {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<view class="house-container">
|
||||
<!-- 房屋列表 -->
|
||||
<view class="house-list">
|
||||
<view
|
||||
class="house-item"
|
||||
:class="{ active: selectedHouse.id === item.id }"
|
||||
@click="selectHouse(item)"
|
||||
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>
|
||||
<view class="house-name">
|
||||
{{ item.community }}
|
||||
<view class="house-detail">{{ item.address }}</view>
|
||||
</view>
|
||||
|
||||
<uni-icons type="checkbox-filled" size="20" color="#007aff" v-if="selectedHouse.id === item.id"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 确认按钮 -->
|
||||
<button class="confirm-btn" @click="confirmSelect">确认</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
// import { uniShowToast, uniNavigateBack } from '@dcloudio/uni-app'
|
||||
|
||||
// 房屋列表数据
|
||||
const houseList = ref([
|
||||
{ id: 1, community: '桂花园(别墅)', address: '2号楼2幢' },
|
||||
{ id: 2, community: '安泰翡翠城', address: '11号楼5单元1801' },
|
||||
{ id: 3, community: '碧桂园新城·时代之光', address: '3号楼' }
|
||||
])
|
||||
|
||||
// 选中的房屋
|
||||
const selectedHouse = ref(houseList.value[0]) // 默认选中第一个
|
||||
|
||||
// 选择房屋
|
||||
const selectHouse = (item) => {
|
||||
selectedHouse.value = item
|
||||
}
|
||||
|
||||
// 确认选择并返回
|
||||
const confirmSelect = () => {
|
||||
if (!selectedHouse.value) {
|
||||
uni.showToast({ title: '请选择房屋', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 把选中的房屋信息传给表单页(通过uni.$emit)
|
||||
uni.$emit('selectHouse', {
|
||||
name: `${selectedHouse.value.community} ${selectedHouse.value.address}`
|
||||
})
|
||||
|
||||
// 返回上一页
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.house-container {
|
||||
padding: 15px;
|
||||
height: 100vh;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
background: #fff;
|
||||
}
|
||||
.house-list {
|
||||
flex: 1;
|
||||
}
|
||||
.house-item {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 15px 10px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.house-item.active {
|
||||
border-color: #007aff;
|
||||
background: #f0f8ff;
|
||||
}
|
||||
.house-name {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
margin-left: 30rpx;
|
||||
width: 80%;
|
||||
}
|
||||
.house-detail {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.confirm-btn {
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user