Commit 92e84446 authored by 王's avatar

群发消息

parent cd7e343f
...@@ -4,6 +4,46 @@ ...@@ -4,6 +4,46 @@
<el-table <el-table
:data="tableData" :data="tableData"
style="width: 100%"> style="width: 100%">
<el-table-column type="expand">
<template slot-scope="props">
<el-table
:border="false"
:data="[JSON.parse(props.row.content)]">
<el-table-column
label="类型"
>
<template slot-scope="item">
{{item.row.type | typeFilter}}
</template>
</el-table-column>
<el-table-column
v-if="JSON.parse(props.row.content).type !== 'text'"
prop="media_id"
label="media_id"
>
<template slot-scope="item">
{{item.row.content}}
</template>
</el-table-column>
<el-table-column
prop="url"
label="内容"
>
<template slot-scope="item">
<div v-if="item.row.type === 'text'">
<span v-html="item.row.content.replace(/\/[\u4E00-\u9FA5]{1,3}/gi, emotion)"></span>
</div>
<div v-else-if="item.row.type === 'image'">
<img style="width: 80px;" :src="item.row.url"/>
</div>
<div v-else-if="item.row.type === 'video'">
<a :href="item.row.url" target="_blank">点击查看视频</a>
</div>
</template>
</el-table-column>
</el-table>
</template>
</el-table-column>
<el-table-column <el-table-column
prop="send_id" prop="send_id"
label="消息ID"> label="消息ID">
...@@ -38,7 +78,7 @@ ...@@ -38,7 +78,7 @@
type="text" type="text"
plain plain
size="mini"> size="mini">
查询结果 查询及时结果
</el-button> </el-button>
</template> </template>
</el-table-column> </el-table-column>
...@@ -47,7 +87,13 @@ ...@@ -47,7 +87,13 @@
<el-dialog title="新建群发消息" <el-dialog title="新建群发消息"
:visible.sync="show"> :visible.sync="show">
<el-form ref="searchFrom" :model="searchFrom" label-width="150px"> <el-form ref="searchFrom" :model="searchFrom" label-width="150px">
<el-form-item label="时间"> <el-form-item label="是否发送筛选用户">
<el-switch
v-model="searchFrom.is_test"
active-color="#13ce66"
inactive-color="#ff4949"/>
</el-form-item>
<el-form-item label="时间" v-if="searchFrom.is_test">
<el-date-picker <el-date-picker
v-model="searchFrom.time" v-model="searchFrom.time"
type="datetimerange" type="datetimerange"
...@@ -57,15 +103,16 @@ ...@@ -57,15 +103,16 @@
:default-time="['00:00:00','23:59:59']"> :default-time="['00:00:00','23:59:59']">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="是否发送筛选用户"> <el-row>
<el-switch <el-col :span="16">
v-model="searchFrom.is_test" <el-form-item label="用户ID">
active-color="#13ce66" <el-input v-model="searchFrom.user_ids"></el-input>
inactive-color="#ff4949"/> </el-form-item>
</el-form-item> </el-col>
<el-form-item label="额外添加的open_id"> <el-col :span="8">
<el-input v-model="searchFrom.test_open_ids"></el-input> <el-button type="primary" @click="onSelectUser">选择用户</el-button>
</el-form-item> </el-col>
</el-row>
<el-tabs v-model="activeName" type="card" @tab-click="handleClick"> <el-tabs v-model="activeName" type="card" @tab-click="handleClick">
<el-tab-pane label="文本" name="text"> <el-tab-pane label="文本" name="text">
<div class="inner-edit_area"> <div class="inner-edit_area">
...@@ -76,6 +123,21 @@ ...@@ -76,6 +123,21 @@
v-model="content"> v-model="content">
</el-input> </el-input>
</div> </div>
<div style="float: right">
<el-popover
placement="bottom-end"
width="400"
:offset="10"
trigger="hover"
v-model="showEmotion">
<div>
<emotion @emotion="handleEmotion" :height="200" ></emotion>
</div>
<el-button @click="showEmotion = !showEmotion" slot="reference" type="text">
<span class="icon_emotion emotion_switch"></span>
</el-button>
</el-popover>
</div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="图片" name="image"> <el-tab-pane label="图片" name="image">
<div class="inner-edit_area"> <div class="inner-edit_area">
...@@ -96,7 +158,7 @@ ...@@ -96,7 +158,7 @@
<el-upload <el-upload
class="upload-video" class="upload-video"
action="/api/public/upload/zone" action="/api/public/upload/zone"
:http-request="uploadVideoFile" :http-request="uploadVideo"
:file-list="fileList" :file-list="fileList"
:on-remove="handleRemoveVideo" :on-remove="handleRemoveVideo"
:limit="1"> :limit="1">
...@@ -111,18 +173,74 @@ ...@@ -111,18 +173,74 @@
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button type="primary" @click="send()">确 定</el-button> <el-button type="primary" @click="send()">确 定</el-button>
</span> </span>
<el-dialog :visible.sync="userDialog.show" append-to-body>
<el-form label-width="90px">
<el-row>
<el-col :span="8">
<el-form-item label="ID">
<el-input v-model="searchUserFrom.userId"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="昵称">
<el-input v-model="searchUserFrom.nickName"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="电话">
<el-input v-model="searchUserFrom.mobile"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8" :offset="16">
<el-form-item>
<el-button style="float: right" type="primary" plain @click="getUser">搜索</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-table
:data="userList"
ref="multipleTable"
@selection-change="handleSelectionChange"
style="width: 100%">
<el-table-column
type="selection"
width="55">
</el-table-column>
<el-table-column
className="f-c"
label="用户">
<template slot-scope="scope">
<img style="margin-right:5px;width: 50px;height: 50px;border-radius: 50px" :src="scope.row.avatar">{{scope.row.nickname}}(ID:{{scope.row.user_id}})
</template>
</el-table-column>
<el-table-column
prop="mobile"
label="手机号">
</el-table-column>
</el-table>
<page :total="userDialog.total" :limit="userDialog.limit" @pageChange="onUserPageChange"/>
<span slot="footer" class="dialog-footer">
<el-button @click="userDialog.show = false">取 消</el-button>
<el-button type="primary" @click="onConfirm">确 定</el-button>
</span>
</el-dialog>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script> <script>
import {uploadFileApi,getMsgListApi,sendMsgApi} from "../../service/api"; import {uploadFileApi,getMsgListApi,sendMsgApi,getUserListApi} from "../../service/api";
import page from '../framework/page' import page from '../framework/page'
import emotion from '../framework/Emotion/index'
import CommonJs from '../../util/common'; import CommonJs from '../../util/common';
export default { export default {
name: "index", name: "index",
components: { components: {
page page,
emotion
}, },
data() { data() {
return { return {
...@@ -141,7 +259,25 @@ ...@@ -141,7 +259,25 @@
videoContent: '', videoContent: '',
searchFrom: {}, searchFrom: {},
tableData: [], tableData: [],
fileUid: null fileUid: null,
userDialog: {
total: 0,
limit: 10,
nowPage: 1,
show: false
},
userList: [],
searchUserFrom: {},
multipleSelection: [],
showEmotion: false
}
},
filters: {
typeFilter(val){
if(!val) return;
if(val === 'text') return '文本';
if(val === 'image') return '图片';
if(val === 'video') return '视频';
} }
}, },
methods: { methods: {
...@@ -164,28 +300,43 @@ ...@@ -164,28 +300,43 @@
this.imageList = [{name:res.data.url,url:process.env.IMAGE_URL_HEAD + res.data.url}] this.imageList = [{name:res.data.url,url:process.env.IMAGE_URL_HEAD + res.data.url}]
}, },
uploadFile(a) { uploadFile(a) {
this.loading = true;
this.$store.dispatch('setProgress',{type:'new',id:a.file.uid}); this.$store.dispatch('setProgress',{type:'new',id:a.file.uid});
uploadFileApi({file:a.file,type:'local'}).then(res=>{ uploadFileApi({file:a.file,type:'wechat'}).then(res=>{
this.imageList = [{name:res.url,url:process.env.IMAGE_URL_HEAD + res.url}] this.imageContent = {
this.imageContent = process.env.IMAGE_URL_HEAD + res.url; content: res.media_id,
console.log('this.imageContent', this.imageContent) url: res.url
this.loading = false; }
this.imageList = [{name:res.media_id,url:res.url}]
this.$message({ this.$message({
type: 'success', type: 'success',
message: '上传成功!' message: '上传成功!'
}); });
}).catch(()=>{ }).catch(()=>{
this.loading = false; this.$message({
type: 'error',
message: '上传失败!'
});
}) })
}, },
uploadVideoFile(a) { uploadVideo(a){
uploadFileApi({file:a.file,type:'wechat'}).then(res=>{
this.uploadVideoFile(a, res)
}).catch(()=>{
this.$message({
type: 'error',
message: '上传失败!'
});
})
},
uploadVideoFile(a,data) {
this.fileUid = a.file.uid; this.fileUid = a.file.uid;
this.loading = true; this.loading = true;
this.$store.dispatch('setProgress',{type:'new',id:a.file.uid}); this.$store.dispatch('setProgress',{type:'new',id:a.file.uid});
uploadFileApi({file:a.file,type:'local'}).then(res=>{ uploadFileApi({file:a.file,type:'local'}).then(res=>{
console.log('uploadVideoFile', res); this.videoContent = {
this.videoContent = process.env.IMAGE_URL_HEAD + res.url; content: data.media_id,
url: process.env.IMAGE_URL_HEAD + res.url
}
this.fileList = [{name:res.name,url:process.env.IMAGE_URL_HEAD + res.url}] this.fileList = [{name:res.name,url:process.env.IMAGE_URL_HEAD + res.url}]
this.loading = false; this.loading = false;
this.$message({ this.$message({
...@@ -196,19 +347,33 @@ ...@@ -196,19 +347,33 @@
this.fileUid=null this.fileUid=null
}).catch(()=>{ }).catch(()=>{
this.loading = false; this.loading = false;
this.$message({
type: 'error',
message: '上传失败!'
});
}) })
}, },
send(){ send(){
let json = {} let json = {}
if(this.searchFrom.time && this.searchFrom.time.length > 0){ if(this.searchFrom.is_test){
json.start_at = CommonJs.dateFmt(this.searchFrom.time[0],"yyyy-MM-dd hh:mm:ss"); if(this.searchFrom.time && this.searchFrom.time.length > 0){
json.end_at = CommonJs.dateFmt(this.searchFrom.time[1],"yyyy-MM-dd hh:mm:ss") json.start_at = CommonJs.dateFmt(this.searchFrom.time[0],"yyyy-MM-dd hh:mm:ss");
} else { json.end_at = CommonJs.dateFmt(this.searchFrom.time[1],"yyyy-MM-dd hh:mm:ss")
} else {
this.$message({
type: 'error',
message: '请选择时间!'
});
return
}
}
if(this.searchFrom.user_ids){
json.user_ids = this.searchFrom.user_ids
}else {
this.$message({ this.$message({
type: 'error', type: 'error',
message: '请选择时间!' message: '请加入内部人员!'
}); });
return
} }
let _content = {} let _content = {}
_content.type = this.activeName; _content.type = this.activeName;
...@@ -230,7 +395,8 @@ ...@@ -230,7 +395,8 @@
}); });
return return
} else { } else {
_content.content = this.imageContent; _content.content = this.imageContent.content;
_content.url = this.imageContent.url;
} }
} else if (this.activeName === 'video') { } else if (this.activeName === 'video') {
...@@ -241,14 +407,12 @@ ...@@ -241,14 +407,12 @@
}); });
return return
} else { } else {
_content.content = this.videoContent; _content.content = this.videoContent.content;
_content.url = this.videoContent.url
} }
} }
json.content = JSON.stringify(_content) json.content = JSON.stringify(_content)
json.is_test = this.searchFrom.is_test ? 1 : 2 json.is_test = this.searchFrom.is_test ? 2 : 1
if(this.searchFrom.test_open_ids){
json.test_open_ids = this.searchFrom.test_open_ids
}
sendMsgApi(json).then((res)=>{ sendMsgApi(json).then((res)=>{
this.$message({ this.$message({
message: res, message: res,
...@@ -295,7 +459,76 @@ ...@@ -295,7 +459,76 @@
}); });
this.getMsgList(); this.getMsgList();
}) })
} },
getUser(){
let json = {
page: this.userDialog.nowPage,
limit: this.userDialog.limit
};
if (this.searchUserFrom.userId) {
json.user_id = this.searchUserFrom.userId
}
if (this.searchUserFrom.nickName) {
json.nickname = this.searchUserFrom.nickName
}
if (this.searchUserFrom.mobile) {
json.mobile = this.searchUserFrom.mobile
}
getUserListApi(json).then(res=>{
this.userList = res.list;
this.userDialog.total = res.total;
})
},
onUserPageChange(val){
this.userDialog.nowPage = val
this.getUser()
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
onSelectUser(){
this.userDialog.show = true;
if(this.searchFrom.user_ids) {
this.multipleSelection = this.searchFrom.user_ids.split(',');
} else {
this.multipleSelection = []
}
this.getUser();
},
onConfirm(){
let _list = this.multipleSelection;
if(_list.length === 0) {
this.$message({
type: 'error',
message: '请选择用户!'
});
} else {
let _userIds = [];
_list.forEach((item)=>{
_userIds.push(item.user_id)
})
let _tmp = _userIds
if (this.searchFrom.user_ids) {
_tmp = _userIds.concat(this.searchFrom.user_ids.split(','));
}
let _result = this.dedupe(_tmp);
this.searchFrom.user_ids = _result.join(',');
this.userDialog.show = false;
this.multipleSelection = [];
}
},
dedupe(array){
return Array.from(new Set(array));
},
emotion (res) {
let word = res.replace(/\//gi,'')
const list = ['微笑', '撇嘴', '色', '发呆', '得意', '流泪', '害羞', '闭嘴', '睡', '大哭', '尴尬', '发怒', '调皮', '呲牙', '惊讶', '难过', '酷', '冷汗', '抓狂', '吐', '偷笑', '可爱', '白眼', '傲慢', '饥饿', '困', '惊恐', '流汗', '憨笑', '大兵', '奋斗', '咒骂', '疑问', '嘘', '晕', '折磨', '衰', '骷髅', '敲打', '再见', '擦汗', '抠鼻', '鼓掌', '糗大了', '坏笑', '左哼哼', '右哼哼', '哈欠', '鄙视', '委屈', '快哭了', '阴险', '亲亲', '吓', '可怜', '菜刀', '西瓜', '啤酒', '篮球', '乒乓', '咖啡', '饭', '猪头', '玫瑰', '凋谢', '示爱', '爱心', '心碎', '蛋糕', '闪电', '炸弹', '刀', '足球', '瓢虫', '便便', '月亮', '太阳', '礼物', '拥抱', '强', '弱', '握手', '胜利', '抱拳', '勾引', '拳头', '差劲', '爱你', 'NO', 'OK', '爱情', '飞吻', '跳跳', '发抖', '怄火', '转圈', '磕头', '回头', '跳绳', '挥手', '激动', '街舞', '献吻', '左太极', '右太极']
let index = list.indexOf(word)
return `<img src="https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/${index}.gif" align="middle">`
},
handleEmotion (i) {
this.content += i
},
}, },
mounted(){ mounted(){
this.getMsgList(); this.getMsgList();
...@@ -335,4 +568,15 @@ ...@@ -335,4 +568,15 @@
padding: 20px; padding: 20px;
color: #666; color: #666;
} }
.emotion_switch {
float: left;
height: 28px;
line-height: 999em;
overflow: hidden;
background: transparent url(https://res.wx.qq.com/mpres/en_US/htmledition/pages/modules/reply/images/icon_emotion_switch.png) no-repeat 0 0;
width: 20px;
height: 20px;
vertical-align: middle;
display: inline-block;
}
</style> </style>
...@@ -96,6 +96,7 @@ ...@@ -96,6 +96,7 @@
this.searchFrom.priceList.push(i.current_price) this.searchFrom.priceList.push(i.current_price)
}); });
this.goodsList=res.list this.goodsList=res.list
this.searchPage();
}) })
}, },
searchPage(){ searchPage(){
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment