Преглед изворни кода

Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_companyUI

lmx пре 1 дан
родитељ
комит
bbe97bd82c

+ 1 - 0
.cursorignore

@@ -0,0 +1 @@
+# Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv)

+ 3 - 0
.env.prod-ddgy

@@ -23,3 +23,6 @@ VUE_APP_PROJECT_FROM=ddgy
 
 # 路由懒加载
 VUE_CLI_BABEL_TRANSPILE_MODULES = true
+
+# 叮当国医
+VUE_APP_PROJECT_CODE = 'ddgy'

+ 25 - 0
.env.prod-jsbk

@@ -0,0 +1,25 @@
+# 页面标题
+VUE_APP_TITLE =济世百康客服系统
+# 公司名称
+VUE_APP_COMPANY_NAME =辽宁济世百康大药房有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD =辽ICP备2025055445号-16
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/jsbk.jpg
+
+# 生产环境配置
+ENV = 'production'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 1
+
+#项目所属
+VUE_APP_PROJECT_FROM=jsbk
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 1 - 0
package.json

@@ -59,6 +59,7 @@
     "build:prod-xcsw": "vue-cli-service build --mode prod-xcsw",
     "build:prod-zlwh": "vue-cli-service build --mode prod-zlwh",
     "build:prod-mengniu": "vue-cli-service build --mode prod-mengniu",
+    "build:prod-jsbk": "vue-cli-service build --mode prod-jsbk",
     "preview": "node build/index.js --preview",
     "lint": "eslint --ext .js,.vue src",
     "test:unit": "jest --clearCache && vue-cli-service test:unit",

+ 9 - 0
src/api/qw/sopLogs.js

@@ -77,3 +77,12 @@ export function generateShortLink(data) {
     data: data
   })
 }
+
+//生成直播短链
+export function generateLiveShortLink(data) {
+  return request({
+    url: '/qw/sopLogs/generateLiveShortLink',
+    method: 'post',
+    data: data
+  })
+}

