643 lines
16 KiB
Vue
643 lines
16 KiB
Vue
<template>
|
||
<view class="container">
|
||
<view class="header">
|
||
<view class="search-box">
|
||
<view class="input-button-container">
|
||
<view class="search-input-wrapper">
|
||
<u-input v-model="searchKeyword" placeholder="搜索户主姓名或身份证号" prefix-icon="search"
|
||
@confirm="handleSearch" :disabled="isSerach" clearable />
|
||
</view>
|
||
<view class="scan-button" @click="handleScan">
|
||
<uni-icons type="scan" size="28" color="#28A0F8"></uni-icons>
|
||
</view>
|
||
<view class="search-button-wrapper">
|
||
<u-button @click="handleSearch" :disabled="isSerach" type="error" size="medium">
|
||
<u-icon name="search" size="24" />
|
||
搜索
|
||
</u-button>
|
||
</view>
|
||
</view>
|
||
<view class="area-select-row">
|
||
<!-- 镇/街 -->
|
||
<view class="select-item">
|
||
<uni-easyinput prefixIcon="search" v-model="selectedTown" placeholder="请选择镇/街"
|
||
@clear="clearTown" @iconClick="showTown" clearable />
|
||
</view>
|
||
<!-- 村/社区 -->
|
||
<view class="select-item">
|
||
<uni-easyinput prefixIcon="search" v-model="selectedVillage" @clear="clearVillage"
|
||
placeholder="请选择村/社区" clearable @iconClick="showVillage()" />
|
||
</view>
|
||
<!-- 组/网格 -->
|
||
<view class="select-item">
|
||
<uni-easyinput prefixIcon="search" v-model="selectedGroup" placeholder="请选择组/网格" clearable
|
||
@iconClick="showGroup()" />
|
||
</view>
|
||
|
||
<!-- 镇选择器 -->
|
||
<u-picker :show="showTownPicker" mode="region" :columns="[townList]" keyName="label"
|
||
@confirm="onTownConfirm" @close="showTownPicker = false" />
|
||
<!-- 村选择器 -->
|
||
<u-picker :show="showVillagePicker" mode="region" :columns="[villageList]" keyName="label"
|
||
@confirm="onVillageConfirm" @close="showVillagePicker = false" />
|
||
<!-- 组选择器 -->
|
||
<u-picker :show="showGroupPicker" mode="region" :columns="[groupList]" keyName="label"
|
||
@confirm="onGroupConfirm" @close="showGroupPicker = false" />
|
||
</view>
|
||
<view class="area-select-row">
|
||
<view class="select-item1">
|
||
<uni-easyinput prefixIcon="search" v-model="selectDoorNum"
|
||
placeholder="请输入门牌号,若要未填写门牌号数据,请输入无" clearable />
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="content">
|
||
<view class="filter-tabs">
|
||
<view class="tab-item" :class="{ active: currentStatus === '' }" @click="filterByStatus('')">
|
||
{{getTitel('')}}
|
||
</view>
|
||
<view class="tab-item" :class="{ active: currentStatus === '1' }" @click="filterByStatus('1')">
|
||
{{getTitel('1')}}
|
||
|
||
</view>
|
||
<view class="tab-item" :class="{ active: currentStatus === '0' }" @click="filterByStatus('0')">
|
||
{{getTitel('0')}}
|
||
|
||
</view>
|
||
|
||
</view>
|
||
<view class="list-container">
|
||
|
||
<mescroll-body ref="mescrollRef" :up="upOption" @init="mescrollInit" @up="upCallback" :down="downOption"
|
||
@down="downCallback" :height="mescrollHeight">
|
||
<view v-if="loading && householdList.length === 0" class="loading">
|
||
<u-loading-icon mode="spinner" size="40"></u-loading-icon>
|
||
<text>加载中...</text>
|
||
</view>
|
||
<view v-else-if="householdList.length === 0" class="empty">
|
||
<u-icon name="info-circle" size="80" color="#ccc"></u-icon>
|
||
<text>暂无数据</text>
|
||
</view>
|
||
<view v-else class="household-list">
|
||
|
||
<view class="household-item" v-for="item in householdList" :key="item.id"
|
||
@click="viewDetail(item)">
|
||
<view class="item-header">
|
||
<text class="householder-name">{{ getMsg(item.householderName) }}</text>
|
||
<view class="status-tag" :class="item.submitStatus === 1 ? 'submitted' : 'draft'">
|
||
{{ item.submitStatus === 1 ? '已提交' : '暂存' }}
|
||
</view>
|
||
</view>
|
||
<view class="item-info">
|
||
<text class="info-text">{{ '身份证号:'+getMsg(item.householderIdNumber) }}</text>
|
||
<text class="info-text">{{ '联系电话:'+getMsg(item.householderPhone) }}</text>
|
||
<text class="info-text">{{'户籍人数:'+getMsg(item.householdNum) }}人</text>
|
||
<text class="info-text">{{'地址:'}}{{ getMsg(item.town) }}{{ getMsg(item.village) }}{{getMsg(item.groupName)}}{{ getMsg(item.doorNumber) }}</text>
|
||
<text class="info-text">{{ '入户员:'+ getMsg(item.submitterName) }}</text>
|
||
</view>
|
||
<view class="item-footer">
|
||
<text class="time-text">{{ '入户时间:'+formatTime(item.updateTime) }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</mescroll-body>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import MescrollBody from 'mescroll-uni/mescroll-body.vue'
|
||
import MescrollMixin from 'mescroll-uni/mescroll-mixins.js'
|
||
import {
|
||
householdApi,areaApi
|
||
} from '../../utils/api.js'
|
||
import CryptoJS from "crypto-js";
|
||
let Qrcode = require('../../utils/reqrcode.js') //引用二维码(源码)
|
||
export default {
|
||
components: {
|
||
MescrollBody
|
||
},
|
||
mixins: [MescrollMixin],
|
||
data() {
|
||
return {
|
||
qrCodeRes: '',
|
||
searchKeyword: '',
|
||
total: '',
|
||
isSerach: false,
|
||
type: 'select',
|
||
secretKey: "m+=sad_sgAlo+1sag",
|
||
currentStatus: '',
|
||
householdList: [],
|
||
// 选择器弹窗控制
|
||
showTownPicker: false,
|
||
showVillagePicker: false,
|
||
showGroupPicker: false,
|
||
// 选中的值
|
||
selectedTown: '',
|
||
selectedVillage: '',
|
||
selectedGroup: '',
|
||
selectDoorNum: '',
|
||
// 下拉数据
|
||
townList: [],
|
||
villageList: [],
|
||
groupList: [],
|
||
// 三级原始数据
|
||
townVillageGroup: [],
|
||
loading: false,
|
||
upOption: {
|
||
use: true,
|
||
auto: true,
|
||
page: {
|
||
size: 5
|
||
},
|
||
noMoreSize: 5,
|
||
empty: {
|
||
tip: '暂无数据'
|
||
}
|
||
},
|
||
downOption: {
|
||
use: true
|
||
},
|
||
mescrollHeight: 'auto',
|
||
userInfo: {},
|
||
query: {}
|
||
}
|
||
},
|
||
async onLoad() {
|
||
this.loadUserInfo()
|
||
await this.listAreaNode();
|
||
|
||
},
|
||
methods: {
|
||
getMsg(value){
|
||
if(value){
|
||
return value
|
||
}else{
|
||
return ''
|
||
}
|
||
},
|
||
async listAreaNode() {
|
||
var areaDate = await areaApi.getAreaList();
|
||
this.townVillageGroup = this.transformTree(areaDate);
|
||
this.townList = this.townVillageGroup
|
||
},
|
||
transformTree(nodes) {
|
||
return nodes.map(node => {
|
||
// 创建基础对象(只包含label和value)
|
||
const newNode = {
|
||
"label": node.name,
|
||
"value": node.name
|
||
};
|
||
|
||
// 如果存在非空children则递归处理
|
||
if (node.children && node.children.length > 0) {
|
||
newNode.children = this.transformTree(node.children);
|
||
}
|
||
|
||
return newNode;
|
||
});
|
||
},
|
||
handleScan() {
|
||
// #ifdef APP-PLUS || MP-WEIXIN
|
||
uni.scanCode({
|
||
success: (res) => {
|
||
var msg = res.result
|
||
const bytes = CryptoJS.AES.decrypt(msg, this.secretKey);
|
||
this.searchKeyword = bytes.toString(CryptoJS.enc.Utf8);
|
||
this.mescroll.resetUpScroll()
|
||
},
|
||
fail: () => {
|
||
uni.showToast({
|
||
title: '扫码失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
})
|
||
// #endif
|
||
// #ifdef H5
|
||
this.scanCodeH5()
|
||
// #endif
|
||
},
|
||
//h5识别条码和二维码
|
||
scanCodeH5() {
|
||
uni.chooseImage({
|
||
count: 1,
|
||
success: imgRes => {
|
||
Qrcode.qrcode.decode(this.getObjectURL(imgRes.tempFiles[0]))
|
||
Qrcode.qrcode.callback = (codeRes) => {
|
||
if (codeRes.indexOf('error') >= 0) {
|
||
// 二维码识别失败
|
||
uni.showToast({
|
||
title: '扫码失败',
|
||
icon: 'none'
|
||
})
|
||
} else {
|
||
const bytes = CryptoJS.AES.decrypt(codeRes, this.secretKey);
|
||
this.searchKeyword = bytes.toString(CryptoJS.enc.Utf8);
|
||
this.mescroll.resetUpScroll()
|
||
}
|
||
}
|
||
}
|
||
})
|
||
},
|
||
getTitel(current) {
|
||
if (current === '') {
|
||
if (this.currentStatus != '' || this.total == '' || this.total == 0) {
|
||
return '全部'
|
||
} else {
|
||
return '全部(' + this.total + ')'
|
||
}
|
||
} else if (current === '1') {
|
||
if (this.currentStatus != '1' || this.total == '' || this.total == 0) {
|
||
return '已提交'
|
||
} else {
|
||
return '已提交(' + this.total + ')'
|
||
}
|
||
} else if (current === '0') {
|
||
if (this.currentStatus != '0' || this.total == '' || this.total == 0) {
|
||
return '暂存'
|
||
} else {
|
||
return '暂存(' + this.total + ')'
|
||
}
|
||
}
|
||
|
||
|
||
},
|
||
// 获取文件地址函数
|
||
getObjectURL(file) {
|
||
var url = null
|
||
if (window.createObjectURL !== undefined) { // basic
|
||
url = window.createObjectURL(file)
|
||
} else if (window.URL !== undefined) { // mozilla(firefox)
|
||
url = window.URL.createObjectURL(file)
|
||
} else if (window.webkitURL !== undefined) { // webkit or chrome
|
||
url = window.webkitURL.createObjectURL(file)
|
||
}
|
||
return url
|
||
},
|
||
// 解码,输出:中文
|
||
decodeStr(str) {
|
||
var out, i, len, c;
|
||
var char2, char3;
|
||
out = "";
|
||
len = str.length;
|
||
i = 0;
|
||
while (i < len) {
|
||
c = str.charCodeAt(i++);
|
||
switch (c >> 4) {
|
||
case 0:
|
||
case 1:
|
||
case 2:
|
||
case 3:
|
||
case 4:
|
||
case 5:
|
||
case 6:
|
||
case 7:
|
||
// 0xxxxxxx
|
||
out += str.charAt(i - 1);
|
||
break;
|
||
case 12:
|
||
case 13:
|
||
// 110x xxxx 10xx xxxx
|
||
char2 = str.charCodeAt(i++);
|
||
out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
|
||
break;
|
||
case 14:
|
||
// 1110 xxxx 10xx xxxx 10xx xxxx
|
||
char2 = str.charCodeAt(i++);
|
||
char3 = str.charCodeAt(i++);
|
||
out += String.fromCharCode(((c & 0x0F) << 12) |
|
||
((char2 & 0x3F) << 6) |
|
||
((char3 & 0x3F) << 0));
|
||
break;
|
||
}
|
||
}
|
||
return out;
|
||
},
|
||
mescrollInit(mescroll) {
|
||
this.mescroll = mescroll
|
||
},
|
||
loadUserInfo() {
|
||
const userInfo = uni.getStorageSync('userInfo')
|
||
if (userInfo) {
|
||
this.userInfo = userInfo
|
||
} else {
|
||
uni.reLaunch({
|
||
url: '/packageUser/pages/login'
|
||
})
|
||
}
|
||
},
|
||
handleSearch() {
|
||
this.mescroll.resetUpScroll()
|
||
},
|
||
filterByStatus(status) {
|
||
this.currentStatus = status
|
||
this.mescroll.resetUpScroll()
|
||
},
|
||
clearTown() {
|
||
this.selectedGroup = '';
|
||
this.selectedVillage = '';
|
||
},
|
||
clearVillage() {
|
||
this.selectedGroup = '';
|
||
},
|
||
// 镇选择
|
||
onTownConfirm(e) {
|
||
const town = e.value[0]
|
||
this.selectedTown = town.label
|
||
// 找到对应村
|
||
this.villageList = town.children || []
|
||
this.selectedVillage = ''
|
||
this.groupList = []
|
||
this.selectedGroup = ''
|
||
this.showTownPicker = false
|
||
},
|
||
showTown() {
|
||
console.log('s')
|
||
this.showTownPicker = true
|
||
},
|
||
showVillage() {
|
||
if (this.selectedTown) {
|
||
this.showVillagePicker = true
|
||
} else {
|
||
uni.showToast({
|
||
title: "请先选择村镇/街",
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
showGroup() {
|
||
if (this.selectedVillage) {
|
||
this.showGroupPicker = true;
|
||
} else {
|
||
uni.showToast({
|
||
title: "请先选择村/社区",
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
// 村选择
|
||
onVillageConfirm(e) {
|
||
const village = e.value[0]
|
||
this.selectedVillage = village.label
|
||
// 找到对应组
|
||
this.groupList = village.children || []
|
||
this.selectedGroup = ''
|
||
this.showVillagePicker = false
|
||
},
|
||
// 组选
|
||
onGroupConfirm(e) {
|
||
const group = e.value[0]
|
||
this.selectedGroup = group.label
|
||
this.showGroupPicker = false
|
||
},
|
||
downCallback() {
|
||
this.mescroll.resetUpScroll()
|
||
},
|
||
async upCallback(page) {
|
||
this.total = 0
|
||
// this.loading = page.num === 1
|
||
try {
|
||
uni.showLoading();
|
||
this.isSerach = true;
|
||
// console.log(this.loading)
|
||
// const token = uni.getStorageSync('token')
|
||
const params = {
|
||
pageNo: page.num,
|
||
pageSize: page.size,
|
||
}
|
||
if (this.searchKeyword) {
|
||
params.keyword = this.searchKeyword
|
||
}
|
||
if (this.currentStatus !== '') {
|
||
params.submitStatus = this.currentStatus
|
||
}
|
||
if (this.selectedTown != '') {
|
||
params.town = this.selectedTown;
|
||
|
||
}
|
||
if (this.selectedVillage != '') {
|
||
params.village = this.selectedVillage;
|
||
|
||
}
|
||
if (this.selectedGroup != '') {
|
||
params.groupName = this.selectedGroup;
|
||
}
|
||
if (this.selectDoorNum != '') {
|
||
params.doorNumber = this.selectDoorNum;
|
||
}
|
||
const response = await householdApi.pageHouseHoldPage(params)
|
||
if (response.total && response.total > 0) {
|
||
const newList = response.list;
|
||
this.total = response.total
|
||
if (page.num === 1) {
|
||
this.householdList = newList
|
||
|
||
} else {
|
||
this.householdList = [...this.householdList, ...newList]
|
||
}
|
||
this.mescroll.endBySize(newList.length, response.total || 0)
|
||
uni.hideLoading();
|
||
this.isSerach = false;
|
||
} else {
|
||
this.mescroll.endErr()
|
||
uni.hideLoading();
|
||
this.isSerach = false;
|
||
}
|
||
} catch (error) {
|
||
uni.hideLoading();
|
||
this.isSerach = false;
|
||
this.mescroll.endErr()
|
||
uni.showToast({
|
||
title: '加载失败',
|
||
icon: 'none'
|
||
})
|
||
} finally {
|
||
uni.hideLoading();
|
||
this.isSerach = false;
|
||
}
|
||
|
||
},
|
||
viewDetail(item) {
|
||
uni.navigateTo({
|
||
url: `/packageForm/pages/householdForm?id=${item.id}`
|
||
})
|
||
},
|
||
formatTime(timeStr) {
|
||
if (!timeStr) return ''
|
||
const date = new Date(timeStr)
|
||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.container {
|
||
min-height: 100vh;
|
||
background: #f4f6fa;
|
||
}
|
||
|
||
.header {
|
||
background: #fff;
|
||
padding: 20rpx;
|
||
border-bottom: 1rpx solid #eee;
|
||
}
|
||
|
||
.search-box {
|
||
/* 搜索框样式 */
|
||
}
|
||
|
||
.input-button-container {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.search-input-wrapper {
|
||
flex: 3;
|
||
}
|
||
|
||
.scan-button {
|
||
background: none;
|
||
border: none;
|
||
padding: 0 10rpx;
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 8rpx;
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.search-button-wrapper {
|
||
flex: 1;
|
||
}
|
||
|
||
.content {
|
||
padding: 15rpx;
|
||
}
|
||
|
||
.filter-tabs {
|
||
display: flex;
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
margin-bottom: 15rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.tab-item {
|
||
flex: 1;
|
||
text-align: center;
|
||
padding: 24rpx 0;
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
transition: all 0.3s;
|
||
border-left: 1rpx solid #F5F3F2;
|
||
/* 灰色边框 */
|
||
/* 添加上边框 */
|
||
border-top: 1rpx solid #F5F3F2;
|
||
/* 添加下边框 */
|
||
border-bottom: 1rpx solid #F5F3F2;
|
||
border-right: 1rpx solid #F5F3F2;
|
||
}
|
||
|
||
.tab-item.active {
|
||
background: #2979ff;
|
||
color: #fff;
|
||
}
|
||
|
||
.list-container {
|
||
min-height: 400rpx;
|
||
}
|
||
|
||
.loading,
|
||
.empty {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 80rpx 0;
|
||
color: #999;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.household-list {
|
||
margin-bottom: 32rpx;
|
||
}
|
||
|
||
.household-item {
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
padding: 32rpx;
|
||
margin-bottom: 24rpx;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.item-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.householder-name {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.status-tag {
|
||
padding: 8rpx 16rpx;
|
||
border-radius: 12rpx;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.status-tag.submitted {
|
||
background: #e8f5e8;
|
||
color: #19be6b;
|
||
}
|
||
|
||
.status-tag.draft {
|
||
background: #fff3e0;
|
||
color: #ff9500;
|
||
}
|
||
|
||
.item-info {
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.info-text {
|
||
display: block;
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.item-footer {
|
||
border-top: 1rpx solid #eee;
|
||
padding-top: 16rpx;
|
||
}
|
||
|
||
.time-text {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.area-select-row {
|
||
display: flex;
|
||
margin-top: 20rpx;
|
||
flex-direction: row;
|
||
}
|
||
.select-item1 {
|
||
flex: 1;
|
||
}
|
||
|
||
.select-item {
|
||
width: 32%;
|
||
margin-right: 2%;
|
||
}
|
||
</style> |