初始化
This commit is contained in:
		| @@ -0,0 +1,89 @@ | ||||
| <template> | ||||
|   <ai-list v-if="!isShowDetail"> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="居民群管理" :isShowBottomBorder="false"></ai-title> | ||||
|     </template> | ||||
|     <template slot="tabs"> | ||||
|       <el-tabs v-model="currIndex"> | ||||
|         <el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label"> | ||||
|           <component :ref="String(i)" v-if="currIndex == i" :is="tab.comp" @change="onChange" lazy :instance="instance" :dict="dict" :permissions="permissions"/> | ||||
|         </el-tab-pane> | ||||
|       </el-tabs> | ||||
|     </template> | ||||
|   </ai-list> | ||||
|   <Detail v-else-if="componentName === 'Detail'" :params="params" :instance="instance" :dict="dict" :permissions="permissions" @change="onChange"></Detail> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import List from './components/List.vue' | ||||
|   import Statistics from './components/Statistics' | ||||
|   import Tags from './components/Tags' | ||||
|   import Detail from './components/Detail' | ||||
|   import { mapState } from 'vuex' | ||||
|  | ||||
|   export default { | ||||
|     name: 'AppResidentGroupManage', | ||||
|     label: '居民群管理', | ||||
|  | ||||
|     components: { | ||||
|       List, | ||||
|       Tags, | ||||
|       Detail, | ||||
|       Statistics | ||||
|     }, | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       permissions: Function | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       ...mapState(['user']), | ||||
|  | ||||
|       tabs () { | ||||
|         const tabList = [ | ||||
|           {label: '居民群列表', name: 'List', comp: List, permission: ''}, | ||||
|           {label: '居民群统计', name: 'Statistics', comp: Statistics, permission: ''}, | ||||
|           {label: '居民群标签', name: 'Tags', comp: Tags, permission: ''} | ||||
|         ].filter(item => { | ||||
|           return true | ||||
|         }) | ||||
|  | ||||
|         return tabList | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         activeName: 'JoinEvent', | ||||
|         currIndex: '0', | ||||
|         componentName: '', | ||||
|         params: {}, | ||||
|         isShowDetail: false | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       onChange (data) { | ||||
|         if (data.type === 'list') { | ||||
|           this.componentName = 'List' | ||||
|           this.isShowDetail = false | ||||
|           this.params = data.params | ||||
|         } | ||||
|  | ||||
|         if (data.type === 'detail') { | ||||
|           this.componentName = 'Detail' | ||||
|           this.isShowDetail = true | ||||
|           this.params = data.params | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| </style> | ||||
							
								
								
									
										377
									
								
								packages/wechat/AppResidentGroupManage/components/Detail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										377
									
								
								packages/wechat/AppResidentGroupManage/components/Detail.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,377 @@ | ||||
| <template> | ||||
|   <ai-detail class="AppResidentManage"> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="居民群详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)"></ai-title> | ||||
|     </template> | ||||
|     <template slot="content"> | ||||
|       <div class="detail-top"> | ||||
|         <div class="detail-top__header"> | ||||
|           <div class="header-left"> | ||||
|             <img src="https://cdn.cunwuyun.cn/dvcp/h5/groupAvatar.png"> | ||||
|             <div class="header-left__right"> | ||||
|               <h2>{{ info.name }}</h2> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div class="header-right"> | ||||
| <!--            <div class="header-right__item">--> | ||||
| <!--              <span>成员总数</span>--> | ||||
| <!--              <h3>{{ chartData.groupSum}}</h3>--> | ||||
| <!--            </div>--> | ||||
|             <div class="header-right__item"> | ||||
|               <span>成员总数</span> | ||||
|               <h3>{{chartData.today && chartData.today.total }}</h3> | ||||
|             </div> | ||||
|             <div class="header-right__item"> | ||||
|               <span>今日新增</span> | ||||
|               <h3>{{ chartData.today && chartData.today.increase }}</h3> | ||||
|             </div> | ||||
|             <div class="header-right__item"> | ||||
|               <span>今日流失</span> | ||||
|               <h3>{{chartData.today && chartData.today.decrease}}</h3> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="detail-top__content"> | ||||
|           <ai-wrapper | ||||
|             label-width="80px"> | ||||
|             <ai-info-item label="群主" :value="info.ownerName"></ai-info-item> | ||||
|             <ai-info-item label="群公告" :value="info.notice" isLine></ai-info-item> | ||||
|             <ai-info-item label="群聊标签" isLine> | ||||
|               <div class="table-tags"> | ||||
|                 <el-tag type="info" v-for="(item, index) in info.tagList" size="small" :key="index">{{ item.tagName }} | ||||
|                 </el-tag> | ||||
|               </div> | ||||
|             </ai-info-item> | ||||
|           </ai-wrapper> | ||||
|         </div> | ||||
|       </div> | ||||
|       <ai-card title="图表数据"> | ||||
|         <template slot="content"> | ||||
|           <div id="lineChart"></div> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|       <ai-card title="成员列表"> | ||||
|         <template slot="content"> | ||||
|           <ai-table | ||||
|             :tableData="tableData" | ||||
|             :col-configs="colConfigs" | ||||
|             :total="total" | ||||
|             border | ||||
|             ref="aitableex" | ||||
|             @getList="getDynamicInfo" | ||||
|             :current.sync="search.current" | ||||
|             :size.sync="search.size"> | ||||
|             <el-table-column slot="options" label="操作" width="100" align="center"> | ||||
|               <template slot-scope="{ row }"> | ||||
|                 <el-button type="text" v-if="row.type==2 && row.avatar" @click="toDetail(row)">居民详情</el-button> | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|           </ai-table> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|     </template> | ||||
|   </ai-detail> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import * as echarts from 'echarts' | ||||
|  | ||||
|   export default { | ||||
|     name: 'Detail', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       params: Object | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       colConfigs() { | ||||
|         return [ | ||||
|           { | ||||
|             prop: 'memberName', label: '成员',render:(h,{row})=>[<img class="avatar" src={row.avatar || "https://cdn.cunwuyun.cn/dvcp/h5/defaultAvatar.png"} />, | ||||
|           <span>{row.memberName}</span>, | ||||
|           <span style={{color:row.customerType==1 ? '#2EA222' : '#3C7FC8',marginLeft:'8px'}}>{ row.customerType?(row.customerType==1 ? '@微信' : '@' + row.corpName):''  }</span>], | ||||
|       }, | ||||
|           {prop: 'type', label: '类型',render:(h,{row})=>[<span>{this.dict.getLabel("wxGroupMemberType",row.type)}</span>]}, | ||||
|           {prop: 'joinTime', label: '入群时间'}, | ||||
|           {prop: 'joinScene', label: '入群方式',render:(h,{row})=>[<span>{this.dict.getLabel("wxGroupMemberJoinScene",row.joinScene)}</span>]}, | ||||
|           {slot: "options"}, | ||||
|         ] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     data() { | ||||
|       return { | ||||
|         isShow: false, | ||||
|         info: {}, | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10 | ||||
|         }, | ||||
|         total: 0, | ||||
|         tableData: [], | ||||
|         chart: null, | ||||
|         chartData: {}, | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created() { | ||||
|       this.dict.load("wxGroupMemberJoinScene", "wxGroupMemberType") | ||||
|     }, | ||||
|  | ||||
|     mounted() { | ||||
|       if (this.params && this.params.id) { | ||||
|         this.getInfo() | ||||
|         this.getDynamicInfo() | ||||
|         this.getChart() | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getChart() { | ||||
|         this.instance.post(`/app/wxcp/wxgroup/groupStatistic`, null, { | ||||
|           params: { | ||||
|             id: this.params.id | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res && res.data) { | ||||
|             this.chartData = res.data | ||||
|             this.initChart() | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|       initChart() { | ||||
|         this.chart = echarts.init(document.getElementById('lineChart')) | ||||
|         this.setOptions() | ||||
|       }, | ||||
|       setOptions() { | ||||
|         const x = Object.keys(this.chartData.list) | ||||
|         const y = Object.values(this.chartData.list) | ||||
|         this.chart.setOption({ | ||||
|           tooltip: { | ||||
|             trigger: 'axis' | ||||
|           }, | ||||
|           legend: { | ||||
|             type: "plain" | ||||
|           }, | ||||
|           grid: { | ||||
|             left: '20px', | ||||
|             right: '38px', | ||||
|             bottom: '14px', | ||||
|             top: '30px', | ||||
|             containLabel: true | ||||
|           }, | ||||
|           color: ['#2266FF', '#22AA99', '#F8B425'], | ||||
|           xAxis: { | ||||
|             type: 'category', | ||||
|             axisLabel: { | ||||
|               align: 'center', | ||||
|               padding: [2, 0, 0, 0], | ||||
|               interval: 0, | ||||
|               fontSize: 14, | ||||
|               color: '#666666' | ||||
|             }, | ||||
|             boundaryGap: false, | ||||
|             axisLine: { | ||||
|               lineStyle: { | ||||
|                 color: '#E1E5EF' | ||||
|               } | ||||
|             }, | ||||
|             data: x | ||||
|           }, | ||||
|           yAxis: { | ||||
|             axisTick: { | ||||
|               length: 0, | ||||
|               show: false | ||||
|             }, | ||||
|             splitLine: { | ||||
|               show: true, | ||||
|               lineStyle: { | ||||
|                 color: ['#E1E5EF'], | ||||
|                 width: 1, | ||||
|                 type: 'solid' | ||||
|               } | ||||
|             }, | ||||
|             nameTextStyle: { | ||||
|               color: '#666666', | ||||
|               align: 'left' | ||||
|             }, | ||||
|             axisLine: { | ||||
|               show: false | ||||
|             }, | ||||
|             axisLabel: { | ||||
|               color: '#666666' | ||||
|             }, | ||||
|             type: 'value' | ||||
|           }, | ||||
|           series: [ | ||||
|             { | ||||
|               name: '成员总数', | ||||
|               type: 'line', | ||||
|               data: y.map(v => v.total) | ||||
|             }, | ||||
|             { | ||||
|               name: '新增成员数', | ||||
|               type: 'line', | ||||
|               data: y.map(v => v.increase) | ||||
|             }, | ||||
|             { | ||||
|               name: '流失成员数', | ||||
|               type: 'line', | ||||
|               data: y.map(v => v.decrease) | ||||
|             } | ||||
|           ] | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       getInfo() { | ||||
|         this.instance.post(`/app/wxcp/wxgroup/getDetail?id=${this.params.id}`).then(res => { | ||||
|           if (res && res.data) { | ||||
|             this.info = res.data | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       getDynamicInfo() { | ||||
|         this.instance.post(`/app/wxcp/wxgroup/listMember?groupId=${this.params.id}`, null, { | ||||
|           params: { | ||||
|             ...this.search | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code === 0) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       toDetail(row) { | ||||
|         this.$router.push({ | ||||
|           name: '居民管理', | ||||
|           query: { | ||||
|             id: row.userId, | ||||
|             type: 'Detail' | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       cancel(isRefresh) { | ||||
|         this.$emit('change', { | ||||
|           type: 'list', | ||||
|           isRefresh: isRefresh ? true : false | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
|   .AppResidentManage { | ||||
|     ::v-deep .ai-detail__content--wrapper { | ||||
|       max-width: 100% !important; | ||||
|       padding: 20px; | ||||
|     } | ||||
|  | ||||
|     h2, h3 { | ||||
|       margin: 0; | ||||
|     } | ||||
|  | ||||
|     .detail-top { | ||||
|       padding: 30px 40px; | ||||
|       background: #FFFFFF; | ||||
|       box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15); | ||||
|       border-radius: 2px; | ||||
|       margin-bottom: 20px; | ||||
|  | ||||
|       .detail-top__content { | ||||
|         padding-top: 32px; | ||||
|       } | ||||
|  | ||||
|       .detail-top__header { | ||||
|         display: flex; | ||||
|         justify-content: space-between; | ||||
|         align-items: center; | ||||
|         padding-bottom: 32px; | ||||
|         border-bottom: 1px solid #EEEEEE; | ||||
|  | ||||
|         .header-right { | ||||
|           .header-right__item { | ||||
|             width: 120px; | ||||
|             margin-right: 8px; | ||||
|             text-align: center; | ||||
|           } | ||||
|  | ||||
|           div { | ||||
|             text-align: center; | ||||
|  | ||||
|             &:last-child { | ||||
|               margin-right: 0; | ||||
|             } | ||||
|  | ||||
|             span { | ||||
|               display: block; | ||||
|               margin-bottom: 10px; | ||||
|               color: #888888; | ||||
|             } | ||||
|           } | ||||
|  | ||||
|           .el-button { | ||||
|             height: 28px; | ||||
|             margin-left: 8px; | ||||
|             border-radius: 14px; | ||||
|             font-size: 12px; | ||||
|             padding: 7px 15px; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         .header-left, .header-right { | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|         } | ||||
|  | ||||
|         .header-left { | ||||
|           img { | ||||
|             width: 64px; | ||||
|             height: 64px; | ||||
|             margin-right: 16px; | ||||
|           } | ||||
|  | ||||
|           h2 { | ||||
|             margin-bottom: 6px; | ||||
|             color: #222222; | ||||
|             font-size: 16px; | ||||
|           } | ||||
|  | ||||
|           p { | ||||
|             color: #2EA222; | ||||
|             font-size: 14px; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     #lineChart { | ||||
|       width: 100%; | ||||
|       height: 336px; | ||||
|     } | ||||
|  | ||||
|     .table-tags { | ||||
|       .el-tag { | ||||
|         margin-right: 8px; | ||||
|  | ||||
|         &:last-child { | ||||
|           margin-right: 0; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     ::v-deep .avatar { | ||||
|       width: 40px; | ||||
|       height: 40px; | ||||
|       vertical-align: middle; | ||||
|       margin-right: 8px; | ||||
|       object-fit: fill; | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										401
									
								
								packages/wechat/AppResidentGroupManage/components/List.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										401
									
								
								packages/wechat/AppResidentGroupManage/components/List.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,401 @@ | ||||
| <template> | ||||
|   <ai-list class="AppPetitionManage" isTabs> | ||||
|     <template slot="content"> | ||||
|       <ai-search-bar class="search-bar"> | ||||
|         <template slot="left"> | ||||
| <!--          <ai-select--> | ||||
| <!--            v-model="search.owner"--> | ||||
| <!--            filterable--> | ||||
| <!--            @change="search.current = 1, getList()"--> | ||||
| <!--            placeholder="群主"--> | ||||
| <!--            :selectList="userList">--> | ||||
| <!--          </ai-select>--> | ||||
|           <ai-select | ||||
|             v-model="search.tagId" | ||||
|             @change="search.current = 1, getList()" | ||||
|             placeholder="选择标签" | ||||
|             :selectList="subTags"> | ||||
|           </ai-select> | ||||
|         </template> | ||||
|         <template slot="right"> | ||||
|           <el-input | ||||
|             v-model="search.name" | ||||
|             class="search-input" | ||||
|             size="small" | ||||
|             @keyup.enter.native="search.current = 1, getList()" | ||||
|             placeholder="请输入群主/群名称" | ||||
|             clearable | ||||
|             @change="getList" | ||||
|             @clear="search.current = 1, search.name = '', getList()" | ||||
|             suffix-icon="iconfont iconSearch"> | ||||
|           </el-input> | ||||
|         </template> | ||||
|       </ai-search-bar> | ||||
|       <ai-search-bar> | ||||
|         <template slot="left"> | ||||
|           <el-button type="primary" icon="iconfont iconAdd" @click="isShow = true" :disabled="!ids.length">批量打群标签 | ||||
|           </el-button> | ||||
|         </template> | ||||
|         <template slot="left"> | ||||
|           <el-button type="primary" icon="iconfont iconDelete" @click="onConfirm(1)" :disabled="!ids.length">批量移除群标签 | ||||
|           </el-button> | ||||
|         </template> | ||||
|         <template slot="right"> | ||||
|           <el-button type="primary" icon="iconfont iconResetting" @click="update">更新数据</el-button> | ||||
|         </template> | ||||
|       </ai-search-bar> | ||||
|       <ai-table | ||||
|         :tableData="tableData" | ||||
|         :col-configs="colConfigs" | ||||
|         :total="total" | ||||
|         ref="aitableex" | ||||
|         :current.sync="search.current" | ||||
|         @selection-change="handleSelectionChange" | ||||
|         :size.sync="search.size" | ||||
|         v-loading="isLoading" | ||||
|         @getList="getList"> | ||||
|         <el-table-column slot="avatar" label="" width="80" align="center"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="avatar" style="text-align: right;justify-content: end;"> | ||||
|               <img :src="row.avatar"> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column slot="userinfo" label="群名称" show-overflow-tooltip width="300px" align="left"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="userinfo"> | ||||
|               <div class="userinfo-right ellipsis"> | ||||
|                 <div class="userinfo-right__top"> | ||||
|                   <h3>{{ row.name || "群聊" }}</h3> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column slot="tags" label="群标签" align="left"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-tags"> | ||||
|               <el-tag type="info" v-for="(item, index) in row.tagList" size="medium" :key="index">{{ item.tagName }} | ||||
|               </el-tag> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column slot="options" label="操作" width="100" fixed="right" align="center"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-options"> | ||||
|               <el-button type="text" @click="toDetail(row.id)">详情</el-button> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </ai-table> | ||||
|       <ai-dialog | ||||
|         :visible.sync="isShow" | ||||
|         width="800px" | ||||
|         title="批量打标签" | ||||
|         @close="chooseTags = []" | ||||
|         @onConfirm="onConfirm"> | ||||
|         <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.indexOf(item.id) === -1 ? '' : 'primary'" | ||||
|                 v-for="(item, index) in item.tagList" | ||||
|                 @click="choose(item.id)" | ||||
|                 :key="index"> | ||||
|                 {{ item.name }} | ||||
|               </el-button> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </ai-dialog> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import {mapState} from 'vuex' | ||||
|  | ||||
|   export default { | ||||
|     name: 'List', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, dict: Object | ||||
|     }, | ||||
|  | ||||
|     data() { | ||||
|       return { | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10, | ||||
|           name: '', | ||||
|           // tagId: '', | ||||
|           owner: '' | ||||
|         }, | ||||
|         isLoading: false, | ||||
|         isShow: false, | ||||
|         ids: [], | ||||
|         total: 10, | ||||
|         chooseTags: [], | ||||
|         tags: [], | ||||
|         colConfigs: [ | ||||
|           {type: 'selection'}, | ||||
|           // {slot: 'avatar'}, | ||||
|           {slot: 'userinfo'}, | ||||
|           {prop: 'ownerName', label: '群主', align: 'center'}, | ||||
|           {slot: 'tags'}, | ||||
|           { | ||||
|             prop: 'personCount', label: '群人数', align: 'center' | ||||
|           }, | ||||
|           {prop: 'increase', label: '当日入群人数', align: 'center'}, | ||||
|           {prop: 'decrease', label: '当日退群人数', align: 'center'}, | ||||
|           { | ||||
|             prop: 'createTime', label: '创建时间', align: 'left' | ||||
|           }, | ||||
|           {slot: 'options', label: '操作', align: 'center'}], | ||||
|         tableData: [], | ||||
|         subTags: [], | ||||
|         userList: [] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       ...mapState(['user']) | ||||
|     }, | ||||
|  | ||||
|     mounted() { | ||||
|       this.getTags() | ||||
|       this.getSubTags() | ||||
|       // this.getWxUserList() | ||||
|       this.getList() | ||||
|       this.isLoading = true | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getWxUserList () { | ||||
|         this.instance.post(`/app/wxcp/wxuser/listByDepartId`, { | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.userList = res.data.map(item => { | ||||
|               item.dictName = item.name | ||||
|               item.dictValue = item.id | ||||
|  | ||||
|               return item | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       update() { | ||||
|         this.instance.post(`/app/wxcp/wxgroup/sync`).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.$message.success('更新成功') | ||||
|             this.getList() | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       getSubTags() { | ||||
|         this.instance.post(`/app/wxcp/wxgroupchattag/listAllTag`).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.subTags = res.data?.map(item => { | ||||
|               return { | ||||
|                 dictName: item.name, | ||||
|                 dictValue: item.id | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       getList() { | ||||
|         this.instance.post(`/app/wxcp/wxgroup/list`, null, { | ||||
|           params: { | ||||
|             ...this.search | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|           this.isLoading = false | ||||
|         }).catch(() => { | ||||
|           this.isLoading = false | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       choose(id) { | ||||
|         const index = this.chooseTags.indexOf(id) | ||||
|         if (index === -1) { | ||||
|           this.chooseTags.push(id) | ||||
|         } else { | ||||
|           this.chooseTags.splice(index, 1) | ||||
|         } | ||||
|       }, | ||||
|  | ||||
|       onConfirm(type = 0) { | ||||
|         if (type == 0 && !this.chooseTags.length) { | ||||
|           return this.$message.error('请选择标签') | ||||
|         } | ||||
|         this.instance.post(`/app/wxcp/wxgroupchattag/markTagForWeb`, { | ||||
|           tagIds: this.chooseTags, groupIds: this.ids.map(v => v.id), type, | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             type == 0 ? (this.isShow = false) : false | ||||
|             this.$message.success(type == 0 ? "添加成功" : "删除成功") | ||||
|             this.getList() | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       getTags() { | ||||
|         this.instance.post(`/app/wxcp/wxgroupchattag/listAll?size=999`).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tags = res.data.records | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onAdd() { | ||||
|         this.$emit('change', { | ||||
|           type: 'add' | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       handleSelectionChange(e) { | ||||
|         this.ids = e | ||||
|       }, | ||||
|  | ||||
|       removeAll() { | ||||
|         this.remove(this.ids.map(v => v.id).join(',')) | ||||
|       }, | ||||
|  | ||||
|       remove(id) { | ||||
|         this.$confirm('确定删除该数据?').then(() => { | ||||
|           this.instance.post(`/app/apppetition/delete?ids=${id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('删除成功!') | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       toDetail(id) { | ||||
|         this.$emit('change', { | ||||
|           type: 'detail', params: { | ||||
|             id: id | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onAdd() { | ||||
|         this.$emit('change', { | ||||
|           type: 'add' | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .table-tags { | ||||
|     .el-tag { | ||||
|       margin-right: 8px; | ||||
|       margin-bottom: 8px; | ||||
|       border: 1px solid #D0D4DC; | ||||
|       background: #F3F4F7; | ||||
|       border-radius: 4px; | ||||
|       font-size: 13px; | ||||
|       color: #222222; | ||||
|  | ||||
|       &:last-child { | ||||
|         margin-right: 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .ellipsis { | ||||
|     overflow: hidden; | ||||
|     text-overflow: ellipsis; | ||||
|     white-space: nowrap; | ||||
|   } | ||||
|  | ||||
|   .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; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .avatar { | ||||
|     text-align: right; | ||||
|  | ||||
|     img { | ||||
|       position: relative; | ||||
|       top: 4px; | ||||
|       width: 40px; | ||||
|       height: 40px; | ||||
|       border-radius: 2px; | ||||
|       border: 1px solid #CCCCCC; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .userinfo { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     line-height: 1; | ||||
|  | ||||
|     .userinfo-right__top { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       cursor: pointer; | ||||
|       white-space: nowrap; | ||||
|     } | ||||
|  | ||||
|     .userinfo-right__bottom { | ||||
|       text-align: left; | ||||
|     } | ||||
|  | ||||
|     i { | ||||
|       cursor: pointer; | ||||
|       font-style: normal; | ||||
|       color: #888888; | ||||
|       font-size: 14px; | ||||
|     } | ||||
|  | ||||
|     h3 { | ||||
|       margin-top: 0; | ||||
|       margin-bottom: 0; | ||||
|       margin-right: 8px; | ||||
|       color: #222222; | ||||
|       font-weight: normal; | ||||
|       font-size: 14px; | ||||
|     } | ||||
|  | ||||
|     span { | ||||
|       color: #2EA222; | ||||
|       white-space: nowrap; | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										207
									
								
								packages/wechat/AppResidentGroupManage/components/Statistics.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								packages/wechat/AppResidentGroupManage/components/Statistics.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,207 @@ | ||||
| <template> | ||||
|   <ai-list class="statistics" isTabs style="width: 100%"> | ||||
|     <template slot="content" v-loading="loading"> | ||||
|       <div class="statistics-top"> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>群聊总数</span> | ||||
|           <h2 style="color: #2266FF;">{{ groupSum }}</h2> | ||||
|         </div> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>群成员总人数</span> | ||||
|           <h2>{{ info.total }}</h2> | ||||
|         </div> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>今日入群人数</span> | ||||
|           <h2 style="color: #22AA99;">{{ info.increase }}</h2> | ||||
|         </div> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>今日退群人数</span> | ||||
|           <h2 style="color: #F8B425">{{ info.decrease }}</h2> | ||||
|         </div> | ||||
|       </div> | ||||
|       <ai-card title="趋势图"> | ||||
|         <template #content> | ||||
|           <div class="chart" style="height: 340px; width: 100%;"></div> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import * as echarts from 'echarts' | ||||
|  | ||||
|   export default { | ||||
|     name: 'Statistics', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|  | ||||
|     data() { | ||||
|       return { | ||||
|         chart: null, | ||||
|         info: {}, | ||||
|         chartWidth: '', | ||||
|         groupSum: "", | ||||
|         loading: false | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     mounted() { | ||||
|       this.loading = true | ||||
|       this.$nextTick(() => { | ||||
|         this.chart = echarts.init(document.querySelector('.chart')) | ||||
|         window.addEventListener('resize', this.onResize) | ||||
|         this.getInfo() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     destroyed() { | ||||
|       window.removeEventListener('resize', this.onResize) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       onResize() { | ||||
|         this.chart.resize() | ||||
|       }, | ||||
|  | ||||
|       getInfo() { | ||||
|         this.instance.post(`/app/wxcp/wxgroup/groupStatistic`).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.info = res.data.today | ||||
|             this.groupSum = res.data.groupSum | ||||
|             this.initChart(res.data.list) | ||||
|             this.loading = false | ||||
|           } else { | ||||
|             this.loading = false | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       initChart(data) { | ||||
|         const x = Object.keys(data) | ||||
|         const y = Object.values(data) | ||||
|         let option = { | ||||
|           tooltip: { | ||||
|             trigger: 'axis' | ||||
|           }, | ||||
|           legend: { | ||||
|             type: "plain" | ||||
|           }, | ||||
|           grid: { | ||||
|             left: '20px', | ||||
|             right: '38px', | ||||
|             bottom: '14px', | ||||
|             top: '30px', | ||||
|             containLabel: true | ||||
|           }, | ||||
|           color: ['#2266FF', '#22AA99', '#F8B425'], | ||||
|           xAxis: { | ||||
|             type: 'category', | ||||
|             axisLabel: { | ||||
|               align: 'center', | ||||
|               padding: [2, 0, 0, 0], | ||||
|               interval: 0, | ||||
|               fontSize: 14, | ||||
|               color: '#666666' | ||||
|             }, | ||||
|             boundaryGap: false, | ||||
|             axisLine: { | ||||
|               lineStyle: { | ||||
|                 color: '#E1E5EF' | ||||
|               } | ||||
|             }, | ||||
|             data: x | ||||
|           }, | ||||
|           yAxis: { | ||||
|             axisTick: { | ||||
|               length: 0, | ||||
|               show: false | ||||
|             }, | ||||
|             splitLine: { | ||||
|               show: true, | ||||
|               lineStyle: { | ||||
|                 color: ['#E1E5EF'], | ||||
|                 width: 1, | ||||
|                 type: 'solid' | ||||
|               } | ||||
|             }, | ||||
|             nameTextStyle: { | ||||
|               color: '#666666', | ||||
|               align: 'left' | ||||
|             }, | ||||
|             axisLine: { | ||||
|               show: false | ||||
|             }, | ||||
|             axisLabel: { | ||||
|               color: '#666666' | ||||
|             }, | ||||
|             type: 'value' | ||||
|           }, | ||||
|           series: [ | ||||
|             { | ||||
|               name: '群成员总数', | ||||
|               type: 'line', | ||||
|               data: y.map(v => v.total) | ||||
|             }, | ||||
|             { | ||||
|               name: '新增入群人数', | ||||
|               type: 'line', | ||||
|               data: y.map(v => v.increase) | ||||
|             }, | ||||
|             { | ||||
|               name: '退群人数', | ||||
|               type: 'line', | ||||
|               data: y.map(v => v.decrease) | ||||
|             } | ||||
|           ] | ||||
|         } | ||||
|         this.chart.setOption(option) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
|   .statistics { | ||||
|     ::v-deep .ai-list__content--right-wrapper { | ||||
|       background: transparent !important; | ||||
|       box-shadow: none !important; | ||||
|       padding: 12px 0 12px !important; | ||||
|     } | ||||
|  | ||||
|     .statistics-top { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       margin-bottom: 20px; | ||||
|  | ||||
|       & > div { | ||||
|         flex: 1; | ||||
|         height: 96px; | ||||
|         line-height: 1; | ||||
|         margin-right: 20px; | ||||
|         padding: 16px 24px; | ||||
|         background: #FFFFFF; | ||||
|         box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15); | ||||
|         border-radius: 4px; | ||||
|  | ||||
|         &:last-child { | ||||
|           margin-right: 0; | ||||
|         } | ||||
|  | ||||
|         h3 { | ||||
|           font-size: 24px; | ||||
|         } | ||||
|  | ||||
|         span { | ||||
|           display: block; | ||||
|           margin-bottom: 16px; | ||||
|           color: #888888; | ||||
|           font-size: 16px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										201
									
								
								packages/wechat/AppResidentGroupManage/components/Tags.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								packages/wechat/AppResidentGroupManage/components/Tags.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,201 @@ | ||||
| <template> | ||||
|   <ai-list class="AppPetitionManage" isTabs> | ||||
|     <template slot="content"> | ||||
|       <ai-search-bar> | ||||
|         <template slot="left"> | ||||
|           <el-button type="primary" icon="iconfont iconAdd" @click="id = '', form.name = '', form.tagList = [], isShow = true">添加群标签组</el-button> | ||||
|         </template> | ||||
|       </ai-search-bar> | ||||
|       <ai-table | ||||
|         :tableData="tableData" | ||||
|         :col-configs="colConfigs" | ||||
|         :total="total" | ||||
|         ref="aitableex" | ||||
|         :current.sync="search.current" | ||||
|         :size.sync="search.size" | ||||
|         @getList="getList"> | ||||
|         <el-table-column slot="tags" label="群标签" align="left"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-tags"> | ||||
|               <el-tag type="info" v-for="(item, index) in row.tagList" size="small" :key="index">{{ item.name }}</el-tag> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column slot="options" label="操作" width="180" fixed="right" align="center"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-options"> | ||||
|               <!-- <el-button type="text" @click="edit(row)">添加标签</el-button> --> | ||||
|               <el-button type="text" @click="edit(row)">编辑</el-button> | ||||
|               <el-button type="text" @click="remove(row.id)">删除</el-button> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </ai-table> | ||||
|       <ai-dialog | ||||
|         :visible.sync="isShow" | ||||
|         width="800px" | ||||
|         title="添加群标签组" | ||||
|         @onConfirm="onConfirm" | ||||
|         @onCancel="onCancel"> | ||||
|         <el-form class="ai-form" ref="form" label-width="120px" :model="form"> | ||||
|           <el-form-item style="width: 100%" label="群标签组名称" prop="name" :rules="[{ required: true, message: '请输入群标签组名称', trigger: 'blur' }]"> | ||||
|             <el-input size="small" v-model.trim="form.name" :maxlength="15" show-word-limit placeholder="请输入群标签组名称"></el-input> | ||||
|           </el-form-item> | ||||
|           <el-form-item style="width: 100%" label="群标签" prop="tagList" :rules="[{ required: true, message: '请输入群标签组名称', trigger: 'blur' }]"> | ||||
|             <div class="table-tags"> | ||||
|               <el-tag type="info" color="#fff" closable @close="onClose(index)" v-for="(item, index) in form.tagList" :key="index">{{ item.name }}</el-tag> | ||||
|               <el-input | ||||
|                 v-if="inputVisible" | ||||
|                 v-model.trim="tagName" | ||||
|                 size="small" | ||||
|                 style="width: 100px;" | ||||
|                 maxlength="30" | ||||
|                 clearable | ||||
|                 @keyup.enter.native="handleInputConfirm" | ||||
|                 @blur="handleInputConfirm"> | ||||
|               </el-input> | ||||
|               <el-button v-else size="small" icon="iconfont iconAdd" @click="inputVisible = true">添加</el-button> | ||||
|             </div> | ||||
|           </el-form-item> | ||||
|         </el-form> | ||||
|       </ai-dialog> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'Tags', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10 | ||||
|         }, | ||||
|         tagName: '', | ||||
|         form: { | ||||
|           name: '', | ||||
|           tagList: [] | ||||
|         }, | ||||
|         inputVisible: false, | ||||
|         isShow: false, | ||||
|         ids: [], | ||||
|         total: 10, | ||||
|         colConfigs: [ | ||||
|           { prop: 'name', label: '群标签组名称', align: 'left', width: 160 }, | ||||
|           { slot: 'tags' }, | ||||
|           { slot: 'options', label: '操作', align: 'center' } | ||||
|         ], | ||||
|         id: '', | ||||
|         tableData: [], | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     mounted () { | ||||
|       this.getList() | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getList() { | ||||
|         this.instance.post(`/app/wxcp/wxgroupchattag/listAll`, null, { | ||||
|           params: { | ||||
|             ...this.search | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onCancel () { | ||||
|         this.form.name = '' | ||||
|         this.form.tagList = [] | ||||
|         this.id = '' | ||||
|         this.inputVisible = '' | ||||
|         this.isShow = false | ||||
|       }, | ||||
|  | ||||
|       edit (e) { | ||||
|         this.id = e.id | ||||
|         this.form = JSON.parse(JSON.stringify(e)) | ||||
|  | ||||
|         this.$nextTick(() => { | ||||
|           this.isShow = true | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       handleInputConfirm () { | ||||
|         if (!this.tagName) { | ||||
|           return | ||||
|         } | ||||
|  | ||||
|         this.form.tagList.push({ | ||||
|           name: this.tagName | ||||
|         }) | ||||
|  | ||||
|         this.$nextTick(() => { | ||||
|           this.tagName = '' | ||||
|           this.inputVisible = false | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onClose (index) { | ||||
|         this.form.tagList.splice(index, 1) | ||||
|       }, | ||||
|  | ||||
|       onConfirm() { | ||||
|         this.$refs.form.validate((valid) => { | ||||
|           if (valid) { | ||||
|             this.instance.post(this.id ? '/app/wxcp/wxgroupchattag/update' : `/app/wxcp/wxgroupchattag/add`, { | ||||
|               name: this.form.name, | ||||
|               id: this.id || null, | ||||
|               tagList: this.form.tagList | ||||
|             }).then(res => { | ||||
|               if (res.code === 0) { | ||||
|                 this.getList() | ||||
|                 this.isShow = false | ||||
|                 this.$message.success(`${this.id}` ? '编辑成功' : '提交成功') | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       remove (id) { | ||||
|         this.$confirm('确定删除该数据?').then(() => { | ||||
|           this.instance.post(`/app/wxcp/wxgroupchattag/delete?id=${id}&type=0`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('删除成功!') | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .table-tags { | ||||
|     .el-tag { | ||||
|       margin-right: 8px; | ||||
|       border: 1px solid #D0D4DC; | ||||
|       background: #F3F4F7; | ||||
|       border-radius: 4px; | ||||
|       font-size: 13px; | ||||
|       color: #222222; | ||||
|  | ||||
|       &:last-child { | ||||
|         margin-right: 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
		Reference in New Issue
	
	Block a user