+ 53 - 0
src/api/wx/wxSop.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询个微SOP列表
+export function listWxSop(query) {
+  return request({
+    url: '/wx/wxSop/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询个微SOP详细
+export function getWxSop(id) {
+  return request({
+    url: '/wx/wxSop/' + id,
+    method: 'get'
+  })
+}
+
+// 新增个微SOP
+export function addWxSop(data) {
+  return request({
+    url: '/wx/wxSop',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改个微SOP
+export function updateWxSop(data) {
+  return request({
+    url: '/wx/wxSop',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除个微SOP
+export function delWxSop(id) {
+  return request({
+    url: '/wx/wxSop/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出个微SOP
+export function exportWxSop(query) {
+  return request({
+    url: '/wx/wxSop/export',
+    method: 'get',
+    params: query
+  })
+}

+ 53 - 0
src/api/wx/wxSopLogs.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询个微发送记录列表
+export function listWxSopLogs(query) {
+  return request({
+    url: '/wx/wxSopLogs/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询个微发送记录详细
+export function getWxSopLogs(id) {
+  return request({
+    url: '/wx/wxSopLogs/' + id,
+    method: 'get'
+  })
+}
+
+// 新增个微发送记录
+export function addWxSopLogs(data) {
+  return request({
+    url: '/wx/wxSopLogs',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改个微发送记录
+export function updateWxSopLogs(data) {
+  return request({
+    url: '/wx/wxSopLogs',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除个微发送记录
+export function delWxSopLogs(id) {
+  return request({
+    url: '/wx/wxSopLogs/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出个微发送记录
+export function exportWxSopLogs(query) {
+  return request({
+    url: '/wx/wxSopLogs/export',
+    method: 'get',
+    params: query
+  })
+}

+ 53 - 0
src/api/wx/wxSopUser.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询个微营期列表
+export function listWxSopUser(query) {
+  return request({
+    url: '/wx/wxSopUser/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询个微营期详细
+export function getWxSopUser(id) {
+  return request({
+    url: '/wx/wxSopUser/' + id,
+    method: 'get'
+  })
+}
+
+// 新增个微营期
+export function addWxSopUser(data) {
+  return request({
+    url: '/wx/wxSopUser',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改个微营期
+export function updateWxSopUser(data) {
+  return request({
+    url: '/wx/wxSopUser',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除个微营期
+export function delWxSopUser(id) {
+  return request({
+    url: '/wx/wxSopUser/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出个微营期
+export function exportWxSopUser(query) {
+  return request({
+    url: '/wx/wxSopUser/export',
+    method: 'get',
+    params: query
+  })
+}

+ 53 - 0
src/api/wx/wxSopUserInfo.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询个微营期详情列表
+export function listWxSopUserInfo(query) {
+  return request({
+    url: '/wx/wxSopUserInfo/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询个微营期详情详细
+export function getWxSopUserInfo(id) {
+  return request({
+    url: '/wx/wxSopUserInfo/' + id,
+    method: 'get'
+  })
+}
+
+// 新增个微营期详情
+export function addWxSopUserInfo(data) {
+  return request({
+    url: '/wx/wxSopUserInfo',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改个微营期详情
+export function updateWxSopUserInfo(data) {
+  return request({
+    url: '/wx/wxSopUserInfo',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除个微营期详情
+export function delWxSopUserInfo(id) {
+  return request({
+    url: '/wx/wxSopUserInfo/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出个微营期详情
+export function exportWxSopUserInfo(query) {
+  return request({
+    url: '/wx/wxSopUserInfo/export',
+    method: 'get',
+    params: query
+  })
+}

BIN
src/assets/logo/jsbk.jpg


+ 8 - 2
src/views/member/list.vue

@@ -253,9 +253,12 @@
         <el-form-item label="昵称" prop="nickname">
           <el-input v-model="form.nickname" :disabled="true" placeholder="请输入昵称" />
         </el-form-item>
-        <el-form-item label="手机号码" prop="phone">
+        <el-form-item label="手机号码" prop="phone" v-if = "projectCode != 'ddgy' ">
           <el-input v-model="form.phone" disabled placeholder="请输入手机号码" />
         </el-form-item>
+        <el-form-item label="手机号码" prop="phone" v-if = "projectCode === 'ddgy' ">
+          <el-input v-model="form.phone" placeholder="请输入手机号码" />
+        </el-form-item>
         <el-form-item label="最后登录IP" prop="lastIp" v-if="form.lastIp">
           <el-input v-model="form.lastIp" disabled placeholder="最后一次登录IP" />
         </el-form-item>
@@ -333,6 +336,7 @@ export default {
   components: {userDetails},
   data() {
     return {
+      projectCode: process.env.VUE_APP_PROJECT_CODE,
       show:{
         open:false,
       },
@@ -595,7 +599,9 @@ export default {
           const updateForm={
             id: this.rowInfo.id,
             status: this.form.status,
-            remark: this.form.remark
+            remark: this.form.remark,
+            userId: this.form.userId,
+            phone: this.form.phone
           }
           updateMemberUser(updateForm).then(response => {
             if (response.code === 200) {

+ 8 - 3
src/views/member/mylist.vue

@@ -253,9 +253,12 @@
         <el-form-item label="昵称" prop="nickname">
           <el-input v-model="form.nickname" :disabled="true" placeholder="请输入昵称" />
         </el-form-item>
-        <el-form-item label="手机号码" prop="phone">
+        <el-form-item label="手机号码" prop="phone"  v-if = "projectCode != 'ddgy' ">
           <el-input v-model="form.phone" disabled placeholder="请输入手机号码" />
         </el-form-item>
+        <el-form-item label="手机号码" prop="phone" v-if = "projectCode === 'ddgy' ">
+          <el-input v-model="form.phone" placeholder="请输入手机号码" />
+        </el-form-item>
         <el-form-item label="最后登录IP" prop="lastIp" v-if="form.lastIp">
           <el-input v-model="form.lastIp" disabled placeholder="最后一次登录IP" />
         </el-form-item>
@@ -336,7 +339,7 @@ export default {
   components: {userDetails,userCoursePeriod},
   data() {
     return {
-
+      projectCode: process.env.VUE_APP_PROJECT_CODE,
       show:{
         title:"会员详情",
         open:false,
@@ -627,7 +630,9 @@ export default {
           const updateForm={
             id: this.rowInfo.id,
             status: this.form.status,
-            remark: this.form.remark
+            remark: this.form.remark,
+            userId: this.form.userId,
+            phone: this.form.phone
           }
           updateMemberUser(updateForm).then(response => {
             if (response.code === 200) {

+ 9 - 0
src/views/qw/sop/sop.vue

@@ -867,6 +867,15 @@
                         </el-form-item>
                       </el-card>
                     </div>
+                    <div v-if="item.contentType == 11">
+                      <el-input
+                        v-model="item.value"
+                        type="textarea"
+                        :rows="5"
+                        placeholder="请输入群公告内容"
+                        style="width: 90%;margin-top: 10px;"
+                      />
+                    </div>
                   </el-form-item>
 
                   <el-form-item label="添加短链" v-if="item.contentType == 1 "  >

+ 22 - 4
src/views/qw/sopLogs/sopLogsList.vue

@@ -186,7 +186,12 @@
                 <span v-if="item.contentType == 10">自定义小程序</span>
                 <span v-if="item.contentType == 15">APP文本</span>
                 <span v-if="item.contentType == 16">APP语音</span>
-                <span v-if="item.contentType == 4"><el-button size="mini" type="primary" @click="generateShortLink(item)" style="margin-left: 330px;">生成短链</el-button></span>
+                <span v-if="item.contentType == 11">群公告</span>
+                <span v-if="item.contentType == 16">H5看课卡片</span>
+                <span v-if="item.contentType == 18">直播卡片</span>
+                <span v-if="item.contentType == 19">直播短链</span>
+                <span v-if="item.contentType == 4 || item.contentType == 17"><el-button size="mini" type="primary" @click="generateShortLink(item)" style="margin-left: 330px;">生成短链</el-button></span>
+                <span v-if="item.contentType == 18 || item.contentType == 19"><el-button size="mini" type="primary" @click="generateLiveShortLink(item)" style="margin-left: 330px;">复制短链</el-button></span>
               </div>
               <div v-if="item.sendStatus">
                 <span>发送状态:</span>
@@ -195,7 +200,7 @@
               </div>
             </div>
             <div v-if="item.sendStatus && item.sendStatus == 2">发送失败原因:<span style="color: #ff4949">{{item.sendRemarks}}</span></div>
-            <div v-if="item.contentType == 1 || item.contentType == 15" v-html="item.value"></div>
+            <div v-if="item.contentType == 1 || item.contentType == 15 || item.contentType == 19" v-html="item.value"></div>
             <div v-if="item.contentType == 2">
               <el-image
                 style="width: 100px; height: 100px"
@@ -219,7 +224,7 @@
                 </div>
               </div>
             </div>
-            <div v-if="item.contentType == 4 || item.contentType == 10" class="message-style">
+            <div v-if="item.contentType == 4 || item.contentType == 10 || item.contentType == 18 || item.contentType == 17" class="message-style">
                 <div style="display: flex; justify-content: space-between; width: 100%">
                   <span style="font-size: 13px; flex: 1">{{ item.miniprogramTitle }}</span>
                   <el-image
@@ -277,6 +282,9 @@
                 </el-form-item >
               </el-card>
             </div>
+            <div v-if="item.contentType == 11">
+              <div v-html="item.value"></div>
+            </div>
 
           </el-card>
         </div>
@@ -335,7 +343,7 @@ import {
   listQwSopLogsList,
   delQwSopLogs,
   editCourseQwSopLogs,
-  generateShortLink
+  generateShortLink,generateLiveShortLink
 } from '../../../api/qw/sopLogs'
 import {delSopUserLogsInfo} from "@/api/qw/sopUserLogsInfo";
 import userVideo from "@/views/qw/userVideo/userVideo";
@@ -649,6 +657,16 @@ export default {
       });
       this.shortLinkDialogVisible = true;
     },
+    generateLiveShortLink(val){
+      const param = {
+        linkStr:val.miniprogramPage,
+        appId:val.miniprogramAppid
+      };
+      generateLiveShortLink(param).then(res=>{
+        this.copyText = res.urlLink;
+      });
+      this.shortLinkDialogVisible = true;
+    },
     onCopy(){
       navigator.clipboard.writeText(this.copyText).then(() => {
         this.$message.success('复制成功')

+ 12 - 2
src/views/qw/sopTemp/updateSopTemp.vue

@@ -514,7 +514,7 @@
                                               </el-form-item>
                                             </el-card>
                                           </div>
-                                          <div v-if="setList.contentType == 12">
+                                          <div v-if="setList.contentType == 12 || setList.contentType == 18 || setList.contentType == 19">
                                             <el-card class="box-card miniprogram-card">
                                               <div slot="header" class="card-header-mini">
                                                 <i class="el-icon-video-camera"></i>
@@ -678,6 +678,16 @@
                                               </el-form-item>
                                             </el-card>
                                           </div>
+                                          <div v-if="setList.contentType == 11">
+                                            <el-input
+                                              :disabled="formType == 3 || !roles.includes('edit_sop_temp_content')"
+                                              v-model="setList.value"
+                                              type="textarea"
+                                              :rows="5"
+                                              placeholder="请输入群公告内容"
+                                              style="width: 90%;margin-top: 10px;"
+                                            />
+                                          </div>
                                         </el-form-item>
                                         <!--                                        <el-form-item label="添加短链"-->
                                         <!--                                                      v-if="content.type == 2 && setList.contentType == 1  ">-->
@@ -1807,7 +1817,7 @@ export default {
       ruleList: [],
       ids: [],
       // startTimeRange: [],
-      courseTypeList: ['1','2', '4','5','6', '7','8','9','10','14','15'],
+      courseTypeList: ['1','2', '4','5','6', '7','8','9','10','14','15','16','11'],
       sysFsSopWatchStatus: [],
       //消息内容类型 企微版
       sysQwSopContentType: [],

+ 9 - 9
src/views/qw/sopUserLogsInfo/sendMsgOpenTool.vue

@@ -101,7 +101,7 @@
                     </el-card>
                   </div> -->
                   <el-form-item label="内容" style="margin-bottom: 2%" >
-                    <div v-if="item.contentType == 12">
+                    <div v-if="item.contentType == 12 || item.contentType == 18 || item.contentType == 19">
                       <el-card class="box-card">
                         <el-form-item label="直播间" >
                           <el-select  v-model="item.liveId"
@@ -179,7 +179,7 @@
                         </el-form-item>
                       </el-card>
                     </div>
-                    <div v-if="item.contentType == 4 || item.contentType == 10 ">
+                    <div v-if="item.contentType == 4 || item.contentType == 10  || item.contentType == 17 ">
                       <el-card class="box-card">
                         <el-form-item label="标题" prop="miniprogramTitle">
                           <el-input v-model="item.miniprogramTitle" placeholder="请输入小程序消息标题,最长为64字"  />
@@ -596,7 +596,7 @@ export default {
               this.$set(this.setting[i], 'linkImageUrl', selectedCourse.dictImgUrl);
             }
 
-            if ( this.setting[i].contentType == 4 || this.setting[i].contentType == 10 ){
+            if ( this.setting[i].contentType == 4 || this.setting[i].contentType == 10  || this.setting[i].contentType == 17 ){
               this.$set(this.setting[i], 'miniprogramPicUrl', selectedCourse.dictImgUrl);
             }
           }
@@ -627,7 +627,7 @@ export default {
 
             }
 
-            if (this.setting[i].contentType == 4 || this.setting[i].contentType == 10 ){
+            if (this.setting[i].contentType == 4 || this.setting[i].contentType == 10  || this.setting[i].contentType == 17 ){
               this.$set(this.setting[i], 'miniprogramTitle', selectedVideo.dictLabel);
 
               if (this.projectFrom == 'sxjz' && selectedVideo.dictImgUrl) {
@@ -853,7 +853,7 @@ export default {
               this.$set(this.setting[i], 'linkTitle', selectedCourse.dictLabel);
               this.$set(this.setting[i], 'linkImageUrl', selectedCourse.dictImgUrl);
             }
-            if (this.setting[i].contentType == 4 || this.setting[i].contentType == 10 ){
+            if (this.setting[i].contentType == 4 || this.setting[i].contentType == 10 || this.setting[i].contentType == 17 ){
               this.$set(this.setting[i], 'miniprogramPicUrl', selectedCourse.dictImgUrl);
             }
 
@@ -878,7 +878,7 @@ export default {
                 this.$set(this.setting[i], 'linkImageUrl', selectedVideo.dictImgUrl);
               }
             }
-            if (this.setting[i].contentType == 4 || this.setting[i].contentType == 10){
+            if (this.setting[i].contentType == 4 || this.setting[i].contentType == 10 || this.setting[i].contentType == 17){
               this.$set(this.setting[i], 'miniprogramTitle', selectedVideo.dictLabel);
 
               if (this.projectFrom == 'sxjz' && selectedVideo.dictImgUrl) {
@@ -935,7 +935,7 @@ export default {
           let hasLiveSetting = false;
           console.log(jsonSetting)
           for(let index=0;index < jsonSetting.length;index++){
-           if(!!jsonSetting[index] && jsonSetting[index].contentType == "12") {
+           if(!!jsonSetting[index] && (jsonSetting[index].contentType == "12" || jsonSetting[index].contentType == "18" || jsonSetting[index].contentType == "19") ) {
             if(!!hasLiveSetting){
                return this.$message.error("发送直播间只能一次只能发送一条");
             }
@@ -977,10 +977,10 @@ export default {
                 return this.$message.error("链接地址不能为空")
               }
 
-              if ((this.setting[i].contentType == 4 || this.setting[i].contentType == 10 ) && (this.setting[i].miniprogramTitle == null || this.setting[i].miniprogramTitle == "")) {
+              if ((this.setting[i].contentType == 4 || this.setting[i].contentType == 10 || this.setting[i].contentType == 17) && (this.setting[i].miniprogramTitle == null || this.setting[i].miniprogramTitle == "")) {
                 return this.$message.error("小程序消息标题不能为空")
               }
-              if ((this.setting[i].contentType == 4 || this.setting[i].contentType == 10 ) && (this.setting[i].miniprogramPicUrl == null || this.setting[i].miniprogramPicUrl == "")) {
+              if ((this.setting[i].contentType == 4 || this.setting[i].contentType == 10 || this.setting[i].contentType == 17) && (this.setting[i].miniprogramPicUrl == null || this.setting[i].miniprogramPicUrl == "")) {
                 return this.$message.error("小程序封面地址不能为空")
               }
 

+ 27 - 8
src/views/qw/sopUserLogsInfo/sendMsgSopOpenTool.vue

@@ -104,7 +104,7 @@
                         </el-form-item>
                       </el-card>
                     </div>
-                    <div v-if="item.contentType == 4 || item.contentType == 10 ">
+                    <div v-if="item.contentType == 4 || item.contentType == 10 || item.contentType == 17">
                       <el-card class="box-card">
                         <el-form-item label="标题" prop="miniprogramTitle">
                           <el-input v-model="item.miniprogramTitle" placeholder="请输入小程序消息标题,最长为64字"  />
@@ -204,7 +204,7 @@
                       </el-card>
                     </div>
 
-                    <div v-if="item.contentType == 12">
+                    <div v-if="item.contentType == 12 || item.contentType == 18 || item.contentType == 19">
                       <el-card class="box-card">
                         <el-form-item label="直播间" >
                           <el-select  v-model="item.liveId"
@@ -329,6 +329,7 @@ import ImageUpload from "@/views/qw/sop/ImageUpload.vue";
 import {courseList, videoList} from "@/api/qw/sop";
 import userVideo from "@/views/qw/userVideo/userVideo";
 import {listReward} from "@/api/qw/luckyBag";
+import {listToLiveNoEnd} from "@/api/live/live";
 
 
 export default {
@@ -405,6 +406,7 @@ export default {
       //插件版
       sysQwSopAiContentType:[],
 
+      liveList: [],
       sendMsgOpen:{
         title:'一键批量群发',
         open:false,
@@ -446,6 +448,9 @@ export default {
     this.getDicts("sys_fs_sop_watch_status").then(response => {
       this.sysFsSopWatchStatus = response.data;
     });
+    listToLiveNoEnd().then(response => {
+      this.liveList = response.rows;
+    });
 
     courseList().then(response => {
       this.courseList = response.list;
@@ -464,6 +469,20 @@ export default {
         content.luckyBagDataStatus = null;
       }
     },
+    liveChange(content) {
+      // content.liveId 是选中的直播间 ID(liveId)
+      const selectedLive = this.liveList.find(live => live.liveId === content.liveId);
+      if (selectedLive) {
+        // 从选中的直播间对象中提取标题和封面,赋值给当前内容的对应字段
+        // 假设直播间对象中标题字段为 liveTitle,封面字段为 coverImg(根据实际接口字段调整)
+        content.miniprogramTitle = selectedLive.liveName || ''; // 自动填充标题
+        content.miniprogramPicUrl = selectedLive.liveImgUrl || ''; // 自动填充封面
+      } else {
+        // 若未找到对应直播间,清空标题和封面(可选)
+        content.miniprogramTitle = '';
+        content.miniprogramPicUrl = '';
+      }
+    },
 
     qwUserVideoResult(val) {
 
@@ -502,7 +521,7 @@ export default {
               this.$set(this.setting[i], 'linkImageUrl', selectedCourse.dictImgUrl);
             }
 
-            if ( this.setting[i].contentType == 4 || this.setting[i].contentType == 10  ){
+            if ( this.setting[i].contentType == 4 || this.setting[i].contentType == 10 || this.setting[i].contentType == 17){
               this.$set(this.setting[i], 'miniprogramPicUrl', selectedCourse.dictImgUrl);
             }
           }
@@ -532,7 +551,7 @@ export default {
               }
             }
 
-            if (this.setting[i].contentType == 4 || this.setting[i].contentType == 10 ){
+            if (this.setting[i].contentType == 4 || this.setting[i].contentType == 10 || this.setting[i].contentType == 17){
               this.$set(this.setting[i], 'miniprogramTitle', selectedVideo.dictLabel);
 
               if (this.projectFrom == 'sxjz' && selectedVideo.dictImgUrl) {
@@ -760,7 +779,7 @@ export default {
               this.$set(this.setting[i], 'linkImageUrl', selectedCourse.dictImgUrl);
 
             }
-            if (this.setting[i].contentType == 4 || this.setting[i].contentType == 10){
+            if (this.setting[i].contentType == 4 || this.setting[i].contentType == 10 || this.setting[i].contentType == 17){
               this.$set(this.setting[i], 'miniprogramPicUrl', selectedCourse.dictImgUrl);
 
             }
@@ -787,7 +806,7 @@ export default {
               }
 
             }
-            if (this.setting[i].contentType == 4 || this.setting[i].contentType == 10){
+            if (this.setting[i].contentType == 4 || this.setting[i].contentType == 10 || this.setting[i].contentType == 17){
               this.$set(this.setting[i], 'miniprogramTitle', selectedVideo.dictLabel);
 
               if (this.projectFrom == 'sxjz' && selectedVideo.dictImgUrl) {
@@ -865,10 +884,10 @@ export default {
                 return this.$message.error("链接地址不能为空")
               }
 
-              if ((this.setting[i].contentType == 4 || this.setting[i].contentType == 10) && (this.setting[i].miniprogramTitle == null || this.setting[i].miniprogramTitle == "")) {
+              if ((this.setting[i].contentType == 4 || this.setting[i].contentType == 10  || this.setting[i].contentType == 17) && (this.setting[i].miniprogramTitle == null || this.setting[i].miniprogramTitle == "")) {
                 return this.$message.error("小程序消息标题不能为空")
               }
-              if ((this.setting[i].contentType == 4 || this.setting[i].contentType == 10) && (this.setting[i].miniprogramPicUrl == null || this.setting[i].miniprogramPicUrl == "")) {
+              if ((this.setting[i].contentType == 4 || this.setting[i].contentType == 10 || this.setting[i].contentType == 17) && (this.setting[i].miniprogramPicUrl == null || this.setting[i].miniprogramPicUrl == "")) {
                 return this.$message.error("小程序封面地址不能为空")
               }
 

+ 2 - 2
src/views/qw/sopUserLogsInfo/sopUserLogsInfoDetails.vue

@@ -407,7 +407,7 @@
                         placeholder="输入要转为语音的内容" style="width: 90%;margin-top: 10px;"
                         @input="handleInputVideoText(item.value,item)"/>
                     </div>
-                    <div v-if="item.contentType == 12">
+                    <div v-if="item.contentType == 12 || item.contentType == 18 || item.contentType == 19">
                       <!--                                           <div >-->
                       <el-card class="box-card">
                         <el-form-item label="直播间" >
@@ -1405,7 +1405,7 @@ export default {
           let hasLiveSetting = false;
           let jsonSetting = JSON.parse(this.msgForm.setting);
           for(let index=0;index < jsonSetting.length;index++){
-           if(!!jsonSetting[index] && jsonSetting[index].contentType == "12") {
+           if(!!jsonSetting[index] && (jsonSetting[index].contentType == "12" || jsonSetting[index].contentType == "18" || jsonSetting[index].contentType == "19") ) {
             if(!!hasLiveSetting){
                return this.$message.error("发送直播间只能一次只能发送一条");
             }

+ 678 - 0
src/views/wx/wxSop/index.vue

@@ -0,0 +1,678 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="筛选方式" prop="filterType">
+        <el-select
+          v-model="queryParams.filterType"
+          placeholder="请选择筛选方式"
+          clearable
+          size="small"
+        >
+          <el-option
+            v-for="item in filterTypeOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="模板" prop="tempId">
+        <el-select
+          v-model="queryParams.tempId"
+          placeholder="请选择模板"
+          clearable
+          filterable
+          size="small"
+          style="width: 200px;"
+        >
+          <el-option
+            v-for="item in tempList"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="固定营期" prop="isFixed">
+        <el-select
+          v-model="queryParams.isFixed"
+          placeholder="请选择固定营期"
+          clearable
+          size="small"
+        >
+          <el-option
+            v-for="item in isFixedOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="营期时间" prop="startTime">
+        <el-date-picker clearable size="small"
+          v-model="queryParams.startTime"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择营期时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['wx:wxSop:add']"
+        >新增</el-button>
+      </el-col>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="wxSopList" @selection-change="handleSelectionChange">
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="名称" align="center" prop="name" />
+      <el-table-column label="筛选方式" align="center" prop="filterType">
+        <template slot-scope="scope">
+          <dict-tag :options="filterTypeOptions" :value="scope.row.filterType" />
+        </template>
+      </el-table-column>
+      <el-table-column label="模板" align="center" prop="tempId">
+        <template slot-scope="scope">
+          <span
+            v-for="item in tempList"
+            :key="item.id"
+            v-if="String(item.id) === String(scope.row.tempId)"
+          >
+            {{ item.name }}
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否固定营期" align="center" prop="isFixed">
+        <template slot-scope="scope">
+          <dict-tag :options="isFixedOptions" :value="scope.row.isFixed" />
+        </template>
+      </el-table-column>
+      <el-table-column label="过期时间(小时)" align="center" prop="expiryTime">
+        <template slot-scope="scope">
+          {{ scope.row.expiryTime }} 小时
+        </template>
+      </el-table-column>
+      <el-table-column label="营期开始时间" align="center" prop="startTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['wx:wxSop:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['wx:wxSop:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改个微SOP对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="70%" append-to-body class="wx-sop-dialog">
+      <div class="wx-sop-dialog-content">
+        <el-form ref="form" :model="form" :rules="rules" label-width="130px" class="wx-sop-form">
+          <!-- 基本信息 -->
+          <div class="form-section">
+            <div class="section-title">
+              <i class="el-icon-document"></i>
+              <span>基本信息</span>
+            </div>
+            <el-form-item label="规则名称" prop="name">
+              <el-input v-model="form.name" placeholder="请输入规则名称" clearable maxlength="50" show-word-limit />
+            </el-form-item>
+            <el-form-item label="模板" prop="tempId">
+              <el-select
+                v-model="form.tempId"
+                placeholder="请选择模板"
+                filterable
+                clearable
+                style="width: 100%;"
+                v-loading="tempListLoading"
+                @focus="loadTempList"
+              >
+                <el-option
+                  v-for="item in tempList"
+                  :key="item.id"
+                  :label="item.name"
+                  :value="item.id"
+                />
+              </el-select>
+              <Tip title="选择想要发送的模板规则" />
+            </el-form-item>
+          </div>
+
+          <!-- 筛选规则 -->
+          <div class="form-section">
+            <div class="section-title">
+              <i class="el-icon-s-operation"></i>
+              <span>筛选规则</span>
+            </div>
+            <el-form-item label="筛选方式" prop="filterType">
+              <el-radio-group v-model="form.filterType">
+                <el-radio :label="'0'">按标签</el-radio>
+                <el-radio :label="'1'">按群聊</el-radio>
+              </el-radio-group>
+              <Tip :title="'标签:按标签筛选客户进入SOP;群聊:按群聊筛选进入SOP'" />
+            </el-form-item>
+            <template v-if="form.filterType === '0'">
+              <el-form-item label="选择的标签" prop="selectTags">
+                <el-select
+                  v-model="selectTagsList"
+                  multiple
+                  filterable
+                  clearable
+                  placeholder="请选择进入SOP的标签"
+                  style="width: 100%;"
+                  @change="onSelectTagsChange"
+                >
+                  <el-option
+                    v-for="item in tagsOptions"
+                    :key="item.dictValue"
+                    :label="item.dictLabel"
+                    :value="item.dictValue"
+                  />
+                </el-select>
+              </el-form-item>
+              <el-form-item label="排除的标签" prop="excludeTags">
+                <el-select
+                  v-model="excludeTagsList"
+                  multiple
+                  filterable
+                  clearable
+                  placeholder="请选择不想进入SOP的标签"
+                  style="width: 100%;"
+                  @change="onExcludeTagsChange"
+                >
+                  <el-option
+                    v-for="item in tagsOptions"
+                    :key="item.dictValue"
+                    :label="item.dictLabel"
+                    :value="item.dictValue"
+                  />
+                </el-select>
+              </el-form-item>
+            </template>
+            <el-form-item label="执行账号" prop="accountIds">
+              <el-button
+                type="primary"
+                plain
+                icon="el-icon-user"
+                size="small"
+                @click="openQwUserSelect"
+              >
+                选择账号
+                <el-tag v-if="selectedQwUsers && selectedQwUsers.length" type="success" size="mini" style="margin-left: 6px;">
+                  {{ selectedQwUsers.length }}
+                </el-tag>
+              </el-button>
+              <div v-if="selectedQwUsers && selectedQwUsers.length" class="selected-tags">
+                <el-tag
+                  v-for="item in selectedQwUsers"
+                  :key="item.id"
+                  size="mini"
+                  closable
+                  @close="removeQwUser(item)"
+                >
+                  {{ item.wxNickName || item.wxNo || item.companyUserName }}
+                </el-tag>
+              </div>
+              <Tip title="从企微账号列表中选择用于执行个微SOP的账号" />
+            </el-form-item>
+          </div>
+
+          <!-- 时间与营期 -->
+          <div class="form-section">
+            <div class="section-title">
+              <i class="el-icon-time"></i>
+              <span>时间与营期</span>
+            </div>
+            <el-row :gutter="24">
+              <el-col :span="12">
+                <el-form-item label="开始时间" prop="startTime">
+                  <el-date-picker
+                    clearable
+                    size="small"
+                    v-model="form.startTime"
+                    type="date"
+                    value-format="yyyy-MM-dd"
+                    placeholder="选择开始时间"
+                    style="width: 100%;"
+                  />
+                  <Tip title="SOP开始发送时间" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="过期时间" prop="expiryTime">
+                  <div class="expiry-time-wrap">
+                    <el-input-number
+                      v-model="form.expiryTime"
+                      :min="1"
+                      :max="100"
+                      controls-position="right"
+                      style="flex: 1;"
+                    />
+                    <span class="unit-text">小时</span>
+                  </div>
+                  <Tip title="待发送消息超过此时间未发送将自动作废" />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-form-item label="固定营期" prop="isFixed">
+              <el-radio-group v-model="form.isFixed">
+                <el-radio :label="'0'">否</el-radio>
+                <el-radio :label="'1'">是</el-radio>
+              </el-radio-group>
+              <Tip title="固定营期:不管什么时候进入SOP的客户,营期时间都为任务开始时间" />
+            </el-form-item>
+          </div>
+
+          <!-- 其他 -->
+          <div class="form-section">
+            <div class="section-title">
+              <i class="el-icon-edit-outline"></i>
+              <span>其他</span>
+            </div>
+            <el-form-item label="备注" prop="remark">
+              <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注(选填)" maxlength="200" show-word-limit />
+            </el-form-item>
+          </div>
+        </el-form>
+      </div>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="cancel">取 消</el-button>
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+      </div>
+
+      <qw-user-select @success="selectQwUserFun" ref="qwUserSelect" />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listWxSop, getWxSop, delWxSop, addWxSop, updateWxSop, exportWxSop } from "@/api/wx/wxSop";
+import { listSopTemp } from "@/api/qw/sopTemp";
+import Tip from "@/components/Tip";
+import QwUserSelect from "@/views/components/QwUserSelect.vue";
+
+export default {
+  name: "WxSop",
+  components: { Tip, QwUserSelect },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 模板下拉数据
+      tempList: [],
+      tempListLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 个微SOP表格数据
+      wxSopList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 选择的企微账号
+      selectedQwUsers: [],
+      // 标签库(与线索客户打标签共用 crm_customer_tag)
+      tagsOptions: [],
+      selectTagsList: [],
+      excludeTagsList: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        filterType: null,
+        selectTags: null,
+        excludeTags: null,
+        tempId: null,
+        isFixed: null,
+        expiryTime: null,
+        startTime: null,
+      },
+      // 本地字典(筛选方式、是否固定营期)
+      filterTypeOptions: [
+        { dictValue: "0", dictLabel: "按标签筛选" },
+        { dictValue: "1", dictLabel: "按群聊筛选" },
+      ],
+      isFixedOptions: [
+        { dictValue: "0", dictLabel: "否" },
+        { dictValue: "1", dictLabel: "是" },
+      ],
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        name: [{ required: true, message: "请输入规则名称", trigger: "blur" }],
+        tempId: [{ required: true, message: "请选择模板", trigger: "change" }]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.loadTempList();
+    this.getDicts("crm_customer_tag").then((response) => {
+      this.tagsOptions = response.data || [];
+    });
+  },
+  methods: {
+    loadTempList() {
+      this.tempListLoading = true;
+      listSopTemp()
+        .then(response => {
+          this.tempList = response.rows || [];
+        })
+        .finally(() => {
+          this.tempListLoading = false;
+        });
+    },
+    onSelectTagsChange(val) {
+      this.form.selectTags = Array.isArray(val) ? val.join(",") : "";
+    },
+    onExcludeTagsChange(val) {
+      this.form.excludeTags = Array.isArray(val) ? val.join(",") : "";
+    },
+    syncTagsFromForm() {
+      this.selectTagsList = this.form.selectTags ? String(this.form.selectTags).split(",").filter(Boolean) : [];
+      this.excludeTagsList = this.form.excludeTags ? String(this.form.excludeTags).split(",").filter(Boolean) : [];
+    },
+    /** 查询个微SOP列表 */
+    getList() {
+      this.loading = true;
+      listWxSop(this.queryParams).then(response => {
+        this.wxSopList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        name: null,
+        filterType: "0",
+        selectTags: null,
+        excludeTags: null,
+        tempId: null,
+        tempName: null,
+        isFixed: "0",
+        accountIds: null,
+        expiryTime: 24,
+        startTime: null,
+        createTime: null,
+        createBy: null,
+        updateTime: null,
+        updateBy: null,
+        remark: null
+      };
+      this.selectTagsList = [];
+      this.excludeTagsList = [];
+      this.resetForm("form");
+    },
+    // 打开企微账号选择
+    openQwUserSelect() {
+      this.$nextTick(() => {
+        this.$refs.qwUserSelect && this.$refs.qwUserSelect.setRows(this.selectedQwUsers);
+      });
+    },
+    // 选择企微账号回调(数据源与外呼任务分配账号一致)
+    selectQwUserFun(e) {
+      this.selectedQwUsers = e.rows || [];
+      const ids = e.ids || [];
+      this.form.accountIds = ids.join(",");
+      this.$forceUpdate();
+    },
+    removeQwUser(item) {
+      this.selectedQwUsers = this.selectedQwUsers.filter((u) => u.id !== item.id);
+      this.form.accountIds = this.selectedQwUsers.map((u) => u.id).join(",");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加个微SOP";
+      this.loadTempList();
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getWxSop(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改个微SOP";
+        // 兼容后端返回 number,确保 radio 正常回显
+        this.form.filterType =
+          this.form.filterType === null || typeof this.form.filterType === "undefined"
+            ? "0"
+            : String(this.form.filterType);
+        this.form.isFixed =
+          this.form.isFixed === null || typeof this.form.isFixed === "undefined"
+            ? "0"
+            : String(this.form.isFixed);
+        this.syncTagsFromForm();
+        // 回显执行账号
+        this.selectedQwUsers = response.data.selectedQwUsers || [];
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          const payload = this.buildSubmitPayload();
+          if (this.form.id != null) {
+            updateWxSop(payload).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addWxSop(payload).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 构建提交数据,确保与后端 WxSop 字段一致 */
+    buildSubmitPayload() {
+      const f = this.form;
+      return {
+        id: f.id,
+        name: f.name,
+        filterType: f.filterType != null ? parseInt(f.filterType, 10) : 0,
+        selectTags: f.selectTags || null,
+        excludeTags: f.excludeTags || null,
+        tempId: f.tempId != null ? String(f.tempId) : null,
+        isFixed: f.isFixed != null ? parseInt(f.isFixed, 10) : 0,
+        expiryTime: f.expiryTime != null ? parseInt(f.expiryTime, 10) : 24,
+        startTime: f.startTime || null,
+        remark: f.remark || null,
+        accountIds: f.accountIds || null
+      };
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除个微SOP编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delWxSop(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有个微SOP数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportWxSop(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.wx-sop-dialog-content {
+  padding: 8px 16px 24px;
+  max-height: 70vh;
+  overflow-y: auto;
+}
+
+.wx-sop-form {
+  .form-section {
+    background: #fafbfc;
+    border-radius: 10px;
+    padding: 24px 28px;
+    margin-bottom: 24px;
+    border: 1px solid #ebeef5;
+  }
+
+  .form-section:last-of-type {
+    margin-bottom: 0;
+  }
+
+  .section-title {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+    font-size: 15px;
+    font-weight: 600;
+    color: #303133;
+    margin-bottom: 20px;
+    padding-bottom: 14px;
+    border-bottom: 1px solid #e4e7ed;
+  }
+
+  .section-title i {
+    font-size: 18px;
+    color: #409eff;
+  }
+
+  ::v-deep .el-form-item {
+    margin-bottom: 22px;
+  }
+
+  ::v-deep .el-form-item:last-child {
+    margin-bottom: 0;
+  }
+
+  .expiry-time-wrap {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+    width: 100%;
+  }
+
+  .unit-text {
+    color: #909399;
+    font-size: 13px;
+    flex-shrink: 0;
+  }
+
+  .selected-tags {
+    margin-top: 12px;
+    display: flex;
+    flex-wrap: wrap;
+    gap: 8px;
+  }
+
+  .selected-tags .el-tag {
+    margin: 0;
+  }
+}
+
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 16px;
+  padding: 16px 0 8px;
+}
+</style>

+ 481 - 0
src/views/wx/wxSopLogs/index.vue

@@ -0,0 +1,481 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="消息类型0个人1群" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择消息类型0个人1群" clearable size="small">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="任务ID" prop="sopId">
+        <el-input
+          v-model="queryParams.sopId"
+          placeholder="请输入任务ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="营期ID" prop="sopUserId">
+        <el-input
+          v-model="queryParams.sopUserId"
+          placeholder="请输入营期ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="发送类型" prop="sendType">
+        <el-select v-model="queryParams.sendType" placeholder="请选择发送类型" clearable size="small">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="生成类型(0自动1手动)" prop="generateType">
+        <el-select v-model="queryParams.generateType" placeholder="请选择生成类型(0自动1手动)" clearable size="small">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="发送账号ID" prop="accountId">
+        <el-input
+          v-model="queryParams.accountId"
+          placeholder="请输入发送账号ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="发送对象ID" prop="wxContactId">
+        <el-input
+          v-model="queryParams.wxContactId"
+          placeholder="请输入发送对象ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="发送对象名称" prop="wxContactName">
+        <el-input
+          v-model="queryParams.wxContactName"
+          placeholder="请输入发送对象名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="发送群聊ID" prop="wxRoomId">
+        <el-input
+          v-model="queryParams.wxRoomId"
+          placeholder="请输入发送群聊ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="发送群聊名称" prop="wxRoomName">
+        <el-input
+          v-model="queryParams.wxRoomName"
+          placeholder="请输入发送群聊名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="小程序ID" prop="fsUserId">
+        <el-input
+          v-model="queryParams.fsUserId"
+          placeholder="请输入小程序ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="发送状态0待发送1发送成功2发送失败3消息作废" prop="sendStatus">
+        <el-select v-model="queryParams.sendStatus" placeholder="请选择发送状态0待发送1发送成功2发送失败3消息作废" clearable size="small">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="发送备注" prop="sendRemark">
+        <el-input
+          v-model="queryParams.sendRemark"
+          placeholder="请输入发送备注"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="发送排序" prop="sendSort">
+        <el-input
+          v-model="queryParams.sendSort"
+          placeholder="请输入发送排序"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="消息过期时间" prop="expirationTime">
+        <el-date-picker clearable size="small"
+          v-model="queryParams.expirationTime"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择消息过期时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['wx:wxSopLogs:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['wx:wxSopLogs:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['wx:wxSopLogs:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['wx:wxSopLogs:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="wxSopLogsList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="消息类型0个人1群" align="center" prop="type" />
+      <el-table-column label="任务ID" align="center" prop="sopId" />
+      <el-table-column label="营期ID" align="center" prop="sopUserId" />
+      <el-table-column label="发送类型" align="center" prop="sendType" />
+      <el-table-column label="生成类型(0自动1手动)" align="center" prop="generateType" />
+      <el-table-column label="发送账号ID" align="center" prop="accountId" />
+      <el-table-column label="发送对象ID" align="center" prop="wxContactId" />
+      <el-table-column label="发送对象名称" align="center" prop="wxContactName" />
+      <el-table-column label="发送群聊ID" align="center" prop="wxRoomId" />
+      <el-table-column label="发送群聊名称" align="center" prop="wxRoomName" />
+      <el-table-column label="小程序ID" align="center" prop="fsUserId" />
+      <el-table-column label="发送状态0待发送1发送成功2发送失败3消息作废" align="center" prop="sendStatus" />
+      <el-table-column label="发送备注" align="center" prop="sendRemark" />
+      <el-table-column label="发送排序" align="center" prop="sendSort" />
+      <el-table-column label="消息过期时间" align="center" prop="expirationTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.expirationTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['wx:wxSopLogs:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['wx:wxSopLogs:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改个微发送记录对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="消息类型0个人1群" prop="type">
+          <el-select v-model="form.type" placeholder="请选择消息类型0个人1群">
+            <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="任务ID" prop="sopId">
+          <el-input v-model="form.sopId" placeholder="请输入任务ID" />
+        </el-form-item>
+        <el-form-item label="营期ID" prop="sopUserId">
+          <el-input v-model="form.sopUserId" placeholder="请输入营期ID" />
+        </el-form-item>
+        <el-form-item label="发送类型" prop="sendType">
+          <el-select v-model="form.sendType" placeholder="请选择发送类型">
+            <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="生成类型(0自动1手动)" prop="generateType">
+          <el-select v-model="form.generateType" placeholder="请选择生成类型(0自动1手动)">
+            <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="发送账号ID" prop="accountId">
+          <el-input v-model="form.accountId" placeholder="请输入发送账号ID" />
+        </el-form-item>
+        <el-form-item label="发送对象ID" prop="wxContactId">
+          <el-input v-model="form.wxContactId" placeholder="请输入发送对象ID" />
+        </el-form-item>
+        <el-form-item label="发送对象名称" prop="wxContactName">
+          <el-input v-model="form.wxContactName" placeholder="请输入发送对象名称" />
+        </el-form-item>
+        <el-form-item label="发送群聊ID" prop="wxRoomId">
+          <el-input v-model="form.wxRoomId" placeholder="请输入发送群聊ID" />
+        </el-form-item>
+        <el-form-item label="发送群聊名称" prop="wxRoomName">
+          <el-input v-model="form.wxRoomName" placeholder="请输入发送群聊名称" />
+        </el-form-item>
+        <el-form-item label="小程序ID" prop="fsUserId">
+          <el-input v-model="form.fsUserId" placeholder="请输入小程序ID" />
+        </el-form-item>
+        <el-form-item label="发送状态0待发送1发送成功2发送失败3消息作废">
+          <el-radio-group v-model="form.sendStatus">
+            <el-radio label="1">请选择字典生成</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="发送备注" prop="sendRemark">
+          <el-input v-model="form.sendRemark" placeholder="请输入发送备注" />
+        </el-form-item>
+        <el-form-item label="发送排序" prop="sendSort">
+          <el-input v-model="form.sendSort" placeholder="请输入发送排序" />
+        </el-form-item>
+        <el-form-item label="消息过期时间" prop="expirationTime">
+          <el-date-picker clearable size="small"
+            v-model="form.expirationTime"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择消息过期时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listWxSopLogs, getWxSopLogs, delWxSopLogs, addWxSopLogs, updateWxSopLogs, exportWxSopLogs } from "@/api/wx/wxSopLogs";
+
+export default {
+  name: "WxSopLogs",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 个微发送记录表格数据
+      wxSopLogsList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        type: null,
+        sopId: null,
+        sopUserId: null,
+        sendType: null,
+        generateType: null,
+        accountId: null,
+        wxContactId: null,
+        wxContactName: null,
+        wxRoomId: null,
+        wxRoomName: null,
+        fsUserId: null,
+        sendStatus: null,
+        sendRemark: null,
+        sendSort: null,
+        expirationTime: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询个微发送记录列表 */
+    getList() {
+      this.loading = true;
+      listWxSopLogs(this.queryParams).then(response => {
+        this.wxSopLogsList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        type: null,
+        sopId: null,
+        sopUserId: null,
+        sendType: null,
+        generateType: null,
+        accountId: null,
+        wxContactId: null,
+        wxContactName: null,
+        wxRoomId: null,
+        wxRoomName: null,
+        fsUserId: null,
+        sendStatus: 0,
+        sendRemark: null,
+        sendSort: null,
+        expirationTime: null,
+        createTime: null,
+        createBy: null,
+        updateTime: null,
+        updateBy: null,
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加个微发送记录";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getWxSopLogs(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改个微发送记录";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateWxSopLogs(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addWxSopLogs(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除个微发送记录编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delWxSopLogs(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有个微发送记录数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportWxSopLogs(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 350 - 0
src/views/wx/wxSopUser/index.vue

@@ -0,0 +1,350 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="类型(0个人1群聊)" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择类型(0个人1群聊)" clearable size="small">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="任务ID" prop="sopId">
+        <el-input
+          v-model="queryParams.sopId"
+          placeholder="请输入任务ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="个微账号ID" prop="accountId">
+        <el-input
+          v-model="queryParams.accountId"
+          placeholder="请输入个微账号ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="营期时间" prop="startTime">
+        <el-date-picker clearable size="small"
+          v-model="queryParams.startTime"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择营期时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="群聊ID" prop="chatId">
+        <el-input
+          v-model="queryParams.chatId"
+          placeholder="请输入群聊ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['wx:wxSopUser:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['wx:wxSopUser:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['wx:wxSopUser:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['wx:wxSopUser:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="wxSopUserList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="类型(0个人1群聊)" align="center" prop="type" />
+      <el-table-column label="任务ID" align="center" prop="sopId" />
+      <el-table-column label="个微账号ID" align="center" prop="accountId" />
+      <el-table-column label="营期时间" align="center" prop="startTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="群聊ID" align="center" prop="chatId" />
+      <el-table-column label="状态" align="center" prop="status" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['wx:wxSopUser:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['wx:wxSopUser:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改个微营期对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="类型(0个人1群聊)" prop="type">
+          <el-select v-model="form.type" placeholder="请选择类型(0个人1群聊)">
+            <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="任务ID" prop="sopId">
+          <el-input v-model="form.sopId" placeholder="请输入任务ID" />
+        </el-form-item>
+        <el-form-item label="个微账号ID" prop="accountId">
+          <el-input v-model="form.accountId" placeholder="请输入个微账号ID" />
+        </el-form-item>
+        <el-form-item label="营期时间" prop="startTime">
+          <el-date-picker clearable size="small"
+            v-model="form.startTime"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择营期时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="群聊ID" prop="chatId">
+          <el-input v-model="form.chatId" placeholder="请输入群聊ID" />
+        </el-form-item>
+        <el-form-item label="状态">
+          <el-radio-group v-model="form.status">
+            <el-radio label="1">请选择字典生成</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listWxSopUser, getWxSopUser, delWxSopUser, addWxSopUser, updateWxSopUser, exportWxSopUser } from "@/api/wx/wxSopUser";
+
+export default {
+  name: "WxSopUser",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 个微营期表格数据
+      wxSopUserList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        type: null,
+        sopId: null,
+        accountId: null,
+        startTime: null,
+        chatId: null,
+        status: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询个微营期列表 */
+    getList() {
+      this.loading = true;
+      listWxSopUser(this.queryParams).then(response => {
+        this.wxSopUserList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        type: null,
+        sopId: null,
+        accountId: null,
+        startTime: null,
+        chatId: null,
+        status: 0,
+        createTime: null,
+        createBy: null,
+        updateTime: null,
+        updateBy: null,
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加个微营期";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getWxSopUser(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改个微营期";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateWxSopUser(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addWxSopUser(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除个微营期编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delWxSopUser(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有个微营期数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportWxSopUser(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 412 - 0
src/views/wx/wxSopUserInfo/index.vue

@@ -0,0 +1,412 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="任务ID" prop="sopId">
+        <el-input
+          v-model="queryParams.sopId"
+          placeholder="请输入任务ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="营期ID" prop="sopUserId">
+        <el-input
+          v-model="queryParams.sopUserId"
+          placeholder="请输入营期ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="联系人ID" prop="wxContactId">
+        <el-input
+          v-model="queryParams.wxContactId"
+          placeholder="请输入联系人ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="小程序ID" prop="fsUserId">
+        <el-input
+          v-model="queryParams.fsUserId"
+          placeholder="请输入小程序ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="是否7天都没有看课 0否 1是" prop="isDaysNotStudy">
+        <el-input
+          v-model="queryParams.isDaysNotStudy"
+          placeholder="请输入是否7天都没有看课 0否 1是"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="总完课天数" prop="finishCout">
+        <el-input
+          v-model="queryParams.finishCout"
+          placeholder="请输入总完课天数"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="最近完课时间" prop="finishTime">
+        <el-date-picker clearable size="small"
+          v-model="queryParams.finishTime"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择最近完课时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="连续完课天数" prop="finishCourseDays">
+        <el-input
+          v-model="queryParams.finishCourseDays"
+          placeholder="请输入连续完课天数"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="客户评级的等级" prop="grade">
+        <el-input
+          v-model="queryParams.grade"
+          placeholder="请输入客户评级的等级"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="禁用状态 0 正常 1禁用" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择禁用状态 0 正常 1禁用" clearable size="small">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['wx:wxSopUserInfo:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['wx:wxSopUserInfo:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['wx:wxSopUserInfo:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['wx:wxSopUserInfo:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="wxSopUserInfoList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="任务ID" align="center" prop="sopId" />
+      <el-table-column label="营期ID" align="center" prop="sopUserId" />
+      <el-table-column label="联系人ID" align="center" prop="wxContactId" />
+      <el-table-column label="小程序ID" align="center" prop="fsUserId" />
+      <el-table-column label="是否7天都没有看课 0否 1是" align="center" prop="isDaysNotStudy" />
+      <el-table-column label="总完课天数" align="center" prop="finishCout" />
+      <el-table-column label="最近完课时间" align="center" prop="finishTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.finishTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="连续完课天数" align="center" prop="finishCourseDays" />
+      <el-table-column label="客户评级的等级" align="center" prop="grade" />
+      <el-table-column label="禁用状态 0 正常 1禁用" align="center" prop="status" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['wx:wxSopUserInfo:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['wx:wxSopUserInfo:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改个微营期详情对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="任务ID" prop="sopId">
+          <el-input v-model="form.sopId" placeholder="请输入任务ID" />
+        </el-form-item>
+        <el-form-item label="营期ID" prop="sopUserId">
+          <el-input v-model="form.sopUserId" placeholder="请输入营期ID" />
+        </el-form-item>
+        <el-form-item label="联系人ID" prop="wxContactId">
+          <el-input v-model="form.wxContactId" placeholder="请输入联系人ID" />
+        </el-form-item>
+        <el-form-item label="小程序ID" prop="fsUserId">
+          <el-input v-model="form.fsUserId" placeholder="请输入小程序ID" />
+        </el-form-item>
+        <el-form-item label="是否7天都没有看课 0否 1是" prop="isDaysNotStudy">
+          <el-input v-model="form.isDaysNotStudy" placeholder="请输入是否7天都没有看课 0否 1是" />
+        </el-form-item>
+        <el-form-item label="总完课天数" prop="finishCout">
+          <el-input v-model="form.finishCout" placeholder="请输入总完课天数" />
+        </el-form-item>
+        <el-form-item label="最近完课时间" prop="finishTime">
+          <el-date-picker clearable size="small"
+            v-model="form.finishTime"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择最近完课时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="连续完课天数" prop="finishCourseDays">
+          <el-input v-model="form.finishCourseDays" placeholder="请输入连续完课天数" />
+        </el-form-item>
+        <el-form-item label="客户评级的等级" prop="grade">
+          <el-input v-model="form.grade" placeholder="请输入客户评级的等级" />
+        </el-form-item>
+        <el-form-item label="禁用状态 0 正常 1禁用">
+          <el-radio-group v-model="form.status">
+            <el-radio label="1">请选择字典生成</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listWxSopUserInfo, getWxSopUserInfo, delWxSopUserInfo, addWxSopUserInfo, updateWxSopUserInfo, exportWxSopUserInfo } from "@/api/wx/wxSopUserInfo";
+
+export default {
+  name: "WxSopUserInfo",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 个微营期详情表格数据
+      wxSopUserInfoList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        sopId: null,
+        sopUserId: null,
+        wxContactId: null,
+        fsUserId: null,
+        isDaysNotStudy: null,
+        finishCout: null,
+        finishTime: null,
+        finishCourseDays: null,
+        grade: null,
+        status: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询个微营期详情列表 */
+    getList() {
+      this.loading = true;
+      listWxSopUserInfo(this.queryParams).then(response => {
+        this.wxSopUserInfoList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        sopId: null,
+        sopUserId: null,
+        wxContactId: null,
+        fsUserId: null,
+        isDaysNotStudy: null,
+        finishCout: null,
+        finishTime: null,
+        finishCourseDays: null,
+        grade: null,
+        status: 0,
+        createTime: null,
+        createBy: null,
+        updateTime: null,
+        updateBy: null,
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加个微营期详情";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getWxSopUserInfo(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改个微营期详情";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateWxSopUserInfo(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addWxSopUserInfo(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除个微营期详情编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delWxSopUserInfo(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有个微营期详情数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportWxSopUserInfo(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>