迁移视频监控

This commit is contained in:
aixianling
2021-12-16 17:27:39 +08:00
parent 6ed973c0fc
commit 7966b3f9f4
16 changed files with 4 additions and 3327 deletions

View File

@@ -1,17 +1,17 @@
<template>
<section class="videoSurveillance">
<ai-top-fixed>
<AiTopFixed>
<div class="header" flex>
<div flex v-for="(node,i) in nodes" :key="i">
<div :class="{current:isCurrent(i)}" v-text="node.nodeName" @click="gotoNode(node,i)"/>
<u-icon v-if="!isCurrent(i)" name="arrow-right" color="#ddd"/>
</div>
</div>
</ai-top-fixed>
</AiTopFixed>
<div class="list">
<div class="item" v-for="row in monitors" :key="row.nodeId" :class="{online:!row.online}">
<template v-if="!!row.deviceId">
<img src="../resourcesManage/img/video-img.png" alt="" class="videoIcon" @click="showMonitor(row)">
<img src="../../pages/resourcesManage/img/video-img.png" alt="" class="videoIcon" @click="showMonitor(row)">
<div class="area-name" v-text="row.deviceName" @click="showMonitor(row)"/>
<div class="deviceStatus" v-text="!row.online?'在线':'离线'" @click="showMonitor(row)"/>
</template>
@@ -25,11 +25,9 @@
</template>
<script>
import AiTopFixed from "../../components/AiTopFixed";
export default {
name: "videoSurveillance",
components: {AiTopFixed},
appName: "视频监控",
data() {
return {
nodes: [

View File

@@ -8,11 +8,9 @@
</template>
<script>
import AiFixedBtn from "../../components/AiFixedBtn";
export default {
name: "monitorDetail",
components: {AiFixedBtn},
data() {
return {
style: {},

View File

@@ -1,400 +0,0 @@
<template>
<div class="add-meeting">
<div v-if="!userSelect">
<div class="card">
<header><em>*</em>会议标题</header>
<input v-model="form.title" placeholder="请输入" :maxlength="30">
</div>
<div class="card">
<header><em>*</em>起止时间</header>
<u-row justify="between">
<div class="time" @click="pick(0)">
<span>{{ form.startTime.time }}</span>
<span>{{ form.startTime.year }}{{ form.startTime.month }}{{ form.startTime.day }} {{ form.startTime.weekday }}</span>
</div>
<div class="arrow"></div>
<div class="time" @click="pick(1)">
<span>{{ form.endTime.time }}</span>
<span>{{ form.endTime.year }}{{ form.endTime.month }}{{ form.endTime.day }} {{ form.endTime.weekday }}</span>
</div>
</u-row>
</div>
<div class="card">
<header><em>*</em>会议地点</header>
<input v-model="form.address" placeholder="请输入" :maxlength="30">
</div>
<div class="card">
<header><em>*</em>会议内容</header>
<textarea v-model="form.content" placeholder="请输入" :maxlength="500"></textarea>
</div>
<div class="card">
<AiUploader :multiple="true" type="file" :limit="9" placeholder="上传附件" @list="fileList"
:def="form.files"></AiUploader>
</div>
<div class="card item-wrap" @click="select">
<u-row justify="between" class="item" @click="userSelect=true">
<header><em>*</em>参会人</header>
<div class="right">
<template v-if="!form.attendees.length">
<span>请选择</span>
</template>
<template v-else>
已选择<em>{{ form.attendees.map(e => e.name).slice(0, 2).join("、") }}</em><em>{{ form.attendees.length }}</em>
</template>
<div class="right-arrow"></div>
</div>
</u-row>
</div>
<div class="card item-wrap" style="margin-top: 0">
<u-row justify="between" class="item">
<header>参会提醒</header>
<picker class="right" @change="beforeNoticeChange" :value="form.noticeBefore" range-key="dictName"
:range="$dict.getDict('meetingNoticeBefore')">
<span>{{ form.noticeBefore != null ? $dict.getDict('meetingNoticeBefore')[form.noticeBefore]["dictName"] : "请选择" }}</span>
<div class="right-arrow"></div>
</picker>
</u-row>
</div>
<div class="card item-wrap" style="margin-top: 0">
<u-row justify="between" class="item">
<header>确认提醒</header>
<picker class="right" @change="afterNoticeChange" :value="form.noticeAfter" range-key="dictName"
:range="$dict.getDict('meetingNoticeAfter')">
<span>{{ form.noticeAfter != null ? $dict.getDict('meetingNoticeAfter')[form.noticeAfter]["dictName"] : "请选择" }}</span>
<div class="right-arrow"></div>
</picker>
</u-row>
</div>
<div class="footer">
<div @click="add(0)">保存草稿</div>
<div @click="add(1)">发布会议</div>
</div>
</div>
<u-picker mode="time" v-model="show" :params="params" @confirm="confirm"></u-picker>
<AiBack ref="aiBack" v-if="!userSelect"/>
<AiSelectEnterprise :visible.sync="userSelect" :value="form.attendees" v-if="userSelect"
@change="change"></AiSelectEnterprise>
</div>
</template>
<script>
import AiBack from "../../../components/AiBack";
import AiSelectEnterprise from "../../../components/AiSelectEnterprise";
import AiUploader from "../../../components/AiUploader";
export default {
name: "addMeeting",
components: {AiBack, AiSelectEnterprise, AiUploader},
data() {
const initTime = {
time: "",
year: "",
month: "",
day: "",
weekday: "",
timestamp: "",
}
return {
show: false,
index: 0,
list: [],
form: {
id: null,
title: "",
startTime: {...initTime},
endTime: {...initTime},
address: "",
content: "",
attendees: [],
noticeBefore: 4,
noticeAfter: 0,
files: [],
},
userSelect: false,
}
},
onLoad(opt) {
if (opt.id) {
this.form.id = opt.id
this.getDetail()
}
this.$dict.load("meetingNoticeBefore", "meetingNoticeAfter");
this.$nextTick(() => {
let date = new Date();
this.form.startTime.time = date.getHours()?.toString()?.padStart(2, "0") + ":" + date.getMinutes()?.toString()?.padStart(2, "0")
this.form.startTime.year = date.getFullYear()
this.form.startTime.month = (date.getMonth() + 1)?.toString()?.padStart(2, "0")
this.form.startTime.day = date.getDate()
this.form.startTime.weekday = '日一二三四五六'.charAt(date.getDay())
this.form.endTime = {...this.form.startTime}
})
},
computed: {
params() {
return {
year: true,
month: true,
day: true,
hour: true,
minute: true,
timestamp: true,
}
}
},
methods: {
fileList(e) {
this.form.files = e
},
change(e) {
this.form.attendees = e
},
beforeNoticeChange(e) {
this.form.noticeBefore = e.detail.value
},
afterNoticeChange(e) {
this.form.noticeAfter = e.detail.value
},
getDetail() {
this.$http.post("/app/appmeetinginfo/info-id", null, {
params: {
id: this.form.id
}
}).then(res => {
if (res && res.data) {
this.form.title = res.data.title
this.form.address = res.data.address
this.form.content = res.data.content
this.form.attendees = res.data.attendees
this.form.noticeBefore = res.data.noticeBefore
this.form.noticeAfter = res.data.noticeAfter
this.form.files = res.data.files
this.form.startTime.time = res.data.startTime.split(" ")[1].substr(0, 5)
this.form.startTime.year = res.data.startTime.split(" ")[0].split("-")[0]
this.form.startTime.month = res.data.startTime.split(" ")[0].split("-")[1]
this.form.startTime.day = res.data.startTime.split(" ")[0].split("-")[2]
this.form.startTime.weekday = '日一二三四五六'.charAt(new Date(res.data.startTime.split(" ")[0]).getDay())
this.form.startTime.timestamp = new Date(res.data.startTime).getTime()
this.form.endTime.time = res.data.endTime.split(" ")[1].substr(0, 5)
this.form.endTime.year = res.data.endTime.split(" ")[0].split("-")[0]
this.form.endTime.month = res.data.endTime.split(" ")[0].split("-")[1]
this.form.endTime.day = res.data.endTime.split(" ")[0].split("-")[2]
this.form.endTime.weekday = '日一二三四五六'.charAt(new Date(res.data.endTime.split(" ")[0]).getDay())
this.form.endTime.timestamp = new Date(res.data.endTime).getTime()
}
})
},
confirm(e) {
if (new Date().getTime() / 1000 > e.timestamp) return this.$u.toast("选择时间不能小于当前时间")
if (this.index == 0) {
this.form.startTime = {...e}
this.form.startTime.time = e.hour + ":" + (e.minute.length > 1 ? e.minute : ("0" + e.minute))
this.form.startTime.weekday = '日一二三四五六'.charAt(new Date(e.timestamp * 1000).getDay())
} else {
if (this.form.startTime.timestamp >= e.timestamp) {
return this.$u.toast("结束时间不能小于开始时间");
}
this.form.endTime = {...e}
this.form.endTime.time = e.hour + ":" + (e.minute.length > 1 ? e.minute : ("0" + e.minute))
this.form.endTime.weekday = '日一二三四五六'.charAt(new Date(e.timestamp * 1000).getDay())
}
},
add(status) {
if (status == 1) {
if (!this.form.title) return this.$u.toast("请输入会议标题")
if (this.form.startTime.timestamp >= this.form.endTime.timestamp) return this.$u.toast("结束时间不能小于开始时间")
if (!this.form.address) return this.$u.toast("请输入会议地点")
if (!this.form.content) return this.$u.toast("请输入会议内容")
if (!this.form.attendees.length) return this.$u.toast("请选择参会人")
}
this.$http.post("/app/appmeetinginfo/add-update", {
...this.form,
files: this.form.files.map(e => e.id),
status,
startTime: this.form.startTime.year + "-" + this.form.startTime.month + "-" + this.form.startTime.day + " " + this.form.startTime.time + ":00",
endTime: this.form.endTime.year + "-" + this.form.endTime.month + "-" + this.form.endTime.day + " " + this.form.endTime.time + ":00",
}).then(res => {
if (res.code == 0) {
this.$u.toast(status == 1 ? "发布成功" : "保存成功")
this.$refs["aiBack"].back()
}
})
},
pick(index) {
this.index = index
this.show = true
},
select() {
uni.navigateTo({
url: "/pages/meetingNotice/components/notice"
})
}
},
}
</script>
<style lang="scss" scoped>
.add-meeting {
min-height: 100%;
background: #F5F5F5;
padding-bottom: 140px;
.card {
background-color: #FFFFFF;
box-sizing: border-box;
padding: 32px;
margin-top: 16px;
header {
font-size: 32px;
font-weight: 400;
color: #333333;
em {
font-style: normal;
font-size: 32px;
color: #FF4466;
margin-right: 8px;
vertical-align: middle;
}
}
input {
margin: 32px 0 16px;
box-sizing: border-box;
padding: 0 16px;
}
textarea {
width: 100%;
height: 160px;
margin: 32px 0 16px;
box-sizing: border-box;
padding: 0 16px;
}
.u-row {
margin-top: 34px;
.time {
display: flex;
flex-direction: column;
& > span:first-child {
font-size: 60px;
font-weight: 600;
color: #333333;
line-height: 84px;
}
& > span:last-child {
font-size: 22px;
color: #333333;
}
}
.arrow {
width: 28px;
height: 68px;
overflow: hidden;
position: relative;
transform: rotate(180deg);
&:before, &:after {
content: "";
width: 50px;
height: 50px;
position: absolute;
transform: scaleY(1.3) translate(30%, -40px) rotate(45deg);
}
&:before {
top: 59px;
background-color: #CCCCCC;
}
&:after {
left: 7px;
top: 59px;
background-color: #FFFFFF;
}
}
}
.item {
height: 112px;
box-shadow: 0px -1px 0px 0px #D8DDE6;
margin-top: 0;
.right {
font-size: 28px;
color: #999999;
display: flex;
align-items: center;
em {
font-style: normal;
color: #1365DD;
}
}
.right-arrow {
width: 16px;
height: 16px;
display: inline-block;
border-top: 5px solid #CCCCCC;
border-right: 5px solid #CCCCCC;
transform: rotate(45deg);
}
}
}
.item-wrap {
padding: 0 32px;
}
.footer {
height: 112px;
width: 100%;
position: fixed;
left: 0;
bottom: 0;
background-color: #FFFFFF;
display: flex;
align-items: center;
& > div {
font-size: 36px;
color: #333333;
}
& > div:first-child {
width: 270px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
& > div:last-child {
width: calc(100% - 270px);
height: 100%;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
background-color: #1365DD;
}
}
}
</style>

View File

@@ -1,231 +0,0 @@
<template>
<div class="belong-to-me">
<ai-top-fixed>
<u-tabs :list="tabs" :is-scroll="false" :current="index" bar-width="88" :height="96" @change="change"></u-tabs>
</ai-top-fixed>
<div class="body">
<template v-if="list.length">
<div class="card" v-for="(item,index) in list" :key="index" @click="handleClick(item)">
<header>{{ item.title }}</header>
<u-row justify="between">
<div class="time">
<span>{{ item.startTime|formatTime }}</span>
<span>{{ item.startTime|formatDate(0) }}{{ item.startTime|formatDate(1) }}{{ item.startTime|formatDate(2) }} {{ item.startTime|formatWeek }}</span>
</div>
<div class="arrow"></div>
<div class="time">
<span>{{ item.endTime|formatTime }}</span>
<span>{{ item.endTime|formatDate(0) }}{{ item.endTime|formatDate(1) }}{{ item.endTime|formatDate(2) }} {{ item.endTime|formatWeek }}</span>
</div>
</u-row>
<u-row class="info">
<span>发起单位</span>
<span>{{ item.unitName }}</span>
</u-row>
<u-gap height="20"></u-gap>
<u-row class="info">
<span>会议地点</span>
<span>{{ item.address }}</span>
</u-row>
<div class="tag" :style="{background:'url(' + tag(item.status) + ')'}"></div>
</div>
</template>
<template v-else>
<ai-empty/>
</template>
</div>
<AiBack/>
</div>
</template>
<script>
import AiTopFixed from "../../../components/AiTopFixed";
import AiBack from "../../../components/AiBack";
import AiEmpty from "../../../components/AiEmpty";
export default {
name: "belongToMe",
components: {AiTopFixed, AiBack, AiEmpty},
data() {
return {
index: 0,
current: 1,
list: [],
status: "加载更多",
}
},
onLoad() {
this.getList()
},
computed: {
tabs() {
return [
{name: "全部"},
{name: "未开始"},
{name: "进行中"},
{name: "已取消"},
{name: "已结束"},
]
}
},
methods: {
tag(status) {
return {
"1": this.$cdn + 'common/1wks.png',
"2": this.$cdn + 'common/1jxz.png',
"3": this.$cdn + 'common/1yqx.png',
"4": this.$cdn + 'common/1yjs.png'
}[status]
},
getList() {
this.$http.post("/app/appmeetinginfo/list", null, {
params: {
listType: 0,
meetingStatus: this.index == 0 ? "-1" : this.index,
size: 10,
current: this.current
}
}).then(res => {
if (res && res.data) {
if (this.current > 1 && this.current > res.data.pages) {
this.status = "已经到底啦"
}
this.list = this.current > 1 ? [...this.list, ...res.data.records] : res.data.records
}
})
},
handleClick({id}) {
uni.navigateTo({
url: "/pages/meetingNotice/components/detail?id=" + id
})
},
change(e) {
this.index = e
this.current = 1
this.getList()
},
},
onReachBottom() {
this.current = this.current + 1;
this.getList()
},
filters: {
formatTime(date) {
return date.split(" ")[1]?.substr(0, 5)
},
formatDate(date, i) {
return date.split(" ")[0]?.split("-")[i]
},
formatWeek(date) {
return "日一二三四五六".charAt(new Date(date.split(" ")[0]).getDay())
},
}
}
</script>
<style lang="scss" scoped>
.belong-to-me {
min-height: 100%;
background-color: #F5F5F5;
::v-deep .content {
padding: 0 !important;
}
.body {
box-sizing: border-box;
padding: 40px 32px;
.card {
background-color: #FFFFFF;
box-sizing: border-box;
padding: 32px;
border-radius: 8px;
margin-bottom: 32px;
position: relative;
&:last-child {
margin-bottom: 0;
}
& > header {
font-size: 32px;
font-weight: 600;
color: #333333;
}
.time {
display: flex;
flex-direction: column;
margin: 46px 0;
& > span:first-child {
font-size: 60px;
font-weight: 600;
color: #333333;
line-height: 84px;
}
& > span:last-child {
font-size: 22px;
color: #333333;
}
}
.arrow {
width: 28px;
height: 68px;
overflow: hidden;
position: relative;
transform: rotate(180deg);
&:before, &:after {
content: "";
width: 50px;
height: 50px;
position: absolute;
transform: scaleY(1.3) translate(30%, -40px) rotate(45deg);
}
&:before {
top: 59px;
background-color: #CCCCCC;
}
&:after {
left: 7px;
top: 59px;
background-color: #FFFFFF;
}
}
.info {
flex-wrap: nowrap;
& > span:first-child {
font-size: 30px;
color: #999999;
flex-shrink: 0;
}
& > span:last-child {
font-size: 30px;
color: #343D65;
}
}
.tag {
width: 112px;
height: 112px;
background-repeat: no-repeat;
background-size: 100% 100% !important;
position: absolute;
top: 0;
right: 0;
}
}
}
}
</style>

View File

@@ -1,480 +0,0 @@
<template>
<div class="detail">
<template v-if="!list">
<div class="card">
<header>{{ detail.title }}</header>
<u-gap height="16"></u-gap>
<u-row>
<u-avatar :src="$cdn + 'common/xzh.png'" v-if="false"></u-avatar>
<div class="u-avatar__img" v-else>{{ detail.userName && detail.userName.substr(-2) }}</div>
<span>{{ detail.userName }}</span>
</u-row>
<u-gap height="32"></u-gap>
<u-row>
<img :src="$cdn + 'common/meeting.png'" alt="">
<span :style="{color:color(detail.status)}">{{ $dict.getLabel('meetStatus', detail.status) }}</span>
</u-row>
<u-gap height="8"></u-gap>
<u-row>
<img :src="$cdn + 'common/date.png'" alt="">
<span>{{
detail.startTime && detail.startTime.substr(0, 16)
}} {{ detail.endTime && detail.endTime.substr(0, 16) }}</span>
</u-row>
<u-gap height="8"></u-gap>
<u-row>
<img :src="$cdn + 'common/location.png'" alt="">
<span>{{ detail.address }}</span>
</u-row>
</div>
<div class="card">
<span>{{ detail.content }}</span>
</div>
<div class="card" v-if="detail.files && detail.files.length">
<div class="label">相关附件</div>
<div class="file" v-for="(item,index) in detail.files" @click="preFile(item)" :key="index">
<u-row justify="between">
<label class="left">
<img :src="$cdn + 'common/appendix.png'" alt="">
<span>{{ item.fileName }}.{{ item.postfix }}</span>
</label>
<span>{{ item.fileSizeStr }}</span>
</u-row>
</div>
</div>
<div class="card item-wrap">
<u-row justify="between">
<span>参会人</span>
<label class="right" @click="list=true">
查看全部<em>{{ detail.attendees && detail.attendees.length }}</em>
<div class="right-arrow"></div>
</label>
</u-row>
</div>
<div class="footer" v-if="['1','2'].includes(detail.status) && detail.joinStatus==0">
<div @click="updateStatus(0)">请假</div>
<div @click="updateStatus(1)">确认会议</div>
</div>
<div class="footer" v-if="['1','2'].includes(detail.status) && detail.joinStatus!=0">
<label>{{ detail.joinStatus|transform }}</label>
<img :src="$cdn + tag(detail.joinStatus)" alt="">
</div>
</template>
<template v-else>
<div class="att-list">
<AiTopFixed>
<u-tabs :list="tabs" :current="current" height="96" :is-scroll="false" bar-width="192"
@change="change"></u-tabs>
</AiTopFixed>
<div v-for="(item,index) in detail.attendees && detail.attendees.filter(e=>e.joinStatus==current)" :key="index"
class="att-wrap">
<div class="left">
<u-avatar :src="item.avatar || (($cdn + 'common/xztx.png'))" size="74" mode="square"></u-avatar>
<text class="name" style="margin-left: 8px">{{ item.name }}</text>
</div>
<img :src="$cdn + 'common/phone.png'" alt="" @click="call(item)">
</div>
</div>
</template>
<AiBack visible eventName="back" @back="list=false"/>
</div>
</template>
<script>
import AiBack from "../../../components/AiBack";
import {mapActions} from "vuex";
import AiTopFixed from "../../../components/AiTopFixed";
export default {
name: "detail",
components: {AiBack, AiTopFixed},
data() {
return {
id: null,
detail: {},
list: false,
current: 0,
}
},
computed: {
tabs() {
return [
{name: this.count(0) + "人未确认"},
{name: this.count(1) + "人已确认"},
{name: this.count(2) + "人已请假"},
]
},
},
onLoad(opt) {
this.id = opt.id
this.$dict.load("meetStatus").then(_ => this.getDetail())
},
methods: {
count(sta) {
return this.detail.attendees?.filter(e => e.joinStatus == sta)?.length;
},
change(index) {
this.current = index;
},
call(item) {
if (item.phone) {
uni.makePhoneCall({
phoneNumber: item.phone
});
}
},
...mapActions(['previewFile', 'injectJWeixin']),
preFile(e) {
if ([".jpg", ".png", ".gif"].includes(e.postfix.toLowerCase())) {
uni.previewImage({
current: e.url,
urls: [e.url]
})
} else {
this.previewFile({...e})
}
},
tag(status) {
return {
"1": "common/2confirmed2.png",
"2": "common/2absent2.png"
}[status]
},
updateStatus(status) {
this.$http.post(status == 0 ? "/app/appmeetinginfo/absent" : "/app/appmeetinginfo/confirm", null, {
params: {
meetingId: this.id,
reason: status == 0 ? "" : null
}
}).then(res => {
if (res.code == 0) {
this.$u.toast(status == 0 ? "请假成功" : "确认成功")
this.getDetail()
}
})
},
color(status) {
if (status == 1) {
return "#FF8822"
}
if (status == 2) {
return "#1365DD"
}
if (status == 3) {
return "#FF4466"
}
return "#343D65"
},
getDetail() {
this.$http.post("/app/appmeetinginfo/info-id", null, {
params: {id: this.id}
}).then(res => {
if (res && res.data) {
this.detail = res.data
}
})
}
},
filters: {
transform(status) {
if (status == 1) {
return "已确认"
}
if (status == 2) {
return "已请假"
}
}
}
}
</script>
<style lang="scss" scoped>
.detail {
min-height: 100%;
background-color: #F5F5F5;
padding-bottom: 140px;
::v-deep .AiTopFixed {
margin-bottom: 16px;
.content {
padding: 0 !important;
}
}
.att-list {
min-height: 100%;
.att-wrap {
display: flex;
height: 112px;
align-items: center;
justify-content: space-between;
background-color: #ffffff;
box-sizing: border-box;
padding: 0 50px;
border-bottom: 1px solid #E4E5E6;
.left {
display: flex;
align-items: center;
&:after {
content: "";
position: absolute;
right: 0;
bottom: 0;
width: 622px;
height: 2px;
background-color: rgba(216, 221, 230, 0.5);
}
.name {
font-size: 30px;
font-weight: 600;
color: #333333;
}
}
& > img {
width: 48px;
height: 48px;
}
}
}
.card {
background-color: #FFFFFF;
margin-bottom: 8px;
box-sizing: border-box;
padding: 16px 32px;
header {
font-size: 40px;
font-weight: 600;
color: #333333;
line-height: 64px;
letter-spacing: 1px;
}
.u-row {
& > div {
background-color: #2266FF;
border-radius: 50%;
text-align: center;
font-size: 22px;
font-weight: bold;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
}
& > span {
font-size: 30px;
color: #343D65;
margin-left: 16px;
}
::v-deep .u-avatar__img {
width: 56px;
height: 56px;
vertical-align: middle;
}
img {
width: 48px;
height: 48px;
}
}
& > span {
font-size: 32px;
color: #333333;
line-height: 48px;
letter-spacing: 1px;
display: inline-block;
box-sizing: border-box;
padding: 16px 0;
}
.label {
height: 96px;
font-size: 32px;
color: #333333;
display: flex;
align-items: center;
margin-bottom: 16px;
}
.file {
height: 128px;
background: #FFFFFF;
border-radius: 8px;
border: 1px solid #CCCCCC;
box-sizing: border-box;
padding: 0 16px;
margin-bottom: 32px;
& > .u-row {
height: 100%;
.left {
width: 522px;
display: flex;
align-items: center;
& > img {
width: 96px;
height: 96px;
}
& > span {
font-size: 32px;
color: #333333;
display: inline-block;
line-height: 44px;
}
}
& > span {
font-size: 28px;
color: #999999;
}
}
}
.active {
background-color: #F3F6F9;
}
.name {
font-size: 32px;
font-weight: 400;
color: #333333;
}
.wrap {
height: 112px;
display: flex;
align-items: center;
position: relative;
&:after {
content: "";
position: absolute;
right: 0;
bottom: 0;
width: 622px;
height: 2px;
background-color: rgba(216, 221, 230, 0.5);
}
& > label {
width: 80px;
height: 80px;
border-radius: 50%;
background-color: #4E8EEE;
font-size: 28px;
font-weight: 600;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.item-wrap {
height: 112px;
padding: 0 32px;
.u-row {
height: 100%;
& > span {
font-size: 32px;
font-weight: 400;
color: #333333;
}
}
.right {
font-size: 28px;
color: #999999;
display: flex;
align-items: center;
em {
font-style: normal;
color: #1365DD;
}
.right-arrow {
width: 16px;
height: 16px;
border-top: 5px solid #CCCCCC;
border-right: 5px solid #CCCCCC;
transform: rotate(45deg);
}
}
}
.footer {
height: 112px;
width: 100%;
position: fixed;
left: 0;
bottom: 0;
background-color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
& > div {
font-size: 36px;
color: #333333;
}
& > div:first-child {
width: 270px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
& > div:last-child {
width: calc(100% - 270px);
height: 100%;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
background-color: #1365DD;
}
& > label {
font-size: 36px;
font-weight: 400;
color: #999999;
}
img {
width: 158px;
height: 104px;
position: absolute;
right: 0;
top: 0;
}
}
}
</style>

View File

@@ -1,226 +0,0 @@
<template>
<div class="meeting-list">
<div class="card" v-for="(item,index) in list" :key="index" @click="detail(item)">
<header>
<span>{{ item.title }}</span>
<span>
<span v-if="index==2">保存于</span>
{{ item.createTime }}</span>
</header>
<u-row justify="between">
<div class="time">
<span>{{ item.startTime|format }}</span>
<span>{{ item.startTime|formatDate(0) }}{{ item.startTime|formatDate(1) }}{{ item.startTime|formatDate(2) }} {{ item.startTime|formatWeek }}</span>
</div>
<div class="arrow"></div>
<div class="time">
<span>{{ item.endTime|format }}</span>
<span>{{ item.endTime|formatDate(0) }}{{ item.endTime|formatDate(1) }}{{ item.endTime|formatDate(2) }} {{ item.endTime|formatWeek }}</span>
</div>
</u-row>
<u-row class="info">
<span>发起人员</span>
<span>{{ item.userName }}</span>
</u-row>
<u-gap height="20"></u-gap>
<u-row class="info">
<span>会议地点</span>
<span>{{ item.address }}</span>
</u-row>
<div class="tag" v-if="item.status!=0" :style="{background:'url(' + $cdn + tag(item.status) +')'}"></div>
</div>
<u-loadmore :status="status" v-if="list.length"/>
<AiEmpty v-if="!list.length"></AiEmpty>
<AiBack/>
</div>
</template>
<script>
import AiBack from "../../../components/AiBack";
import AiEmpty from "../../../components/AiEmpty";
export default {
name: "meetingList",
components: {AiBack, AiEmpty},
data() {
return {
index: null,
list: [],
current: 1,
status: "加载更多",
}
},
onLoad(opt) {
this.index = opt.index
uni.setNavigationBarTitle({
title: opt.index == 0 ? "历史会议" : "草稿箱"
});
},
methods: {
detail({id}) {
let url
if (this.index == 2) {
url = "/pages/meetingNotice/components/addMeeting?id=" + id
} else {
url = "/pages/meetingNotice/components/detail?id=" + id
}
uni.navigateTo({url})
},
tag(status) {
return {
"1": 'common/1wks.png',
"2": 'common/1jxz.png',
"3": 'common/1yqx.png',
"4": 'common/1yjs.png'
}[status]
},
getData() {
this.$http.post("/app/appmeetinginfo/list", null, {
params: {
listType: this.index == 0 ? "2" : '0',
meetingStatus: this.index == 0 ? "4" : "0",
size: 10,
current: this.current,
}
}).then(res => {
if (res && res.data) {
if (this.current > 1 && this.current > res.data.pages) {
this.status = "已经到底啦"
}
this.list = this.current > 1 ? [...this.list, ...res.data.records] : res.data.records
}
})
},
},
filters: {
format(date) {
return date.split(" ")[1].substr(0, 5)
},
formatDate(date, index) {
return date.split(" ")[0].split("-")[index]
},
formatWeek(date) {
return "日一二三四五六".charAt((new Date(date.split(" ")[0]).getDay()))
}
},
onShow() {
this.getData()
},
onReachBottom() {
this.current = this.current + 1;
this.getData()
},
}
</script>
<style lang="scss" scoped>
.meeting-list {
min-height: 100%;
background-color: #F5F5F5;
box-sizing: border-box;
padding: 32px;
.card {
background-color: #FFFFFF;
box-sizing: border-box;
padding: 32px;
border-radius: 8px;
margin-bottom: 32px;
position: relative;
&:last-child {
margin-bottom: 0;
}
& > header {
font-size: 32px;
font-weight: 600;
color: #333333;
display: flex;
flex-direction: column;
& > span:last-child {
font-size: 28px;
font-weight: 400;
color: #999999;
margin-top: 10px;
}
}
.time {
display: flex;
flex-direction: column;
margin: 46px 0;
& > span:first-child {
font-size: 60px;
font-weight: 600;
color: #333333;
line-height: 84px;
}
& > span:last-child {
font-size: 22px;
color: #333333;
}
}
.arrow {
width: 28px;
height: 68px;
overflow: hidden;
position: relative;
transform: rotate(180deg);
&:before, &:after {
content: "";
width: 50px;
height: 50px;
position: absolute;
transform: scaleY(1.3) translate(30%, -40px) rotate(45deg);
}
&:before {
top: 59px;
background-color: #CCCCCC;
}
&:after {
left: 7px;
top: 59px;
background-color: #FFFFFF;
}
}
.info {
flex-wrap: nowrap;
& > span:first-child {
flex-shrink: 0;
font-size: 30px;
color: #999999;
}
& > span:last-child {
font-size: 30px;
color: #343D65;
}
}
.tag {
width: 112px;
height: 112px;
background-repeat: no-repeat !important;
background-size: 100% 100% !important;
position: absolute;
top: 0;
right: 0;
}
}
}
</style>

View File

@@ -1,256 +0,0 @@
<template>
<div class="meeting">
<ai-top-fixed>
<u-grid :col="3" :border="false">
<u-grid-item v-for="(item,index) in grid" :key="index" :custom-style="{padding:'14px 0'}"
@click="handleClick(index)">
<u-icon :name="item.icon" :size="64"></u-icon>
<view class="label">{{ item.label }}</view>
</u-grid-item>
</u-grid>
</ai-top-fixed>
<div class="body">
<header>待参加的会议</header>
<template v-if="meetingList.length">
<div class="card" v-for="(item,index) in meetingList" :key="index" @click="detail(item)">
<header>{{ item.title }}</header>
<u-row justify="between">
<div class="time">
<span>{{ item.startTime|format }}</span>
<span>{{ item.startTime|formatDate(0) }}{{ item.startTime|formatDate(1) }}{{ item.startTime|formatDate(2) }} {{ item.startTime|formatWeek }}</span>
</div>
<div class="arrow"></div>
<div class="time">
<span>{{ item.endTime|format }}</span>
<span>{{ item.endTime|formatDate(0) }}{{ item.endTime|formatDate(1) }}{{ item.endTime|formatDate(2) }} {{ item.endTime|formatWeek }}</span>
</div>
</u-row>
<u-row class="info">
<span>发起人员</span>
<span>{{ item.userName }}</span>
</u-row>
<u-gap height="20"></u-gap>
<u-row class="info">
<span>会议地点</span>
<span>{{ item.address }}</span>
</u-row>
<div class="tag" :style="{background:'url(' + $cdn + tag(item.joinStatus) + ')'}"></div>
</div>
</template>
<template v-else>
<ai-empty/>
</template>
</div>
<u-divider bg-color="#F5F5F5" v-if="meetingList.length">已经到底啦</u-divider>
<ai-add @add="add"/>
</div>
</template>
<script>
import AiEmpty from "../../components/AiEmpty";
import AiTopFixed from "../../components/AiTopFixed";
import AiAdd from "../../components/AiAdd";
export default {
name: "meetingNotice",
components: {AiEmpty, AiTopFixed, AiAdd},
data() {
return {
meetingList: []
}
},
computed: {
grid() {
return [
{
icon: this.$cdn + "/common/iconlshy.png",
label: "历史会议"
},
{
icon: this.$cdn + "/common/iconwfqd.png",
label: "我发起的"
},
{
icon: this.$cdn + "/common/iconcgx.png",
label: "草稿箱"
}
]
}
},
methods: {
tag(status) {
return {
"0": "common/1wqr.png",
"1": "common/1yqr.png",
"2": "common/1yqj.png",
}[status]
},
detail({id}) {
uni.navigateTo({
url: "/pages/meetingNotice/components/detail?id=" + id
})
},
getData() {
this.$http.post("/app/appmeetinginfo/list", null, {
params: {
listType: "1",
meetingStatus: "1|2",
size: 999
}
}).then(res => {
if (res && res.data) {
this.meetingList = res.data.records
}
})
},
handleClick(index) {
let url
if (index == 0 || index == 2) {
url = "/pages/meetingNotice/components/meetingList?index=" + index
} else if (index == 1) {
url = "/pages/meetingNotice/components/belongToMe"
}
uni.navigateTo({url})
},
add() {
uni.navigateTo({
url: "/pages/meetingNotice/components/addMeeting"
})
}
},
filters: {
format(date) {
return date.split(" ")[1].substr(0, 5)
},
formatDate(date, index) {
return date.split(" ")[0].split("-")[index]
},
formatWeek(date) {
return "日一二三四五六".charAt((new Date(date.split(" ")[0]).getDay()))
}
},
onShow() {
this.getData()
}
}
</script>
<style lang="scss" scoped>
.meeting {
min-height: 100%;
background: #F5F5F5;
padding-bottom: 48px;
.label {
font-size: 28px;
font-weight: 400;
color: #333333;
line-height: 48px;
margin-top: 8px;
}
.body {
box-sizing: border-box;
padding: 40px 32px;
& > header {
font-size: 36px;
font-weight: 600;
color: #333333;
margin-bottom: 38px;
}
.card {
background-color: #FFFFFF;
box-sizing: border-box;
padding: 32px;
border-radius: 8px;
margin-bottom: 32px;
position: relative;
&:last-child {
margin-bottom: 0;
}
& > header {
font-size: 32px;
font-weight: 600;
color: #333333;
}
.time {
display: flex;
flex-direction: column;
margin: 46px 0;
& > span:first-child {
font-size: 60px;
font-weight: 600;
color: #333333;
line-height: 84px;
}
& > span:last-child {
font-size: 22px;
color: #333333;
}
}
.arrow {
width: 28px;
height: 68px;
overflow: hidden;
position: relative;
transform: rotate(180deg);
&:before, &:after {
content: "";
width: 50px;
height: 50px;
position: absolute;
transform: scaleY(1.3) translate(30%, -40px) rotate(45deg);
}
&:before {
top: 59px;
background-color: #CCCCCC;
}
&:after {
left: 7px;
top: 59px;
background-color: #FFFFFF;
}
}
.info {
& > span:first-child {
font-size: 30px;
color: #999999;
}
& > span:last-child {
font-size: 30px;
color: #343D65;
}
}
.tag {
width: 112px;
height: 112px;
background-repeat: no-repeat !important;
background-size: 100% 100% !important;
position: absolute;
top: 0;
right: 0;
}
}
}
::v-deep .content {
padding: 0 !important;
}
}
</style>

View File

@@ -1,100 +0,0 @@
<template>
<section class="comp">
<ai-result v-if="error" status="error" :tips="error"/>
<template v-else-if="isNormal">
<component ref="currentTab" :is="currentTab.comp" :isNormal="isNormal"/>
<ai-tabbar :active.sync="active" :list="bottomBar"/>
</template>
<ai-loading v-else tips="居民管理加载中..."/>
</section>
</template>
<script>
import {mapActions} from "vuex";
import AiLoading from "../../components/AiLoading";
import AiResult from "../../components/AiResult";
import ResidentSta from "./residentSta";
import ResidentList from "./residentList";
import GroupList from "./groupList";
import AiTabbar from "../../components/AiTabbar";
export default {
name: "comp",
components: {AiTabbar, GroupList, ResidentList, ResidentSta, AiResult, AiLoading},
data() {
return {
error: "",
active: 0,
isNormal: false
}
},
computed: {
bottomBar() {
const link = icon => `${this.$cdn}resident/${icon}.png`
return [
{text: "统计分析", iconPath: "qwhome2", selectedIconPath: "qwhome1", comp: ResidentSta},
{text: "居民列表", iconPath: "qwjmda1", selectedIconPath: "qwjmda2", comp: ResidentList},
{text: "居民群列表", iconPath: "qwjmq1", selectedIconPath: "qwjmq2", comp: GroupList},
].map(e => ({
...e,
iconPath: link(e.iconPath),
selectedIconPath: link(e.selectedIconPath)
}))
},
currentTab() {
return this.bottomBar?.[this.active] || {}
}
},
methods: {
...mapActions(['injectJWeixin', "wxInvoke"]),
},
created() {
if (this.$route.hash == "#dev") {
this.isNormal = true
} else this.injectJWeixin(["getContext", "getCurExternalChat"]).then(() => {
this.wxInvoke(['getContext', {}, res => {
if (res.err_msg == "getContext:ok") {
if (res.entry == 'normal') this.isNormal = true
else this.wxInvoke(['getCurExternalChat', {}, res => {
if (res?.err_msg == 'getCurExternalChat:ok') {
wx.redirectTo({
url: "./groupResident"
})
} else {
wx.redirectTo({
url: "./resident"
})
}
}])
} else {
this.error = "wxwork:获取进入场景失败"
}
}])
}).catch(() => {
this.error = "应用加载失败"
})
},
onReachBottom() {
if (typeof this.$refs?.currentTab?.reachBottom == 'function') this.$refs?.currentTab.reachBottom()
}
}
</script>
<style lang="scss" scoped>
.comp {
height: 100%;
::v-deep .u-tabbar__content__item {
padding: 0;
.u-icon__img {
height: 44px !important;
width: 44px !important;
}
.u-tabbar__content__item__text {
margin-top: 4px;
font-size: 22px;
}
}
}
</style>

View File

@@ -1,132 +0,0 @@
<template>
<section class="document">
<div class="card">
<div class="info">
<u-image border-radius="4" :src="top.detail.avatar" width="118" height="118"/>
<div class="fill">
<b>{{ top.detail.realName || top.detail.name }}</b>
<u-row>
<span class="idNumber" v-html="IDObj.id"/>
<a @tap="showID=!showID">{{ IDObj.btn }}</a>
</u-row>
</div>
</div>
<ai-cell label="性别">{{ $dict.getLabel("sex", resident.sex) || "-" }}</ai-cell>
<ai-cell label="出生日期">{{ resident.birthDate }}</ai-cell>
<ai-cell label="年龄">{{ resident.age }}</ai-cell>
<ai-cell label="籍贯">{{ resident.birthplaceAreaName }}</ai-cell>
<ai-cell label="民族">{{ $dict.getLabel("nation", resident.nation) || "-" }}</ai-cell>
<ai-cell label="文化程度">{{ $dict.getLabel("education", resident.education) || "-" }}</ai-cell>
<ai-cell label="兵役状况">{{ $dict.getLabel("militaryStatus", resident.militaryStatus) || "-" }}</ai-cell>
<ai-cell label="政治面貌">{{ $dict.getLabel("politicsStatus", resident.politicsStatus) || "-" }}</ai-cell>
<ai-cell label="职业">{{ $dict.getLabel("job", resident.job) || "-" }}</ai-cell>
<ai-cell label="宗教信仰">{{ $dict.getLabel("faithType", resident.faithType) || "-" }}</ai-cell>
</div>
<div class="card">
<ai-cell title label="联络信息"/>
<ai-cell label="联系方式">{{ resident.phone }}</ai-cell>
<ai-cell label="现住址">{{ resident.currentAreaName + resident.currentAddress }}</ai-cell>
</div>
<div class="card">
<ai-cell title label="家庭信息"/>
<ai-cell label="是否户主">{{ $dict.getLabel("householdName", resident.householdName) || "-" }}</ai-cell>
<ai-cell label="与户主关系">{{ $dict.getLabel("householdRelation", resident.householdRelation) || "-" }}</ai-cell>
<ai-cell label="现住址">{{ resident.householdAreaName + resident.householdAddress }}</ai-cell>
</div>
<div class="card">
<ai-cell title label="家庭成员"/>
<ai-table :data="family" :colConfigs="colConfigs"/>
</div>
</section>
</template>
<script>
import AiCell from "../../components/AiCell";
import AiTable from "../../components/AiTable";
export default {
name: "document",
components: {AiTable, AiCell},
inject: ['top'],
computed: {
IDObj() {
return this.showID ? {
id: this.resident?.idNumber,
btn: '隐藏'
} : {
id: this.resident?.idNumber?.replace(/(\d{10}).+/g, '$1******'),
btn: '显示'
}
},
colConfigs() {
return [
{label: "与户主关系", prop: "householdRelation", width: '160rpx', dict: "householdRelation"},
{label: "姓名", prop: "name", width: '120rpx'},
{label: "性别", prop: "sex", dict: "sex"},
{label: "年龄", prop: "age"},
{label: "身份证号", prop: "idNumber", width: '320rpx'},
]
},
resident() {
let obj = {}
Object.keys(this.top.detail?.residentInfo?.resident || {}).map(e => {
obj[e] = this.top.detail?.residentInfo?.resident[e] || ""
})
return obj
},
family() {
return this.top.detail?.residentInfo?.family?.map(e => ({...e, householdRelation: e.householdRelation || "户主"}))
}
},
data() {
return {
showID: false,
familyList: []
}
},
created() {
this.$dict.load("sex", "nation", "education", "job",
"faithType", "politicsStatus", "militaryStatus", "householdRelation",
"householdName")
}
}
</script>
<style lang="scss" scoped>
.document {
overflow-y: auto;
background: #F5F5F5;
.info {
height: 186px;
width: 100%;
display: flex;
align-items: center;
.fill {
color: #3C7FC8;
margin-left: 24px;
font-size: 28px;
line-height: 40px;
display: flex;
flex-direction: column;
b {
font-size: 36px;
color: #333;
margin-bottom: 8px;
line-height: 50px;
}
a {
cursor: pointer;
}
.idNumber {
margin-right: 16px;
color: #999;
}
}
}
}
</style>

View File

@@ -1,182 +0,0 @@
<template>
<section class="groupList">
<ai-top-fixed>
<u-search placeholder="请输入群名、群主名" :show-action="false" search-icon-color="#ccc"
v-model="search.name" @search="page.current=1,getList()"/>
<ai-cell>
<b slot="label" class="title"><i v-html="page.total||0"/>个居民群</b>
</ai-cell>
</ai-top-fixed>
<div class="mainPane">
<ai-cell v-for="item in list" :key="item.id" @click.native="showResident(item)">
<template #label>
<ai-image :src="item.avatar" preview/>
</template>
<div class="card column start" flex>
<div flex class="groupName">
<b>{{ item.name || "群聊" }}</b>
<div class="personCount" v-if="item.personCount">({{ item.personCount }})</div>
</div>
<div class="owner" v-html="`群主:${item.ownerName}`"/>
<div flex class="trends">
<div flex v-html="`今日入群:<em>${item.increase||0}</em>`"/>
<div flex v-html="`今日退群:<p>${item.decrease||0}</p>`"/>
</div>
</div>
</ai-cell>
</div>
</section>
</template>
<script>
import AiCell from "../../components/AiCell";
import AiImage from "../../components/AiImage";
import AiTopFixed from "../../components/AiTopFixed";
export default {
name: "groupList",
components: {AiTopFixed, AiImage, AiCell},
data() {
return {
page: {current: 1, size: 10, total: 0},
search: {name: ""},
list: []
}
},
methods: {
getList() {
this.$http.post("/app/wxcp/wxgroup/list", null, {
params: {...this.page, ...this.search}
}).then(res => {
if (res?.data) {
let meta = res.data.records?.map(e => ({
...e,
avatar: e?.avatar || this.$cdn + "groupAvatar.png"
}))
if (this.page.current > 1) {
this.list = [...this.list, ...meta]
} else this.list = meta
this.page.total = res.data.total
}
})
},
reachBottom() {
if (this.page.total > this.list.length) {
this.page.current++
this.getList()
}
},
showResident({id}) {
id && uni.navigateTo({
url: './groupResident?id=' + id
})
}
},
created() {
this.getList()
}
}
</script>
<style lang="scss" scoped>
.groupList {
::v-deep .AiTopFixed {
b.title {
color: #333;
font-size: 32px;
& > i {
color: #267FCE;
font-style: normal;
margin: 0 4px;
}
}
}
::v-deep .mainPane {
background: #fff;
padding: 0 32px;
.AiCell {
align-items: center;
height: 230px;
justify-content: flex-start;
.content {
flex: 1;
min-width: 0;
height: 100%;
max-width: unset;
border-bottom: 1px solid rgba(221, 221, 221, 1);
}
}
.card {
height: 100%;
justify-content: center;
b {
font-size: 36px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.tag {
justify-content: center;
background: #F3F4F7;
border-radius: 4px;
padding: 0 16px;
font-size: 28px;
font-weight: 400;
color: #333;
margin-left: 16px;
height: 56px;
}
.groupName {
width: 100%;
text-align: left;
}
.owner, .trends {
margin-top: 8px;
font-size: 28px;
font-weight: 400;
color: #999;
}
.personCount {
flex-shrink: 0;
font-size: 30px;
font-weight: 400;
color: #666;
}
.trends {
* + * {
margin-left: 24px;
}
em {
font-style: normal;
color: #5FBA95;
}
p {
color: #F09535;
}
}
}
.AiImage {
margin-right: 24px;
image {
width: 112px;
height: 112px;
}
}
}
}
</style>

View File

@@ -1,305 +0,0 @@
<template>
<div class="group-resident">
<template v-if="!showTagManage">
<ai-top-fixed>
<div class="card">
<header>
<u-avatar mode="square" :src="$cdn + 'groupAvatar.png'" :size="112"></u-avatar>
{{ detail.name }}
</header>
<u-grid :col="2" :border="false">
<u-grid-item>
<label>建群日期</label>
<label v-if="detail.createTime">{{ detail.createTime.split(" ")[0] }}</label>
</u-grid-item>
<u-grid-item>
<label>成员总数</label>
<label v-if="isToday">{{ detail.statistic.today.total }}</label>
</u-grid-item>
<u-grid-item>
<label>今日入群</label>
<label v-if="isToday">{{ detail.statistic.today.increase }}</label>
</u-grid-item>
<u-grid-item>
<label>今日退群</label>
<label v-if="isToday">{{ detail.statistic.today.decrease }}</label>
</u-grid-item>
<!-- <u-grid-item>-->
<!-- <label>今日活跃人数</label>-->
<!-- <label>{{item.value}}</label>-->
<!-- </u-grid-item>-->
</u-grid>
<p class="statistics">
<span>成员性别</span>
<label>男性</label>
<b>{{ detail.man }}</b>
<label>女性</label>
<b>{{ detail.woman }}</b>
<label>未知</label>
<b>{{ detail.unknown }}</b>
</p>
</div>
</ai-top-fixed>
<div class="card">
<ai-cell title label="群标签">
<u-icon label="添加" size="38" name="iconAdd" custom-prefix="iconfont" color="#1365DD"
label-color="#1365DD" @tap="showTagManage=true"/>
</ai-cell>
<ai-cell top-label v-for="(op,name) in tagsList" :label="name" :key="name">
<u-row>
<div class="tag" v-for="(tag,j) in op" :key="j">{{ tag }}</div>
</u-row>
</ai-cell>
</div>
<div class="card">
<ai-cell title label="群成员"></ai-cell>
<div class="wrap">
<div class="item" v-for="(item,index) in detail.groupUserList" :key="index" @click="handleWechat(item)">
<u-avatar mode="square" :src="item.avatar"></u-avatar>
<div class="info">
<div class="left">
<p>{{ item.memberName }}
<b v-if="item.customerType==2" style="color: #3C7FC8;">@{{ item.corpName }}</b>
<b v-if="item.customerType==1" style="color: #2EA222;">@微信</b>
</p>
<p>真实姓名{{ item.realName }}</p>
</div>
<span v-if="item.userId==detail.owner">群主</span>
</div>
</div>
</div>
</div>
</template>
<tag-manage v-if="showTagManage"/>
<ai-back v-if="isNormal&&!showTagManage"/>
</div>
</template>
<script>
import AiCell from "../../components/AiCell";
import {mapActions} from "vuex";
import TagManage from "./tagManage";
import AiBack from "../../components/AiBack";
import AiTopFixed from "../../components/AiTopFixed";
export default {
name: "groupResident",
components: {AiTopFixed, AiBack, AiCell, TagManage},
provide() {
return {
top: this
}
},
data() {
return {
detail: {},
groupId: null,
showTagManage: false,
}
},
computed: {
tagsList() {
let obj = {}
this.detail?.tagList?.map(e => {
if (e?.groupName) {
if (obj?.[e.groupName]) {
obj[e.groupName].push(e.tagName)
} else {
obj[e.groupName] = [e.tagName]
}
}
})
return obj
},
isToday() {
return !!this.detail?.statistic?.today
},
isNormal() {
return !!this.$route.query.id;
}
},
methods: {
...mapActions(['injectJWeixin', "wxInvoke"]),
getContact() {
if (this.isNormal) {
this.groupId = this.$route.query.id
this.getGroup(this.$route.query.id)
} else this.injectJWeixin("getCurExternalChat").then(() => {
this.wxInvoke(['getCurExternalChat', {}, res => {
if (res?.err_msg == 'getCurExternalChat:ok') {
this.groupId = res.chatId
this.getGroup(res.chatId)
}
}])
})
},
getGroup(id) {
this.$http.post("/app/wxcp/wxgroup/getDetail", null, {
params: {id}
}).then(res => {
if (res?.data) {
this.detail = res.data
}
})
},
handleWechat({userId, type}) {
this.injectJWeixin('openUserProfile').then(() => {
this.wxInvoke(['openUserProfile', {
type,
userid: userId
}, () => 0])
})
}
},
created() {
this.getContact()
}
}
</script>
<style lang="scss" scoped>
.group-resident {
width: 100%;
min-height: 100%;
background-color: #F5F5F5;
display: flex;
flex-direction: column;
::v-deep .AiTopFixed {
& > .card {
margin-top: 0;
}
}
::v-deep .card {
background-color: #FFFFFF;
padding: 16px 32px;
box-sizing: border-box;
margin-top: 16px;
header {
height: 192px;
display: flex;
align-items: center;
font-size: 36px;
font-weight: 600;
color: #333333;
.u-avatar {
margin-right: 24px;
}
}
::v-deep .u-grid-item-box {
box-sizing: border-box;
padding: 16px !important;
.uni-label-pointer {
width: 100%;
line-height: 40px;
color: #999999;
}
uni-label:last-child {
margin-top: 16px;
font-weight: 600;
color: #333333;
}
}
.statistics {
height: 96px;
display: flex;
align-items: center;
border-top: 1px solid #eee;
margin-top: 16px;
span {
font-size: 28px;
color: #999999
}
label + b {
font-size: 28px;
color: #333333;
}
b {
color: #1365DD !important;
margin: 0 32px 0 16px;
}
}
& > section:first-child {
height: 90px !important;
display: flex;
align-items: center;
}
.wrap {
margin-bottom: 20px;
.item {
height: 176px;
display: flex;
align-items: center;
.info {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
margin-left: 24px;
border-bottom: 1px solid #eee;
.left {
font-size: 36px;
font-weight: 600;
color: #333333;
b {
font-size: 28px;
font-weight: 400;
color: #3C7FC8;
margin-left: 16px;
}
p:last-child {
font-size: 28px;
font-weight: 400;
color: #999999;
margin-top: 8px;
}
}
span {
width: 88px;
height: 56px;
text-align: center;
background: rgba(19, 101, 221, 0.1);
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.02);
border-radius: 4px;
font-size: 28px;
font-weight: 400;
color: #1365DD;
line-height: 56px;
}
}
}
}
}
::v-deep .tag {
height: 56px;
line-height: 56px;
background: #F3F4F7;
border-radius: 6px;
padding: 8px 16px;
margin-right: 16px;
margin-bottom: 16px;
overflow: hidden;
cursor: default;
}
}
</style>

View File

@@ -1,360 +0,0 @@
<template>
<section class="info">
<div class="card">
<div class="baseInfo">
<u-image border-radius="4" :src="top.detail.avatar" width="118" height="118"/>
<div class="fill">
<b>{{ top.detail.name }}</b>
<div v-if="top.detail.type==1" class="wx">@微信</div>
<div v-if="top.detail.type==2">@企业微信</div>
</div>
<div class="certBtn" @tap="handleCert">{{ !isCert ? "实名认证" : "解绑" }}</div>
</div>
<u-row>
<ai-cell class="half" top-label label="来源">{{ $dict.getLabel("wxCustomerAddWay", top.detail.addWay) }}</ai-cell>
<ai-cell class="half" top-label label="添加时间">{{ top.detail.createTime }}</ai-cell>
<ai-cell class="half" top-label label="真实姓名">{{ top.detail.realName }}</ai-cell>
<ai-cell class="half" top-label label="手机号码">{{ resident.phone || "-" }}</ai-cell>
<ai-cell class="half" top-label label="家庭积分">{{ resident.familyIntegral }}</ai-cell>
<ai-cell class="half" top-label label="个人积分">{{ resident.personalIntegral }}</ai-cell>
</u-row>
</div>
<div class="card">
<ai-cell title label="公共标签">
<u-icon label="添加" size="38" name="iconAdd" custom-prefix="iconfont" color="#1365DD"
label-color="#1365DD" @tap="top.showTagManage=true"/>
</ai-cell>
<ai-cell top-label v-for="(op,name) in tagsList" :label="name" :key="name">
<u-row>
<div class="tag" v-for="(tag,j) in op" :key="j">{{ tag }}</div>
</u-row>
</ai-cell>
</div>
<div class="card">
<ai-cell title label="动态"/>
<ai-cell top-label>
<div class="logItem" v-for="item in customLogs" :key="item.id">
<div flex class="column" shrink>
<div class="dot"/>
<div class="line fill"/>
</div>
<div flex class="start column">
<b>{{ $dict.getLabel('wxCustomerLogType', item.type) }}</b>
<span>{{ item.createTime }}</span>
<div v-html="item.content"/>
</div>
</div>
</ai-cell>
</div>
<u-mask :show="dialog" @tap="dialog=false">
<div class="bindCert" @tap.stop>
<b class="title">实名认证</b>
<u-input class="searchInput" v-model="search" clearable placeholder="请输入姓名或身份证号" @input="handleSearch"/>
<div class="residents">
<div flex class="spb" v-for="(op,i) in result" :key="i" @tap="bindCert(op.id)">
<div v-html="op.name"/>
<div v-html="op.idNumber"/>
</div>
</div>
</div>
</u-mask>
<div bottom>
<u-button type="primary" @tap="handleWechat">微信联系</u-button>
<u-button v-if="isMobile" :disabled="!resident.phone" @tap="handleTel">电话联系</u-button>
</div>
</section>
</template>
<script>
import AiCell from "../../components/AiCell";
import UMask from "../../uview/components/u-mask/u-mask";
import UInput from "../../uview/components/u-input/u-input";
import USteps from "../../uview/components/u-steps/u-steps";
import ULine from "../../uview/components/u-line/u-line";
import UButton from "../../uview/components/u-button/u-button";
import {mapActions} from "vuex";
export default {
name: "info",
components: {UButton, ULine, USteps, UInput, UMask, AiCell},
inject: ['top'],
computed: {
resident() {
return this.top.detail?.residentInfo?.resident || {}
},
tagsList() {
let obj = {}
this.top.detail?.tags?.map(e => {
if (e.type == 1 && e?.groupName) {
if (obj?.[e.groupName]) {
obj[e.groupName].push(e.tagName)
} else {
obj[e.groupName] = [e.tagName]
}
}
})
return obj
},
isCert() {
return !!this.top?.detail?.residentInfo
},
isMobile() {
return ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]
.some(e => navigator.userAgent.indexOf(e) > -1)
}
},
data() {
return {
dialog: false,
search: "",
result: [],
customLogs: []
}
},
methods: {
...mapActions(['injectJWeixin', 'wxInvoke']),
searchResident() {
this.$http.post("/app/appresident/check-name", null, {
params: {name: this.search}
}).then(res => {
if (res?.data) {
let reg = new RegExp(this.search, 'g')
this.result = res.data?.map(e => ({
...e,
name: e.name.replace(reg, `<b>${this.search}</b>`),
idNumber: e.idNumber.replace(reg, `<b>${this.search}</b>`),
}))
}
})
},
handleSearch() {
if (this.search?.length >= 2) {
this.searchResident()
} else {
this.result = []
}
},
handleCert() {
if (this.isCert) {
this.$confirm("是否要解绑当前实名认证?").then(() => {
this.$http.post("/app/wxcp/wxcustomer/unBindCustomer2Resident", null, {
params: {residentId: this.resident.id, customerId: this.top.custom}
}).then(res => {
if (res?.code == 0) {
this.$u.toast("解除绑定成功!")
this.top.getContact()
}
})
})
} else this.dialog = true
},
bindCert(residentId) {
this.dialog = false
this.$confirm("是否要绑定该居民?").then(() => {
this.$http.post("/app/wxcp/wxcustomer/bindCustomer2Resident", null, {
params: {residentId, customerId: this.top.custom}
}).then(res => {
if (res?.code == 0) {
this.$u.toast("绑定成功!")
this.top.getContact()
}
}).catch(err => {
this.$u.toast(err)
setTimeout(() => this.dialog = true, 1000)
})
}).catch(() => this.dialog = true)
},
getCustomLog(customerId) {
customerId && this.$http.post("/app/wxcp/wxcustomerlog/listAll", null, {
params: {customerId}
}).then(res => {
if (res?.data) {
this.customLogs = res.data
}
})
},
handleTel() {
location.href = "tel:" + this.resident.phone
},
handleWechat() {
this.wxInvoke(['openUserProfile', {
type: 2,
userid: this.top.custom
}, () => 0])
}
},
created() {
this.$dict.load("wxCustomerAddWay", 'wxCustomerLogType')
this.getCustomLog(this.top.custom)
this.injectJWeixin('openUserProfile')
}
}
</script>
<style lang="scss" scoped>
.info {
padding-bottom: 130px;
.certBtn {
cursor: pointer;
background: $uni-color-primary;
color: #fff;
padding: 8px 16px;
border-radius: 4px;
}
.baseInfo {
height: 186px;
width: 100%;
display: flex;
align-items: center;
.fill {
color: #3C7FC8;
margin-left: 24px;
font-size: 28px;
line-height: 40px;
b {
font-size: 36px;
color: #333;
margin-bottom: 8px;
line-height: 50px;
}
.wx {
color: #2EA222;
}
}
}
::v-deep .AiCell {
&.half {
width: 50%;
}
}
::v-deep .u-form-item {
width: 50%;
min-height: 124px;
.u-form-item--left {
color: #999;
min-height: 40px;
}
.u-form-item--right {
min-height: 0;
margin-top: 16px;
}
}
::v-deep .u-mask {
display: flex;
align-items: center;
justify-content: center;
.bindCert {
width: 600px;
padding: 32px;
min-height: 400px;
background-color: #fff;
display: flex;
flex-direction: column;
color: #333;
}
.residents {
max-height: 780px;
overflow-y: auto;
}
.title {
text-align: center;
font-size: 36px;
}
.searchInput {
margin: 16px 0;
border: 1px solid #D0D4DC;
border-radius: 8px;
padding: 0 16px !important;
flex: 0;
}
.spb {
height: 60px;
cursor: pointer;
padding: 0 16px;
b {
font-size: 32px;
}
&:nth-of-type(2n) {
background: #eee;
}
}
}
::v-deep .logItem {
display: flex;
min-height: 220px;
&:last-of-type {
.line {
display: none;
}
}
& > .column + .column {
margin-left: 16px;
}
.dot {
flex-shrink: 0;
width: 16px;
height: 16px;
background: $uni-color-primary;
border: 8px solid #FFFFFF;
border-radius: 50%;
margin: 8px 0;
}
.line {
width: 4px;
background: #eee;
}
.start {
font-size: 26px;
font-weight: 400;
color: #666;
b {
color: #333;
}
i {
color: $uni-color-primary;
font-style: normal;
}
& > b {
font-size: 32px;
font-weight: bold;
margin-bottom: 8px;
}
& > span {
color: #999;
}
& > div {
margin-top: 16px;
}
}
}
}
</style>

View File

@@ -1,149 +0,0 @@
<template>
<section class="resident">
<ai-loading v-if="!custom&&!error" tips="获取居民信息中..."/>
<ai-result v-else-if="error" status="error" :tips="error"/>
<template v-else>
<tag-manage v-if="showTagManage"/>
<template v-else>
<ai-top-fixed>
<u-tabs :list="tabs" :is-scroll="false" :current="currentType" font-size="32"
bar-width="192" height="96" @change="handleTabClick"/>
</ai-top-fixed>
<component :is="currentTab.comp"/>
</template>
</template>
<ai-back v-if="isNormal&&!showTagManage"/>
</section>
</template>
<script>
import {mapActions} from "vuex";
import Info from "./info";
import Document from "./document";
import TagManage from "./tagManage";
import AiLoading from "../../components/AiLoading";
import AiResult from "../../components/AiResult";
import AiBack from "../../components/AiBack";
import AiTopFixed from "../../components/AiTopFixed";
export default {
name: "resident",
components: {AiTopFixed, AiBack, AiResult, AiLoading, TagManage, Document, Info},
provide() {
return {
top: this
}
},
computed: {
tabs() {
return [
{name: "居民信息", value: 0, comp: Info},
{name: "居民档案", value: 1, comp: Document, hide: !this.detail.residentInfo},
].filter(e => !e.hide)
},
currentTab() {
return this.tabs.find(e => e.value == this.currentType)
},
isNormal() {
return !!this.$route.query.id;
}
},
data() {
return {
currentType: 0,
detail: {},
showTagManage: false,
custom: "",
error: ""
}
},
methods: {
...mapActions(['injectJWeixin', 'wxInvoke']),
handleTabClick(i) {
this.currentType = i
},
getContact() {
if (this.isNormal) {
this.getCustom(this.$route.query.id)
} else {
this.injectJWeixin("getCurExternalContact").then(() => {
this.wxInvoke(['getCurExternalContact', {}, res => {
if (res?.err_msg == 'getCurExternalContact:ok') {
this.getCustom(res.userId)
}
}])
}).catch(({errMsg}) => {
this.error = errMsg
})
}
},
getCustom(id) {
this.$http.post("/app/wxcp/wxcustomer/queryCustomerById", null, {
params: {id}
}).then(ret => {
if (ret?.data) {
this.custom = id
this.detail = ret.data
if (this.detail.type == 2) {
this.error = "只能查看个人微信绑定的居民信息"
}
}
})
}
},
created() {
this.getContact()
}
}
</script>
<style lang="scss" scoped>
.resident {
display: flex;
flex-direction: column;
height: 100%;
background: #F5F5F5;
.error {
font-size: 32px;
color: #666;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
::v-deep .u-scroll-box {
border-bottom: 1px solid #D4D4D4;
.u-tab-bar {
position: absolute;
bottom: -6px;
}
}
::v-deep .card {
background: #fff;
margin-bottom: 16px;
padding: 16px 32px;
}
.half {
width: 50%;
}
::v-deep .tag {
height: 56px;
line-height: 56px;
background: #F3F4F7;
border-radius: 6px;
padding: 8px 16px;
margin-right: 16px;
margin-bottom: 16px;
overflow: hidden;
cursor: default;
}
}
</style>

View File

@@ -1,146 +0,0 @@
<template>
<section class="residentList">
<ai-top-fixed>
<u-search placeholder="请输入昵称、姓名" :show-action="false" search-icon-color="#ccc"
v-model="search.name" @search="page.current=1,getList()"/>
<ai-cell>
<b slot="label" class="title"><i v-html="page.total||0"/>个居民</b>
</ai-cell>
</ai-top-fixed>
<div class="mainPane">
<ai-cell v-for="item in list" :key="item.id" @click.native="showResident(item)">
<template #label>
<ai-image :src="item.avatar" preview/>
</template>
<div class="card wrap start" flex>
<b>{{ item.name }}</b>
<div flex class="tag" v-for="(tag,j) in item.tags" :key="j">{{ tag.tagName }}</div>
<div class="realName" shrink v-html="`真实姓名:${item.realName||'-'}`"/>
</div>
</ai-cell>
</div>
</section>
</template>
<script>
import AiCell from "../../components/AiCell";
import AiImage from "../../components/AiImage";
import AiTopFixed from "../../components/AiTopFixed";
export default {
name: "residentList",
components: {AiTopFixed, AiImage, AiCell},
data() {
return {
page: {current: 1, size: 10, total: 0},
search: {name: ""},
list: []
}
},
methods: {
getList() {
this.$http.post("/app/wxcp/wxcustomer/list", null, {
params: {...this.page, ...this.search, type: 1}
}).then(res => {
if (res?.data) {
if (this.page.current > 1) {
this.list = [...this.list, ...res.data.records]
} else this.list = res.data.records
this.page.total = res.data.total
}
})
},
reachBottom() {
if (this.page.total > this.list.length) {
this.page.current++
this.getList()
}
},
showResident({id}) {
id && uni.navigateTo({
url: './resident?id=' + id
})
}
},
created() {
this.getList()
}
}
</script>
<style lang="scss" scoped>
.residentList {
::v-deep .AiTopFixed {
b.title {
color: #333;
font-size: 32px;
& > i {
color: #267FCE;
font-style: normal;
margin: 0 4px;
}
}
}
::v-deep .mainPane {
background: #fff;
padding: 0 32px;
.AiCell {
flex-shrink: 0;
justify-content: flex-start;
.content {
flex: 1;
min-width: 0;
max-width: unset;
border-bottom: 1px solid rgba(221, 221, 221, 1);
min-height: 160px;
}
}
.card {
text-align: left;
b {
max-width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 36px;
}
.tag {
justify-content: center;
background: #F3F4F7;
border-radius: 4px;
padding: 0 16px;
font-size: 28px;
font-weight: 400;
color: #333;
margin-left: 16px;
margin-bottom: 16px;
height: 56px;
}
.realName {
width: 100%;
margin-top: 8px;
font-size: 28px;
font-weight: 400;
color: #999;
}
}
.AiImage {
margin-right: 24px;
image {
width: 112px;
height: 112px;
}
}
}
}
</style>

View File

@@ -1,258 +0,0 @@
<template>
<div class="resident-statistical">
<u-tabs :list="tabs" :is-scroll="false" :current="currentType" font-size="32"
bar-width="192" height="96" bg-color="#3975C6"
active-color="#fff" inactive-color="#fff" @change="handleChange"/>
<div class="bg" :style="{backgroundImage:'url(' + $cdn + 'dvcp_bg.png' + ')'}"></div>
<div class="card">
<u-row justify="between">
<div class="item" v-for="(item,index) in cardList" :key="index">
<span :style="{color:item.color} ">{{ item.value }}</span>
<span>{{ item.label }}</span>
</div>
</u-row>
</div>
<div class="chart">
<div id="chart"></div>
</div>
</div>
</template>
<script>
import echarts from "echarts"
import {mapActions} from "vuex";
export default {
name: "residentSta",
props: {
isNormal: Boolean
},
data() {
return {
currentType: 0,
groupId: null,
chart: null,
chartData: null
}
},
methods: {
...mapActions(['injectJWeixin', "wxInvoke"]),
handleChange(i) {
this.currentType = i
this.getChart()
},
getChart() {
this.$http.post(this.currentType == 0 ? "/app/wxcp/wxgroup/groupStatistic" : "/app/wxcp/wxcustomerlog/customerStatistic", null, {
params: {
id: this.groupId
}
}).then(res => {
if (res.code == 0) {
this.chartData = res.data
this.initChart()
}
})
},
initChart() {
this.chart = echarts.init(document.getElementById('chart'))
this.setOptions()
},
setOptions() {
const x = Object.keys(this.chartData.list)
const y = Object.values(this.chartData.list)
this.chart.setOption({
backgroundColor: "#F9F9F9",
legend: {
data: this.currentType == 0 ? ["群成员总数", "入群人数", "退群人数"] : ["居民总数", "新增居民数", "流失居民数"],
icon: "rect",
itemWidth: 8,
itemHeight: 8,
itemGap: 10,
textStyle: {
fontSize: 14,
color: "#666666",
lineHeight: 20
},
bottom: 0
},
grid: {
left: 60,
top: "10%",
bottom: "30%",
},
xAxis: {
axisTick: {
show: false
},
axisLine: {
show: false
},
axisLabel: {
marginTop: 10,
rotate: 40,
textStyle: {
fontSize: 12,
color: '#666666'
}
},
data: x.map(e => e.slice(5))
},
yAxis: {
axisTick: {
show: false
},
axisLine: {
show: false
},
axisLabel: {
textStyle: {
fontSize: 12,
color: '#666666'
}
},
},
series: [
{
name: this.currentType == 0 ? "群成员总数" : "居民总数",
type: "line",
itemStyle: {
color: "#4B87FE"
},
data: y.map(e => e.total)
},
{
name: this.currentType == 0 ? "入群人数" : "新增居民数",
type: "line",
itemStyle: {
color: "#32C5FF"
},
data: y.map(e => e.increase)
},
{
name: this.currentType == 0 ? "退群人数" : "流失居民数",
type: "line",
itemStyle: {
color: "#FFAA44"
},
data: y.map(e => e.decrease)
}
]
})
}
},
computed: {
tabs() {
return [
{name: "居民群统计", value: 0},
{name: "居民统计", value: 1},
]
},
currentTab() {
return this.tabs.find(e => e.value == this.currentType)
},
cardList() {
return this.currentType == 0 ? [
{label: "群聊总数", value: this.chartData?.groupSum || "0", color: "#354FC7"},
{label: "群成员总数", value: this.chartData?.today?.total || "0", color: "#868686"},
{label: "今日入群", value: this.chartData?.today?.increase || "0", color: "#5FBA95"},
{label: "今日退群", value: this.chartData?.today?.decrease || "0", color: "#F09535"},
] : [
{label: "居民总数", value: this.chartData?.today?.total || "0", color: "#354FC7"},
{label: "今日新增", value: this.chartData?.today?.increase || "0", color: "#5FBA95"},
{label: "今日流失", value: this.chartData?.today?.decrease || "0", color: "#F09535"},
]
}
},
watch: {
isNormal(v) {
v && this.getChart()
}
},
created() {
if (this.$route.hash == "#dev") {
this.getChart()
} else this.injectJWeixin("getCurExternalChat").then(() => {
return Promise.resolve()
}).then(() => {
this.wxInvoke(['getCurExternalChat', {}, res => {
if (res?.err_msg == 'getCurExternalChat:ok') {
this.groupId = res.chatId
}
this.getChart()
}])
})
}
}
</script>
<style lang="scss" scoped>
.resident-statistical {
display: flex;
flex-direction: column;
background: #F5F5F5;
padding-top: 96px;
::v-deep .u-tabs {
position: fixed;
top: 0;
width: 100%;
z-index: 9;
}
.bg {
height: 340px;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.card {
width: 686px;
height: 232px;
margin: -140px auto 0;
background-color: #FFFFFF;
border-radius: 8px;
display: flex;
align-items: center;
box-sizing: border-box;
padding: 32px;
.u-row {
width: 100%;
.item {
flex: 1;
text-align: center;
font-size: 40px;
font-weight: bold;
color: #354FC7;
& > span {
display: block;
}
& > span:last-child {
font-size: 30px;
font-weight: 500;
color: #999999;
line-height: 42px;
}
}
}
}
.chart {
background-color: #FFFFFF;
margin: 24px 0;
box-sizing: border-box;
padding: 32px;
display: flex;
justify-content: center;
align-items: center;
#chart {
width: 686px;
height: 470px;
}
}
}
</style>

View File

@@ -1,94 +0,0 @@
<template>
<section class="tagManage">
<div class="card" v-for="(group,i) in tags" :key="i">
<ai-cell title :label="group.name"/>
<u-row>
<div class="tag" v-for="(op,j) in group.tagList" :key="j" :class="{selected:selected.includes(op.id)}"
@tap="$u.debounce(handleToggle(op.id))">
{{ op.name }}
</div>
</u-row>
</div>
<ai-back custom @back="top.showTagManage=false"/>
</section>
</template>
<script>
import AiCell from "../../components/AiCell";
import UButton from "../../uview/components/u-button/u-button";
import ULoadingPage from "../../uview/components/u-loading-page/u-loading-page";
import AiBack from "../../components/AiBack";
export default {
name: "tagManage",
inject: ['top'],
components: {AiBack, ULoadingPage, UButton, AiCell},
data() {
return {
tags: []
}
},
computed: {
selected() {
return this.top.groupId ? this.top.detail?.tagList.map(e => e.tagId) : this.top.detail?.tags.map(e => e.tagId)
}
},
methods: {
getTags() {
this.$http.post(this.top.groupId ? "/app/wxcp/wxgroupchattag/listAll" : "/app/wxcp/wxcorptag/listAll", null, {
params: {size: 9999}
}).then(res => {
if (res?.data) {
this.tags = res.data.records
}
})
},
handleToggle(tagId) {
uni.showLoading({
title: '提交中'
});
this.$http.post(this.top.groupId ? "/app/wxcp/wxgroupchattag/markTagForCP" : "/app/wxcp/wxcorptag/markTagForCP", null, {
params: this.top.groupId ? {tagId, groupId: this.top.groupId,} : {tagId, customerId: this.top.custom}
}).then(res => {
uni.hideLoading()
if (res?.code == 0) {
this.$u.toast("操作成功!")
this.getTags()
this.top.getContact()
}
}).catch(err => {
uni.hideLoading()
this.$u.toast(err)
})
}
},
created() {
this.getTags()
}
}
</script>
<style lang="scss" scoped>
.tagManage {
padding-top: 16px;
.tag {
cursor: pointer !important;
&.selected {
background-color: $uni-color-primary !important;
color: #fff
}
&.disabled {
color: #999;
cursor: not-allowed;
}
& + .tag {
margin-left: 16px;
}
}
}
</style>