This commit is contained in:
花有清香月有阴
2022-02-15 11:54:40 +08:00
25 changed files with 5971 additions and 6 deletions

View File

@@ -71,7 +71,7 @@ import {mapState} from 'vuex'
export default { export default {
name: "AppActivityList", name: "AppActivityList",
appName: "居民活动", appName: "活动列表",
computed: { computed: {
...mapState(['user', 'token']) ...mapState(['user', 'token'])
}, },
@@ -102,7 +102,7 @@ export default {
} }
}, },
onShow() { onShow() {
this.$dict.load('partyReportActionStatus', 'partyReportSignupStatus').then((res) => { this.$dict.load('partyReportActionStatus', 'partyReportSignupStatus').then(() => {
this.activeStatusList = this.getSelectList('partyReportActionStatus') this.activeStatusList = this.getSelectList('partyReportActionStatus')
this.checkStatusList = this.getSelectList('partyReportSignupStatus') this.checkStatusList = this.getSelectList('partyReportSignupStatus')
this.getListInit() this.getListInit()

View File

@@ -5,7 +5,7 @@
v-if="propAreaId == '341021104000'">{{ areaName }}信用好超市管理制度点击查看 >> v-if="propAreaId == '341021104000'">{{ areaName }}信用好超市管理制度点击查看 >>
</div> </div>
<div class="goods-list" v-if="numList.length" <div class="goods-list" v-if="numList.length"
:style="propAreaId == '341021104000' ? 'padding-top:80px' : 'padding-top: 0;'"> :style="propAreaId == '341021104000' ? 'padding-top:80rpx' : 'padding-top: 0;'">
<div class="left"> <div class="left">
<div <div
:class="numIndex == index ? 'item active' : 'item'" :class="numIndex == index ? 'item active' : 'item'"
@@ -290,7 +290,9 @@ export default {
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
flex: 1; flex: 1;
padding: 032px h3 { padding: 0 32px;
h3 {
color: #F94246; color: #F94246;
font-size: 32px; font-size: 32px;
} }
@@ -427,7 +429,6 @@ export default {
} }
.item-point { .item-point {
color: #FA4A51;;
font-size: 24px; font-size: 24px;
font-family: PingFangSC-Medium, PingFang SC; font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500; font-weight: 500;

View File

@@ -0,0 +1,382 @@
<template>
<div class="photo" v-if="pageShow">
<div class="header" :class="[isFixed ? 'header-active' : '']">
<div class="status-bar" :style="{height: statusBarHeight + 'px'}"></div>
<div class="nav-bar">
<image src="/static/img/left.png" @click="back" />
<h2>乡村相册</h2>
</div>
</div>
<div class="back-wrapper" @click="back" v-show="!isFixed" :style="{marginTop : statusBarHeight + 'px'}">
<image src="/static/img/left.png" />
</div>
<div class="photo-header">
<image :src="coverImg" mode="aspectFill" />
<h2>{{ name }}</h2>
</div>
<div class="photo-info">
<div class="photo-info__item">
<h2>{{ info.total }}</h2>
<span>照片</span>
</div>
<div class="photo-info__item">
<h2>{{ info.thisMonth }}</h2>
<span>本月</span>
</div>
<div class="photo-info__item">
<h2>{{ info.lastMonth }}</h2>
<span>上月</span>
</div>
<div class="photo-info__item">
<h2>{{ info.thisYear }}</h2>
<span>今年</span>
</div>
</div>
<div class="photo-list">
<div class="photo-group" v-for="(group, index) in list" :key="index">
<h2>{{ group.name }}</h2>
<div class="photo-wrapper">
<div class="photo-item" v-for="(item, i) in group.list" :key="i">
<image :src="item.url" @click="preview(item.url)" mode="aspectFill" />
<div class="photo-item__text">
<span>{{ item.createUserName }} 上传</span>
</div>
</div>
</div>
</div>
<AiEmpty v-if="!list.length" description="暂无照片"></AiEmpty>
</div>
<div class="btn-wrapper">
<div class="btn" @click="upload" hover-class="text-hover">上传图片</div>
</div>
<ai-login ref="login"></ai-login>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name:"AppPhotoAlbum",
appName:"乡村相册",
data () {
return {
isFixed: false,
statusBarHeight: 20,
list: [],
type: '',
info: {},
name: '',
coverImg: '',
imgList: [],
hideStatus: false,
pageShow: false
}
},
computed: {
...mapState(['user', 'token'])
},
onLoad (query) {
this.type = query.type
this.name = query.name
this.coverImg = query.url
this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight
this.$loading()
this.getList(query.type)
this.getTotalInfo(query.type)
},
onUnload () {
// uni.$off('update')
},
methods: {
back () {
uni.navigateBack({
delta: 1
})
},
preview (url) {
let imgs = []
this.list.forEach(item => {
imgs = [...imgs, ...item.list.map(v => v.url)]
})
uni.previewImage({
urls: imgs,
current: url
})
},
upload() {
if (!this.token) {
this.$refs.login.show()
return false
}
this.imgList = []
this.hideStatus = false
uni.chooseImage({
count: this.limit,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
if (res.tempFilePaths.length > 9) {
this.$toast(`图片不能超过9张`)
return false
}
this.$loading('上传中')
res.tempFilePaths.forEach((item, index) => {
if (index === res.tempFilePaths.length - 1) {
this.hideStatus = true
}
this.$nextTick(() => {
this.uploadFile(item, res.tempFilePaths.length)
})
})
},
})
},
uploadFile (img, total) {
uni.uploadFile({
url: this.$http.baseURL + '/admin/file/add',
filePath: img,
name: 'file',
header: {
'Content-Type': 'multipart/form-data',
Authorization: uni.getStorageSync('token'),
},
success: (res) => {
const data = JSON.parse(res.data)
if (data.code === 0) {
this.imgList.push(data.data[0].split(';')[0])
} else {
this.$toast(data.msg)
}
},
complete: () => {
this.$nextTick(() => {
if (this.imgList.length === total && this.hideStatus) {
this.$instance.post(`/app/appvillagepicturealbum/addPictures`, {
areaName: uni.getStorageSync('areaName'),
areaId: uni.getStorageSync('areaId'),
type: this.type,
urlList: this.imgList
}).then(res => {
if (res.code == 0) {
this.getList(this.type)
this.getTotalInfo(this.type)
uni.$emit('update')
}
this.$hideLoading()
this.hideStatus = false
})
}
})
}
})
},
getTotalInfo (type) {
this.$instance.post(`/app/appvillagepicturealbum/statistic?areaId=${uni.getStorageSync('areaId')}&type=${type}`).then(res => {
if (res.code === 0) {
this.info = res.data
}
})
},
getList (type) {
this.$instance.post(`/app/appvillagepicturealbum/queryAlbum?areaId=${uni.getStorageSync('areaId')}&type=${type}`).then(res => {
if (res.code === 0) {
this.list = Object.keys(res.data).map(v => {
return {
name: v,
list: res.data[v]
}
})
this.$nextTick(() => {
this.pageShow = true
})
}
this.$hideLoading()
})
}
},
onPageScroll(params) {
this.isFixed = params.scrollTop > 60;
}
}
</script>
<style lang="scss" socped>
.photo {
padding-bottom: 130px;
* {
box-sizing: border-box;
}
.back-wrapper {
position: fixed;
z-index: 11;
left: 20px;
top: 24px;
width: 40px;
height: 40px;
image {
width: 40px;
height: 40px;
}
}
.header {
position: fixed;
left: 0;
top: 0;
z-index: 0;
width: 100%;
opacity: 0;
transition: all 0.2s ease;
&.header-active {
z-index: 1111;
opacity: 1;
background: linear-gradient(180deg, #4670F5 0%, #4772F5 100%);
}
.nav-bar {
position: relative;
height: 88px;
line-height: 88px;
color: #fff;
font-size: 32px;
text-align: center;
image {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 40px;
height: 40px;
padding: 24px 20px 0 20px;
box-sizing: content-box;
}
}
}
.photo-header {
position: relative;
height: 400px;
image {
width: 100%;
height: 400px;
filter: blur(2px);
}
h2 {
display: flex;
position: absolute;
align-items: center;
justify-content: center;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
color: #fff;
background: rgba(0,0,0, 0.1);
font-size: 56px;
}
}
.photo-info {
display: flex;
align-items: center;
height: 168px;
background: #FFFFFF;
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.02);
& > div {
flex: 1;
text-align: center;
h2 {
margin-bottom: 10px;
font-weight: 600;
font-size: 38px;
color: #333333;
}
span {
color: #999999;
font-size: 26px;
}
}
}
.photo-list {
margin-top: 32px;
padding: 0 32px;
h2 {
margin-bottom: 32px;
color: #333333;
font-size: 38px;
}
.photo-wrapper {
display: flex;
flex-wrap: wrap;
.photo-item {
position: relative;
width: 328px;
height: 328px;
margin-right: 30px;
margin-bottom: 32px;
border-radius: 12px;
overflow: hidden;
&:nth-of-type(2n) {
margin-right: 0;
}
.photo-item__text {
position: absolute;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
height: 80px;
line-height: 80px;
padding: 0 16px;
color: #FFFFFF;
font-size: 26px;
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.5) 100%);
}
image {
width: 328px;
height: 328px;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,469 @@
<template>
<div class="detail" v-if="pageShow" :style="{paddingBottom: info.status === '0' ? '130px' : '40px'}">
<div class="detail-wrapper">
<image class="banner" mode="aspectFill" :src="info.url" />
<h2>{{ info.title }}</h2>
<div class="detail-status">
<span :class="'status' + info.status">{{ $dict.getLabel('villageActivityStatus', info.status) }}</span>
<div class="detail-status__right">
<span>已有</span>
<i>{{ info.realNum }}</i>
<span>人报名</span>
</div>
</div>
<div class="detail-info">
<div class="detail-info__item">
<label>联系人</label>
<div class="right">
<span>{{ info.contactPerson }}</span>
</div>
</div>
<div class="detail-info__item">
<label>联系方式</label>
<div class="right detail-info__item--phone" hover-class="text-hover" @click="call(info.contactPhone)">
<span>{{ info.contactPhone }}</span>
</div>
</div>
<div class="detail-info__item">
<label>开始时间</label>
<div class="right">
<span>{{ info.beginTime }}</span>
</div>
</div>
<div class="detail-info__item">
<label>结束时间</label>
<div class="right">
<span>{{ info.endTime }}</span>
</div>
</div>
<div class="detail-info__item">
<label>活动地点</label>
<div class="right">
<span>{{ info.areaName }}{{ info.address }}</span>
</div>
</div>
</div>
<div class="detail-tips">
<u-tabs
:list="tabs"
font-size="32"
bg-color="transparent"
inactive-color="#999999"
:active-item-style="tabActive"
:is-scroll="true"
:current="currIndex"
@change="i => currIndex = i">
</u-tabs>
<div class="tab-content">
<div class="rich-content" v-show="currIndex === 0">
<u-parse :html="info.content"></u-parse>
</div>
<div class="dynamic-list" v-show="currIndex === 1">
<div class="dynamic-item" v-for="(item, index) in list" :key="index">
<div class="dynamic-item__top">
<h2>{{ item.name }}</h2>
<span>{{ item.createTime }}</span>
</div>
<p>{{ item.content }}</p>
<div class="images" v-if="item.images.length">
<image v-for="(img, i) in item.images" @click="preview(img.url, item.images)" :key="i" class="banner" :src="img.url" />
</div>
</div>
<AiEmpty v-if="!list.length"></AiEmpty>
</div>
</div>
</div>
</div>
<div class="add" v-if="isShowAdd" hover-class="text-hover" @click="toAdd(`/village/villageActivity/AddDynamic?activityId=${id}`)">
<image src="/static/img/add-big.png" />
</div>
<div class="btn-wrapper" v-if="info.status === '0'">
<div class="btn" :class="[info.hasReport === '1' ? 'disabled' : '']" @click="signUp" hover-class="text-hover">{{ info.hasReport === '1' ? '已报名' : '立即报名' }}</div>
</div>
<ai-login ref="login"></ai-login>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
data () {
return {
currIndex: 0,
tabActive: {
color: '#333333',
fontSize: '16px'
},
pageShow: false,
id: '',
current: 1,
list: [],
isMore: false,
info: ''
}
},
computed: {
tabs () {
return [{
name: '活动须知'
}, {
name: '活动动态'
}]
},
...mapState(['user', 'token']),
isShowAdd () {
const time = (new Date().getTime() - new Date(this.info.endTime).getTime()) / 60 / 60 / 1000
if (!this.info.endTime) {
return false
}
if (this.info.status === '0') {
return false
}
return !(this.info.status === '2' && time > 24);
}
},
onLoad (query) {
this.$loading()
this.id = query.id
this.getList(query.id)
this.$dict.load(['villageActivityStatus']).then(() => {
this.getInfo(query.id)
})
uni.$on('update', () => {
this.isMore = false
this.current = 1
this.getList(query.id)
})
},
methods: {
getInfo (id) {
this.$instance.post(`/app/appvillageactivityinfo/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.info = res.data
this.info.url = res.data.url ? JSON.parse(res.data.url)[0].url: ''
this.$nextTick(() => {
this.pageShow = true
})
}
this.$hideLoading()
}).catch(() => {
this.$hideLoading()
})
},
toAdd (url) {
if (!this.token) {
this.$refs.login.show()
return false
}
if (!this.user.residentId) {
this.$linkTo('/pages/auth/authenticationInfo')
return false
}
if (this.info.hasReport === '0') {
return this.$toast('您还未报名,无法发布活动动态!')
}
this.$linkTo(url)
},
signUp () {
if (this.info.status === '1') {
return this.$toast('报名已截止')
}
if (this.info.status === '2') {
return this.$toast('活动已结束')
}
if (!this.token) {
this.$refs.login.show()
return false
}
if (!this.user.residentId) {
this.$linkTo('/pages/auth/authenticationInfo')
return false
}
this.$loading()
this.$instance.post('/app/appvillageactivityuser/report', {
activityId: this.id,
userId: this.$store.state.user.id,
name: this.$store.state.user.nickName,
phone: this.$store.state.user.phone
}).then(res => {
if (res.code === 0) {
this.$toast('报名成功')
this.getInfo(this.id)
}
this.$hideLoading()
})
},
preview (url, imgs) {
uni.previewImage({
urls: imgs.map(v => v.url),
current: url
})
},
getList (id) {
if (this.isMore) return
this.$instance.post(`/app/appvillageactivitypost/list?activityId=${id}`, null, {
params: {
current: this.current,
size: 10
}
}).then(res => {
if (res.code == 0) {
if (this.current > 1) {
this.list = [...this.list, ...res.data.records].map(v => {
return {
...v,
images: v.images ? JSON.parse(v.images) : []
}
})
} else {
this.list = res.data.records.map(v => {
return {
...v,
images: v.images ? JSON.parse(v.images) : []
}
})
}
this.pageShow = true
if (res.data.records.length < 10) {
this.isMore = true
return false
}
this.current = this.current + 1
}
})
},
call (phone) {
uni.makePhoneCall({
phoneNumber: phone
})
}
},
onReachBottom() {
this.getList()
}
}
</script>
<style lang="scss" scoped>
.detail {
min-height: 100vh;
padding: 0 0 250px 0;
background: #fff;
.add {
position: fixed;
bottom: 140px;
right: 20px;
z-index: 111;
width: 128px;
height: 128px;
image {
width: 128px;
height: 128px;
}
}
::v-deep .u-tab-item {
font-size: 32px!important;
&:first-child {
padding: 0!important;
}
}
.detail-wrapper {
padding-bottom: 48px;
background: #fff;
& > image {
width: 100%;
height: 480px;
}
& > h2 {
line-height: 1.4;
padding: 32px;
font-size: 40px;
font-weight: 600;
color: #333;
text-align: justify;
}
& > div {
padding: 0 32px;
}
}
.detail-info {
.detail-info__item {
display: flex;
justify-content: space-between;
padding: 34px 0;
border-bottom: 1px solid #DDDDDD;
label {
color: #999999;
font-size: 32px;
}
.right {
display: flex;
align-items: center;
max-width: 480px;
text-align: right;
span {
color: #333333;
font-size: 32px;
}
&.detail-info__item--phone {
span {
color: #4181FF;
}
}
}
}
}
.detail-status {
display: flex;
align-items: center;
justify-content: space-between;
padding-bottom: 12px;
& > span {
width: 96px;
height: 44px;
line-height: 44px;
text-align: center;
color: #fff;
background: #42D784;
border-radius: 8px;
font-size: 26px;
&.status1 {
background: #1AAAFF;
}
&.status2 {
background: #E4E4E4;
}
}
.detail-status__right {
display: flex;
align-items: center;
span {
color: #999999;
font-size: 28px;
}
i {
font-style: normal;
color: #4181FF;
font-size: 28px;
}
}
}
.tab-active {
color: #333333;
font-size: 32px;
}
.detail-tips {
padding: 10px 32px 0!important;
& > h2 {
height: 116px;
line-height: 116px;
color: #333333;
font-size: 32px;
}
p {
line-height: 1.4;
margin-top: 24px;
color: #333333;
font-size: 32px;
text-align: justify;
}
}
.dynamic-list {
.dynamic-item {
padding: 24px 0;
.images {
display: flex;
flex-wrap: wrap;
margin-top: 16px;
image {
width: 226px;
height: 226px;
margin: 0 4px 4px 0;
border-radius: 16px;
}
}
.dynamic-item__top {
display: flex;
align-items: center;
justify-content: space-between;
span {
color: #999999;
font-size: 26px;
}
h2 {
color: #333333;
font-size: 34px;
font-weight: 600;
}
}
p {
line-height: 1.4;
text-align: justify;
color: #333333;
font-size: 28px;
}
}
}
}
</style>

View File

@@ -0,0 +1,132 @@
<template>
<div class="dynamic">
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i></i>
<h2>内容</h2>
</div>
<div class="form-item__textarea">
<textarea v-model="content" :maxlength="500" placeholder="请输入详细描述信息"></textarea>
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i style="opacity: 0;"></i>
<h2>图片上传</h2>
<span>(最多9张)</span>
</div>
<div class="form-item__img">
<ai-uploader v-model="images" :limit="9"></ai-uploader>
</div>
</div>
</div>
<div class="btn-wrapper">
<div class="btn disabled" hover-class="text-hover" @click="submit">提交</div>
</div>
</div>
</template>
<script>
import AiUploader from '@/components/AiUploader/AiUploader'
export default {
data () {
return {
content: '',
images: [],
id: '',
flag: false
}
},
components: {
AiUploader
},
onLoad (e) {
this.id = e.activityId
},
methods: {
submit () {
if (this.flag) return
if (!this.content && !this.images.length) {
return this.$u.toast('内容或图片不能为空')
}
this.flag = true
this.$loading()
this.$instance.post('/app/appvillageactivitypost/addOrUpdate', {
content: this.content,
activityId: this.id,
avatar: this.$store.state.user.avatarUrl,
name: this.$store.state.user.nickName,
images: JSON.stringify(this.images)
}).then(res => {
if (res.code === 0) {
this.$toast('提交成功')
uni.$emit('update')
setTimeout(() => {
uni.navigateBack({
delta: 1
})
}, 800)
}
this.$hideLoading()
})
}
}
}
</script>
<style lang="scss">
.dynamic {
.form-item {
margin-bottom: 24px;
padding-left: 32px;
padding-bottom: 20px;
background: #fff;
.form-item__wrapper {
padding-right: 32px;
}
.form-item__textarea, .form-item__img {
padding-left: 18px;
textarea {
width: 100%;
}
}
.form-item__title {
display: flex;
align-items: center;
padding: 32px 0;
i {
font-size: 32px;
color: #FF4466;
}
span {
font-size: 28px;
color: #999999;
}
h2 {
padding: 0 4px;
font-weight: 600;
font-size: 32px;
color: #333333;
}
}
}
}
</style>

View File

@@ -0,0 +1,223 @@
<template>
<div class="activity" v-if="pageShow">
<div class="activity-title">
<h2>活动列表</h2>
<div class="right">
<span></span>
<i>{{ total }}</i>
<span>个活动</span>
</div>
</div>
<div class="activity-list">
<div class="item" hover-class="bg-hover" @click="$linkTo(`/village/villageActivity/ActivityDetail?id=${item.id}`)"
v-for="(item, index) in list" :key="index">
<div class="left">
<h2>{{ item.title }}</h2>
<div class="left-info">
<span></span>
<i>{{ item.createUserName }}</i>
<span>发起</span>
</div>
<div class="date">{{ item.beginTime }} {{ item.endTime }}</div>
<div class="address">{{ item.areaName }}{{ item.address }}</div>
</div>
<div class="right">
<span :class="'status' + item.status">{{ item.statusName }}</span>
<image :src="item.url" mode="aspectFill"/>
</div>
</div>
<AiEmpty v-if="!list.length"></AiEmpty>
</div>
</div>
</template>
<script>
export default {
name: "AppVillageActivity",
appName: "居民活动",
data() {
return {
list: [],
pageShow: false,
current: 1,
total: 0,
isMore: false
}
},
onLoad() {
this.$loading()
this.$dict.load(['villageActivityStatus']).then(() => {
this.getList()
})
},
methods: {
getList() {
if (this.isMore) return
this.$instance.post(`/app/appvillageactivityinfo/listUp`, null, {
params: {
current: this.current,
size: 15,
areaId: uni.getStorageSync('areaId')
}
}).then(res => {
if (res.code == 0) {
this.total = res.data.total
if (this.current > 1) {
this.list = [...this.list, ...res.data.records].map(v => {
return {
...v,
statusName: this.$dict.getLabel('villageActivityStatus', v.status),
url: v.url ? JSON.parse(v.url)[0].url : ''
}
})
} else {
this.list = res.data.records.map(v => {
return {
...v,
statusName: this.$dict.getLabel('villageActivityStatus', v.status),
url: v.url ? JSON.parse(v.url)[0].url : ''
}
})
}
uni.hideLoading()
this.pageShow = true
if (res.data.records.length < 15) {
this.isMore = true
return false
}
this.current = this.current + 1
} else {
uni.hideLoading()
}
}).catch(() => {
uni.hideLoading()
})
}
},
onReachBottom() {
this.getList()
}
}
</script>
<style lang="scss" socped>
.activity {
padding-bottom: 40px;
.activity-title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
padding: 48px 32px 0 32px;
& > h2 {
font-size: 38px;
color: #333;
font-weight: 600;
}
.right {
display: flex;
align-items: center;
span {
color: #666666;
font-size: 28px;
}
i {
color: #4181FF;
font-style: normal;
font-size: 28px;
}
}
}
.item {
display: flex;
justify-content: space-between;
margin: 0 32px 24px;
padding: 32px;
border-radius: 16px;
background: #fff;
.left {
flex: 1;
color: #666666;
font-size: 26px;
h2 {
margin-bottom: 16px;
color: #333;
font-size: 32px;
font-weight: 600;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.date {
margin: 8px 0;
}
.left-info {
display: flex;
align-items: center;
i {
color: #4181FF;
font-style: normal;
font-size: 26px;
}
}
}
.right {
position: relative;
width: 200px;
height: 200px;
border-radius: 10px;
overflow: hidden;
image {
width: 200px;
height: 200px;
border-radius: 10px;
}
span {
position: absolute;
right: 0;
top: 0;
z-index: 1;
width: 96px;
height: 44px;
line-height: 44px;
font-size: 26px;
text-align: center;
color: #fff;
}
.status0 {
background: #42D784;
}
.status1 {
background: #1AAAFF;
}
.status2 {
background: #E4E4E4;
}
}
}
}
</style>

View File

@@ -0,0 +1,279 @@
<template>
<div class="villager-discussion">
<div class="header">
<u-tabs
:list="tabs"
font-size="36"
bg-color="transparent"
:bold="false"
inactive-color="#ccddff"
:is-scroll="true"
:gutter="16"
active-color="#fff"
:current="currIndex"
@change="onChange">
</u-tabs>
</div>
<div class="discussion-total">
<h2>议事列表</h2>
<div class="right">
<span></span>
<i>{{ total }}</i>
<span></span>
</div>
</div>
<div class="discussion-list">
<div class="item" hover-class="text-hover" v-for="(item, index) in list" :key="index" @click="$linkTo('/village/villagerDiscussion/VillagerDiscussionDetail?id=' + item.id)">
<h2>{{ item.title || item.content }}</h2>
<div class="images">
<image v-for="(img, i) in item.images" v-if="i < 3" :key="i" :src="img.url" />
</div>
<div class="item-tags">
<span :style="{backgroundColor: item.type === '1' ? '#FF883C' : '#1AAAFF'}">{{ item.typeName }}</span>
<div class="item-tags__right">
<span>{{ item.type === '1' ? item.voteCount : item.msgCount }}</span>
<i>{{ item.type === '1' ? '投票' : '发表过意见' }}</i>
</div>
</div>
<div class="item-bottom">
<span>{{ item.createUserName }}</span>
<i>{{ item.createTime }}</i>
</div>
</div>
<AiEmpty v-if="!list.length"></AiEmpty>
</div>
</div>
</template>
<script>
export default {
name:"AppVillagerDiscussion",
appName:"议事大厅",
data () {
return {
currIndex: 0,
list: [],
pageShow: false,
current: 1,
total: 0,
isMore: false
}
},
computed: {
tabs () {
return [{
name: '进行中'
}, {
name: '公示中'
}]
}
},
onLoad () {
this.$loading()
this.$dict.load(['discussType', 'discussStatus']).then(() => {
this.getList()
})
},
methods: {
onChange (e) {
this.currIndex = e
this.isMore = false
this.current = 1
this.$nextTick(() => {
this.getList()
})
},
getList() {
if (this.isMore) return
this.$instance.post(`/app/appvillagediscuss/listUp`, null, {
params: {
current: this.current,
size: 15,
status: this.currIndex,
areaId: uni.getStorageSync('areaId')
}
}).then(res => {
if (res.code == 0) {
this.total = res.data.total
if (this.current > 1) {
this.list = [...this.list, ...res.data.records].map(v => {
return {
...v,
typeName: this.$dict.getLabel('discussType', v.type),
images: v.images ? JSON.parse(v.images): []
}
})
} else {
this.list = res.data.records.map(v => {
return {
...v,
typeName: this.$dict.getLabel('discussType', v.type),
images: v.images ? JSON.parse(v.images): []
}
})
}
uni.hideLoading()
this.pageShow = true
if (res.data.records.length < 15) {
this.isMore = true
return false
}
this.current = this.current + 1
} else {
uni.hideLoading()
}
}).catch(() => {
uni.hideLoading()
})
}
},
onReachBottom() {
this.getList()
}
}
</script>
<style lang="scss">
.villager-discussion {
padding-bottom: 60px;
padding-top: 100px;
.header {
position: fixed;
top: 0;
left: 0;
z-index: 11;
width: 100%;
padding: 10px 0 10px 16px;
box-sizing: border-box;
background: #4181FF;
}
.discussion-total {
display: flex;
align-items: center;
justify-content: space-between;
margin: 48px 0 32px;
padding: 0 32px;
h2 {
color: #333333;
font-size: 38px;
font-weight: 600;
}
.right {
display: flex;
align-items: center;
span {
color: #666666;
font-size: 28px;
}
i {
font-style: normal;
color: #4181FF;
font-size: 28px;
}
}
}
.discussion-list {
.item {
margin: 0 32px 24px;
padding: 32px 32px 0 32px;
background: #fff;
border-radius: 16px;
overflow: hidden;
.item-bottom {
display: flex;
align-items: center;
justify-content: space-between;
height: 104px;
span {
color: #333333;
font-size: 28px;
}
i {
color: #999999;
font-size: 28px;
}
}
& > h2 {
margin-bottom: 24px;
color: #333333;
font-size: 36px;
font-weight: 600;
overflow : hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.images {
display: flex;
align-items: center;
image {
width: 204px;
height: 204px;
margin-right: 4px;
&:last-child {
margin-right: 0;
}
}
}
.item-tags {
display: flex;
align-items: center;
justify-content: space-between;
height: 104px;
border-bottom: 1px solid #DDDDDD;
& > span {
width: 148px;
height: 48px;
line-height: 48px;
text-align: center;
background: #1AAAFF;
color: #fff;
font-size: 28px;
border-radius: 24px;
}
.item-tags__right {
display: flex;
align-items: center;
span {
color: #4181FF;
font-size: 28px;
}
i {
color: #999999;
font-size: 28px;
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,630 @@
<template>
<div class="detail" v-if="pageShow">
<div class="detail-header">
<h2>{{ info.content || info.title }}</h2>
<div class="detail-info">
<h2>{{ info.createUserName }}</h2>
<span>{{ info.createTime }}</span>
</div>
<div class="images">
<image v-for="(img, i) in info.images" :key="i" :src="img.url" @click="preview(img.url)" />
</div>
</div>
<div class="detail-list">
<div class="detail-list__title">
<h2>{{ info.type === '0' ? '全部评论' : (info.voteType === '1' ? '投票清单(可多选)' : '投票清单') }}</h2>
<span v-if="!isTimeout && time">剩余 {{ time }}</span>
<span v-if="info.status !== '0'">已截止</span>
</div>
<div class="user-list" :style="{paddingBottom: !list.length ? '20px' : '0px'}" v-if="info.type === '0'">
<div class="user-item" v-for="(item, index) in list" :key="index">
<div class="user-item__top">
<image :src="item.avatar" />
<div class="user-item__top--right">
<div class="top">
<div class="left">
<h2>{{ item.createUserName }}</h2>
<span v-if="info.createUserId === item.createUserId">话事人</span>
</div>
<div class="right" @click="like(item.id)">
<image :src="item.isSuport ? '/static/img/like-active.png' : '/static/img/like.png'" />
<span>{{ item.suport }}</span>
</div>
</div>
<p>{{ item.createTime }}</p>
</div>
</div>
<p>{{ item.content }}</p>
</div>
<AiEmpty v-if="!list.length"></AiEmpty>
</div>
<div class="vote-list" v-if="info.type === '1'">
<div class="vote-item__wrapper">
<div
class="vote-item"
@click="choose(index)"
v-for="(item, index) in info.voteItems"
:key="index"
:class="[choosed.indexOf(index) > -1 ? 'active' : '']">
<span>{{ item.item }}</span>
<p>{{ item.content }}</p>
</div>
</div>
<div class="vote-total">
<div class="left">
<span></span>
<i>{{ info.votes.length }}</i>
<span>人投票</span>
</div>
<i @click="$linkTo('/village/villagerDiscussion/VoteList?id=' + id + '&anonymous=' + info.anonymous)">查看投票详情</i>
</div>
</div>
</div>
<div class="footer" v-if="info.type === '0' && info.status === '0' && !info.isTimeout">
<div class="input" @click="show = true">我来说两句...</div>
</div>
<div class="btn-wrapper" v-if="info.type === '1' && !info.isTimeout && info.status === '0'">
<div class="btn" :class="[info.myVote ? 'disabled' : '']" @click="signUp" hover-class="text-hover">{{ buttonText }}</div>
</div>
<!-- 弹框 -->
<u-popup v-model="show" mode="bottom">
<div class="inputBox" :style="{paddingBottom: height + px}">
<div class="text">
<textarea
@blur="height = 0"
placeholder-style="color: #999"
v-model="content"
:cursor-spacing="40"
fixed
placeholder="写下你的想法..."
@keyboardheightchange="keyboard">
</textarea>
</div>
<div class="option">
<div @click="clearBtn" class="clear">清空内容</div>
<div @click="confirm" class="publish">发表</div>
</div>
</div>
</u-popup>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
data () {
return {
content: '',
currIndex: 0,
pageShow: false,
info: {},
isTimeout: false,
time: '',
timer: null,
list: [],
current: 1,
choosed: [],
total: 0,
id: '',
isMore: false,
keys: ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
show: false,
height: 0
}
},
computed: {
...mapState(['user']),
buttonText () {
if (this.info.myVote) {
return '已投票'
}
if (this.info.anonymous === '1') {
return '匿名投票'
}
return '实名投票'
}
},
onLoad (query) {
this.id = query.id
this.getInfo(query.id)
this.$nextTick(() => {
this.getList()
})
},
methods: {
choose (index) {
if (this.info.status !== '0') {
return false
}
if (this.info.myVote) {
return false
}
if (this.info.voteType === '1') {
const i = this.choosed.indexOf(index)
if (i > -1) {
this.choosed.splice(i, 1)
} else {
this.choosed.push(index)
}
} else {
this.choosed = [index]
}
},
like (id) {
this.$loading()
this.$instance.post(`/app/appvillagediscussmessage/suport?id=${id}&userId=${this.user.id}`).then(res => {
if (res.code === 0) {
this.$toast('点赞成功')
this.current = 1
this.isMore = false
this.$nextTick(() => {
this.getList()
})
}
this.$hideLoading()
}).catch(() => {
this.$hideLoading()
})
},
getInfo (id) {
this.$loading()
this.$instance.post(`/app/appvillagediscuss/queryDetailById?id=${id}&userId=${this.user.id}`).then(res => {
if (res.code === 0) {
this.info = res.data
this.info.images = res.data.images ? JSON.parse(res.data.images): []
if (res.data.myVote && this.info.status === '0') {
const myVote = res.data.myVote.split(',')
myVote.forEach(v => {
this.choosed.push(this.keys.indexOf(v))
})
}
if (res.data.discussDeadline) {
this.countdown(res.data.discussDeadline)
}
this.$nextTick(() => {
this.pageShow = true
})
}
this.$hideLoading()
}).catch(() => {
this.$hideLoading()
})
},
signUp () {
if (this.info.myVote) {
return
}
if (!this.choosed.length) {
return this.$toast('请选择投票项')
}
this.$loading()
let item = []
this.choosed.forEach(v => {
item.push(this.info.voteItems[v].item)
})
this.$instance.post(`/app/appvillagediscussvote/addOrUpdate`, {
item: item.join(','),
discussId: this.id,
createUserId: this.user.realName || this.user.name,
createUserName: this.user.id,
avatar: this.user.avatarUrl
}).then(res => {
this.$hideLoading()
if (res.code === 0) {
this.$toast('投票成功')
this.getInfo(this.id)
}
}).catch(() => {
this.$hideLoading()
})
},
getList() {
if (this.isMore) return
this.$instance.post(`/app/appvillagediscussmessage/list`, null, {
params: {
current: this.current,
size: 15,
discussId: this.id,
status: this.currIndex,
areaId: uni.getStorageSync('areaId')
}
}).then(res => {
if (res.code == 0) {
this.total = res.data.total
if (this.current > 1) {
this.list = [...this.list, ...res.data.records].map(v => {
return {
...v,
typeName: this.$dict.getLabel('discussType', v.type),
images: v.images ? JSON.parse(v.images): [],
isSuport: v.suportUser ? v.suportUser.indexOf(this.user.id) > -1 : false
}
})
} else {
this.list = res.data.records.map(v => {
return {
...v,
typeName: this.$dict.getLabel('discussType', v.type),
images: v.images ? JSON.parse(v.images): [],
isSuport: v.suportUser ? v.suportUser.indexOf(this.user.id) > -1 : false
}
})
}
uni.hideLoading()
this.pageShow = true
if (res.data.records.length < 10) {
this.isMore = true
return false
}
this.current = this.current + 1
} else {
uni.hideLoading()
}
}).catch(() => {
uni.hideLoading()
})
},
clearBtn() {
this.content = ''
},
confirm () {
if (!this.content) {
return this.$toast('留言不能为空')
}
this.$loading()
this.$instance.post(`/app/appvillagediscussmessage/addOrUpdate`, {
content: this.content,
discussId: this.id,
createUserId: this.user.realName || this.user.name,
createUserName: this.user.id,
avatar: this.user.avatarUrl
}).then(res => {
if (res.code === 0) {
this.content = ''
this.$toast('发布成功')
this.isMore = false
this.current = 1
this.show = false
this.getList()
}
this.$hideLoading()
}).catch(() => {
this.$hideLoading()
})
},
keyboard(e) {
this.height = e.detail.height
},
countdown (time) {
this.timer = setInterval(() => {
if (new Date(time.replace(/-/g, '/')).getTime() < new Date().getTime()) {
this.isTimeout = true
clearInterval(this.timer)
} else {
var durationObj = this.$dayjs.duration(new Date(time.replace(/-/g, '/')).getTime() - new Date().getTime())
var hours = durationObj.hours() > 9 ? durationObj.hours() : '0' + durationObj.hours()
var min = durationObj.minutes() > 9 ? durationObj.minutes() : '0' + durationObj.minutes()
var seconds = durationObj.seconds() > 9 ? durationObj.seconds() : '0' + durationObj.seconds()
this.time = `${hours}小时${min}分钟${seconds}`
this.isTimeout = false
}
}, 1000)
},
preview (url) {
uni.previewImage({
urls: this.info.images.map(v => v.url),
current: url
})
}
},
onReachBottom() {
this.getList()
}
}
</script>
<style lang="scss" scoped>
.detail {
padding-bottom: 140px;
.vote-list {
.vote-item {
display: flex;
line-height: 1.3;
margin-top: 24px;
padding: 34px 32px;
color: #333333;
font-size: 32px;
background: #FFFFFF;
border-radius: 16px;
border: 1px solid #CCCCCC;
box-sizing: border-box;
p {
text-align: justify;
}
&.active {
border-color: #4181FF;
color: #fff;
background: #4181FF;
}
}
.vote-total {
display: flex;
align-items: center;
justify-content: space-between;
height: 100px;
.left {
display: flex;
align-items: center;
}
span {
color: #999999;
font-size: 28px;
}
i {
color: #4181FF;
font-size: 28px;
font-style: normal;
}
}
}
.footer {
display: flex;
position: fixed;
align-items: center;
justify-content: center;
bottom: 0;
left: 0;
z-index: 11;
width: 100%;
height: 120px;
padding: 0 30px;
box-sizing: border-box;
background-color: #fff;
border-top: 1px solid #DDDDDD;
.input {
flex: 1;
height: 88px;
line-height: 88px;
padding: 0 32px;
font-size: 32px;
border-radius: 44px;
box-sizing: border-box;
background-color: #F0F0F0;
color: #666666;
}
}
.inputBox {
width: 100%;
padding: 32px 30px 32px 24px;
box-sizing: border-box;
background-color: #FFFFFF;
.option {
display: flex;
justify-content: space-between;
.clear {
color: #666666;
}
.publish {
width: 144px;
height: 64px;
line-height: 64px;
text-align: center;
border-radius: 32px;
background-color: #1365DD;
color: #FFFFFF;
}
}
.text {
padding: 16px;
box-sizing: border-box;
background-color: #f7f7f7;
margin-bottom: 24px;
textarea {
width: 100%;
}
}
}
.detail-header {
margin-bottom: 40px;
padding: 32px;
background-color: #fff;
.images {
display: flex;
align-items: center;
flex-wrap: wrap;
margin-top: 30px;
image {
width: 226px;
height: 226px;
margin-bottom: 6px;
margin-right: 6px;
&:nth-of-type(3n) {
margin-right: 0;
}
}
}
& > h2 {
margin-bottom: 16px;
color: #333333;
font-size: 48px;
font-weight: 600;
}
.detail-info {
display: flex;
align-items: center;
margin-bottom: 30px;
span {
color: #999999;
font-size: 30px;
}
h2 {
margin-right: 32px;
font-size: 26px;
color: #333333;
font-weight: normal;
}
}
}
.detail-list {
padding: 0 32px;
background-color: #fff;
.detail-list__title {
display: flex;
align-items: center;
justify-content: space-between;
height: 116px;
h2 {
color: #333333;
font-weight: 600;
font-size: 38px;
}
span {
color: #999999;
font-size: 28px;
}
}
.user-item {
padding: 32px 0;
border-bottom: 1px solid #DDDDDD;
&:last-child {
border-bottom: none;
}
& > p {
line-height: 1.3;
margin-top: 12px;
padding-left: 114px;
color: #333333;
font-size: 28px;
}
.user-item__top {
display: flex;
align-items: center;
.user-item__top--right {
flex: 1;
.top {
display: flex;
align-items: center;
justify-content: space-between;
& > div {
display: flex;
align-items: center;
}
.right {
image {
width: 32px;
height: 32px;
margin-right: 8px;
}
span {
color: #999999;
font-size: 28px;
}
}
.left {
h2 {
margin-right: 24px;
color: #333333;
font-size: 34px;
font-weight: normal;
}
span {
width: 96px;
height: 44px;
line-height: 44px;
text-align: center;
color: #fff;
font-size: 26px;
background: #1AAAFF;
border-radius: 8px;
}
}
}
& > p {
margin-top: 8px;
color: #999999;
font-size: 26px;
}
}
& > image {
width: 96px;
height: 96px;
margin-right: 18px;
border-radius: 50%;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,123 @@
<template>
<div class="user">
<div class="user-item" :key="i" v-for="(item, i) in list">
<image :src="anonymous === '1' ? '/static/img/avatar.png' : item.avatar" />
<div class="user-item__right">
<div class="left">
<h2>{{ anonymous === '1' ? '居民' : item.userName }}</h2>
<p>{{ item.createTime }}</p>
</div>
<span>选择了{{ item.item }}</span>
</div>
</div>
<AiEmpty v-if="!list.length"></AiEmpty>
</div>
</template>
<script>
export default {
data () {
return {
pageShow: false,
id: '',
current: 1,
list: [],
isMore: false,
info: '',
anonymous: ''
}
},
onLoad (query) {
this.$loading()
this.anonymous = query.anonymous
this.getList(query.id)
},
methods: {
getList(id) {
if (this.isMore) return
this.$instance.post(`/app/appvillagediscussvote/list?discussId=${id}`, null, {
params: {
current: this.current,
size: 15
}
}).then(res => {
if (res.code == 0) {
this.total = res.data.total
if (this.current > 1) {
this.list = [...this.list, ...res.data.records]
} else {
this.list = res.data.records
}
uni.hideLoading()
this.pageShow = true
if (res.data.records.length < 15) {
this.isMore = true
return false
}
this.current = this.current + 1
} else {
uni.hideLoading()
}
}).catch(() => {
uni.hideLoading()
})
}
},
onReachBottom() {
this.getList()
}
}
</script>
<style lang="scss" socped>
.user {
padding: 32px 32px 40px;
.user-item {
display: flex;
align-items: center;
justify-content: space-between;
height: 160px;
margin-bottom: 24px;
padding: 0 32px;
border-radius: 16px;
background-color: #fff;
image {
width: 96px;
height: 96px;
margin-right: 16px;
border-radius: 50%;
}
.user-item__right {
display: flex;
align-items: center;
justify-content: space-between;
flex: 1;
span {
color: #999999;
font-size: 28px;
}
h2 {
margin-bottom: 10px;
color: #333333;
font-size: 32px;
}
p {
color: #999999;
font-size: 28px;
}
}
}
}
</style>

View File

@@ -0,0 +1,98 @@
<template>
<div class="info" v-if="pageShow">
<h2>{{ info.title }}</h2>
<div class="info-info">
<span>{{ info.areaName }}</span>
<span>{{ info.createDate }}</span>
</div>
<image class="banner" @click="preview(banner)" v-if="banner" mode="widthFix" :src="banner"/>
<div class="rich-content">
<u-parse :html="info.content"></u-parse>
</div>
<AiEmpty v-if="!info.title"></AiEmpty>
</div>
</template>
<script>
export default {
name: "AppVillagerInfo",
appName: "本村简介",
data() {
return {
pageShow: false,
info: {},
banner: ''
}
},
onLoad(query) {
if (query.type !== '0') {
uni.setNavigationBarTitle({
title: '村规民约'
})
}
this.$loading()
this.getInfo(query.type)
},
methods: {
getInfo(type) {
this.$instance.post(`/app/appcountrysidetourism/queryDetailByAreaIdForWX?areaId=${uni.getStorageSync('areaId')}&type=${type}`).then(res => {
if (res.code === 0 && res.data) {
this.info = res.data
this.banner = res.data.thumbUrl ? JSON.parse(res.data.thumbUrl)[0].url : ''
}
this.$nextTick(() => {
this.pageShow = true
})
})
},
preview(url) {
uni.previewImage({
urls: [url],
current: url
})
}
}
}
</script>
<style lang="scss" scoped>
.info {
min-height: 100vh;
padding: 0 32px 40px;
box-sizing: border-box;
background-color: #fff;
.banner {
width: 100%;
margin-bottom: 20px;
}
h2 {
line-height: 1.3;
padding: 32px 0 16px;
font-size: 48px;
font-weight: 600;
color: #333;
}
.info-info {
display: flex;
align-items: center;
margin-bottom: 30px;
span {
color: #999999;
font-size: 30px;
&:last-child {
margin-left: 32px;
}
}
}
}
</style>

View File

@@ -0,0 +1,435 @@
<template>
<div class="album">
<div class="tips">请确保以下信息全部由本人填写本人对所填写内容的真实性和完整性负责</div>
<div class="form-item__group">
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>返乡人员姓名</h2>
</div>
<div class="form-item__right">
<input placeholder="请输入" v-model="form.name" disabled :maxlength="20" />
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>身份证号</h2>
</div>
<div class="form-item__right">
<input placeholder="请输入" v-model="form.idNumber" disabled :maxlength="20" />
</div>
</div>
</div>
</div>
<div class="form-item__group">
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>当前体温</h2>
</div>
<div class="form-item__right">
<input placeholder="请输入" v-model="form.temperature" :maxlength="20" />
<i></i>
</div>
</div>
</div>
<div class="form-item form-item__imgs">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>14天内是否接触新冠确诊或疑似患者</h2>
</div>
<div class="form-item__right">
<ai-radio style="width: 100%;" v-model="form.touchInFourteen" dict="epidemicTouchInFourteen"></ai-radio>
</div>
</div>
</div>
<div class="form-item form-item__imgs">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>当前健康状况可多选</h2>
</div>
<div class="form-item__right">
<ai-checkbox style="width: 100%;" v-model="form.health" dict="epidemicRecentHealth"></ai-checkbox>
</div>
</div>
</div>
</div>
<div class="form-item__group">
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>核酸检测日期</h2>
</div>
<div class="form-item__right">
<div class="ai-area" @click="isShowDate = true">
<div class="ai-area__wrapper">
<span class="label" v-if="form.checkTime">{{ form.checkTime }}</span>
<i v-else>请选择</i>
<u-icon name="arrow-right" color="#ddd"/>
</div>
</div>
</div>
</div>
</div>
<div class="form-item form-item__imgs">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>核酸检测结果</h2>
</div>
<div class="form-item__right">
<ai-radio style="width: 100%;" v-model="form.checkResult" dict="epidemicRecentTestResult"></ai-radio>
</div>
</div>
</div>
<div class="form-item form-item__imgs">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>健康码类型</h2>
</div>
<div class="form-item__right">
<ai-radio style="width: 100%;" v-model="form.healthCode" dict="epidemicHealthCode"></ai-radio>
</div>
</div>
</div>
<div class="form-item form-item__imgs">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>已接种疫苗次数</h2>
</div>
<div class="form-item__right">
<ai-radio style="width: 100%;" v-model="form.vaccine" dict="epidemicVaccineTime"></ai-radio>
</div>
</div>
</div>
<div class="form-item form-item__imgs">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>本人健康码截图</h2>
</div>
<div class="form-item__right">
<ai-uploader v-model="form.checkPhoto" :limit="1"></ai-uploader>
</div>
</div>
</div>
</div>
<u-picker mode="time" :params="dataParams" v-model="isShowDate" @confirm="onDateChange"></u-picker>
<div class="btn-wrapper">
<div class="btn" hover-class="text-hover" @click="submit">提交</div>
</div>
</div>
</template>
<script>
import AiUploader from '@/components/AiUploader/AiUploader'
import AiSelect from '@/components/AiSelect/AiSelect'
import { mapState } from 'vuex'
export default {
data () {
return {
isShowDate: false,
dataParams: {
year: true,
month: true,
day: true
},
form: {
name: '',
idNumber: '',
checkPhoto: [],
checkResult: '',
health: '',
healthCode: '',
temperature: '',
vaccine: '',
checkTime: '',
memberId: ''
}
}
},
components: {
AiSelect,
AiUploader
},
computed: {
...mapState(['user'])
},
onLoad (query) {
this.form.memberId = query.id
this.getInfo(query.id)
},
methods: {
getInfo (id) {
this.$instance.post(`/app/appepidemicreportmember/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.form.name = res.data.name
this.form.idNumber = res.data.idNumber
this.form.checkTime = res.data.checkTime ? res.data.checkTime.split(' ')[0] : ''
this.form.checkResult = res.data.checkResult || ''
this.form.healthCode = res.data.healthCode || ''
this.form.vaccine = res.data.vaccine || ''
}
this.$hideLoading()
}).catch(() => {
this.$hideLoading()
})
},
onDateChange (e) {
this.form.checkTime = `${e.year}-${e.month}-${e.day}`
},
submit () {
if (!this.form.temperature) {
return this.$toast('请输入当前体温')
}
if (!this.form.touchInFourteen) {
return this.$toast('请选择14天内是否接触新冠确诊或疑似患者')
}
if (!this.form.health.length) {
return this.$toast('请选择当前健康状况')
}
if (!this.form.checkTime) {
return this.$toast('请选择核酸检测日期')
}
if (!this.form.checkResult) {
return this.$toast('请选择核酸检测结果')
}
if (!this.form.healthCode) {
return this.$toast('请选择健康码类型')
}
if (!this.form.vaccine) {
return this.$toast('请选择已接种疫苗次数')
}
if (!this.form.checkPhoto.length) {
return this.$toast('请上传健康码截图')
}
this.$loading()
this.$instance.post(`/app/appepidemichealthreport/addOrUpdate`, {
...this.form,
openid: this.user.openid,
health: this.form.health.join(','),
checkPhoto: JSON.stringify(this.form.checkPhoto),
checkTime: this.form.checkTime + ' 00:00:00'
}).then(res => {
if (res.code == 0) {
uni.$emit('update')
this.$toast('提交成功')
setTimeout(() => {
uni.navigateBack()
}, 400)
}
this.$hideLoading()
})
}
}
}
</script>
<style lang="scss">
.album {
padding-bottom: 140px;
.tips {
line-height: 1.3;
padding: 32px 32px;
color: #FF883C;
font-size: 30px;
text-align: justify;
background: #FFF8F3;
}
.form-item__group {
margin-bottom: 24px;
background: #fff;
}
.form-item {
padding-left: 32px;
.form-item__checkbox {
width: 100%;
div {
width: 100%;
height: 80px;
line-height: 80px;
margin-bottom: 24px;
text-align: center;
background: #FFFFFF;
border-radius: 16px;
color: #333333;
font-size: 28px;
border: 1px solid #CCCCCC;
&.active {
background: #4181FF;
color: #fff;
border-color: #4181FF;
}
}
}
.form-item__radio {
display: flex;
align-items: center;
flex-wrap: wrap;
div {
width: 212px;
height: 80px;
line-height: 80px;
margin-right: 16px;
margin-bottom: 8px;
text-align: center;
background: #FFFFFF;
border-radius: 16px;
color: #333333;
font-size: 28px;
border: 1px solid #CCCCCC;
&:nth-of-type(3n) {
margin-right: 0;
}
&.active {
background: #4181FF;
color: #fff;
border-color: #4181FF;
}
}
}
.ai-area__wrapper {
display: flex;
align-items: center;
padding-left: 100px;
span {
color: #333;
font-size: 30px;
}
i {
color: #999;
font-size: 30px;
}
image {
width: 16px;
height: 8px;
}
}
.form-item__wrapper {
display: flex;
align-items: center;
justify-content: space-between;
height: 128px;
padding-right: 28px;
border-bottom: 1px solid #DDDDDD;
input {
flex: 1;
height: 100%;
text-align: right;
color: #333;
padding-right: 10px;
}
.form-item__right {
display: flex;
align-items: center;
font-size: 32px;
span {
max-width: 400px;
margin-right: 8px;
color: #333333;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
i {
margin-right: 8px;
color: #999999;
}
}
}
&:last-child {
.form-item__wrapper {
border-bottom: none;
}
}
.form-item__title {
display: flex;
align-items: center;
i {
font-size: 32px;
color: #FF4466;
}
span {
font-size: 28px;
color: #999999;
}
h2 {
padding: 0 4px;
font-weight: 600;
font-size: 32px;
color: #333333;
}
}
&.form-item__imgs, &.form-item__textarea {
.form-item__wrapper {
display: block;
height: auto;
padding-bottom: 32px;
}
textarea {
width: 100%;
height: 90px;
}
.form-item__title {
padding: 32px 0;
}
.form-item__right {
padding-left: 18px;
}
}
}
}
</style>

View File

@@ -0,0 +1,330 @@
<template>
<div class="album">
<div class="form-item__group">
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>上报人姓名</h2>
</div>
<div class="form-item__right">
<input placeholder="请输入" v-model="form.name" :maxlength="20" />
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>身份证号</h2>
</div>
<div class="form-item__right">
<input placeholder="请输入" type="idcard" v-model="form.idNumber" :maxlength="20" />
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>手机号码</h2>
</div>
<div class="form-item__right">
<input placeholder="请输入" type="number" v-model="form.phone" :maxlength="11" />
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>上报地区</h2>
</div>
<div class="form-item__right">
<ai-area-picker ref="area" class="ai-area" :value="form.areaId" :areaId="$areaId" :fullName.sync="form.areaName" all mode="custom" @select="v => form.areaId = v">
<div class="ai-area__wrapper">
<span class="label" v-if="form.areaName">{{ form.areaName }}</span>
<i v-else>请选择</i>
<u-icon name="arrow-right" color="#ddd"/>
</div>
</ai-area-picker>
</div>
</div>
</div>
<div class="form-item form-item__textarea">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>详细地址</h2>
</div>
<div class="form-item__right">
<textarea auto-height v-model="form.address" :maxlength="500" placeholder="请输入详细地址" placeholder-style="font-size: 16px;"></textarea>
</div>
</div>
</div>
</div>
<div class="btn-wrapper">
<div class="btn" hover-class="text-hover" @click="submit">提交</div>
</div>
</div>
</template>
<script>
import AiSelect from '@/components/AiSelect/AiSelect'
import { mapState } from 'vuex'
export default {
data () {
return {
form: {
address: '',
areaId: '',
areaName: '',
idNumber: '',
name: '',
phone: ''
},
$areaId: '',
flag: false
}
},
components: {
AiSelect
},
computed: {
...mapState(['user'])
},
methods: {
submit () {
if (!this.form.name) {
return this.$toast('请输入上报人姓名')
}
if (!this.form.idNumber) {
return this.$toast('请输入上报人身份证号')
}
if (!/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(this.form.idNumber)) {
return this.$toast('请输入正确的身份证账号')
}
if (!this.form.phone) {
return this.$toast('请选择上报人手机号码')
}
if (!/^1[0-9]{10,10}$/.test(this.form.phone)) {
return this.$toast('请输入正确的手机号码')
}
if (!this.form.areaId) {
return this.$toast('请选择上报地区')
}
if (this.form.areaId.substr(this.form.areaId.length - 3, 3) === '000') {
return this.$toast('上报地区必须选到村或社区')
}
if (!this.form.address) {
return this.$toast('请输入详细地址')
}
if (this.flag) return
this.flag = true
this.$loading()
this.$instance.post(`/app/appepidemicreportmember/addOrUpdate`, {
...this.form,
openid: this.user.openid
}).then(res => {
this.$hideLoading()
this.flag = false
if (res.code == 0) {
this.$toast('提交成功')
uni.$emit('update')
setTimeout(() => {
uni.redirectTo({
url: `./Result?id=${res.data.id}`
})
}, 400)
}
})
}
}
}
</script>
<style lang="scss">
.album {
padding-bottom: 140px;
.form-item__group {
margin-bottom: 24px;
background: #fff;
}
.form-item {
padding-left: 32px;
.form-item__checkbox {
width: 100%;
div {
width: 100%;
height: 80px;
line-height: 80px;
margin-bottom: 24px;
text-align: center;
background: #FFFFFF;
border-radius: 16px;
color: #333333;
font-size: 28px;
border: 1px solid #CCCCCC;
&.active {
background: #4181FF;
color: #fff;
border-color: #4181FF;
}
}
}
.form-item__radio {
display: flex;
align-items: center;
flex-wrap: wrap;
div {
width: 212px;
height: 80px;
line-height: 80px;
margin-right: 16px;
margin-bottom: 8px;
text-align: center;
background: #FFFFFF;
border-radius: 16px;
color: #333333;
font-size: 28px;
border: 1px solid #CCCCCC;
&:nth-of-type(3n) {
margin-right: 0;
}
&.active {
background: #4181FF;
color: #fff;
border-color: #4181FF;
}
}
}
.ai-area__wrapper {
display: flex;
align-items: center;
padding-left: 100px;
span {
color: #333;
font-size: 30px;
}
i {
color: #999;
font-size: 30px;
}
image {
width: 16px;
height: 8px;
}
}
.form-item__wrapper {
display: flex;
align-items: center;
justify-content: space-between;
height: 128px;
padding-right: 28px;
border-bottom: 1px solid #DDDDDD;
input {
flex: 1;
height: 100%;
text-align: right;
color: #333;
padding-right: 10px;
}
.form-item__right {
display: flex;
align-items: center;
font-size: 32px;
span {
max-width: 400px;
margin-right: 8px;
color: #333333;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
i {
margin-right: 8px;
color: #999999;
}
}
}
&:last-child {
.form-item__wrapper {
border-bottom: none;
}
}
.form-item__title {
display: flex;
align-items: center;
i {
font-size: 32px;
color: #FF4466;
}
span {
font-size: 28px;
color: #999999;
}
h2 {
padding: 0 4px;
font-weight: 600;
font-size: 32px;
color: #333333;
}
}
&.form-item__imgs, &.form-item__textarea {
.form-item__wrapper {
display: block;
height: auto;
padding-bottom: 32px;
}
textarea {
width: 100%;
height: 90px;
}
.form-item__title {
padding: 32px 0;
}
.form-item__right {
padding-left: 18px;
}
}
}
}
</style>

View File

@@ -0,0 +1,225 @@
<template>
<div class="returnHomeRegister" v-if="pageShow">
<div class="title">
<h2>上报人员</h2>
<div class="right">
<span></span>
<i>{{ total }}</i>
<span></span>
</div>
</div>
<div class="home-list">
<div class="item" v-for="(item, index) in list" :key="index">
<div class="item-top">
<div class="item-top__left">
<h2>{{ item.name }}</h2>
<p @click.stop="$linkTo('./UserInfo?id=' + item.id)" hover-class="text-hover">查看个人信息></p>
</div>
<span v-if="item.status === '0'">健康数据异常</span>
</div>
<div class="item-bottom">
<div class="item-bottom__left">
<span>上报第</span>
<i>{{ item.diffNum || 0 }}</i>
<span></span>
</div>
<div class="item-bottom__right" hover-class="text-hover" v-if="item.today === '0'" @click.stop="$linkTo('./AddReport?id=' + item.id)">
<span style="color: #FF883C">今日未上报</span>
<u-icon name="arrow-right" color="#ddd"/>
</div>
<div class="item-bottom__right" hover-class="text-hover" v-else @click.stop="$linkTo('./RecordList?id=' + item.id)">
<span style="color: #999999">今日已上报</span>
<u-icon name="arrow-right" color="#ddd"/>
</div>
</div>
</div>
<AiEmpty v-if="!list.length && isMore"></AiEmpty>
</div>
<div class="btn-wrapper">
<div class="btn" @click="toReport" hover-class="text-hover">添加上报人员</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name:"AppHealthReport",
appName:"健康上报",
data () {
return {
list: [],
pageShow: false,
current: 1,
total: 0,
isMore: false
}
},
computed: {
...mapState(['user'])
},
onLoad () {
this.$loading()
this.$dict.load(['villageActivityStatus']).then(() => {
this.getList()
})
uni.$on('update', () => {
this.current = 1
this.isMore = false
this.$nextTick(() => {
this.getList()
})
})
},
methods: {
toReport () {
this.$linkTo('./AddUser')
},
getList() {
if (this.isMore) return
this.$instance.post(`/app/appepidemicreportmember/list?openId=${this.user.openId}`, null, {
params: {
current: this.current,
size: 15
}
}).then(res => {
if (res.code == 0) {
this.total = res.data.total
if (this.current > 1) {
this.list = [...this.list, ...res.data.records]
} else {
this.list = res.data.records
}
uni.hideLoading()
this.pageShow = true
if (res.data.records.length < 15) {
this.isMore = true
return false
}
this.current = this.current + 1
} else {
uni.hideLoading()
}
}).catch(() => {
uni.hideLoading()
})
}
},
onReachBottom() {
this.getList()
}
}
</script>
<style lang="scss" socped>
.returnHomeRegister {
padding: 0 0 150px 0;
.title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
padding: 48px 32px 0 32px;
& > h2 {
font-size: 38px;
color: #333;
font-weight: 600;
}
.right {
display: flex;
align-items: center;
span {
color: #666666;
font-size: 28px;
}
i {
color: #4181FF;
font-style: normal;
font-size: 28px;
}
}
}
.item {
margin: 0 32px 24px;
border-radius: 16px;
background: #fff;
.item-top {
display: flex;
align-items: center;
justify-content: space-between;
height: 152px;
padding: 0 32px;
border-bottom: 1px solid #DDDDDD;
.item-top__left {
h2 {
line-height: 44px;
margin-bottom: 8px;
color: #333;
font-size: 32px;
font-weight: 600;
}
p {
color: #999999;
font-size: 26px;
}
}
& > span {
font-size: 26px;
color: #FF4466;
}
}
.item-bottom {
display: flex;
align-items: center;
justify-content: space-between;
height: 104px;
padding: 0 32px;
.item-bottom__right {
span {
color: #999999;
font-size: 28px;
}
}
.item-bottom__left {
span {
color: #999999;
font-size: 28px;
}
i {
color: #4181FF;
font-size: 28px;
}
}
& > div {
display: flex;
align-items: center;
}
}
}
}
</style>

View File

@@ -0,0 +1,245 @@
<template>
<div class="detail">
<div class="detail-info">
<h2>健康状况</h2>
<div class="detail-info__item">
<div class="left">
<label>当前体温</label>
</div>
<div class="right">
<span :style="{color: info.temperature >= 37.3 ? '#FF4466' : '#42D784'}">{{ info.temperature }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>14天内是否接触新冠确诊或疑似患者</label>
</div>
<div class="right">
<span :style="{color: info.touchInFourteen === '0' ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicTouchInFourteen', info.touchInFourteen) }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>当前健康状况</label>
</div>
<div class="right">
<span :style="{color: !info.isHealth ? '#42D784' : '#FF4466'}">{{ info.healthName }}</span>
</div>
</div>
</div>
<div class="detail-info">
<h2>核酸检测信息</h2>
<div class="detail-info__item">
<div class="left">
<label>核酸检测日期</label>
</div>
<div class="right">
<span>{{ info.checkTime.split(' ')[0] }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>核酸检测结果</label>
</div>
<div class="right">
<span :style="{color: info.checkResult === '0' ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicRecentTestResult', info.checkResult) }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>健康码状态</label>
</div>
<div class="right">
<span :style="{color: info.healthCode === '0' || info.healthCode === '1' ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicHealthCode', info.healthCode) }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>已接种疫苗次数</label>
</div>
<div class="right">
<span>{{ $dict.getLabel('epidemicVaccineTime', info.vaccine) }}</span>
</div>
</div>
<div class="detail-info__item detail-info__item--img">
<div class="left">
<label>本人健康码截图</label>
</div>
<div class="right">
<image :src="item.url" @click="preview(item.url)" v-for="(item, index) in info.checkPhoto" :key="index" />
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
info: {},
pageShow: false
}
},
onLoad (query) {
this.$loading()
this.$dict.load(['epidemicTouchInFourteen', 'epidemicRecentHealth', 'epidemicRecentTestResult', 'epidemicHealthCode', 'epidemicVaccineTime']).then(() => {
this.getInfo(query.id)
})
},
methods: {
preview (url) {
uni.previewImage({
urls: this.info.checkPhoto.map(v => v.url),
current: url
})
},
getInfo (id) {
this.$instance.post(`/app/appepidemichealthreport/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.info = res.data
this.info.checkPhoto = JSON.parse(res.data.checkPhoto)
let healthName = ''
this.info.isHealth = false
res.data.health.split(',').forEach(v => {
if (v > 0) {
this.info.isHealth = true
}
healthName = healthName + this.$dict.getLabel('epidemicRecentHealth', v)
})
this.info.healthName = healthName
this.$nextTick(() => {
this.pageShow = true
})
}
this.$hideLoading()
})
},
call (phone) {
uni.makePhoneCall({
phoneNumber: phone
})
}
}
}
</script>
<style lang="scss">
.detail {
padding-bottom: 40px;
.detail-header {
padding: 32px;
background: #fff;
h2 {
margin-bottom: 32px;
color: #333333;
font-size: 40px;
font-weight: 600;
}
.item-info {
.item-info__item {
display: flex;
align-items: center;
margin-bottom: 8px;
&:last-child {
margin-bottom: 0;
}
image {
width: 32px;
height: 32px;
margin-right: 16px;
}
span {
color: #333;
font-size: 28px;
}
}
}
}
.detail-info {
margin-top: 24px;
padding: 0 32px;
background: #fff;
& > h2 {
height: 116px;
line-height: 116px;
font-size: 38px;
font-weight: 600;
color: #333;
}
.detail-info__item {
display: flex;
justify-content: space-between;
padding: 34px 0;
border-bottom: 1px solid #DDDDDD;
&:last-child {
border: none;
}
.left {
display: flex;
line-height: 1.3;
max-width: 360px;
label {
position: relative;
color: #999999;
font-size: 32px;
}
}
.right {
display: flex;
max-width: 450px;
span {
color: #333333;
font-size: 32px;
text-align: right;
}
image {
width: 40px;
height: 40px;
}
}
}
.detail-info__item--img {
display: block;
.right {
flex-wrap: wrap;
max-width: 100%;
margin-top: 34px;
image {
width: 226px;
height: 226px;
margin: 0 9px 9px 0;
&:nth-of-type(3n) {
margin-right: 0;
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,114 @@
<template>
<div class="record" v-if="pageShow">
<div class="record-item" v-for="(item, index) in list" :key="index" @click="$linkTo('./Detail?id=' + item.id)" hover-class="bg-hover">
<div class="left">{{ item.createTime.split(' ')[0] }}的健康上报</div>
<div class="right">
<i v-if="item.status === '0'">健康数据异常</i>
<u-icon name="arrow-right" color="#ddd"/>
</div>
</div>
<AiEmpty v-if="!list.length && isMore"></AiEmpty>
</div>
</template>
<script>
export default {
data () {
return {
list: [],
pageShow: false,
current: 1,
total: 0,
isMore: false
}
},
onLoad (query) {
this.$loading()
this.getList(query)
},
methods: {
getList(query) {
if (this.isMore) return
this.$instance.post(`/app/appepidemichealthreport/list?memberId=${query.id}`, null, {
params: {
current: this.current,
size: 15
}
}).then(res => {
if (res.code == 0) {
this.total = res.data.total
if (this.current > 1) {
this.list = [...this.list, ...res.data.records]
} else {
this.list = res.data.records
}
uni.hideLoading()
this.pageShow = true
if (res.data.records.length < 15) {
this.isMore = true
return false
}
this.current = this.current + 1
} else {
uni.hideLoading()
}
}).catch(() => {
uni.hideLoading()
})
}
},
onReachBottom() {
this.getList()
}
}
</script>
<style lang="scss">
.record {
padding: 32px 0;
.record-item {
display: flex;
align-items: center;
justify-content: space-between;
width: 686px;
height: 112px;
margin: 0 auto 24px;
padding: 0 28px 0 32px;
background: #FFFFFF;
box-sizing: border-box;
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.02);
border-radius: 16px;
.left {
color: #333333;
font-size: 32px;
font-weight: 600;
}
.right {
i {
width: 158px;
height: 36px;
line-height: 36px;
margin-right: 8px;
text-align: center;
font-size: 26px;
color: #FF4466;
background: #FFF5F7;
}
}
& > div {
display: flex;
align-items: center;
}
}
}
</style>

View File

@@ -0,0 +1,83 @@
<template>
<div class="result">
<image src="/static/img/result.png" />
<h2>添加成功</h2>
<div class="result-btn" hover-class="text-hover" @click="toReport">上报今日状态</div>
<div class="result-backBtn" @click="back">返回</div>
</div>
</template>
<script>
export default {
data () {
return {
id: ''
}
},
onLoad (query) {
this.id = query.id
},
methods: {
back () {
uni.navigateBack({
delta: 1
})
},
toReport () {
uni.redirectTo({
url: `./AddReport?id=${this.id}`
})
}
}
}
</script>
<style lang="scss">
.result {
min-height: 100vh;
padding-top: 160px;
box-sizing: border-box;
text-align: center;
background: #fff;
image {
width: 220px;
height: 220px;
}
.result-backBtn {
width: 320px;
height: 88px;
line-height: 88px;
margin: 32px auto 0;
text-align: center;
border: 1px solid #4181FF;
color: #4181FF;
font-size: 34px;
box-sizing: border-box;
border-radius: 16px;
}
h2 {
margin: 32px 0 80px;
font-weight: 600;
font-size: 40px;
color: #333;
}
.result-btn {
width: 320px;
height: 88px;
line-height: 88px;
margin: 0 auto;
text-align: center;
background: #4181FF;
color: #fff;
font-size: 34px;
border-radius: 16px;
}
}
</style>

View File

@@ -0,0 +1,133 @@
<template>
<div class="userinfo" v-if="pageShow">
<div class="cell-group">
<div class="cell-item">
<div class="cell-item__wrapper">
<div class="left">
<span>上报人姓名</span>
</div>
<div class="right">
<span>{{ info.name }}</span>
</div>
</div>
</div>
<div class="cell-item">
<div class="cell-item__wrapper">
<div class="left">
<span>身份证号</span>
</div>
<div class="right">
<span>{{ info.idNumber }}</span>
</div>
</div>
</div>
<div class="cell-item">
<div class="cell-item__wrapper">
<div class="left">
<span>手机号码</span>
</div>
<div class="right">
<span>{{ info.phone }}</span>
</div>
</div>
</div>
<div class="cell-item">
<div class="cell-item__wrapper">
<div class="left">
<span>所属地区</span>
</div>
<div class="right">
<span>{{ info.areaName }}</span>
</div>
</div>
</div>
<div class="cell-item">
<div class="cell-item__wrapper">
<div class="left">
<span>详细地址</span>
</div>
<div class="right">
<span>{{ info.address }}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
info: {},
pageShow: false
}
},
onLoad (query) {
this.$loading()
this.getInfo(query.id)
},
methods: {
getInfo (id) {
this.$instance.post(`/app/appepidemicreportmember/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.info = res.data
if (res.data.eventStatus > 1) {
this.result = res.data.processList[0]
}
this.$nextTick(() => {
this.pageShow = true
})
}
this.$hideLoading()
}).catch(() => {
this.$hideLoading()
})
}
}
}
</script>
<style lang="scss">
.userinfo {
.cell-group {
background: #fff;
.cell-item {
padding-left: 32px;
.cell-item__wrapper {
display: flex;
justify-content: space-between;
padding: 34px 32px 34px 0;
border-bottom: 1px solid #DDDDDD;
.left {
span {
color: #999999;
font-size: 32px;
}
}
.right {
max-width: 450px;
text-align: right;
span {
color: #333333;
font-size: 32px;
}
}
}
&:last-child {
.cell-item__wrapper {
border-bottom: none;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,206 @@
<template>
<div class="photo-list">
<div class="photo-list__wrapper">
<div class="photo-item" v-for="(item, index) in list" :key="index" hover-class="bg-hover" @click="$linkTo('./PhotoDetail?id=' + item.id)">
<div class="photo-item__top">
<h2>{{ item.content }}</h2>
<div class="photo-item__top--info">
<div class="photo-item__top--info-item">
<label>事件类型</label>
<span>{{ item.groupName }}</span>
</div>
<div class="photo-item__top--info-item">
<label>所属网格</label>
<span>{{ item.girdName }}</span>
</div>
</div>
</div>
<div class="photo-item__bottom">
<i :class="'status-' + item.eventStatus"></i>
<span :class="'status-' + item.eventStatus">{{ item.statusName }}</span>
</div>
</div>
<AiEmpty v-if="!list.length"></AiEmpty>
</div>
<div class="btn-wrapper">
<div class="btn" @click="toReport" hover-class="text-hover">我要上报</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name:"AppPhotoReport",
appName:"随手拍",
data () {
return {
list: [],
pageShow: false,
current: 1,
total: 0,
isMore: false
}
},
computed: {
...mapState(['user'])
},
onLoad () {
this.$loading()
this.$dict.load(['clapEventStatus']).then(() => {
this.getList()
})
uni.$on('update', () => {
this.current = 1
this.isMore = false
this.getList()
})
},
methods: {
toReport () {
this.$linkTo('./PhotoForm')
},
getList() {
if (this.isMore) return
this.$instance.post(`/app/appclapeventinfo/listByWxApplet`, null, {
params: {
current: this.current,
size: 15
}
}).then(res => {
if (res.code == 0) {
this.total = res.data.total
if (this.current > 1) {
this.list = [...this.list, ...res.data.records].map(v => {
return {
...v,
statusName: this.$dict.getLabel('clapEventStatus', v.eventStatus)
}
})
} else {
this.list = res.data.records.map(v => {
return {
...v,
statusName: this.$dict.getLabel('clapEventStatus', v.eventStatus)
}
})
}
uni.hideLoading()
this.pageShow = true
if (res.data.records.length < 15) {
this.isMore = true
return false
}
this.current = this.current + 1
} else {
uni.hideLoading()
}
}).catch(() => {
uni.hideLoading()
})
}
},
onReachBottom() {
this.getList()
}
}
</script>
<style lang="scss">
.photo-list {
padding: 24px 0 150px 0;
.photo-item {
width: 686px;
margin: 0 auto 24px;
background: #FFFFFF;
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.02);
border-radius: 16px;
.photo-item__top {
padding: 32px;
text-align: justify;
h2 {
margin-bottom: 32px;
line-height: 1.4;
color: #333333;
font-size: 32px;
font-weight: 600;
overflow : hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.photo-item__top--info-item {
display: flex;
align-items: center;
&:last-child {
margin-bottom: 8px;
}
label {
margin-right: 32px;
color: #999999;
font-size: 26px;
}
span {
color: #333333;
font-size: 26px;
}
}
}
.photo-item__bottom {
display: flex;
align-items: center;
height: 104px;
padding: 0 32px;
border-top: 1px solid #DDDDDD;
i {
width: 8px;
height: 8px;
margin-right: 8px;
border-radius: 50%;
background: #FF883C;
}
span {
color: #FF883C;
font-size: 28px;
background: transparent!important;
}
.status-1 {
color: #1AAAFF;
background: #1AAAFF;
}
.status-2 {
color: #42D784;
background: #42D784;
}
.status-3 {
color: #FF4466;
background: #FF4466;
}
}
}
}
</style>

View File

@@ -0,0 +1,205 @@
<template>
<div class="photo-detail" v-if="pageShow">
<h2>{{ info.content }}</h2>
<div class="status-name" :class="'status-' + info.eventStatus">{{ $dict.getLabel('clapEventStatus', info.eventStatus) }}</div>
<div class="photo-detail__info">
<div class="photo-detail__item">
<i>事件类型</i>
<span>{{ info.groupName }}</span>
</div>
<div class="photo-detail__item">
<i>所属网格</i>
<span>{{ info.girdName }}</span>
</div>
<div class="photo-detail__item">
<i>上报时间</i>
<span>{{ info.createTime }}</span>
</div>
<div class="photo-detail__img" style="border: none;">
<i>照片</i>
<div class="photo-detail__img--imgs">
<image v-for="(item, index) in info.files" @click="preview(item.url)" :key="index" :src="item.url" />
</div>
<span v-if="info.files && !info.files.length">暂无照片</span>
</div>
</div>
<div class="result" v-if="info.eventStatus > 1">
<h2>处理详情</h2>
<div class="result-info">
<h2>处理结果</h2>
<p>{{ result.doExplain || '-' }}</p>
</div>
<div class="photo-detail__img" v-if="result.files.length">
<i>照片</i>
<div class="photo-detail__img--imgs">
<image @click="previewResult(item.url)" v-for="(item, index) in result.files" :key="index" :src="item.url" />
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
pageShow: false,
info: {},
result: {}
}
},
onLoad (query) {
this.$loading()
this.$dict.load(['clapEventStatus']).then(() => {
this.getInfo(query.id)
})
},
methods: {
getInfo (id) {
this.$instance.post(`/app/appclapeventinfo/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.info = res.data
if (res.data.eventStatus > 1) {
this.result = res.data.processList[0]
}
this.$nextTick(() => {
this.pageShow = true
})
}
this.$hideLoading()
}).catch(() => {
this.$hideLoading()
})
},
previewResult (url) {
uni.previewImage({
urls: this.result.files.map(v => v.url),
current: url
})
},
preview (url) {
uni.previewImage({
urls: this.info.files.map(v => v.url),
current: url
})
}
}
}
</script>
<style lang="scss">
.photo-detail {
padding: 32px;
margin-bottom: 60px;
background: #fff;
& > h2 {
line-height: 1.3;
margin-bottom: 26px;
color: #333333;
text-align: justify;
font-size: 40px;
}
.status-name {
width: 96px;
height: 44px;
line-height: 44px;
margin-bottom: 20px;
text-align: center;
background: #FF883C;
color: #fff;
font-size: 26px;
border-radius: 8px;
&.status-1 {
background: #1AAAFF;
}
&.status-2 {
background: #42D784;
}
&.status-3 {
background: #FF4466;
}
}
.photo-detail__item {
display: flex;
align-items: center;
justify-content: space-between;
height: 112px;
font-size: 32px;
border-bottom: 1px solid #DDDDDD;
i {
color: #999999;
font-size: 32px;
}
span {
color: #333333;
}
}
.result {
& > h2 {
height: 116px;
line-height: 116px;
font-size: 38px;
color: #333;
font-weight: 600;
border-top: 1px solid #DDDDDD;
}
.result-info {
h2 {
height: 112px;
line-height: 112px;
color: #999999;
font-size: 32px;
}
p {
line-height: 1.3;
padding-bottom: 32px;
color: #333333;
font-size: 32px;
}
}
}
.photo-detail__img {
border-top: 1px solid #DDDDDD;
padding: 32px 0;
& > i {
display: block;
margin-bottom: 32px;
color: #999999;
font-size: 32px;
}
.photo-detail__img--imgs {
display: flex;
flex-wrap: wrap;
image {
width: 226px;
height: 226px;
margin: 0 9px 9px 0;
&:nth-of-type(3n) {
margin-right: 0;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,384 @@
<template>
<div class="album">
<div class="form-item__group">
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>事件类型</h2>
</div>
<div class="form-item__right">
<ai-select :list="dictList" v-model="form.groupId"></ai-select>
</div>
</div>
</div>
<div class="form-item form-item__textarea">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>事件描述</h2>
</div>
<div class="form-item__right">
<textarea v-model="form.content" :maxlength="500" placeholder="请简要描述事件…"></textarea>
<!-- <u-input style="width: 100%;" :height="200" v-model="value" type="textarea" :maxlength="500" :border="border" placeholder="请简要描述事件…" /> -->
</div>
</div>
</div>
</div>
<div class="form-item__group">
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>上报位置</h2>
</div>
<div class="form-item__right" @click="chooseAddress">
<span v-if="form.address">{{ form.address }}</span>
<i v-else>请选择</i>
<u-icon name="arrow-right" color="#ddd" />
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>所属网格</h2>
</div>
<picker :range="gridList" mode="multiSelector" range-key="girdName" @columnchange="onColumnChange" @change="onChange">
<div class="form-item__right">
<span v-if="form.girdName">{{ form.girdName }}</span>
<i v-else>请选择</i>
<u-icon name="arrow-right" color="#ddd" />
</div>
</picker>
</div>
</div>
</div>
<div class="form-item__group">
<div class="form-item form-item__imgs">
<div class="form-item__wrapper">
<div class="form-item__title">
<i style="opacity: 0;">*</i>
<h2>图片上传</h2>
<span>(最多9张)</span>
</div>
<div class="form-item__right">
<ai-uploader v-model="form.files" :limit="9"></ai-uploader>
</div>
</div>
</div>
</div>
<div class="form-item__group">
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>姓名</h2>
</div>
<div class="form-item__right">
<input placeholder="请输入" v-model="form.name" :maxlength="20" />
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>联系方式</h2>
</div>
<div class="form-item__right">
<input placeholder="请输入" v-model="form.phone" :maxlength="20" />
</div>
</div>
</div>
</div>
<div class="btn-wrapper">
<div class="btn" hover-class="text-hover" @click="submit">提交</div>
</div>
</div>
</template>
<script>
import AiUploader from '@/components/AiUploader/AiUploader'
import AiSelect from '@/components/AiSelect/AiSelect'
import { mapState } from 'vuex'
export default {
data () {
return {
isShowType: false,
form: {
content: '',
lat: '',
lng: '',
address: '',
name: '',
phone: '',
groupId: '',
groupName: '',
girdName: '',
girdId: '',
files: []
},
dictList: [],
arr: [],
gridList: [[], []],
flag: false
}
},
components: {
AiSelect,
AiUploader
},
computed: {
...mapState(['user'])
},
onLoad () {
this.getDict()
this.form.phone = this.user.phone
this.form.name = this.user.realName || ''
this.getGirdList()
},
methods: {
chooseAddress () {
uni.authorize({
scope: 'scope.userLocation',
success: () => {
uni.chooseLocation({
success: res => {
this.form.address = res.address
this.form.lat = res.latitude
this.form.lng = res.longitude
}
})
},
fail: () => {
this.$dialog.confirm({
content: '您未授权定位权限,无法选择位置'
}).then(() => {
wx.openSetting({
success: res => {
if (!res.authSetting['scope.userLocation']) {
this.$dialog.alert({
content: '您未授权定位权限,无法选择位置'
}).then(() => {
})
} else {
console.log('设置定位权限')
}
}
})
})
}
})
},
getDict () {
this.$instance.post(`/app/appclapeventgroup/list?current=1&size=100000`).then(res => {
if (res.code == 0) {
this.dictList = res.data.records.map(v => {
return {
value: v.id,
label: v.groupName
}
})
}
})
},
getGirdData (x) {
if (x > -1) {
this.$set(this.gridList, '1', this.arr[0].girdList[x].girdList)
}
},
getGirdList () {
this.$instance.post(`/app/appgirdinfo/listAllByTop`).then(res => {
if (res.code == 0) {
this.arr = res.data
this.gridList[0] = res.data[0].girdList
this.gridList[1] = res.data[0].girdList[0].girdList
}
})
},
onColumnChange (e) {
const column = e.detail.column
const value = e.detail.value
if (column === column) {
this.getGirdData(value)
}
},
onChange (e) {
console.log(e)
const v = e.detail.value[1]
console.log(v)
if (this.gridList[1][v]) {
this.form.girdName = this.gridList[1][v].girdName
this.form.girdId = this.gridList[1][v].id
} else {
return this.$toast('所属网格必须选第三级网格')
// this.form.girdName = this.gridList[e.detail.value[0].girdName
// this.form.girdId = this.gridList[e.detail.value[0].id
}
},
submit () {
if (!this.form.groupId) {
return this.$toast('请选择事件类型')
}
if (!this.form.content) {
return this.$toast('请输入事件描述')
}
if (!this.form.address) {
return this.$toast('请选择上报位置')
}
if (!this.form.girdName) {
return this.$toast('请选择所属网格')
}
if (!this.form.name) {
return this.$toast('请输入上报人姓名')
}
if (!this.form.girdName) {
return this.$toast('请输入上报人联系方式')
}
if(this.flag) return
this.flag = true
this.$loading()
this.$instance.post(`/app/appclapeventinfo/addOrUpdate`, {
...this.form,
openid: this.user.openid,
portrait: this.user.avatarUrl,
files: this.form.files,
groupName: this.dictList.filter(v => v.value === this.form.groupId)[0].label
}).then(res => {
this.$hideLoading()
this.flag = false
if (res.code == 0) {
uni.$emit('update')
setTimeout(() => {
uni.redirectTo({
url: './PhotoResult?id=' + res.data.id
})
}, 400)
}
this.$hideLoading()
})
}
}
}
</script>
<style lang="scss">
.album {
padding-bottom: 140px;
.form-item__group {
margin-bottom: 24px;
background: #fff;
}
.form-item {
padding-left: 32px;
.form-item__wrapper {
display: flex;
align-items: center;
justify-content: space-between;
height: 128px;
padding-right: 28px;
border-bottom: 1px solid #DDDDDD;
input {
flex: 1;
height: 100%;
text-align: right;
padding-right: 10px;
}
.form-item__right {
display: flex;
align-items: center;
font-size: 32px;
span {
max-width: 400px;
margin-right: 8px;
color: #333333;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
i {
margin-right: 8px;
color: #999999;
}
}
}
&:last-child {
.form-item__wrapper {
border-bottom: none;
}
}
.form-item__title {
display: flex;
align-items: center;
i {
font-size: 32px;
color: #FF4466;
}
span {
font-size: 28px;
color: #999999;
}
h2 {
padding: 0 4px;
font-weight: 600;
font-size: 32px;
color: #333333;
}
}
&.form-item__imgs, &.form-item__textarea {
.form-item__wrapper {
display: block;
height: auto;
padding-bottom: 32px;
}
textarea {
width: 100%;
height: 160px;
}
.form-item__title {
padding: 32px 0;
}
.form-item__right {
padding-left: 18px;
}
}
}
}
</style>

View File

@@ -0,0 +1,63 @@
<template>
<div class="result">
<image src="/static/img/result.png" />
<h2>上报成功</h2>
<div class="result-btn" hover-class="text-hover" @click="back">前往查看</div>
</div>
</template>
<script>
export default {
data () {
return {
id: ''
}
},
onLoad (query) {
this.id = query.id
},
methods: {
back () {
uni.redirectTo({
url: './PhotoDetail?id=' + this.id
})
}
}
}
</script>
<style lang="scss">
.result {
min-height: 100vh;
padding-top: 160px;
box-sizing: border-box;
text-align: center;
background: #fff;
image {
width: 220px;
height: 220px;
}
h2 {
margin: 32px 0 80px;
font-weight: 600;
font-size: 40px;
color: #333;
}
.result-btn {
width: 320px;
height: 88px;
line-height: 88px;
margin: 0 auto;
text-align: center;
background: #4181FF;
color: #fff;
font-size: 34px;
border-radius: 16px;
}
}
</style>

View File

@@ -0,0 +1,642 @@
<template>
<div class="album">
<div class="tips">请确保以下信息全部由本人填写本人对所填写内容的真实性和完整性负责</div>
<div class="form-item__group">
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>返乡人员姓名</h2>
</div>
<div class="form-item__right">
<input placeholder="请输入" v-model="form.name" :maxlength="20" />
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>身份证号</h2>
</div>
<div class="form-item__right">
<input placeholder="请输入" type="idcard" v-model="form.idNumber" :maxlength="20" />
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>手机号码</h2>
</div>
<div class="form-item__right">
<input placeholder="请输入" type="number" v-model="form.phone" :maxlength="11" />
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>人员类别</h2>
</div>
<div class="form-item__right">
<ai-select v-model="form.type" dict="epidemicRecentPersonType" class="select"></ai-select>
</div>
</div>
</div>
</div>
<div class="form-item__group">
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>出行方式</h2>
</div>
<div class="form-item__right">
<ai-select dict="epidemicRecentTravel" v-model="form.travelType" class="select"></ai-select>
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>出发时间</h2>
</div>
<div class="form-item__right">
<div class="ai-area" @click="isShowStartTime = true">
<div class="ai-area__wrapper">
<span class="label" v-if="form.startTime">{{ form.startTime }}</span>
<i v-else>请选择</i>
<u-icon name="arrow-right" color="#ddd"/>
</div>
</div>
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>出发地区</h2>
</div>
<div class="form-item__right">
<ai-area-picker ref="area" class="ai-area" :value="form.startAreaId" :fullName.sync="form.startAreaName" all mode="custom" @select="v => form.startAreaId = v">
<div class="ai-area__wrapper">
<span class="label" v-if="form.startAreaName">{{ form.startAreaName }}</span>
<i v-else>请选择</i>
<u-icon name="arrow-right" color="#ddd"/>
</div>
</ai-area-picker>
</div>
</div>
</div>
<div class="form-item form-item__textarea">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>出发地址</h2>
</div>
<div class="form-item__right">
<textarea auto-height v-model="form.startAddress" :maxlength="500" placeholder="请输入详细的出发地址" placeholder-style="font-size: 16px"></textarea>
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>到达时间</h2>
</div>
<div class="form-item__right">
<div class="ai-area" @click="isShowEndTime = true">
<div class="ai-area__wrapper">
<span class="label" v-if="form.arriveTime">{{ form.arriveTime }}</span>
<i v-else>请选择</i>
<u-icon name="arrow-right" color="#ddd"/>
</div>
</div>
</div>
</div>
</div>
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>到达地区</h2>
</div>
<div class="form-item__right">
<ai-area-picker
ref="area"
class="ai-area"
:value="form.arriveAreaId"
:fullName.sync="form.arriveAreaName"
:areaId="$areaId"
mode="custom" @select="v => form.arriveAreaId = v">
<div class="ai-area__wrapper">
<span class="label" v-if="form.arriveAreaName">{{ form.arriveAreaName }}</span>
<i v-else>请选择</i>
<u-icon name="arrow-right" color="#ddd"/>
</div>
</ai-area-picker>
</div>
</div>
</div>
<div class="form-item form-item__textarea">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>返乡地址</h2>
</div>
<div class="form-item__right">
<textarea auto-height v-model="form.arriveAddress" :maxlength="500" placeholder="请输入详细的返乡地址" placeholder-style="font-size: 16px"></textarea>
</div>
</div>
</div>
<div class="form-item form-item__textarea">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>行程描述</h2>
</div>
<div class="form-item__right">
<textarea auto-height style="height: 90px" v-model="form.description" :maxlength="500" placeholder="请输入行程描述" placeholder-style="font-size: 16px"></textarea>
</div>
</div>
</div>
</div>
<div class="form-item__group">
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>核酸检测日期</h2>
</div>
<div class="form-item__right">
<div class="ai-area" @click="isShowDate = true">
<div class="ai-area__wrapper">
<span class="label" v-if="form.checkTime">{{ form.checkTime }}</span>
<i v-else>请选择</i>
<u-icon name="arrow-right" color="#ddd"/>
</div>
</div>
</div>
</div>
</div>
<div class="form-item form-item__imgs">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>本人健康码截图或核酸检测报告</h2>
</div>
<div class="form-item__right">
<ai-uploader v-model="form.checkPhoto" :limit="1"></ai-uploader>
</div>
</div>
</div>
<div class="form-item form-item__imgs">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>核酸检测结果</h2>
</div>
<div class="form-item__right">
<ai-radio style="width: 100%;" v-model="form.checkResult" dict="epidemicRecentTestResult"></ai-radio>
</div>
</div>
</div>
</div>
<div class="form-item__group">
<div class="form-item">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>当前体温</h2>
</div>
<div class="form-item__right">
<input placeholder="请输入" v-model="form.temperature" :maxlength="20" />
<i></i>
</div>
</div>
</div>
<div class="form-item form-item__imgs">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>14天内是否接触新冠确诊或疑似患者</h2>
</div>
<div class="form-item__right">
<ai-radio style="width: 100%;" v-model="form.touchInFourteen" dict="epidemicTouchInFourteen"></ai-radio>
</div>
</div>
</div>
<div class="form-item form-item__imgs">
<div class="form-item__wrapper">
<div class="form-item__title">
<i>*</i>
<h2>当前健康状况可多选</h2>
</div>
<div class="form-item__right">
<ai-checkbox style="width: 100%;" v-model="form.health" dict="epidemicRecentHealth"></ai-checkbox>
</div>
</div>
</div>
</div>
<u-picker mode="time" :params="dataParams" v-model="isShowDate" @confirm="onDateChange"></u-picker>
<u-picker mode="time" :params="params" v-model="isShowStartTime" @confirm="onStartChange"></u-picker>
<u-picker mode="time" :params="params" v-model="isShowEndTime" @confirm="onEndChange"></u-picker>
<div class="btn-wrapper">
<div class="btn" hover-class="text-hover" @click="submit">提交</div>
</div>
</div>
</template>
<script>
import AiUploader from '@/components/AiUploader/AiUploader'
import AiSelect from '@/components/AiSelect/AiSelect'
import { mapState } from 'vuex'
export default {
data () {
return {
isShowType: false,
isShowEndTime: false,
isShowStartTime: false,
isShowDate: false,
params: {
year: true,
month: true,
day: true,
hour: true,
minute: true
},
dataParams: {
year: true,
month: true,
day: true
},
form: {
arriveAddress: '',
arriveAreaId: '',
arriveAreaName: '',
arriveTime: '',
checkPhoto: [],
checkResult: '',
checkTime: '',
description: '',
health: [],
idNumber: '',
name: '',
phone: '',
startAddress: '',
startAreaId: '',
startAreaName: '',
startTime: '',
temperature: '',
touchInFourteen: '',
travelType: '',
type: '',
unusual: '',
},
dictList: [],
arr: [],
gridList: [[], [], []],
flag: false,
$areaId: ''
}
},
components: {
AiSelect,
AiUploader
},
computed: {
...mapState(['user'])
},
onLoad () {
this.$areaId = this.user.$areaId
},
methods: {
onDateChange (e) {
this.form.checkTime = `${e.year}-${e.month}-${e.day}`
},
onStartChange (e) {
this.form.startTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}`
},
onEndChange (e) {
this.form.arriveTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}`
},
submit () {
if (!this.form.name) {
return this.$toast('请输入返乡人员姓名')
}
if (!this.form.idNumber) {
return this.$toast('请输入返乡人员身份证号')
}
if (!/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(this.form.idNumber)) {
return this.$toast('请输入正确的身份证账号')
}
if (!this.form.phone) {
return this.$toast('请输入返乡人员手机号码')
}
if (!/^1[0-9]{10,10}$/.test(this.form.phone)) {
return this.$toast('请输入正确的手机号码')
}
if (!this.form.type) {
return this.$toast('请选择人员类别')
}
if (!this.form.travelType) {
return this.$toast('请选择出行方式')
}
if (!this.form.startTime) {
return this.$toast('请选择出发时间')
}
if (new Date(this.form.startTime.replace(/-/g, '/')).getTime() > new Date().getTime()) {
return this.$toast('出发时间不得晚于当前时间')
}
if (!this.form.startAreaName) {
return this.$toast('请选择出发地区')
}
if (this.form.startAreaId.substr(this.form.startAreaId.length - 3, 3) === '000') {
return this.$toast('出发地区必须选到村或社区')
}
if (!this.form.startAddress) {
return this.$toast('请输入出发详细地址')
}
if (!this.form.arriveTime) {
return this.$toast('请选择到达时间')
}
if (new Date(this.form.startTime.replace(/-/g, '/')).getTime() >= new Date(this.form.arriveTime.replace(/-/g, '/')).getTime()) {
return this.$toast('到达时间不得早于出发时间')
}
if (!this.form.arriveAreaName) {
return this.$toast('请选择到达地区')
}
if (this.form.arriveAreaId.substr(this.form.arriveAreaId.length - 3, 3) === '000') {
return this.$toast('到达地区必须选到村或社区')
}
if (!this.form.arriveAddress) {
return this.$toast('请输入返乡地址')
}
if (!this.form.description) {
return this.$toast('请输入行程描述')
}
if (!this.form.checkTime) {
return this.$toast('请选择核酸检测日期')
}
if (!this.form.checkPhoto.length) {
return this.$toast('请上传本人健康码截图或核酸检测报告')
}
if (!this.form.checkResult) {
return this.$toast('请选择核酸检测结果')
}
if (!this.form.temperature) {
return this.$toast('请输入当前体温')
}
if (!this.form.touchInFourteen) {
return this.$toast('请选择14天内是否接触新冠确诊或疑似患者')
}
if (!this.form.health.length) {
return this.$toast('请选择当前健康状况')
}
if (this.flag) return
this.flag = true
this.$loading()
this.$instance.post(`/app/appepidemicbackhomerecord/addOrUpdate`, {
...this.form,
openid: this.user.openid,
startTime: this.form.startTime + ':00',
arriveTime: this.form.arriveTime + ':00',
checkTime: this.form.checkTime + ' 00:00:00',
health: this.form.health.join(','),
checkPhoto: JSON.stringify(this.form.checkPhoto)
}).then(res => {
this.$hideLoading()
this.flag = false
if (res.code == 0) {
uni.$emit('update')
this.$toast('提交成功')
setTimeout(() => {
uni.navigateBack()
}, 400)
}
})
}
}
}
</script>
<style lang="scss">
.album {
padding-bottom: 140px;
.tips {
line-height: 1.3;
padding: 32px 32px;
color: #FF883C;
font-size: 30px;
text-align: justify;
background: #FFF8F3;
}
.form-item__group {
margin-bottom: 24px;
background: #fff;
}
.form-item {
padding-left: 32px;
.form-item__checkbox {
width: 100%;
div {
width: 100%;
height: 80px;
line-height: 80px;
margin-bottom: 24px;
text-align: center;
background: #FFFFFF;
border-radius: 16px;
color: #333333;
font-size: 28px;
border: 1px solid #CCCCCC;
&.active {
background: #4181FF;
color: #fff;
border-color: #4181FF;
}
}
}
.form-item__radio {
display: flex;
align-items: center;
flex-wrap: wrap;
div {
width: 212px;
height: 80px;
line-height: 80px;
margin-right: 16px;
margin-bottom: 8px;
text-align: center;
background: #FFFFFF;
border-radius: 16px;
color: #333333;
font-size: 28px;
border: 1px solid #CCCCCC;
&:nth-of-type(3n) {
margin-right: 0;
}
&.active {
background: #4181FF;
color: #fff;
border-color: #4181FF;
}
}
}
.ai-area__wrapper {
display: flex;
align-items: center;
padding-left: 100px;
span {
color: #333;
font-size: 30px;
}
i {
color: #999;
font-size: 30px;
}
image {
width: 16px;
height: 8px;
}
}
.form-item__wrapper {
display: flex;
align-items: center;
justify-content: space-between;
height: 128px;
padding-right: 28px;
border-bottom: 1px solid #DDDDDD;
input {
flex: 1;
height: 100%;
text-align: right;
color: #333;
padding-right: 10px;
}
.form-item__right {
display: flex;
align-items: center;
font-size: 32px;
.select {
._i {
padding-left: 100px;
}
}
span {
max-width: 400px;
margin-right: 8px;
color: #333333;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
i {
margin-right: 8px;
color: #999999;
}
}
}
&:last-child {
.form-item__wrapper {
border-bottom: none;
}
}
.form-item__title {
display: flex;
align-items: center;
i {
font-size: 32px;
color: #FF4466;
}
span {
font-size: 28px;
color: #999999;
}
h2 {
padding: 0 4px;
font-weight: 600;
font-size: 32px;
color: #333333;
}
}
&.form-item__imgs, &.form-item__textarea {
.form-item__wrapper {
display: block;
height: auto;
padding-bottom: 32px;
}
textarea {
width: 100%;
height: 90px;
}
.form-item__title {
padding: 32px 0;
}
.form-item__right {
padding-left: 18px;
}
}
}
}
</style>

View File

@@ -0,0 +1,214 @@
<template>
<div class="returnHomeRegister" v-if="pageShow">
<div class="title">
<h2>全部记录</h2>
<div class="right">
<span></span>
<i>{{ total }}</i>
<span></span>
</div>
</div>
<div class="home-list">
<div class="item" hover-class="bg-hover" @click="$linkTo(`./Detail?id=${item.id}`)"
v-for="(item, index) in list" :key="index">
<div class="item-top">
<h2>{{ item.name }}</h2>
<span v-if="item.status === '0'">有异常情况</span>
</div>
<p>{{ item.idNumber.replace(/^(\d{6})\d{8}(.{4}$)/g, `$1${Array(9).join('*')}$2`) }}</p>
<div class="item-info">
<div class="item-info__item">
<image src="/static/img/from-icon.png"/>
<span>{{ item.startAreaName }}</span>
</div>
<div class="item-info__item">
<image src="/static/img/to-icon.png"/>
<span>{{ item.arriveAreaName }}</span>
</div>
<div class="item-info__item">
<image src="/static/img/to-date.png"/>
<span>{{ item.arriveTime && item.arriveTime.substr(0, item.arriveTime.length - 3) }} 到达</span>
</div>
</div>
</div>
<AiEmpty v-if="!list.length && isMore"></AiEmpty>
</div>
<div class="btn-wrapper">
<div class="btn" @click="toReport" hover-class="text-hover">添加返乡记录</div>
</div>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
name: "AppReturnHomeRegister",
appName: "返乡登记",
data() {
return {
list: [],
pageShow: false,
current: 1,
total: 0,
isMore: false
}
},
computed: {
...mapState(['user'])
},
onLoad() {
this.$loading()
this.$dict.load(['villageActivityStatus']).then(() => {
this.getList()
})
uni.$on('update', () => {
this.current = 1
this.isMore = false
this.$nextTick(() => {
this.getList()
})
})
},
methods: {
toReport() {
this.$linkTo('./Add')
},
getList() {
if (this.isMore) return
this.$instance.post(`/app/appepidemicbackhomerecord/list?openId=${this.user.openId}`, null, {
params: {
current: this.current,
size: 15
}
}).then(res => {
if (res.code == 0) {
this.total = res.data.total
if (this.current > 1) {
this.list = [...this.list, ...res.data.records]
} else {
this.list = res.data.records
}
uni.hideLoading()
this.pageShow = true
if (res.data.records.length < 15) {
this.isMore = true
return false
}
this.current = this.current + 1
} else {
uni.hideLoading()
}
}).catch(() => {
uni.hideLoading()
})
}
},
onReachBottom() {
this.getList()
}
}
</script>
<style lang="scss" socped>
.returnHomeRegister {
padding: 0 0 150px 0;
.title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
padding: 48px 32px 0 32px;
& > h2 {
font-size: 38px;
color: #333;
font-weight: 600;
}
.right {
display: flex;
align-items: center;
span {
color: #666666;
font-size: 28px;
}
i {
color: #4181FF;
font-style: normal;
font-size: 28px;
}
}
}
.item {
margin: 0 32px 24px;
padding: 32px;
border-radius: 16px;
background: #fff;
.item-info {
.item-info__item {
display: flex;
margin-bottom: 8px;
line-height: 1.3;
&:last-child {
margin-bottom: 0;
}
image {
position: relative;
top: 2px;
width: 32px;
height: 32px;
margin-right: 16px;
}
span {
flex: 1;
color: #333;
font-size: 28px;
}
}
}
.item-top {
display: flex;
align-items: center;
justify-content: space-between;
height: 50px;
h2 {
color: #333333;
font-size: 36px;
font-weight: 600;
}
span {
font-size: 28px;
color: #FF4466;
}
}
p {
margin: 14px 0 20px;
color: #999999;
font-size: 28px;
}
}
}
</style>

View File

@@ -0,0 +1,349 @@
<template>
<div class="detail" v-if="pageShow">
<div class="detail-header">
<h2>{{ info.name }}的返乡登记信息</h2>
<div class="item-info">
<div class="item-info__item">
<image src="/static/img/from-icon.png" />
<span>{{ info.startAreaName }}</span>
</div>
<div class="item-info__item">
<image src="/static/img/to-icon.png" />
<span>{{ info.arriveAreaName }}</span>
</div>
<div class="item-info__item">
<image src="/static/img/to-date.png" />
<span>{{ info.arriveTime && info.arriveTime.substr(0, info.arriveTime.length - 3) }} 到达</span>
</div>
</div>
</div>
<div class="detail-info">
<h2>基本信息</h2>
<div class="detail-info__item">
<div class="left">
<label>姓名</label>
</div>
<div class="right">
<span>{{ info.name }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>身份证号</label>
</div>
<div class="right">
<span>{{ info.idNumber }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>手机号码</label>
</div>
<div class="right" @click="call(info.phone)" hover-class="text-hover">
<image src="https://cdn.cunwuyun.cn/dvcp/h5/common/phone.png" />
<span style="color: #4181FF">{{ info.phone }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>人员类别</label>
</div>
<div class="right">
<span :style="{color: info.type === '0' ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicMemberType', info.type) }}</span>
</div>
</div>
</div>
<div class="detail-info">
<h2>行程信息</h2>
<div class="detail-info__item">
<div class="left">
<label>出行方式</label>
</div>
<div class="right">
<span>{{ $dict.getLabel('epidemicRecentTravel', info.travelType) }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>出发时间</label>
</div>
<div class="right">
<span>{{ info.startTime && info.startTime.substr(0, info.startTime.length - 3) }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>出发地区</label>
</div>
<div class="right">
<span :style="{color: info.denger == 1 ? '#FF4466' : '#333'}">{{ info.startAreaName }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>出发地址</label>
</div>
<div class="right">
<span>{{ info.startAddress }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>到达时间</label>
</div>
<div class="right">
<span>{{ info.arriveTime && info.arriveTime.substr(0, info.arriveTime.length - 3) }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>返乡地区</label>
</div>
<div class="right">
<span>{{ info.arriveAreaName }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>返乡地址</label>
</div>
<div class="right">
<span>{{ info.arriveAddress }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>行程描述</label>
</div>
<div class="right">
<span>{{ info.description }}</span>
</div>
</div>
</div>
<div class="detail-info">
<h2>核酸检测信息</h2>
<div class="detail-info__item">
<div class="left">
<label>核酸检测日期</label>
</div>
<div class="right">
<span>{{ info.checkTime.split(' ')[0] }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>核酸检测结果</label>
</div>
<div class="right">
<span :style="{color: info.checkResult === '0' ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicRecentTestResult', info.checkResult) }}</span>
</div>
</div>
<div class="detail-info__item detail-info__item--img">
<div class="left" style="max-width: 100%;">
<label>本人健康码截图或核酸检测报告</label>
</div>
<div class="right">
<image :src="item.url" @click="preview(item.url)" v-for="(item, index) in info.checkPhoto" :key="index" />
</div>
</div>
</div>
<div class="detail-info">
<h2>健康状况</h2>
<div class="detail-info__item">
<div class="left">
<label>当前体温</label>
</div>
<div class="right">
<span :style="{color: info.temperature >= 37.3 ? '#FF4466' : '#42D784'}">{{ info.temperature }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>14天内是否接触新冠确诊或疑似患者</label>
</div>
<div class="right">
<span :style="{color: info.touchInFourteen === '0' ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicTouchInFourteen', info.touchInFourteen) }}</span>
</div>
</div>
<div class="detail-info__item">
<div class="left">
<label>当前健康状况</label>
</div>
<div class="right">
<span :style="{color: !info.isHealth ? '#42D784' : '#FF4466'}">{{ info.healthName }}</span>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
info: {},
pageShow: false
}
},
onLoad (query) {
this.$loading()
this.$dict.load(['epidemicRecentHealth', 'epidemicRecentTravel', 'epidemicTouchInFourteen', 'epidemicMemberType', 'epidemicRecentTestResult']).then(() => {
this.getInfo(query.id)
})
},
methods: {
preview (url) {
uni.previewImage({
urls: this.info.checkPhoto.map(v => v.url),
current: url
})
},
getInfo (id) {
this.$instance.post(`/app/appepidemicbackhomerecord/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.info = res.data
this.info.checkPhoto = JSON.parse(res.data.checkPhoto)
let healthName = ''
this.info.isHealth = false
res.data.health.split(',').forEach(v => {
if (v > 0) {
this.info.isHealth = true
}
healthName = healthName + this.$dict.getLabel('epidemicRecentHealth', v)
})
this.info.healthName = healthName
this.$nextTick(() => {
this.pageShow = true
})
}
this.$hideLoading()
})
},
call (phone) {
uni.makePhoneCall({
phoneNumber: phone
})
}
}
}
</script>
<style lang="scss">
.detail {
padding-bottom: 40px;
.detail-header {
padding: 32px;
background: #fff;
h2 {
margin-bottom: 32px;
color: #333333;
font-size: 40px;
font-weight: 600;
}
.item-info {
.item-info__item {
display: flex;
align-items: center;
margin-bottom: 8px;
&:last-child {
margin-bottom: 0;
}
image {
width: 32px;
height: 32px;
margin-right: 16px;
}
span {
color: #333;
font-size: 28px;
}
}
}
}
.detail-info {
margin-top: 24px;
padding: 0 32px;
background: #fff;
& > h2 {
height: 116px;
line-height: 116px;
font-size: 38px;
font-weight: 600;
color: #333;
}
.detail-info__item {
display: flex;
justify-content: space-between;
padding: 34px 0;
border-bottom: 1px solid #DDDDDD;
&:last-child {
border: none;
}
.left {
display: flex;
line-height: 1.3;
max-width: 360px;
label {
position: relative;
color: #999999;
font-size: 32px;
}
}
.right {
display: flex;
max-width: 450px;
span {
color: #333333;
font-size: 32px;
text-align: right;
}
image {
width: 40px;
height: 40px;
}
}
}
.detail-info__item--img {
display: block;
.right {
flex-wrap: wrap;
max-width: 100%;
margin-top: 34px;
image {
width: 226px;
height: 226px;
margin: 0 9px 9px 0;
&:nth-of-type(3n) {
margin-right: 0;
}
}
}
}
}
}
</style>