# Conflicts:
#	property-uniapp-project/manifest.json
#	property-uniapp-project/pageSubPack/api/request.js
This commit is contained in:
wangyuxin
2026-04-30 08:33:11 +08:00
25 changed files with 1766 additions and 1217 deletions

View File

@@ -8,7 +8,9 @@
}, },
onHide: function() { onHide: function() {
console.log('App Hide') console.log('App Hide')
} },
} }
</script> </script>

View File

@@ -1,5 +1,6 @@
<template> <template>
<view class="container"> <view class="container">
<view class="status_bar"></view>
<!-- 顶部导航栏 --> <!-- 顶部导航栏 -->
<view class="nav-bar"> <view class="nav-bar">
<view class="nav-left" @tap="goBack"> <view class="nav-left" @tap="goBack">
@@ -8,10 +9,10 @@
<view class="nav-title">{{navTitle}}</view> <view class="nav-title">{{navTitle}}</view>
<view class="nav-right"></view> <view class="nav-right"></view>
</view> </view>
<view style="status_bar"></view>
<!-- 内容区域 --> <!-- 内容区域 -->
<scroll-view class="content" scroll-y> <scroll-view class="scroll-content" scroll-y="true">
<!-- 选项卡 --> <!-- 选项卡 -->
<view class="tabs"> <view class="tabs">
<view <view
@@ -36,51 +37,51 @@
<view class="info-section"> <view class="info-section">
<view class="info-item"> <view class="info-item">
<view class="info-label">报名截止时间</view> <view class="info-label">报名截止时间</view>
<view class="info-value">2023-08-08 23:00</view> <view class="info-value">{{formatTime(activityConent.applyDeadline)}}</view>
</view> </view>
<view class="info-item"> <view class="info-item">
<view class="info-label">活动时间</view> <view class="info-label">活动时间</view>
<view class="info-value"> <view class="info-value">
<text>2023-08-09 10:00 2023-08-20 16:00</text> <text>{{formatTime(activityConent.startTime)}} {{formatTime(activityConent.endTime)}}</text>
</view> </view>
</view> </view>
<view class="info-item"> <view class="info-item">
<view class="info-label">签到时间</view> <view class="info-label">签到时间</view>
<view class="info-value"> <view class="info-value">
<text>2023-08-09 10:00 2023-08-10 16:00</text> <text>{{formatTime(activityConent.signinStartTime)}} {{formatTime(activityConent.signinEndTime)}}</text>
</view> </view>
</view> </view>
<view class="info-item"> <view class="info-item">
<view class="info-label">活动地点</view> <view class="info-label">活动地点</view>
<view class="info-value">山东省日照市高新区高新管委会大厦前高新公园</view> <view class="info-value">{{activityConent.address}}</view>
</view> </view>
<view class="info-item"> <view class="info-item">
<view class="info-label">活动名额</view> <view class="info-label">活动名额</view>
<view class="info-value">10</view> <view class="info-value">{{activityConent.quota}}</view>
</view> </view>
<view class="info-item"> <view class="info-item">
<view class="info-label">主办方</view> <view class="info-label">主办方</view>
<view class="info-value">山海天社区</view> <view class="info-value">{{activityConent.organizer}}</view>
</view> </view>
<view class="info-item"> <view class="info-item">
<view class="info-label">联系人</view> <view class="info-label">联系人</view>
<view class="info-value">赵璐</view> <view class="info-value">{{activityConent.contactName}}</view>
</view> </view>
<view class="info-item"> <view class="info-item">
<view class="info-label">联系电话</view> <view class="info-label">联系电话</view>
<view class="info-value">15799999999</view> <view class="info-value">{{activityConent.contactPhone}}</view>
</view> </view>
<view class="info-item"> <view class="info-item">
<view class="info-label">积分奖励</view> <view class="info-label">积分奖励</view>
<view class="info-value">100</view> <view class="info-value">{{activityConent.pointsReward}}</view>
</view> </view>
</view> </view>
@@ -88,7 +89,7 @@
<view class="section"> <view class="section">
<view class="section-title">招募要求</view> <view class="section-title">招募要求</view>
<view class="section-content"> <view class="section-content">
要求就是要求就是要求就是 {{activityConent.requirements}}
</view> </view>
</view> </view>
@@ -96,8 +97,8 @@
<view class="section" style="margin-bottom: 40rpx;"> <view class="section" style="margin-bottom: 40rpx;">
<view class="section-title">活动详情</view> <view class="section-title">活动详情</view>
<view class="section-content"> <view class="section-content">
<view>1这就是活动详情zhejiushihuodongxiangqing这就是活动详情zhejiushihuodongxiangqing</view> <view>{{activityConent.content || "暂无"}}</view>
<view>2活动详情zhejiushuodongxiangqing</view> <view></view>
</view> </view>
</view> </view>
</view> </view>
@@ -106,7 +107,7 @@
<view v-else class="status-content"> <view v-else class="status-content">
<view class="status-header"> <view class="status-header">
<view class="status-title"> <view class="status-title">
<image src="http://47.104.199.163:9090/images/activity/liveScene.png" style="width: 40rpx;height: 30rpx;"></image> <image src="http://47.104.199.163:9090/images/activity/liveScene.png" style="width: 38rpx;height: 23rpx;"></image>
现场实况 现场实况
</view> </view>
<view class="status-count">{{ liveRecords.length }}</view> <view class="status-count">{{ liveRecords.length }}</view>
@@ -165,16 +166,9 @@
> >
取消报名 取消报名
</button> </button>
<button class="action-btn add-status-btn" v-if="activeTab === 'status'" @click="liveClick">添加实况</button>
<!-- 活动实况页显示添加实况按钮 -->
<!-- 已报名且在活动实况页显示添加实况按钮 --> <button class="action-btn add-status-btn" v-if="hasSigned &&activeTab === 'status'" @click="liveClick">添加实况</button>
<!-- <button
v-if="hasSigned && activeTab === 'status'"
class="action-btn add-status-btn"
@tap="handleAddStatus"
>
添加实况
</button> -->
</view> </view>
<!-- 报名确认模态框 --> <!-- 报名确认模态框 -->
@@ -182,7 +176,7 @@
<view class="modal-content"> <view class="modal-content">
<view class="modal-header">报名确认</view> <view class="modal-header">报名确认</view>
<view class="modal-body"> <view class="modal-body">
<view>确定要报名参加"社区'小槐花课堂'开课了"</view> <view>{{navTitle}}</view>
<view class="modal-tip">报名后请按时参加活动</view> <view class="modal-tip">报名后请按时参加活动</view>
</view> </view>
<view class="modal-footer"> <view class="modal-footer">
@@ -197,7 +191,7 @@
<view class="modal-content"> <view class="modal-content">
<view class="modal-header">取消报名</view> <view class="modal-header">取消报名</view>
<view class="modal-body"> <view class="modal-body">
<view>确定要取消报名"社区'小槐花课堂'开课了"</view> <view>{{navTitle}}</view>
<view class="modal-tip">取消后如需参加需重新报名</view> <view class="modal-tip">取消后如需参加需重新报名</view>
</view> </view>
<view class="modal-footer"> <view class="modal-footer">
@@ -216,44 +210,89 @@
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import {onLoad} from '@dcloudio/uni-app' import {onLoad,onUnload} from '@dcloudio/uni-app'
import moment from 'moment' import moment from 'moment'
import {getActivityDetails,confirmResident,cancelActivity,getActivityLive} from '../api/api.js'
// 响应式数据 // 响应式数据
const activeTab = ref('detail') // 'detail' 或 'status' const activeTab = ref('detail') // 'detail' 或 'status'
const hasSigned = ref(false) // 是否已报名 const hasSigned = ref(false) // 是否已报名
const showSignupModal = ref(false) const showSignupModal = ref(false)
const showCancelModal = ref(false) const showCancelModal = ref(false)
// const showAddStatusModal = ref(false)
const showToast = ref(false) const showToast = ref(false)
const toastMessage = ref('') const toastMessage = ref('')
const newStatusContent = ref('') const newStatusContent = ref('')
// const newStatusImages = ref([])
const navTitle = ref('') const navTitle = ref('')
const curActivityId = ref('') // 当前活动的id
const activityConent = ref({}) // 获取详情数据
// 实况记录数据 // 实况记录数据
const liveRecords = ref([ const liveRecords = ref([
{ // {
id: 1, // id: 1,
user: '微信用户', // user: '微信用户',
time: '2023-08-20 16:00:02', // time: '2023-08-20 16:00:02',
content: '参与活动打卡', // content: '参与活动打卡',
images: [] // images: []
}, // },
{ // {
id: 2, // id: 2,
user: '微信用户', // user: '微信用户',
time: '2023-08-20 16:20:02', // time: '2023-08-20 16:20:02',
content: '目前现场的互动氛围很好', // content: '目前现场的互动氛围很好',
images: ['http://47.104.199.163:9090/images/logo.png', 'http://47.104.199.163:9090/images/repair/house1.png'] // images: ['http://47.104.199.163:9090/images/logo.png', 'http://47.104.199.163:9090/images/repair/house1.png']
} // }
]) ])
// 接受参数
// ========方法=====
// 时间格式化函数
const formatTime = (timeStr) => {
if (!timeStr) return ''
return moment(timeStr).format('YYYY-MM-DD HH:mm')
}
// ---接收参数---
onLoad((option) =>{ onLoad((option) =>{
// console.log('dsdsds',option) navTitle.value = option?.title
navTitle.value = option.title curActivityId.value = option?.id
// 处理applied参数可能是字符串类型需要转布尔
hasSigned.value = option?.applied === 'true' || option?.applied === true
// console.log('hasSigned.value',hasSigned.value)
// 2. 初始化数据
if (curActivityId.value) {
getActivityDetailsData(curActivityId.value) // 获取活动详情
getLiveActivityList() // 获取实况列表
}
// 3. 监听实况列表刷新事件
uni.$on('refreshLiveList', () => {
getLiveActivityList()
})
}) })
// 获取列表详情
const getActivityDetailsData = async (id) =>{
try{
const res = await getActivityDetails(id)
if(res.code === 200){
activityConent.value = res.data || {}
}else{
activityConent.value = {}
uni.showToast({
title: res.msg ||"详情获取失败",
icon:"error"
})
}
}catch(err){
uni.showToast({
title: "网络异常",
icon:"none"
})
// console.error('获取活动详情失败:', err)
}
}
// 切换选项卡 // 切换选项卡
const switchTab = (tab) => { const switchTab = (tab) => {
activeTab.value = tab activeTab.value = tab
@@ -276,12 +315,40 @@ const hideSignupModal = () => {
// 确认报名 // 确认报名
const confirmSignup = () => { const confirmSignup = () => {
hasSigned.value = true confirmRegist()
hideSignupModal() hideSignupModal()
showToastMessage('报名成功!') }
// 模拟更新名额 // 确认报名接口
// 在实际应用中这里应该调用API更新后端数据 const confirmRegist = async () =>{
try{
const res = await confirmResident(curActivityId.value)
if(res.code === 200){
hasSigned.value = true // 报名成功后更新状态
uni.showToast({
title: '报名成功',
icon:"success"
})
setTimeout(() =>{
uni.$emit('refreshActivityList', {
activityId: curActivityId.value,
isSigned: true
})
uni.navigateBack()
},1500)
}else{
uni.showToast({
title: res.msg || "报名失败",
icon:"error"
})
}
}catch(err){
uni.showToast({
title: "网络异常",
icon:"none"
})
// console.error('报名失败:', err)
}
} }
// 处理取消报名 // 处理取消报名
@@ -294,28 +361,79 @@ const hideCancelModal = () => {
showCancelModal.value = false showCancelModal.value = false
} }
// 确认取消报名 // 确认取消报名
const confirmCancel = () => { const confirmCancel = () => {
hasSigned.value = false hasSigned.value = false // 取消报名后更新状态
cancelActivityData()
hideCancelModal() hideCancelModal()
showToastMessage('已取消报名') // showToastMessage('已取消报名')
// 模拟更新名额
// 在实际应用中这里应该调用API更新后端数据
} }
// 确认取消报名接口
const cancelActivityData = async () =>{
try{
const res = await cancelActivity(curActivityId.value)
if(res.code === 200){
hasSigned.value = false // 报名成功后更新状态
uni.showToast({
title: '取消报名成功',
icon:"success"
})
setTimeout(() =>{
uni.$emit('refreshActivityList', {
activityId: curActivityId.value,
isSigned: false
})
uni.navigateBack()
},1500)
}else{
uni.showToast({
title: res.msg || "取消报名失败",
icon:"error"
})
}
}catch(err){
uni.showToast({
title: "网络异常",
icon:"none"
})
}
}
// -----获取活动实况列表----
const getLiveActivityList = async () =>{
try{
const res = await getActivityLive(curActivityId.value)
if(res.code === 200){
liveRecords.value = res.rows || []
}else{
liveRecords.value = []
uni.showToast({
title: res.msg ||"实况列表获取失败",
icon:"error"
})
}
}catch(err){
uni.showToast({
title: "网络异常",
icon:"none"
})
}
}
// 添加实况跳转 // 添加实况跳转
const liveClick = () =>{ const liveClick = () =>{
uni.navigateTo({ uni.navigateTo({
url:'/pageSubPack/activity-list/live-add' url:`/pageSubPack/activity-list/live-add?id=${curActivityId.value}`
}) })
} }
// 监听实况列表刷新
// ---------
// 获取当前时间 onUnload(() => {
const getCurrentTime = () => { uni.$off('refreshLiveList')
return moment(date).format('YYYY-MM-DD HH:mm:ss') })
}
// 显示提示信息 // 显示提示信息
const showToastMessage = (message) => { const showToastMessage = (message) => {
@@ -327,17 +445,11 @@ const showToastMessage = (message) => {
}, 2000) }, 2000)
} }
// 初始化
onMounted(() => {
// 模拟检查用户是否已报名
// 实际项目中应该从接口获取
setTimeout(() => {
hasSigned.value = false // 默认未报名
}, 100)
})
</script> </script>
<style> <style scoped>
/* 页面容器 */ /* 页面容器 */
.container { .container {
min-height: 100vh; min-height: 100vh;
@@ -345,11 +457,15 @@ onMounted(() => {
flex-direction: column; flex-direction: column;
background: linear-gradient(to bottom left, #E2F0FF 0%, #ffffff 50%) background: linear-gradient(to bottom left, #E2F0FF 0%, #ffffff 50%)
} }
/* 状态栏 */
.status_bar {
height: 46px;
width: 100%;
}
/* 顶部导航栏 */ /* 顶部导航栏 */
.nav-bar { .nav-bar {
height: 90rpx; height: 90rpx;
/* background: linear-gradient(135deg, #007AFF 0%, #0056cc 100%); */
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0 30rpx; padding: 0 30rpx;
@@ -357,7 +473,6 @@ onMounted(() => {
position: sticky; position: sticky;
top: 44px; top: 44px;
z-index: 100; z-index: 100;
/* box-shadow: 0 4rpx 12rpx rgba(0, 122, 255, 0.2); */
} }
.nav-left { .nav-left {
@@ -370,7 +485,7 @@ onMounted(() => {
.nav-title { .nav-title {
flex: 1; flex: 1;
text-align: left; text-align: left;
font-size: 36rpx; font-size: 32rpx;
font-weight: 600; font-weight: 600;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -383,28 +498,22 @@ onMounted(() => {
width: 60rpx; width: 60rpx;
} }
/* 内容区域 */ /* 滚动内容区域 */
.content { .scroll-content {
flex: 1; flex: 1;
width: 100%;
box-sizing: border-box;
overflow-y: auto;
margin-bottom: 120rpx; margin-bottom: 120rpx;
} }
.status_bar {
height: 46px;
width: 100%;
}
/* 选项卡 */ /* 选项卡 */
.tabs { .tabs {
display: flex; display: flex;
/* background-color: #fff; */
border-bottom: 1rpx solid #e9ecef; border-bottom: 1rpx solid #e9ecef;
position: sticky;
top: 90rpx;
z-index: 90;
} }
.tab-item { .tab-item {
/* flex: 1; */
text-align: center; text-align: center;
padding: 30rpx 35rpx; padding: 30rpx 35rpx;
font-size: 32rpx; font-size: 32rpx;
@@ -418,31 +527,15 @@ onMounted(() => {
font-weight: 600; font-weight: 600;
} }
/* .tab-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 80rpx;
height: 6rpx;
background: linear-gradient(90deg, #007AFF, #00aaff);
border-radius: 3rpx 3rpx 0 0;
} */
/* 活动详情内容 */ /* 活动详情内容 */
.detail-content { .detail-content {
/* padding: 30rpx; */ padding: 0;
margin-top: 89rpx;
} }
/* 基本信息区域 */ /* 基本信息区域 */
.info-section { .info-section {
/* background-color: #fff; */
border-radius: 16rpx; border-radius: 16rpx;
padding: 30rpx; padding: 30rpx 40rpx;
/* margin-bottom: 30rpx; */
/* box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); */
} }
.info-item { .info-item {
@@ -471,14 +564,13 @@ onMounted(() => {
color: #222; color: #222;
font-weight: 500; font-weight: 500;
line-height: 1.4; line-height: 1.4;
text-align: right;
} }
/* 区块样式 */ /* 区块样式 */
.section { .section {
/* background-color: #fff; */
border-radius: 16rpx; border-radius: 16rpx;
padding: 30rpx; padding: 30rpx 40rpx;
/* margin-bottom: 30rpx; */
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
} }
@@ -515,12 +607,9 @@ onMounted(() => {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
/* background-color: #fff; */
border-radius: 16rpx; border-radius: 16rpx;
padding: 30rpx; padding: 30rpx;
margin-bottom: 30rpx; margin-bottom: 30rpx;
margin-top: 80rpx;
/* box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); */
} }
.status-title { .status-title {
@@ -532,19 +621,16 @@ onMounted(() => {
.status-count { .status-count {
padding: 8rpx 20rpx; padding: 8rpx 20rpx;
/* background-color: #007AFF; */
color: #666; color: #666;
font-size: 24rpx; font-size: 28rpx;
border-radius: 20rpx; border-radius: 20rpx;
font-weight: 500; font-weight: 500;
} }
/* 实况列表 */ /* 实况列表 */
.record-list { .record-list {
/* background-color: #fff; */
border-radius: 16rpx; border-radius: 16rpx;
overflow: hidden; overflow: hidden;
/* box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); */
} }
.record-item { .record-item {
@@ -552,10 +638,6 @@ onMounted(() => {
border-bottom: 1rpx solid #f0f0f0; border-bottom: 1rpx solid #f0f0f0;
} }
/* .record-item:last-child {
border-bottom: none;
} */
.record-user { .record-user {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
@@ -576,11 +658,9 @@ onMounted(() => {
} }
.user-info { .user-info {
/* flex: 1; */
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-start; justify-content: flex-start;
} }
.user-name { .user-name {
@@ -599,7 +679,6 @@ onMounted(() => {
font-size: 28rpx; font-size: 28rpx;
color: #333; color: #333;
line-height: 1.5; line-height: 1.5;
/* margin-bottom: 20rpx; */
margin: 25rpx 0rpx; margin: 25rpx 0rpx;
} }
@@ -612,7 +691,7 @@ onMounted(() => {
.image-item { .image-item {
width: 150rpx; width: 150rpx;
height: 170rpx; height: 150rpx;
border-radius: 12rpx; border-radius: 12rpx;
background-color: #f8f9fa; background-color: #f8f9fa;
background-size: cover; background-size: cover;
@@ -774,97 +853,6 @@ onMounted(() => {
background-color: #f0f7ff; background-color: #f0f7ff;
} }
/* 添加实况模态框 */
.add-status-modal {
width: 650rpx;
}
.status-input {
width: 100%;
min-height: 200rpx;
padding: 20rpx;
font-size: 28rpx;
color: #333;
background-color: #f8f9fa;
border-radius: 12rpx;
border: 1rpx solid #e9ecef;
margin-bottom: 20rpx;
}
.input-counter {
text-align: right;
font-size: 24rpx;
color: #999;
margin-bottom: 30rpx;
}
.image-upload-area {
margin-top: 30rpx;
}
.upload-tip {
font-size: 24rpx;
color: #999;
margin-bottom: 20rpx;
text-align: left;
}
.image-preview {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
.preview-item {
position: relative;
width: 150rpx;
height: 150rpx;
border-radius: 12rpx;
overflow: hidden;
}
.preview-image {
width: 100%;
height: 100%;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-color: #f8f9fa;
}
.remove-btn {
position: absolute;
top: 0;
right: 0;
width: 40rpx;
height: 40rpx;
background-color: rgba(0, 0, 0, 0.6);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
border-radius: 0 0 0 12rpx;
}
.upload-btn {
width: 150rpx;
height: 150rpx;
border: 2rpx dashed #e9ecef;
border-radius: 12rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #999;
background-color: #f8f9fa;
}
.upload-text {
font-size: 24rpx;
margin-top: 10rpx;
}
/* 提示信息 */ /* 提示信息 */
.toast { .toast {
position: fixed; position: fixed;

View File

@@ -54,16 +54,27 @@
<script setup> <script setup>
import { ref } from 'vue'; import { ref } from 'vue';
// import { chooseImage, uploadFile, getLocation } from '@dcloudio/uni-app'; import { onLoad } from '@dcloudio/uni-app';
import { addActivityLive, signinActivityLive, uploadImage } from '../api/api.js';
// 活动ID
const activityId = ref('');
// 实况描述内容 // 实况描述内容
const statusDesc = ref(''); const statusDesc = ref('');
// 输入字符长度 // 输入字符长度
const currentLength = ref(0); const currentLength = ref(0);
// 图片列表 // 图片列表(本地临时路径)
const imgList = ref([]); const imgList = ref([]);
// 定位信息 // 定位信息
const location = ref('山东省日照市东港区学院路'); const location = ref('山东省日照市东港区学院路');
// 经纬度
const longitude = ref('');
const latitude = ref('');
// 接收活动ID
onLoad((option) => {
activityId.value = option?.id || '';
});
// 监听输入框字数变化 // 监听输入框字数变化
const handleTextInput = (e) => { const handleTextInput = (e) => {
@@ -73,11 +84,10 @@ const handleTextInput = (e) => {
// 选择图片 // 选择图片
const chooseImg = () => { const chooseImg = () => {
uni.chooseImage({ uni.chooseImage({
count: 3 - imgList.value.length, // 最多可选择的数量 count: 3 - imgList.value.length,
sizeType: ['original', 'compressed'], sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'], sourceType: ['album', 'camera'],
success: (res) => { success: (res) => {
// 临时文件路径转存到图片列表
imgList.value = [...imgList.value, ...res.tempFilePaths]; imgList.value = [...imgList.value, ...res.tempFilePaths];
}, },
fail: (err) => { fail: (err) => {
@@ -88,57 +98,104 @@ const chooseImg = () => {
}; };
// 删除图片 // 删除图片
const deleteImg = (index) => { const deleteImg = (index) => {
imgList.value.splice(index, 1); imgList.value.splice(index, 1);
}; };
// 重新定位 // 重新定位
// 定位并获取具体地点名称
const reLocate = () => { const reLocate = () => {
uni.showLoading({ title: '定位中...' }); // 调用微信原生选择位置接口(自带地址解析,无调用上限)
uni.getLocation({ uni.chooseLocation({
type: 'gcj02',
success: (res) => { success: (res) => {
uni.hideLoading(); // res.address = 具体地址XX市XX区XX街道XX小区
// 实际项目中可调用逆地理编码接口转换为具体地址,这里模拟 // res.name = 地点名称XX小区
location.value = '山东省日照市东港区学院路(新定位)'; longitude.value = res.longitude;
uni.showToast({ title: '定位成功', icon: 'success' }); latitude.value = res.latitude;
location.value = res.address; // 显示具体地址
uni.showToast({ title: `定位成功:${res.name}`, icon: 'success' });
}, },
fail: (err) => { fail: (err) => {
uni.hideLoading(); // 处理权限拒绝/定位失败
uni.showToast({ title: '定位失败,请检查权限', icon: 'none' }); if (err.errMsg.includes('auth deny')) {
console.error('定位失败:', err); uni.showModal({
title: '需要定位权限',
content: '请允许获取位置信息以显示具体地点',
confirmText: '去设置',
success: (modalRes) => {
if (modalRes.confirm) {
uni.openSetting({
success: (settingRes) => {
// 用户开启权限后重新定位
if (settingRes.authSetting['scope.userLocation']) {
reLocate();
}
}
});
}
}
});
} else {
uni.hideLoading();
uni.showToast({ title: '定位失败,请重试', icon: 'none' });
console.error('定位失败:', err);
}
} }
}); });
}; };
// 上传所有图片
const uploadAllImages = async () => {
if (imgList.value.length === 0) return [];
const uploadPromises = imgList.value.map(img => uploadImage(img));
const results = await Promise.all(uploadPromises);
return results.map(res => res.data?.url || res.data);
};
// 提交实况 // 提交实况
const submitStatus = () => { const submitStatus = async () => {
// 简单校验
if (!statusDesc.value.trim()) { if (!statusDesc.value.trim()) {
uni.showToast({ title: '请输入实况描述', icon: 'none' }); uni.showToast({ title: '请输入实况描述', icon: 'none' });
return; return;
} }
if (!activityId.value) {
uni.showToast({ title: '活动ID缺失', icon: 'none' });
return;
}
// 模拟提交逻辑(实际项目中可上传图片+提交表单) uni.showLoading({ title: '提交中...', mask: true });
uni.showLoading({ title: '提交中...' });
try {
// 如需上传图片可循环调用uploadFile // 上传图片
// 示例: const imageUrls = await uploadAllImages();
// const uploadPromises = imgList.value.map(img => {
// return uploadFile({ // 提交实况
// url: '你的上传接口', const liveData = {
// filePath: img, content: statusDesc.value.trim(),
// name: 'file' images: imageUrls,
// }); location: location.value,
// }); longitude: longitude.value,
// Promise.all(uploadPromises).then(res => { /* 处理上传结果 */ }); latitude: latitude.value
};
await addActivityLive(activityId.value, liveData);
// 同时签到
await signinActivityLive(activityId.value, {
location: location.value,
longitude: longitude.value,
latitude: latitude.value
});
setTimeout(() => {
uni.hideLoading(); uni.hideLoading();
uni.showToast({ title: '添加成功', icon: 'success' }); uni.showToast({ title: '添加成功', icon: 'success' });
// 提交成功后可返回上一页 uni.$emit('refreshLiveList');
uni.navigateBack(); setTimeout(() => {
}, 1000); uni.navigateBack();
}, 1500);
} catch (err) {
uni.hideLoading();
uni.showToast({ title: err || '提交失败', icon: 'none' });
}
}; };
</script> </script>

View File

@@ -1,4 +1,4 @@
import request,{get,post} from "./request.js" import request,{get,post,upload} from "./request.js"
// =======账号密码登录======== // =======账号密码登录========
@@ -39,7 +39,12 @@ export const getCurrentVillage = () =>{
export const getVillageSwitch = (data)=>{ export const getVillageSwitch = (data)=>{
return post('/api/resident/village/switch',data) return post('/api/resident/village/switch',data)
} }
// ====公告列表====== // 首页最新活动列表
export const getActivitylatest = () =>{
return get('/api/resident/activity/latest')
}
// ========公告列表======
// 获取公告列表 // 获取公告列表
export const getNoticeList = (data) =>{ export const getNoticeList = (data) =>{
return get('/api/resident/notice/list',data) return get('/api/resident/notice/list',data)
@@ -47,4 +52,73 @@ export const getNoticeList = (data) =>{
// 获取公告详情 // 获取公告详情
export const getNoticeDetails = (noticeId) =>{ export const getNoticeDetails = (noticeId) =>{
return get(`/api/resident/notice/${noticeId}`) return get(`/api/resident/notice/${noticeId}`)
}
// =========键开门===============
// 查询门禁列表
export const getAccessDevices = (data) =>{
return get("/api/resident/access/devices",data)
}
// 确认开门
export const getAccessOpen = (data) =>{
return post("/api/resident/access/open",data)
}
// ==========活动列表===========
// 获取活动列表
export const getActivityList = (data) =>{
return get("/api/resident/activity/list",data)
}
// 获取活动列表详情
export const getActivityDetails = (id) =>{
return get(`/api/resident/activity/${id}`)
}
// 确认报名
export const confirmResident = (id) =>{
return post(`/api/resident/activity/${id}/apply`)
}
// 取消报名
export const cancelActivity = (id) =>{
return post(`/api/resident/activity/${id}/cancel`)
}
// =========我的活动========
export const getMyActivityList = () =>{
return get("/api/resident/activity/my")
}
// ===========活动实况============
// 活动实况列表
export const getActivityLive = (id) =>{
return get(`/api/resident/activity/${id}/live`)
}
// 添加实况
export const addActivityLive = (id, data) =>{
return post(`/api/resident/activity/${id}/live`, 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

@@ -103,4 +103,4 @@ export default function request(url, data = {}, method = "GET") {
export const get = (url, data) => request(url, data, 'GET'); export const get = (url, data) => request(url, data, 'GET');
export const post = (url, data) => request(url, data, 'POST'); export const post = (url, data) => request(url, data, 'POST');
export const deleteMethod = (url, data) => request(url, data, 'DELETE'); export const deleteMethod = (url, data) => request(url, data, 'DELETE');
export const putMethod = (url, data) => request(url, data, 'PUT'); export const putMethod = (url, data) => request(url, data, 'PUT');

View File

@@ -49,20 +49,22 @@
</view> </view>
<!-- 协议勾选 --> <!-- 协议勾选 -->
<view class="agreement-item" @click="toggleAgreement"> <view class="agreement-item" >
<uni-icons <view @click="toggleAgreement">
type="checkbox-filled" <uni-icons
size="24" type="checkbox-filled"
color="#007aff" size="24"
v-if="agreeAgreement" color="#007aff"
></uni-icons> v-if="agreeAgreement"
<uni-icons ></uni-icons>
type="checkbox" <uni-icons
size="24" type="checkbox"
color="#999" size="24"
v-else color="#999"
></uni-icons> v-else
<text class="agreement-text">我已阅读并同意用户隐私政策</text> ></uni-icons>
</view>
<text class="agreement-text" @click.stop="goToPrivacy">我已阅读并同意<text class="agreePrivacy">用户隐私政策</text></text>
</view> </view>
<!-- 登录按钮 --> <!-- 登录按钮 -->
@@ -93,11 +95,13 @@ const phoneNumber = ref('');
const verifyCode = ref(''); const verifyCode = ref('');
const placeholderStyle = ref('font-size:24rpx') const placeholderStyle = ref('font-size:24rpx')
// 是否同意协议 // 是否同意协议
const agreeAgreement = ref(true); // 默认勾选 const agreeAgreement = ref(false); // 默认勾选
// 倒计时(秒) // 倒计时(秒)
const countDown = ref(0); const countDown = ref(0);
// 定时器 // 定时器
let timer = null; let timer = null;
// 控制点击变色
// const isClicked = ref(false)
// ========== 计算属性 ========== // ========== 计算属性 ==========
// 是否可以获取验证码(手机号格式正确) // 是否可以获取验证码(手机号格式正确)
@@ -124,6 +128,14 @@ const checkForm = () => {
const toggleAgreement = () => { const toggleAgreement = () => {
agreeAgreement.value = !agreeAgreement.value; agreeAgreement.value = !agreeAgreement.value;
}; };
// 跳转隐私协议
const goToPrivacy = () => {
// 点击变色
// isClicked.value = true
uni.navigateTo({
url:'/pageSubPack/loginSub/privacy',
})
}
// 获取验证码 // 获取验证码
const getVerifyCode = () => { const getVerifyCode = () => {
@@ -206,9 +218,17 @@ const handleLogin = () => {
// 模拟登录请求 // 模拟登录请求
// uni.showLoading({ // uni.showLoading({
// title: '登录中...' // title: '登录中...'
// }); // });
// uni.showToast({
// title:"登录成功",
// icon:'success'
// })
// setTimeout(() =>{
// uni.switchTab({ url: '/pages/index/index' });
// },1500)
uni.hideLoading()
}; };
// ========== 生命周期 ========== // ========== 生命周期 ==========
@@ -319,7 +339,12 @@ onUnmounted(() => {
color: #666; color: #666;
margin-left: 10rpx; margin-left: 10rpx;
} }
.agreePrivacy{
color: #2F77FD;
}
/* .agreePrivacy.active{
color: #2F77FD;
} */
/* 登录按钮 */ /* 登录按钮 */
.login-btn { .login-btn {
width: 100%; width: 100%;

View File

@@ -0,0 +1,169 @@
<template>
<view class="privacy-page">
<!-- 协议内容 -->
<scroll-view class="privacy-content" scroll-y>
<view class="content-wrap">
<view class="title">隐私政策</view>
<view class="section">
<!-- <view class="section-title">适用范围</view> -->
<view class="section-text">
欢迎使用我们的产品/服务以下统称服务我们高度重视用户隐私保护
致力于为您提供安全可靠的服务体验本隐私政策旨在向您说明我们如何收集使用存储保护您的个人信息
以及您享有的相关权利请您在使用我们的服务前仔细阅读并理解本政策全部内容
一旦您使用我们的服务即视为您同意本政策的所有条款
我们收集的个人信息 为了向您提供更优质个性化的服务我们会根据服务功能的需要收集您主动提供或在使用服务过程中产生的个人信息
具体如下 您主动提供的信息 账户注册信息当您注册我们的账户时您可能需要提供姓名手机号码电子邮箱密码等信息用于身份验证账户登录及找回
服务相关信息根据您使用的具体服务您可能需要提供相关补充信息如使用客服咨询服务时提供问题描述及相关凭证使用交易类服务时提供收货地址支付相关信息等
自愿提交的信息您主动向我们反馈的意见建议或参与我们的问卷调查活动时提交的相关信息
若您通过第三方平台如微信支付宝QQ等登录我们的服务我们会根据您的授权
从第三方获取您的相关账户信息如昵称头像用于完成登录及账户绑定
我们不会获取第三方平台的其他未授权信息
</view>
</view>
</view>
</scroll-view>
<!-- 底部同意按钮新增 -->
<!-- <view class="agree-btn-wrap" v-if="needAgree">
<button class="agree-btn" @click="agreePrivacy">同意隐私政策</button>
</view> -->
</view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
// 返回上一页
// const navigateBack = () => {
// uni.navigateBack({
// delta: 1
// });
// };
// 页面加载
// onLoad((options) => {
// // 判断是否需要同意
// if (options.needAgree === '1') {
// needAgree.value = true;
// }
// });
// 返回上一页
// const goToBack = () => {
// uni.navigateBack({
// delta: 1
// });
// };
// 同意隐私政策(新增)
// const agreePrivacy = () => {
// // #ifdef MP-WEIXIN
// wx.requirePrivacyAuthorize({
// success: () => {
// uni.showToast({
// title: '已同意隐私政策',
// icon: 'success'
// });
// // 记录授权状态(可选,存入本地缓存)
// uni.setStorageSync('privacyAgreed', true);
// navigateBack();
// },
// fail: () => {
// uni.showToast({
// title: '授权失败',
// icon: 'none'
// });
// }
// });
// // #endif
// // 非微信小程序直接标记同意
// // #ifndef MP-WEIXIN
// uni.setStorageSync('privacyAgreed', true);
// uni.showToast({
// title: '已同意隐私政策',
// icon: 'success'
// });
// navigateBack();
// // #endif
// };
</script>
<style scoped>
.privacy-page {
min-height: 100vh;
background-color: #f8f8f8;
}
/* 导航栏 */
.nav-bar {
display: flex;
align-items: center;
padding: 20rpx;
background-color: #fff;
border-bottom: 1rpx solid #eee;
}
.nav-back {
display: flex;
align-items: center;
}
.back-text {
font-size: 30rpx;
color: #333;
margin-left: 10rpx;
}
.nav-title {
font-size: 32rpx;
font-weight: 500;
margin-left: 60rpx;
}
/* 协议内容 */
.privacy-content {
height: calc(100vh - 88rpx);
}
.content-wrap {
padding: 30rpx;
}
.title {
font-size: 28rpx;
font-weight: 600;
text-align: center;
margin-bottom: 40rpx;
color: #333;
}
.section {
margin-bottom: 30rpx;
padding: 0 20rpx;
}
.section-title {
font-size: 30rpx;
font-weight: 500;
color: #333;
margin-bottom: 10rpx;
}
.section-text {
font-size: 28rpx;
line-height: 1.6;
color: #666;
}
/* 同意按钮样式(新增) */
.agree-btn-wrap {
padding: 20rpx;
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #fff;
border-top: 1rpx solid #eee;
}
.agree-btn {
background-color: #007aff;
color: #fff;
border-radius: 8rpx;
height: 88rpx;
font-size: 32rpx;
}
</style>

View File

@@ -29,20 +29,25 @@
<!-- 协议勾选 + 忘记密码 --> <!-- 协议勾选 + 忘记密码 -->
<view class="agreement-wrap"> <view class="agreement-wrap">
<view class="agreement-item" @click="toggleAgreement"> <view class="agreement-item">
<uni-icons <view @click="toggleAgreement">
type="checkbox-filled" <uni-icons
size="24" type="checkbox-filled"
color="#007aff" size="24"
v-if="agreeAgreement" color="#007aff"
></uni-icons> v-if="agreeAgreement"
<uni-icons ></uni-icons>
type="checkbox" <uni-icons
size="24" type="checkbox"
color="#999" size="24"
v-else color="#999"
></uni-icons> v-else
<text class="agreement-text">我已阅读并同意用户隐私政策</text> ></uni-icons>
</view>
<text class="agreement-text" @click.stop="goToPrivacy">我已阅读并同意
<text class="agreePrivacy" >用户隐私政策</text>
</text>
</view> </view>
<navigator class="forget-pwd" url="/pageSubPack/loginSub/forget-pwd">忘记密码</navigator> <navigator class="forget-pwd" url="/pageSubPack/loginSub/forget-pwd">忘记密码</navigator>
</view> </view>
@@ -72,8 +77,10 @@ import {getLoginPassword} from '../api/api.js'
// 响应式数据 // 响应式数据
const phoneNumber = ref(''); const phoneNumber = ref('');
const password = ref(''); const password = ref('');
const agreeAgreement = ref(true); // 默认勾选 const agreeAgreement = ref(false); // 默认勾选
const placeholderStyle = ref('font-size:24rpx') const placeholderStyle = ref('font-size:24rpx')
// 控制点击变色
// const isClicked = ref(false)
// 计算属性:是否可登录(帐号+密码+协议都满足) // 计算属性:是否可登录(帐号+密码+协议都满足)
const canLogin = computed(() => { const canLogin = computed(() => {
@@ -87,6 +94,15 @@ const toggleAgreement = () => {
agreeAgreement.value = !agreeAgreement.value; agreeAgreement.value = !agreeAgreement.value;
}; };
// 跳转隐私协议
const goToPrivacy = () => {
// 点击变色
// isClicked.value = true
uni.navigateTo({
url:'/pageSubPack/loginSub/privacy',
})
}
// 检查表单 // 检查表单
const checkForm = () => {}; const checkForm = () => {};
@@ -113,13 +129,13 @@ const handleLogin = () => {
uni.showToast({ title: '请勾选协议', icon: 'none' }); uni.showToast({ title: '请勾选协议', icon: 'none' });
return; return;
} }
uni.showLoading({ title: '登录中...', mask: true }); // uni.showLoading({ title: '登录中...', mask: true });
let params = { let params = {
username:phoneNumber.value, username:phoneNumber.value,
password:password.value password:password.value
} }
getLoginPassword(params).then(res =>{ getLoginPassword(params).then(res =>{
console.log('33333',res) // console.log('33333',res)
if(res.code === 200){ if(res.code === 200){
uni.setStorageSync('token', res.data.token); uni.setStorageSync('token', res.data.token);
// 存用户ID // 存用户ID
@@ -127,6 +143,7 @@ const handleLogin = () => {
// 存当前绑定的小区ID0 表示未绑定 // 存当前绑定的小区ID0 表示未绑定
const currentVillageId = res.data.currentVillageId || 0; const currentVillageId = res.data.currentVillageId || 0;
uni.setStorageSync('currentVillageId', currentVillageId); uni.setStorageSync('currentVillageId', currentVillageId);
uni.setStorageSync('userId',res.data.userId)
} }
uni.hideLoading(); uni.hideLoading();
uni.showToast({ title: '登录成功', icon: 'success' }); uni.showToast({ title: '登录成功', icon: 'success' });
@@ -220,6 +237,12 @@ const handleLogin = () => {
color: #666; color: #666;
margin-left: 10rpx; margin-left: 10rpx;
} }
.agreePrivacy{
color: #2F77FD;
}
/* .agreePrivacy.active{
color: #2F77FD;
} */
.forget-pwd { .forget-pwd {
font-size: 28rpx; font-size: 28rpx;

View File

@@ -105,7 +105,7 @@
} }
}catch(err){ }catch(err){
uni.showToast({ uni.showToast({
title:"加载失败", title: res.msg ||"网络异常",
icon:"none" icon:"none"
}) })
} }

View File

@@ -28,42 +28,50 @@
<view <view
v-for="(item, index) in doorList" v-for="(item, index) in doorList"
:key="index" :key="index"
:class="['door-item', { active: selectedDoor === index }]" :class="['door-item', { active: selectedDoor === item.id }]"
@click="selectDoor(index)" @click="selectDoor(item.id)"
> >
<!-- 图标占位可替换为真实图标/图片 --> <!-- 图标占位 -->
<view class="door-icon"> <view class="door-icon">
<image class="icon-text" :src="selectedDoor === index ? item.iconActive:item.iconText"></image> <image class="icon-text" :src="selectedDoor === item.id ? item.iconActive:item.iconText"></image>
</view> </view>
<!-- 门名称 --> <!-- 门名称 -->
<text class="door-name">{{ item.name }}</text> <text class="door-name" :class="{active :selectedDoor === item.id}">{{ item.deviceName }}</text>
</view> </view>
</view> </view>
<!-- 空状态 -->
<view v-if="doorList.length === 0" class="empty-state">
<uni-icons type="info" size="60" color="#ccc"></uni-icons>
<text class="empty-text">暂无可用门禁</text>
</view>
</view> </view>
<!-- 确认开门按钮 --> <!-- 确认开门按钮 -->
<button class="confirm-btn" @click="openDoor" :disabled="selectedDoor === -1">确认开门</button> <button class="confirm-btn" @click="openDoorClick" :disabled="selectedDoor === -1">确认开门</button>
</view> </view>
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import {onLoad} from '@dcloudio/uni-app'
import {getAccessDevices,getAccessOpen} from '../api/api.js'
// 响应式数据:选中的门索引、开门成功提示 // 响应式数据:选中的门索引、开门成功提示
const selectedDoor = ref(-1) // -1表示未选中 const selectedDoor = ref(-1) // -1表示未选中
const showSuccess = ref(false) const showSuccess = ref(false)
// 门列表数据 // 门列表数据
const doorList = ref([ const doorList = ref([
{ iconText: 'http://47.104.199.163:9090/images/openDoor/westDoor.png',iconActive:"http://47.104.199.163:9090/images/openDoor/westDoorWhite.png", name: '西入门闸机' }, // { iconText: 'http://47.104.199.163:9090/images/openDoor/westDoor.png',iconActive:"http://47.104.199.163:9090/images/openDoor/westDoorWhite.png", name: '西入门闸机' },
{ iconText: 'http://47.104.199.163:9090/images/openDoor/eastDoor.png',iconActive:"http://47.104.199.163:9090/images/openDoor/eastDoorWhite.png", name: '东入门闸机' }, // { iconText: 'http://47.104.199.163:9090/images/openDoor/eastDoor.png',iconActive:"http://47.104.199.163:9090/images/openDoor/eastDoorWhite.png", name: '东入门闸机' },
{ iconText: 'http://47.104.199.163:9090/images/openDoor/unitDoor.png',iconActive:"http://47.104.199.163:9090/images/openDoor/unitDoorWhite.png", name: '1号楼1单元门' }, // { iconText: 'http://47.104.199.163:9090/images/openDoor/unitDoor.png',iconActive:"http://47.104.199.163:9090/images/openDoor/unitDoorWhite.png", name: '1号楼1单元门' },
{ iconText: 'http://47.104.199.163:9090/images/openDoor/unitDoor.png',iconActive:"http://47.104.199.163:9090/images/openDoor/unitDoorWhite.png", name: '1号楼2单元门' } // { iconText: 'http://47.104.199.163:9090/images/openDoor/unitDoor.png',iconActive:"http://47.104.199.163:9090/images/openDoor/unitDoorWhite.png", name: '1号楼2单元门' }
]) ])
// 选择门的方法 // 选择门的方法
const selectDoor = (index) => { const selectDoor = (id) => {
selectedDoor.value = index selectedDoor.value = id
showSuccess.value = false // 选择新门时隐藏成功提示 showSuccess.value = false // 选择新门时隐藏成功提示
} }
// 返回 // 返回
@@ -80,8 +88,38 @@ const narBack = () =>{
uni.removeStorageSync('sourcePage') uni.removeStorageSync('sourcePage')
} }
// 查询门禁列表
const getAccessControl = async () =>{
try{
const res = await getAccessDevices()
if(res.code === 200){
if(res.data){
doorList.value = res.data || []
}else{
doorList.value = []
}
}else{
doorList.value = []
uni.showToast({
title:'门禁查询失败',
icon:"error"
})
}
}catch{
doorList.value = []
uni.showToast({
title:res.msg,
icon:"error"
})
}
}
// 确认开门方法 // 确认开门方法
const openDoor = () => { const openDoorClick = () => {
// 校验:未选择门时提示 // 校验:未选择门时提示
// if (selectedDoor.value === -1) { // if (selectedDoor.value === -1) {
// uni.showToast({ // uni.showToast({
@@ -90,14 +128,42 @@ const openDoor = () => {
// }) // })
// return // return
// } // }
getAccessOpenData()
// 模拟开门接口请求(实际项目替换为真实接口)
setTimeout(() => {
showSuccess.value = true
// 可选:添加成功提示后自动隐藏
// setTimeout(() => showSuccess.value = false, 2000)
}, 500)
} }
// 开门接口
const getAccessOpenData = async () =>{
try{
let params = {deviceId:selectedDoor.value}
const res = await getAccessOpen(params)
if(res.code === 200){
if(res.data){
uni.showToast({
title:'开门成功',
icon:"success"
})
}else{
uni.showToast({
title:'开门失败',
icon:"error"
})
}
}else{
uni.showToast({
title:'开门失败',
icon:"error"
})
}
}catch{
uni.showToast({
title: res.msg,
icon:"error"
})
}
}
onLoad(() =>{
getAccessControl()
})
</script> </script>
<style scoped> <style scoped>
@@ -229,6 +295,23 @@ const openDoor = () => {
font-size: 26rpx; font-size: 26rpx;
color: #333333; color: #333333;
} }
.door-name.active {
color: #ffffff;
}
.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;
}
/* 确认按钮 */ /* 确认按钮 */
.confirm-btn { .confirm-btn {

View File

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

View File

@@ -5,7 +5,7 @@
<text class="label">报修房屋</text> <text class="label">报修房屋</text>
<view class="value" @click="goToSelectHouse"> <view class="value" @click="goToSelectHouse">
{{ houseName || '请选择房屋' }} {{ houseName || '请选择房屋' }}
<text class="switch" v-if="houseName">切换</text> <!-- <text class="switch" v-if="houseName">切换</text> -->
<uni-icons type="arrowright" size="16"></uni-icons> <uni-icons type="arrowright" size="16"></uni-icons>
</view> </view>
</view> </view>
@@ -145,13 +145,15 @@
<script setup> <script setup>
import { ref,computed,onMounted} from 'vue' import { ref,computed,onMounted} from 'vue'
import { import {
onLoad, onUnload onLoad, onUnload
} from '@dcloudio/uni-app' } from '@dcloudio/uni-app'
import { addQueryRepair, uploadFile } from '../api/api.js'
import moment from 'moment/moment' import moment from 'moment/moment'
// 选中的房屋/项目名称 // 选中的房屋/项目名称
const houseName = ref('') const houseName = ref('')
const houseId = ref('')
const projectName = ref('') const projectName = ref('')
// 表单数据 // 表单数据
@@ -159,7 +161,7 @@ const form = ref({
title: '', title: '',
desc: '', desc: '',
phone: '', phone: '',
datetime: '2023-08-01 15:30', // 默认时间(匹配截图) datetime: '', // 默认时间
images: [] images: []
}) })
@@ -167,7 +169,7 @@ const form = ref({
const timePopupRef = ref(null) const timePopupRef = ref(null)
// 初始时间() // 初始时间()
const selectedTime = ref(moment().hour(9).minute(30).second(0)); const selectedTime = ref(moment().hour(9).minute(30).second(0));
// 选择的时间(弹窗中预览) // 选择的时间
const tempTime = 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}`; const selectedDateTime = `${selectedDate.value} ${selectedHour.value}:${selectedMinute.value}`;
selectedTime.value = moment(selectedDateTime, 'YYYY-MM-DD HH:mm'); selectedTime.value = moment(selectedDateTime, 'YYYY-MM-DD HH:mm');
// 给表单赋值
form.value.datetime = selectedTime.value.format('YYYY-MM-DD HH:mm')
// 关闭弹窗 // 关闭弹窗
closeTimePopup(); closeTimePopup();
@@ -332,6 +336,7 @@ onLoad(() => {
// 监听选择房屋事件 // 监听选择房屋事件
uni.$on('selectHouse', (data) => { uni.$on('selectHouse', (data) => {
houseName.value = data.name houseName.value = data.name
houseId.value = data.id
}) })
// 监听选择维修项目事件 // 监听选择维修项目事件
uni.$on('selectProject', (data) => { uni.$on('selectProject', (data) => {
@@ -348,7 +353,7 @@ onUnload(() => {
// 跳转到选择房屋页 // 跳转到选择房屋页
const goToSelectHouse = () => { const goToSelectHouse = () => {
uni.navigateTo({ 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) 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) { if (!houseName.value) {
uni.showToast({ title: '请选择报修房屋', icon: 'none' }) uni.showToast({ title: '请选择报修房屋', icon: 'none' })
@@ -426,16 +449,46 @@ const submitForm = () => {
return return
} }
// 提交逻辑(替换为你的接口) const villageId = uni.getStorageSync('currentVillageId')
if (!villageId || villageId === '0') {
uni.showToast({ title: '请先选择小区', icon: 'none' })
return
}
uni.showLoading({ title: '提交中...' }) uni.showLoading({ title: '提交中...' })
setTimeout(() => { 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 = ''
uni.navigateBack({ delta: 1 })
} else {
uni.showToast({ title: res.msg || '提交失败', icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '网络异常', icon: 'none' })
} finally {
uni.hideLoading() uni.hideLoading()
uni.showToast({ title: '提交成功', icon: 'success' }) }
// 重置表单
// form.value = { title: '', desc: '', phone: '', datetime: '', images: [] }
// houseName.value = ''
// projectName.value = ''
}, 1000)
} }
</script> </script>

View File

@@ -17,7 +17,7 @@
v-for="item in categoryList" v-for="item in categoryList"
:key="item.id" :key="item.id"
> >
{{ item.name }} {{ item.projectName }}
</view> </view>
</scroll-view> </scroll-view>
@@ -30,7 +30,7 @@
v-for="item in currentProjectList" v-for="item in currentProjectList"
:key="item.id" :key="item.id"
> >
{{ item.name }} {{ item.projectName }}
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
@@ -42,39 +42,50 @@
<script setup> <script setup>
import { ref, computed } from 'vue' 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([ const categoryList = ref([])
{ id: 1, name: '家具' },
{ id: 2, name: '电路' },
{ id: 3, name: '水暖' },
{ id: 4, name: '门频' },
{ id: 5, name: '电器' }
])
// 项目列表(匹配截图:床/沙发/柜子/椅子等) // 项目列表
const projectList = 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 activeCategory = ref(1) // 默认选中家具 const activeCategory = ref(1)
const selectedProject = ref({}) // 选中的项目 const selectedProject = ref({}) // 选中的项目
const searchKey = 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(() => { const currentProjectList = computed(() => {
let list = projectList.value.filter(item => item.categoryId === activeCategory.value) let list = projectList.value.filter(item => item.categoryId === activeCategory.value)
if (searchKey.value) { if (searchKey.value) {
list = list.filter(item => item.name.includes(searchKey.value)) list = list.filter(item => item.projectName.includes(searchKey.value))
} }
return list 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', { uni.$emit('selectProject', {
name: `${categoryName}-${selectedProject.value.name}` name: `${categoryName}-${selectedProject.value.projectName}`
}) })
uni.navigateBack({ delta: 1 }) uni.navigateBack({ delta: 1 })

View File

@@ -57,10 +57,11 @@
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import{onLoad} from "@dcloudio/uni-app" 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 repairProject = ref('')
const projectId = ref('')
// 表单数据 // 表单数据
const form = ref({ const form = ref({
@@ -75,6 +76,9 @@ onLoad((options) => {
if (options.category && options.project) { if (options.category && options.project) {
repairProject.value = `${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 const tempFilePaths = res.tempFilePaths
form.value.images = [...form.value.images, ...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) 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) { if (!repairProject.value) {
uni.showToast({ title: '请选择维修项目', icon: 'none' }) uni.showToast({ title: '请选择维修项目', icon: 'none' })
@@ -138,19 +150,49 @@ const submitForm = () => {
return return
} }
// 提交数据(替换成你的接口) const villageId = uni.getStorageSync('currentVillageId')
if (!villageId || villageId === '0') {
uni.showToast({ title: '请先选择小区', icon: 'none' })
return
}
uni.showLoading({ title: '提交中...' }) uni.showLoading({ title: '提交中...' })
// 模拟接口请求 try {
setTimeout(() => { // 先上传图片
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: [] }
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() uni.hideLoading()
uni.showToast({ title: '提交成功', icon: 'success' }) }
// 提交成功后重置表单/返回上一页
// form.value = { title: '', desc: '', phone: '', images: [] }
// 或返回上一页
uni.navigateBack({ delta: 3 })
}, 1000)
} }
</script> </script>

View File

@@ -3,7 +3,6 @@
<!-- 维修流程模块 --> <!-- 维修流程模块 -->
<view class="info-section"> <view class="info-section">
<!-- <uni-section title="维修流程" type="line" style="margin-bottom: 20rpx;"> -->
<view class="section-title">维修流程</view> <view class="section-title">维修流程</view>
<uni-row class="demo-uni-row" :width="nvueWidth"> <uni-row class="demo-uni-row" :width="nvueWidth">
<uni-col :span="12"> <uni-col :span="12">
@@ -19,13 +18,10 @@
<view class="step-time-3">2026-03-28 09:30:38</view> <view class="step-time-3">2026-03-28 09:30:38</view>
</uni-col> </uni-col>
</uni-row> </uni-row>
<!-- </uni-section> -->
</view> </view>
<!-- 报修信息模块 --> <!-- 报修信息模块 -->
<view class="info-section"> <view class="info-section">
<!-- <uni-section title="报修信息" type="line" style="margin-bottom: 20rpx;"> -->
<view class="section-title">报修信息</view> <view class="section-title">报修信息</view>
<view class="info-item"> <view class="info-item">
<view class="info-label">报修房屋</view> <view class="info-label">报修房屋</view>
@@ -59,7 +55,6 @@
</view> </view>
</view> </view>
</view> </view>
<!-- </uni-section> -->
</view> </view>
<!-- 联系物业按钮 --> <!-- 联系物业按钮 -->
@@ -70,15 +65,9 @@
</template> </template>
<script setup> <script setup>
import { import { ref, computed } from 'vue'
ref import { onLoad } from '@dcloudio/uni-app'
} from 'vue'
import {
onLoad
} from '@dcloudio/uni-app'
// 步骤条当前激活的步骤0=待处理1=已派单2=已完成)
const currentStep = ref(2)
const nvueWidth = ref('300') const nvueWidth = ref('300')
// 报修信息数据 // 报修信息数据
@@ -91,21 +80,25 @@
time: '2023-08-01 15:30' time: '2023-08-01 15:30'
}) })
// 步骤状态
const currentStep = ref(1)
onLoad((option) => { onLoad((option) => {
const decodeStr = decodeURIComponent(JSON.stringify(option)) const optionstr = decodeURIComponent(JSON.stringify(option))
// let item = JSON.parse(decodeStr) // console.log('接收参数:', optionstr)
// repairInfo.value = optionStr
console.log('item', decodeStr) // ✅ 正确解析参数
const status = decodeStr.statusClass const status = optionstr.statusClass
// console.log('status',status)
// ✅ 正确赋值
switch (status) { switch (status) {
case 'pending': //待处理 case 'pending': //待处理
currentStep.value = 0 currentStep.value = 0
break break
case 'assignde': case 'assignde': //已派单
currentStep.value = 1 currentStep.value = 1
break break
case 'completed': case 'completed': //已完成
currentStep.value = 2 currentStep.value = 2
break break
default: default:
@@ -135,7 +128,6 @@
border-radius: 8px; border-radius: 8px;
padding: 13px; padding: 13px;
margin-bottom: 16px; margin-bottom: 16px;
/* margin-top: 20rpx; */
} }
.repair-steps-container { .repair-steps-container {
@@ -153,21 +145,16 @@
.step-time { .step-time {
height: 54px; height: 54px;
line-height: 54px; line-height: 54px;
font-size: 12px; font-size: 24rpx;
color: #999; color: #999;
/* font-size: 22rpx;
color: #999;
text-align: right;
margin-top: 5rpx; */
} }
.step-time-3{ .step-time-3{
height: 38px; height: 38px;
line-height: 38px; line-height: 38px;
font-size: 12px; font-size: 24rpx;
color: #999; color: #999;
} }
/* -------- */
.section-title { .section-title {
font-size: 32rpx; font-size: 32rpx;
font-weight: bold; font-weight: bold;
@@ -184,32 +171,18 @@
.slot-desc { .slot-desc {
font-size: 10px; font-size: 10px;
} }
/* .step-time {
position: absolute;
right: 0;
top: 0;
font-size: 14px;
color: #999;
white-space: nowrap;
} */
.info-item { .info-item {
display: flex; display: flex;
padding: 12px 0; padding: 12px 0;
/* border-bottom: 1px solid #f0f0f0; */
} }
.info-item-desc { .info-item-desc {
/* display: flex; */
padding: 12px 0; padding: 12px 0;
/* border-bottom: 1px solid #f0f0f0; */
} }
.info-section.active { .info-section.active {
color: #007AFF; color: #007AFF;
/* font-weight: 500; */
} }
.info-item:last-child { .info-item:last-child {
@@ -270,4 +243,14 @@
.contact-btn::after { .contact-btn::after {
border: none; border: none;
} }
/* ========== 颜色的代码 ========== */
/* u-text__value u-text__value--main */
/* 激活的步骤标题 + 描述 强制蓝色 */
::v-deep .u-text__value .u-text__value--main {
color: #007aff !important;
}
::v-deep .up-steps-item--active .up-steps-item__desc {
color: #007aff !important;
}
</style> </style>

View File

@@ -17,7 +17,7 @@
v-for="item in categoryList" v-for="item in categoryList"
:key="item.id" :key="item.id"
> >
{{ item.name }} {{ item.projectName }}
</view> </view>
</scroll-view> </scroll-view>
@@ -29,7 +29,7 @@
v-for="item in currentProjectList" v-for="item in currentProjectList"
:key="item.id" :key="item.id"
> >
{{ item.name }} {{ item.projectName }}
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
@@ -38,24 +38,43 @@
<script setup> <script setup>
import { ref, computed } from 'vue' 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([ const categoryList = ref([])
{ id: 1, name: '基础设施' },
{ id: 2, name: '电子设施' }
])
// 所有项目数据 // 所有项目数据
const projectList = 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 activeCategory = ref(1) 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('') const searchKey = ref('')
@@ -63,7 +82,7 @@ const searchKey = ref('')
const currentProjectList = computed(() => { const currentProjectList = computed(() => {
let list = projectList.value.filter(item => item.categoryId === activeCategory.value) let list = projectList.value.filter(item => item.categoryId === activeCategory.value)
if (searchKey.value) { if (searchKey.value) {
list = list.filter(item => item.name.includes(searchKey.value)) list = list.filter(item => item.projectName.includes(searchKey.value))
} }
return list return list
}) })
@@ -76,10 +95,10 @@ const selectCategory = (item) => {
// 选择项目并跳转到维修项目填写页 // 选择项目并跳转到维修项目填写页
const selectProject = (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({ 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> </script>

View File

@@ -9,10 +9,10 @@
v-for="item in houseList" v-for="item in houseList"
:key="item.id" :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"> <view class="house-name">
{{ item.community }} {{ item.villageName }}
<view class="house-detail">{{ item.address }}</view> <view class="house-detail">{{ item.houseType }}</view>
</view> </view>
<uni-icons type="checkbox-filled" size="20" color="#007aff" v-if="selectedHouse.id === item.id"></uni-icons> <uni-icons type="checkbox-filled" size="20" color="#007aff" v-if="selectedHouse.id === item.id"></uni-icons>
@@ -26,17 +26,49 @@
<script setup> <script setup>
import { ref } from 'vue' 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([ 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 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) => { const selectHouse = (item) => {
@@ -52,7 +84,8 @@ const confirmSelect = () => {
// 把选中的房屋信息传给表单页通过uni.$emit // 把选中的房屋信息传给表单页通过uni.$emit
uni.$emit('selectHouse', { uni.$emit('selectHouse', {
name: `${selectedHouse.value.community} ${selectedHouse.value.address}` id: selectedHouse.value.id,
name: `${selectedHouse.value.villageName} ${selectedHouse.value.houseType}`
}) })
// 返回上一页 // 返回上一页
@@ -68,7 +101,7 @@ const confirmSelect = () => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
background: #fff; background: #f9f9f9;
} }
.house-list { .house-list {
flex: 1; flex: 1;
@@ -78,13 +111,14 @@ const confirmSelect = () => {
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
padding: 15px 10px; padding: 15px 10px;
border: 1px solid #eee; background-color: #fff;
border-radius: 8px; border-radius: 8px;
margin-bottom: 10px; margin-bottom: 10px;
} }
.house-item.active { .house-item.active {
border-color: #007aff; border-color: #007aff;
background: #f0f8ff; background: #f0f8ff;
border: 1px solid #2F77FD;
} }
.house-name { .house-name {
font-size: 16px; font-size: 16px;
@@ -108,7 +142,8 @@ const confirmSelect = () => {
background: #007aff; background: #007aff;
color: #fff; color: #fff;
border-radius: 8px; border-radius: 8px;
font-size: 16px; font-size: 28rpx;
margin-top: 20px; margin-top: 20px;
margin-bottom: 20rpx;
} }
</style> </style>

View File

@@ -112,6 +112,8 @@ const sendToFriend = () => {
color: #fff; color: #fff;
border-radius: 8rpx; border-radius: 8rpx;
height: 88rpx; height: 88rpx;
font-size: 32rpx; font-size: 28rpx;
line-height: 88rpx;
} }
</style> </style>

View File

@@ -1,11 +1,5 @@
<template> <template>
<view class="visitor-invite"> <view class="visitor-invite">
<!-- 顶部导航 -->
<!-- <view class="nav-bar">
<uni-icons type="left" size="20" color="#000" @click="navigateBack"></uni-icons>
<view class="nav-title">访客邀请</view>
</view> -->
<!-- 标签切换车辆来访/人员来访 --> <!-- 标签切换车辆来访/人员来访 -->
<view class="tab-wrap"> <view class="tab-wrap">
<view <view
@@ -27,8 +21,8 @@
<!-- 表单区域 --> <!-- 表单区域 -->
<view class="form-wrap"> <view class="form-wrap">
<!-- 房屋信息 --> <!-- 房屋信息 -->
<view class="section-title">房屋信息</view>
<view class="form-section"> <view class="form-section">
<view class="section-title">房屋信息</view>
<view class="form-item"> <view class="form-item">
<view class="label"> <view class="label">
<text class="required">*</text>来访地址 <text class="required">*</text>来访地址
@@ -41,8 +35,9 @@
</view> </view>
<!-- 访客信息 --> <!-- 访客信息 -->
<view class="section-title">访客信息</view>
<view class="form-section"> <view class="form-section">
<view class="section-title">访客信息</view>
<view class="form-item"> <view class="form-item">
<view class="label">访客姓名</view> <view class="label">访客姓名</view>
<input <input
@@ -103,14 +98,15 @@
</view> </view>
<!-- 有效期 --> <!-- 有效期 -->
<view class="section-title">有效期</view>
<view class="form-section"> <view class="form-section">
<view class="section-title">有效期</view>
<view class="form-item"> <view class="form-item">
<view class="label"> <view class="label">
<text class="required">*</text>来访时间 <text class="required">*</text>来访时间
</view> </view>
<view class="value"> <view class="value">
<uni-datetime-picker type="datetime" v-model="visitTime" @change="changeLog" :border="false"/> <uni-datetime-picker type="datetime" v-model="form.visitTime" @change="handleTimeChange" :border="false"/>
</view> </view>
</view> </view>
<view class="form-item"> <view class="form-item">
@@ -118,11 +114,11 @@
<text class="required">*</text>离开时间 <text class="required">*</text>离开时间
</view> </view>
<view class="value"> <view class="value">
<uni-datetime-picker type="datetime" v-model="leaveTime" @change="changeLog" :border="false"/> <uni-datetime-picker type="datetime" v-model="form.leaveTime" @change="handleTimeChange" :border="false"/>
</view> </view>
</view> </view>
<view class="tips">预计来访时间和预计离开时间间隔不能超过24小时</view> <view class="tips">预计来访时间和预计离开时间间隔不能超过24小时</view>
<view class="tips">车辆停留请勿超出有效期需及时驶出小区</view> <view class="tips-2">车辆停留请勿超出有效期需及时驶出小区</view>
</view> </view>
</view> </view>
@@ -176,31 +172,30 @@
</view> </view>
</view> </view>
</uni-popup> </uni-popup>
</view> </view>
</template> </template>
<script setup> <script setup>
import { ref, reactive} from 'vue'; import { ref, reactive} from 'vue';
import{onLoad } from "@dcloudio/uni-app" import{onLoad } from "@dcloudio/uni-app"
import moment from 'moment';
// 标签激活状态 // 标签激活状态
const activeTab = ref('car'); const activeTab = ref('car');
// 表单数据 // 表单数据
const form = reactive({ const form = reactive({
address: '桂花园别墅2号楼2层', // 来访地址默认值 address: '',
name: '', // 访客姓名 name: '',
gender: '', // 性别默认值 gender: '',
phone: '', // 联系方式 phone: '',
carNumber: ['', '', '', '', '', '', ''], // 车牌7位 carNumber: ['', '', '', '', '', '', '', ''], // 修复8位车牌
peopleNum: '', // 随行人数 peopleNum: '',
visitTime: '', // 来访时间默认值 visitTime: '',
leaveTime: '' // 离开时间 leaveTime: ''
}); });
// 地址列表(模拟数据) // 地址列表
const addressList = ref([ const addressList = ref([
'桂花园别墅1号楼1层', '桂花园别墅1号楼1层',
'桂花园别墅2号楼2层' '桂花园别墅2号楼2层'
@@ -209,31 +204,18 @@ const addressList = ref([
// 性别列表 // 性别列表
const genderList = ref(['男', '女']); const genderList = ref(['男', '女']);
// 弹窗/选择器实例 // 弹窗实例
const addressModalRef = ref(null); const addressModalRef = ref(null);
const genderModalRef = ref(null); const genderModalRef = ref(null);
const timePickerRef = ref(null);
// 标记当前选择的是来访/离开时间
const currentTimeType = ref('');
// 页面初始化
onLoad(() => { onLoad(() => {
// 可在这里请求接口获取地址/默认时间等数据
}); });
// 切换tab // 切换tab
const switchTab = (tab) => { const switchTab = (tab) => {
activeTab.value = tab; activeTab.value = tab;
// 切换Tab后重置表单
resetForm(); resetForm();
// nextTick(() =>{
// })
};
// 返回上一页
const navigateBack = () => {
uni.navigateBack();
}; };
// 打开地址弹窗 // 打开地址弹窗
@@ -263,32 +245,51 @@ const selectGender = (item) => {
genderModalRef.value.close(); genderModalRef.value.close();
}; };
// 打开时间选择器 // 时间校验
// const openTimePicker = (type) => { const handleTimeChange = () => {
// currentTimeType.value = type; if (!form.visitTime || !form.leaveTime) return true;
// timePickerRef.value.open();
// }; const visitMoment = moment(form.visitTime);
const leaveMoment = moment(form.leaveTime);
// 离开时间不能早于来访时间
if (leaveMoment.isBefore(visitMoment)) {
uni.showToast({
title: '离开时间不能早于来访时间',
icon: 'none'
});
form.leaveTime = visitMoment.clone().add(1, 'hours').format('YYYY-MM-DD HH:mm');
return false;
}
// 不能超过24小时
// 校验来访/离开时间间隔 const diffHours = leaveMoment.diff(visitMoment, 'hours', true);
const checkTimeInterval = () => {
if (!form.visitTime || !form.leaveTime) return;
const visitTime = new Date(form.visitTime).getTime();
const leaveTime = new Date(form.leaveTime).getTime();
const diffHours = (leaveTime - visitTime) / (1000 * 60 * 60);
if (diffHours > 24) { if (diffHours > 24) {
uni.showToast({ uni.showToast({
title: '时间间隔不能超过24小时', title: '时间间隔不能超过24小时',
icon: 'none' icon: 'none'
}); });
form.leaveTime = ''; form.leaveTime = visitMoment.clone().add(24, 'hours').format('YYYY-MM-DD HH:mm');
return false;
} }
return true;
}; };
// 表单提交 // 提交表单
const submitForm = () => { const submitForm = () => {
// 必填项校验 // 1. 必填项校验
if (!form.address) {
uni.showToast({ title: '请选择来访地址', icon: 'none' });
return;
}
if (!form.name) {
uni.showToast({ title: '请输入访客姓名', icon: 'none' });
return;
}
if (!form.gender) {
uni.showToast({ title: '请选择性别', icon: 'none' });
return;
}
if (!form.phone) { if (!form.phone) {
uni.showToast({ title: '请输入访客联系方式', icon: 'none' }); uni.showToast({ title: '请输入访客联系方式', icon: 'none' });
return; return;
@@ -297,22 +298,27 @@ const submitForm = () => {
uni.showToast({ title: '请输入正确的手机号', icon: 'none' }); uni.showToast({ title: '请输入正确的手机号', icon: 'none' });
return; return;
} }
if (activeTab === 'car' && form.carNumber.join('').length < 8) { if (activeTab === 'car' && form.carNumber.join('').length < 7) {
uni.showToast({ title: '请填写完整车牌号', icon: 'none' }); uni.showToast({ title: '请填写完整车牌号', icon: 'none' });
return; return;
} }
if (!form.peopleNum || form.peopleNum < 0) { if (!form.peopleNum || form.peopleNum <= 0) {
uni.showToast({ title: '请输入正确的随行人数', icon: 'none' }); uni.showToast({ title: '请输入正确的随行人数', icon: 'none' });
return; return;
} }
if (!form.visitTime) {
uni.showToast({ title: '请选择来访时间', icon: 'none' });
return;
}
if (!form.leaveTime) { if (!form.leaveTime) {
uni.showToast({ title: '请选择离开时间', icon: 'none' }); uni.showToast({ title: '请选择离开时间', icon: 'none' });
return; return;
} }
checkTimeInterval();
if (!form.leaveTime) return; // 时间校验失败则终止提交
// 提交逻辑(替换为实际接口请求) // 2. 时间规则校验
if (!handleTimeChange()) return;
// 3. 提交成功
uni.showLoading({ title: '提交中...' }); uni.showLoading({ title: '提交中...' });
setTimeout(() => { setTimeout(() => {
uni.hideLoading(); uni.hideLoading();
@@ -321,22 +327,28 @@ const submitForm = () => {
icon: 'success' icon: 'success'
}); });
}, 1000); }, 1000);
setTimeout(() =>{
uni.navigateTo({
url:"/pageSubPack/visitor/qrcode-page"
})
},1500)
}; };
// 重置表单
const resetForm = () => { // 重置表单
form.address = ''; const resetForm = () => {
form.name = ''; form.address = '';
form.gender = ''; form.name = '';
form.phone = ''; form.gender = '';
form.carNumber = ''; form.phone = '';
form.escortNum = ''; form.carNumber = ['', '', '', '', '', '', '', ''];
form.visitTime = ''; form.peopleNum = '';
form.leaveTime = ''; form.visitTime = '';
form.carNumber = ['', '', '', '', '', '', '']; // 重置车牌号输入 form.leaveTime = '';
}; };
</script> </script>
<style scoped> <style scoped>
.visitor-invite { .visitor-invite {
background-color: #f5f5f5; background-color: #f5f5f5;
@@ -385,22 +397,23 @@ const submitForm = () => {
padding: 20rpx 40rpx; padding: 20rpx 40rpx;
} }
.section-title { .section-title {
font-size: 32rpx; font-size: 28rpx;
font-weight: 500; font-weight: 500;
margin-bottom: 20rpx; /* margin-bottom: 20rpx; */
margin: 30rpx 40rpx 10rpx;
} }
.form-item { .form-item {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 20rpx 0; padding: 30rpx 0;
border-bottom: 1rpx solid #f0f0f0; border-bottom: 1rpx solid #f0f0f0;
} }
.form-item:last-child { .form-item:last-child {
border-bottom: none; border-bottom: none;
} }
.label { .label {
width: 200rpx; width: 205rpx;
font-size: 30rpx; font-size: 32rpx;
color: #333; color: #333;
} }
.required { .required {
@@ -440,18 +453,24 @@ const submitForm = () => {
.tips { .tips {
font-size: 24rpx; font-size: 24rpx;
color: #999; color: #999;
margin-top: 10rpx; margin-top: 44rpx;
text-align: center; text-align: center;
} }
.tips-2{
font-size: 24rpx;
color: #999;
margin: 20rpx;
text-align: center;
}
/* 底部按钮 */ /* 底部按钮 */
.btn-wrap { .btn-wrap {
padding: 20rpx; padding: 20rpx 40rpx 50rpx;
} }
.submit-btn { .submit-btn {
background-color: #007aff; background-color: #007aff;
color: #fff; color: #fff;
font-size: 32rpx; font-size: 28rpx;
height: 80rpx; height: 80rpx;
line-height: 80rpx; line-height: 80rpx;
border-radius: 8rpx; border-radius: 8rpx;

View File

@@ -167,6 +167,7 @@ const goToQrcode = () => {
color: #fff; color: #fff;
border-radius: 8rpx; border-radius: 8rpx;
height: 88rpx; height: 88rpx;
font-size: 32rpx; font-size: 28rpx;
line-height: 88rpx
} }
</style> </style>

View File

@@ -73,8 +73,8 @@
<!-- 新增邀请按钮 --> <!-- 新增邀请按钮 -->
<view class="add-btn" @click="addInvitation"> <view class="add-btn" @click="addInvitation">
<uni-icons type="plus" size="18" color="#fff"></uni-icons> <!-- <uni-icons type="plus" size="18" color="#fff"></uni-icons> -->
<text class="add-text">新增邀请</text> <text class="add-text">新增邀请+</text>
</view> </view>
</view> </view>
</template> </template>
@@ -332,5 +332,6 @@ const addInvitation = () => {
} }
.add-text { .add-text {
margin-left: 5px; margin-left: 5px;
font-size: 28rpx;
} }
</style> </style>

View File

@@ -68,6 +68,13 @@
"navigationBarTitleText": "修改密码", "navigationBarTitleText": "修改密码",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
},
{
"path": "privacy",
"style": {
"navigationBarTitleText": "用户隐私政策"
// "navigationStyle": "custom"
}
} }
] ]
}, },

View File

@@ -50,7 +50,7 @@
<up-col span="3"> <up-col span="3">
<view class="demo-layout bg-purple openClass" @click="openDoorClick"> <view class="demo-layout bg-purple openClass" @click="openDoorClick">
<view class="iconClass"> <view class="iconClass">
<image src="http://47.104.199.163:9090/images/home/openDoor.png" mode="" style="width: 70px;height: 70px;border-radius: 8px;"></image> <image src="http://47.104.199.163:9090/images/home/openDoor.png" class="iconClass-img"></image>
</view> </view>
<view class="title-dome-calss">一键开门</view> <view class="title-dome-calss">一键开门</view>
</view> </view>
@@ -58,7 +58,7 @@
<up-col span="3"> <up-col span="3">
<view class="demo-layout bg-purple-light openClass" @click="payMentClick"> <view class="demo-layout bg-purple-light openClass" @click="payMentClick">
<view class="iconClass"> <view class="iconClass">
<image src="http://47.104.199.163:9090/images/home/lifePay.png" mode="" style="width: 70px;height: 70px;border-radius: 8px;"></image> <image src="http://47.104.199.163:9090/images/home/lifePay.png" class="iconClass-img"></image>
</view> </view>
<view class="title-dome-calss">生活缴费</view> <view class="title-dome-calss">生活缴费</view>
</view> </view>
@@ -66,7 +66,7 @@
<up-col span="3"> <up-col span="3">
<view class="demo-layout bg-purple openClass" @click="onlineRepairClick"> <view class="demo-layout bg-purple openClass" @click="onlineRepairClick">
<view class="iconClass"> <view class="iconClass">
<image src="http://47.104.199.163:9090/images/home/repair.png" mode="" style="width: 70px;height: 70px;border-radius: 8px;"></image> <image src="http://47.104.199.163:9090/images/home/repair.png" class="iconClass-img"></image>
</view> </view>
<view class="title-dome-calss">在线报修</view> <view class="title-dome-calss">在线报修</view>
</view> </view>
@@ -74,7 +74,7 @@
<up-col span="3"> <up-col span="3">
<view class="demo-layout bg-purple-light openClass" @click="visitorClick"> <view class="demo-layout bg-purple-light openClass" @click="visitorClick">
<view class="iconClass"> <view class="iconClass">
<image src="http://47.104.199.163:9090/images/home/visitorInvite.png" mode="" style="width: 70px;height: 70px;border-radius: 8px;"></image> <image src="http://47.104.199.163:9090/images/home/visitorInvite.png" class="iconClass-img"></image>
</view> </view>
<view class="title-dome-calss">访客邀请</view> <view class="title-dome-calss">访客邀请</view>
</view> </view>
@@ -126,18 +126,18 @@
<up-row justify="space-between" customStyle="margin-bottom: 10px"> <up-row justify="space-between" customStyle="margin-bottom: 10px">
<up-col span="4"> <up-col span="4">
<view class="demo-layout bg-purple-light activity-img"> <view class="demo-layout bg-purple-light activity-img">
<image src="http://47.104.199.163:9090/images/home/activity-img.png" style="width: 100%;height: 100%;"></image> <image :src="activity.coverImage" style="width: 100%;height: 100%;"></image>
</view> </view>
</up-col> </up-col>
<up-col span="10"> <up-col span="8">
<view class="demo-layout bg-purple activity-info"> <view class="demo-layout bg-purple activity-info">
<view class="activity-title">{{activity.title}}</view> <view class="activity-title">{{activity.title}}</view>
<view class="activity-time">{{activity.time}}</view> <view class="activity-time">{{formatDate(activity.startTime)}}-{{formatDate(activity.endTime)}}</view>
<view class="activity-organizer"> <view class="activity-organizer">
<text>{{activity.organizer}}</text> <text>{{activity.createName}}</text>
</view> </view>
<view class="activity-enrollment"> <view class="activity-enrollment">
<text>活动名额100已报名{{activity.enrollment}}</text> <text>活动名额{{activity.quota}}已报名{{activity.appliedCount}}</text>
</view> </view>
</view> </view>
</up-col> </up-col>
@@ -147,6 +147,13 @@
</view> </view>
</scroll-view> </scroll-view>
<!-- 空状态 -->
<view v-if="activityList.length === 0" class="empty-state">
<uni-icons type="info" size="30" color="#ccc"></uni-icons>
<text class="empty-text">暂无数据</text>
</view>
</uni-card> </uni-card>
@@ -158,34 +165,14 @@
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import {onLoad,onUnload,onShow} from '@dcloudio/uni-app' import {onLoad,onUnload,onShow} from '@dcloudio/uni-app'
import {getNoticeLatest,getCurrentVillage} from "/pageSubPack/api/api.js" import moment from 'moment'
import {getNoticeLatest,getCurrentVillage,getActivitylatest} from "/pageSubPack/api/api.js"
// 列表数据状态 // 列表数据状态
const isDropdownOpen = ref(false) const isDropdownOpen = ref(false)
const scrollTop = ref(0) const scrollTop = ref(0)
const activityList = ref([ const activityList = ref([]) // 活动列表数据
{
id:'0',
statusText:'进行中',
img:'/static/logo.png',
title:'社区活动节活动',
time:'2026.3.5-2026.4.30',
organizer:'物业中心',
enrollment:'87'
},
// {
// id:'1',
// statusText:'进行中',
// img:'',
// title:'222',
// time:'2026.3.5-2026.4.30',
// organizer:'物业中心',
// enrollment:'87'
// },
])
const currentCommunity = ref('请认证小区') const currentCommunity = ref('请认证小区')
const currentVillageId = ref('') const currentVillageId = ref('')
const bannerList = ref([ const bannerList = ref([
@@ -196,6 +183,11 @@ const noticeText = ref('暂无公告')
const noticeId = ref('') const noticeId = ref('')
// =======方法======= // =======方法=======
// 格式化时间
const formatDate = (date) => {
if (!date) return ''
return moment(date).format('YYYY-MM-DD HH:mm')
}
// 公告跳转 // 公告跳转
const getNoticeMore = () =>{ const getNoticeMore = () =>{
uni.setStorageSync('sourcePage',"index") uni.setStorageSync('sourcePage',"index")
@@ -205,7 +197,7 @@ const getNoticeMore = () =>{
} }
// 接收选择小区返回的参数 // 接收选择小区返回的参数
const slelctHomeData = (data) =>{ const slelctHomeData = (data) =>{
console.log('收到B页面返回的数据', data) // console.log('收到B页面返回的数据', data)
if(data.name){ if(data.name){
currentCommunity.value = data.name currentCommunity.value = data.name
} }
@@ -214,6 +206,7 @@ const slelctHomeData = (data) =>{
} }
getCurrentCommunityData() getCurrentCommunityData()
getNoticeData() getNoticeData()
getNewActivityList()
} }
// 获取当前认证小区的方法 // 获取当前认证小区的方法
const getCurrentCommunityData = () => { const getCurrentCommunityData = () => {
@@ -235,7 +228,7 @@ const getCurrentCommunityData = () => {
} }
// 获取小区公告 // 获取首页最新小区公告
const getNoticeData = async() =>{ const getNoticeData = async() =>{
try{ try{
const res = await getNoticeLatest() const res = await getNoticeLatest()
@@ -282,6 +275,7 @@ onLoad(() => {
getCurrentCommunityData(); // 加载时获取认证小区 getCurrentCommunityData(); // 加载时获取认证小区
} }
getNoticeData() getNoticeData()
getNewActivityList()
}) })
// 页面销毁时移除监听(防止内存泄漏) // 页面销毁时移除监听(防止内存泄漏)
@@ -305,10 +299,10 @@ const payMentClick =() =>{
} }
// 点击小区选择 // 点击小区选择
const navigateToPage = () => { const navigateToPage = () => {
const token = uni.getStorageSync('token') || ''; // const token = uni.getStorageSync('token') || '';
const cachedVillageId = uni.getStorageSync('currentVillageId'); const cachedVillageId = uni.getStorageSync('currentVillageId');
// 未登录 或 未绑定小区 → 去我的页面认证 // 未登录 或 未绑定小区 → 去我的页面认证
if (!token || !cachedVillageId || cachedVillageId === '0' || cachedVillageId === 0) { if ( !cachedVillageId || cachedVillageId === '0' || cachedVillageId === 0) {
currentCommunity.value = '请去认证小区'; currentCommunity.value = '请去认证小区';
uni.setStorageSync('currentCommunity', '请去认证小区'); uni.setStorageSync('currentCommunity', '请去认证小区');
uni.showToast({ uni.showToast({
@@ -328,6 +322,33 @@ const navigateToPage = () => {
}); });
} }
}; };
// 获取首页最新活动
const getNewActivityList = async() =>{
try{
const res = await getActivitylatest()
if(res.code === 200){
if(res.data){
activityList.value = res.data || []
}else{
activityList.value = []
}
}else{
activityList.value = []
uni.showToast({
title: err.msg,
icon: 'error',
duration: 1000
})
}
}catch{
uni.showToast({
title: err.msg,
icon: 'error',
duration: 1000
})
}
}
const onlineRepairClick = () =>{ const onlineRepairClick = () =>{
@@ -352,15 +373,10 @@ const moreClick = () =>{
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.content-class{ .content-class{
// margin: 0 20rpx;
// padding: 2rpx;
background-color: #f9f9f9; background-color: #f9f9f9;
padding-bottom: 100rpx; padding-bottom: 100rpx;
box-sizing: border-box; /* 保证padding不会撑大容器 */ box-sizing: border-box; /* 保证padding不会撑大容器 */
@@ -369,7 +385,6 @@ const moreClick = () =>{
.nar-top{ .nar-top{
height: 400rpx; height: 400rpx;
width: 100%; width: 100%;
// background-color: #C0E4FB;
background: repeating-linear-gradient(to right, #EDF4FA , #C0E4FB); background: repeating-linear-gradient(to right, #EDF4FA , #C0E4FB);
position: absolute; position: absolute;
@@ -468,15 +483,20 @@ const moreClick = () =>{
align-items: center; align-items: center;
margin-top: 20rpx; margin-top: 20rpx;
.iconClass{ .iconClass{
width: 130rpx; width: 88rpx;
height: 130rpx; height: 88rpx;
border-radius: 10rpx; border-radius: 10rpx;
// opacity: 0.4; // opacity: 0.4;
} }
.iconClass-img{
width: 100%;
height: 100%;
border-radius: 8px
}
.title-dome-calss{ .title-dome-calss{
margin-top: 10rpx; margin-top: 10rpx;
font-size: 13px; font-size: 28rpx;
color: #000; color: #000;
} }
} }
@@ -572,8 +592,21 @@ const moreClick = () =>{
font-size: 15px; font-size: 15px;
margin-top: 20rpx; margin-top: 20rpx;
color: #666666; color: #666666;
} }
}
.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;
} }
.look-more-title{ .look-more-title{
color: #3E8EFF; color: #3E8EFF;

View File

@@ -2,7 +2,7 @@ const version = '3'
// 开发环境才提示,生产环境不会提示 // 开发环境才提示,生产环境不会提示
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
console.log(`\n %c uview-plus V${version} %c https://uview-plus.jiangruyi.com/ \n\n`, 'color: #ffffff; background: #3c9cff; padding:5px 0;', 'color: #3c9cff;background: #ffffff; padding:5px 0;'); //console.log(`\n %c uview-plus V${version} %c https://uview-plus.jiangruyi.com/ \n\n`, 'color: #ffffff; background: #3c9cff; padding:5px 0;', 'color: #3c9cff;background: #ffffff; padding:5px 0;');
} }
export default { export default {