Browse Source

250824

master
梁欣 12 hours ago
parent
commit
1d54cd063d
  1. 5
      api/bill.js
  2. 7
      api/legalDoc.js
  3. 8
      api/legalOrgCheck.js
  4. 7
      api/legalOrgCheckSuggest.js
  5. 4
      api/notary.js
  6. 7
      api/room.js
  7. 4
      config/color.js
  8. 2
      config/index.js
  9. 16
      main.js
  10. 3
      package.json
  11. 265
      pages.json
  12. 70
      pages/service/index.scss
  13. 38
      pages/service/index.vue
  14. 8
      pages/user/auth.vue
  15. 93
      pages/user/index.vue
  16. 320
      pages/user/join.vue
  17. 277
      pages/user/my-properties.vue
  18. 221
      pages/user/property-bill.vue
  19. 323
      pnpm-lock.yaml
  20. BIN
      static/empty-bill.png
  21. BIN
      static/empty-property.png
  22. BIN
      static/home-active.png
  23. BIN
      static/home.png
  24. BIN
      static/service-active.png
  25. BIN
      static/service.png
  26. BIN
      static/store-active.png
  27. BIN
      static/store.png
  28. 4
      static/style/common.scss
  29. BIN
      static/user-active.png
  30. BIN
      static/user.png
  31. BIN
      static/一键开门.png
  32. BIN
      static/个人投诉登记.png
  33. BIN
      static/交警.png
  34. BIN
      static/交通出行.png
  35. BIN
      static/亲子活动.png
  36. BIN
      static/保险.png
  37. BIN
      static/发布.png
  38. BIN
      static/工具.png
  39. BIN
      static/工单.png
  40. BIN
      static/快递.png
  41. BIN
      static/报修管理备份2x.png
  42. BIN
      static/收藏.png
  43. BIN
      static/服务.png
  44. BIN
      static/物业费.png
  45. BIN
      static/租赁资产.png
  46. BIN
      static/跑步.png
  47. BIN
      static/银行卡-01.png
  48. BIN
      static/门店管理.png
  49. BIN
      static/餐饮.png
  50. 13
      userPages/pages/cars.vue
  51. 13
      userPages/pages/guest.vue
  52. 238
      userPages/pages/peopleList.vue

5
api/bill.js

@ -0,0 +1,5 @@
import post, {get} from "@/api/request";
export const listBillReq = params => get('/zhsq/zhsq-tollcenter-record-bill-estate/userList', {params})
export const makePayReq = data => post('/union-pay/make-pay', data)

7
api/legalDoc.js

@ -1,7 +0,0 @@
import post, {get} from "@/api/request";
export const listLegalDocTypeReq = () => get('/law/law-legal-doc-type')
export const legalDocTypeInfoReq = (id) => get(`/law/law-legal-doc-type/${id}`)
export const legalDocConfigReq = params => get('/law/law-legal-doc-config', {params})
export const legalDocMakeReq = data => post('/law/law-legal-doc-config/make', data)
export const legalDocSendEmailReq = data => post('/law/law-legal-doc-config/send-email', data)

8
api/legalOrgCheck.js

@ -1,8 +0,0 @@
import post, {get, put} from "@/api/request";
export const listLegalOrgCheckTypeReq = () => get('/law/law-legal-org-check-type')
export const listLegalOrgCheckTypeInfoReq = (id) => get(`/law/law-legal-org-check-type/${id}`)
export const listLegalOrgCheckConfigReq = params => get('/law/law-legal-org-check-config', {params})
export const addLegalOrgCheckContentReq = data => post('/law/law-legal-org-check-content', data)
export const updateLegalOrgCheckContentReq = data => post('/law/law-legal-org-check-content/update', data)
export const listLegalOrgCheckContentReq = () => get('/law/law-legal-org-check-content')

7
api/legalOrgCheckSuggest.js

@ -1,7 +0,0 @@
import post, {get, put} from "@/api/request";
export const listLegalOrgCheckTypeSuggestReq = () => get('/law/law-legal-org-check-type-suggest')
export const listLegalOrgCheckTypeSuggestInfoReq = (id) => get(`/law/law-legal-org-check-type-suggest/${id}`)
export const listLegalOrgCheckSuggestConfigReq = params => get('/law/law-legal-org-check-config-suggest', {params})
export const addLegalOrgCheckContentSuggestReq = data => post('/law/law-legal-org-check-content-suggest', data)
export const updateLegalOrgCheckContentSuggestReq = data => put('/law/law-legal-org-check-content-suggest', data)

4
api/notary.js

@ -1,4 +0,0 @@
import post, {get} from "@/api/request";
export const listNotaryConfigReq = () => get('/law/law-notary-config')
export const notaryActionReq = data => post('/law/law-notary-list', data)

7
api/room.js

@ -0,0 +1,7 @@
import post, {get} from "@/api/request";
export const roomInfoReq = params => get('/zhsq/zhsq-base-room', {params})
export const roomInfoByCodeReq = code => get(`/zhsq/zhsq-base-room/by-code/${code}`)
export const roomListReq = params => get('/zhsq/zhsq-base-population/userBindList', {params})
export const wechatMakeJoinQrReq = data => post('/wechat/make-join-qr', data)

4
config/color.js

@ -1,7 +1,7 @@
export const YELLOW = '#e2d602'
export const ORANGE = '#fd7600'
export const ORANGE_LIGHT = '#FEEDA8'
export const GREEN = '#2ACF8D'
export const GREEN = '#98C147'
export const GREEN_LIGHT = '#96b0a3'
export const BLUE = '#2665c4'
export const BLUE_LIGHT = '#049DFF'
@ -14,5 +14,5 @@ export const PUBLISH = '#FDCB05'
export const GRAY = '#999'
export const PURPLE_LIGHT = '#7F6CDE'
export const MAIN = BLUE
export const MAIN = GREEN
export const LINEAR = 'linear-gradient(90deg, #049DFF, #2665c4)'

2
config/index.js

@ -3,7 +3,7 @@ const MAIN_API_FN = () => {
return 'http://127.0.0.1:9011'
// return 'https://sifa-api.wsdns.cn'
} else {
return 'https://zhsq-api.websoft.top'
return 'https://zhsq.websoft.top'
}
}

16
main.js

