Merge remote-tracking branch 'origin/dev' into build
This commit is contained in:
		| @@ -0,0 +1,79 @@ | |||||||
|  | <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> | ||||||
| @@ -0,0 +1,924 @@ | |||||||
|  | <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.wxGroups.length"> | ||||||
|  |                         <span v-for="(item, index) in form.wxGroups" :key="index" v-if="index < 9"> | ||||||
|  |                           <ai-open-data | ||||||
|  |                             type="userName" | ||||||
|  |                             :openid="item.groupOwnerId"> | ||||||
|  |                             </ai-open-data> | ||||||
|  |                         </span> | ||||||
|  |                         <em v-if="form.wxGroups.length > 9">等{{ form.wxGroups.length }}个</em> | ||||||
|  |                       </div> | ||||||
|  |                       <i v-if="!form.wxGroups.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="发送内容" 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="340" | ||||||
|  |                       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> | ||||||
|  |                         <el-upload | ||||||
|  |                             ref="upload" | ||||||
|  |                             multiple | ||||||
|  |                             :file-list="fileList" | ||||||
|  |                             :show-file-list="false" | ||||||
|  |                             :before-upload="v => handleChange(v, 20, '.zip,.rar,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt')" | ||||||
|  |                             :limit="9" | ||||||
|  |                             :on-exceed="onExceed" | ||||||
|  |                             action="/app/wxcp/upload/uploadFile" | ||||||
|  |                             accept=".zip,.rar,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt" | ||||||
|  |                             :http-request="v => submitUpload(v, '3')"> | ||||||
|  |                           <div class="content-item" trigger> | ||||||
|  |                             <img src="https://cdn.cunwuyun.cn/dvcp/announce/folder.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 class="content-item" @click="isShowAddMiniapp = true"> | ||||||
|  |                           <img src="https://cdn.cunwuyun.cn/dvcp/announce/miniapp.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-user-get :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"> | ||||||
|  |                           <ai-open-data type="userName" :openid="item.wxOpenUserId"></ai-open-data> | ||||||
|  |                         </span> | ||||||
|  |                       </div> | ||||||
|  |                       <i v-if="!form.examines.length">请选择</i> | ||||||
|  |                         <div class="select-right">{{ form.examines.length ? '重新选择' : '选择' }}</div> | ||||||
|  |                     </div> | ||||||
|  |                   </ai-user-get> | ||||||
|  |                 </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="isShowAddMiniapp" | ||||||
|  |             width="920px" | ||||||
|  |             title="小程序消息" | ||||||
|  |             @close="onClose" | ||||||
|  |             @onConfirm="onMiniAppForm"> | ||||||
|  |           <el-form ref="miniAppForm" :model="miniAppForm" label-width="130px" label-position="right"> | ||||||
|  |             <div class="ai-form"> | ||||||
|  |               <el-form-item label="小程序appid" style="width: 100%;" prop="mpAppid" :rules="[{ required: true, message: '小程序appid', trigger: 'blur' }]"> | ||||||
|  |                 <el-input | ||||||
|  |                     size="small" | ||||||
|  |                     placeholder="小程序appid" | ||||||
|  |                     v-model="miniAppForm.mpAppid"> | ||||||
|  |                 </el-input> | ||||||
|  |               </el-form-item> | ||||||
|  |               <el-form-item label="小程序page路径" style="width: 100%;" prop="mpPage" :rules="[{ required: true, message: '请输入小程序page路径', trigger: 'blur' }]"> | ||||||
|  |                 <el-input | ||||||
|  |                     size="small" | ||||||
|  |                     placeholder="请输入小程序page路径" | ||||||
|  |                     v-model="miniAppForm.mpPage"> | ||||||
|  |                 </el-input> | ||||||
|  |               </el-form-item> | ||||||
|  |               <el-form-item label="标题" style="width: 100%;" prop="mpTitle" :rules="[{ required: true, message: '请输入标题', trigger: 'blur' }]"> | ||||||
|  |                 <el-input | ||||||
|  |                     size="small" | ||||||
|  |                     placeholder="请输入标题" | ||||||
|  |                     maxlength="20" | ||||||
|  |                     show-word-limit | ||||||
|  |                     v-model="miniAppForm.mpTitle"> | ||||||
|  |                 </el-input> | ||||||
|  |               </el-form-item> | ||||||
|  |               <el-form-item label="封面图" prop="media" style="width: 100%;" :rules="[{ required: true, message: '请上传封面图', trigger: 'change' }]"> | ||||||
|  |                 <ai-uploader url="/app/wxcp/upload/uploadFile?type=image" :instance="instance" isWechat v-model="miniAppForm.media" :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> | ||||||
|  |       </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, | ||||||
|  |       fileList: [], | ||||||
|  |       isShowAddLink: false, | ||||||
|  |       isShowAddMiniapp: false, | ||||||
|  |       isShowDate: false, | ||||||
|  |       isLoading: false, | ||||||
|  |       linkForm: { | ||||||
|  |         linkPicUrl: [], | ||||||
|  |         linkDesc: '', | ||||||
|  |         linkTitle: '', | ||||||
|  |         linkUrl: '' | ||||||
|  |       }, | ||||||
|  |       dateForm: { | ||||||
|  |         choiceTime: '' | ||||||
|  |       }, | ||||||
|  |       miniAppForm: { | ||||||
|  |         mpAppid: '', | ||||||
|  |         mpPage: '', | ||||||
|  |         mpTitle: '', | ||||||
|  |         media: [] | ||||||
|  |       }, | ||||||
|  |       form: { | ||||||
|  |         content: '', | ||||||
|  |         choiceTime: '', | ||||||
|  |         contents: [], | ||||||
|  |         enableExamine: '0', | ||||||
|  |         examines: [], | ||||||
|  |         wxGroups: [], | ||||||
|  |         wxGroupsName: '', | ||||||
|  |         sendScope: '0', | ||||||
|  |         sendType: 0, | ||||||
|  |         name: '', | ||||||
|  |         filterCriteria: [], | ||||||
|  |         taskTitle: '', | ||||||
|  |         examinesName: '' | ||||||
|  |       }, | ||||||
|  |       girdNames: '', | ||||||
|  |       id: '', | ||||||
|  |       tagsList: [], | ||||||
|  |       pickerOptions: { | ||||||
|  |         disabledDate: e => { | ||||||
|  |           return e.getTime() < (Date.now() - 60 * 1000 * 60 * 24) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['user']), | ||||||
|  |  | ||||||
|  |     groupLen() { | ||||||
|  |       let i = 0 | ||||||
|  |       this.form.wxGroups.forEach(v => { | ||||||
|  |         i = i + v.groupIds.split(',').length | ||||||
|  |       }) | ||||||
|  |  | ||||||
|  |       return i | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   created() { | ||||||
|  |     if (this.params && this.params.id) { | ||||||
|  |       this.id = this.params.id | ||||||
|  |       this.getInfo(this.params.id) | ||||||
|  |     } else { | ||||||
|  |       this.getWxGroups() | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   methods: { | ||||||
|  |     ...mapActions(['initOpenData', 'transCanvas']), | ||||||
|  |  | ||||||
|  |     getInfo(id) { | ||||||
|  |       this.instance.post(`/app/appmasssendingtask/queryDetailById?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 | ||||||
|  |               } | ||||||
|  |             }) | ||||||
|  |             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.wxGroupsName = '' | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onScopeChange(e) { | ||||||
|  |       this.form.filterCriteria = [] | ||||||
|  |       this.form.wxGroups = [] | ||||||
|  |       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.wxGroups = [] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     getWxGroups() { | ||||||
|  |       this.instance.post(`/app/appmasssendingtask/queryWxGroups?sendScope=${this.form.sendScope}`, null, { | ||||||
|  |         data: { | ||||||
|  |           filterCriteria: this.form.filterCriteria.join(',') | ||||||
|  |         }, | ||||||
|  |         headers: {'Content-Type': 'application/json;charset=utf-8'}, | ||||||
|  |         transformRequest: [function (data) { | ||||||
|  |           return data.filterCriteria | ||||||
|  |         }] | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res.code === 0) { | ||||||
|  |           this.form.wxGroups = res.data | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onLinkConfirm() { | ||||||
|  |       this.$refs.linkForm.validate((valid) => { | ||||||
|  |         if (valid) { | ||||||
|  |           this.fileList.push({ | ||||||
|  |             ...this.linkForm, | ||||||
|  |             linkPicUrl: this.linkForm.linkPicUrl.length ? this.linkForm.linkPicUrl[0].url : '', | ||||||
|  |             msgType: '4' | ||||||
|  |           }) | ||||||
|  |  | ||||||
|  |           this.isShowAddLink = false | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onMiniAppForm() { | ||||||
|  |       this.$refs.miniAppForm.validate((valid) => { | ||||||
|  |         if (valid) { | ||||||
|  |           this.fileList.push({ | ||||||
|  |             ...this.miniAppForm, | ||||||
|  |             msgType: '5', | ||||||
|  |             ...this.miniAppForm.media[0], | ||||||
|  |             mediaId: this.miniAppForm.media[0].media.mediaId, | ||||||
|  |             sysFileId: this.miniAppForm.media[0].id | ||||||
|  |           }) | ||||||
|  |  | ||||||
|  |           this.isShowAddMiniapp = false | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onClose() { | ||||||
|  |       this.linkForm.linkPicUrl = [] | ||||||
|  |       this.linkForm.linkDesc = '' | ||||||
|  |       this.linkForm.linkTitle = '' | ||||||
|  |       this.linkForm.linkUrl = '' | ||||||
|  |       this.miniAppForm.mpAppid = '' | ||||||
|  |       this.miniAppForm.mpPage = '' | ||||||
|  |       this.miniAppForm.mpTitle = '' | ||||||
|  |       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) { | ||||||
|  |       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('type', fileType) | ||||||
|  |       let loading = this.$loading() | ||||||
|  |       this.instance.post(`/app/wxcp/upload/uploadFile`, 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.wxGroups.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/appmasssendingtask/addOrUpdate`, { | ||||||
|  |             ...this.form, | ||||||
|  |             id: this.params.id, | ||||||
|  |             wxGroups: this.form.wxGroups, | ||||||
|  |             contents, | ||||||
|  |             sendType, | ||||||
|  |             choiceTime: this.dateForm.choiceTime, | ||||||
|  |             filterCriteria: this.form.filterCriteria.join(','), | ||||||
|  |             examines: this.form.examines.length ? this.form.examines.map(v => { | ||||||
|  |               return { | ||||||
|  |                 ...v, | ||||||
|  |                 examineUserId: v.id | ||||||
|  |               } | ||||||
|  |             }) : [] | ||||||
|  |           }).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; | ||||||
|  | } | ||||||
|  | .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> | ||||||
| @@ -0,0 +1,777 @@ | |||||||
|  | <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><ai-open-data type="userName" :openid="info.createUserId"></ai-open-data></span> | ||||||
|  |                 (<span><ai-open-data type="departmentName" :openid="info.createUserDept"></ai-open-data></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><ai-open-data type="userName" :openid="item.examineUserId"></ai-open-data></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> | ||||||
|  |         <template #title> | ||||||
|  |           <div class="AppAnnounceDetail-title"> | ||||||
|  |             <span :class="[currIndex === 0 ? 'active' : '']" @click="currIndex = 0">成员统计</span> | ||||||
|  |             <span :class="[currIndex === 1 ? 'active' : '']" @click="currIndex = 1">居民群统计</span> | ||||||
|  |           </div> | ||||||
|  |         </template> | ||||||
|  |         <template #content> | ||||||
|  |           <div class="content-item" v-if="currIndex === 0"> | ||||||
|  |             <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> | ||||||
|  |                         <ai-open-data type="userName" :openid="row.groupOwnerId"></ai-open-data> | ||||||
|  |                       </span> | ||||||
|  |                       <span style="color: #999"> | ||||||
|  |                         <ai-open-data type="departmentName" :openid="row.mainDepartment"></ai-open-data> | ||||||
|  |                       </span> | ||||||
|  |                     </div> | ||||||
|  |                   </template> | ||||||
|  |                 </el-table-column> | ||||||
|  |               </ai-table> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |           <div class="content-item" v-if="currIndex === 1"> | ||||||
|  |             <div class="top"> | ||||||
|  |               <div class="top-item"> | ||||||
|  |                 <div class="top-item__title"> | ||||||
|  |                   <h3>计划送达居民群</h3> | ||||||
|  |                 </div> | ||||||
|  |                 <p>{{ groupInfo.planCount || 0 }}</p> | ||||||
|  |               </div> | ||||||
|  |               <div class="top-item"> | ||||||
|  |                 <div class="top-item__title"> | ||||||
|  |                   <h3>未送达居民群</h3> | ||||||
|  |                 </div> | ||||||
|  |                 <p>{{ groupInfo.unExecutedCount || 0 }}</p> | ||||||
|  |               </div> | ||||||
|  |               <div class="top-item"> | ||||||
|  |                 <div class="top-item__title"> | ||||||
|  |                   <h3>已送达居民群</h3> | ||||||
|  |                 </div> | ||||||
|  |                 <p>{{ groupInfo.executedCount || 0 }}</p> | ||||||
|  |               </div> | ||||||
|  |               <div class="top-item"> | ||||||
|  |                 <div class="top-item__title"> | ||||||
|  |                   <h3>无法送达居民群</h3> | ||||||
|  |                 </div> | ||||||
|  |                 <p>{{ groupInfo.cannotExecuteCount || 0 }}</p> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |             <div class="bottom"> | ||||||
|  |               <div class="bottom-search"> | ||||||
|  |                 <div class="left"> | ||||||
|  |                   <el-radio-group v-model="search2.sendStatus" size="small" @change="search2.current = 1, getGroupInfo()"> | ||||||
|  |                     <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, 'search2')" :multiple="false" v-model="user2"> | ||||||
|  |                     <div class="userSelcet"> | ||||||
|  |                       <span style="color: #606266;" v-if="search2.deptartId"><ai-open-data type="departmentName" :openid="search2.deptartId"></ai-open-data></span> | ||||||
|  |                       <span v-else>部门</span> | ||||||
|  |                       <i class="el-icon-arrow-up"  v-if="!search2.deptartId"></i> | ||||||
|  |                       <i class="el-icon-circle-close" v-if="search2.deptartId" @click.stop="user1 = [], search2.deptartId = '', search2.current = 1, getGroupInfo()"></i> | ||||||
|  |                     </div> | ||||||
|  |                   </ai-picker> | ||||||
|  |                 </div> | ||||||
|  |                 <el-button :type="isDisabled ? '' : 'primary'" :disabled="isDisabled"  @click="sendMsg(1)" v-if="info.status === '4'">{{ isDisabled ? min + '分钟后可再次提醒' : '提醒成员发送' }}</el-button> | ||||||
|  |               </div> | ||||||
|  |               <ai-table | ||||||
|  |                 :tableData="tableData2" | ||||||
|  |                 :col-configs="colConfigs2" | ||||||
|  |                 :total="total2" | ||||||
|  |                 border | ||||||
|  |                 tableSize="small" | ||||||
|  |                 :current.sync="search2.current" | ||||||
|  |                 :size.sync="search2.size" | ||||||
|  |                 @getList="getGroupInfo"> | ||||||
|  |                 <el-table-column slot="user" label="群主" align="center"> | ||||||
|  |                   <template slot-scope="{ row }"> | ||||||
|  |                     <div class="userinfo"> | ||||||
|  |                       <span> | ||||||
|  |                         <ai-open-data type="userName" :openid="row.groupOwnerId"></ai-open-data> | ||||||
|  |                       </span> | ||||||
|  |                       <span style="color: #999"> | ||||||
|  |                         <ai-open-data type="departmentName" :openid="row.mainDepartment"></ai-open-data> | ||||||
|  |                       </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: [], | ||||||
|  |         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: 'groupOwnerId', label: '群主', openType: 'userName' }, | ||||||
|  |           { prop: 'groupNames', label: '群名称' } | ||||||
|  |         ], | ||||||
|  |         colConfigs1: [ | ||||||
|  |           { slot: 'user', label: '成员', openType: 'userName' }, | ||||||
|  |           { prop: 'groupCount', label: '预计送达居民群', align: 'center' } | ||||||
|  |         ], | ||||||
|  |         colConfigs2: [ | ||||||
|  |           { prop: 'groupName', label: '居民群' }, | ||||||
|  |           { prop: 'memberCount', label: '群人数', align: 'center' }, | ||||||
|  |           { slot: 'user', 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) { | ||||||
|  |           this[search].deptartId = e[0].id | ||||||
|  |         } else { | ||||||
|  |           this[search].deptartId = '' | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         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); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       ::v-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; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ::v-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; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ::v-deep .right-tips { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |  | ||||||
|  |       i { | ||||||
|  |         margin-right: 4px; | ||||||
|  |         color: #8899bb; | ||||||
|  |         font-size: 16px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         color: #888888; | ||||||
|  |         font-size: 12px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
| @@ -0,0 +1,296 @@ | |||||||
|  | <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-user-get :instance="instance" @change="onUserChange" :isMultiple="false" v-model="user"> | ||||||
|  |             <div class="userSelcet"> | ||||||
|  |               <span style="color: #606266;" v-if="search.createUserId"><ai-open-data type="userName" :openid="search.createUserId"></ai-open-data></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 = '', search.current = 1, getList()"></i> | ||||||
|  |             </div> | ||||||
|  |           </ai-user-get> | ||||||
|  |         </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> | ||||||
|  |                 <ai-open-data type="userName" :openid="row.createUserId"></ai-open-data> | ||||||
|  |               </span> | ||||||
|  |               <span style="color: #999"> | ||||||
|  |                 <ai-open-data type="departmentName" :openid="row.createUserDept"></ai-open-data> | ||||||
|  |               </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.search.createUserId = e[0].wxOpenUserId | ||||||
|  |         } else { | ||||||
|  |           this.search.createUserId = '' | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         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> | ||||||
| @@ -0,0 +1,344 @@ | |||||||
|  | <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> | ||||||
| @@ -0,0 +1,759 @@ | |||||||
|  | <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; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     ::v-deep .el-calendar-table:not(.is-range) td.next, | ||||||
|  |     ::v-deep .el-calendar-table:not(.is-range) td.prev { | ||||||
|  |       color: #ccc; | ||||||
|  |     } | ||||||
|  |     ::v-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; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar__header{ | ||||||
|  |       display: none; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar__body{ | ||||||
|  |       padding: 0; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar-table thead th:nth-of-type(1){ | ||||||
|  |       border-left: 1px solid #eee; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar-table thead th:nth-of-type(7){ | ||||||
|  |       border-right: 1px solid #eee; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar-table tr td:first-child { | ||||||
|  |       border-left: 1px solid #eee; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar-table tr:first-child td { | ||||||
|  |       border-top: 1px solid #eee; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar-table td { | ||||||
|  |       border-bottom: 1px solid #eee; | ||||||
|  |       border-right: 1px solid #eee; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-timeline-item__timestamp.is-top{ | ||||||
|  |       margin-bottom: 0; | ||||||
|  |       padding-top: 0; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-timeline-item__node{ | ||||||
|  |       background-color: #26F; | ||||||
|  |       width: 8px; | ||||||
|  |       height: 8px; | ||||||
|  |       border-radius: 50%; | ||||||
|  |       left: 1px; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-card{ | ||||||
|  |       border: none; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-card__body{ | ||||||
|  |       padding: 8px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-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; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .AiPicker{ | ||||||
|  |     display: inline-block; | ||||||
|  |   } | ||||||
|  | </style> | ||||||
| @@ -0,0 +1,79 @@ | |||||||
|  | <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> | ||||||
| @@ -0,0 +1,924 @@ | |||||||
|  | <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.wxGroups.length"> | ||||||
|  |                         <span v-for="(item, index) in form.wxGroups" :key="index" v-if="index < 9"> | ||||||
|  |                           <ai-open-data | ||||||
|  |                             type="userName" | ||||||
|  |                             :openid="item.groupOwnerId"> | ||||||
|  |                             </ai-open-data> | ||||||
|  |                         </span> | ||||||
|  |                         <em v-if="form.wxGroups.length > 9">等{{ form.wxGroups.length }}个</em> | ||||||
|  |                       </div> | ||||||
|  |                       <i v-if="!form.wxGroups.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="发送内容" 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="340" | ||||||
|  |                       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> | ||||||
|  |                         <el-upload | ||||||
|  |                             ref="upload" | ||||||
|  |                             multiple | ||||||
|  |                             :file-list="fileList" | ||||||
|  |                             :show-file-list="false" | ||||||
|  |                             :before-upload="v => handleChange(v, 20, '.zip,.rar,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt')" | ||||||
|  |                             :limit="9" | ||||||
|  |                             :on-exceed="onExceed" | ||||||
|  |                             action="/app/wxcp/upload/uploadFile" | ||||||
|  |                             accept=".zip,.rar,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt" | ||||||
|  |                             :http-request="v => submitUpload(v, '3')"> | ||||||
|  |                           <div class="content-item" trigger> | ||||||
|  |                             <img src="https://cdn.cunwuyun.cn/dvcp/announce/folder.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 class="content-item" @click="isShowAddMiniapp = true"> | ||||||
|  |                           <img src="https://cdn.cunwuyun.cn/dvcp/announce/miniapp.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-user-get :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"> | ||||||
|  |                           <ai-open-data type="userName" :openid="item.wxOpenUserId"></ai-open-data> | ||||||
|  |                         </span> | ||||||
|  |                       </div> | ||||||
|  |                       <i v-if="!form.examines.length">请选择</i> | ||||||
|  |                         <div class="select-right">{{ form.examines.length ? '重新选择' : '选择' }}</div> | ||||||
|  |                     </div> | ||||||
|  |                   </ai-user-get> | ||||||
|  |                 </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="isShowAddMiniapp" | ||||||
|  |             width="920px" | ||||||
|  |             title="小程序消息" | ||||||
|  |             @close="onClose" | ||||||
|  |             @onConfirm="onMiniAppForm"> | ||||||
|  |           <el-form ref="miniAppForm" :model="miniAppForm" label-width="130px" label-position="right"> | ||||||
|  |             <div class="ai-form"> | ||||||
|  |               <el-form-item label="小程序appid" style="width: 100%;" prop="mpAppid" :rules="[{ required: true, message: '小程序appid', trigger: 'blur' }]"> | ||||||
|  |                 <el-input | ||||||
|  |                     size="small" | ||||||
|  |                     placeholder="小程序appid" | ||||||
|  |                     v-model="miniAppForm.mpAppid"> | ||||||
|  |                 </el-input> | ||||||
|  |               </el-form-item> | ||||||
|  |               <el-form-item label="小程序page路径" style="width: 100%;" prop="mpPage" :rules="[{ required: true, message: '请输入小程序page路径', trigger: 'blur' }]"> | ||||||
|  |                 <el-input | ||||||
|  |                     size="small" | ||||||
|  |                     placeholder="请输入小程序page路径" | ||||||
|  |                     v-model="miniAppForm.mpPage"> | ||||||
|  |                 </el-input> | ||||||
|  |               </el-form-item> | ||||||
|  |               <el-form-item label="标题" style="width: 100%;" prop="mpTitle" :rules="[{ required: true, message: '请输入标题', trigger: 'blur' }]"> | ||||||
|  |                 <el-input | ||||||
|  |                     size="small" | ||||||
|  |                     placeholder="请输入标题" | ||||||
|  |                     maxlength="20" | ||||||
|  |                     show-word-limit | ||||||
|  |                     v-model="miniAppForm.mpTitle"> | ||||||
|  |                 </el-input> | ||||||
|  |               </el-form-item> | ||||||
|  |               <el-form-item label="封面图" prop="media" style="width: 100%;" :rules="[{ required: true, message: '请上传封面图', trigger: 'change' }]"> | ||||||
|  |                 <ai-uploader url="/app/wxcp/upload/uploadFile?type=image" :instance="instance" isWechat v-model="miniAppForm.media" :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> | ||||||
|  |       </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, | ||||||
|  |       fileList: [], | ||||||
|  |       isShowAddLink: false, | ||||||
|  |       isShowAddMiniapp: false, | ||||||
|  |       isShowDate: false, | ||||||
|  |       isLoading: false, | ||||||
|  |       linkForm: { | ||||||
|  |         linkPicUrl: [], | ||||||
|  |         linkDesc: '', | ||||||
|  |         linkTitle: '', | ||||||
|  |         linkUrl: '' | ||||||
|  |       }, | ||||||
|  |       dateForm: { | ||||||
|  |         choiceTime: '' | ||||||
|  |       }, | ||||||
|  |       miniAppForm: { | ||||||
|  |         mpAppid: '', | ||||||
|  |         mpPage: '', | ||||||
|  |         mpTitle: '', | ||||||
|  |         media: [] | ||||||
|  |       }, | ||||||
|  |       form: { | ||||||
|  |         content: '', | ||||||
|  |         choiceTime: '', | ||||||
|  |         contents: [], | ||||||
|  |         enableExamine: '0', | ||||||
|  |         examines: [], | ||||||
|  |         wxGroups: [], | ||||||
|  |         wxGroupsName: '', | ||||||
|  |         sendScope: '0', | ||||||
|  |         sendType: 0, | ||||||
|  |         name: '', | ||||||
|  |         filterCriteria: [], | ||||||
|  |         taskTitle: '', | ||||||
|  |         examinesName: '' | ||||||
|  |       }, | ||||||
|  |       girdNames: '', | ||||||
|  |       id: '', | ||||||
|  |       tagsList: [], | ||||||
|  |       pickerOptions: { | ||||||
|  |         disabledDate: e => { | ||||||
|  |           return e.getTime() < (Date.now() - 60 * 1000 * 60 * 24) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['user']), | ||||||
|  |  | ||||||
|  |     groupLen() { | ||||||
|  |       let i = 0 | ||||||
|  |       this.form.wxGroups.forEach(v => { | ||||||
|  |         i = i + v.groupIds.split(',').length | ||||||
|  |       }) | ||||||
|  |  | ||||||
|  |       return i | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   created() { | ||||||
|  |     if (this.params && this.params.id) { | ||||||
|  |       this.id = this.params.id | ||||||
|  |       this.getInfo(this.params.id) | ||||||
|  |     } else { | ||||||
|  |       this.getWxGroups() | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   methods: { | ||||||
|  |     ...mapActions(['initOpenData', 'transCanvas']), | ||||||
|  |  | ||||||
|  |     getInfo(id) { | ||||||
|  |       this.instance.post(`/app/appmasssendingtask/queryDetailById?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 | ||||||
|  |               } | ||||||
|  |             }) | ||||||
|  |             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.wxGroupsName = '' | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onScopeChange(e) { | ||||||
|  |       this.form.filterCriteria = [] | ||||||
|  |       this.form.wxGroups = [] | ||||||
|  |       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.wxGroups = [] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     getWxGroups() { | ||||||
|  |       this.instance.post(`/app/appmasssendingtask/queryWxGroups?sendScope=${this.form.sendScope}`, null, { | ||||||
|  |         data: { | ||||||
|  |           filterCriteria: this.form.filterCriteria.join(',') | ||||||
|  |         }, | ||||||
|  |         headers: {'Content-Type': 'application/json;charset=utf-8'}, | ||||||
|  |         transformRequest: [function (data) { | ||||||
|  |           return data.filterCriteria | ||||||
|  |         }] | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res.code === 0) { | ||||||
|  |           this.form.wxGroups = res.data | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onLinkConfirm() { | ||||||
|  |       this.$refs.linkForm.validate((valid) => { | ||||||
|  |         if (valid) { | ||||||
|  |           this.fileList.push({ | ||||||
|  |             ...this.linkForm, | ||||||
|  |             linkPicUrl: this.linkForm.linkPicUrl.length ? this.linkForm.linkPicUrl[0].url : '', | ||||||
|  |             msgType: '4' | ||||||
|  |           }) | ||||||
|  |  | ||||||
|  |           this.isShowAddLink = false | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onMiniAppForm() { | ||||||
|  |       this.$refs.miniAppForm.validate((valid) => { | ||||||
|  |         if (valid) { | ||||||
|  |           this.fileList.push({ | ||||||
|  |             ...this.miniAppForm, | ||||||
|  |             msgType: '5', | ||||||
|  |             ...this.miniAppForm.media[0], | ||||||
|  |             mediaId: this.miniAppForm.media[0].media.mediaId, | ||||||
|  |             sysFileId: this.miniAppForm.media[0].id | ||||||
|  |           }) | ||||||
|  |  | ||||||
|  |           this.isShowAddMiniapp = false | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onClose() { | ||||||
|  |       this.linkForm.linkPicUrl = [] | ||||||
|  |       this.linkForm.linkDesc = '' | ||||||
|  |       this.linkForm.linkTitle = '' | ||||||
|  |       this.linkForm.linkUrl = '' | ||||||
|  |       this.miniAppForm.mpAppid = '' | ||||||
|  |       this.miniAppForm.mpPage = '' | ||||||
|  |       this.miniAppForm.mpTitle = '' | ||||||
|  |       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) { | ||||||
|  |       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('type', fileType) | ||||||
|  |       let loading = this.$loading() | ||||||
|  |       this.instance.post(`/app/wxcp/upload/uploadFile`, 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.wxGroups.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/appmasssendingtask/addOrUpdate`, { | ||||||
|  |             ...this.form, | ||||||
|  |             id: this.params.id, | ||||||
|  |             wxGroups: this.form.wxGroups, | ||||||
|  |             contents, | ||||||
|  |             sendType, | ||||||
|  |             choiceTime: this.dateForm.choiceTime, | ||||||
|  |             filterCriteria: this.form.filterCriteria.join(','), | ||||||
|  |             examines: this.form.examines.length ? this.form.examines.map(v => { | ||||||
|  |               return { | ||||||
|  |                 ...v, | ||||||
|  |                 examineUserId: v.id | ||||||
|  |               } | ||||||
|  |             }) : [] | ||||||
|  |           }).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; | ||||||
|  | } | ||||||
|  | .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> | ||||||
| @@ -0,0 +1,777 @@ | |||||||
|  | <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><ai-open-data type="userName" :openid="info.createUserId"></ai-open-data></span> | ||||||
|  |                 (<span><ai-open-data type="departmentName" :openid="info.createUserDept"></ai-open-data></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><ai-open-data type="userName" :openid="item.examineUserId"></ai-open-data></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> | ||||||
|  |         <template #title> | ||||||
|  |           <div class="AppAnnounceDetail-title"> | ||||||
|  |             <span :class="[currIndex === 0 ? 'active' : '']" @click="currIndex = 0">成员统计</span> | ||||||
|  |             <span :class="[currIndex === 1 ? 'active' : '']" @click="currIndex = 1">居民群统计</span> | ||||||
|  |           </div> | ||||||
|  |         </template> | ||||||
|  |         <template #content> | ||||||
|  |           <div class="content-item" v-if="currIndex === 0"> | ||||||
|  |             <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> | ||||||
|  |                         <ai-open-data type="userName" :openid="row.groupOwnerId"></ai-open-data> | ||||||
|  |                       </span> | ||||||
|  |                       <span style="color: #999"> | ||||||
|  |                         <ai-open-data type="departmentName" :openid="row.mainDepartment"></ai-open-data> | ||||||
|  |                       </span> | ||||||
|  |                     </div> | ||||||
|  |                   </template> | ||||||
|  |                 </el-table-column> | ||||||
|  |               </ai-table> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |           <div class="content-item" v-if="currIndex === 1"> | ||||||
|  |             <div class="top"> | ||||||
|  |               <div class="top-item"> | ||||||
|  |                 <div class="top-item__title"> | ||||||
|  |                   <h3>计划送达居民群</h3> | ||||||
|  |                 </div> | ||||||
|  |                 <p>{{ groupInfo.planCount || 0 }}</p> | ||||||
|  |               </div> | ||||||
|  |               <div class="top-item"> | ||||||
|  |                 <div class="top-item__title"> | ||||||
|  |                   <h3>未送达居民群</h3> | ||||||
|  |                 </div> | ||||||
|  |                 <p>{{ groupInfo.unExecutedCount || 0 }}</p> | ||||||
|  |               </div> | ||||||
|  |               <div class="top-item"> | ||||||
|  |                 <div class="top-item__title"> | ||||||
|  |                   <h3>已送达居民群</h3> | ||||||
|  |                 </div> | ||||||
|  |                 <p>{{ groupInfo.executedCount || 0 }}</p> | ||||||
|  |               </div> | ||||||
|  |               <div class="top-item"> | ||||||
|  |                 <div class="top-item__title"> | ||||||
|  |                   <h3>无法送达居民群</h3> | ||||||
|  |                 </div> | ||||||
|  |                 <p>{{ groupInfo.cannotExecuteCount || 0 }}</p> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |             <div class="bottom"> | ||||||
|  |               <div class="bottom-search"> | ||||||
|  |                 <div class="left"> | ||||||
|  |                   <el-radio-group v-model="search2.sendStatus" size="small" @change="search2.current = 1, getGroupInfo()"> | ||||||
|  |                     <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, 'search2')" :multiple="false" v-model="user2"> | ||||||
|  |                     <div class="userSelcet"> | ||||||
|  |                       <span style="color: #606266;" v-if="search2.deptartId"><ai-open-data type="departmentName" :openid="search2.deptartId"></ai-open-data></span> | ||||||
|  |                       <span v-else>部门</span> | ||||||
|  |                       <i class="el-icon-arrow-up"  v-if="!search2.deptartId"></i> | ||||||
|  |                       <i class="el-icon-circle-close" v-if="search2.deptartId" @click.stop="user1 = [], search2.deptartId = '', search2.current = 1, getGroupInfo()"></i> | ||||||
|  |                     </div> | ||||||
|  |                   </ai-picker> | ||||||
|  |                 </div> | ||||||
|  |                 <el-button :type="isDisabled ? '' : 'primary'" :disabled="isDisabled"  @click="sendMsg(1)" v-if="info.status === '4'">{{ isDisabled ? min + '分钟后可再次提醒' : '提醒成员发送' }}</el-button> | ||||||
|  |               </div> | ||||||
|  |               <ai-table | ||||||
|  |                 :tableData="tableData2" | ||||||
|  |                 :col-configs="colConfigs2" | ||||||
|  |                 :total="total2" | ||||||
|  |                 border | ||||||
|  |                 tableSize="small" | ||||||
|  |                 :current.sync="search2.current" | ||||||
|  |                 :size.sync="search2.size" | ||||||
|  |                 @getList="getGroupInfo"> | ||||||
|  |                 <el-table-column slot="user" label="群主" align="center"> | ||||||
|  |                   <template slot-scope="{ row }"> | ||||||
|  |                     <div class="userinfo"> | ||||||
|  |                       <span> | ||||||
|  |                         <ai-open-data type="userName" :openid="row.groupOwnerId"></ai-open-data> | ||||||
|  |                       </span> | ||||||
|  |                       <span style="color: #999"> | ||||||
|  |                         <ai-open-data type="departmentName" :openid="row.mainDepartment"></ai-open-data> | ||||||
|  |                       </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: [], | ||||||
|  |         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: 'groupOwnerId', label: '群主', openType: 'userName' }, | ||||||
|  |           { prop: 'groupNames', label: '群名称' } | ||||||
|  |         ], | ||||||
|  |         colConfigs1: [ | ||||||
|  |           { slot: 'user', label: '成员', openType: 'userName' }, | ||||||
|  |           { prop: 'groupCount', label: '预计送达居民群', align: 'center' } | ||||||
|  |         ], | ||||||
|  |         colConfigs2: [ | ||||||
|  |           { prop: 'groupName', label: '居民群' }, | ||||||
|  |           { prop: 'memberCount', label: '群人数', align: 'center' }, | ||||||
|  |           { slot: 'user', 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) { | ||||||
|  |           this[search].deptartId = e[0].id | ||||||
|  |         } else { | ||||||
|  |           this[search].deptartId = '' | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         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); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       ::v-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; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ::v-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; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ::v-deep .right-tips { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |  | ||||||
|  |       i { | ||||||
|  |         margin-right: 4px; | ||||||
|  |         color: #8899bb; | ||||||
|  |         font-size: 16px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         color: #888888; | ||||||
|  |         font-size: 12px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
| @@ -0,0 +1,296 @@ | |||||||
|  | <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-user-get :instance="instance" @change="onUserChange" :isMultiple="false" v-model="user"> | ||||||
|  |             <div class="userSelcet"> | ||||||
|  |               <span style="color: #606266;" v-if="search.createUserId"><ai-open-data type="userName" :openid="search.createUserId"></ai-open-data></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 = '', search.current = 1, getList()"></i> | ||||||
|  |             </div> | ||||||
|  |           </ai-user-get> | ||||||
|  |         </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> | ||||||
|  |                 <ai-open-data type="userName" :openid="row.createUserId"></ai-open-data> | ||||||
|  |               </span> | ||||||
|  |               <span style="color: #999"> | ||||||
|  |                 <ai-open-data type="departmentName" :openid="row.createUserDept"></ai-open-data> | ||||||
|  |               </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.search.createUserId = e[0].wxOpenUserId | ||||||
|  |         } else { | ||||||
|  |           this.search.createUserId = '' | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         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> | ||||||
| @@ -0,0 +1,344 @@ | |||||||
|  | <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> | ||||||
| @@ -0,0 +1,759 @@ | |||||||
|  | <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; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     ::v-deep .el-calendar-table:not(.is-range) td.next, | ||||||
|  |     ::v-deep .el-calendar-table:not(.is-range) td.prev { | ||||||
|  |       color: #ccc; | ||||||
|  |     } | ||||||
|  |     ::v-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; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar__header{ | ||||||
|  |       display: none; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar__body{ | ||||||
|  |       padding: 0; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar-table thead th:nth-of-type(1){ | ||||||
|  |       border-left: 1px solid #eee; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar-table thead th:nth-of-type(7){ | ||||||
|  |       border-right: 1px solid #eee; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar-table tr td:first-child { | ||||||
|  |       border-left: 1px solid #eee; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar-table tr:first-child td { | ||||||
|  |       border-top: 1px solid #eee; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-calendar-table td { | ||||||
|  |       border-bottom: 1px solid #eee; | ||||||
|  |       border-right: 1px solid #eee; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-timeline-item__timestamp.is-top{ | ||||||
|  |       margin-bottom: 0; | ||||||
|  |       padding-top: 0; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-timeline-item__node{ | ||||||
|  |       background-color: #26F; | ||||||
|  |       width: 8px; | ||||||
|  |       height: 8px; | ||||||
|  |       border-radius: 50%; | ||||||
|  |       left: 1px; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-card{ | ||||||
|  |       border: none; | ||||||
|  |     } | ||||||
|  |     ::v-deep .el-card__body{ | ||||||
|  |       padding: 8px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-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; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .AiPicker{ | ||||||
|  |     display: inline-block; | ||||||
|  |   } | ||||||
|  | </style> | ||||||
| @@ -11,20 +11,39 @@ | |||||||
|       <div class="left"> |       <div class="left"> | ||||||
|         <div class="title"> |         <div class="title"> | ||||||
|           <h2>分组</h2> |           <h2>分组</h2> | ||||||
|           <el-button icon="iconfont iconAdd">添加分组</el-button> |           <el-button icon="iconfont iconAdd" size="mini">添加分组</el-button> | ||||||
|         </div> |         </div> | ||||||
|         <el-scrollbar class="group-list"> |         <el-scrollbar class="group-list"> | ||||||
|           <div class="item" v-for="(item, index) in 20" :key="index"> |           <div | ||||||
|  |             class="item" | ||||||
|  |             v-for="(item, index) in 20" | ||||||
|  |             :class="[currIndex === index ? 'active' : '']" | ||||||
|  |             :key="index" | ||||||
|  |             @click="currIndex = index"> | ||||||
|             <h2>全部分类</h2> |             <h2>全部分类</h2> | ||||||
|             <img src="https://cdn.cunwuyun.cn/dvcp/announce/menu-active.png"/> |             <el-dropdown class="avatar-container"> | ||||||
|  |               <img v-if="currIndex !== index" src="https://cdn.cunwuyun.cn/dvcp/announce/menu-active.png"/> | ||||||
|  |               <img v-else src="https://cdn.cunwuyun.cn/dvcp/announce/menu.png"/> | ||||||
|  |               <el-dropdown-menu slot="dropdown"> | ||||||
|  |                 <el-dropdown-item>编辑</el-dropdown-item> | ||||||
|  |                 <el-dropdown-item>删除</el-dropdown-item> | ||||||
|  |               </el-dropdown-menu> | ||||||
|  |             </el-dropdown> | ||||||
|           </div> |           </div> | ||||||
|         </el-scrollbar> |         </el-scrollbar> | ||||||
|       </div> |       </div> | ||||||
|     </template> |     </template> | ||||||
|     <template slot="content"> |     <template slot="content"> | ||||||
|  |       <div class="tabs"> | ||||||
|  |         <span>话术</span> | ||||||
|  |         <span>图片</span> | ||||||
|  |         <span>小程序</span> | ||||||
|  |         <span>话术</span> | ||||||
|  |         <span>话术</span> | ||||||
|  |       </div> | ||||||
|       <ai-search-bar class="search-bar"> |       <ai-search-bar class="search-bar"> | ||||||
|         <template #left> |         <template #left> | ||||||
|           <el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加话术</el-button> |           <el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加素材</el-button> | ||||||
|         </template> |         </template> | ||||||
|         <template slot="right"> |         <template slot="right"> | ||||||
|           <el-input |           <el-input | ||||||
| @@ -91,7 +110,7 @@ | |||||||
|           taskTitle: '', |           taskTitle: '', | ||||||
|           endTime: '' |           endTime: '' | ||||||
|         }, |         }, | ||||||
|         user: [], |         currIndex: 0, | ||||||
|         tableData: [], |         tableData: [], | ||||||
|         loading: false, |         loading: false, | ||||||
|         total: 0, |         total: 0, | ||||||
| @@ -174,5 +193,65 @@ | |||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
|   .AppMaterialLibrary { |   .AppMaterialLibrary { | ||||||
|     height: 100%; |     height: 100%; | ||||||
|  |  | ||||||
|  |     ::v-deep .ai-list__content--left { | ||||||
|  |       margin-right: 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .left { | ||||||
|  |       width: 100%; | ||||||
|  |       height: 100%; | ||||||
|  |       overflow: hidden; | ||||||
|  |       background: #F5F5F9; | ||||||
|  |  | ||||||
|  |       .title { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: space-between; | ||||||
|  |         height: 40px; | ||||||
|  |         padding: 0 8px 0 16px; | ||||||
|  |         background: #FAFAFB; | ||||||
|  |         box-shadow: inset 0px -1px 0px 0px #E6ECF0; | ||||||
|  |         border-radius: 2px 0px 0px 0px; | ||||||
|  |  | ||||||
|  |         h2 { | ||||||
|  |           font-size: 14px; | ||||||
|  |           color: #222222; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .el-button { | ||||||
|  |           height: 28px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       .group-list { | ||||||
|  |         height: calc(100% - 40px); | ||||||
|  |         padding-top: 8px; | ||||||
|  |         overflow-x: hidden; | ||||||
|  |         .item { | ||||||
|  |           display: flex; | ||||||
|  |           align-items: center; | ||||||
|  |           justify-content: space-between; | ||||||
|  |           height: 40px; | ||||||
|  |           padding: 0 16px 0 24px; | ||||||
|  |           cursor: pointer; | ||||||
|  |           background: transparent; | ||||||
|  |           transition: all ease 0.5s; | ||||||
|  |  | ||||||
|  |           h2 { | ||||||
|  |             font-size: 14px; | ||||||
|  |             color: #222; | ||||||
|  |             font-weight: 600; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           &:hover, &.active { | ||||||
|  |             background: #E8EFFF; | ||||||
|  |  | ||||||
|  |             h2 { | ||||||
|  |               color: #2266FF; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| </style> | </style> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user