设置和消息对接口 改回上报记录页面

This commit is contained in:
zhouyanli
2026-05-15 17:55:31 +08:00
parent 856f36455c
commit eb7d4da5e3
4 changed files with 268 additions and 318 deletions

View File

@@ -75,7 +75,16 @@ export const switchOpenDoor = (data) =>{
export const getSettingInfo = () =>{ export const getSettingInfo = () =>{
return get('/api/setting/info') return get('/api/setting/info')
} }
// 设置-修改密码 // =====设置=======
// 修改密码
export const changePassword = (data) =>{ export const changePassword = (data) =>{
return post('/api/setting/changePassword',data) return post('/api/setting/changePassword',data)
} }
// 退出登录
export const logout = () =>{
return post('/api/butler/auth/logout')
}
// 修改手机号
export const changePhone = (data) =>{
return post('/api/setting/changePhone',data)
}

View File

@@ -1,111 +1,99 @@
<template> <template>
<view class="report-record-page page_padding"> <view class="report-record-page">
<view class="status-bar"></view>
<!-- 顶部导航栏 --> <!-- 顶部导航栏 -->
<navBar @clickLeft="navBack" title="上报记录"></navBar> <uni-nav-bar
<view class="hall_body flex-1 flex flex-col"> left-icon="back"
<view class="bgaction"> </view> title="上报记录"
<!-- 状态筛选标签 --> backgroundColor="transparent"
<TabsComponents :border= "false"
:tabslist="statusTabs" @clickLeft="navBack"/>
:options="{ label: 'label', value: 'value' }"
@update="switchStatus"
></TabsComponents>
<!-- 类型筛选标签 --> <!-- 状态筛选标签 -->
<view class="type-tabs"> <view class="status-tabs">
<view <view
v-for="item in typeTabs" v-for="item in statusTabs"
:key="item.value" :key="item.value"
class="type-tab-item" class="status-tab-item"
:class="{ active: activeType === item.value }" :class="{ active: activeStatus === item.value }"
@tap="switchType(item.value)" @tap="switchStatus(item.value)"
> >
{{ item.label }} {{ item.label }}
</view> </view>
</view>
<!-- 类型筛选标签 -->
<view class="type-tabs">
<view
v-for="item in typeTabs"
:key="item.value"
class="type-tab-item"
:class="{ active: activeType === item.value }"
@tap="switchType(item.value)"
>
{{ item.label }}
</view>
</view>
<!-- 上报记录列表 -->
<scroll-view
class="record-list"
scroll-y
:style="{ height: `calc(100vh - ${navHeight + statusTabHeight + typeTabHeight}px)` }"
>
<!-- 空状态 -->
<view v-if="filteredRecords.length === 0" class="empty-state">
<uni-icons type="empty" size="60" color="#ccc"></uni-icons>
<text class="empty-text">暂无上报记录</text>
</view> </view>
<!-- 上报记录列表 --> <!-- 记录卡片 -->
<scroll-view <view
class="record-list flex-1" v-for="record in filteredRecords"
scroll-y :key="record.id"
lower-threshold="60" class="record-card"
@scrolltolower="scrolltolower"
> >
<!-- 空状态 --> <!-- 标题 + 状态标签 -->
<view v-if="reportRecords.length === 0" class="empty-state"> <view class="card-header">
<uni-icons type="empty" size="60" color="#ccc"></uni-icons> <text class="card-title">{{ record.title }}</text>
<text class="empty-text">暂无上报记录</text> <view class="status-tag" :class="record.status">
</view> {{ getStatusText(record.status) }}
<!-- 记录卡片 -->
<view
v-for="(record, index) in reportRecords"
:key="index"
class="record-card"
@tap="handleMain(record.id)"
>
<!-- 标题 + 状态标签 -->
<view class="card-header">
<text class="card-title">{{ record.title }}</text>
<view
class="status-tag"
:class="{
pending: record.repairStatus === 0,
processing: record.repairStatus === 1,
completed: record.repairStatus === 2
}"
>
{{ getStatusText(record.repairStatus) }}
</view>
</view>
<!-- 类型标签 -->
<view class="tag-group">
<view class="tag-item">{{ record.reportType }}</view>
<view class="tag-item">{{ record.category }}</view>
</view>
<!-- 内容 -->
<view class="card-content">
{{ record.content }}
</view>
<!-- 工单图片 -->
<!-- <view class="card-image">
<image
v-for="(item, index) in record.images"
:key="index"
lazy-load
:src="item"
class="images"
mode="scaleToFill"
@tap="handlePrivew(record.images)"
></image>
</view> -->
<!-- 底部信息 -->
<view class="card-footer">
<text class="create-time">{{ record.createTime }}</text>
<text v-if="record.repairStatus !== 0" class="repairman"
>维修师傅:{{ record.repairman }}</text
>
<!-- <view class="share" v-if="record.repairStatus === 0">
<text>分配</text>
</view> -->
</view> </view>
</view> </view>
</scroll-view>
</view> <!-- 类型标签 -->
<view class="tag-group">
<view class="tag-item">{{ record.reportType }}</view>
<view class="tag-item">{{ record.category }}</view>
</view>
<!-- 内容 -->
<view class="card-content">
{{ record.content }}
</view>
<!-- 底部信息 -->
<view class="card-footer">
<text class="create-time">{{ record.createTime }}</text>
<text v-if="record.repairman" class="repairman">维修师傅:{{ record.repairman }}</text>
</view>
</view>
</scroll-view>
</view> </view>
</template> </template>
<script setup> <script setup>
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { onReady } from '@dcloudio/uni-app' import {onReady} from "@dcloudio/uni-app"
import TabsComponents from '@/components/tabs/tabs.vue'
import NavBar from '@/components/navbar/navbar.vue' // 导航栏/标签高度(适配不同设备)
const navHeight = ref(44)
const statusTabHeight = ref(88)
const typeTabHeight = ref(88)
// 筛选状态 // 筛选状态
const activeStatus = ref('all') // 全部/待分配/待解决/已完成 const activeStatus = ref('all') // 全部/待分配/待解决/已完成
const activeType = ref('all') // 全部/公共报修/个人报修 const activeType = ref('all') // 全部/公共报修/个人报修
// 状态筛选选项 // 状态筛选选项
const statusTabs = ref([ const statusTabs = ref([
@@ -123,144 +111,101 @@ const typeTabs = ref([
]) ])
// 模拟上报记录数据(实际项目替换为接口请求) // 模拟上报记录数据(实际项目替换为接口请求)
const reportRecords = ref([]) const reportRecords = ref([
{
const queryParmas = ref({ id: 1,
pageNum: 1, title: '标题巴拉巴拉巴拉',
pageSize: 5, status: 'pending', // pending/processing/completed
value: '' reportType: '公共报修',
}) category: '路灯',
const isLoading = ref(false) // 加载锁 content: '1栋楼下道路路灯不亮,并且有的亮度不够,请物业公司及时更换,防止发生意外事故。',
const hasMore = ref(true) // 是否还有更多数据 createTime: '2026-08-01 10:05:46',
const total = ref(21) repairman: ''
function scrolltolower() { },
// 必须加这两个判断! {
if (isLoading.value || !hasMore.value) { id: 2,
return title: '标题巴拉巴拉巴拉',
status: 'processing',
reportType: '公共报修',
category: '路灯',
content: '1栋楼下道路路灯不亮,并且有的亮度不够,请物业公司及时更换,防止发生意外事故。',
createTime: '2026-08-01 10:05:46',
repairman: '张三'
},
{
id: 3,
title: '标题巴拉巴拉巴拉',
status: 'completed',
reportType: '公共报修',
category: '路灯',
content: '1栋楼下道路路灯不亮,并且有的亮度不够,请物业公司及时更换,防止发生意外事故。',
createTime: '2026-08-01 10:05:46',
repairman: '张三'
} }
queryParmas.value.pageNum += 1 ])
getlist()
}
function getlist() {
// 1. 如果正在加载或没有更多数据,直接返回
if (isLoading.value || !hasMore.value) return
// 2. 开启锁
isLoading.value = true
uni.showLoading({
title: '加载中',
mask: true
})
const { pageNum, pageSize } = queryParmas.value
const startId = (pageNum - 1) * pageSize + 1 // 筛选后的记录
const arr = Array.from({ length: pageSize }).map((_, index) => { const filteredRecords = computed(() => {
const realId = startId + index return reportRecords.value.filter(record => {
const randomStatus = Math.floor(Math.random() * 3) // 状态筛选
return { const statusMatch = activeStatus.value === 'all' || record.status === activeStatus.value
id: realId, // 类型筛选
title: '标题巴拉巴拉巴拉', const typeMatch = activeType.value === 'all' || record.reportType === typeTabs.value.find(item => item.value === activeType.value)?.label
status: 'pending', // pending/processing/completed return statusMatch && typeMatch
reportType: '公共报修',
category: '路灯',
content: '1栋楼下道路路灯不亮,并且有的亮度不够,请物业公司及时更换,防止发生意外事故。',
createTime: '2026-08-01 10:05:46',
repairman: '张三' + realId,
images: [
'https://picsum.photos/93',
'https://picsum.photos/93',
'https://picsum.photos/93',
'https://picsum.photos/93',
'https://picsum.photos/93'
],
repairStatus: randomStatus // 0 待分配,1待解决 2已完成
}
}) })
// 追加数据(正确方式) })
reportRecords.value = [...reportRecords.value, ...arr]
// 判断是否还有更多
hasMore.value = reportRecords.value.length < total.value
isLoading.value = false
uni.hideLoading()
}
getlist()
function resetList() {
reportRecords.value = []
queryParmas.value.pageNum = 1
hasMore.value = true
getlist()
}
// 0-------------------------------
// 切换状态(全部/待分配/待解决/已完成)筛选 // 切换状态(全部/待分配/待解决/已完成)筛选
const switchStatus = value => { const switchStatus = (value) => {
activeStatus.value = value activeStatus.value = value
} }
// 切换类型(公共/个人)筛选 // 切换类型(公共/个人)筛选
const switchType = value => { const switchType = (value) => {
activeType.value = value activeType.value = value
} }
const statusMap = ['待分配', '待解决', '已完成']
// 获取状态文本
const getStatusText = status => {
return statusMap[status] || ''
}
// 返回上一页 // 返回上一页
const navBack = () => { const navBack = () => {
uni.switchTab({ uni.navigateBack({
url: '/pages/my/my' delta: 1
}) })
} }
/* 0 待分配,1待解决 2已完成*/
function handleMain(id) { // 获取状态文本
const find = reportRecords.value.find(item => item.id === id) const getStatusText = (status) => {
if (find) { const statusMap = {
const status = find.repairStatus pending: '待分配',
if (status === 2) { processing: '待解决',
uni.navigateTo({ completed: '已完成'
url: `/pageSubPack/ticket/repairMain?id=${id}&showbtn=${false}&path=hall`
})
} else {
uni.navigateTo({
url: `/pageSubPack/ticket/repairMain?id=${id}&showbtn=${false}&path=hall`
})
}
} }
return statusMap[status] || ''
} }
/* 预览图片 */ // 页面渲染完成后适配高度
function handlePrivew(imgs) { onReady(() => {
// if (imgs.length > 0) { // 可根据实际设备调整高度
// uni.previewImage({ uni.getSystemInfo({
// urls: imgs, success: (res) => {
// success(e) { if (res.platform === 'ios') {
// console.log(JSON.stringify(e)) navHeight.value = 44
// } } else {
// }) navHeight.value = 48
// } }
} }
})
})
</script> </script>
<style scoped> <style scoped>
.bgaction {
position: absolute;
right: 0;
top: 20%;
width: 100%;
height: 100%;
z-index: 0;
background: linear-gradient(225deg, #e2f0ff 0%, #f9f9f9 25%);
}
.report-record-page { .report-record-page {
width: 100%;
height: 100vh; height: 100vh;
background: linear-gradient(225deg, #e2f0ff 0%, #f9f9f9 25.71%); background: linear-gradient(to left bottom, #e2efff 0%, #f9f9f9 50%)
} }
.status-bar{
.hall_body { width: 100%;
padding: 0 40rpx; height: 46px;
overflow: hidden;
position: relative;
} }
/* 状态筛选标签 */ /* 状态筛选标签 */
.status-tabs { .status-tabs {
@@ -271,40 +216,66 @@ function handlePrivew(imgs) {
align-items: center; align-items: center;
} }
.status-tab-item {
/* flex: 1; */
display: flex;
justify-content: flex-start;
margin-right: 60rpx;
text-align: left;
font-size: 32rpx;
color: #666;
height: 100%;
line-height: 88rpx;
position: relative;
}
.status-tab-item.active {
color: #4D5DFA;
font-weight: 500;
}
.status-tab-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 80rpx;
height: 8rpx;
background: linear-gradient(to bottom, #4D5DFA, #BAC0FA);
border-radius: 6rpx;
}
/* 类型筛选标签 */ /* 类型筛选标签 */
.type-tabs { .type-tabs {
display: flex; display: flex;
height: 48rpx;
/* background-color: #fff; */ /* background-color: #fff; */
margin: 20rpx 0; padding: 20rpx 0rpx;
margin-top: 10rpx;
justify-content: flex-start; justify-content: flex-start;
gap: 20rpx; gap: 20rpx;
margin: 0rpx 40rpx;
} }
.type-tab-item { .type-tab-item {
width: 142rpx; padding: 7rpx 14rpx;
height: 48rpx;
border-radius: 24rpx;
border: 2rpx solid #999999;
font-weight: 400;
font-size: 28rpx; font-size: 28rpx;
color: #999999; color: #999;
line-height: 48rpx; border: 2rpx solid #999;
text-align: center; border-radius: 198rpx;
} }
.type-tab-item.active { .type-tab-item.active {
color: #4d5dfa; color: #4D5DFA;
border: 2rpx solid #4d5dfa; border: 2rpx solid #4D5DFA;
border-radius: 24rpx; border-radius: 198rpx;
/* background-color: #007AFF; */
} }
/* 记录列表 */ /* 记录列表 */
.record-list { .record-list {
padding: 20rpx 40rpx;
box-sizing: border-box; box-sizing: border-box;
padding-bottom: 40rpx;
overflow: auto;
} }
/* 空状态 */ /* 空状态 */
@@ -327,7 +298,7 @@ function handlePrivew(imgs) {
.record-card { .record-card {
background-color: #fff; background-color: #fff;
border-radius: 16rpx; border-radius: 16rpx;
padding: 34rpx 32rpx; padding: 30rpx;
margin-bottom: 20rpx; margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
} }
@@ -340,81 +311,55 @@ function handlePrivew(imgs) {
} }
.card-title { .card-title {
margin-right: 20rpx;
font-weight: 450;
font-size: 32rpx; font-size: 32rpx;
color: #222222; font-weight: 500;
line-height: 40rpx; color: #333;
margin-right: 20rpx;
} }
/* 状态标签 */ /* 状态标签 */
.status-tag { .status-tag {
width: 82rpx; padding: 6rpx 16rpx;
height: 30rpx;
border-radius: 15rpx;
font-weight: 400;
font-size: 20rpx; font-size: 20rpx;
color: #ffffff; border-radius: 12rpx;
line-height: 30rpx; color: #fff;
text-align: center; border-radius: 198rpx;
line-height: 30rpx;
} }
.status-tag.pending { .status-tag.pending {
background-color: #e34d59; /* 待分配-红色 */ background-color: #E34D59; /* 待分配-红色 */
} }
.status-tag.processing { .status-tag.processing {
background-color: #09c2bd; /* 待解决-绿色 */ background-color: #09C2BD; /* 待解决-绿色 */
} }
.status-tag.completed { .status-tag.completed {
background-color: #4d5dfa; /* 已完成-蓝色 */ background-color: #4D5DFA; /* 已完成-蓝色 */
} }
/* 类型标签组 */ /* 类型标签组 */
.tag-group { .tag-group {
display: flex; display: flex;
gap: 20rpx; gap: 15rpx;
margin-bottom: 20rpx; margin-bottom: 20rpx;
} }
.tag-item { .tag-item {
width: 112rpx; padding: 6rpx 20rpx;
height: 42rpx;
border-radius: 8rpx 8rpx 8rpx 8rpx;
border: 1rpx solid #999999;
font-weight: 400;
font-size: 24rpx; font-size: 24rpx;
color: #999999; color: #666;
line-height: 42rpx; border: 1rpx solid #999;
text-align: center; border-radius: 8rpx;
} }
/* 内容 */ /* 内容 */
.card-content { .card-content {
margin-bottom: 20rpx;
font-weight: 450;
font-size: 28rpx; font-size: 28rpx;
color: #666666; color: #666;
line-height: 40rpx; line-height: 1.6;
letter-spacing: 2rpx;
}
/* 图片 */
.card-image {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20rpx;
min-width: 186rpx;
min-height: 104rpx;
margin-bottom: 20rpx; margin-bottom: 20rpx;
} }
.images {
width: 186rpx;
height: 104rpx;
}
/* 底部信息 */ /* 底部信息 */
.card-footer { .card-footer {
@@ -423,21 +368,9 @@ function handlePrivew(imgs) {
align-items: center; align-items: center;
font-size: 28rpx; font-size: 28rpx;
color: #999; color: #999;
font-weight: 400;
font-size: 28rpx;
line-height: 40rpx;
} }
.share {
width: 127rpx;
height: 44rpx;
background: #4d5dfa;
border-radius: 22rpx;
font-weight: 400; .repairman {
font-size: 28rpx; color: #999;
color: #ffffff;
line-height: 44rpx;
text-align: center;
} }
</style> </style>

View File

@@ -44,7 +44,7 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, onUnmounted } from 'vue'; import { ref, computed, onUnmounted } from 'vue';
import {getSendCode} from '../../api/api.js' import {getSendCode,changePhone} from '../../api/api.js'
// ====响应式数据====== // ====响应式数据======
const phoneNumber = ref('') const phoneNumber = ref('')
@@ -66,7 +66,7 @@ const getVerifyCode = () => {
if (!canGetVerify.value) return; if (!canGetVerify.value) return;
let params = { let params = {
phone:phoneNumber.value, phone:phoneNumber.value,
scene:'reset' scene:'butler_login'
} }
getSendCode(params).then(res =>{ getSendCode(params).then(res =>{
if(res.code === 200){ if(res.code === 200){
@@ -103,21 +103,34 @@ const canRegister = computed(() => {
&& verifyReg.test(verifyCode.value) && verifyReg.test(verifyCode.value)
}); });
// 确认 // 确认
const handleConfirm = () =>{ const handleConfirm = () => {
// 把参数存到本地缓存 if (!canRegister.value) {
uni.setStorageSync('tempChangePwdParams', { uni.showToast({ title: '请输入正确的手机号和验证码', icon: 'none' })
phoneNumber:phoneNumber.value, return
verifyCode: verifyCode.value }
});
if(!canRegister.value){ uni.showLoading({ title: '提交中...' })
uni.showToast({ title: '请输入',icon: 'error'}); changePhone({
return phone: phoneNumber.value,
} smsCode: verifyCode.value
setTimeout(()=>{ }).then(res => {
uni.navigateTo({ if (res.code === 200) {
url:"/pageSubPack/setting/setting" uni.showToast({ title: '修改成功', icon: 'success' })
}) // 把参数存到本地缓存
}) uni.setStorageSync('tempChangePwdParams', {
phoneNumber:phoneNumber.value
});
setTimeout(() => {
uni.navigateBack()
}, 800)
} else {
uni.showToast({ title: res.msg || '修改失败', icon: 'none' })
}
}).catch(() => {
uni.showToast({ title: '请求失败,请重试', icon: 'none' })
}).finally(() => {
uni.hideLoading()
})
} }
// 返回上一页 // 返回上一页
// const goBack = () => { // const goBack = () => {

View File

@@ -38,16 +38,15 @@
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app' import { onShow } from '@dcloudio/uni-app'
import { logout } from '../../api/api.js'
// 响应式数据 // 响应式数据
const phoneNumber = ref('') // 绑定手机号 const phoneNumber = ref('') // 绑定手机号
const passwordNumber = ref('') const passwordNumber = ref('')
// 页面加载时可从接口获取用户信息 // 页面显示时读取最新数据(从修改页返回也会触发)
onLoad(option => { onShow(() => {
// console.log('option',option)
passwordNumber.value = option.newPassword
const userInfo = uni.getStorageSync('tempChangePwdParams') const userInfo = uni.getStorageSync('tempChangePwdParams')
if (userInfo.phoneNumber) { if (userInfo.phoneNumber) {
phoneNumber.value = userInfo.phoneNumber phoneNumber.value = userInfo.phoneNumber
@@ -92,25 +91,21 @@ const handleLogout = () => {
// 确认退出登录 // 确认退出登录
const confirmLogout = () => { const confirmLogout = () => {
// 模拟退出登录接口请求
uni.showLoading({ title: '退出中...' }) uni.showLoading({ title: '退出中...' })
setTimeout(() => { logout().then(res => {
if (res.code === 200) {
uni.clearStorageSync()
uni.showToast({ title: '退出登录成功', icon: 'success' })
uni.redirectTo({ url: '/pageSubPack/loginSub/pwd-login' })
} else {
uni.showToast({ title: res.msg || '退出失败', icon: 'none' })
}
}).catch(() => {
uni.showToast({ title: '退出失败,请重试', icon: 'none' })
}).finally(() => {
uni.hideLoading() uni.hideLoading()
// 清除本地存储的token等信息 })
uni.clearStorageSync()
// 提示并跳转到登录页
uni.showToast({
title: '退出登录成功',
icon: 'success'
})
// 跳转到登录页,关闭所有页面
uni.redirectTo({
url: '/pageSubPack/loginSub/pwd-login'
})
}, 800)
} }
</script> </script>