群发朋友圈
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar">
|
||||
<template #left>
|
||||
<el-button size="small" type="primary" icon="iconfont iconAdd" @click="isShow = true">创建宣发</el-button>
|
||||
<el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd(0, '')">创建宣发</el-button>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
@change="search.current = 1, getList()"
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
<template>
|
||||
<div class="AppAnnounceResident">
|
||||
<!-- <keep-alive :include="['List']"> -->
|
||||
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
|
||||
<!-- </keep-alive> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List'
|
||||
import Add from './components/Add'
|
||||
import Detail from './components/Detail'
|
||||
|
||||
export default {
|
||||
name: 'AppAnnounceResident',
|
||||
label: '群发居民',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Add,
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
|
||||
mounted () {
|
||||
if (this.$route.params.id) {
|
||||
this.component = 'Detail'
|
||||
this.params = {
|
||||
id: this.$route.params.id
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange (data) {
|
||||
if (data.type === 'Add') {
|
||||
this.component = 'Add'
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'Detail') {
|
||||
this.component = 'Detail'
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'list') {
|
||||
this.component = 'List'
|
||||
this.params = data.params
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (data.isRefresh) {
|
||||
this.$refs.component.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.AppAnnounceResident {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,692 +0,0 @@
|
||||
<template>
|
||||
<ai-detail class="AppAnnounceDetail">
|
||||
<template slot="title">
|
||||
<ai-title title="群发详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="基础信息">
|
||||
<template #right>
|
||||
<div class="right-tips" v-if="info.status === '4'">
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
content="任务开始后,3天内15分钟更新1次,3天后访问页面时触发更新,1小时最多刷新1次">
|
||||
<i class="iconfont iconDetails"></i>
|
||||
</el-tooltip>
|
||||
<span>数据更新于{{ info.dataUpdateTime }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="任务名称" isLine :value="info.taskTitle"></ai-info-item>
|
||||
<ai-info-item label="任务状态" isLine>
|
||||
<span :style="{ color: dict.getColor('mstStatus', info.status) }">{{ dict.getLabel('mstStatus', info.status) }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="创建人" isLine>
|
||||
<div class="user">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/user.png" />
|
||||
<span>{{ info.createUserName }}</span>
|
||||
(<span>{{ info.createUserDeptName }}</span>)
|
||||
</div>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="审批人" isLine v-if="info.enableExamine === '1'">
|
||||
<div class="user-wrapper">
|
||||
<div class="user" v-for="(item, index) in info.examines" :key="index">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/user.png" />
|
||||
<span>{{ item.examineUserName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="创建时间" :value="info.createTime"></ai-info-item>
|
||||
<ai-info-item label="群发时间" :value="info.choiceTime"></ai-info-item>
|
||||
<ai-info-item label="群发范围" isLine>
|
||||
<div class="text">
|
||||
<span>{{ info.sendScope === '0' ? '全部' : '按条件筛选的' }}</span>
|
||||
<i>{{ groups.length }}</i>
|
||||
<span>个居民群</span>
|
||||
<em @click="isShowGroups = true">详情</em>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="消息内容" isLine>
|
||||
<div class="msg">
|
||||
<p>{{ content }}</p>
|
||||
<div class="msg-bottom">
|
||||
<div class="left" v-if="fileList.length">
|
||||
<img :src="mapIcon(fileList[0].msgType)" />
|
||||
<span>{{ mapType(fileList[0].msgType) }}{{ fileList[0].mpTitle || fileList[0].name || fileList[0].linkTitle }} 等</span>
|
||||
<i>{{ fileList.length }}</i>
|
||||
<span>个附件</span>
|
||||
</div>
|
||||
<div class="left" v-else>
|
||||
<span>暂无附件</span>
|
||||
</div>
|
||||
<div class="right" @click="isShowPhone = true">预览消息</div>
|
||||
</div>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="成员统计">
|
||||
<template #content>
|
||||
<div class="content-item">
|
||||
<div class="top">
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>计划执行成员</h3>
|
||||
</div>
|
||||
<p>{{ memberInfo.planCount || 0 }}</p>
|
||||
</div>
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>未执行成员</h3>
|
||||
</div>
|
||||
<p>{{ memberInfo.unExecutedCount || 0 }}</p>
|
||||
</div>
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>已执行成员</h3>
|
||||
</div>
|
||||
<p>{{ memberInfo.executedCount || 0 }}</p>
|
||||
</div>
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>无法执行成员</h3>
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
content="由于员工不在可见范围、离职、客户群接收已达到上限等原因,无法执行群发任务的成员总数">
|
||||
<i class="iconfont iconDetails"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<p>{{ memberInfo.cannotExecuteCount || 0 }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div class="bottom-search">
|
||||
<div class="left">
|
||||
<el-radio-group v-model="search1.sendStatus" size="small" @change="search1.current = 1, getMemberInfo()">
|
||||
<el-radio-button size="small" label="0">未执行</el-radio-button>
|
||||
<el-radio-button size="small" label="1">已执行</el-radio-button>
|
||||
<el-radio-button size="small" label="2">无法执行</el-radio-button>
|
||||
</el-radio-group>
|
||||
<ai-picker
|
||||
dialogTitle="选择部门"
|
||||
action="/app/wxcp/wxdepartment/departList"
|
||||
:instance="instance"
|
||||
@pick="e => onUserChange(e, 'search1')" :multiple="false" v-model="user1">
|
||||
<div class="userSelcet">
|
||||
<span style="color: #606266;" v-if="search1.deptartId">{{ name1 }}</span>
|
||||
<span v-else>部门</span>
|
||||
<i class="el-icon-arrow-up" v-if="!search1.deptartId"></i>
|
||||
<i class="el-icon-circle-close" v-if="search1.deptartId" @click.stop="user1 = [], search1.deptartId = '', search1.current = 1, getMemberInfo()"></i>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</div>
|
||||
<el-button :type="isDisabled ? '' : 'primary'" :disabled="isDisabled" @click="sendMsg(0)" v-if="info.status === '4'">{{ isDisabled ? min + '分钟后可再次提醒' : '提醒成员发送' }}</el-button>
|
||||
</div>
|
||||
<ai-table
|
||||
:tableData="tableData1"
|
||||
:col-configs="colConfigs1"
|
||||
:total="total1"
|
||||
border
|
||||
tableSize="small"
|
||||
:current.sync="search1.current"
|
||||
:size.sync="search1.size"
|
||||
@getList="getMemberInfo">
|
||||
<el-table-column slot="user" label="成员" align="left">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="userinfo">
|
||||
<span>{{ row.groupOwnerName }}</span>
|
||||
<span style="color: #999">{{ row.mainDepartmentName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowGroups"
|
||||
width="890px"
|
||||
title="群发范围"
|
||||
@onConfirm="isShowGroups = false">
|
||||
<ai-table
|
||||
:tableData="info.wxGroups"
|
||||
:col-configs="colConfigs3"
|
||||
border
|
||||
tableSize="small"
|
||||
:isShowPagination="false"
|
||||
@getList="() => {}">
|
||||
</ai-table>
|
||||
</ai-dialog>
|
||||
<div class="detail-phone" v-if="isShowPhone">
|
||||
<div class="mask"></div>
|
||||
<Phone :avatar="user.info.avatar" @close="isShowPhone = false" :isShowClose="true" :content="content" :fileList="fileList"></Phone>
|
||||
</div>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import Phone from './Phone'
|
||||
export default {
|
||||
name: 'Detail',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
components: {
|
||||
Phone
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
total1: 0,
|
||||
isShowGroups: false,
|
||||
isShowPhone: false,
|
||||
total2: 0,
|
||||
user1: [],
|
||||
user2: [],
|
||||
name1: '',
|
||||
name2: '',
|
||||
radio1: '未执行',
|
||||
search1: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
deptartId: '',
|
||||
type: 0,
|
||||
sendStatus: '0'
|
||||
},
|
||||
search2: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
deptartId: '',
|
||||
type: 1,
|
||||
sendStatus: '0'
|
||||
},
|
||||
memberInfo: {},
|
||||
groupInfo: {},
|
||||
tableData1: [],
|
||||
fileList: [],
|
||||
tableData2: [],
|
||||
info: {},
|
||||
content: '',
|
||||
currIndex: 0,
|
||||
colConfigs3: [
|
||||
{ prop: 'groupOwnerName', label: '群主' },
|
||||
{ prop: 'groupNames', label: '群名称' }
|
||||
],
|
||||
colConfigs1: [
|
||||
{ slot: 'user', label: '成员' },
|
||||
{ prop: 'groupCount', label: '预计送达居民群', align: 'center' }
|
||||
],
|
||||
groups: [],
|
||||
timer: null,
|
||||
min: 60,
|
||||
isDisabled: false,
|
||||
rejecterId: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getInfo(this.params.id)
|
||||
this.getMemberInfo()
|
||||
this.getGroupInfo()
|
||||
},
|
||||
|
||||
destroyed () {
|
||||
clearInterval(this.timer)
|
||||
},
|
||||
|
||||
methods: {
|
||||
getMemberInfo () {
|
||||
this.instance.post(`/app/appmasssendingtask/detailStatistics`, null, {
|
||||
params: {
|
||||
...this.search1,
|
||||
taskId: this.params.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.tableData1 = res.data.executedList.records
|
||||
this.total1 = res.data.executedList.total
|
||||
this.memberInfo = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onUserChange (e, search) {
|
||||
if (e.length) {
|
||||
search === 'search1' ? this.name1 = e[0].name : this.name2 = e[0].name
|
||||
this[search].deptartId = e[0].id
|
||||
} else {
|
||||
this[search].deptartId = ''
|
||||
search === 'search1' ? this.name1 = '' : this.name2 = ''
|
||||
}
|
||||
|
||||
this[search].current = 1
|
||||
if (search === 'search1') {
|
||||
this.getMemberInfo()
|
||||
} else {
|
||||
this.getGroupInfo()
|
||||
}
|
||||
},
|
||||
|
||||
sendMsg () {
|
||||
this.instance.post(`/app/appmasssendingtask/remindSend?id=${this.params.id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success('提醒成功')
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getGroupInfo () {
|
||||
this.instance.post(`/app/appmasssendingtask/detailStatistics`, null, {
|
||||
params: {
|
||||
...this.search2,
|
||||
taskId: this.params.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.tableData2 = res.data.executedList.records.map(v => {
|
||||
return {
|
||||
...v,
|
||||
groupName: v.groupName || '未命名群聊'
|
||||
}
|
||||
})
|
||||
this.total2 = res.data.executedList.total
|
||||
this.groupInfo = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
countdown () {
|
||||
this.timer = setInterval(() => {
|
||||
const nowTime = this.$moment(new Date())
|
||||
const min = nowTime.diff(this.info.remindTime, 'minute')
|
||||
this.min = (60 - min)
|
||||
|
||||
if (this.min <= 0) {
|
||||
this.isDisabled = false
|
||||
clearInterval(this.timer)
|
||||
} else {
|
||||
this.isDisabled = true
|
||||
}
|
||||
}, 1000)
|
||||
},
|
||||
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/appmasssendingtask/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.info = res.data
|
||||
if (res.data.status === '4' && res.data.remindTime) {
|
||||
this.countdown()
|
||||
}
|
||||
|
||||
const content = res.data.contents.filter(v => v.msgType === '0')
|
||||
|
||||
if (content.length) {
|
||||
this.content = content[0].content
|
||||
}
|
||||
|
||||
this.fileList = res.data.contents.filter(v => v.msgType !== '0').map(v => {
|
||||
return {
|
||||
...v,
|
||||
...v.sysFile
|
||||
}
|
||||
})
|
||||
|
||||
this.info.wxGroups = res.data.wxGroups.map(v => {
|
||||
this.groups.push(...v.groupIds.split(','))
|
||||
|
||||
return {
|
||||
...v,
|
||||
groupIds: v.groupIds.split(',')
|
||||
}
|
||||
})
|
||||
|
||||
if (res.data.examines && res.data.examines.length) {
|
||||
const user = res.data.examines.filter(v => v.examineStatus === '2')
|
||||
|
||||
if (user.length) {
|
||||
this.rejecterId = user[0].examineUserId
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
mapType (type) {
|
||||
return {
|
||||
1: '图片',
|
||||
2: '视频',
|
||||
3: '文件',
|
||||
4: '网站',
|
||||
5: '小程序'
|
||||
}[type]
|
||||
},
|
||||
|
||||
mapIcon (type) {
|
||||
return {
|
||||
1: 'https://cdn.cunwuyun.cn/dvcp/announce/img.png',
|
||||
2: 'https://cdn.cunwuyun.cn/dvcp/announce/video.png',
|
||||
3: 'https://cdn.cunwuyun.cn/dvcp/announce/folder.png',
|
||||
4: 'https://cdn.cunwuyun.cn/dvcp/announce/site.png',
|
||||
5: 'https://cdn.cunwuyun.cn/dvcp/announce/miniapp.png'
|
||||
}[type]
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.AppAnnounceDetail {
|
||||
position: relative;
|
||||
.user-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.detail-phone {
|
||||
position: fixed;
|
||||
left: 0%;
|
||||
top: 0%;
|
||||
z-index: 11;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.mask {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
background: rgba($color: #000000, $alpha: 0.6);
|
||||
}
|
||||
|
||||
:deep( .phone-container ){
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 11;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
.userSelcet {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 215px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin-left: 12px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d0d4dc;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: #26f;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
color: #d0d4dc;
|
||||
transform: rotateZ(180deg);
|
||||
}
|
||||
|
||||
.el-icon-circle-close:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
padding: 0 15px;
|
||||
font-size: 12px;
|
||||
color: $placeholderColor;
|
||||
}
|
||||
}
|
||||
|
||||
.userinfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
|
||||
span:first-child {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
.user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
margin-right: 8px;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
i {
|
||||
color: #2266FF;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
em {
|
||||
margin-left: 8px;
|
||||
color: #2266FF;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.msg {
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
|
||||
p {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: 38px;
|
||||
padding: 0px 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.msg-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 38px;
|
||||
padding: 0 16px;
|
||||
border-top: 1px solid #D0D4DC;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #2266FF;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
color: #2266FF;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .AppAnnounceDetail-title ){
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
height: 100%;
|
||||
line-height: 56px;
|
||||
margin-right: 32px;
|
||||
color: #888888;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
transition: all ease 0.3s;
|
||||
border-bottom: 3px solid transparent;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
color: #222;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #222222;
|
||||
border-bottom: 3px solid #2266FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-item {
|
||||
.top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.top-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
height: 90px;
|
||||
margin-right: 16px;
|
||||
padding: 0 16px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.top-item__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
|
||||
i {
|
||||
margin-left: 4px;
|
||||
color: #8899bb;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #2266FF;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .right-tips ){
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
i {
|
||||
margin-right: 4px;
|
||||
color: #8899bb;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #888888;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,295 +0,0 @@
|
||||
<template>
|
||||
<ai-list class="AppAnnounce">
|
||||
<template slot="title">
|
||||
<ai-title title="群发居民" isShowBottomBorder>
|
||||
<template #sub>
|
||||
<span>管理员统一创建宣发任务,选择要发送的居民群后通知群主发送,群主确认后即可群发到居民群。群主向同一个居民群每天最多可群发10条消息。</span>
|
||||
</template>
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar">
|
||||
<template #left>
|
||||
<el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')">创建宣发</el-button>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
@change="search.current = 1, getList()"
|
||||
placeholder="任务状态"
|
||||
:selectList="dict.getDict('mstStatus')">
|
||||
</ai-select>
|
||||
<el-date-picker
|
||||
v-model="search.startTime"
|
||||
type="date"
|
||||
size="small"
|
||||
value-format="yyyy-MM-dd"
|
||||
@change="search.current = 1, getList()"
|
||||
placeholder="选择群发开始日期">
|
||||
</el-date-picker>
|
||||
<el-date-picker
|
||||
v-model="search.endTime"
|
||||
type="date"
|
||||
size="small"
|
||||
value-format="yyyy-MM-dd"
|
||||
@change="search.current = 1, getList()"
|
||||
placeholder="选择群发结束日期">
|
||||
</el-date-picker>
|
||||
<ai-wechat-selecter :instance="instance" @change="onUserChange" :isMultiple="false" v-model="user">
|
||||
<div class="userSelcet">
|
||||
<span style="color: #606266;" v-if="search.createUserId">{{ name }}</span>
|
||||
<span v-else>创建人</span>
|
||||
<i class="el-icon-arrow-up" v-if="!search.createUserId"></i>
|
||||
<i class="el-icon-circle-close" v-if="search.createUserId" @click.stop="user = [], search.createUserId = '', name = '', search.current = 1, getList()"></i>
|
||||
</div>
|
||||
</ai-wechat-selecter>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.taskTitle"
|
||||
size="small"
|
||||
v-throttle="() => { search.current = 1, getList() }"
|
||||
placeholder="请输入任务名称"
|
||||
clearable
|
||||
@clear="search.current = 1, search.taskTitle = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
v-loading="loading"
|
||||
style="margin-top: 6px; width: 100%;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="user" width="140px" label="创建人" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="userinfo">
|
||||
<span>{{ row.createUserName }}</span>
|
||||
<span style="color: #999">{{ row.createUserDeptName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" width="140px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="remindExamine(row.id)" v-if="['0'].includes(row.status)">催办</el-button>
|
||||
<el-button type="text" @click="cancel(row.id)" v-if="['0'].includes(row.status)">撤回</el-button>
|
||||
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
|
||||
<el-button type="text" @click="toAdd(row.id)" v-if="['1', '3'].includes(row.status)">编辑</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
status: '',
|
||||
createUserId: '',
|
||||
taskTitle: '',
|
||||
startTime: '',
|
||||
endTime: ''
|
||||
},
|
||||
name: '',
|
||||
user: [],
|
||||
tableData: [],
|
||||
loading: false,
|
||||
total: 0,
|
||||
colConfigs: [
|
||||
{ prop: 'taskTitle', label: '任务名称' },
|
||||
{ prop: 'typeName', label: '群发类型', align: 'center' },
|
||||
{ slot: 'user', label: '创建人', openType: 'userName', align: 'center' },
|
||||
{ prop: 'choiceTime', label: '群发时间', align: 'center' },
|
||||
{
|
||||
prop: 'status',
|
||||
align: 'center',
|
||||
label: '状态',
|
||||
render: (h, {row}) => {
|
||||
return h('span', {
|
||||
style: {
|
||||
color: this.dict.getColor('mstStatus', row.status)
|
||||
}
|
||||
}, this.dict.getLabel('mstStatus', row.status))
|
||||
}
|
||||
},
|
||||
{ prop: 'completionRate', label: '任务完成率', align: 'center', formart: v => v ? v === '0.0' ? '0%' : `${v}%` : '-' }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.dict.load('mstStatus', 'mstSendType').then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
onUserChange (e) {
|
||||
if (e.length) {
|
||||
this.name = e[0].name
|
||||
this.search.createUserId = e[0].id
|
||||
} else {
|
||||
this.search.createUserId = ''
|
||||
this.name = ''
|
||||
}
|
||||
|
||||
this.search.current = 1
|
||||
this.getList()
|
||||
},
|
||||
|
||||
getList() {
|
||||
this.loading = true
|
||||
this.instance.post(`/app/appmasssendingtask/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records.map(v => {
|
||||
return {
|
||||
...v,
|
||||
typeName: '群发居民群'
|
||||
}
|
||||
})
|
||||
this.total = res.data.total
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.loading = false
|
||||
})
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
remindExamine (id) {
|
||||
this.$confirm('确认再次通知任务审核人员?').then(() => {
|
||||
this.instance.post(`/app/appmasssendingtask/remindExamine?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('催办成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
cancel (id) {
|
||||
this.$confirm('确认撤回该群发任务?').then(() => {
|
||||
this.instance.post(`/app/appmasssendingtask/cancel?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('撤回成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appmasssendingtask/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
toAdd(id) {
|
||||
this.$emit('change', {
|
||||
type: 'Add',
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toDetail (id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppAnnounce {
|
||||
height: 100%;
|
||||
.userinfo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
|
||||
span:first-child {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.userSelcet {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 215px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d0d4dc;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: #26f;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
color: #d0d4dc;
|
||||
transform: rotateZ(180deg);
|
||||
}
|
||||
|
||||
.el-icon-circle-close:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
padding: 0 15px;
|
||||
font-size: 12px;
|
||||
color: $placeholderColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,344 +0,0 @@
|
||||
<template>
|
||||
<div class="phone-container">
|
||||
<img class="close" @click="$emit('close')" v-if="isShowClose" src="https://cdn.cunwuyun.cn/dvcp/announce/close.png" />
|
||||
<img class="phone" src="https://cdn.cunwuyun.cn/dvcp/announce/phone.png" />
|
||||
<img class="phone-wrapper" src="https://cdn.cunwuyun.cn/dvcp/announce/phone-wrapper.png" />
|
||||
<div class="right-content">
|
||||
<div class="msg-list">
|
||||
<div class="msg-item" v-if="content">
|
||||
<div class="msg-item__left">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/avatar.png" />
|
||||
</div>
|
||||
<div class="msg-item__right">
|
||||
<div class="msg-wrapper msg-text">
|
||||
<p>{{ content }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="msg-item" v-for="item in fileList" :key="item.id">
|
||||
<div class="msg-item__left">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/avatar.png" />
|
||||
</div>
|
||||
<div class="msg-item__right" :class="[['1', '2'].indexOf(item.msgType) !== -1 ? 'left-border' : '']">
|
||||
<div class="msg-wrapper msg-img" v-if="item.msgType === '1'">
|
||||
<img :src="item.imgPicUrl" />
|
||||
</div>
|
||||
<div class="msg-wrapper msg-video" v-if="item.msgType === '2'">
|
||||
<video controls :src="item.url"></video>
|
||||
</div>
|
||||
<div class="msg-wrapper msg-file" v-if="item.msgType === '3'">
|
||||
<div class="msg-left">
|
||||
<h2>{{ item.name }}</h2>
|
||||
<p>{{ item.fileSizeStr }}</p>
|
||||
</div>
|
||||
<img :src="mapIcon(item.name)" />
|
||||
</div>
|
||||
<div class="msg-wrapper msg-link" v-if="item.msgType === '4'">
|
||||
<h2>{{ item.linkTitle }}</h2>
|
||||
<div class="msg-right">
|
||||
<p>{{ item.linkDesc }}</p>
|
||||
<img :src="item.linkPicUrl || 'https://cdn.cunwuyun.cn/dvcp/announce/html.png'" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="msg-wrapper msg-miniapp" v-if="item.msgType === '5'">
|
||||
<h2>{{ item.mpTitle }}</h2>
|
||||
<img :src="item.url" />
|
||||
<div class="msg-bottom">
|
||||
<i>小程序</i>
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/miniapp.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['fileList', 'avatar', 'content', 'isShowClose'],
|
||||
|
||||
watch: {
|
||||
fileList (v) {
|
||||
if (v.length) {
|
||||
setTimeout(() => {
|
||||
document.querySelector('.right-content').scrollTo(0, 999999)
|
||||
}, 800)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
mapIcon (fileName) {
|
||||
if (['.zip', '.rar'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/zip.png'
|
||||
}
|
||||
|
||||
if (['.doc', '.docx'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/world.png'
|
||||
}
|
||||
|
||||
if (['.xls', '.xlsx'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/xls.png'
|
||||
}
|
||||
|
||||
if (['.txt'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/txt.png'
|
||||
}
|
||||
|
||||
if (['.pdf'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/pdf.png'
|
||||
}
|
||||
|
||||
if (['.ppt', '.pptx'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/ppt.png'
|
||||
}
|
||||
},
|
||||
|
||||
getExtension(name) {
|
||||
return name.substring(name.lastIndexOf('.'))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.phone-container {
|
||||
width: 338px;
|
||||
height: 675px;
|
||||
padding: 80px 15px 100px 32px;
|
||||
|
||||
.phone {
|
||||
position: absolute;
|
||||
left: 13px;
|
||||
top: 4px;
|
||||
z-index: 1;
|
||||
width: 314px;
|
||||
height: 647px;
|
||||
}
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 111;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.5s;
|
||||
transform: translate(100%, -50%);
|
||||
|
||||
&:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.phone-wrapper {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
width: 338px;
|
||||
height: 675px;
|
||||
}
|
||||
|
||||
.right-content {
|
||||
position: relative;
|
||||
z-index: 11;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
|
||||
.msg-item {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.msg-item__left {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
margin-right: 16px;
|
||||
border-radius: 4px;
|
||||
flex-shrink: 1;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.msg-item__right {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-right: 6px solid #fff;
|
||||
border-left: 6px solid transparent;
|
||||
border-bottom: 6px solid transparent;
|
||||
border-top: 6px solid transparent;
|
||||
content: " ";
|
||||
transform: translate(-100%, 0%);
|
||||
}
|
||||
|
||||
&.left-border::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.msg-img img {
|
||||
max-width: 206px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.msg-video video {
|
||||
max-width: 206px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.msg-text {
|
||||
max-width: 206px;
|
||||
width: max-content;
|
||||
line-height: 1.3;
|
||||
padding: 12px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
word-break: break-all;
|
||||
font-size: 14px;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
.msg-miniapp {
|
||||
width: 206px;
|
||||
padding: 0 12px;
|
||||
text-align: justify;
|
||||
font-size: 0;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
color: #222222;
|
||||
|
||||
h2 {
|
||||
line-height: 1.2;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
& > img {
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.msg-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
padding: 4px 0;
|
||||
border-top: 1px solid #eee;
|
||||
|
||||
i {
|
||||
margin-right: 4px;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.msg-file {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 206px;
|
||||
padding: 12px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
|
||||
.msg-left {
|
||||
flex: 1;
|
||||
margin-right: 18px;
|
||||
|
||||
h2 {
|
||||
display: -webkit-box;
|
||||
flex: 1;
|
||||
line-height: 16px;
|
||||
margin-bottom: 4px;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #888888;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.msg-link {
|
||||
width: 206px;
|
||||
padding: 12px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
|
||||
h2 {
|
||||
margin-bottom: 4px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.msg-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
p {
|
||||
display: -webkit-box;
|
||||
flex: 1;
|
||||
line-height: 16px;
|
||||
margin-right: 10px;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,759 +0,0 @@
|
||||
<template>
|
||||
<ai-list class="AppAnnounceStatistics">
|
||||
<template slot="content">
|
||||
<div class="statistics-content">
|
||||
<ai-title title="宣发日历"></ai-title>
|
||||
<div class="flex-content">
|
||||
<div class="flex-left">
|
||||
<div class="date-header">
|
||||
<p>{{chooseYear}}年{{chooseMonth}}月</p>
|
||||
<div>
|
||||
<el-date-picker size="small"
|
||||
v-model="searchMonth"
|
||||
type="month" value-format="yyyy-MM"
|
||||
placeholder="选择日期" @change="searchMonthChange">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</div>
|
||||
<el-calendar v-model="calendarDate">
|
||||
<template
|
||||
slot="dateCell"
|
||||
slot-scope="{date, data}" >
|
||||
<div class="flex-date">
|
||||
<span>{{Number(data.day.substring(8, 10))}}</span>
|
||||
<span class="tips" v-if="data.day.substring(5, 7) == chooseMonth && dateList[Number(data.day.substring(8, 10))] && dateList[Number(data.day.substring(8, 10))].taskList.length">{{dateList[Number(data.day.substring(8, 10))].taskList.length}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-calendar>
|
||||
</div>
|
||||
<div class="flex-right">
|
||||
<div class="title">{{chooseMonth}}月{{chooseDay}}日宣发内容</div>
|
||||
<div class="list-content" v-if="taskList.length">
|
||||
<el-timeline >
|
||||
<el-timeline-item v-for="(item, index) in taskList" :key="index">
|
||||
<el-card>
|
||||
<div class="flex-between">
|
||||
<p class="item-title">{{item.taskTitle}}</p>
|
||||
<span class="item-time" v-if="item.choiceTime">{{item.choiceTime.substring(10, 16)}}</span>
|
||||
</div>
|
||||
<div class="item-info item-created">
|
||||
<span class="label">创建人:</span>
|
||||
<ai-open-data type="userName" :openid="item.createUserId" class="name"></ai-open-data>
|
||||
</div>
|
||||
<div class="item-info item-dept">
|
||||
<span class="label">创建部门:</span>
|
||||
<ai-open-data type="departmentName" :openid="item.createUserDept" class="name"></ai-open-data>
|
||||
</div>
|
||||
<div class="flex-between">
|
||||
<!-- <div class="item-info">群发类型:<span>{{$dict.getLabel('mstSendType', item.sendType) || ''}}</span></div> -->
|
||||
<div class="item-info"><span class="label">群发类型:</span><span>群发居民群</span></div>
|
||||
<span class="item-btn" @click="$router.push({name: '357e228ba8e64008ace90d095a7a0dd7', params: { id: item.id }})">详情</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
|
||||
</div>
|
||||
<ai-empty v-if="!taskList.length" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistics-content">
|
||||
<div class="flex-between mar-b16">
|
||||
<ai-title title="宣发效果"></ai-title>
|
||||
<div class="right-search">
|
||||
<div class="time-select" :class="effectType == index ? 'active' : ''" v-for="(item, index) in dateTypeList" :key="index" @click="changeEffectType(index)">{{item}}</div>
|
||||
<ai-picker :instance="instance" @pick="e => onUserChange(e)" :multiple="false" dialogTitle="选择部门" action="/app/wxcp/wxdepartment/departList">
|
||||
<div class="time-select">
|
||||
<span class="dept-name" style="color:#999;" v-if="deptList && !deptList.length">宣发部门</span>
|
||||
<ai-open-data class="dept-name" type="departmentName" :openid="deptList[0].id" v-else/>
|
||||
<i class="el-icon-arrow-down"></i>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line-content">
|
||||
<div class="flex1">
|
||||
<div class="header">
|
||||
<p>累计创建宣发任务数</p>
|
||||
<h2>{{effectData.createCount}}</h2>
|
||||
</div>
|
||||
<div class="chart-content">
|
||||
<div class="chart-title">宣发任务数</div>
|
||||
<div class="chart-box" id="createChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex1">
|
||||
<div class="header">
|
||||
<p>累计执行宣发次数</p>
|
||||
<h2>{{effectData.executeCount}}</h2>
|
||||
</div>
|
||||
<div class="chart-content">
|
||||
<div class="chart-title">宣发次数</div>
|
||||
<div class="chart-box" id="executeChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex1 mar-r0">
|
||||
<div class="header">
|
||||
<p>累计触达人次</p>
|
||||
<h2>{{effectData.receiveCount}}</h2>
|
||||
</div>
|
||||
<div class="chart-content">
|
||||
<div class="chart-title">触达人次</div>
|
||||
<div class="chart-box" id="receiveChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistics-content">
|
||||
<div class="flex-between mar-b16">
|
||||
<ai-title title="宣发明细"></ai-title>
|
||||
<div class="right-search">
|
||||
<div class="time-select" :class="departType == index ? 'active' : ''" v-for="(item, index) in dateTypeList" :key="index" @click="changeDepartType(index)">{{item}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="departBarChart" v-if="isDepartData"></div>
|
||||
<ai-empty v-if="!isDepartData"></ai-empty>
|
||||
</div>
|
||||
|
||||
<ai-dialog :visible.sync="dialogDate" title="选择时间" width="500px" customFooter>
|
||||
<el-date-picker v-model="timeList" size="small" type="daterange" value-format="yyyy-MM-dd"
|
||||
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期">
|
||||
</el-date-picker>
|
||||
<el-button slot="footer" @click="selectDete" type="primary">确认</el-button>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from "echarts";
|
||||
import { mapActions, mapState } from 'vuex';
|
||||
export default {
|
||||
name: 'AppAnnounceResidentStatistics',
|
||||
label: '协同宣发居民统计',
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
calendarDate: new Date(),
|
||||
dateList: {},
|
||||
chooseYear: '',
|
||||
chooseMonth: '',
|
||||
chooseDay: '',
|
||||
searchMonth: '',
|
||||
taskList: [],
|
||||
effectType: 0, // 宣发效果类型 0:近七天、1:近30天、2:近一年、3:自定义
|
||||
effectData: {},
|
||||
createChart: null,
|
||||
executeChart: null,
|
||||
receiveChart: null,
|
||||
departType: 0, // 宣发明细类型 0:近七天、1:近30天、2:近一年、3:自定义
|
||||
dateTypeList: ['近7天', '近30天', '近1年', '自定义'],
|
||||
departData: {},
|
||||
departBarChart: null,
|
||||
dialogDate: false,
|
||||
timeListEffect: '',
|
||||
timeListDepart: '',
|
||||
timeList: '',
|
||||
isEffectTimeSelect: false,
|
||||
deptList: [],
|
||||
selectDeptName: '',
|
||||
isDepartData: true,
|
||||
departBarData: [],
|
||||
type: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
},
|
||||
watch: {
|
||||
calendarDate: function() {
|
||||
var year = '' , month = '', date = ''
|
||||
if(this.calendarDate.length == 9) { // 月份选择器触发
|
||||
year = this.calendarDate.substring(0, 4)
|
||||
month = this.calendarDate.substring(5, 7)
|
||||
date = this.calendarDate.substring(8, 10)
|
||||
}else { // 日历点击
|
||||
year = this.calendarDate.getFullYear();
|
||||
month = this.calendarDate.getMonth() + 1;
|
||||
date = this.calendarDate.getDate()
|
||||
if (month >= 1 && month <= 9) {
|
||||
month = "0" + month;
|
||||
}
|
||||
|
||||
if(this.chooseMonth != month) { // 日历点击不同月
|
||||
this.searchMonth = ''
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.chooseDay = date
|
||||
|
||||
if(this.chooseMonth != month || this.chooseYear != year) { // 不同年/不同月重新请求日历列表
|
||||
this.getCalendarList(year, month)
|
||||
} else {
|
||||
this.getTaskList(date)
|
||||
}
|
||||
|
||||
this.chooseMonth = month
|
||||
this.chooseYear = year
|
||||
|
||||
}
|
||||
},
|
||||
created() {
|
||||
var year = this.calendarDate.getFullYear();
|
||||
var month = this.calendarDate.getMonth() + 1;
|
||||
var date = this.calendarDate.getDate()
|
||||
if (month >= 1 && month <= 9) {
|
||||
month = "0" + month;
|
||||
}
|
||||
this.chooseMonth = month
|
||||
this.chooseYear = year
|
||||
this.chooseDay = date
|
||||
this.getCalendarList(year, month)
|
||||
this.getEffect()
|
||||
this.getDepart()
|
||||
this.dict.load('mstSendType')
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['initOpenData', 'transCanvas']),
|
||||
onUserChange (e) {
|
||||
this.deptList = e
|
||||
this.getEffect()
|
||||
},
|
||||
selectDete() {
|
||||
if(!this.timeList || !this.timeList.length) {
|
||||
return this.$message.error('请选择自定义时间');
|
||||
}
|
||||
|
||||
if(this.isEffectTimeSelect) { //宣发效果
|
||||
this.timeListEffect = this.timeList
|
||||
this.effectType = 3
|
||||
this.getEffect()
|
||||
} else { //宣发明细
|
||||
this.timeListDepart = this.timeList
|
||||
this.departType = 3
|
||||
this.getDepart()
|
||||
}
|
||||
|
||||
this.dialogDate = false
|
||||
},
|
||||
searchMonthChange() {
|
||||
this.calendarDate = this.searchMonth + '-1'
|
||||
},
|
||||
getCalendarList(year, month){
|
||||
this.instance.post(`/app/appmasssendingtask/statisticsCalendar?yyyyMM=${year}${month}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.dateList = res.data
|
||||
this.getTaskList(this.chooseDay)
|
||||
}
|
||||
})
|
||||
},
|
||||
getTaskList(day) {
|
||||
this.taskList = this.dateList[day].taskList
|
||||
},
|
||||
changeEffectType(type) {
|
||||
if(this.effectType != 3) {
|
||||
this.timeList = []
|
||||
}else {
|
||||
this.timeList = this.timeListEffect
|
||||
}
|
||||
if(type == 3) {
|
||||
this.isEffectTimeSelect = true
|
||||
this.dialogDate = true
|
||||
}else {
|
||||
this.effectType = type
|
||||
this.getEffect()
|
||||
}
|
||||
},
|
||||
getEffect() {
|
||||
var startTime = this.timeListEffect[0] || '' , endTime = this.timeListEffect[1] || '', departId = this.deptList[0] || ''
|
||||
this.instance.post(`/app/appmasssendingtask/statisticsEffect?type=${this.effectType}&startTime=${startTime}&endTime=${endTime}&departId=${departId}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.effectData = res.data
|
||||
var xData = [], createData = [], executeData = [], receiveData = []
|
||||
res.data.trend.map(e => {
|
||||
if(this.effectType == 0 || this.effectType == 1) {
|
||||
e.ymd = e.ymd.substring(5, 10)
|
||||
}
|
||||
xData.push(e.ymd)
|
||||
createData.push(e.createCount)
|
||||
executeData.push(e.executeCount)
|
||||
receiveData.push(e.receiveCount)
|
||||
})
|
||||
|
||||
this.setLineChart(xData, createData, 'createChart', ['#2891FF'])
|
||||
this.setLineChart(xData, executeData, 'executeChart', ['#FFB865'])
|
||||
this.setLineChart(xData, receiveData, 'receiveChart', ['#26D52B'])
|
||||
}
|
||||
})
|
||||
},
|
||||
setLineChart(xData, yData, id, colorList) {
|
||||
this[id] = echarts.init(document.querySelector(`#${id}`))
|
||||
var option = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: xData
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
grid: {
|
||||
left: '10px',
|
||||
right: '28px',
|
||||
bottom: '14px',
|
||||
top: '30px',
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
type: "plain"
|
||||
},
|
||||
color: colorList,
|
||||
series: [
|
||||
{
|
||||
data: yData,
|
||||
type: 'line'
|
||||
}
|
||||
]
|
||||
}
|
||||
this[id].setOption(option)
|
||||
},
|
||||
changeDepartType(type) {
|
||||
if(this.departType != 3) {
|
||||
this.timeList = []
|
||||
}else {
|
||||
this.timeList = this.timeListDepart
|
||||
}
|
||||
if(type == 3) {
|
||||
this.isEffectTimeSelect = false
|
||||
this.dialogDate = true
|
||||
}else {
|
||||
this.departType = type
|
||||
this.getDepart()
|
||||
}
|
||||
},
|
||||
getDepart() {
|
||||
var startTime = this.timeListDepart[0] || '' , endTime = this.timeListDepart[1] || ''
|
||||
this.instance.post(`/app/appmasssendingtask/statisticsDepart?type=${this.departType}&startTime=${startTime}&endTime=${endTime}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
if(res.data && res.data.length) {
|
||||
this.isDepartData = true
|
||||
var items = [], xData = [], yData = []
|
||||
res.data.map((item) => {
|
||||
this.departBarData.push(item)
|
||||
var i = {type: 'departmentName', id: item.deptId, corpid: this.user.info.corpId}
|
||||
items.push(i)
|
||||
yData.push(item.taskCount)
|
||||
})
|
||||
|
||||
this.initOpenData({canvas:true})
|
||||
this.transCanvas(items).then((data) => {
|
||||
xData = data.items.map((i) => {
|
||||
return i.data
|
||||
})
|
||||
this.setBarChart(xData, yData)
|
||||
})
|
||||
}else {
|
||||
this.isDepartData = false
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
setBarChart(xData, yData) {
|
||||
this.departBarChart = echarts.init(document.querySelector(`#departBarChart`))
|
||||
var option = {
|
||||
color: ['#2891FF'],
|
||||
grid: {
|
||||
top: '10%',
|
||||
left: '2%',
|
||||
right: '2%',
|
||||
bottom: 90,
|
||||
containLabel: true
|
||||
},
|
||||
// toolbox: {
|
||||
// feature: {
|
||||
// dataZoom: {
|
||||
// yAxisIndex: false
|
||||
// },
|
||||
// saveAsImage: {
|
||||
// pixelRatio: 2
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
},
|
||||
formatter: (data) => {
|
||||
var index = data[0].dataIndex
|
||||
return `<ww-open-data type="departmentName" openid="${this.departBarData[index].deptId}"></ww-open-data><br/>宣发任务数:${data[0].value}`
|
||||
}
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside'
|
||||
},
|
||||
{
|
||||
type: 'slider'
|
||||
}
|
||||
],
|
||||
xAxis: {
|
||||
data: xData,
|
||||
silent: false,
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
splitArea: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
splitArea: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'bar',
|
||||
data: yData,
|
||||
barWidth: 20,
|
||||
barGap: '250%',
|
||||
large: true
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// {
|
||||
// tooltip: {
|
||||
// trigger: 'axis',
|
||||
// axisPointer: {
|
||||
// type: 'shadow'
|
||||
// }
|
||||
// },
|
||||
// grid: {
|
||||
// top: '10%',
|
||||
// left: '2%',
|
||||
// right: '2%',
|
||||
// bottom: '2%',
|
||||
// containLabel: true
|
||||
// },
|
||||
// color: ['#2891FF'],
|
||||
// xAxis: {
|
||||
// type: 'category',
|
||||
// data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
|
||||
// },
|
||||
// yAxis: {
|
||||
// type: 'value'
|
||||
// },
|
||||
// series: [
|
||||
// {
|
||||
// data: [120, 200, 150, 80, 70, 110, 130],
|
||||
// type: 'bar',
|
||||
// barWidth: 20,
|
||||
// barGap: '250%',
|
||||
// }
|
||||
// ]
|
||||
// };
|
||||
this.departBarChart.setOption(option)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppAnnounceStatistics {
|
||||
height: 100%;
|
||||
.flex-between{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.mar-b16{
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.mar-r0{
|
||||
margin-right: 0!important;
|
||||
}
|
||||
.statistics-content{
|
||||
padding: 0 24px 24px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15,15,21,0.1500);
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
.flex-content{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
margin-top: 16px;
|
||||
.flex-left{
|
||||
width: 50%;
|
||||
.date-header{
|
||||
padding: 12px 16px;
|
||||
border: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
p{
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.flex-date{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.tips{
|
||||
display: inline-block;
|
||||
padding: 0 4px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
border-radius: 8px;
|
||||
background: #2891FF;
|
||||
font-size: 12px;
|
||||
font-family: ArialMT;
|
||||
color: #FFF;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
.flex-right{
|
||||
width: 50%;
|
||||
margin-left: 16px;
|
||||
border: 1px solid #eee;
|
||||
.title{
|
||||
line-height: 56px;
|
||||
border-bottom: 1px solid #EEE;
|
||||
padding-left: 16px;
|
||||
font-size: 16px;
|
||||
font-family: MicrosoftYaHeiSemibold;
|
||||
color: #333;
|
||||
}
|
||||
.list-content{
|
||||
padding: 16px;
|
||||
height: 339px;
|
||||
box-sizing: border-box;
|
||||
overflow-y: scroll;
|
||||
background-color: #F9F9F9;
|
||||
box-sizing: border-box;
|
||||
.item-title{
|
||||
width: calc(100% - 100px);
|
||||
word-break: break-all;
|
||||
margin-bottom: 8px;
|
||||
font-size: 16px;
|
||||
font-family: MicrosoftYaHeiSemibold;
|
||||
color: #222;
|
||||
line-height: 24px;
|
||||
}
|
||||
.item-time{
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
font-size: 16px;
|
||||
font-family: ArialMT;
|
||||
color: #888;
|
||||
line-height: 24px;
|
||||
}
|
||||
.item-info{
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
font-family: MicrosoftYaHei;
|
||||
color: #222;
|
||||
line-height: 22px;
|
||||
span{
|
||||
display: inline-block;
|
||||
color: #222;
|
||||
word-break: break-all;
|
||||
// vertical-align: text-top;
|
||||
}
|
||||
.label{
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
.item-created{
|
||||
width: 152px;
|
||||
margin-bottom: 4px;
|
||||
.label{
|
||||
width: 56px;
|
||||
}
|
||||
.name{
|
||||
width: calc(100% - 56px);
|
||||
}
|
||||
}
|
||||
.item-dept{
|
||||
width: calc(100% - 152px);
|
||||
.label{
|
||||
width: 70px;
|
||||
}
|
||||
.name{
|
||||
width: calc(100% - 70px);
|
||||
}
|
||||
}
|
||||
.item-btn{
|
||||
color: #26f;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.right-search{
|
||||
margin-top: 10px;
|
||||
div{
|
||||
display: inline-block;
|
||||
}
|
||||
.time-select{
|
||||
font-size: 14px;
|
||||
font-family: MicrosoftYaHei;
|
||||
color: #222;
|
||||
line-height: 22px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
margin-right: 8px;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
.dept-name{
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
height: 22px;
|
||||
overflow:hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.el-icon-arrow-down{
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.active{
|
||||
border: 1px solid #26f;
|
||||
color: #26f;
|
||||
}
|
||||
}
|
||||
.line-content{
|
||||
display: flex;
|
||||
.flex1{
|
||||
flex: 1;
|
||||
margin-right: 16px;
|
||||
.header{
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
height: 90px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 16px;
|
||||
p{
|
||||
font-size: 14px;
|
||||
font-family: MicrosoftYaHeiSemibold;
|
||||
color: #222;
|
||||
line-height: 22px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
h2{
|
||||
font-size: 24px;
|
||||
font-family: DINAlternate-Bold, DINAlternate;
|
||||
font-weight: bold;
|
||||
color: #26F;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.chart-content{
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
box-sizing: border-box;
|
||||
.chart-title{
|
||||
font-size: 16px;
|
||||
font-family: MicrosoftYaHeiSemibold;
|
||||
color: #333;
|
||||
line-height: 24px;
|
||||
}
|
||||
.chart-box{
|
||||
width: 100%;
|
||||
height: 280px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#departBarChart{
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
:deep( .el-calendar-table:not(.is-range) td.next),
|
||||
:deep( .el-calendar-table:not(.is-range) td.prev ){
|
||||
color: #ccc;
|
||||
}
|
||||
:deep( .el-calendar-table .el-calendar-day){
|
||||
height: 48px;
|
||||
line-height: 32px;
|
||||
padding-left: 12px;
|
||||
font-size: 14px;
|
||||
font-family: ArialMT;
|
||||
}
|
||||
.el-calendar-table:not(.is-range) td .current{
|
||||
color: #888;
|
||||
}
|
||||
:deep( .el-calendar__header){
|
||||
display: none;
|
||||
}
|
||||
:deep( .el-calendar__body){
|
||||
padding: 0;
|
||||
}
|
||||
:deep( .el-calendar-table thead th:nth-of-type(1)){
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-calendar-table thead th:nth-of-type(7)){
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-calendar-table tr td:first-child ){
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-calendar-table tr:first-child td ){
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-calendar-table td ){
|
||||
border-bottom: 1px solid #eee;
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-timeline-item__timestamp.is-top){
|
||||
margin-bottom: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
:deep( .el-timeline-item__node){
|
||||
background-color: #26F;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
left: 1px;
|
||||
}
|
||||
:deep( .el-card){
|
||||
border: none;
|
||||
}
|
||||
:deep( .el-card__body){
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .ai-list__content ){
|
||||
padding: 0!important;
|
||||
|
||||
.ai-list__content--right-wrapper {
|
||||
background: transparent!important;
|
||||
box-shadow: none!important;
|
||||
margin: 0!important;
|
||||
padding: 0 0 0!important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .AiPicker){
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
@@ -1,79 +0,0 @@
|
||||
<template>
|
||||
<div class="AppAnnounceWeChat">
|
||||
<!-- <keep-alive :include="['List']"> -->
|
||||
<component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component>
|
||||
<!-- </keep-alive> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from './components/List'
|
||||
import Add from './components/Add'
|
||||
import Detail from './components/Detail'
|
||||
|
||||
export default {
|
||||
name: 'AppAnnounceWeChat',
|
||||
label: '群发朋友圈',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
component: 'List',
|
||||
params: {},
|
||||
include: []
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
Add,
|
||||
List,
|
||||
Detail
|
||||
},
|
||||
|
||||
mounted () {
|
||||
if (this.$route.params.id) {
|
||||
this.component = 'Detail'
|
||||
this.params = {
|
||||
id: this.$route.params.id
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange (data) {
|
||||
if (data.type === 'Add') {
|
||||
this.component = 'Add'
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'Detail') {
|
||||
this.component = 'Detail'
|
||||
this.params = data.params
|
||||
}
|
||||
|
||||
if (data.type === 'list') {
|
||||
this.component = 'List'
|
||||
this.params = data.params
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (data.isRefresh) {
|
||||
this.$refs.component.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.AppAnnounceWeChat {
|
||||
height: 100%;
|
||||
background: #F3F6F9;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -1,936 +0,0 @@
|
||||
<template>
|
||||
<ai-detail class="AppAnnounceAdd">
|
||||
<template slot="title">
|
||||
<ai-title :title="id ? '编辑群发朋友圈' : '添加群发朋友圈'" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<div class="AppAnnounceDetail-container">
|
||||
<el-form ref="form" class="left" :model="form" label-width="110px" label-position="right">
|
||||
<ai-card title="基本信息">
|
||||
<template #content>
|
||||
<div class="ai-form">
|
||||
<el-form-item label="任务名称" prop="taskTitle" style="width: 100%;" :rules="[{ required: true, message: '请输入任务名称', trigger: 'blur' }]">
|
||||
<el-input size="small" placeholder="请输入任务名称" v-model="form.taskTitle" :maxlength="15" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="发送范围" style="width: 100%;" prop="sendScope" :rules="[{ required: true, message: '请选择发送范围', trigger: 'change' }]">
|
||||
<el-radio-group v-model="form.sendScope" @change="onScopeChange">
|
||||
<el-radio label="0">全部居民群</el-radio>
|
||||
<el-radio label="1">按部门选择</el-radio>
|
||||
<el-radio label="2">按网格选择</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="发送居民" v-if="form.sendScope !== '0'" prop="wxGroupsName" style="width: 100%;" :rules="[{ required: true, message: '请选择发送居民', trigger: 'change' }]">
|
||||
<ai-picker
|
||||
:instance="instance"
|
||||
multiple
|
||||
:dialogTitle="form.sendScope === '2' ? '选择网格' : '选择部门'"
|
||||
:ops="{label: form.sendScope === '2' ? 'girdName' : 'name'}"
|
||||
:pageTitle="form.sendScope === '2' ? '网格' : '部门'"
|
||||
:action="form.sendScope === '1' ? '/app/wxcp/wxdepartment/departList' : '/app/appgirdinfo/girdList'"
|
||||
v-model="form.filterCriteria"
|
||||
@pick="onPick"
|
||||
@change="onSelcetChange">
|
||||
<div class="AppAnnounceDetail-select">
|
||||
<el-input size="small" class="AppAnnounceDetail-select__input" placeholder="请选择..." disabled v-model="form.wxGroupsName"></el-input>
|
||||
<div class="select-left" v-if="form.executorList.length">
|
||||
<span v-for="(item, index) in form.executorList" :key="index" v-if="index < 9">{{ item.executorName }}</span>
|
||||
<em v-if="form.executorList.length > 9">等{{ form.executorList.length }}个</em>
|
||||
</div>
|
||||
<i v-if="!form.executorList.length">请选择</i>
|
||||
<div class="select-right">{{ form.filterCriteria.length ? '重新选择' : '选择' }}</div>
|
||||
</div>
|
||||
</ai-picker>
|
||||
<div class="tips">
|
||||
<p>消息预计送达居民群数:</p>
|
||||
<span>{{ groupLen }}</span>
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
content="将由指定群主发送给TA作为群主的所有的群,由于企业微信限制,当超过1000个时将只发送到最近活跃的1000个群">
|
||||
<i class="iconfont iconModal_Warning"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="居民标签" style="width: 100%" v-if="form.sendScope !== '0'" prop="wxGroupsName">
|
||||
<div class="AppAnnounceDetail-select" @click="isShowTags = true">
|
||||
<el-input class="AppAnnounceDetail-select__input" size="small" placeholder="请选择..." v-model="form.filterTagsName"></el-input>
|
||||
<div class="select-left" v-if="form.filterTags.length">
|
||||
<span v-for="(item, index) in form.filterTags" :key="index">{{ item.name }}</span>
|
||||
</div>
|
||||
<i v-if="!form.filterTags.length">请选择</i>
|
||||
<div class="select-right">{{ form.filterTags.length ? '重新选择' : '选择' }}</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="发送内容" prop="content" style="width: 100%;" :rules="[{ required: true, message: '请输入发送内容', trigger: 'blur' }]">
|
||||
<el-input size="small" type="textarea" :rows="6" maxlength="1300" show-word-limit placeholder="请输入文本内容..." v-model="form.content"></el-input>
|
||||
<div class="add">
|
||||
<div class="fileList" v-if="fileList.length">
|
||||
<div class="add-item" v-for="(item, index) in fileList" :key="index">
|
||||
<div class="left">
|
||||
<img :src="mapIcon(item.msgType)"/>
|
||||
<span>{{ item.mpTitle || item.name || item.linkTitle }}</span>
|
||||
</div>
|
||||
<i @click="removeFile(index)">删除</i>
|
||||
</div>
|
||||
</div>
|
||||
<el-popover
|
||||
placement="top"
|
||||
width="200"
|
||||
offset="0"
|
||||
trigger="hover">
|
||||
<div class="add-item" slot="reference" style="width: max-content;">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/add.png"/>
|
||||
<span style="color: #2266FF; font-size: 12px;">添加附件类型</span>
|
||||
</div>
|
||||
<div class="AppAnnounceDetail-content-wrapper">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
multiple
|
||||
:file-list="fileList"
|
||||
:show-file-list="false"
|
||||
:before-upload="v => handleChange(v, 10, '.jpg,.png,.jpeg')"
|
||||
:limit="9"
|
||||
action="/app/wxcp/upload/uploadFile"
|
||||
accept=".jpg,.png,.jpeg"
|
||||
:on-exceed="onExceed"
|
||||
:http-request="v => submitUpload(v, '1')">
|
||||
<div class="content-item" trigger>
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/big-img.png"/>
|
||||
<p>图片</p>
|
||||
</div>
|
||||
</el-upload>
|
||||
<el-upload
|
||||
ref="upload"
|
||||
multiple
|
||||
:file-list="fileList"
|
||||
:show-file-list="false"
|
||||
:before-upload="v => handleChange(v, 10, '.mp4')"
|
||||
:limit="9"
|
||||
action="/app/wxcp/upload/uploadFile"
|
||||
accept=".mp4"
|
||||
:on-exceed="onExceed"
|
||||
:http-request="v => submitUpload(v, '2')">
|
||||
<div class="content-item" trigger>
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/big-video.png"/>
|
||||
<p>视频</p>
|
||||
</div>
|
||||
</el-upload>
|
||||
<div class="content-item" @click="isShowAddLink = true">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/site.png"/>
|
||||
<p>网页</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
<div class="tips">
|
||||
<em>从本地上传,图片最大支持10MB,支持JPG,PNG格式;视频最大支持10MB,支持MP4格式;文件最大支持20MB</em>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="宣发审批" prop="enableExamine" style="width: 100%;" :rules="[{ required: true, message: '请输入任务名称', trigger: 'blur' }]">
|
||||
<el-switch
|
||||
v-model="form.enableExamine"
|
||||
active-value="1"
|
||||
inactive-value="0"
|
||||
active-text="开启后,创建的群发任务需要审批人进行审批">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.enableExamine === '1'" label="审批人员" prop="examines" style="width: 100%;" :rules="[{ required: true, message: '请选择审批人员', trigger: 'change' }]">
|
||||
<ai-wechat-selecter :instance="instance" v-model="form.examines" @change="onUserChange">
|
||||
<div class="AppAnnounceDetail-select">
|
||||
<el-input class="AppAnnounceDetail-select__input" size="small" placeholder="请选择..." v-model="form.examinesName"></el-input>
|
||||
<div class="select-left" v-if="form.examines.length">
|
||||
<span v-for="(item, index) in form.examines" :key="index">{{ item.name }}</span>
|
||||
</div>
|
||||
<i v-if="!form.examines.length">请选择</i>
|
||||
<div class="select-right">{{ form.examines.length ? '重新选择' : '选择' }}</div>
|
||||
</div>
|
||||
</ai-wechat-selecter>
|
||||
</el-form-item>``
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
</el-form>
|
||||
<div class="right">
|
||||
<Phone :avatar="user.info.avatar" @close="isShowPhone = false" :isShowClose="false" :content="form.content" :fileList="fileList"></Phone>
|
||||
</div>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowAddLink"
|
||||
width="920px"
|
||||
title="链接消息"
|
||||
@close="onClose"
|
||||
@onConfirm="onLinkConfirm">
|
||||
<el-form ref="linkForm" :model="linkForm" label-width="110px" label-position="right">
|
||||
<div class="ai-form">
|
||||
<el-form-item label="标题" style="width: 100%;" prop="linkTitle" :rules="[{ required: true, message: '请输入标题', trigger: 'blur' }]">
|
||||
<el-input
|
||||
size="small"
|
||||
placeholder="请输入标题"
|
||||
maxlength="42"
|
||||
show-word-limit
|
||||
v-model="linkForm.linkTitle">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="链接" style="width: 100%;" prop="linkUrl" :rules="[{ required: true, message: '请输入链接', trigger: 'blur' }]">
|
||||
<el-input
|
||||
size="small"
|
||||
placeholder="请输入链接"
|
||||
maxlength="682"
|
||||
show-word-limit
|
||||
v-model="linkForm.linkUrl">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述" style="width: 100%;" prop="linkDesc">
|
||||
<el-input
|
||||
size="small"
|
||||
placeholder="请输入描述"
|
||||
maxlength="170"
|
||||
show-word-limit
|
||||
v-model="linkForm.linkDesc">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="封面图" prop="linkPicUrl" style="width: 100%;">
|
||||
<ai-uploader :instance="instance" v-model="linkForm.linkPicUrl" :limit="1"></ai-uploader>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowDate"
|
||||
width="590px"
|
||||
title="定时发送"
|
||||
customFooter>
|
||||
<el-form ref="dateForm" :model="dateForm" label-width="130px" label-position="right">
|
||||
<div class="ai-form">
|
||||
<el-form-item label="定时发送时间" style="width: 100%;" prop="choiceTime" :rules="[{ required: true, message: '请选择定时发送时间', trigger: 'change' }]">
|
||||
<el-date-picker
|
||||
style="width: 100%;"
|
||||
v-model="dateForm.choiceTime"
|
||||
type="datetime"
|
||||
size="small"
|
||||
:picker-options="pickerOptions"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择定时发送时间">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="onClose">取消</el-button>
|
||||
<el-button @click="onDateForm" type="primary" :loading="isLoading2" style="width: 92px;">确认</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowTags"
|
||||
width="800px"
|
||||
title="标签'"
|
||||
@close="onClose"
|
||||
@onConfirm="onTagsConfirm">
|
||||
<div class="tags">
|
||||
<div class="tag-item" v-for="(item, index) in tags" :key="index">
|
||||
<h2>{{ item.name }}</h2>
|
||||
<div class="tag-item__right">
|
||||
<el-button
|
||||
:type="chooseTags.map(v => v.id).indexOf(item.id) === -1 ? '' : 'primary'"
|
||||
v-for="(item, index) in item.tagList"
|
||||
@click="choose(item)"
|
||||
:key="index">
|
||||
{{ item.name }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
<el-button type="primary" @click="confirm(0)" :loading="isLoading1" style="width: 120px;">通知成员发送</el-button>
|
||||
<el-button type="primary" @click="confirm(1)">定时发送</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Phone from './Phone'
|
||||
import {mapActions, mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Add',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
components: {
|
||||
Phone
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
info: {},
|
||||
department: [],
|
||||
isLoading1: false,
|
||||
isLoading2: false,
|
||||
isShowTags: false,
|
||||
fileList: [],
|
||||
isShowAddLink: false,
|
||||
isShowAddMiniapp: false,
|
||||
isShowDate: false,
|
||||
isLoading: false,
|
||||
linkForm: {
|
||||
linkPicUrl: [],
|
||||
linkDesc: '',
|
||||
linkTitle: '',
|
||||
linkUrl: ''
|
||||
},
|
||||
dateForm: {
|
||||
choiceTime: ''
|
||||
},
|
||||
form: {
|
||||
content: '',
|
||||
choiceTime: '',
|
||||
contents: [],
|
||||
enableExamine: '0',
|
||||
examines: [],
|
||||
executorList: [],
|
||||
wxGroupsName: '',
|
||||
sendScope: '0',
|
||||
sendType: 0,
|
||||
name: '',
|
||||
filterTags: [],
|
||||
filterTagsName: '',
|
||||
filterCriteria: [],
|
||||
taskTitle: '',
|
||||
examinesName: ''
|
||||
},
|
||||
girdNames: '',
|
||||
id: '',
|
||||
tagsList: [],
|
||||
tags: [],
|
||||
chooseTags: [],
|
||||
pickerOptions: {
|
||||
disabledDate: e => {
|
||||
return e.getTime() < (Date.now() - 60 * 1000 * 60 * 24)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
|
||||
groupLen() {
|
||||
return this.form.executorList.length
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.params && this.params.id) {
|
||||
this.id = this.params.id
|
||||
this.getInfo(this.params.id)
|
||||
} else {
|
||||
this.getWxGroups()
|
||||
}
|
||||
|
||||
this.getTags()
|
||||
},
|
||||
|
||||
methods: {
|
||||
...mapActions(['initOpenData', 'transCanvas']),
|
||||
|
||||
choose (e) {
|
||||
const index = this.chooseTags.map(v => v.id).indexOf(e.id)
|
||||
if (index === -1) {
|
||||
this.chooseTags.push(e)
|
||||
} else {
|
||||
this.chooseTags.splice(index, 1)
|
||||
}
|
||||
},
|
||||
|
||||
getTags () {
|
||||
this.instance.post(`/app/wxcp/wxcorptag/listAll?size=100`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tags = res.data.records
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onTagsConfirm () {
|
||||
this.form.filterTagsName = this.chooseTags.map(v => v.name).join(',')
|
||||
this.form.filterTags = [...this.chooseTags]
|
||||
|
||||
this.isShowTags = false
|
||||
},
|
||||
|
||||
getInfo(id) {
|
||||
this.instance.post(`/app/whchatmomentstask/customerTasKDetail?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form = {
|
||||
...this.form,
|
||||
...res.data,
|
||||
wxGroupsName: '1',
|
||||
filterCriteria: res.data.filterCriteria.split(',')
|
||||
}
|
||||
|
||||
if (res.data.girdNames) {
|
||||
this.girdNames = res.data.girdNames.split(',')
|
||||
}
|
||||
|
||||
this.dateForm.choiceTime = ''
|
||||
|
||||
if (res.data.examines && res.data.examines.length) {
|
||||
this.form.examines = res.data.examines.map(v => {
|
||||
return {
|
||||
...v,
|
||||
wxOpenUserId: v.examineUserId,
|
||||
id: v.examineUserId,
|
||||
name: v.examineUserName
|
||||
}
|
||||
})
|
||||
this.form.examinesName = '1'
|
||||
}
|
||||
|
||||
|
||||
const content = res.data.contents.filter(v => v.msgType === '0')
|
||||
|
||||
if (content.length) {
|
||||
this.$set(this.form, 'content', content[0].content)
|
||||
}
|
||||
|
||||
this.fileList = res.data.contents.filter(v => v.msgType !== '0').map(v => {
|
||||
return {
|
||||
...v,
|
||||
...v.sysFile
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onUserChange(e) {
|
||||
if (e.length) {
|
||||
this.form.examinesName = '1'
|
||||
} else {
|
||||
this.form.examinesName = ''
|
||||
}
|
||||
},
|
||||
|
||||
onScopeChange(e) {
|
||||
this.form.filterCriteria = []
|
||||
this.form.executorList = []
|
||||
this.girdNames = ''
|
||||
|
||||
if (e === '0') {
|
||||
this.getWxGroups()
|
||||
} else {
|
||||
this.form.filterCriteria = []
|
||||
}
|
||||
},
|
||||
|
||||
onPick(e) {
|
||||
if (this.form.sendScope === '2' && e.length) {
|
||||
this.girdNames = e.map(v => v.girdName)
|
||||
}
|
||||
},
|
||||
|
||||
onSelcetChange(e) {
|
||||
if (e.length) {
|
||||
this.form.wxGroupsName = '1'
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.getWxGroups()
|
||||
})
|
||||
} else {
|
||||
this.form.wxGroupsName = ''
|
||||
this.form.executorList = []
|
||||
}
|
||||
},
|
||||
|
||||
getWxGroups() {
|
||||
this.instance.post(`/app/whchatmomentstask/getSendScope`, {
|
||||
sendScope: this.form.sendScope,
|
||||
filterTags: this.form.filterTags.map(v => v.id).join(','),
|
||||
filterCriteria: this.form.filterCriteria.join(','),
|
||||
taskType: 0
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.form.executorList = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onLinkConfirm() {
|
||||
this.$refs.linkForm.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.fileList.length) {
|
||||
this.$message.error('最多支持9张图片,或1个视频,或1个链接')
|
||||
return false
|
||||
}
|
||||
|
||||
this.fileList.push({
|
||||
...this.linkForm,
|
||||
linkPicUrl: this.linkForm.linkPicUrl.length ? this.linkForm.linkPicUrl[0].url : '',
|
||||
msgType: '4'
|
||||
})
|
||||
|
||||
this.isShowAddLink = false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onClose() {
|
||||
this.linkForm.linkPicUrl = []
|
||||
this.linkForm.linkDesc = ''
|
||||
this.linkForm.linkTitle = ''
|
||||
this.linkForm.linkUrl = ''
|
||||
this.dateForm.choiceTime = ''
|
||||
|
||||
this.isShowDate = false
|
||||
},
|
||||
|
||||
removeFile(index) {
|
||||
this.fileList.splice(index, 1)
|
||||
},
|
||||
|
||||
mapIcon(type) {
|
||||
return {
|
||||
1: 'https://cdn.cunwuyun.cn/dvcp/announce/img.png',
|
||||
2: 'https://cdn.cunwuyun.cn/dvcp/announce/video.png',
|
||||
3: 'https://cdn.cunwuyun.cn/dvcp/announce/folder.png',
|
||||
4: 'https://cdn.cunwuyun.cn/dvcp/announce/site.png',
|
||||
5: 'https://cdn.cunwuyun.cn/dvcp/announce/miniapp.png'
|
||||
}[type]
|
||||
},
|
||||
|
||||
onBeforeUpload(event) {
|
||||
return this.onOverSize(event)
|
||||
},
|
||||
|
||||
getExtension(name) {
|
||||
return name.substring(name.lastIndexOf('.'))
|
||||
},
|
||||
|
||||
handleChange(e, size, accept) {
|
||||
if (accept === '.mp4' && this.fileList.length) {
|
||||
this.$message.error('最多支持9张图片,或1个视频,或1个链接')
|
||||
return false
|
||||
}
|
||||
|
||||
if (accept !== '.mp4' && (this.fileList.map(v => v.msgType).indexOf('2') !== -1 || this.fileList.map(v => v.msgType).indexOf('4') !== -1) ) {
|
||||
this.$message.error('最多支持9张图片,或1个视频,或1个链接')
|
||||
return false
|
||||
}
|
||||
|
||||
const isLt10M = e.size / 1024 / 1024 < size
|
||||
const suffixName = this.getExtension(e.name)
|
||||
const suffixNameList = accept.split(',')
|
||||
|
||||
if (suffixNameList.indexOf(`${suffixName.toLowerCase()}`) === -1) {
|
||||
this.$message.error(`不支持该格式`)
|
||||
return false
|
||||
}
|
||||
|
||||
if (!isLt10M) {
|
||||
this.$message.error(`大小不超过${10}MB!`)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
onExceed() {
|
||||
this.$message.error(`最多上传9个附件`)
|
||||
},
|
||||
|
||||
submitUpload(file, type) {
|
||||
const fileType = {
|
||||
'1': 'image',
|
||||
'2': 'video',
|
||||
'3': 'file'
|
||||
}[type]
|
||||
let formData = new FormData()
|
||||
formData.append('file', file.file)
|
||||
formData.append('attachmentType', 1)
|
||||
formData.append('mediaType', fileType)
|
||||
let loading = this.$loading()
|
||||
this.instance.post(`/app/wxcp/upload/uploadAttachment`, formData, {
|
||||
withCredentials: false
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.fileList.push({
|
||||
...res.data.file,
|
||||
media: res.data.media,
|
||||
msgType: type,
|
||||
sysFileId: res.data.file.id,
|
||||
imgPicUrl: res.data.file.url,
|
||||
mediaId: res.data.media.mediaId
|
||||
})
|
||||
|
||||
this.$message.success('上传成功')
|
||||
}
|
||||
}).finally(() => loading.close())
|
||||
},
|
||||
|
||||
onDateForm() {
|
||||
this.$refs.dateForm.validate((valid) => {
|
||||
if (valid) {
|
||||
if (new Date(this.dateForm.choiceTime).getTime() < Date.now()) {
|
||||
return this.$message.error('定时发送时间不得早于当前时间')
|
||||
} else {
|
||||
this.confirm(1)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
confirm(sendType) {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
if (!this.form.executorList.length) {
|
||||
return this.$message.error('居民群数量不能为0')
|
||||
}
|
||||
|
||||
if (sendType === 1 && !this.dateForm.choiceTime) {
|
||||
this.isShowDate = true
|
||||
return false
|
||||
}
|
||||
|
||||
const contents = [
|
||||
{
|
||||
content: this.form.content,
|
||||
msgType: '0'
|
||||
},
|
||||
...this.fileList
|
||||
]
|
||||
|
||||
if (sendType === 0) {
|
||||
this.isLoading1 = true
|
||||
} else {
|
||||
this.isLoading2 = true
|
||||
}
|
||||
|
||||
this.instance.post(`/app/whchatmomentstask/addOrUpdate`, {
|
||||
...this.form,
|
||||
id: this.params.id,
|
||||
executorList: this.form.executorList,
|
||||
contents,
|
||||
sendType,
|
||||
taskType: 0,
|
||||
filterTags: this.form.filterTags.map(v => v.id).join(','),
|
||||
choiceTime: this.dateForm.choiceTime,
|
||||
filterCriteria: this.form.filterCriteria.join(','),
|
||||
examines: this.form.examines.length ? this.form.examines.map(v => {
|
||||
return {
|
||||
...v,
|
||||
examineUserId: v.id,
|
||||
examineUserName: v.name
|
||||
}
|
||||
}) : []
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.cancel(true)
|
||||
}, 600)
|
||||
} else {
|
||||
this.isLoading1 = false
|
||||
this.isLoading2 = false
|
||||
}
|
||||
|
||||
}).catch(() => {
|
||||
this.isLoading1 = false
|
||||
this.isLoading2 = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancel(isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.el-tooltip__popper.is-dark {
|
||||
max-width: 240px;
|
||||
}
|
||||
.tags {
|
||||
.tag-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-bottom: 30px;
|
||||
padding-top: 30px;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
|
||||
&:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.el-tag {
|
||||
margin-right: 8px;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
h2 {
|
||||
width: 88px;
|
||||
margin-right: 40px;
|
||||
text-align: right;
|
||||
color: #888888;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.AppAnnounceDetail-content-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.content-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
line-height: 1;
|
||||
margin-right: 4px;
|
||||
text-align: center;
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #222;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.AppAnnounceAdd {
|
||||
.ai-detail__content {
|
||||
.ai-detail__content--wrapper {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.ai-form {
|
||||
textarea {
|
||||
border-radius: 4px 4px 0 0!important;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.add {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 14px 16px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 0px 0px 4px 4px;
|
||||
border: 1px solid #D0D4DC;
|
||||
border-top: none;
|
||||
|
||||
.add-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.fileList {
|
||||
margin-bottom: 12px;
|
||||
|
||||
.add-item {
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
font-style: normal;
|
||||
color: red;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.AppAnnounceDetail-container {
|
||||
display: flex;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
padding: 0 20px;
|
||||
overflow: auto;
|
||||
overflow: overlay;
|
||||
|
||||
.left {
|
||||
flex: 1;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.right {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.AppAnnounceDetail-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 32px;
|
||||
line-height: 1;
|
||||
background: #F5F5F5;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #D0D4DC;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: #26f;
|
||||
}
|
||||
|
||||
& > i {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
padding: 0 12px;
|
||||
color: #888888;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
border-right: 1px solid #D0D4DC;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.AppAnnounceDetail-select__input {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.select-right {
|
||||
height: 100%;
|
||||
padding: 0 12px;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.select-left {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex: 1;
|
||||
padding: 5px 0 0px 12px;
|
||||
border-right: 1px solid #D0D4DC;
|
||||
border-radius: 4px 0 0 4px;
|
||||
background: #fff;
|
||||
|
||||
em {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin: 0 4px 5px 0;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
span {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
margin: 0 4px 5px 0;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
color: #222222;
|
||||
background: #F3F4F7;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tips {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: #222222;
|
||||
|
||||
span {
|
||||
margin: 0 3px;
|
||||
color: #2266FF;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #8899bb;
|
||||
}
|
||||
|
||||
em {
|
||||
line-height: 20px;
|
||||
margin-top: 8px;
|
||||
color: #888888;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,657 +0,0 @@
|
||||
<template>
|
||||
<ai-detail class="AppAnnounceDetail">
|
||||
<template slot="title">
|
||||
<ai-title title="群发详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)">
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="基础信息">
|
||||
<template #right>
|
||||
<div class="right-tips" v-if="info.status === '4'">
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
content="任务开始后,3天内15分钟更新1次,3天后访问页面时触发更新,1小时最多刷新1次">
|
||||
<i class="iconfont iconDetails"></i>
|
||||
</el-tooltip>
|
||||
<span>数据更新于{{ info.dataUpdateTime }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="任务名称" isLine :value="info.taskTitle"></ai-info-item>
|
||||
<ai-info-item label="任务状态" isLine>
|
||||
<span :style="{ color: dict.getColor('mstStatus', info.status) }">{{ dict.getLabel('mstStatus', info.status) }}</span>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="创建人" isLine>
|
||||
<div class="user">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/user.png" />
|
||||
<span>{{ info.createUserName }}</span>
|
||||
<span>({{ info.createUserDeptName }})</span>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="审批人" isLine v-if="info.enableExamine === '1'">
|
||||
<div class="user-wrapper">
|
||||
<div class="user" v-for="(item, index) in info.examines" :key="index">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/user.png" />
|
||||
<span>{{ item.examineUserName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="创建时间" :value="info.createTime"></ai-info-item>
|
||||
<ai-info-item label="群发时间" :value="info.choiceTime"></ai-info-item>
|
||||
<ai-info-item label="群发范围" isLine>
|
||||
<div class="text">
|
||||
<span>{{ info.sendScope === '0' ? '全部' : '按条件筛选的' }}</span>
|
||||
<i>{{ info.executorList.length }}</i>
|
||||
<span>个居民</span>
|
||||
<em @click="isShowGroups = true">详情</em>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="消息内容" isLine>
|
||||
<div class="msg">
|
||||
<p>{{ content }}</p>
|
||||
<div class="msg-bottom">
|
||||
<div class="left" v-if="fileList.length">
|
||||
<img :src="mapIcon(fileList[0].msgType)" />
|
||||
<span>{{ mapType(fileList[0].msgType) }}{{ fileList[0].mpTitle || fileList[0].name || fileList[0].linkTitle }} 等</span>
|
||||
<i>{{ fileList.length }}</i>
|
||||
<span>个附件</span>
|
||||
</div>
|
||||
<div class="left" v-else>
|
||||
<span>暂无附件</span>
|
||||
</div>
|
||||
<div class="right" @click="isShowPhone = true">预览消息</div>
|
||||
</div>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="成员统计">
|
||||
<template #content>
|
||||
<div class="content-item">
|
||||
<div class="top">
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>预计执行员工</h3>
|
||||
</div>
|
||||
<p>{{ memberInfo.planCount || 0 }}</p>
|
||||
</div>
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>未执行员工</h3>
|
||||
</div>
|
||||
<p>{{ memberInfo.unExecutedCount || 0 }}</p>
|
||||
</div>
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>已执行员工</h3>
|
||||
</div>
|
||||
<p>{{ memberInfo.executedCount || 0 }}</p>
|
||||
</div>
|
||||
<div class="top-item">
|
||||
<div class="top-item__title">
|
||||
<h3>无法执行员工</h3>
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
content="由于员工不在可见范围、离职、客户群接收已达到上限等原因,无法执行群发任务的成员总数">
|
||||
<i class="iconfont iconDetails"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<p>{{ memberInfo.cannotExecuteCount || 0 }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div class="bottom-search">
|
||||
<div class="left">
|
||||
<el-radio-group v-model="search1.sendStatus" size="small" @change="search1.current = 1, getMemberInfo()">
|
||||
<el-radio-button size="small" label="0">未执行</el-radio-button>
|
||||
<el-radio-button size="small" label="1">已执行</el-radio-button>
|
||||
<el-radio-button size="small" label="2">无法执行</el-radio-button>
|
||||
</el-radio-group>
|
||||
<ai-picker
|
||||
dialogTitle="选择部门"
|
||||
action="/app/wxcp/wxdepartment/departList"
|
||||
:instance="instance"
|
||||
@pick="e => onUserChange(e, 'search1')" :multiple="false" v-model="user1">
|
||||
<div class="userSelcet">
|
||||
<span style="color: #606266;" v-if="search1.deptartId"><ai-open-data type="departmentName" :openid="search1.deptartId"></ai-open-data></span>
|
||||
<span v-else>部门</span>
|
||||
<i class="el-icon-arrow-up" v-if="!search1.deptartId"></i>
|
||||
<i class="el-icon-circle-close" v-if="search1.deptartId" @click.stop="user1 = [], search1.deptartId = '', search1.current = 1, getMemberInfo()"></i>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</div>
|
||||
<el-button :type="isDisabled ? '' : 'primary'" :disabled="isDisabled" @click="sendMsg(0)" v-if="info.status === '4'">{{ isDisabled ? min + '分钟后可再次提醒' : '提醒成员发送' }}</el-button>
|
||||
</div>
|
||||
<ai-table
|
||||
:tableData="tableData1"
|
||||
:col-configs="colConfigs1"
|
||||
:total="total1"
|
||||
border
|
||||
tableSize="small"
|
||||
:current.sync="search1.current"
|
||||
:size.sync="search1.size"
|
||||
@getList="getMemberInfo">
|
||||
<el-table-column slot="user" label="成员" align="left">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="userinfo">
|
||||
<span>{{ row.groupOwnerName }}</span>
|
||||
<span style="color: #999">{{ row.mainDepartmentName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowGroups"
|
||||
width="890px"
|
||||
title="群发范围"
|
||||
@onConfirm="isShowGroups = false">
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="消息发送" isLine :value="info.taskTitle">
|
||||
<div class="text">
|
||||
<span>{{ info.sendScope === '0' ? '全部' : '按条件筛选的' }}</span>
|
||||
<i>{{ info.executorList.length }}</i>
|
||||
<span>个居民</span>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
<ai-info-item label="添加人" isLine :value="userNames"></ai-info-item>
|
||||
<ai-info-item label="标签" isLine>{{ info.filterTagsName || '-' }}</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</ai-dialog>
|
||||
<div class="detail-phone" v-if="isShowPhone">
|
||||
<div class="mask"></div>
|
||||
<Phone :avatar="user.info.avatar" @close="isShowPhone = false" :isShowClose="true" :content="content" :fileList="fileList"></Phone>
|
||||
</div>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import Phone from './Phone'
|
||||
export default {
|
||||
name: 'Detail',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
params: Object
|
||||
},
|
||||
|
||||
components: {
|
||||
Phone
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
total1: 0,
|
||||
isShowGroups: false,
|
||||
isShowPhone: false,
|
||||
user1: [],
|
||||
user2: [],
|
||||
radio1: '未执行',
|
||||
search1: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
deptartId: '',
|
||||
type: 0,
|
||||
sendStatus: '0'
|
||||
},
|
||||
memberInfo: {},
|
||||
groupInfo: {},
|
||||
tableData1: [],
|
||||
fileList: [],
|
||||
tableData2: [],
|
||||
info: {},
|
||||
content: '',
|
||||
currIndex: 0,
|
||||
colConfigs3: [
|
||||
{ prop: 'groupOwnerName', label: '群主' },
|
||||
{ prop: 'groupNames', label: '群名称' }
|
||||
],
|
||||
colConfigs1: [
|
||||
{ slot: 'user', label: '成员' },
|
||||
{ prop: 'groupCount', label: '预计送达居民群', align: 'center' }
|
||||
],
|
||||
groups: [],
|
||||
timer: null,
|
||||
min: 60,
|
||||
isDisabled: false,
|
||||
rejecterId: '',
|
||||
userNames: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getInfo(this.params.id)
|
||||
this.getMemberInfo()
|
||||
},
|
||||
|
||||
destroyed () {
|
||||
clearInterval(this.timer)
|
||||
},
|
||||
|
||||
methods: {
|
||||
getMemberInfo () {
|
||||
this.instance.post(`/app/whchatmomentstask/detailStatistics`, null, {
|
||||
params: {
|
||||
...this.search1,
|
||||
taskId: this.params.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
// this.tableData1 = res.data.executedList.records
|
||||
// this.total1 = res.data.executedList.total
|
||||
this.memberInfo = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onUserChange (e, search) {
|
||||
if (e.length) {
|
||||
this[search].deptartId = e[0].id
|
||||
} else {
|
||||
this[search].deptartId = ''
|
||||
}
|
||||
|
||||
this[search].current = 1
|
||||
this.getMemberInfo()
|
||||
},
|
||||
|
||||
sendMsg () {
|
||||
this.instance.post(`/app/whchatmomentstask/remindExamine?id=${this.params.id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success('提醒成功')
|
||||
this.getInfo(this.params.id)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
countdown () {
|
||||
this.timer = setInterval(() => {
|
||||
const nowTime = this.$moment(new Date())
|
||||
const min = nowTime.diff(this.info.remindTime, 'minute')
|
||||
this.min = (60 - min)
|
||||
|
||||
if (this.min <= 0) {
|
||||
this.isDisabled = false
|
||||
clearInterval(this.timer)
|
||||
} else {
|
||||
this.isDisabled = true
|
||||
}
|
||||
}, 1000)
|
||||
},
|
||||
|
||||
getInfo (id) {
|
||||
this.instance.post(`/app/whchatmomentstask/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.info = res.data
|
||||
if (res.data.status === '4' && res.data.remindTime) {
|
||||
this.countdown()
|
||||
}
|
||||
|
||||
const content = res.data.contents.filter(v => v.msgType === '0')
|
||||
|
||||
if (content.length) {
|
||||
this.content = content[0].content
|
||||
}
|
||||
|
||||
this.fileList = res.data.contents.filter(v => v.msgType !== '0').map(v => {
|
||||
return {
|
||||
...v,
|
||||
...v.sysFile
|
||||
}
|
||||
})
|
||||
|
||||
let userNames = ''
|
||||
res.data.executorList.forEach(e => {
|
||||
userNames = e.executorName + userNames
|
||||
})
|
||||
|
||||
this.userNames = res.data.executorList.map(e => e.executorName).join(',')
|
||||
|
||||
if (res.data.examines && res.data.examines.length) {
|
||||
const user = res.data.examines.filter(v => v.examineStatus === '2')
|
||||
|
||||
if (user.length) {
|
||||
this.rejecterId = user[0].examineUserId
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
mapType (type) {
|
||||
return {
|
||||
1: '图片',
|
||||
2: '视频',
|
||||
3: '文件',
|
||||
4: '网站',
|
||||
5: '小程序'
|
||||
}[type]
|
||||
},
|
||||
|
||||
mapIcon (type) {
|
||||
return {
|
||||
1: 'https://cdn.cunwuyun.cn/dvcp/announce/img.png',
|
||||
2: 'https://cdn.cunwuyun.cn/dvcp/announce/video.png',
|
||||
3: 'https://cdn.cunwuyun.cn/dvcp/announce/folder.png',
|
||||
4: 'https://cdn.cunwuyun.cn/dvcp/announce/site.png',
|
||||
5: 'https://cdn.cunwuyun.cn/dvcp/announce/miniapp.png'
|
||||
}[type]
|
||||
},
|
||||
|
||||
cancel (isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'list',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.AppAnnounceDetail {
|
||||
position: relative;
|
||||
.user-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.detail-phone {
|
||||
position: fixed;
|
||||
left: 0%;
|
||||
top: 0%;
|
||||
z-index: 11;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.mask {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
background: rgba($color: #000000, $alpha: 0.6);
|
||||
}
|
||||
|
||||
:deep( .phone-container ){
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 11;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
.userSelcet {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 215px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin-left: 12px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d0d4dc;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: #26f;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
color: #d0d4dc;
|
||||
transform: rotateZ(180deg);
|
||||
}
|
||||
|
||||
.el-icon-circle-close:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
padding: 0 15px;
|
||||
font-size: 12px;
|
||||
color: $placeholderColor;
|
||||
}
|
||||
}
|
||||
|
||||
.userinfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
|
||||
span:first-child {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
.user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
margin-right: 8px;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
i {
|
||||
color: #2266FF;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
em {
|
||||
margin-left: 8px;
|
||||
color: #2266FF;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.msg {
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
|
||||
p {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: 38px;
|
||||
padding: 0px 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.msg-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 38px;
|
||||
padding: 0 16px;
|
||||
border-top: 1px solid #D0D4DC;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #2266FF;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
color: #2266FF;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .AppAnnounceDetail-title ){
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
height: 100%;
|
||||
line-height: 56px;
|
||||
margin-right: 32px;
|
||||
color: #888888;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
transition: all ease 0.3s;
|
||||
border-bottom: 3px solid transparent;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
color: #222;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #222222;
|
||||
border-bottom: 3px solid #2266FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-item {
|
||||
.top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.top-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
height: 90px;
|
||||
margin-right: 16px;
|
||||
padding: 0 16px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.top-item__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
|
||||
i {
|
||||
margin-left: 4px;
|
||||
color: #8899bb;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #2266FF;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .right-tips ){
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
i {
|
||||
margin-right: 4px;
|
||||
color: #8899bb;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #888888;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,294 +0,0 @@
|
||||
<template>
|
||||
<ai-list class="AppAnnounce">
|
||||
<template slot="title">
|
||||
<ai-title title="群发居民朋友圈" isShowBottomBorder>
|
||||
<template #sub>
|
||||
<span>管理员统一创建宣发任务,成员确认发布后,将在所有已添加的居民朋友圈进行展示。一个居民每天只能看到同个人发送的3条朋友圈。</span>
|
||||
</template>
|
||||
</ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar">
|
||||
<template #left>
|
||||
<el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')">创建宣发</el-button>
|
||||
<ai-select
|
||||
v-model="search.status"
|
||||
@change="search.current = 1, getList()"
|
||||
placeholder="任务状态"
|
||||
:selectList="dict.getDict('mstStatus')">
|
||||
</ai-select>
|
||||
<el-date-picker
|
||||
v-model="search.startTime"
|
||||
type="date"
|
||||
size="small"
|
||||
value-format="yyyy-MM-dd"
|
||||
@change="search.current = 1, getList()"
|
||||
placeholder="选择群发开始日期">
|
||||
</el-date-picker>
|
||||
<el-date-picker
|
||||
v-model="search.endTime"
|
||||
type="date"
|
||||
size="small"
|
||||
value-format="yyyy-MM-dd"
|
||||
@change="search.current = 1, getList()"
|
||||
placeholder="选择群发结束日期">
|
||||
</el-date-picker>
|
||||
<ai-wechat-selecter :instance="instance" @change="onUserChange" :isMultiple="false" v-model="user">
|
||||
<div class="userSelcet">
|
||||
<span style="color: #606266;" v-if="search.createUserId">{{ name }}</span>
|
||||
<span v-else>创建人</span>
|
||||
<i class="el-icon-arrow-up" v-if="!search.createUserId"></i>
|
||||
<i class="el-icon-circle-close" v-if="search.createUserId" @click.stop="user = [], search.createUserId = '', name = '', search.current = 1, getList()"></i>
|
||||
</div>
|
||||
</ai-wechat-selecter>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.taskTitle"
|
||||
size="small"
|
||||
v-throttle="() => { search.current = 1, getList() }"
|
||||
placeholder="请输入任务名称"
|
||||
clearable
|
||||
@clear="search.current = 1, search.taskTitle = '', getList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
v-loading="loading"
|
||||
style="margin-top: 6px; width: 100%;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="user" width="140px" label="创建人" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="userinfo">
|
||||
<span>{{ row.createUserName }}</span>
|
||||
<span style="color: #999">{{ row.createUserDeptName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" width="140px" fixed="right" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="remindExamine(row.id)" v-if="['0'].includes(row.status)">催办</el-button>
|
||||
<el-button type="text" @click="cancel(row.id)" v-if="['0'].includes(row.status)">撤回</el-button>
|
||||
<el-button type="text" @click="toDetail(row.id)">详情</el-button>
|
||||
<el-button type="text" @click="toAdd(row.id)" v-if="['1', '3'].includes(row.status)">编辑</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
status: '',
|
||||
createUserId: '',
|
||||
taskTitle: '',
|
||||
startTime: '',
|
||||
endTime: ''
|
||||
},
|
||||
user: [],
|
||||
tableData: [],
|
||||
loading: false,
|
||||
total: 0,
|
||||
colConfigs: [
|
||||
{ prop: 'taskTitle', label: '任务名称' },
|
||||
{ prop: 'typeName', label: '群发类型', align: 'center' },
|
||||
{ slot: 'user', label: '创建人', openType: 'userName', align: 'center' },
|
||||
{ prop: 'choiceTime', label: '群发时间', align: 'center' },
|
||||
{
|
||||
prop: 'status',
|
||||
align: 'center',
|
||||
label: '状态',
|
||||
render: (h, {row}) => {
|
||||
return h('span', {
|
||||
style: {
|
||||
color: this.dict.getColor('mstStatus', row.status)
|
||||
}
|
||||
}, this.dict.getLabel('mstStatus', row.status))
|
||||
}
|
||||
},
|
||||
{ prop: 'completionRate', label: '任务完成率', align: 'center', formart: v => v ? v === '0.0' ? '0%' : `${v}%` : '-' }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.dict.load('mstStatus', 'mstSendType').then(() => {
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
onUserChange (e) {
|
||||
if (e.length) {
|
||||
this.name = e[0].name
|
||||
this.search.createUserId = e[0].id
|
||||
} else {
|
||||
this.search.createUserId = ''
|
||||
this.name = ''
|
||||
}
|
||||
|
||||
this.search.current = 1
|
||||
this.getList()
|
||||
},
|
||||
|
||||
getList() {
|
||||
this.loading = true
|
||||
this.instance.post(`/app/whchatmomentstask/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records.map(v => {
|
||||
return {
|
||||
...v,
|
||||
typeName: '群发居民群'
|
||||
}
|
||||
})
|
||||
this.total = res.data.total
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.loading = false
|
||||
})
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
remindExamine (id) {
|
||||
this.$confirm('确认再次通知任务审核人员?').then(() => {
|
||||
this.instance.post(`/app/appmasssendingtask/remindExamine?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('催办成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
cancel (id) {
|
||||
this.$confirm('确认撤回该群发任务?').then(() => {
|
||||
this.instance.post(`/app/appmasssendingtask/cancel?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('撤回成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
this.$confirm('确定删除该数据?').then(() => {
|
||||
this.instance.post(`/app/appmasssendingtask/delete?ids=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
toAdd(id) {
|
||||
this.$emit('change', {
|
||||
type: 'Add',
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toDetail (id) {
|
||||
this.$emit('change', {
|
||||
type: 'Detail',
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppAnnounce {
|
||||
height: 100%;
|
||||
.userinfo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
|
||||
span:first-child {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.userSelcet {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 215px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d0d4dc;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&:hover {
|
||||
border-color: #26f;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
color: #d0d4dc;
|
||||
transform: rotateZ(180deg);
|
||||
}
|
||||
|
||||
.el-icon-circle-close:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
padding: 0 15px;
|
||||
font-size: 12px;
|
||||
color: $placeholderColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,344 +0,0 @@
|
||||
<template>
|
||||
<div class="phone-container">
|
||||
<img class="close" @click="$emit('close')" v-if="isShowClose" src="https://cdn.cunwuyun.cn/dvcp/announce/close.png" />
|
||||
<img class="phone" src="https://cdn.cunwuyun.cn/dvcp/announce/phone.png" />
|
||||
<img class="phone-wrapper" src="https://cdn.cunwuyun.cn/dvcp/announce/phone-wrapper.png" />
|
||||
<div class="right-content">
|
||||
<div class="msg-list">
|
||||
<div class="msg-item" v-if="content">
|
||||
<div class="msg-item__left">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/avatar.png" />
|
||||
</div>
|
||||
<div class="msg-item__right">
|
||||
<div class="msg-wrapper msg-text">
|
||||
<p>{{ content }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="msg-item" v-for="item in fileList" :key="item.id">
|
||||
<div class="msg-item__left">
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/avatar.png" />
|
||||
</div>
|
||||
<div class="msg-item__right" :class="[['1', '2'].indexOf(item.msgType) !== -1 ? 'left-border' : '']">
|
||||
<div class="msg-wrapper msg-img" v-if="item.msgType === '1'">
|
||||
<img :src="item.imgPicUrl" />
|
||||
</div>
|
||||
<div class="msg-wrapper msg-video" v-if="item.msgType === '2'">
|
||||
<video controls :src="item.url"></video>
|
||||
</div>
|
||||
<div class="msg-wrapper msg-file" v-if="item.msgType === '3'">
|
||||
<div class="msg-left">
|
||||
<h2>{{ item.name }}</h2>
|
||||
<p>{{ item.fileSizeStr }}</p>
|
||||
</div>
|
||||
<img :src="mapIcon(item.name)" />
|
||||
</div>
|
||||
<div class="msg-wrapper msg-link" v-if="item.msgType === '4'">
|
||||
<h2>{{ item.linkTitle }}</h2>
|
||||
<div class="msg-right">
|
||||
<p>{{ item.linkDesc }}</p>
|
||||
<img :src="item.linkPicUrl || 'https://cdn.cunwuyun.cn/dvcp/announce/html.png'" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="msg-wrapper msg-miniapp" v-if="item.msgType === '5'">
|
||||
<h2>{{ item.mpTitle }}</h2>
|
||||
<img :src="item.url" />
|
||||
<div class="msg-bottom">
|
||||
<i>小程序</i>
|
||||
<img src="https://cdn.cunwuyun.cn/dvcp/announce/miniapp.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['fileList', 'avatar', 'content', 'isShowClose'],
|
||||
|
||||
watch: {
|
||||
fileList (v) {
|
||||
if (v.length) {
|
||||
setTimeout(() => {
|
||||
document.querySelector('.right-content').scrollTo(0, 999999)
|
||||
}, 800)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
mapIcon (fileName) {
|
||||
if (['.zip', '.rar'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/zip.png'
|
||||
}
|
||||
|
||||
if (['.doc', '.docx'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/world.png'
|
||||
}
|
||||
|
||||
if (['.xls', '.xlsx'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/xls.png'
|
||||
}
|
||||
|
||||
if (['.txt'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/txt.png'
|
||||
}
|
||||
|
||||
if (['.pdf'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/pdf.png'
|
||||
}
|
||||
|
||||
if (['.ppt', '.pptx'].indexOf(this.getExtension(fileName)) !== -1) {
|
||||
return 'https://cdn.cunwuyun.cn/dvcp/announce/ppt.png'
|
||||
}
|
||||
},
|
||||
|
||||
getExtension(name) {
|
||||
return name.substring(name.lastIndexOf('.'))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.phone-container {
|
||||
width: 338px;
|
||||
height: 675px;
|
||||
padding: 80px 15px 100px 32px;
|
||||
|
||||
.phone {
|
||||
position: absolute;
|
||||
left: 13px;
|
||||
top: 4px;
|
||||
z-index: 1;
|
||||
width: 314px;
|
||||
height: 647px;
|
||||
}
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 111;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.5s;
|
||||
transform: translate(100%, -50%);
|
||||
|
||||
&:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.phone-wrapper {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
width: 338px;
|
||||
height: 675px;
|
||||
}
|
||||
|
||||
.right-content {
|
||||
position: relative;
|
||||
z-index: 11;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
|
||||
.msg-item {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.msg-item__left {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
margin-right: 16px;
|
||||
border-radius: 4px;
|
||||
flex-shrink: 1;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.msg-item__right {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-right: 6px solid #fff;
|
||||
border-left: 6px solid transparent;
|
||||
border-bottom: 6px solid transparent;
|
||||
border-top: 6px solid transparent;
|
||||
content: " ";
|
||||
transform: translate(-100%, 0%);
|
||||
}
|
||||
|
||||
&.left-border::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.msg-img img {
|
||||
max-width: 206px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.msg-video video {
|
||||
max-width: 206px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.msg-text {
|
||||
max-width: 206px;
|
||||
width: max-content;
|
||||
line-height: 1.3;
|
||||
padding: 12px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
word-break: break-all;
|
||||
font-size: 14px;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
.msg-miniapp {
|
||||
width: 206px;
|
||||
padding: 0 12px;
|
||||
text-align: justify;
|
||||
font-size: 0;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
color: #222222;
|
||||
|
||||
h2 {
|
||||
line-height: 1.2;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
& > img {
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.msg-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
padding: 4px 0;
|
||||
border-top: 1px solid #eee;
|
||||
|
||||
i {
|
||||
margin-right: 4px;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.msg-file {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 206px;
|
||||
padding: 12px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
|
||||
.msg-left {
|
||||
flex: 1;
|
||||
margin-right: 18px;
|
||||
|
||||
h2 {
|
||||
display: -webkit-box;
|
||||
flex: 1;
|
||||
line-height: 16px;
|
||||
margin-bottom: 4px;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #888888;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.msg-link {
|
||||
width: 206px;
|
||||
padding: 12px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
|
||||
h2 {
|
||||
margin-bottom: 4px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.msg-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
p {
|
||||
display: -webkit-box;
|
||||
flex: 1;
|
||||
line-height: 16px;
|
||||
margin-right: 10px;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,759 +0,0 @@
|
||||
<template>
|
||||
<ai-list class="AppAnnounceStatistics">
|
||||
<template slot="content">
|
||||
<div class="statistics-content">
|
||||
<ai-title title="宣发日历"></ai-title>
|
||||
<div class="flex-content">
|
||||
<div class="flex-left">
|
||||
<div class="date-header">
|
||||
<p>{{chooseYear}}年{{chooseMonth}}月</p>
|
||||
<div>
|
||||
<el-date-picker size="small"
|
||||
v-model="searchMonth"
|
||||
type="month" value-format="yyyy-MM"
|
||||
placeholder="选择日期" @change="searchMonthChange">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</div>
|
||||
<el-calendar v-model="calendarDate">
|
||||
<template
|
||||
slot="dateCell"
|
||||
slot-scope="{date, data}" >
|
||||
<div class="flex-date">
|
||||
<span>{{Number(data.day.substring(8, 10))}}</span>
|
||||
<span class="tips" v-if="data.day.substring(5, 7) == chooseMonth && dateList[Number(data.day.substring(8, 10))] && dateList[Number(data.day.substring(8, 10))].taskList.length">{{dateList[Number(data.day.substring(8, 10))].taskList.length}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-calendar>
|
||||
</div>
|
||||
<div class="flex-right">
|
||||
<div class="title">{{chooseMonth}}月{{chooseDay}}日宣发内容</div>
|
||||
<div class="list-content" v-if="taskList.length">
|
||||
<el-timeline >
|
||||
<el-timeline-item v-for="(item, index) in taskList" :key="index">
|
||||
<el-card>
|
||||
<div class="flex-between">
|
||||
<p class="item-title">{{item.taskTitle}}</p>
|
||||
<span class="item-time" v-if="item.choiceTime">{{item.choiceTime.substring(10, 16)}}</span>
|
||||
</div>
|
||||
<div class="item-info item-created">
|
||||
<span class="label">创建人:</span>
|
||||
<ai-open-data type="userName" :openid="item.createUserId" class="name"></ai-open-data>
|
||||
</div>
|
||||
<div class="item-info item-dept">
|
||||
<span class="label">创建部门:</span>
|
||||
<ai-open-data type="departmentName" :openid="item.createUserDept" class="name"></ai-open-data>
|
||||
</div>
|
||||
<div class="flex-between">
|
||||
<!-- <div class="item-info">群发类型:<span>{{$dict.getLabel('mstSendType', item.sendType) || ''}}</span></div> -->
|
||||
<div class="item-info"><span class="label">群发类型:</span><span>群发居民群</span></div>
|
||||
<span class="item-btn" @click="$router.push({name: '357e228ba8e64008ace90d095a7a0dd7', params: { id: item.id }})">详情</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
|
||||
</div>
|
||||
<ai-empty v-if="!taskList.length" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistics-content">
|
||||
<div class="flex-between mar-b16">
|
||||
<ai-title title="宣发效果"></ai-title>
|
||||
<div class="right-search">
|
||||
<div class="time-select" :class="effectType == index ? 'active' : ''" v-for="(item, index) in dateTypeList" :key="index" @click="changeEffectType(index)">{{item}}</div>
|
||||
<ai-picker :instance="instance" @pick="e => onUserChange(e)" :multiple="false" dialogTitle="选择部门" action="/app/wxcp/wxdepartment/departList">
|
||||
<div class="time-select">
|
||||
<span class="dept-name" style="color:#999;" v-if="deptList && !deptList.length">宣发部门</span>
|
||||
<ai-open-data class="dept-name" type="departmentName" :openid="deptList[0].id" v-else/>
|
||||
<i class="el-icon-arrow-down"></i>
|
||||
</div>
|
||||
</ai-picker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line-content">
|
||||
<div class="flex1">
|
||||
<div class="header">
|
||||
<p>累计创建宣发任务数</p>
|
||||
<h2>{{effectData.createCount}}</h2>
|
||||
</div>
|
||||
<div class="chart-content">
|
||||
<div class="chart-title">宣发任务数</div>
|
||||
<div class="chart-box" id="createChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex1">
|
||||
<div class="header">
|
||||
<p>累计执行宣发次数</p>
|
||||
<h2>{{effectData.executeCount}}</h2>
|
||||
</div>
|
||||
<div class="chart-content">
|
||||
<div class="chart-title">宣发次数</div>
|
||||
<div class="chart-box" id="executeChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex1 mar-r0">
|
||||
<div class="header">
|
||||
<p>累计触达人次</p>
|
||||
<h2>{{effectData.receiveCount}}</h2>
|
||||
</div>
|
||||
<div class="chart-content">
|
||||
<div class="chart-title">触达人次</div>
|
||||
<div class="chart-box" id="receiveChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistics-content">
|
||||
<div class="flex-between mar-b16">
|
||||
<ai-title title="宣发明细"></ai-title>
|
||||
<div class="right-search">
|
||||
<div class="time-select" :class="departType == index ? 'active' : ''" v-for="(item, index) in dateTypeList" :key="index" @click="changeDepartType(index)">{{item}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="departBarChart" v-if="isDepartData"></div>
|
||||
<ai-empty v-if="!isDepartData"></ai-empty>
|
||||
</div>
|
||||
|
||||
<ai-dialog :visible.sync="dialogDate" title="选择时间" width="500px" customFooter>
|
||||
<el-date-picker v-model="timeList" size="small" type="daterange" value-format="yyyy-MM-dd"
|
||||
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期">
|
||||
</el-date-picker>
|
||||
<el-button slot="footer" @click="selectDete" type="primary">确认</el-button>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from "echarts";
|
||||
import { mapActions, mapState } from 'vuex';
|
||||
export default {
|
||||
name: 'AppAnnounceWeChatStatistics',
|
||||
label: '协同宣发朋友圈统计',
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
calendarDate: new Date(),
|
||||
dateList: {},
|
||||
chooseYear: '',
|
||||
chooseMonth: '',
|
||||
chooseDay: '',
|
||||
searchMonth: '',
|
||||
taskList: [],
|
||||
effectType: 0, // 宣发效果类型 0:近七天、1:近30天、2:近一年、3:自定义
|
||||
effectData: {},
|
||||
createChart: null,
|
||||
executeChart: null,
|
||||
receiveChart: null,
|
||||
departType: 0, // 宣发明细类型 0:近七天、1:近30天、2:近一年、3:自定义
|
||||
dateTypeList: ['近7天', '近30天', '近1年', '自定义'],
|
||||
departData: {},
|
||||
departBarChart: null,
|
||||
dialogDate: false,
|
||||
timeListEffect: '',
|
||||
timeListDepart: '',
|
||||
timeList: '',
|
||||
isEffectTimeSelect: false,
|
||||
deptList: [],
|
||||
selectDeptName: '',
|
||||
isDepartData: true,
|
||||
departBarData: [],
|
||||
type: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
},
|
||||
watch: {
|
||||
calendarDate: function() {
|
||||
var year = '' , month = '', date = ''
|
||||
if(this.calendarDate.length == 9) { // 月份选择器触发
|
||||
year = this.calendarDate.substring(0, 4)
|
||||
month = this.calendarDate.substring(5, 7)
|
||||
date = this.calendarDate.substring(8, 10)
|
||||
}else { // 日历点击
|
||||
year = this.calendarDate.getFullYear();
|
||||
month = this.calendarDate.getMonth() + 1;
|
||||
date = this.calendarDate.getDate()
|
||||
if (month >= 1 && month <= 9) {
|
||||
month = "0" + month;
|
||||
}
|
||||
|
||||
if(this.chooseMonth != month) { // 日历点击不同月
|
||||
this.searchMonth = ''
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.chooseDay = date
|
||||
|
||||
if(this.chooseMonth != month || this.chooseYear != year) { // 不同年/不同月重新请求日历列表
|
||||
this.getCalendarList(year, month)
|
||||
} else {
|
||||
this.getTaskList(date)
|
||||
}
|
||||
|
||||
this.chooseMonth = month
|
||||
this.chooseYear = year
|
||||
|
||||
}
|
||||
},
|
||||
created() {
|
||||
var year = this.calendarDate.getFullYear();
|
||||
var month = this.calendarDate.getMonth() + 1;
|
||||
var date = this.calendarDate.getDate()
|
||||
if (month >= 1 && month <= 9) {
|
||||
month = "0" + month;
|
||||
}
|
||||
this.chooseMonth = month
|
||||
this.chooseYear = year
|
||||
this.chooseDay = date
|
||||
this.getCalendarList(year, month)
|
||||
this.getEffect()
|
||||
this.getDepart()
|
||||
this.dict.load('mstSendType')
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['initOpenData', 'transCanvas']),
|
||||
onUserChange (e) {
|
||||
this.deptList = e
|
||||
this.getEffect()
|
||||
},
|
||||
selectDete() {
|
||||
if(!this.timeList || !this.timeList.length) {
|
||||
return this.$message.error('请选择自定义时间');
|
||||
}
|
||||
|
||||
if(this.isEffectTimeSelect) { //宣发效果
|
||||
this.timeListEffect = this.timeList
|
||||
this.effectType = 3
|
||||
this.getEffect()
|
||||
} else { //宣发明细
|
||||
this.timeListDepart = this.timeList
|
||||
this.departType = 3
|
||||
this.getDepart()
|
||||
}
|
||||
|
||||
this.dialogDate = false
|
||||
},
|
||||
searchMonthChange() {
|
||||
this.calendarDate = this.searchMonth + '-1'
|
||||
},
|
||||
getCalendarList(year, month){
|
||||
this.instance.post(`/app/appmasssendingtask/statisticsCalendar?yyyyMM=${year}${month}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.dateList = res.data
|
||||
this.getTaskList(this.chooseDay)
|
||||
}
|
||||
})
|
||||
},
|
||||
getTaskList(day) {
|
||||
this.taskList = this.dateList[day].taskList
|
||||
},
|
||||
changeEffectType(type) {
|
||||
if(this.effectType != 3) {
|
||||
this.timeList = []
|
||||
}else {
|
||||
this.timeList = this.timeListEffect
|
||||
}
|
||||
if(type == 3) {
|
||||
this.isEffectTimeSelect = true
|
||||
this.dialogDate = true
|
||||
}else {
|
||||
this.effectType = type
|
||||
this.getEffect()
|
||||
}
|
||||
},
|
||||
getEffect() {
|
||||
var startTime = this.timeListEffect[0] || '' , endTime = this.timeListEffect[1] || '', departId = this.deptList[0] || ''
|
||||
this.instance.post(`/app/appmasssendingtask/statisticsEffect?type=${this.effectType}&startTime=${startTime}&endTime=${endTime}&departId=${departId}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.effectData = res.data
|
||||
var xData = [], createData = [], executeData = [], receiveData = []
|
||||
res.data.trend.map(e => {
|
||||
if(this.effectType == 0 || this.effectType == 1) {
|
||||
e.ymd = e.ymd.substring(5, 10)
|
||||
}
|
||||
xData.push(e.ymd)
|
||||
createData.push(e.createCount)
|
||||
executeData.push(e.executeCount)
|
||||
receiveData.push(e.receiveCount)
|
||||
})
|
||||
|
||||
this.setLineChart(xData, createData, 'createChart', ['#2891FF'])
|
||||
this.setLineChart(xData, executeData, 'executeChart', ['#FFB865'])
|
||||
this.setLineChart(xData, receiveData, 'receiveChart', ['#26D52B'])
|
||||
}
|
||||
})
|
||||
},
|
||||
setLineChart(xData, yData, id, colorList) {
|
||||
this[id] = echarts.init(document.querySelector(`#${id}`))
|
||||
var option = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: xData
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
grid: {
|
||||
left: '10px',
|
||||
right: '28px',
|
||||
bottom: '14px',
|
||||
top: '30px',
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
type: "plain"
|
||||
},
|
||||
color: colorList,
|
||||
series: [
|
||||
{
|
||||
data: yData,
|
||||
type: 'line'
|
||||
}
|
||||
]
|
||||
}
|
||||
this[id].setOption(option)
|
||||
},
|
||||
changeDepartType(type) {
|
||||
if(this.departType != 3) {
|
||||
this.timeList = []
|
||||
}else {
|
||||
this.timeList = this.timeListDepart
|
||||
}
|
||||
if(type == 3) {
|
||||
this.isEffectTimeSelect = false
|
||||
this.dialogDate = true
|
||||
}else {
|
||||
this.departType = type
|
||||
this.getDepart()
|
||||
}
|
||||
},
|
||||
getDepart() {
|
||||
var startTime = this.timeListDepart[0] || '' , endTime = this.timeListDepart[1] || ''
|
||||
this.instance.post(`/app/appmasssendingtask/statisticsDepart?type=${this.departType}&startTime=${startTime}&endTime=${endTime}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
if(res.data && res.data.length) {
|
||||
this.isDepartData = true
|
||||
var items = [], xData = [], yData = []
|
||||
res.data.map((item) => {
|
||||
this.departBarData.push(item)
|
||||
var i = {type: 'departmentName', id: item.deptId, corpid: this.user.info.corpId}
|
||||
items.push(i)
|
||||
yData.push(item.taskCount)
|
||||
})
|
||||
|
||||
this.initOpenData({canvas:true})
|
||||
this.transCanvas(items).then((data) => {
|
||||
xData = data.items.map((i) => {
|
||||
return i.data
|
||||
})
|
||||
this.setBarChart(xData, yData)
|
||||
})
|
||||
}else {
|
||||
this.isDepartData = false
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
setBarChart(xData, yData) {
|
||||
this.departBarChart = echarts.init(document.querySelector(`#departBarChart`))
|
||||
var option = {
|
||||
color: ['#2891FF'],
|
||||
grid: {
|
||||
top: '10%',
|
||||
left: '2%',
|
||||
right: '2%',
|
||||
bottom: 90,
|
||||
containLabel: true
|
||||
},
|
||||
// toolbox: {
|
||||
// feature: {
|
||||
// dataZoom: {
|
||||
// yAxisIndex: false
|
||||
// },
|
||||
// saveAsImage: {
|
||||
// pixelRatio: 2
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
},
|
||||
formatter: (data) => {
|
||||
var index = data[0].dataIndex
|
||||
return `<ww-open-data type="departmentName" openid="${this.departBarData[index].deptId}"></ww-open-data><br/>宣发任务数:${data[0].value}`
|
||||
}
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside'
|
||||
},
|
||||
{
|
||||
type: 'slider'
|
||||
}
|
||||
],
|
||||
xAxis: {
|
||||
data: xData,
|
||||
silent: false,
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
splitArea: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
splitArea: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'bar',
|
||||
data: yData,
|
||||
barWidth: 20,
|
||||
barGap: '250%',
|
||||
large: true
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// {
|
||||
// tooltip: {
|
||||
// trigger: 'axis',
|
||||
// axisPointer: {
|
||||
// type: 'shadow'
|
||||
// }
|
||||
// },
|
||||
// grid: {
|
||||
// top: '10%',
|
||||
// left: '2%',
|
||||
// right: '2%',
|
||||
// bottom: '2%',
|
||||
// containLabel: true
|
||||
// },
|
||||
// color: ['#2891FF'],
|
||||
// xAxis: {
|
||||
// type: 'category',
|
||||
// data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
|
||||
// },
|
||||
// yAxis: {
|
||||
// type: 'value'
|
||||
// },
|
||||
// series: [
|
||||
// {
|
||||
// data: [120, 200, 150, 80, 70, 110, 130],
|
||||
// type: 'bar',
|
||||
// barWidth: 20,
|
||||
// barGap: '250%',
|
||||
// }
|
||||
// ]
|
||||
// };
|
||||
this.departBarChart.setOption(option)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppAnnounceStatistics {
|
||||
height: 100%;
|
||||
.flex-between{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.mar-b16{
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.mar-r0{
|
||||
margin-right: 0!important;
|
||||
}
|
||||
.statistics-content{
|
||||
padding: 0 24px 24px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0px 4px 6px -2px rgba(15,15,21,0.1500);
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
.flex-content{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
margin-top: 16px;
|
||||
.flex-left{
|
||||
width: 50%;
|
||||
.date-header{
|
||||
padding: 12px 16px;
|
||||
border: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
p{
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.flex-date{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.tips{
|
||||
display: inline-block;
|
||||
padding: 0 4px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
border-radius: 8px;
|
||||
background: #2891FF;
|
||||
font-size: 12px;
|
||||
font-family: ArialMT;
|
||||
color: #FFF;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
.flex-right{
|
||||
width: 50%;
|
||||
margin-left: 16px;
|
||||
border: 1px solid #eee;
|
||||
.title{
|
||||
line-height: 56px;
|
||||
border-bottom: 1px solid #EEE;
|
||||
padding-left: 16px;
|
||||
font-size: 16px;
|
||||
font-family: MicrosoftYaHeiSemibold;
|
||||
color: #333;
|
||||
}
|
||||
.list-content{
|
||||
padding: 16px;
|
||||
height: 339px;
|
||||
box-sizing: border-box;
|
||||
overflow-y: scroll;
|
||||
background-color: #F9F9F9;
|
||||
box-sizing: border-box;
|
||||
.item-title{
|
||||
width: calc(100% - 100px);
|
||||
word-break: break-all;
|
||||
margin-bottom: 8px;
|
||||
font-size: 16px;
|
||||
font-family: MicrosoftYaHeiSemibold;
|
||||
color: #222;
|
||||
line-height: 24px;
|
||||
}
|
||||
.item-time{
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
font-size: 16px;
|
||||
font-family: ArialMT;
|
||||
color: #888;
|
||||
line-height: 24px;
|
||||
}
|
||||
.item-info{
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
font-family: MicrosoftYaHei;
|
||||
color: #222;
|
||||
line-height: 22px;
|
||||
span{
|
||||
display: inline-block;
|
||||
color: #222;
|
||||
word-break: break-all;
|
||||
// vertical-align: text-top;
|
||||
}
|
||||
.label{
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
.item-created{
|
||||
width: 152px;
|
||||
margin-bottom: 4px;
|
||||
.label{
|
||||
width: 56px;
|
||||
}
|
||||
.name{
|
||||
width: calc(100% - 56px);
|
||||
}
|
||||
}
|
||||
.item-dept{
|
||||
width: calc(100% - 152px);
|
||||
.label{
|
||||
width: 70px;
|
||||
}
|
||||
.name{
|
||||
width: calc(100% - 70px);
|
||||
}
|
||||
}
|
||||
.item-btn{
|
||||
color: #26f;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.right-search{
|
||||
margin-top: 10px;
|
||||
div{
|
||||
display: inline-block;
|
||||
}
|
||||
.time-select{
|
||||
font-size: 14px;
|
||||
font-family: MicrosoftYaHei;
|
||||
color: #222;
|
||||
line-height: 22px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
margin-right: 8px;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
.dept-name{
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
height: 22px;
|
||||
overflow:hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.el-icon-arrow-down{
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.active{
|
||||
border: 1px solid #26f;
|
||||
color: #26f;
|
||||
}
|
||||
}
|
||||
.line-content{
|
||||
display: flex;
|
||||
.flex1{
|
||||
flex: 1;
|
||||
margin-right: 16px;
|
||||
.header{
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
height: 90px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 16px;
|
||||
p{
|
||||
font-size: 14px;
|
||||
font-family: MicrosoftYaHeiSemibold;
|
||||
color: #222;
|
||||
line-height: 22px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
h2{
|
||||
font-size: 24px;
|
||||
font-family: DINAlternate-Bold, DINAlternate;
|
||||
font-weight: bold;
|
||||
color: #26F;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.chart-content{
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
background: #F9F9F9;
|
||||
border-radius: 2px;
|
||||
box-sizing: border-box;
|
||||
.chart-title{
|
||||
font-size: 16px;
|
||||
font-family: MicrosoftYaHeiSemibold;
|
||||
color: #333;
|
||||
line-height: 24px;
|
||||
}
|
||||
.chart-box{
|
||||
width: 100%;
|
||||
height: 280px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#departBarChart{
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
:deep( .el-calendar-table:not(.is-range) td.next),
|
||||
:deep( .el-calendar-table:not(.is-range) td.prev ){
|
||||
color: #ccc;
|
||||
}
|
||||
:deep( .el-calendar-table .el-calendar-day){
|
||||
height: 48px;
|
||||
line-height: 32px;
|
||||
padding-left: 12px;
|
||||
font-size: 14px;
|
||||
font-family: ArialMT;
|
||||
}
|
||||
.el-calendar-table:not(.is-range) td .current{
|
||||
color: #888;
|
||||
}
|
||||
:deep( .el-calendar__header){
|
||||
display: none;
|
||||
}
|
||||
:deep( .el-calendar__body){
|
||||
padding: 0;
|
||||
}
|
||||
:deep( .el-calendar-table thead th:nth-of-type(1)){
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-calendar-table thead th:nth-of-type(7)){
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-calendar-table tr td:first-child ){
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-calendar-table tr:first-child td ){
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-calendar-table td ){
|
||||
border-bottom: 1px solid #eee;
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
:deep( .el-timeline-item__timestamp.is-top){
|
||||
margin-bottom: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
:deep( .el-timeline-item__node){
|
||||
background-color: #26F;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
left: 1px;
|
||||
}
|
||||
:deep( .el-card){
|
||||
border: none;
|
||||
}
|
||||
:deep( .el-card__body){
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .ai-list__content ){
|
||||
padding: 0!important;
|
||||
|
||||
.ai-list__content--right-wrapper {
|
||||
background: transparent!important;
|
||||
box-shadow: none!important;
|
||||
margin: 0!important;
|
||||
padding: 0 0 0!important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .AiPicker){
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
@@ -1,69 +0,0 @@
|
||||
<template>
|
||||
<ai-list v-if="!isShowDetail">
|
||||
<template slot="title">
|
||||
<ai-title title="客户群发" :isShowBottomBorder="true"></ai-title>
|
||||
</template>
|
||||
<template slot="tabs">
|
||||
<component :ref="activeName" :is="activeName" @change="change" :instance="instance" :dict="dict"
|
||||
:permissions="permissions"/>
|
||||
</template>
|
||||
</ai-list>
|
||||
<component v-else :is="activeName" :params="params" @change="change" :instance="instance" :dict="dict" :permissions="permissions"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TableList from './components/TableList.vue'
|
||||
import NewClientMass from './components/NewClientMass.vue'
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'AppClientMassTextin',
|
||||
label: '客户群发',
|
||||
components: {
|
||||
TableList,
|
||||
NewClientMass,
|
||||
},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
activeName: 'TableList',
|
||||
params: {},
|
||||
isShowDetail: false,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
change(val) {
|
||||
console.log(val);
|
||||
if (val.type) {
|
||||
this.activeName = val.type
|
||||
switch (val.type) {
|
||||
case "NewClientMass":
|
||||
this.isShowDetail = true
|
||||
this.params = val.row
|
||||
break;
|
||||
case "TableList":
|
||||
this.isShowDetail = false
|
||||
this.$nextTick(() => {
|
||||
this.$refs[this.activeName].getList()
|
||||
})
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,342 +0,0 @@
|
||||
<template>
|
||||
<div class="new-client-mass">
|
||||
<ai-detail>
|
||||
<template #title>
|
||||
<ai-title :title="params.isAdd?'新建群发':'群发详情'" isShowBottomBorder :isShowBack="true" @onBackClick="onBack"
|
||||
:isShowBottomBorder="true"></ai-title>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-card title="基本信息" v-if="params.isAdd && !isEditInfo">
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<el-form ref="form"
|
||||
:model="form"
|
||||
:rules="formRules"
|
||||
size="small"
|
||||
style="width: 100%;"
|
||||
label-width="120px">
|
||||
<el-form-item label="群发账号" prop="documentName">
|
||||
<el-row type="flex">
|
||||
<div class="input"></div>
|
||||
<ai-person-select :instance="instance" url="/app/appvillagecadres/list" :isMultiple="true"
|
||||
@selectPerson="getSelect" btnText="选择" dialogTitle="选择">
|
||||
<template name="option" v-slot:option="{ item }">
|
||||
<span class="iconfont iconProlife">{{ item.name }}</span>
|
||||
<ai-id mode="show" :show-eyes="false" :value="item.idNumber"/>
|
||||
</template>
|
||||
</ai-person-select>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-row type="flex" justify="space-between">
|
||||
<el-form-item label="群发时间" prop="documentName">
|
||||
<el-radio-group>
|
||||
<el-radio :label="1">立即发送</el-radio>
|
||||
<el-radio :label="2">定时发送</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="发送时间" prop="documentName">
|
||||
<el-time-picker
|
||||
class="select-width"
|
||||
:picker-options="{ selectableRange: '18:30:00 - 20:30:00'}"
|
||||
placeholder="请选择...">
|
||||
</el-time-picker>
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
<el-form-item label="选择居民" prop="documentName">
|
||||
<el-radio-group>
|
||||
<el-radio :label="1">全部居民</el-radio>
|
||||
<el-radio :label="2">筛选居民</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-row type="flex" justify="space-between">
|
||||
<el-form-item label="最早添加日期" prop="documentName">
|
||||
<el-time-picker
|
||||
class="select-width"
|
||||
:picker-options="{ selectableRange: '18:30:00 - 20:30:00'}"
|
||||
placeholder="请选择...">
|
||||
</el-time-picker>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
<el-form-item label="最晚添加日期" prop="documentName">
|
||||
<el-time-picker
|
||||
class="select-width"
|
||||
:picker-options="{ selectableRange: '18:30:00 - 20:30:00'}"
|
||||
placeholder="请选择...">
|
||||
</el-time-picker>
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
<el-form-item label="居民公共标签" prop="documentName">
|
||||
<el-row type="flex">
|
||||
<div class="input"></div>
|
||||
<el-button class="person-select" @click="dialog=true">选择</el-button>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item label="排除居民" prop="documentName">
|
||||
<el-row type="flex">
|
||||
<div class="input"></div>
|
||||
<ai-person-select :instance="instance" url="/app/appvillagecadres/list" :isMultiple="true"
|
||||
@selectPerson="getSelect" btnText="选择" dialogTitle="选择">
|
||||
<template name="option" v-slot:option="{ item }">
|
||||
<span class="iconfont iconProlife">{{ item.name }}</span>
|
||||
<ai-id mode="show" :show-eyes="false" :value="item.idNumber"/>
|
||||
</template>
|
||||
</ai-person-select>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
|
||||
<ai-card title="基本信息" v-if="!params.isAdd && !isEditInfo">
|
||||
<template #right>
|
||||
<el-button icon="iconfont iconjdq_led_edit" size="mini" @click="editInfo()">编辑</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-wrapper label-width="96px">
|
||||
<ai-info-item label="群发账号" isLine>刘仕伟;郭麒麟;陶瑞武</ai-info-item>
|
||||
<ai-info-item label="群发时间">定时发送</ai-info-item>
|
||||
<ai-info-item label="发送时间">2021-05-12 18:00</ai-info-item>
|
||||
<ai-info-item label="选择居民" isLine>筛选居民</ai-info-item>
|
||||
<ai-info-item label="最早添加日期">2021-05-12 18:00</ai-info-item>
|
||||
<ai-info-item label="最晚添加日期">2021-05-12 18:00</ai-info-item>
|
||||
<ai-info-item label="居民公共标签" isLine>2021-05-12 18:00</ai-info-item>
|
||||
<ai-info-item label="排除居民" isLine>陶瑞武</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
|
||||
<ai-card title="群发消息内容" class="msg-title" v-if="params.isAdd && !isEditMsg">
|
||||
<template #right>
|
||||
*居民每个月最多接收来自同一企业管理员的4条群发消息,4条消息可在同一天发送
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<el-form ref="form"
|
||||
style="width: 100%;"
|
||||
:model="form"
|
||||
:rules="formRules"
|
||||
size="small"
|
||||
label-width="120px">
|
||||
<el-form-item label="文本内容">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="5"
|
||||
placeholder="请输入回复内容">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="其他类型">
|
||||
<el-radio-group v-model="form.type">
|
||||
<el-radio label="none">无</el-radio>
|
||||
<el-radio label="img">图片</el-radio>
|
||||
<el-radio label="link">链接</el-radio>
|
||||
<el-radio label="file">附件</el-radio>
|
||||
<el-radio label="video">视频</el-radio>
|
||||
<el-radio label="miniProgrom">小程序</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="comp.label" v-for="(comp,index) in msgConnect" :key="index">
|
||||
<ai-uploader :instance="instance" :limit="1" v-if="comp.type=='img'"></ai-uploader>
|
||||
<el-input placeholder="链接地址请以http或https开头" v-if="comp.type=='link'">
|
||||
<template slot="prepend">Http://</template>
|
||||
</el-input>
|
||||
<ai-uploader :instance="instance" fileType="file" :limit="9" v-if="comp.type=='file'"></ai-uploader>
|
||||
<el-radio-group v-if="comp.type=='miniProgrom'" class="radio-group-wrap">
|
||||
<div class="radio-wrap" v-for="(item,index) in 5" :key="index">
|
||||
<el-radio label="none">
|
||||
<span class="iconfont iconwenmingxiangfeng"></span>
|
||||
小程序名称
|
||||
</el-radio>
|
||||
</div>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
|
||||
<ai-card title="群发消息内容" v-if="!params.isAdd && !isEditMsg">
|
||||
<template #right>
|
||||
<el-button icon="iconfont iconjdq_led_edit" size="mini">编辑</el-button>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-wrapper label-width="96px">
|
||||
<ai-info-item label="文本内容" isLine>内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容</ai-info-item>
|
||||
<ai-info-item label="小程序" isLine>
|
||||
<div class="radio-group-wrap">
|
||||
<div class="radio-wrap" v-for="(item,index) in 5" :key="index">
|
||||
<span class="iconfont iconwenmingxiangfeng"></span>
|
||||
<span style="margin-left: 8px;">小程序名称</span>
|
||||
</div>
|
||||
</div>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
</template>
|
||||
</ai-card>
|
||||
|
||||
</template>
|
||||
|
||||
<template slot="footer" v-if="params.isAdd">
|
||||
<el-button style="width:120px">取消</el-button>
|
||||
<el-button type="primary" style="width:120px">提 交</el-button>
|
||||
</template>
|
||||
</ai-detail>
|
||||
<ai-dialog
|
||||
title="选择标签"
|
||||
width="800px"
|
||||
:visible.sync="dialog"
|
||||
:destroyOnClose="true"
|
||||
@onConfirm="onConfirm">
|
||||
<el-form ref="form" label-width="80px">
|
||||
<el-form-item label="标签规则">
|
||||
<el-radio-group>
|
||||
<el-radio :label="0">以下标签满足其一</el-radio>
|
||||
<el-radio :label="1">以下标签同时满足</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "NewClientMass",
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
type: "0"
|
||||
},
|
||||
isAdd: true,
|
||||
isEditInfo:false,
|
||||
isEditMsg:false,
|
||||
dialog: false,
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions: Function,
|
||||
params:Object
|
||||
},
|
||||
|
||||
computed: {
|
||||
formRules() {
|
||||
return {
|
||||
documentName: [{required: true, message: "请输入公文名称", trigger: 'change'}],
|
||||
documentCode: [{required: true, message: "请输入公文编号", trigger: 'change'}],
|
||||
documentType: [{required: true, message: "请选择公文类型", trigger: 'change'}],
|
||||
readType: [{required: true, message: "请选择阅示类型", trigger: 'change'}],
|
||||
}
|
||||
},
|
||||
msgConnect() {
|
||||
return [
|
||||
{type: 'none', label: ''},
|
||||
{type: 'img', label: '图片'},
|
||||
{type: 'link', label: '链接'},
|
||||
{type: 'file', label: "附件"},
|
||||
{type: 'video', label: "视频"},
|
||||
{type: 'miniProgrom', label: "小程序"},
|
||||
].filter(e => e.type == this.form.type)
|
||||
}
|
||||
},
|
||||
create() {
|
||||
},
|
||||
methods: {
|
||||
editInfo(){
|
||||
this.$emit("change",{
|
||||
type:"NewClientMass",
|
||||
row:{row:this.params.row,isAdd:true}
|
||||
})
|
||||
this.isEditInfo=true
|
||||
},
|
||||
onConfirm(){
|
||||
|
||||
},
|
||||
getSelect() {
|
||||
|
||||
},
|
||||
onBack() {
|
||||
this.$emit("change", {
|
||||
type: 'TableList'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.new-client-mass {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background: #f3f6f9;
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
min-height: 32px;
|
||||
line-height: 32px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d0d4dc;
|
||||
color: #666;
|
||||
display: inline-block;
|
||||
font-size: inherit;
|
||||
cursor: pointer;
|
||||
|
||||
&:after {
|
||||
content: "请选择...";
|
||||
color: #888888;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.select-width {
|
||||
width: 328px;
|
||||
}
|
||||
|
||||
.radio-group-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
|
||||
.radio-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 17px;
|
||||
width: 400px;
|
||||
height: 60px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
}
|
||||
}
|
||||
|
||||
:deep( .AiPersonSelect ){
|
||||
& > button {
|
||||
background: #F5F5F5;
|
||||
border-radius: 0px 2px 2px 0px;
|
||||
border: 1px solid #D0D4DC;
|
||||
color: #222222;
|
||||
}
|
||||
}
|
||||
|
||||
.person-select {
|
||||
background: #F5F5F5;
|
||||
border-radius: 0px 2px 2px 0px;
|
||||
border: 1px solid #D0D4DC;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
:deep( .msg-title ){
|
||||
& > .aibar {
|
||||
justify-content: flex-start;
|
||||
|
||||
& > .aibar-right {
|
||||
margin-left: 64px;
|
||||
font-size: 14px;
|
||||
color: #888888 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,141 +0,0 @@
|
||||
<template>
|
||||
<ai-list isTabs>
|
||||
<template slot="content">
|
||||
<ai-search-bar class="search-bar" bottomBorder>
|
||||
<template slot="left">
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="newClient">新建群发</el-button>
|
||||
</template>
|
||||
<template slot="right">
|
||||
<el-input
|
||||
v-model="search.name"
|
||||
class="search-input"
|
||||
size="small"
|
||||
v-throttle="() => {search.current = 1, getList()}"
|
||||
placeholder="请输入标题或编号"
|
||||
clearable
|
||||
@clear="search.current = 1, search.name = '', getList()"
|
||||
suffix-icon="iconfont iconSearch" />
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:stripe="true"
|
||||
:total="total"
|
||||
ref="aitableex"
|
||||
style="margin-top: 20px;"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="identityNumber" label="群发内容" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-popover
|
||||
placement="right"
|
||||
width="400"
|
||||
trigger="hover">
|
||||
<div>您可以查询到本村(居)的基本情况、小微权力公开情况,并进行留言评价。您自己操作一下看看,是不是很简单?</div>
|
||||
<!-- <ai-file-list :fileList="fileList" :fileOps="{name: 'name', size: 'fileSizeStr'}"></ai-file-list>-->
|
||||
<span style="cursor: pointer;" slot="reference">{{row.identityNumber}}</span>
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span class="table-btn" title="提醒发送" @click="remind(row.id)">提醒发送</span>
|
||||
<span class="table-btn" title="详情" @click="toDetail(row)">详情</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'TableList',
|
||||
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
permissions:Function
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
fileList:[],
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
name: ''
|
||||
},
|
||||
total: 0,
|
||||
colConfigs: [
|
||||
{ prop: 'name', label: '群发类型', align: 'center', width: '200' },
|
||||
{ prop: 'phone', label: '类型', align: 'center' },
|
||||
{ slot: 'identityNumber', label: '群发内容', align: 'center'},
|
||||
{ prop: 'registTime', label: '发送时间', align: 'center' },
|
||||
{ prop: 'recordUser', label: '已发送成员', align: 'center' },
|
||||
{ prop: 'recordUser', label: '未发送成员', align: 'center' },
|
||||
{ prop: 'recordUser', label: '已送达成员', align: 'center' },
|
||||
{ prop: 'recordUser', label: '未送达成员', align: 'center' },
|
||||
{ slot: 'options', label: '操作', align: 'center' }
|
||||
],
|
||||
tableData: [],
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
toDetail(row){
|
||||
this.$emit("change",{
|
||||
type:"NewClientMass",
|
||||
row:{row,isAdd:false}
|
||||
})
|
||||
},
|
||||
newClient(){
|
||||
this.$emit("change",{
|
||||
type:"NewClientMass",
|
||||
row:{row:"",isAdd:true}
|
||||
})
|
||||
},
|
||||
|
||||
getList() {
|
||||
this.instance.post(`/app/apppetition/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
status: 1
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
remind (id) {
|
||||
|
||||
},
|
||||
|
||||
onAdd () {
|
||||
this.$emit('change', {
|
||||
type: 'add'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table-btn{
|
||||
font-size: 14px;
|
||||
color: #2266FF;
|
||||
cursor: pointer;
|
||||
&:nth-child(1){
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,50 +0,0 @@
|
||||
<template>
|
||||
<section class="AppMassNotification">
|
||||
<keep-alive :include="['List']">
|
||||
<component ref="component" :is="currentPage" :instance="instance" :params="params" :dict="dict" @change="onChange"/>
|
||||
</keep-alive>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from "./components/List.vue";
|
||||
import Add from "./components/Add.vue";
|
||||
|
||||
export default {
|
||||
name: "AppMassNotification",
|
||||
label: "群发通知",
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
},
|
||||
components: {Add, List},
|
||||
data() {
|
||||
return {
|
||||
component: "List",
|
||||
params: {},
|
||||
include: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentPage() {
|
||||
const {hash} = this.$route
|
||||
return hash == "#add" ? Add : List
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onChange(data) {
|
||||
if (data.type === "Add") {
|
||||
this.$router.push({hash: "#add", query: data.params})
|
||||
} else {
|
||||
this.$router.push({})
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppMassNotification {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -1,413 +0,0 @@
|
||||
<template>
|
||||
<section class="Add">
|
||||
<ai-detail v-if="!$route.query.id">
|
||||
<template slot="title">
|
||||
<ai-title title="群发通知" isShowBack isShowBottomBorder @onBackClick="cancel(false)"></ai-title>
|
||||
</template>
|
||||
|
||||
<template slot="content">
|
||||
<ai-card>
|
||||
<template #title>
|
||||
<div class="ai-card__title">
|
||||
<h2>发送条件</h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<el-form size="small" class="ai-form" :rules="rules" ref="form" :model="form" label-width="100px" label-position="right">
|
||||
<el-form-item label="发送方式" prop="messageSource" style="width: 50%">
|
||||
<el-radio-group v-model="form.messageSource" @change="sourceChange" >
|
||||
<el-radio label="2">居民群</el-radio>
|
||||
<el-radio label="1">居民</el-radio>
|
||||
</el-radio-group>
|
||||
|
||||
</el-form-item>
|
||||
<el-form-item label="地区选择" style="width: 100%">
|
||||
<ai-area-get v-model="areaId" :root="areaRootId" :instance="instance" @select="handleAreaSelect" multiple size="small" placeholder="请选择"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="发送范围" prop="deptList" style="width: 100%">
|
||||
<select-dept-user v-model="form.deptList" v-bind="$props" :source="form.messageSource"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-card>
|
||||
|
||||
<ai-card title="群发消息设置">
|
||||
<template #content>
|
||||
<el-form class="ai-form" ref="form" :rules="rules" :model="form" label-width="110px" label-position="right">
|
||||
<el-form-item class="el-form-item__textarea" label="群发内容" prop="content" style="width: 100%">
|
||||
<el-input type="textarea" placeholder="请输入…" v-model="form.content" maxlength="1000" :rows="5" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<!-- 图片 -->
|
||||
<el-form-item label="图片" style="width: 100%">
|
||||
<ai-uploader :instance="instance" isWechat v-model="imgList" multiple acceptType=".jpg,.png,.jpeg" :limit="9"
|
||||
url="/app/wxcp/upload/uploadFile?type=image"></ai-uploader>
|
||||
</el-form-item>
|
||||
<!-- 视频 -->
|
||||
<el-form-item label="视频" style="width: 100%">
|
||||
<ai-uploader :instance="instance" fileType="file" isWechat multiple acceptType=".mp4" v-model="videoList" :limit="9"
|
||||
url="/app/wxcp/upload/uploadFile?type=video"></ai-uploader>
|
||||
</el-form-item>
|
||||
<!-- 附件 -->
|
||||
<el-form-item label="附件" style="width: 100%">
|
||||
<ai-uploader :instance="instance" fileType="file" isWechat multiple v-model="filesList" :limit="9"
|
||||
url="/app/wxcp/upload/uploadFile?type=file"></ai-uploader>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
<el-button type="primary" @click="confirm">确认发送</el-button>
|
||||
</template>
|
||||
|
||||
</ai-detail>
|
||||
|
||||
<ai-detail class="add" v-if="$route.query.id">
|
||||
<template slot="title">
|
||||
<ai-title title="群发通知详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)"></ai-title>
|
||||
</template>
|
||||
<template slot="content">
|
||||
<ai-card title="详情">
|
||||
<template #content>
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="创建者" :value="data.userName" isLine></ai-info-item>
|
||||
<ai-info-item label="发送方式" :value="data.messageSource" isLine>{{ data.messageSource | format }}</ai-info-item>
|
||||
</ai-wrapper>
|
||||
|
||||
<ai-wrapper v-for="item in data.fileList" :key="item.id">
|
||||
<ai-info-item label="群发内容" :value="item.content" isLine v-if="item.contentType == 'text'"></ai-info-item>
|
||||
</ai-wrapper>
|
||||
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="图片" isLine v-show="images.length">
|
||||
<ai-uploader v-model="images" :instance="instance" :limit="9" disabled/>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="视频" isLine v-show="videoArr.length" v-for="(item,index) in videoArr" :key="index">
|
||||
<video :src="item.accessUrl" style="width: 100%; height:100%; object-fit: fill;" muted controls="controls"></video>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
|
||||
<ai-wrapper>
|
||||
<ai-info-item label="附件" isLine v-show="fileDownLoad.length">
|
||||
<ai-file-list :fileList="fileDownLoad"></ai-file-list>
|
||||
</ai-info-item>
|
||||
</ai-wrapper>
|
||||
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import SelectDeptUser from "./SelectDeptUser";
|
||||
|
||||
export default {
|
||||
name: 'Add',
|
||||
components: {SelectDeptUser},
|
||||
props: {
|
||||
instance: Function,
|
||||
dict: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShow: false,
|
||||
data: {},
|
||||
form: {
|
||||
areaId: '',
|
||||
tag: '',
|
||||
messageSource: '2',
|
||||
sendTime: '',
|
||||
content: '',
|
||||
contentType: 'text',
|
||||
fileList: [],
|
||||
organization: '',
|
||||
deptList: [],
|
||||
},
|
||||
tags: [],
|
||||
subTags: {},
|
||||
areaId: [],
|
||||
areaName: [],
|
||||
imgList: [],
|
||||
videoList: [],
|
||||
filesList: [],
|
||||
fileDownLoad: [],
|
||||
areaRootId: '',
|
||||
users: [],
|
||||
images: [],
|
||||
imgs: [],
|
||||
videos: [],
|
||||
videoArr: [],
|
||||
files: [],
|
||||
flag: false,
|
||||
rules: {
|
||||
deptList: [{required: true, message: '请选择发送范围'}],
|
||||
content: [{required: true, message: '请输入群发内容'}],
|
||||
messageSource: [{required: true, message: '请选择群发方式'}],
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
tagsChange() {
|
||||
if (this.tags?.length) {
|
||||
return this.form.tag = this.tags.toString();
|
||||
}
|
||||
},
|
||||
areaid() {
|
||||
return this.form.areaId = this.areaId.toString();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.$route.query.id) {
|
||||
this.getInfo()
|
||||
}
|
||||
this.areaRootId = [this.user.info.areaId.substr(0, 6), '000000'].join("")
|
||||
},
|
||||
filters: {
|
||||
format(val) {
|
||||
if(val == 1) {
|
||||
return '居民'
|
||||
} else if(val == 2) {
|
||||
return '居民群'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleAreaSelect(v) {
|
||||
this.areaName = v?.[0]?.label
|
||||
},
|
||||
sourceChange(val) {
|
||||
this.form.messageSource = val
|
||||
this.form.deptList = []
|
||||
},
|
||||
getInfo() {
|
||||
this.instance.post(`/app/pushmessage/detail?id=${this.$route.query.id}`).then(res => {
|
||||
if (res?.data) {
|
||||
this.data = res.data
|
||||
this.images = res.data.fileList.filter(e => e.contentType == "image")?.map(i => {
|
||||
return {
|
||||
url: i.accessUrl
|
||||
}
|
||||
})
|
||||
this.fileDownLoad = res.data.fileList.filter(e => e.contentType == "file")?.map(v => {
|
||||
return {
|
||||
url: v.accessUrl
|
||||
}
|
||||
})
|
||||
if (res.data.fileList.filter(e => e.contentType == "video")) {
|
||||
this.videoArr = res.data.fileList.filter(e => e.contentType == "video")
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
},
|
||||
confirm() {
|
||||
if(this.flag) return
|
||||
|
||||
if(!this.form.deptList.length) {
|
||||
return this.$message.error('请选择发送范围')
|
||||
}
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.flag = true
|
||||
|
||||
this.form.fileList = []
|
||||
let contentList = [{
|
||||
content: this.form.content,
|
||||
contentType: 'text'
|
||||
}]
|
||||
|
||||
if (this.imgList.length) {
|
||||
this.imgs = this.imgList.map(item => {
|
||||
return {
|
||||
contentType: 'image',
|
||||
mediaId: item.media.mediaId,
|
||||
accessUrl: item.url,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (this.videoList.length) {
|
||||
this.videos = this.videoList.map(item => {
|
||||
return {
|
||||
contentType: 'video',
|
||||
mediaId: item.media.mediaId,
|
||||
accessUrl: item.url,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (this.filesList.length) {
|
||||
this.files = this.filesList.map(item => {
|
||||
return {
|
||||
contentType: 'file',
|
||||
mediaId: item.media.mediaId,
|
||||
accessUrl: item.url,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.form.fileList = [...contentList, ...this.imgs, ...this.videos, ...this.files]
|
||||
|
||||
this.instance.post(`/app/pushmessage/addOrUpdate`, {
|
||||
...this.form
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('提交成功')
|
||||
setTimeout(() => {
|
||||
this.cancel(true)
|
||||
}, 600)
|
||||
} else {
|
||||
this.flag = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.flex = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
cancel(isRefresh) {
|
||||
this.$emit('change', {
|
||||
type: 'List',
|
||||
isRefresh: !!isRefresh
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.Add {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ai-card__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
h2 {
|
||||
margin-right: 20px;
|
||||
color: #222222;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #888888;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.appletss {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.applets-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 400px;
|
||||
height: 60px;
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
padding: 0 17px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
border-color: #2266FF;
|
||||
}
|
||||
|
||||
:deep( ){
|
||||
.el-radio__label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 8px 0 13px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #222222;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.el-radio {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&.applets-active {
|
||||
border-color: #2266FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tips {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
padding-left: 8px;
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.el-form-item-item__textarea {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.el-form-item__btn {
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
left: 12px;
|
||||
line-height: 1;
|
||||
z-index: 1;
|
||||
color: #2266FF;
|
||||
font-size: 14px;
|
||||
user-select: none;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tags {
|
||||
// padding: 10px;
|
||||
.tag_title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tag_item {
|
||||
margin: 5px 0;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
// padding: 5px 10px;
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
background: #DDD;
|
||||
color: #333;
|
||||
border-radius: 4px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.active {
|
||||
background: #53bcea;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
@@ -1,210 +0,0 @@
|
||||
<template>
|
||||
<ai-list class="List">
|
||||
<template #title>
|
||||
<ai-title title="群发通知" isShowBottomBorder></ai-title>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size"
|
||||
@getList="getTableData" show-overflow-tooltip :col-configs="colConfigs" :dict="dict">
|
||||
<!-- <el-table-column slot="type" width="240px" label="消息内容" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
width="400"
|
||||
:visible-arrow="false"
|
||||
popper-class="wechat-message__container"
|
||||
trigger="hover">
|
||||
<div class="count row-content" slot="reference" v-if="row.content">{{ row.content }}</div>
|
||||
<div class="message-info">
|
||||
<h2 :style="{marginBottom: row.accessUrl ? '16px' : '0'}">{{ row.content }}</h2>
|
||||
<div class="message-info__wrapper" v-if="row.accessUrl">
|
||||
<img v-if="row.contentType == 'image'" :src="row.accessUrl">
|
||||
<video style="width:40px; height: 40px;" v-if="row.contentType == 'video'" :src="row.accessUrl"></video>
|
||||
<img src="../../../../examples/assets/file.png" v-if="row.contentType == 'file'" width="40" height="40"/>
|
||||
<div class="message-info__wrapper--right">
|
||||
<h3 v-if="row.contentType === 'image'">{{ row.media.file.name }}</h3>
|
||||
<h3 v-if="row.contentType === 'video'">{{ row.media.file.name }}</h3>
|
||||
<p v-if="row.contentType === 'image'">{{ row.media.file.fileSizeStr }}</p>
|
||||
<p v-if="row.contentType === 'video'">{{ row.media.file.fileSizeStr }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<el-table-column slot="options" label="操作" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button type="text" @click="toAdd(row.id)">详情</el-button>
|
||||
<!-- <el-button type="text" @click="handleDelete(row.id)">删除</el-button> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: "List",
|
||||
props: {
|
||||
dict: Object,
|
||||
instance: Function,
|
||||
params: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
page: {current: 1, size: 10, total: 0, pages: 0},
|
||||
id: '',
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTableData()
|
||||
},
|
||||
computed: {
|
||||
colConfigs() {
|
||||
let conType = {
|
||||
text: "文本",
|
||||
image: "图片",
|
||||
video: "视频",
|
||||
file: "附件"
|
||||
}
|
||||
return [
|
||||
// { prop: "fileList", label: '消息类型', align: "center", width: "250px", formart: v => v?.map(e=> conType[e.contentType]).toString() },
|
||||
{ prop: "fileList", label: '消息内容', align: "center", width: "250px", formart: v => v?.filter(e=> e.contentType == 'text')[0].content },
|
||||
// { prop: "fileList", label: '消息内容', align: "center", width: "250px", formart: v => v?.filter(e => e.contentType == 'text')[0].content},
|
||||
// { slot: 'type' },
|
||||
{ prop: "messageSource", label: '消息类型', align: "center", formart: v => v==1? '居民': '居民群'},
|
||||
{ prop: "createTime", label: '创建时间', align: "center", width: "250px"},
|
||||
{ prop: "userName", label: '创建人', align: "center", width: "250px", },
|
||||
{ slot: "options" ,},
|
||||
]
|
||||
},
|
||||
...mapState(['user'])
|
||||
},
|
||||
|
||||
methods: {
|
||||
getTableData() {
|
||||
this.instance.post(`/app/pushmessage/list?`, null, {
|
||||
params: {
|
||||
...this.page,
|
||||
}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.tableData = res.data.records
|
||||
this.page.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
mapType(type) {
|
||||
return {
|
||||
'image': '图片',
|
||||
'video': '视频',
|
||||
'file': '文件',
|
||||
'text': '文本'
|
||||
}[type]
|
||||
},
|
||||
|
||||
toAdd(id) {
|
||||
this.$emit('change', {
|
||||
type: 'Add',
|
||||
params: {
|
||||
id: id || '',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.List {
|
||||
height: 100%;
|
||||
background: #f3f4f5;
|
||||
|
||||
.count {
|
||||
cursor: pointer;
|
||||
color: #2266FF;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
img, video {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.message-info {
|
||||
padding: 8px;
|
||||
min-height: 116px;
|
||||
|
||||
h2 {
|
||||
color: #222222;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.message-info__wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 368px;
|
||||
height: 60px;
|
||||
padding: 10px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
|
||||
.message-info__wrapper--right {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
h3 {
|
||||
width: 100%;
|
||||
color: #222222;
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
img, video {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 6px;
|
||||
font-size: 14px;
|
||||
color: #888888;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.row-content {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
</style>
|
||||
@@ -1,195 +0,0 @@
|
||||
<template>
|
||||
<section class="SelectDeptUser">
|
||||
<el-input :value="selectText" disabled size="small" @click.native="dialog=true">
|
||||
<el-button type="text" slot="append">开始选择</el-button>
|
||||
</el-input>
|
||||
<ai-dialog :visible.sync="dialog" title="选择部门/人员" width="700px" @onConfirm="handleSubmit" @close="selected=[],getDepts()">
|
||||
<el-breadcrumb separator="/">
|
||||
<el-breadcrumb-item v-for="(item, index) in selectDeptPath" :key="index">
|
||||
<el-button type="text" @click="deptNameClick(item)">{{ item.name }}</el-button>
|
||||
</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<div class="optionsItem" v-for="(row, index) in options" :key="index">
|
||||
<el-row type="flex">
|
||||
<el-checkbox class="fill" :label="row.uid" v-model="row.checked" @change="handleCheck(row,index)">{{ row.name }}</el-checkbox>
|
||||
<el-button type="text" v-if="!row.parentid&&row.kind=='dept'" @click="openDialogTag(row)">添加标签</el-button>
|
||||
<el-button type="text" v-if="row.kind=='dept'" @click="itemClick(row)">更多</el-button>
|
||||
</el-row>
|
||||
<el-tag effect="dark" size="small" v-for="tag in row.selectedTags" :key="tag.id" class="mar-4">{{ tag.name }}</el-tag>
|
||||
</div>
|
||||
<ai-empty v-if="!options.length"/>
|
||||
<ai-dialog :visible.sync="dialogTag" title="选择标签" width="500px" @onConfirm="handleSelectTag" @close="selectedTags=[]" append-to-body>
|
||||
<el-checkbox-group v-model="selectedTags">
|
||||
<div class="optionsItem" v-for="(cls, index) in tagOps" :key="index">
|
||||
<ai-title :title="cls.name"/>
|
||||
<el-checkbox class="fill" v-for="(op, i) in cls.tagList" :key="i" :label="op.id">{{ op.name }}</el-checkbox>
|
||||
</div>
|
||||
</el-checkbox-group>
|
||||
<ai-empty v-if="!tagOps.length"/>
|
||||
</ai-dialog>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "SelectDeptUser",
|
||||
model: {
|
||||
event: "change",
|
||||
prop: "value"
|
||||
},
|
||||
props: {
|
||||
value: {default: ""},
|
||||
instance: Function,
|
||||
dict: Object,
|
||||
source: {default: 1}
|
||||
},
|
||||
computed: {
|
||||
selectText: v => v.value?.length > 0 ? "已选择" : "请选择",
|
||||
tagAction: v => v.source == 2 ? '/app/wxcp/wxgroupchattag/listAllByCorp' : '/app/wxcp/wxcorptag/listAllByCorp'
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: false,
|
||||
dialogTag: false,
|
||||
currentCorp: {},
|
||||
selected: [],
|
||||
selectDeptPath: [],
|
||||
selectedTags: [],
|
||||
options: [],
|
||||
tagOps: [],
|
||||
allData: [],
|
||||
tags: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getDepts() {
|
||||
this.instance.post('/app/wxcp/wxdepartment/listAllByCorp').then(res => {
|
||||
if (res?.data) {
|
||||
let parents = res.data.map(e => e.parentid)
|
||||
this.allData = res.data.map(e => ({
|
||||
...e,
|
||||
hasChildren: parents.includes(e.id),
|
||||
uid: [e.corpId, e.id].join("_"),
|
||||
kind: 'dept',
|
||||
checked: false
|
||||
}))
|
||||
this.deptInit()
|
||||
}
|
||||
})
|
||||
},
|
||||
getTagsByCorp(dvcpCorpId) {
|
||||
return this.instance.post(this.tagAction, null, {
|
||||
params: {
|
||||
dvcpCorpId,
|
||||
size: 9999
|
||||
}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
return this.tagOps = res.data.records || []
|
||||
}
|
||||
})
|
||||
},
|
||||
deptInit() {
|
||||
this.options = this.allData.filter(e => !e.parentid)
|
||||
this.selectDeptPath = [{name: "可选范围", id: ''}]
|
||||
},
|
||||
itemClick(row) {
|
||||
let index = this.selectDeptPath.findIndex(e => e.id == row.id)
|
||||
if (index == -1) {
|
||||
this.selectDeptPath.push(row)
|
||||
this.getDeptsAndUsersByParent(row)
|
||||
}
|
||||
},
|
||||
getDeptsAndUsersByParent(row) {
|
||||
let {id: departmentId, corpId: cid} = row
|
||||
this.options = this.allData.filter(e => e.parentid == departmentId && e.corpId == cid) || []
|
||||
this.instance.post(`/app/wxcp/wxuser/listByDeptId`, null, {
|
||||
params: {departmentId, status: 1, cid}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
res.data = res.data.map(e => ({
|
||||
...e, kind: "user", checked: this.selected.some(s => {
|
||||
if (e.id == s.id) return true
|
||||
})
|
||||
}))
|
||||
this.options = [this.options, res.data].flat()
|
||||
}
|
||||
})
|
||||
},
|
||||
deptNameClick(row, index) {
|
||||
if (!index) { //第一级别
|
||||
this.deptInit()
|
||||
} else {
|
||||
let length = this.selectDeptPath.length - index
|
||||
this.selectDeptPath.splice(index + 1, length)
|
||||
this.getDeptsAndUsersByParent(row.id)
|
||||
}
|
||||
},
|
||||
openDialogTag(row) {
|
||||
this.getTagsByCorp(row.corpId).then(() => {
|
||||
this.currentCorp = row
|
||||
this.dialogTag = true
|
||||
})
|
||||
},
|
||||
handleSelectTag() {
|
||||
let {corpId} = this.currentCorp
|
||||
this.currentCorp.selectedTags = this.$copy(this.tagOps.map(e => e.tagList).flat().filter(e => this.selectedTags.includes(e.id)))
|
||||
this.tags[corpId] = this.$copy(this.currentCorp.selectedTags)
|
||||
this.dialogTag = false
|
||||
},
|
||||
handleSubmit() {
|
||||
let result = {}
|
||||
this.selected?.map(e => {
|
||||
let {kind, id} = e
|
||||
result[e.corpId] = [result[e.corpId], {kind, id}].flat()
|
||||
})
|
||||
let selected = Object.keys(result).map(corpId => {
|
||||
let res
|
||||
if (result[corpId]) {
|
||||
res = {
|
||||
corpId,
|
||||
objList: result[corpId].filter(e => !!e)
|
||||
}
|
||||
if (this.tags[corpId]?.length > 0) {
|
||||
res.tagId = this.tags[corpId]?.map(e => e.id)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}).filter(e => !!e)
|
||||
this.$emit("change", selected)
|
||||
this.dialog = false
|
||||
},
|
||||
isSelected(uid) {
|
||||
return !!this.selected.find(e => e.uid == uid)
|
||||
},
|
||||
handleCheck(row, i) {
|
||||
if (row.checked) {
|
||||
this.selected.push(row)
|
||||
} else {
|
||||
this.selected.splice(i, 1)
|
||||
}
|
||||
this.$forceUpdate()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getDepts()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.SelectDeptUser {
|
||||
:deep(.optionsItem ){
|
||||
border: 1px solid #eee;
|
||||
margin-bottom: 8px;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
|
||||
.mar-4 {
|
||||
margin-right: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user