index.blade.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. @extends('Yunshop\WorkWechat::layouts.base')
  2. @section('title', '群管理')
  3. @section('content')
  4. <link rel="stylesheet" href="{{resource_get('plugins/work-wechat-platform/static/css/index.css')}}">
  5. <style>
  6. </style>
  7. <div class="all">
  8. <div id="app" v-cloak>
  9. <div class="vue-head">
  10. <div class="vue-main-title" style="margin-bottom:20px">
  11. <div class="vue-main-title-left"></div>
  12. <div class="vue-main-title-content">群拓客 > 群管理</div>
  13. <div class="vue-main-title-button">
  14. <el-button
  15. type="primary"
  16. icon="el-icon-refresh"
  17. size="mini"
  18. @click="syncData"
  19. >同步群信息</el-button>
  20. </div>
  21. </div>
  22. <div class="vue-search">
  23. <el-form :inline="true" :model="search_form" class="demo-form-inline">
  24. <el-form-item label="">
  25. <el-input v-model="search_form.id" placeholder="群ID"></el-input>
  26. </el-form-item>
  27. <el-form-item label="">
  28. <el-input v-model="search_form.name" placeholder="群名称"></el-input>
  29. </el-form-item>
  30. <el-form-item label="">
  31. <el-input v-model="search_form.owner_name" placeholder="群主"></el-input>
  32. </el-form-item>
  33. <el-form-item label="">
  34. <el-input v-model="search_form.owner_member_kwd" placeholder="锁客会员昵称/姓名/手机号"></el-input>
  35. </el-form-item>
  36. <el-form-item label="">
  37. <el-input v-model="search_form.owner_member_uid" placeholder="锁客会员会员ID"></el-input>
  38. </el-form-item>
  39. <el-form-item label="">
  40. <el-date-picker
  41. v-model="times"
  42. type="datetimerange"
  43. value-format="yyyy-MM-dd HH:mm:ss"
  44. range-separator="至"
  45. start-placeholder="开始时间"
  46. end-placeholder="结束时间"
  47. style="margin-left:5px;"
  48. align="right">
  49. </el-date-picker>
  50. </el-form-item>
  51. <el-form-item label="">
  52. <el-button type="primary" @click="search(1)">搜索</el-button>
  53. <el-button @click="export1()">导出</el-button>
  54. </el-form-item>
  55. </el-form>
  56. </div>
  57. <div>
  58. <p>同步群信息时,请不要离开此页面,以免影响同步进度!</p>
  59. </div>
  60. </div>
  61. <div class="vue-main">
  62. <div class="vue-main-form">
  63. <div class="vue-main-title" style="margin-bottom:20px">
  64. <div class="vue-main-title-left"></div>
  65. <div class="vue-main-title-content" style="flex:0 0 130px">群列表</div>
  66. <div class="" style="text-align:left;font-size:14px;color:#999">
  67. <span>群数量:[[total]]</span>&nbsp;&nbsp;&nbsp;
  68. <span>群客户总数量(未去重):[[summary.all_members]]</span>&nbsp;&nbsp;&nbsp;
  69. <span>群客户数量(去重):[[summary.all_distinct_members]]</span>&nbsp;&nbsp;&nbsp;
  70. </div>
  71. <div class="vue-main-title-button">
  72. </div>
  73. </div>
  74. <el-table :data="list" style="width: 100%">
  75. <el-table-column label="ID" align="center" prop="id" width="100"></el-table-column>
  76. <el-table-column label="创建时间" align="center" prop="group_created_time_str">
  77. </el-table-column>
  78. <el-table-column label="群名" align="center" prop="group_name">
  79. </el-table-column>
  80. <el-table-column label="群主" align="center" prop="owner_name">
  81. </el-table-column>
  82. <el-table-column align="center" prop="mobile">
  83. <template slot="header" slot-scope="scope">
  84. <div>外部客户数量</div>
  85. <div>企业员工数量</div>
  86. </template>
  87. <template slot-scope="scope">
  88. [[scope.row.customer_count]]<br>
  89. [[scope.row.employee_count]]
  90. </template>
  91. </el-table-column>
  92. <el-table-column label="锁客会员" align="center" prop="username">
  93. <template slot-scope="scope">
  94. <div style="cursor: pointer" @click="openMember(scope.row.id)">
  95. <div v-if="scope.row.has_one_owner_member">
  96. <div>
  97. <img :src="scope.row.has_one_owner_member.avatar_image" style="width:30px;height:30px;padding:1px;border:1px solid #ccc">
  98. </div>
  99. <div>
  100. [[scope.row.has_one_owner_member.nickname]]
  101. </div>
  102. </div>
  103. <div v-else>
  104. <i class="el-icon-plus" style="font-size: 18px;font-weight: 600;"></i>
  105. </div>
  106. </div>
  107. </template>
  108. </el-table-column>
  109. <el-table-column label="群二维码" align="center" prop="qrcode_url">
  110. <template slot-scope="scope">
  111. <a :href="scope.row.qrcode_image" v-if="scope.row.qrcode_url">
  112. <img :src="scope.row.qrcode_image" style="width:30px;height:30px;padding:1px;border:1px solid #ccc">
  113. </a>
  114. </template>
  115. </el-table-column>
  116. <el-table-column prop="refund_time" label="操作" align="center" width="100">
  117. <template slot-scope="scope">
  118. <el-dropdown trigger="click">
  119. <span class="el-dropdown-link">
  120. <el-button size="small">操作</el-button>
  121. </span>
  122. <el-dropdown-menu slot="dropdown">
  123. <el-dropdown-item @click.native="gotoGroupMembers(scope.row.id)">群成员</el-dropdown-item>
  124. <el-dropdown-item @click.native="showUploadDialog(scope.row)">上传群二维码</el-dropdown-item>
  125. <el-dropdown-item @click.native="showNewPost(scope.row.id)">生成海报</el-dropdown-item>
  126. </el-dropdown-menu>
  127. </el-dropdown>
  128. </template>
  129. </el-table-column>
  130. </el-table>
  131. </div>
  132. </div>
  133. <!-- 分页 -->
  134. <div class="vue-page" v-if="total>0">
  135. <el-row>
  136. <el-col align="right">
  137. <el-pagination layout="prev, pager, next,jumper" @current-change="search" :total="total"
  138. :page-size="per_page" :current-page="current_page" background
  139. ></el-pagination>
  140. </el-col>
  141. </el-row>
  142. </div>
  143. <!-- 选择会员 -->
  144. <el-dialog title="选择会员" :visible.sync="member_show" width="60%">
  145. <div>
  146. <el-input v-model="member_keyword" style="width:60%;" placeholder="会员手机号码"></el-input>
  147. <el-button @click="getMember" >搜索</el-button>
  148. </div>
  149. <el-table :data="member_list" style="width: 100%;height:400px;overflow:auto;margin-top: 10px;" v-loading="member_loading">
  150. <el-table-column label="ID" prop="uid" align="center" width="100px"></el-table-column>
  151. <el-table-column label="会员信息">
  152. <template slot-scope="scope">
  153. <div style="display:flex;align-items: center;">
  154. <div v-if="scope.row.avatar_image" style="width:40px;">
  155. <el-image :src="scope.row.avatar_image" alt="" style="width:40px;height:40px;border-radius:50%"></el-image>
  156. </div>
  157. <div style="flex:1;">【id:[[scope.row.uid]]】[[scope.row.nickname]]</div>
  158. </div>
  159. </template>
  160. </el-table-column>
  161. <el-table-column prop="refund_time" label="操作" align="center" width="320">
  162. <template slot-scope="scope">
  163. <el-button @click="chooseMember(scope.row)">
  164. 选择
  165. </el-button>
  166. </template>
  167. </el-table-column>
  168. </el-table>
  169. <span slot="footer" class="dialog-footer">
  170. <el-button @click="member_show = false">取 消</el-button>
  171. </span>
  172. </el-dialog>
  173. <!-- 上传二维码 -->
  174. <el-dialog title="上传二维码" :visible.sync="uploadDialogShow" width="60%">
  175. <el-form ref="upload_qrcode_img_form" label-width="15%">
  176. <el-form-item label="二维码" prop="avatar">
  177. <div class="upload-box" @click="openUpload('qrcode_image')" v-if="!current_qrcode_image">
  178. <i class="el-icon-plus" style="font-size:32px"></i>
  179. </div>
  180. <div @click="openUpload('qrcode_image')" class="upload-boxed" v-if="current_qrcode_image">
  181. <img :src="current_qrcode_image" alt="" style="width:150px;height:150px;border-radius: 5px;cursor: pointer;">
  182. <div class="upload-boxed-text">点击重新上传</div>
  183. <div @click.stop="clearImg('qrcode_image')" style="cursor: pointer">
  184. <i class="el-icon-close"></i>点击清除图片
  185. </div>
  186. </div>
  187. <div class="tip">提示: 需通过新海报插件添加群拓客海报,上传二维码图片仅需要上传二维码部分,方形图片!</div>
  188. </el-form-item>
  189. </el-form>
  190. <span slot="footer" class="dialog-footer">
  191. <el-button @click="saveQrcodeImg">保 存</el-button>
  192. <el-button @click="uploadDialogShow = false">取 消</el-button>
  193. </span>
  194. </el-dialog>
  195. <el-dialog title="海报" :visible.sync="new_post_show" width="500">
  196. <div style="display:flex">
  197. <div class="center" style="width:280px;height:410px;margin:0 auto" >
  198. <img :src="new_post_show_url" alt="" style="width:100%;">
  199. </div>
  200. </div>
  201. <span slot="footer" class="dialog-footer">
  202. <el-button type="primary" @click="download(new_post_show_url,'poster')">下载海报</el-button>
  203. <!-- <el-button @click="share_show = false">取 消</el-button> -->
  204. <!-- <el-button type="primary" @click="img_text_url = false">确 定</el-button> -->
  205. </span>
  206. </el-dialog>
  207. <upload-img :upload-show="uploadShow" :name="chooseImgName" @replace="changeProp" @sure="sureImg"></upload-img>
  208. </div>
  209. </div>
  210. @include('public.admin.uploadImg')
  211. <script>
  212. var app = new Vue({
  213. el: "#app",
  214. delimiters: ['[[', ']]'],
  215. name: 'test',
  216. data() {
  217. return {
  218. list:[],
  219. summary:{},
  220. times:[],
  221. search_form:{
  222. id:'',
  223. name:'',
  224. owner_name:'',
  225. owner_member_kwd:'',
  226. owner_member_uid:''
  227. },
  228. uploadDialogShow:false,
  229. uploadShow:false,
  230. chooseImgName:'',
  231. current_id:0,
  232. current_row:{},
  233. current_qrcode_image:'',
  234. // 会员
  235. member_keyword:'',
  236. member_show:false,
  237. member_list:[],
  238. member_loading:false,
  239. choosed_member:{},
  240. new_post_show:false,
  241. new_post_show_url:'',
  242. rules: {},
  243. current_page:1,
  244. total:1,
  245. per_page:1,
  246. loading: null,
  247. }
  248. },
  249. created() {
  250. },
  251. destroyed() {
  252. if (this.timer) {
  253. clearInterval(this.timer);
  254. }
  255. },
  256. mounted() {
  257. this.getData(1);
  258. },
  259. methods: {
  260. getData(page) {
  261. let json = {
  262. page:page,
  263. id:this.search_form.id,
  264. name:this.search_form.name,
  265. owner_name:this.search_form.owner_name,
  266. owner_member_kwd:this.search_form.owner_member_kwd,
  267. owner_member_uid:this.search_form.owner_member_uid
  268. };
  269. if(this.times && this.times.length>0) {
  270. json.start_time = this.times[0];
  271. json.end_time = this.times[1];
  272. }
  273. let loading = this.$loading({target:document.querySelector(".content"),background: 'rgba(0, 0, 0, 0)'});
  274. this.$http.post('{!! yzWebFullUrl('plugin.group-develop-user.manage.groupChat.get-list') !!}',json).then(function(response) {
  275. if (response.data.result) {
  276. this.list = response.data.data.list.data;
  277. this.current_page=response.data.data.list.current_page;
  278. this.total=response.data.data.list.total;
  279. this.per_page=response.data.data.list.per_page;
  280. this.summary = response.data.data.summary;
  281. loading.close();
  282. } else {
  283. this.$message({
  284. message: response.data.msg,
  285. type: 'error'
  286. });
  287. }
  288. loading.close();
  289. }, function(response) {
  290. this.$message({
  291. message: response.data.msg,
  292. type: 'error'
  293. });
  294. loading.close();
  295. });
  296. },
  297. export1(){
  298. var that = this;
  299. console.log(that.search_form);
  300. var url = "{!! yzWebFullUrl('plugin.group-develop-user.manage.groupChat.list-export') !!}";
  301. if (that.search_form.id) {
  302. url += "&id="+that.search_form.id;
  303. }
  304. if (that.search_form.name) {
  305. url += "&name="+that.search_form.name;
  306. }
  307. if (that.search_form.owner_name) {
  308. url += "&owner_name="+that.search_form.owner_name;
  309. }
  310. if (that.search_form.owner_member_kwd) {
  311. url += "&owner_member_kwd="+that.search_form.owner_member_kwd;
  312. }
  313. if (that.search_form.owner_member_uid) {
  314. url += "&owner_member_uid="+that.search_form.owner_member_uid;
  315. }
  316. if(that.times && that.times.length>0) {
  317. url += "&start_time="+that.times[0]+"&end_time="+that.times[1];
  318. }
  319. console.log(url);
  320. window.location.href = url;
  321. },
  322. syncData() {
  323. this.$confirm('确定同步吗?该过程可能耗时较长,同步完成前,请不要离开此页面,以免影响同步进度!', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {
  324. this.loading = this.$loading({target:document.querySelector(".content"),background: 'rgba(0, 0, 0, 0)'});
  325. this.count = 0;
  326. this.$http.post('{!! yzWebFullUrl('plugin.group-develop-user.manage.groupChat.synch') !!}',{is_start:1}).then(function (response) {
  327. if (response.data.result) {
  328. this.loop(1,response.data.data.next_cursor);
  329. }
  330. else{
  331. this.$message({type: 'error',message: response.data.msg});
  332. }
  333. },function (response) {
  334. this.$message({type: 'error',message: response.data.msg});
  335. this.loading.close();
  336. }
  337. );
  338. }).catch(() => {
  339. this.$message({type: 'info',message: '已取消操作'});
  340. });
  341. },
  342. loop(index,next_cursor) {
  343. this.$http.post('{!! yzWebFullUrl('plugin.group-develop-user.manage.groupChat.synch') !!}',{next_cursor:next_cursor}).then(function (response) {
  344. if (response.data.result) {
  345. if (!response.data.data.next_cursor) {
  346. this.$message({type: 'success',message: '数据同步成功!'});
  347. this.getData(this.current_page);
  348. this.loading.close();
  349. } else {
  350. index++;
  351. this.$message({type: 'success',message: "已同步"+(index)+"个群数据"});
  352. this.loop(index,response.data.data.next_cursor);
  353. }
  354. }
  355. else{
  356. this.$message({type: 'error',message: response.data.msg});
  357. }
  358. },function (response) {
  359. this.$message({type: 'error',message: response.data.msg});
  360. this.loading.close();
  361. }
  362. );
  363. },
  364. search(val) {
  365. this.getData(val);
  366. },
  367. openMember(id) {
  368. this.current_id = id;
  369. this.member_show = true;
  370. },
  371. getMember(){
  372. this.$http.post("{!! yzWebUrl('plugin.work-wechat.manage.member.query') !!}",{keyword:this.member_keyword}).then(response => {
  373. if (response.data.result) {
  374. this.member_list=response.data.data
  375. }else{
  376. this.$message({type: 'error',message: response.data.msg});
  377. }
  378. }, response => {
  379. this.$message({type: 'error',message: response.data.msg});
  380. console.log(response);
  381. });
  382. },
  383. chooseMember(row) {
  384. this.choosed_member = row;
  385. this.bindUser(this.current_id,row.uid);
  386. this.member_show = false;
  387. console.log(this.form)
  388. },
  389. bindUser(id,uid){
  390. this.$http.post("{!! yzWebUrl('plugin.group-develop-user.manage.groupChat.bind-user') !!}",{id:id,uid:uid}).then(response => {
  391. if (response.data.result) {
  392. let current_page = this.current_page;
  393. this.getData(current_page);
  394. this.$message({type: 'success',message: '操作成功'});
  395. }else{
  396. this.$message({type: 'error',message: response.data.msg});
  397. }
  398. }, response => {
  399. this.$message({type: 'error',message: response.data.msg});
  400. console.log(response);
  401. });
  402. },
  403. gotoGroupMembers(id){
  404. window.location.href = `{!! yzWebFullUrl('plugin.group-develop-user.manage.groupChat.groupMember') !!}`+`&group_id=`+id;
  405. },
  406. showUploadDialog(row){
  407. this.uploadDialogShow = true;
  408. this.current_row = row;
  409. this.current_qrcode_image = row.qrcode_image;
  410. },
  411. openUpload(str) {
  412. this.chooseImgName = str;
  413. this.uploadShow = true;
  414. },
  415. changeProp(val) {
  416. if(val == true) {
  417. this.uploadShow = false;
  418. }
  419. else {
  420. this.uploadShow = true;
  421. }
  422. },
  423. sureImg(name,image,image_url) {
  424. //console.log(image_url);
  425. this.current_qrcode_image = image_url;
  426. },
  427. clearImg(str) {
  428. this.current_qrcode_image = '';
  429. this.$forceUpdate();
  430. },
  431. saveQrcodeImg(){
  432. this.$http.post("{!! yzWebUrl('plugin.group-develop-user.manage.groupChat.save-qrcode-img') !!}",{id:this.current_row.id,qrcode_url:this.current_qrcode_image}).then(response => {
  433. if (response.data.result) {
  434. let current_page = this.current_page;
  435. this.getData(current_page);
  436. this.current_qrcode_image = '';
  437. this.uploadDialogShow = false;
  438. this.uploadShow = false;
  439. this.$message({type: 'success',message: '操作成功'});
  440. }else{
  441. this.$message({type: 'error',message: response.data.msg});
  442. }
  443. }, response => {
  444. this.$message({type: 'error',message: response.data.msg});
  445. console.log(response);
  446. });
  447. },
  448. showNewPost(id){
  449. this.$http.post("{!! yzWebUrl('plugin.group-develop-user.manage.groupChat.get-new-post') !!}",{id:id}).then(response => {
  450. if (response.data.result) {
  451. this.new_post_show = true;
  452. this.new_post_show_url=response.data.data.image_url
  453. }else{
  454. this.$message({type: 'error',message: response.data.msg});
  455. }
  456. }, response => {
  457. this.$message({type: 'error',message: response.data.msg});
  458. console.log(response);
  459. });
  460. },
  461. download(href, name) {
  462. let eleLink = document.createElement("a");
  463. eleLink.download = name;
  464. eleLink.href = href;
  465. eleLink.click();
  466. eleLink.remove();
  467. }
  468. },
  469. })
  470. </script>
  471. @endsection