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

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,15 +1,26 @@
<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"
:border= "false"
@clickLeft="navBack"/>
<!-- 状态筛选标签 --> <!-- 状态筛选标签 -->
<TabsComponents <view class="status-tabs">
:tabslist="statusTabs" <view
:options="{ label: 'label', value: 'value' }" v-for="item in statusTabs"
@update="switchStatus" :key="item.value"
></TabsComponents> class="status-tab-item"
:class="{ active: activeStatus === item.value }"
@tap="switchStatus(item.value)"
>
{{ item.label }}
</view>
</view>
<!-- 类型筛选标签 --> <!-- 类型筛选标签 -->
<view class="type-tabs"> <view class="type-tabs">
@@ -26,35 +37,27 @@
<!-- 上报记录列表 --> <!-- 上报记录列表 -->
<scroll-view <scroll-view
class="record-list flex-1" class="record-list"
scroll-y scroll-y
lower-threshold="60" :style="{ height: `calc(100vh - ${navHeight + statusTabHeight + typeTabHeight}px)` }"
@scrolltolower="scrolltolower"
> >
<!-- 空状态 --> <!-- 空状态 -->
<view v-if="reportRecords.length === 0" class="empty-state"> <view v-if="filteredRecords.length === 0" class="empty-state">
<uni-icons type="empty" size="60" color="#ccc"></uni-icons> <uni-icons type="empty" size="60" color="#ccc"></uni-icons>
<text class="empty-text">暂无上报记录</text> <text class="empty-text">暂无上报记录</text>
</view> </view>
<!-- 记录卡片 --> <!-- 记录卡片 -->
<view <view
v-for="(record, index) in reportRecords" v-for="record in filteredRecords"
:key="index" :key="record.id"
class="record-card" class="record-card"
@tap="handleMain(record.id)"
> >
<!-- 标题 + 状态标签 --> <!-- 标题 + 状态标签 -->
<view class="card-header"> <view class="card-header">
<text class="card-title">{{ record.title }}</text> <text class="card-title">{{ record.title }}</text>
<view <view class="status-tag" :class="record.status">
class="status-tag" {{ getStatusText(record.status) }}
:class="{
pending: record.repairStatus === 0,
processing: record.repairStatus === 1,
completed: record.repairStatus === 2
}"
>
{{ getStatusText(record.repairStatus) }}
</view> </view>
</view> </view>
@@ -68,40 +71,25 @@
<view class="card-content"> <view class="card-content">
{{ record.content }} {{ record.content }}
</view> </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"> <view class="card-footer">
<text class="create-time">{{ record.createTime }}</text> <text class="create-time">{{ record.createTime }}</text>
<text v-if="record.repairStatus !== 0" class="repairman" <text v-if="record.repairman" class="repairman">维修师傅:{{ record.repairman }}</text>
>维修师傅:{{ record.repairman }}</text
>
<!-- <view class="share" v-if="record.repairStatus === 0">
<text>分配</text>
</view> -->
</view> </view>
</view> </view>
</scroll-view> </scroll-view>
</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') // 全部/待分配/待解决/已完成
@@ -123,144 +111,101 @@ const typeTabs = ref([
]) ])
// 模拟上报记录数据(实际项目替换为接口请求) // 模拟上报记录数据(实际项目替换为接口请求)
const reportRecords = ref([]) const reportRecords = ref([
{
const queryParmas = ref({ id: 1,
pageNum: 1,
pageSize: 5,
value: ''
})
const isLoading = ref(false) // 加载锁
const hasMore = ref(true) // 是否还有更多数据
const total = ref(21)
function scrolltolower() {
// 必须加这两个判断!
if (isLoading.value || !hasMore.value) {
return
}
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 realId = startId + index
const randomStatus = Math.floor(Math.random() * 3)
return {
id: realId,
title: '标题巴拉巴拉巴拉', title: '标题巴拉巴拉巴拉',
status: 'pending', // pending/processing/completed status: 'pending', // pending/processing/completed
reportType: '公共报修', reportType: '公共报修',
category: '路灯', category: '路灯',
content: '1栋楼下道路路灯不亮,并且有的亮度不够,请物业公司及时更换,防止发生意外事故。', content: '1栋楼下道路路灯不亮,并且有的亮度不够,请物业公司及时更换,防止发生意外事故。',
createTime: '2026-08-01 10:05:46', createTime: '2026-08-01 10:05:46',
repairman: '张三' + realId, repairman: ''
images: [ },
'https://picsum.photos/93', {
'https://picsum.photos/93', id: 2,
'https://picsum.photos/93', title: '标题巴拉巴拉巴拉',
'https://picsum.photos/93', status: 'processing',
'https://picsum.photos/93' reportType: '公共报修',
], category: '路灯',
repairStatus: randomStatus // 0 待分配,1待解决 2已完成 content: '1栋楼下道路路灯不亮,并且有的亮度不够,请物业公司及时更换,防止发生意外事故。',
} createTime: '2026-08-01 10:05:46',
}) repairman: '张三'
// 追加数据(正确方式) },
reportRecords.value = [...reportRecords.value, ...arr] {
// 判断是否还有更多 id: 3,
hasMore.value = reportRecords.value.length < total.value title: '标题巴拉巴拉巴拉',
isLoading.value = false status: 'completed',
uni.hideLoading() reportType: '公共报修',
} category: '路灯',
getlist() content: '1栋楼下道路路灯不亮,并且有的亮度不够,请物业公司及时更换,防止发生意外事故。',
function resetList() { createTime: '2026-08-01 10:05:46',
reportRecords.value = [] repairman: '张三'
queryParmas.value.pageNum = 1
hasMore.value = true
getlist()
} }
])
// 筛选后的记录
const filteredRecords = computed(() => {
return reportRecords.value.filter(record => {
// 状态筛选
const statusMatch = activeStatus.value === 'all' || record.status === activeStatus.value
// 类型筛选
const typeMatch = activeType.value === 'all' || record.reportType === typeTabs.value.find(item => item.value === activeType.value)?.label
return statusMatch && typeMatch
})
})
// 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)
if (find) {
const status = find.repairStatus
if (status === 2) {
uni.navigateTo({
url: `/pageSubPack/ticket/repairMain?id=${id}&showbtn=${false}&path=hall`
})
} else {
uni.navigateTo({
url: `/pageSubPack/ticket/repairMain?id=${id}&showbtn=${false}&path=hall`
})
}
}
}
/* 预览图片 */ // 获取状态文本
function handlePrivew(imgs) { const getStatusText = (status) => {
// if (imgs.length > 0) { const statusMap = {
// uni.previewImage({ pending: '待分配',
// urls: imgs, processing: '待解决',
// success(e) { completed: '已完成'
// console.log(JSON.stringify(e))
// }
// })
// }
} }
return statusMap[status] || ''
}
// 页面渲染完成后适配高度
onReady(() => {
// 可根据实际设备调整高度
uni.getSystemInfo({
success: (res) => {
if (res.platform === 'ios') {
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){
@@ -104,19 +104,32 @@ const canRegister = computed(() => {
}); });
// 确认 // 确认
const handleConfirm = () => { const handleConfirm = () => {
// 把参数存到本地缓存
uni.setStorageSync('tempChangePwdParams', {
phoneNumber:phoneNumber.value,
verifyCode: verifyCode.value
});
if (!canRegister.value) { if (!canRegister.value) {
uni.showToast({ title: '请输入',icon: 'error'}); uni.showToast({ title: '请输入正确的手机号和验证码', icon: 'none' })
return return
} }
uni.showLoading({ title: '提交中...' })
changePhone({
phone: phoneNumber.value,
smsCode: verifyCode.value
}).then(res => {
if (res.code === 200) {
uni.showToast({ title: '修改成功', icon: 'success' })
// 把参数存到本地缓存
uni.setStorageSync('tempChangePwdParams', {
phoneNumber:phoneNumber.value
});
setTimeout(() => { setTimeout(() => {
uni.navigateTo({ uni.navigateBack()
url:"/pageSubPack/setting/setting" }, 800)
}) } else {
uni.showToast({ title: res.msg || '修改失败', icon: 'none' })
}
}).catch(() => {
uni.showToast({ title: '请求失败,请重试', icon: 'none' })
}).finally(() => {
uni.hideLoading()
}) })
} }
// 返回上一页 // 返回上一页

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 => {
uni.hideLoading() if (res.code === 200) {
// 清除本地存储的token等信息
uni.clearStorageSync() uni.clearStorageSync()
uni.showToast({ title: '退出登录成功', icon: 'success' })
// 提示并跳转到登录页 uni.redirectTo({ url: '/pageSubPack/loginSub/pwd-login' })
uni.showToast({ } else {
title: '退出登录成功', uni.showToast({ title: res.msg || '退出失败', icon: 'none' })
icon: 'success' }
}).catch(() => {
uni.showToast({ title: '退出失败,请重试', icon: 'none' })
}).finally(() => {
uni.hideLoading()
}) })
// 跳转到登录页,关闭所有页面
uni.redirectTo({
url: '/pageSubPack/loginSub/pwd-login'
})
}, 800)
} }
</script> </script>