@ -6,6 +6,22 @@ Vue.use(uView)
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
Vue.prototype.$toast = (title, back = false) => {
uni.showToast({
icon: 'none',
title
})
if (back) {
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
}
Vue.prototype.$jump = (url) => {
uni.navigateTo({url})
}
App.mpType = 'app'
const app = new Vue({
...App

3
package.json

@ -2,5 +2,8 @@
"devDependencies": {
"sass": "^1.89.2",
"sass-loader": "^16.0.5"
},
"dependencies": {
"dayjs": "^1.11.13"
}
}

265
pages.json

@ -1,115 +1,156 @@
{
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "祥安e家",
"navigationBarBackgroundColor": "#4facfe",
"navigationBarTextStyle": "white",
"backgroundColor": "#f5f5f5",
"pages": [
//pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "祥安e家",
"navigationBarBackgroundColor": "#98C147",
"navigationBarTextStyle": "white",
"backgroundColor": "#f5f5f5",
"navigationStyle": "custom"
}
},
{
"path": "pages/service/index",
"style": {
"navigationBarTitleText": "服务",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"backgroundColor": "#f5f5f5",
"navigationStyle": "custom"
}
},
{
"path": "pages/store/index",
"style": {
"navigationBarTitleText": "商城",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"backgroundColor": "#f5f5f5",
"navigationStyle": "custom"
}
},
{
"path": "pages/user/index",
"style": {
"navigationBarTitleText": "我的",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"backgroundColor": "#f5f5f5",
"navigationStyle": "custom"
}
},
{
"path": "pages/ai/index",
"style": {
"navigationBarTitleText": "AI",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"backgroundColor": "#f5f5f5",
"navigationStyle": "custom"
}
},
{
"path": "pages/user/auth",
"style": {
"navigationBarTitleText": "业主认证",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"backgroundColor": "#f5f5f5",
"navigationStyle": "custom"
}
},
{
"path": "pages/user/select-community",
"style": {
"navigationBarTitleText": "小区选择"
}
},
{
"path": "pages/user/select-room",
"style": {
"navigationBarTitleText": "房屋选择"
}
}
],
"tabBar": {
"color": "#999999",
"selectedColor": "#4facfe",
"backgroundColor": "#ffffff",
"borderStyle": "black",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/home.png",
"selectedIconPath": "static/home.png"
},
{
"pagePath": "pages/service/index",
"text": "服务",
"iconPath": "static/service.png",
"selectedIconPath": "static/service.png"
},
{
"pagePath": "pages/store/index",
"text": "商城",
"iconPath": "static/store.png",
"selectedIconPath": "static/store.png"
},
{
"pagePath": "pages/user/index",
"text": "我的",
"iconPath": "static/user.png",
"selectedIconPath": "static/user.png"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "祥安e家",
"navigationBarBackgroundColor": "#4facfe",
"backgroundColor": "#f5f5f5"
},
"uniIdRouter": {}
}
},
{
"path": "pages/service/index",
"style": {
"navigationBarTitleText": "服务",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"backgroundColor": "#f5f5f5"
}
},
{
"path": "pages/store/index",
"style": {
"navigationBarTitleText": "商城",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"backgroundColor": "#f5f5f5",
"navigationStyle": "custom"
}
},
{
"path": "pages/user/index",
"style": {
"navigationBarTitleText": "我的",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"backgroundColor": "#f5f5f5",
"navigationStyle": "custom"
}
},
{
"path": "pages/ai/index",
"style": {
"navigationBarTitleText": "AI",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"backgroundColor": "#f5f5f5",
"navigationStyle": "custom"
}
},
{
"path": "pages/user/auth",
"style": {
"navigationBarTitleText": "业主认证",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"backgroundColor": "#f5f5f5",
"navigationStyle": "custom"
}
},
{
"path": "pages/user/join",
"style": {
"navigationBarTitleText": "加入",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"backgroundColor": "#f5f5f5",
"navigationStyle": "custom"
}
},
{
"path": "pages/user/select-community",
"style": {
"navigationBarTitleText": "小区选择"
}
},
{
"path": "pages/user/select-room",
"style": {
"navigationBarTitleText": "房屋选择"
}
},
{
"path": "pages/user/property-bill",
"style": {
"navigationBarTitleText": "我的账单"
}
},
{
"path": "pages/user/my-properties",
"style": {
"navigationBarTitleText": "我的房产"
}
}
],
"subPackages": [
{
"root": "userPages",
"pages": [
{
"path": "pages/cars",
"style": {
"navigationBarTitleText": "我的车位车辆"
}
},
{
"path": "pages/guest",
"style": {
"navigationBarTitleText": "访客记录"
}
}
]
}
],
"tabBar": {
"color": "#999999",
"selectedColor": "#98C147",
"backgroundColor": "#ffffff",
"borderStyle": "black",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/home.png",
"selectedIconPath": "static/home-active.png"
},
{
"pagePath": "pages/service/index",
"text": "服务",
"iconPath": "static/service.png",
"selectedIconPath": "static/service-active.png"
},
// {
// "pagePath": "pages/store/index",
// "text": "商城",
// "iconPath": "static/store.png",
// "selectedIconPath": "static/store-active.png"
// },
{
"pagePath": "pages/user/index",
"text": "我的",
"iconPath": "static/user.png",
"selectedIconPath": "static/user-active.png"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "祥安e家",
"navigationBarBackgroundColor": "#98C147",
"backgroundColor": "#f5f5f5"
},
"uniIdRouter": {}
}

70
pages/service/index.scss

@ -1,19 +1,16 @@
.service-page {
min-height: 100vh;
background-color: #f5f5f5;
padding: 20rpx;
/* 服务分类 */
.service-section {
background-color: #ffffff;
border-radius: 20rpx;
margin: 30rpx;
margin: 20rpx;
overflow: hidden;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
&:first-child {
margin-top: 30rpx;
}
/* 分类标题 */
.section-header {
padding: 40rpx 40rpx 30rpx 40rpx;
@ -78,67 +75,4 @@
}
}
/* 响应式调整 */
@media (max-width: 375px) {
.service-section {
margin: 0 20rpx 20rpx 20rpx;
.section-header {
padding: 30rpx 30rpx 20rpx 30rpx;
.section-title {
font-size: 32rpx;
}
}
.service-grid {
padding: 20rpx 16rpx;
.service-item {
padding: 16rpx;
.service-icon {
width: 70rpx;
height: 70rpx;
margin-bottom: 12rpx;
.icon-emoji {
font-size: 32rpx;
}
}
.service-name {
font-size: 22rpx;
max-width: 100rpx;
}
}
}
}
}
/* 超小屏幕适配 */
@media (max-width: 320px) {
.service-section {
.service-grid {
grid-template-columns: repeat(3, 1fr);
.service-item {
.service-icon {
width: 60rpx;
height: 60rpx;
.icon-emoji {
font-size: 28rpx;
}
}
.service-name {
font-size: 20rpx;
max-width: 80rpx;
}
}
}
}
}
}

38
pages/service/index.vue

@ -13,7 +13,7 @@
@click="handleServiceClick(service)"
>
<view class="service-icon">
<text class="icon-emoji">{{ service.icon }}</text>
<u-icon :name="service.icon" size="60rpx"/>
</view>
<text class="service-name">{{ service.name }}</text>
</view>
@ -32,7 +32,7 @@
@click="handleServiceClick(service)"
>
<view class="service-icon">
<text class="icon-emoji">{{ service.icon }}</text>
<u-icon :name="service.icon" size="60rpx"/>
</view>
<text class="service-name">{{ service.name }}</text>
</view>
@ -46,25 +46,25 @@ export default {
data() {
return {
propertyServices: [
{ id: 1, name: '物业缴费', icon: '🏠', path: '/pages/property-payment/index' },
{ id: 2, name: '远程开门', icon: '🚪', path: '/pages/remote-door/index' },
{ id: 3, name: '报事报修', icon: '🔧', path: '/pages/repair/repair' },
{ id: 4, name: '投诉建议', icon: '📝', path: '/pages/complaint/index' }
{ id: 1, name: '物业缴费', icon: '/static/物业费.png', path: '/pages/property-payment/index' },
{ id: 2, name: '远程开门', icon: '/static/一键开门.png', path: '/pages/remote-door/index' },
{ id: 3, name: '报事报修', icon: '/static/报修管理备份2x.png', path: '/pages/repair/repair' },
{ id: 4, name: '投诉建议', icon: '/static/物业费.png', path: '/pages/complaint/index' }
],
lifeServices: [
{ id: 1, name: '生活缴费', icon: '💳', path: '/pages/payment/index' },
{ id: 2, name: '社区育儿', icon: '👶', path: '' },
{ id: 3, name: '交管12123', icon: '🚗', path: '' },
{ id: 4, name: '租中心', icon: '🏘️', path: '' },
{ id: 5, name: '餐饮服务', icon: '🍽️', path: '' },
{ id: 6, name: '常用快递', icon: '📦', path: '' },
{ id: 7, name: '掌上银行', icon: '🏦', path: '' },
{ id: 8, name: '保险服务', icon: '🛡️', path: '' },
{ id: 9, name: '安居客', icon: '🏠', path: '' },
{ id: 10, name: 'e出行', icon: '🚌', path: '' },
{ id: 11, name: '常用工具', icon: '🔨', path: '' },
{ id: 12, name: '健康运动', icon: '🏃', path: '' },
{ id: 13, name: '小区服务', icon: '🤝', path: '' }
{ id: 1, name: '生活缴费', icon: '/static/20-缴费记录.png', path: '/pages/payment/index' },
{ id: 2, name: '社区育儿', icon: '/static/亲子活动.png', path: '' },
{ id: 3, name: '交管12123', icon: '/static/交警.png', path: '' },
{ id: 4, name: '租中心', icon: '/static/租赁资产.png', path: '' },
{ id: 5, name: '餐饮服务', icon: '/static/餐饮.png', path: '' },
{ id: 6, name: '常用快递', icon: '/static/快递.png', path: '' },
{ id: 7, name: '掌上银行', icon: '/static/银行卡-01.png', path: '' },
{ id: 8, name: '保险服务', icon: '/static/保险.png', path: '' },
{ id: 9, name: '安居客', icon: '/static/物业费.png', path: '' },
{ id: 10, name: 'e出行', icon: '/static/交通出行.png', path: '' },
{ id: 11, name: '常用工具', icon: '/static/工具.png', path: '' },
{ id: 12, name: '健康运动', icon: '/static/跑步.png', path: '' },
{ id: 13, name: '小区服务', icon: '/static/服务.png', path: '' }
]
}
},

8
pages/user/auth.vue

@ -48,7 +48,7 @@
<text>真实姓名</text>
</view>
<view class="form-value">
<input class="form-input" v-model="formData.name" placeholder="请输入真实姓名"/>
<u-input border="none" v-model="formData.name" placeholder="请输入真实姓名"/>
</view>
</view>
@ -59,7 +59,7 @@
<text>手机号</text>
</view>
<view class="form-value">
<input class="form-input" v-model="formData.phone" placeholder="请输入手机号"/>
<u-input border="none" readonly v-model="formData.phone" placeholder="请输入手机号"/>
</view>
</view>
@ -124,8 +124,8 @@ export default {
},
methods: {
async getUserData(){
const res = await userInfoReq()
console.log(res)
const {data} = await userInfoReq()
this.formData.phone = data.phone
},
goBack() {
uni.navigateBack()

93
pages/user/index.vue

@ -7,12 +7,14 @@
<view class="user-info">
<view class="nickname">{{ userData ? userData.nickname : '请登录' }}</view>
<view class="auth-row" v-if="userData">
<button class="auth-btn" v-if="userData.wechatUser.isAudit === 3" size="mini" @click="navTo('/pages/user/auth')">
<button class="auth-btn" v-if="userData.wechatUser.isAudit === 3" size="mini"
@click="navTo('/pages/user/auth')">
去认证
</button>
<button class="auth-btn" v-if="userData.wechatUser.isAudit === 0" size="mini">认证审核中</button>
<button class="auth-btn" v-if="userData.wechatUser.isAudit === 1" size="mini">认证通过</button>
<button class="auth-btn" v-if="userData.wechatUser.isAudit === 2" size="mini" @click="navTo('/pages/user/auth')">
<button class="auth-btn" v-if="userData.wechatUser.isAudit === 2" size="mini"
@click="navTo('/pages/user/auth')">
认证拒绝
</button>
</view>
@ -29,65 +31,68 @@
</view>
<!-- 积分卡片 -->
<!-- <view class="score-card">-->
<!-- <view class="score-left">-->
<!-- <image class="score-icon" src="https://img.icons8.com/color/48/000000/hexagonal-structure.png"/>-->
<!-- <text class="score-title">我的积分</text>-->
<!-- </view>-->
<!-- <view class="score-value">&#45;&#45;-->
<!-- <text class="score-unit"></text>-->
<!-- </view>-->
<!-- </view>-->
<!-- <view class="score-card">-->
<!-- <view class="score-left">-->
<!-- <image class="score-icon" src="https://img.icons8.com/color/48/000000/hexagonal-structure.png"/>-->
<!-- <text class="score-title">我的积分</text>-->
<!-- </view>-->
<!-- <view class="score-value">&#45;&#45;-->
<!-- <text class="score-unit"></text>-->
<!-- </view>-->
<!-- </view>-->
<!-- 快捷入口 -->
<view class="quick-entry">
<view class="entry-item">
<view class="entry-item" @click="navTo('/pages/user/my-properties')">
<image class="entry-img" src="/static/房产.png"/>
<text class="entry-title">我的房产</text>
</view>
<view class="entry-item">
<image class="entry-img" src="/static/车位信息.png"/>
<image class="entry-img" src="/static/车位信息.png" @click="jumpWithAuth('/userPages/pages/cars')"/>
<text class="entry-title">我的车位车辆</text>
</view>
</view>
<!-- 功能区 -->
<view class="func-area">
<view class="func-item">
<view class="func-item" @click="navTo('/pages/user/my-properties')">
<image class="entry-img" src="/static/我的家人.png"/>
<text class="func-text">添加家人</text>
</view>
<view class="func-item">
<image class="entry-img" src="/static/汽车.png"/>
<image class="entry-img" src="/static/汽车.png" @click="jumpWithAuth('/userPages/pages/cars')"/>
<text class="func-text">添加车辆</text>
</view>
<view class="func-item">
<image class="entry-img" src="/static/访客.png"/>
<image class="entry-img" src="/static/访客.png" @click="jumpWithAuth('/userPages/pages/cars')"/>
<text class="func-text">访客记录</text>
</view>
<view class="func-item">
<view class="func-item" @click="jumpWithAuth('/pages/user/property-bill')">
<image class="entry-img" src="/static/20-缴费记录.png"/>
<text class="func-text">我的账单</text>
</view>
</view>
<!-- 列表区 -->
<view class="list-area">
<view class="list-item">
<text class="list-icon">📄</text>
<text class="list-title">我的工单</text>
<text class="arrow"></text>
</view>
<view class="list-item">
<text class="list-icon">📤</text>
<text class="list-title">我的发布</text>
<text class="arrow"></text>
</view>
<view class="list-item">
<text class="list-icon"></text>
<text class="list-title">我的收藏</text>
<text class="arrow"></text>
</view>
<!-- <view class="list-area">-->
<!-- <view class="list-item">-->
<!-- <u-icon name="/static/工单.png"/>-->
<!-- <text class="list-title">我的工单</text>-->
<!-- <text class="arrow"></text>-->
<!-- </view>-->
<!-- <view class="list-item">-->
<!-- <u-icon name="/static/发布.png"/>-->
<!-- <text class="list-title">我的发布</text>-->
<!-- <text class="arrow"></text>-->
<!-- </view>-->
<!-- <view class="list-item">-->
<!-- <u-icon name="/static/收藏.png"/>-->
<!-- <text class="list-title">我的收藏</text>-->
<!-- <text class="arrow"></text>-->
<!-- </view>-->
<!-- </view>-->
<view class="m-20">
<u-button type="primary" shape="circle" @click="logout" v-if="isLogin">退出登录</u-button>
</view>
<Login ref="Login" @done="getUserData"></Login>
</view>
@ -95,7 +100,7 @@
<script>
import Login from "@/components/Login.vue";
import {getUserInfo} from "@/util/user";
import {clearUserInfo, getUserInfo} from "@/util/user";
import {userInfoReq} from "@/api/user";
export default {
@ -120,22 +125,30 @@ export default {
const res = await userInfoReq()
if (res) {
this.userData = res.data
this.isLogin = true
}
},
onLogout() {
logout() {
uni.showModal({
title: '提示',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
uni.removeStorageSync('access_token')
uni.removeStorageSync('TenantId')
uni.removeStorageSync('UserId')
uni.removeStorageSync('userInfo')
uni.reLaunch({url: '/pages/index/index'})
this.isLogin = false
this.userData = null
clearUserInfo()
this.$refs.Login.open()
}
}
})
},
jumpWithAuth(url) {
if (!this.userData || this.userData.wechatUser.isAuth !== 1) {
this.$toast('请先完成认证')
this.$jump('/pages/user/auth')
} else {
this.$jump(url)
}
}
},
onShow() {

320
pages/user/join.vue

@ -0,0 +1,320 @@
<template>
<view class="auth-page">
<!-- 自定义导航栏 -->
<view class="custom-navbar">
<view class="status-bar" :style="{height: statusBarHeight + 'px'}"></view>
<view class="nav-content">
<view class="nav-left" @click="goBack">
<text class="nav-back"></text>
</view>
<view class="nav-title">加入</view>
</view>
</view>
<!-- 表单内容 -->
<view class="form-container">
<!-- 所属小区 -->
<view class="form-item">
<view class="form-label">
<text class="required">*</text>
<text>所属小区</text>
</view>
<view class="form-value">
<text :class="selectedCommunity ? 'value-text' : 'placeholder'">
{{ selectedCommunity }}
</text>
</view>
</view>
<!-- 楼栋信息 -->
<view class="form-item">
<view class="form-label">
<text class="required">*</text>
<text>楼栋信息</text>
</view>
<view class="form-value">
<text :class="selectedRoom ? 'value-text' : 'placeholder'">
{{ selectedRoom }}
</text>
</view>
</view>
<!-- 真实姓名 -->
<view class="form-item">
<view class="form-label">
<text class="required">*</text>
<text>真实姓名</text>
</view>
<view class="form-value">
<u-input border="none" v-model="formData.name" placeholder="请输入真实姓名"/>
</view>
</view>
<!-- 手机号 -->
<view class="form-item">
<view class="form-label">
<text class="required">*</text>
<text>手机号</text>
</view>
<view class="form-value">
<u-input border="none" v-model="formData.phone" readonly placeholder="请输入手机号"/>
</view>
</view>
<!-- 业主类型 -->
<view class="form-item">
<view class="form-label">
<text>业主类型</text>
</view>
<view class="form-value" @click="showType = true">
<text class="value-text">{{ ownerType }}</text>
<text class="arrow"></text>
</view>
</view>
</view>
<!-- 底部提交按钮 -->
<view class="submit-container">
<button class="submit-btn" @click="submitAuth">提交</button>
</view>
<u-picker :columns="[ownerTypeList]"></u-picker>
<u-picker :show="showType" :columns="[ownerTypeList]" @cancel="showType = false"
@confirm="selectType" closeOnClickOverlay
/>
<Login ref="Login" @done="getUserData"></Login>
</view>
</template>
<script>
import {communityListReq, roomListReq} from "@/api/common";
import {ownerAuditReq, userInfoReq} from "@/api/user";
import Login from "@/components/Login.vue";
import {roomInfoByCodeReq} from "@/api/room";
import {getUserInfo} from "@/util/user";
export default {
components: {Login},
data() {
return {
statusBarHeight: 0,
realName: '梁欣',
phone: '18577375184',
selectedCommunity: '',
selectedRoom: '',
ownerType: '家属',
livingType: '常驻',
communityList: [],
roomList: [],
showCommunity: false,
showRoom: false,
formData: {
baseVillageVillageCode: '',
baseBuildingBuildCode: '',
baseUnitUnitCode: '',
baseRoomRoomCode: '',
ownerType: 2,
personType: '',
name: '',
direct: true
},
ownerTypeList: [
'家属',
'租客',
'工作人员',
],
showType: false
}
},
onLoad(e) {
if (!getUserInfo().token) this.$refs.Login.open()
this.formData.baseRoomRoomCode = e.scene
//
const systemInfo = uni.getSystemInfoSync()
this.statusBarHeight = systemInfo.statusBarHeight
this.getUserData()
},
methods: {
async getUserData() {
const {data} = await userInfoReq()
this.formData.phone = data.phone
await this.getRoomInfo()
},
goBack() {
uni.navigateBack()
},
async getRoomInfo() {
const {data} = await roomInfoByCodeReq(this.formData.baseRoomRoomCode)
this.formData.baseBuildingBuildCode = data.baseBuildingBuildCode
this.formData.baseCommunityCommunityCode = data.baseCommunityCommunityCode
this.formData.baseVillageVillageCode = data.baseVillageVillageCode
this.formData.baseUnitUnitCode = data.baseUnitUnitCode
this.selectedCommunity = data.village
this.selectedRoom = `${data.building}-${data.unit}-${data.roomNumber}`
},
async submitAuth() {
await ownerAuditReq(this.formData)
uni.showToast({
title: '提交成功',
icon: 'success'
})
setTimeout(() => {
uni.switchTab({url: '/pages/index/index'})
}, 1500)
},
selectType({value}) {
this.ownerType = value[0]
const index = this.ownerTypeList.findIndex(item => item === value[0])
this.formData.ownerType = index + 2
console.log(this.formData.ownerType)
this.showType = false
}
}
}
</script>
<style scoped lang="scss">
.auth-page {
min-height: 100vh;
background: linear-gradient(180deg, #FF6B35 0%, #FF8A65 100%);
}
.custom-navbar {
background: linear-gradient(180deg, #FF6B35 0%, #FF8A65 100%);
.nav-content {
height: 88rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32rpx;
position: relative;
}
.nav-left {
width: 80rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: flex-start;
}
.nav-back {
font-size: 48rpx;
color: #fff;
font-weight: 300;
}
.nav-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 36rpx;
color: #fff;
font-weight: 500;
}
.nav-right {
display: flex;
align-items: center;
gap: 24rpx;
}
.nav-icon {
width: 60rpx;
height: 60rpx;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
color: #fff;
}
}
.form-container {
margin: 32rpx 32rpx 0 32rpx;
background: #fff;
border-radius: 24rpx;
overflow: hidden;
}
.form-item {
display: flex;
align-items: center;
padding: 32rpx 32rpx;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
}
.form-label {
width: 200rpx;
display: flex;
align-items: center;
font-size: 32rpx;
color: #333;
.required {
color: #FF6B35;
margin-right: 8rpx;
font-size: 32rpx;
}
}
.form-value {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
.placeholder {
color: #999;
font-size: 32rpx;
}
.value-text {
color: #333;
font-size: 32rpx;
}
.arrow {
color: #ccc;
font-size: 36rpx;
font-weight: 300;
}
}
.form-input {
flex: 1;
font-size: 32rpx;
color: #333;
text-align: right;
}
.submit-container {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 32rpx;
background: #fff;
}
.submit-btn {
width: 100%;
height: 96rpx;
background: linear-gradient(90deg, #FF6B35 0%, #FF8A65 100%);
border-radius: 48rpx;
border: none;
font-size: 36rpx;
color: #fff;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
}
</style>

277
pages/user/my-properties.vue

@ -0,0 +1,277 @@
<template>
<view class="my-properties-page">
<!-- 房产列表 -->
<view class="property-list">
<view
class="property-card"
v-for="(property, index) in properties"
:key="index"
>
<view class="flex justify-between items-center">
<view class="card-header">
<image class="community-icon" src="/static/房产.png" mode="aspectFit"></image>
<view class="flex justify-start items-center">
<text class="community-name">{{ property.villageName }}</text>
<text class="mx-25">|</text>
<text class="text-25 mr-10 text-gray">{{ property.peopleNum }}</text>
</view>
<view class="identity-badge" :class="identityClass[property.ownerType]">
{{ ownerType[property.ownerType] }}
</view>
</view>
<u-icon name="arrow-right"/>
</view>
<view class="property-info">
<view class="info-row">
<text class="info-label">楼栋</text>
<text class="info-value">{{ property.buildingName }}</text>
</view>
<view class="info-row">
<text class="info-label">单元</text>
<text class="info-value">{{ property.unitName }}</text>
</view>
<view class="info-row">
<text class="info-label">房号</text>
<text class="info-value">{{ property.roomNumber }}</text>
</view>
</view>
<!-- <view class="card-actions">-->
<!-- <button class="action-btn danger">-->
<!-- 解除绑定-->
<!-- </button>-->
<!-- </view>-->
<view class="flex justify-end items-center w-100p">
<u-button type="primary" shape="circle" :custom-style="{width: '200rpx', margin: '0 20rpx'}"
size="small"
@click="showShare(property.baseRoomRoomCode)">
邀请绑定
</u-button>
</view>
</view>
</view>
<u-gap height="120rpx"></u-gap>
<!-- 新增按钮 -->
<view class="add-property-button">
<button class="add-btn" @click="addProperty">
<u-icon name="plus" color="#fff" size="30rpx"></u-icon>
新增房产
</button>
</view>
<!-- 空状态 -->
<view class="empty-state" v-if="properties.length === 0">
<image class="empty-icon" src="/static/empty-property.png" mode="aspectFit"></image>
<text class="empty-text">您还没有绑定任何房产</text>
</view>
<u-popup :show="showPopup" close-on-click-overlay round="10" mode="bottom">
<view class="p-30">
<view class="text-30 my-20">邀请家人</view>
<view class="flex justify-center items-center my-20">
<u-image :src="qr" width="300rpx" height="300rpx"/>
</view>
<u-button shape="circle" type="primary" @click="showPopup = false">关闭</u-button>
</view>
</u-popup>
</view>
</template>
<script>
import {roomListReq, wechatMakeJoinQrReq} from "@/api/room";
export default {
data() {
return {
properties: [],
identityClass: [
'',
'owner',
'family',
'tenant',
'tenant',
],
ownerType: [
'',
'业主',
'家属',
'租客',
'工作人员',
],
qr: '',
showPopup: false
};
},
methods: {
async getRoomList() {
const {data} = await roomListReq({
withPeopleNum: true
})
this.properties = data
},
addProperty() {
//
uni.navigateTo({
url: '/pages/user/auth'
});
},
async showShare(roomCode) {
const {data} = await wechatMakeJoinQrReq({
roomCode
})
this.qr = data
this.showPopup = true
}
},
onShow() {
this.getRoomList();
},
};
</script>
<style scoped lang="scss">
page {
background-color: #f5f5f5;
}
.my-properties-page {
padding: 24rpx;
}
.property-card {
background-color: #fff;
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 24rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
}
.card-header {
display: flex;
align-items: center;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.community-icon {
width: 40rpx;
height: 40rpx;
margin-right: 16rpx;
}
.community-name {
font-size: 32rpx;
font-weight: bold;
color: #333;
flex: 1;
}
.identity-badge {
font-size: 24rpx;
padding: 4rpx 12rpx;
border-radius: 8rpx;
color: #fff;
&.owner {
background-color: #4facfe;
}
&.family {
background-color: #28a745;
}
&.tenant {
background-color: #ffc107;
color: #333;
}
}
.property-info {
padding: 20rpx 0;
}
.info-row {
display: flex;
font-size: 28rpx;
line-height: 1.8;
}
.info-label {
color: #999;
width: 120rpx;
}
.info-value {
color: #333;
}
.card-actions {
display: flex;
justify-content: flex-end;
padding-top: 16rpx;
border-top: 1rpx solid #f0f0f0;
gap: 20rpx;
}
.action-btn {
font-size: 26rpx;
padding: 0 24rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 30rpx;
margin: 0;
&.default {
background-color: #fff;
color: #333;
border: 1rpx solid #ccc;
}
&.danger {
background-color: #f56c6c;
color: #fff;
}
}
.add-property-button {
position: fixed;
bottom: 40rpx;
left: 50%;
transform: translateX(-50%);
width: 90%;
}
.add-btn {
background: linear-gradient(to right, #769636, #98C147);
color: #fff;
border-radius: 50rpx;
font-size: 32rpx;
display: flex;
align-items: center;
justify-content: center;
gap: 10rpx;
border: none;
}
.empty-state {
text-align: center;
padding-top: 200rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.empty-icon {
width: 200rpx;
height: 200rpx;
}
.empty-text {
font-size: 28rpx;
color: #999;
margin-top: 20rpx;
}
</style>

221
pages/user/property-bill.vue

@ -0,0 +1,221 @@
<template>
<view class="min-height bg-gray-light">
<view class="p-20 bg-white flex justify-between items-center text-30" @click="showRoom = true">
<template v-if="currentRoom">
<text>{{ currentRoom.title }}</text>
<u-icon name="arrow-right"/>
</template>
</view>
<view class="p-10">
<u-subsection :list="subsection" :current="billState" mode="button" @change="onChangeSubsection"/>
<template v-if="billList.length">
<view v-for="(item, index) in billList" :key="index"
class="card flex flex-col justify-center items-center my-20">
<view class="flex justify-between items-center mb-15 w-100p">
<view class="flex justify-start items-center" @click="changeSelect(index)">
<u-icon v-if="billState === 0" :name="item.selected ? 'checkmark-circle-fill' : 'checkmark-circle'"
:color="item.selected ? MAIN() : '#999'"/>
<text class="text-25 font-bold">{{ item.month }}</text>
</view>
<view class="flex justify-end items-center" @click="changeShow(index)">
<text class="text-orange text-28 font-bold mr-10">{{ item.totalAmount }}</text>
<u-icon :name="item.show ? 'arrow-down' : 'arrow-right'"/>
</view>
</view>
<view class="p-20 bg-gray-light rounded w-85p p-15 flex flex-col justify-center items-center"
v-if="item.show">
<view class="flex flex-col justify-center items-center w-100p mb-20" v-for="(bill, billIndex) in item.bills"
:key="billIndex">
<view class="flex justify-between items-center w-100p mb-15 text-25">
<text class="font-bold">{{ bill.feeItemName }}</text>
<text class="font-bold text-orange">{{ bill.billAmount }}</text>
</view>
<view class="flex justify-between items-center w-100p mb-15 text-25 text-gray">
<text>{{ bill.feeStandardExplain }}</text>
</view>
<view class="flex justify-between items-center w-100p mb-15 text-25 text-gray">
<text>{{ bill.billName }}</text>
</view>
<view class="flex justify-between items-center w-100p mb-15 text-25 ">
<text class="text-gray">缴费数量({{ bill.amount }})*单价({{ bill.feeStandardValue }})</text>
<text>{{ bill.billAmount }}</text>
</view>
<template v-if="bill.feeStandardExplain.includes('电费') || bill.feeStandardExplain.includes('水费')">
<view class="flex justify-between items-center w-100p mb-15 text-25 text-gray">
<text class="text-gray">上期抄表数:</text>
<text>{{ bill.lastMeterNum }}</text>
</view>
<view class="flex justify-between items-center w-100p mb-15 text-25 text-gray">
<text class="text-gray">本期抄表数:</text>
<text>{{ bill.nowMeterNum }}</text>
</view>
</template>
<view class="flex justify-between items-center w-100p mb-15 text-25 text-green" v-if="!!bill.payItem">
<text>支付时间:</text>
<text>{{ dayjs(bill.payItem.payTime).format('YYYY-MM-DD HH:mm:ss') }}</text>
</view>
</view>
</view>
</view>
</template>
<view class="flex flex-col justify-center items-center mt-50" v-else>
<u-icon name="/static/empty-bill.png" size="200rpx"/>
<text class="text-gray mt-20">暂无账单</text>
</view>
</view>
<view class="footer" v-if="billState === 0">
<view class="m-30">
<view class="bg-white circle p-30 flex justify-between items-center">
<view class="flex justify-start items-center flex-1 mx-25">
<text>合计:</text>
<text class="text-orange text-30 font-bold ml-15">{{ totalAmount }}</text>
</view>
<view class=" flex-1 mx-25">
<u-button type="primary" shape="circle" :disabled="totalAmount <= 0" @click="payBill">立即缴费</u-button>
</view>
</view>
</view>
</view>
<u-picker :show="showRoom" :columns="[roomList]" keyName="title" @confirm="selectRoom"
@cancel="showRoom = true"/>
</view>
</template>
<script>
import {listBillReq, makePayReq} from "@/api/bill";
import {roomListReq} from "@/api/room";
import {MAIN} from "@/config/color";
import dayjs from "dayjs";
export default {
computed: {
dayjs() {
return dayjs
}
},
data() {
return {
roomList: [],
billList: [],
currentRoom: null,
showRoom: false,
totalAmount: 0,
billState: 0,
subsection: ['未缴费', '已缴费']
}
},
methods: {
MAIN() {
return MAIN
},
goBack() {
uni.navigateBack();
},
async getRoomList() {
const {data} = await roomListReq()
this.roomList = data.map(item => {
item.title = ''
if (item.villageName) item.title += item.villageName
if (item.buildingName) item.title += `-${item.buildingName}`
if (item.unitName) item.title += `-${item.unitName}`
if (item.roomNumber) item.title += `-${item.roomNumber}`
return item
})
if (this.roomList.length) {
this.currentRoom = this.roomList[0]
await this.getBillData()
}
},
changeShow(index) {
this.billList[index].show = !this.billList[index].show
},
changeSelect(index) {
this.billList[index].selected = !this.billList[index].selected
this.calTotalAmount()
},
onChangeSubsection(val) {
this.billState = val
this.getBillData()
},
selectRoom({value}) {
this.currentRoom = value[0]
this.getBillData()
this.showRoom = false
},
async getBillData() {
this.billList = []
this.totalAmount = 0
const params = {
roomIdList: this.currentRoom.baseRoomRoomCode,
billState: this.billState + 2
}
try {
const {data} = await listBillReq(params);
this.billList = data.map(item => {
item.show = true
item.selected = true
item.totalAmount = 0
item.bills.map(bill => {
item.totalAmount += bill.billAmount
return bill
})
return item
})
this.calTotalAmount()
console.log(this.billList)
} catch (error) {
console.error('获取账单数据失败:', error);
}
},
calTotalAmount() {
this.totalAmount = 0
this.billList.map(item => {
if (item.selected) {
this.totalAmount += item.totalAmount
}
})
},
async payBill() {
uni.showLoading({title: '支付中'})
const idList = []
this.billList.map(item => {
if (item.selected) {
item.bills.map(bill => {
idList.push(bill.id)
})
}
})
const payRes = await makePayReq({
idList
}).finally(() => uni.hideLoading())
const jsonData = JSON.parse(payRes.message)
const miniPayReq = jsonData.miniPayRequest
const _this = this
uni.requestPayment({
provider: 'wxpay',
timeStamp: miniPayReq.timeStamp,
nonceStr: miniPayReq.nonceStr,
package: miniPayReq.package,
signType: miniPayReq.signType,
paySign: miniPayReq.paySign,
success: function (res) {
uni.showToast({
title: '支付成功',
icon: 'success'
});
_this.getBillData()
},
fail: function (err) {
console.log('支付失败', err);
}
})
}
},
onLoad() {
this.getRoomList();
}
}
</script>
<style scoped lang="scss">
</style>

323
pnpm-lock.yaml

@ -0,0 +1,323 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
dependencies:
dayjs:
specifier: ^1.11.13
version: 1.11.13
devDependencies:
sass:
specifier: ^1.89.2
version: 1.90.0
sass-loader:
specifier: ^16.0.5
version: 16.0.5(sass@1.90.0)
packages:
'@parcel/watcher-android-arm64@2.5.1':
resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [android]
'@parcel/watcher-darwin-arm64@2.5.1':
resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [darwin]
'@parcel/watcher-darwin-x64@2.5.1':
resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [darwin]
'@parcel/watcher-freebsd-x64@2.5.1':
resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [freebsd]
'@parcel/watcher-linux-arm-glibc@2.5.1':
resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
'@parcel/watcher-linux-arm-musl@2.5.1':
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
'@parcel/watcher-linux-arm64-glibc@2.5.1':
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
'@parcel/watcher-linux-arm64-musl@2.5.1':
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
'@parcel/watcher-linux-x64-glibc@2.5.1':
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
'@parcel/watcher-linux-x64-musl@2.5.1':
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
'@parcel/watcher-win32-arm64@2.5.1':
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [win32]
'@parcel/watcher-win32-ia32@2.5.1':
resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==}
engines: {node: '>= 10.0.0'}
cpu: [ia32]
os: [win32]
'@parcel/watcher-win32-x64@2.5.1':
resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [win32]
'@parcel/watcher@2.5.1':
resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
engines: {node: '>= 10.0.0'}
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
chokidar@4.0.3:
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
engines: {node: '>= 14.16.0'}
dayjs@1.11.13:
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
detect-libc@1.0.3:
resolution: {integrity: sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=}
engines: {node: '>=0.10'}
hasBin: true
fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
immutable@5.1.3:
resolution: {integrity: sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==}
is-extglob@2.1.1:
resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=}
engines: {node: '>=0.10.0'}
is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
micromatch@4.0.8:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
neo-async@2.6.2:
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
node-addon-api@7.1.1:
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
readdirp@4.1.2:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'}
sass-loader@16.0.5:
resolution: {integrity: sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==}
engines: {node: '>= 18.12.0'}
peerDependencies:
'@rspack/core': 0.x || 1.x
node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0
sass: ^1.3.0
sass-embedded: '*'
webpack: ^5.0.0
peerDependenciesMeta:
'@rspack/core':
optional: true
node-sass:
optional: true
sass:
optional: true
sass-embedded:
optional: true
webpack:
optional: true
sass@1.90.0:
resolution: {integrity: sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==}
engines: {node: '>=14.0.0'}
hasBin: true
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
snapshots:
'@parcel/watcher-android-arm64@2.5.1':
optional: true
'@parcel/watcher-darwin-arm64@2.5.1':
optional: true
'@parcel/watcher-darwin-x64@2.5.1':
optional: true
'@parcel/watcher-freebsd-x64@2.5.1':
optional: true
'@parcel/watcher-linux-arm-glibc@2.5.1':
optional: true
'@parcel/watcher-linux-arm-musl@2.5.1':
optional: true
'@parcel/watcher-linux-arm64-glibc@2.5.1':
optional: true
'@parcel/watcher-linux-arm64-musl@2.5.1':
optional: true
'@parcel/watcher-linux-x64-glibc@2.5.1':
optional: true
'@parcel/watcher-linux-x64-musl@2.5.1':
optional: true
'@parcel/watcher-win32-arm64@2.5.1':
optional: true
'@parcel/watcher-win32-ia32@2.5.1':
optional: true
'@parcel/watcher-win32-x64@2.5.1':
optional: true
'@parcel/watcher@2.5.1':
dependencies:
detect-libc: 1.0.3
is-glob: 4.0.3
micromatch: 4.0.8
node-addon-api: 7.1.1
optionalDependencies:
'@parcel/watcher-android-arm64': 2.5.1
'@parcel/watcher-darwin-arm64': 2.5.1
'@parcel/watcher-darwin-x64': 2.5.1
'@parcel/watcher-freebsd-x64': 2.5.1
'@parcel/watcher-linux-arm-glibc': 2.5.1
'@parcel/watcher-linux-arm-musl': 2.5.1
'@parcel/watcher-linux-arm64-glibc': 2.5.1
'@parcel/watcher-linux-arm64-musl': 2.5.1
'@parcel/watcher-linux-x64-glibc': 2.5.1
'@parcel/watcher-linux-x64-musl': 2.5.1
'@parcel/watcher-win32-arm64': 2.5.1
'@parcel/watcher-win32-ia32': 2.5.1
'@parcel/watcher-win32-x64': 2.5.1
optional: true
braces@3.0.3:
dependencies:
fill-range: 7.1.1
optional: true
chokidar@4.0.3:
dependencies:
readdirp: 4.1.2
dayjs@1.11.13: {}
detect-libc@1.0.3:
optional: true
fill-range@7.1.1:
dependencies:
to-regex-range: 5.0.1
optional: true
immutable@5.1.3: {}
is-extglob@2.1.1:
optional: true
is-glob@4.0.3:
dependencies:
is-extglob: 2.1.1
optional: true
is-number@7.0.0:
optional: true
micromatch@4.0.8:
dependencies:
braces: 3.0.3
picomatch: 2.3.1
optional: true
neo-async@2.6.2: {}
node-addon-api@7.1.1:
optional: true
picomatch@2.3.1:
optional: true
readdirp@4.1.2: {}
sass-loader@16.0.5(sass@1.90.0):
dependencies:
neo-async: 2.6.2
optionalDependencies:
sass: 1.90.0
sass@1.90.0:
dependencies:
chokidar: 4.0.3
immutable: 5.1.3
source-map-js: 1.2.1
optionalDependencies:
'@parcel/watcher': 2.5.1
source-map-js@1.2.1: {}
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
optional: true

BIN
static/empty-bill.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
static/empty-property.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
static/home-active.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
static/home.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
static/service-active.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
static/service.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
static/store-active.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
static/store.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

4
static/style/common.scss

@ -3,7 +3,7 @@ $yellow: #e2d602;
$orange: #fd7600;
$orange-deep: #FF4B00;
$orange-light: #FFC5AD;
$green: #2ACF8D;
$green: #98C147;
$green-light: #a1ded0;
$blue: #2665c4;
$blue-light: #049DFF;
@ -18,7 +18,7 @@ $gray-light: #F7F7F7;
$gold: #B68320;
$gold-light: #FFF0D3;
$fdca00: #FDCA00;
$u-primary: $blue;
$u-primary: $green;
//p, span {
// font-size: 30rpx;

BIN
static/user-active.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
static/user.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
static/一键开门.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
static/个人投诉登记.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
static/交警.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
static/交通出行.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
static/亲子活动.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
static/保险.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
static/发布.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

BIN
static/工具.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
static/工单.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
static/快递.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
static/报修管理备份2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
static/收藏.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
static/服务.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
static/物业费.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
static/租赁资产.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
static/跑步.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
static/银行卡-01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
static/门店管理.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
static/餐饮.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

13
userPages/pages/cars.vue

@ -0,0 +1,13 @@
<template>
</template>
<script>
export default {
name: "cars",
data() {
return {}
},
methods: {}
}
</script>

13
userPages/pages/guest.vue

@ -0,0 +1,13 @@
<template>
</template>
<script>
export default {
name: "cars",
data() {
return {}
},
methods: {}
}
</script>

238
userPages/pages/peopleList.vue

@ -0,0 +1,238 @@
<template>
<view class="people-list-container">
<!-- 顶部导航栏 -->
<view class="nav-bar">
<view class="nav-back" @click="goBack">
<text class="nav-back-icon"></text>
</view>
<text class="nav-title">住户详情</text>
</view>
<!-- 温馨提示 -->
<view class="tip-container">
<text class="tip-text">温馨提示您在恒大物业服务中心或恒大智慧社区APP登记了以下住户信息</text>
</view>
<!-- 地址信息 -->
<view class="address-container">
<text class="address-text">南宁恒大华府一期01栋1单元4层0405</text>
</view>
<!-- 住户信息卡片 -->
<view class="resident-card">
<!-- 姓名和业主标识 -->
<view class="resident-header">
<text class="resident-name">翟灵</text>
<view class="owner-tag">
<text class="owner-text">业主</text>
</view>
</view>
<!-- 联系信息 -->
<view class="contact-info">
<view class="info-row">
<text class="info-label">联系电话</text>
<text class="info-value">195****4431</text>
</view>
<view class="info-row">
<text class="info-label">身份证号</text>
<text class="info-value">450**********2130</text>
</view>
<view class="info-row">
<text class="info-label">认证时间</text>
<text class="info-value">2020-02-14 19:28</text>
</view>
</view>
<!-- 提示信息 -->
<view class="notice-container">
<text class="notice-text">如果您是业主身份可向左滑动家人/历史业主的卡片并删除解除房屋绑定关系</text>
<text class="notice-text">如果您是租客身份可向左滑动租客家人的卡片并删除解除房屋绑定关系</text>
</view>
</view>
<!-- 添加家人按钮 -->
<view class="add-family-btn" @click="addFamily">
<text class="add-family-text">添加家人</text>
</view>
</view>
</template>
<script>
export default {
name: "peopleList",
data() {
return {
peopleList: [],
}
},
methods: {
goBack() {
uni.navigateBack()
},
addFamily() {
}
}
}
</script>
<style lang="scss" scoped>
.people-list-container {
min-height: 100vh;
background-color: #f5f5f5;
}
.nav-bar {
display: flex;
align-items: center;
justify-content: center;
position: relative;
height: 88rpx;
background-color: #fff;
border-bottom: 1rpx solid #eee;
}
.nav-back {
position: absolute;
left: 30rpx;
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
.nav-back-icon {
font-size: 40rpx;
color: #333;
font-weight: bold;
}
.nav-title {
font-size: 36rpx;
color: #333;
font-weight: 500;
}
.tip-container {
margin: 30rpx;
padding: 30rpx;
background-color: #fff3cd;
border-radius: 12rpx;
border-left: 6rpx solid #ffc107;
}
.tip-text {
font-size: 28rpx;
color: #856404;
line-height: 1.5;
}
.address-container {
margin: 0 30rpx 30rpx;
padding: 30rpx;
background-color: #fff;
border-radius: 12rpx;
}
.address-text {
font-size: 32rpx;
color: #333;
font-weight: 500;
}
.resident-card {
margin: 0 30rpx;
padding: 40rpx 30rpx;
background-color: #fff;
border-radius: 12rpx;
}
.resident-header {
display: flex;
align-items: center;
margin-bottom: 40rpx;
}
.resident-name {
font-size: 36rpx;
color: #333;
font-weight: 600;
margin-right: 20rpx;
}
.owner-tag {
padding: 8rpx 16rpx;
background-color: #ffc107;
border-radius: 20rpx;
}
.owner-text {
font-size: 24rpx;
color: #333;
}
.contact-info {
margin-bottom: 40rpx;
}
.info-row {
display: flex;
align-items: center;
margin-bottom: 24rpx;
}
.info-row:last-child {
margin-bottom: 0;
}
.info-label {
font-size: 30rpx;
color: #666;
width: 180rpx;
}
.info-value {
font-size: 30rpx;
color: #333;
flex: 1;
}
.notice-container {
padding-top: 30rpx;
border-top: 1rpx solid #eee;
}
.notice-text {
display: block;
font-size: 26rpx;
color: #999;
line-height: 1.6;
margin-bottom: 16rpx;
}
.notice-text:last-child {
margin-bottom: 0;
}
.add-family-btn {
position: fixed;
bottom: 60rpx;
left: 30rpx;
right: 30rpx;
height: 96rpx;
background: linear-gradient(135deg, #ffc107 0%, #ff9800 100%);
border-radius: 48rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 24rpx rgba(255, 193, 7, 0.3);
}
.add-family-text {
font-size: 32rpx;
color: #333;
font-weight: 600;
}
</style>
Loading…
Cancel
Save