duanshenglang 2 dias atrás
pai
commit
d7220d924a

BIN
lottery.zip


+ 115 - 11
lottery/WeCom.html

@@ -200,7 +200,7 @@
     color: #222222;
     line-height: 17px;
     padding-top: 10px;
-    width: 240px; /* 必须设置宽度 */
+    width: 228px; /* 必须设置宽度 */
     overflow: hidden;
     white-space: nowrap;
     text-overflow: ellipsis;
@@ -228,6 +228,7 @@
     font-size: 12px;
     color: #136DFB;
     line-height: 17px;
+    white-space: nowrap;
   }
   .client_box_title {
     display: flex;
@@ -754,7 +755,7 @@
                       <div class="task_item_left_bottom" v-else>{{item.taskDesc}}</div>
                     </div>
                     <div class="task_item_line"></div>
-                    <div class="task_item_right" @click="handleTaskDetail(item)">查看</div>
+                    <div class="task_item_right" @click="handleTaskDetail(item)">{{item.type === 'MONITORED_MESSAGE' ? '去回复' : '查看'}}</div>
                   </div>
                 </div>
                 <div class="notask_tip" v-else>暂无需要完成的任务</div>
@@ -903,11 +904,11 @@
                   <img src="./img/qw/client_mass.png" alt="">
                   <div class="task_manage_item">客户群发任务</div>
                 </div>
-                <div class="tools_box">
+                <div class="tools_box" @click="handleClientGroupMass">
                   <img src="./img/qw/group_mass.png" alt="">
                   <div class="task_manage_item">客户群群发任务</div>
                 </div>
-                <div class="tools_box">
+                <div class="tools_box" @click="handlePyqMass">
                   <img src="./img/qw/pyq_mass.png" alt="">
                   <div class="task_manage_item">朋友圈群发任务</div>
                 </div>
@@ -1005,6 +1006,7 @@
       }
       this.startTime = this.getDateTime(0)
       this.endTime = this.getDateTime(0)
+      this.getQyWxSign()
     },
     methods: {
       getAuth() {
@@ -1118,7 +1120,11 @@
         } else if (this.activeTabbar === 'client') {
           this.clientStartTime = this.formatDate(start)
           this.clientEndTime = this.formatDate(end)
-          this.pageClient()
+          if (this.activeTab === '客户') {
+            this.pageClient()
+          } else {
+            this.pageGroup()
+          }
         }
       },
       // 切换底部tabbar
@@ -1156,7 +1162,36 @@
       },
       // 任务详情
       handleTaskDetail(item) {
-        window.location.href = `qw/taskDetail.html?taskId=${item.todoTaskId}&type=${item.type}&env=${this.env}&bId=${this.bId}`
+        if (item.type === 'MONITORED_MESSAGE') {
+          if (!item.clientExternalUserId) {
+            vant.Toast.fail('无效')
+            return
+          }
+          wx.openEnterpriseChat({
+            externalUserIds: item.clientExternalUserId, // 参与会话的外部联系人列表,格式为userId1;userId2;…,用分号隔开。
+            groupName: "",  // 会话名称。单聊时该参数传入空字符串""即可。
+            chatId: "",
+            success: function (res) {
+              var chatId = res.chatId; //返回当前群聊ID,仅当使用agentConfig注入该接口权限时才返回chatId
+              // 回调
+              console.log('成功', res);
+
+            },
+            fail: function (res) {
+              // 回调
+              if (res.errMsg.indexOf('function not exist') > -1) {
+                alert('版本过低请升级');
+              }
+              console.log('失败', res);
+            },
+            complete: function (res) {
+              // 回调
+              console.log('完成', res);
+            }
+          })
+        } else {
+          window.location.href = `qw/taskDetail.html?taskId=${item.todoTaskId}&type=${item.type}&env=${this.env}&bId=${this.bId}`
+        }
       },
       handleChange(tab) {
         this.activeTab = tab
@@ -1250,17 +1285,23 @@
       },
       // 客户日期筛选
       handleClientDate(text) {
-        this.clientDate = text
-        if (text === 'today') {
+        if (this.clientDate === text) {
+          this.clientDate = ''
+          this.clientStartTime = ''
+          this.clientEndTime = ''
+        } else {   
+          this.clientDate = text 
+        }
+        if (this.clientDate === 'today') {
           this.clientStartTime = this.getDateTime(0)
           this.clientEndTime = this.getDateTime(0)
-        } else if (text === 'week') {
+        } else if (this.clientDate === 'week') {
           this.clientStartTime = this.getDateTime(-7)
           this.clientEndTime = this.getDateTime(-1)
-        } else if (text === 'month') {
+        } else if (this.clientDate === 'month') {
           this.clientStartTime = this.getDateTime(-30)
           this.clientEndTime = this.getDateTime(-1)
-        } else if (text === 'custom') {
+        } else if (this.clientDate === 'custom') {
           this.showSelfDate = true
         }
         if (this.activeTab === '客户') {
@@ -1292,6 +1333,14 @@
       handleClientMass() {
         window.location.href = `qw/clientMassList.html?bId=${this.bId}&env=${this.env}&memberId=${this.memberId}`
       },
+      // 客户群群发任务
+      handleClientGroupMass() {
+        window.location.href = `qw/clientGroupMassList.html?bId=${this.bId}&env=${this.env}&memberId=${this.memberId}`
+      },
+      // 朋友圈群发任务
+      handlePyqMass() {
+        window.location.href = `qw/pyqMassList.html?bId=${this.bId}&env=${this.env}&memberId=${this.memberId}`
+      },
       // 勾选客户变更
       onChangeChecked (value) {
         // value 为当前勾选的 name 数组(即 id 集合)
@@ -1336,6 +1385,61 @@
         }
         return tYear + '-' + tMonth + '-' + tDate
       },
+      getQyWxSign() {
+        fetch(this.httpUrl + '/scrm/v1/wxcp-corp/p/getAgentConfig', {
+          method: 'post',
+          body: JSON.stringify({
+            bid: this.bId,
+            url: window.location.href,
+          }),
+          headers: {
+            'Content-Type': 'application/json'
+          }
+        }).then(res => {
+          return res.json()
+        }).then(result => {
+          let { data, code, msg } = result
+          if (code === 1) {
+            wx.config({
+              beta: true,
+              debug: false,
+              appId: data.corpid, // 必填,企业号的唯一标识,此处填写企业号corpid
+              timestamp: data.timestamp, // 必填,生成签名的时间戳
+              nonceStr: data.nonceStr, // 必填,生成签名的随机串
+              signature: data.agentSignature, // 必填,签名,见附录1
+              jsApiList: ['checkJsApi', 'openEnterpriseChat'] // 必填,需要使用的JS接口列表
+            })
+            wx.agentConfig({
+              corpid: data.corpid,
+              agentid: data.agentId,
+              timestamp: data.timestamp, // 必填,生成签名的时间戳
+              nonceStr: data.nonceStr, // 必填,生成签名的随机串
+              signature: data.agentSignature, // 必填,签名,见附录1
+              jsApiList: ['openEnterpriseChat'], // 必填,需要使用的JS接口列表
+              success: function (res) {
+                // 回调
+                console.log('agentConfig成功', res);
+
+              },
+              fail: function (res) {
+                if (res.errMsg.indexOf('function not exist') > -1) {
+                  alert('版本过低请升级');
+                }
+              },
+              complete: function (res) {
+                // 回调
+                console.log('complete', res);
+              }
+            });
+
+          } else {
+            this.$message({
+              message: msg,
+              type: 'warning'
+            })
+          }
+        })
+      },
       // 截取url中的数据
       getQueryParam(paramName) {
         // 获取当前URL的查询字符串部分  

+ 3 - 1
lottery/js/page-return.js

@@ -22,7 +22,9 @@ var demoComponent = Vue.extend({
   },
   methods: {
     handleClickReturn() {
-      if (window.location.pathname.includes('/qw/clientMassList.html')) {
+      if (window.location.pathname.includes('/qw/clientMassList.html')
+        || window.location.pathname.includes('/qw/clientGroupMassList.html')
+        || window.location.pathname.includes('/qw/pyqMassList.html')) {  
         var currentQueryParams = window.location.search;
         window.location.replace('../WeCom.html' + currentQueryParams)
       } else {

+ 1736 - 0
lottery/qw/clientGroupMass.html

@@ -0,0 +1,1736 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport"
+    content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no, viewport-fit=cover" />
+  <title>创建客户群发</title>
+  <!-- 引入样式文件 -->
+  <link rel="stylesheet"
+    href="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012584633/vant.css" />
+  <link rel="stylesheet" href="../css/select-tag.css">
+  <link rel="stylesheet" href="../css/page-return.css">
+  <!-- 必须先引入vue,  后使用vant-ui -->
+  <script
+    src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742017957144/vue.js"></script>
+  <!-- 引入vant的组件库-->
+  <!-- 引入 Vant 的 JS 文件 -->
+  <script
+    src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012748487/vant.min.js"></script>
+
+  <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
+  <script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
+  <script src="../js/page-return.js"></script>
+  <!-- <script src="js/vconsole.min.js"></script>
+    <script>
+  		  var vConsole = new window.VConsole();
+  		</script> -->
+</head>
+<style>
+  body {
+    margin: 0;
+    padding: 0;
+  }
+
+  .box {
+    width: 100vw;
+    min-height: 100vh;
+    box-sizing: border-box;
+    background: #F7F9FC;
+  }
+
+  .page5 {
+    width: 100vw;
+    box-sizing: border-box;
+    padding-bottom: 39px;
+  }
+
+  .task_content {
+    padding: 15px 10px;
+  }
+
+  .send_item {
+    width: 100%;
+    background: #FFFFFF;
+    border-radius: 15px;
+    box-sizing: border-box;
+    padding: 15px 10px;
+    margin-bottom: 15px;
+  }
+
+
+  .client_tag {
+    font-size: 12px;
+    line-height: 17px;
+  }
+
+
+  .status1 {
+    color: #136DFB;
+  }
+
+  .status2 {
+    color: #FFA041;
+  }
+
+  .status3 {
+    color: #FF4141;
+  }
+
+  .mem_title {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+
+  .mem_title_left {
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+    padding-left: 5px;
+    position: relative;
+    display: flex;
+    align-items: center;
+  }
+
+  .mem_title_left::after {
+    position: absolute;
+    left: 0;
+    content: '';
+    width: 2px;
+    height: 12px;
+    background: #136DFB;
+    border-radius: 1px;
+  }
+
+  .mem_title_right {
+    display: flex;
+    align-items: center;
+    font-size: 12px;
+    color: #136DFB;
+    line-height: 17px;
+  }
+
+  .mem_title_right img {
+    width: 16px;
+    height: 16px;
+  }
+
+  .mem_tag_list {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    gap: 10px;
+    max-height: 52px;
+    overflow: hidden;
+  }
+
+  .mem_tag {
+    margin-top: 15px;
+  }
+
+  .mem_tag span {
+    padding: 2px 8px;
+    background: rgba(19, 109, 251, 0.05);
+    border-radius: 5px;
+    font-size: 12px;
+    line-height: 17px;
+    color: #136DFB;
+  }
+
+  .condition_mem_tag1 {
+    margin-top: 10px;
+  }
+
+  .condition_mem_tag2 {
+    margin-top: 10px;
+  }
+
+  .condition_mem_tag3 {
+    margin-top: 18px;
+  }
+
+  .condition_mem_tag1 span {
+    padding: 2px 8px;
+    background: #F2F6FC;
+    border-radius: 5px;
+    font-size: 12px;
+    line-height: 17px;
+    color: #7D97BF;
+  }
+
+  .condition_mem_tag2 span {
+    padding: 2px 8px;
+    background: #FCF7F2;
+    border-radius: 5px;
+    font-size: 12px;
+    line-height: 17px;
+    color: #BFA17D;
+  }
+
+  .condition_mem_tag3 span {
+    padding: 2px 8px;
+    background: #FCF2F2;
+    border-radius: 5px;
+    font-size: 12px;
+    line-height: 17px;
+    color: #BF7D7D;
+  }
+
+  .send_centent {
+    padding: 20px 15px;
+  }
+
+  .send_text {
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+    padding-bottom: 10px;
+  }
+
+  .send_contentText {
+    font-size: 14px;
+    line-height: 23px;
+    color: #666666;
+    padding-bottom: 20px;
+  }
+
+  .img_list {
+    display: flex;
+    flex-wrap: nowrap;
+    overflow-x: auto;
+    gap: 10px;
+    padding: 10px 5px 10px;
+  }
+
+  .img_box {
+    position: relative;
+    width: 105px;
+    height: 140px;
+  }
+
+  .close_imgMater {
+    width: 24px;
+    height: 24px;
+    position: absolute;
+    top: -8px;
+    right: -8px;
+  }
+
+  .img_url {
+    width: 105px;
+    height: 140px;
+    border-radius: 10px;
+    object-fit: cover;
+  }
+
+  .video_container {
+    position: relative;
+    width: 105px;
+    height: 140px;
+  }
+
+  .play_button {
+    width: 24px;
+    height: 24px;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+  }
+
+  .matters_item {
+    width: 163px;
+    height: 60px;
+    border-radius: 10px;
+    display: flex;
+    align-items: center;
+    padding: 10px;
+    box-sizing: border-box;
+    border: 1px solid #EFEFEF;
+    position: relative;
+  }
+
+  .matters_item_img {
+    width: 40px;
+    height: 40px;
+    margin-right: 8px;
+  }
+
+  .close_mater {
+    width: 24px;
+    height: 24px;
+    position: absolute;
+    top: -8px;
+    right: -8px;
+  }
+
+  .matters_item_info {
+    display: flex;
+    flex-direction: column;
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .matters_item_title {
+    font-size: 12px;
+    color: #222222;
+    line-height: 17px;
+    width: 96px;
+    /* 必须设置宽度 */
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    padding-bottom: 4px;
+  }
+
+  .matters_list {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px;
+  }
+
+  .mem_centent {
+    padding: 10px 15px;
+  }
+
+  .filter_list {
+    display: flex;
+    flex-wrap: nowrap;
+    white-space: nowrap;
+    width: 100%;
+    overflow-x: auto;
+    gap: 10px;
+  }
+
+  .filter_span {
+    height: 25px;
+    box-sizing: border-box;
+    font-size: 12px;
+    color: #999999;
+    padding: 4px 12px;
+    background: #FAFAFA;
+    border-radius: 10px;
+  }
+
+  .active {
+    height: 25px;
+    box-sizing: border-box;
+    font-size: 12px;
+    color: #1677FF;
+    background: rgba(22, 119, 255, 0.1);
+    padding: 4px 12px;
+    border-radius: 10px;
+  }
+
+  .send_num_data {
+    display: flex;
+    align-items: center;
+    padding: 15px 5px 10px;
+    font-size: 12px;
+    color: #222222;
+    line-height: 17px;
+  }
+
+  .color1 {
+    color: #1677FF;
+    padding-right: 20px;
+  }
+
+  .color2 {
+    color: #FFA041;
+    padding-right: 20px;
+  }
+
+  .color3 {
+    color: #FF4E4E;
+    padding-right: 20px;
+  }
+
+  .color4 {
+    color: #7D97BF;
+    padding-right: 20px;
+  }
+
+  .send_mem_item {
+    height: 100px;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    padding: 15px;
+    background: #FAFAFA;
+    border-radius: 15px;
+    box-sizing: border-box;
+    margin-bottom: 10px;
+  }
+
+  .send_mem_name {
+    font-weight: 500;
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+  }
+
+  .send_mem_data {
+    display: flex;
+    align-items: center;
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .send_mem_time {
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .van-cell {
+    padding: 15px 5px 0;
+  }
+
+  .matter_btn_box {
+    padding: 20px 0 10px;
+  }
+
+  .cond_btn_box {
+    padding-top: 15px;
+  }
+
+  .matter_btn {
+    height: 50px;
+    padding: 15px 0;
+    background: rgba(19, 109, 251, 0.1);
+    border-radius: 20px;
+    font-weight: 500;
+    font-size: 14px;
+    color: #136DFB;
+    text-align: center;
+    box-sizing: border-box;
+  }
+
+  .send_btn_box {
+    padding: 15px 25px 10px;
+  }
+
+  .send_btn {
+    height: 50px;
+    padding: 15px 0;
+    background: #1677FF;
+    border-radius: 20px;
+    font-weight: 500;
+    font-size: 14px;
+    color: #FFFFFF;
+    text-align: center;
+    box-sizing: border-box;
+  }
+
+  textarea {
+    height: 68px !important;
+    line-height: 23px;
+  }
+
+  .van-radio__icon {
+    width: 16px;
+    height: 16px;
+  }
+
+  .van-radio__label {
+    font-size: 14px;
+    line-height: 20px;
+    color: #222222;
+  }
+
+  .van-radio--horizontal {
+    margin-right: 40px;
+  }
+
+  .van-radio-group {
+    margin-top: 15px;
+  }
+
+  .check_div {
+    width: 16px;
+    height: 16px;
+    border-radius: 50%;
+    border: 1px solid #CCCCCC;
+    box-sizing: border-box;
+    margin-right: 8px;
+  }
+
+  .check_div_active {
+    width: 16px;
+    height: 16px;
+    border-radius: 50%;
+    border: 1px solid #136DFB;
+    box-sizing: border-box;
+    margin-right: 8px;
+  }
+
+  .check_div_active:after {
+    content: "";
+    display: block;
+    width: 10px;
+    height: 10px;
+    border-radius: 50%;
+    background: #136DFB;
+    position: relative;
+    top: 2px;
+    left: 2px;
+  }
+
+  .send_item_name {
+    font-size: 14px;
+    line-height: 20px;
+    color: #666666;
+    padding-top: 20px;
+  }
+
+  .data_item {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 20px 20px 10px;
+  }
+
+  .data_title {
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+    display: -webkit-box;
+    -webkit-line-clamp: 2;
+    -webkit-box-orient: vertical;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  .condition_box1 {
+    padding: 15px;
+    background: rgba(245, 249, 255, 0.5);
+    border-radius: 10px;
+    border: 1px solid #E2EAFF;
+    box-sizing: border-box;
+    margin-bottom: 10px;
+  }
+
+  .condition_box2 {
+    padding: 15px;
+    background: rgba(255, 252, 245, 0.5);
+    border-radius: 10px;
+    border: 1px solid #FFF5E2;
+    box-sizing: border-box;
+    margin-bottom: 10px;
+  }
+
+  .condition_box3 {
+    padding: 15px;
+    background: rgba(255, 245, 245, 0.5);
+    border-radius: 10px;
+    border: 1px solid #FFE2E2;
+    box-sizing: border-box;
+  }
+
+  .con_data {
+    display: flex;
+    align-items: center;
+  }
+
+  .con_data_title {
+    font-weight: 500;
+    font-size: 12px;
+    color: #222222;
+    padding-right: 24px;
+  }
+
+  .con_data_edit {
+    font-size: 12px;
+    color: #136DFB;
+    padding-right: 15px;
+  }
+
+  .con_data_del {
+    font-size: 12px;
+    color: #FF4141;
+  }
+
+  .tag_radio {
+    margin-top: 10px;
+  }
+
+  .tag_radio_item {
+    margin-right: 32px;
+  }
+
+  .condition_list {
+    margin-top: 15px;
+  }
+
+  .exc_title {
+    padding-right: 24px;
+  }
+
+  .filter_list {
+    height: 146px;
+    display: flex;
+    align-items: center;
+    gap: 15px;
+  }
+
+  .filter_or {
+    font-weight: 500;
+    font-size: 16px;
+    color: #FFA041;
+    width: 100%;
+    text-align: center;
+    background: rgba(255, 160, 65, 0.05);
+    padding: 49px 0 48px;
+    border-radius: 15px;
+  }
+
+  .filter_exc_active {
+    font-weight: 500;
+    font-size: 16px;
+    color: #FF4141;
+    width: 100%;
+    text-align: center;
+    padding: 49px 0 48px;
+    background: rgba(255, 65, 65, 0.05);
+    border-radius: 15px;
+  }
+
+  .filter_exc {
+    font-weight: 500;
+    font-size: 16px;
+    color: #999999;
+    width: 100%;
+    text-align: center;
+    padding: 49px 0 48px;
+    background: #FAFAFA;
+    border-radius: 15px;
+  }
+
+  .dev_left {
+    margin-left: 15px;
+  }
+
+  .dev_right {
+    margin-right: 15px;
+  }
+
+  .page_box {
+    padding: 15px 15px 0;
+    height: 446px;
+    box-sizing: border-box;
+  }
+
+  .path_list {
+    display: flex;
+    align-items: center;
+    flex-wrap: nowrap;
+    white-space: nowrap;
+    width: 100%;
+    overflow-x: auto;
+    margin-bottom: 25px;
+    height: 17px;
+  }
+
+  .path_span {
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .path_line {
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+    padding: 0 10px;
+  }
+
+  .path_item:last-child {
+    color: #222222;
+  }
+
+  .data_list {
+    height: 404px;
+    gap: 25px;
+    overflow-y: auto;
+  }
+
+  .mem_item {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-bottom: 20px;
+  }
+
+  .mem_item img {
+    width: 40px;
+    height: 40px;
+    margin-right: 10px;
+  }
+
+  .mem_title {
+    width: 224px;
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+    width: 238px;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  .dept_item {
+    display: flex;
+    align-items: center;
+  }
+
+  .time_list {
+    overflow-y: auto;
+    padding: 10px 20px 29px;
+    box-sizing: border-box;
+  }
+
+  .time_box {
+    height: 50px;
+    box-sizing: border-box;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 15px;
+    border-radius: 15px;
+    border: 1px solid #F1F1F1;
+  }
+
+  .time_box img {
+    width: 16px;
+    height: 16px;
+  }
+
+  .date_box {
+    height: 210px;
+    box-sizing: border-box;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    border-radius: 15px;
+    border: 1px solid #F1F1F1;
+  }
+
+  .date_box .van-ellipsis {
+    /* width: 100px; */
+    width: 102px;
+    text-align: center;
+    font-size: 14px;
+    color: #222222;
+    white-space: wrap;
+  }
+
+  .time_date {
+    display: flex;
+    align-items: center;
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+  }
+
+  .time_date_center {
+    padding: 0 10px;
+  }
+
+  .date_select {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-top: 20px;
+  }
+
+  .select_time {
+    width: 76px;
+    height: 37px;
+    line-height: 37px;
+    background: #FAFAFA;
+    border-radius: 10px;
+    font-size: 12px;
+    color: #222222;
+    text-align: center;
+  }
+
+  .select_time_ac {
+    width: 76px;
+    height: 37px;
+    line-height: 37px;
+    background: rgba(19, 109, 251, 0.05);
+    border-radius: 10px;
+    border: 1px solid #136DFB;
+    font-size: 12px;
+    color: #136DFB;
+    text-align: center;
+    box-sizing: border-box;
+  }
+
+  .now_date {
+    display: flex;
+    align-items: center;
+    font-weight: 500;
+    font-size: 16px;
+    color: #222222;
+    padding: 12px 20px;
+    background: #FAFAFA;
+    border-radius: 15px;
+    justify-content: space-between;
+    margin-top: 20px;
+  }
+</style>
+
+<body>
+  <div id="box" class="box">
+    <div class="page5">
+      <van-dialog v-model="showReturn" title="提示" show-cancel-button :before-close="beforeClose"
+        confirm-button-text="确定" cancel-button-text="取消">
+        <div style="padding: 20px; text-align: center;">确认返回吗?</div>
+      </van-dialog>
+      <!-- 选择群发时间 -->
+      <van-popup v-model="showTime" duration="0.2" round position="bottom" :close-on-click-overlay="false"
+        :style="{ width: '100%', height: showDateColumns ? '426px' : '266px' }">
+        <div class="clientTag_title">
+          <div class="close_icon"></div>
+          <div>选择时间</div>
+          <img class="close_icon" src="../img/qw/close_icon.png" alt="" @click="showTime = false" />
+        </div>
+        <div class="time_list" :style="{ height: showDateColumns ? '306px' : '146px' }">
+          <div class="date_box" v-if="showDateColumns">
+            <van-picker ref="vanPicker" :columns="dateColumns" @change="handleChangeDate" visible-item-count="4" />
+          </div>
+          <div class="time_box" @click="handleShowDateColumns" v-else>
+            <div class="close_icon"></div>
+            <div class="time_date">
+              <span>{{nowDate[0]}}</span>
+              <span class="time_date_center">{{nowDate[1]}}</span>
+              <span>{{nowDate[2]}}</span>
+            </div>
+            <img src="../img/qw/select_icon.png" alt="" @click="showTime = false">
+          </div>
+          <div class="date_select">
+            <span :class="dateIndex === 'hour' ? 'select_time_ac' : 'select_time'"
+              @click="getTimeInfo('hour')">一小时后</span>
+            <span :class="dateIndex === 'day' ? 'select_time_ac' : 'select_time'" @click="getTimeInfo('day')">一天后</span>
+            <span :class="dateIndex === 'week' ? 'select_time_ac' : 'select_time'"
+              @click="getTimeInfo('week')">一周后</span>
+            <span :class="dateIndex === 'month' ? 'select_time_ac' : 'select_time'"
+              @click="getTimeInfo('month')">一个月后</span>
+          </div>
+        </div>
+        <div class="tag_footers">
+          <div class="tag_re_btn" @click="showTime = false">取消</div>
+          <div class="tag_ok_btn" @click="handleTime">保存</div>
+        </div>
+      </van-popup>
+      <!-- 成员数据 -->
+      <van-popup v-model="showMem" duration="0.2" round position="bottom" :close-on-click-overlay="false"
+        :style="{ width: '100%', height: '566px' }">
+        <div class="clientTag_title">
+          <div class="close_icon"></div>
+          <div>添加成员</div>
+          <img class="close_icon" src="../img/qw/close_icon.png" alt="" @click="handleCancelMem">
+        </div>
+        <div class="page_box">
+          <div class="path_list">
+            <div class="path_span">
+              <span @click="getTreeData(0)">全部</span>
+              <span class="path_item" v-for="(item, index) in pathList" :key="index" @click="handlePathClick(item)">
+                <span class="path_line">/</span>{{item.text}}</span>
+            </div>
+          </div>
+          <div class="data_list">
+            <!-- 部门 -->
+            <div class="mem_item" v-for="item in treeData" :key="item.id">
+              <div class="dept_item" @click="handleDeptClick(item)">
+                <img src="../img/qw/dept_icon.png" alt="" />
+                <div class="mem_title">{{item.text}}</div>
+              </div>
+            </div>
+            <!-- 成员 -->
+            <van-checkbox-group v-model="checkedMemIds" @change="onChangeMem">
+              <div class="mem_item" v-for="item in itemList" :key="item.memberId">
+                <div class="dept_item">
+                  <img src="../img/qw/mem_icon.png" alt="" />
+                  <div class="mem_title">{{item.name}}</div>
+                </div>
+                <van-checkbox :name="item.memberId">
+                  <template #icon="props">
+                    <div :class="props.checked ? 'check_div_active' : 'check_div'"></div>
+                  </template>
+                </van-checkbox>
+              </div>
+            </van-checkbox-group>
+          </div>
+        </div>
+        <div class="tag_footer">
+          <div class="tag_re_btn" @click="handleCancelMem">取消</div>
+          <div class="tag_ok_btn" @click="handleMem">保存</div>
+        </div>
+      </van-popup>
+      <div class="task_content">
+        <div class="send_item">
+          <div class="mem_title_left">群发任务名称</div>
+          <van-field v-model="formValidate.name" maxlength="20" show-word-limit placeholder="请输入群发任务名称" />
+        </div>
+        <div class="send_item">
+          <div class="mem_title_left">发送群主账号</div>
+          <div class="mem_tag mem_tag_list">
+            <span v-for="(item, index) in SelectWachAuthor" :key="index">{{item.name}}</span>
+          </div>
+          <div class="matter_btn_box">
+            <div class="matter_btn" @click="handleAddMem">{{SelectWachAuthor.length ? '编辑' : '添加'}}成员</div>
+          </div>
+        </div>
+        <div class="send_item">
+          <div class="mem_title_left">发送内容</div>
+          <van-field v-model="formValidate.contentText" maxlength="500" show-word-limit type="textarea"
+            placeholder="请输入要发送给客户的文本" />
+        </div>
+        <div class="send_item">
+          <div class="mem_title_left">素材</div>
+          <van-radio-group class="tag_radio" v-model="materialType" direction="horizontal">
+            <van-radio :name="1">
+              素材库选择
+              <template #icon="props">
+                <div :class="props.checked ? 'check_div_active' : 'check_div'"></div>
+              </template>
+            </van-radio>
+            <!-- <van-radio :name="2">
+              自定义上传
+              <template #icon="props">
+                <div :class="props.checked ? 'check_div_active' : 'check_div'"></div>
+              </template>
+            </van-radio> -->
+          </van-radio-group>
+          <template v-if="formValidate.ctOthers && formValidate.ctOthers.length > 0">
+            <div class="img_list" v-if="formValidate.ctOthers[0].matterType === 1">
+              <div class="img_box" v-for="(item, index) in formValidate.ctOthers" :key="index">
+                <img class="img_url" :src="item.url" alt="">
+                <img class="close_imgMater" src="../img/qw/close_img.png" alt="" @click="handleCloseMatter(item)">
+              </div>
+            </div>
+            <div class="video_container" v-if="formValidate.ctOthers[0].matterType === 2">
+              <video id="myVideo" style="width: 105px; height: 140px;"
+                :src="formValidate.ctOthers[0].videoPath"></video>
+              <img id="playButton" class="play_button" src="../img/qw/play_icon.png" alt="" @click="playPause">
+            </div>
+            <div class="matters_item" v-if="formValidate.ctOthers[0].matterType === 5">
+              <img class="matters_item_img" src="../img/qw/link.png" alt="">
+              <div class="matters_item_info">
+                <div class="matters_item_title">{{formValidate.ctOthers[0].linkTitle}}</div>
+                <div>自定义链接</div>
+              </div>
+              <img class="close_mater" src="../img/qw/close_mater.png" alt="" @click="handleCloseMatter(item)">
+            </div>
+          </template>
+          <template v-if="formValidate.matters && formValidate.matters.length > 0">
+            <div class="img_list" v-if="matterImgList.length > 0">
+              <div class="img_box" v-for="(item, index) in matterImgList" :key="index">
+                <img class="img_url" :src="item.url" alt="">
+                <img class="close_imgMater" src="../img/qw/close_img.png" alt="" @click="handleCloseMatter(item)">
+              </div>
+            </div>
+            <div class="matters_list">
+              <div class="matters_item" v-for="(item, index) in matterOthersList" :key="index">
+                <img class="matters_item_img" v-if="item.contentType === 0" src="../img/qw/article.png" alt="">
+                <img class="matters_item_img" v-else-if="item.contentType === 2" src="../img/qw/form.png" alt="">
+                <img class="matters_item_img" v-else-if="item.contentType === 3" src="../img/qw/file.png" alt="">
+                <img class="matters_item_img" v-else src="../img/qw/link.png" alt="">
+                <div class="matters_item_info">
+                  <div class="matters_item_title">{{item.title}}</div>
+                  <div>{{matterTypeList.find(type => type.contentType === item.contentType)?.name || '未知类型'}}</div>
+                </div>
+                <img class="close_mater" src="../img/qw/close_mater.png" alt="" @click="handleCloseMatter(item)">
+              </div>
+            </div>
+          </template>
+          <div class="matter_btn_box">
+            <div class="matter_btn" @click="handleAddMatter">添加素材</div>
+          </div>
+        </div>
+        <div class="send_item">
+          <div class="mem_title_left">群发时间</div>
+          <van-radio-group class="tag_radio" v-model="formValidate.type" direction="horizontal"
+            @change="handleRadioType">
+            <van-radio :name="1">
+              立即群发
+              <template #icon="props">
+                <div :class="props.checked ? 'check_div_active' : 'check_div'"></div>
+              </template>
+            </van-radio>
+            <van-radio :name="2">
+              定时转发
+              <template #icon="props">
+                <div :class="props.checked ? 'check_div_active' : 'check_div'"></div>
+              </template>
+            </van-radio>
+          </van-radio-group>
+          <div class="now_date" v-if="showDateTime.length > 0" @click="showTime = true">
+            <span>{{showDateTime[0]}}</span>
+            <span>{{showDateTime[1]}}</span>
+            <span>{{showDateTime[2]}}</span>
+          </div>
+        </div>
+        <div class="send_btn_box">
+          <div class="send_btn" @click="sendMass">一键群发</div>
+        </div>
+      </div>
+    </div>
+    <!-- 底部返回栏 -->
+    <page-return></page-return>
+  </div>
+</body>
+<script>
+  new Vue({
+    el: '#box',
+    data() {
+      return {
+        httpUrl: '',
+        bId: null,
+        env: '',
+        memberId: null,
+        tenancyId: null,
+        token: null,
+        userId: null,
+        showReturn: false,
+        isConfirmingBack: false, // 标记是否已确认返回
+        pushStateCount: 0, // 记录 pushState 的次数
+        initialHistoryLength: 0, // 记录初始历史记录长度
+        materialType: 1,
+        formValidate: {
+          name: '',
+          contentText: '',
+          memberIds: [],
+          ctOthers: [],
+          matters: [],
+          type: 1,
+          sendTime: '',
+        },
+        matterImgList: [],
+        matterOthersList: [],
+        matterTypeList: [
+          { contentType: 0, name: '文章' },
+          { contentType: 2, name: '表单' },
+          { contentType: 3, name: '文件' },
+          { contentType: 4, name: '外部链接' },
+          { contentType: 15, name: '视频' },
+          { contentType: 17, name: '图集链接' },
+        ],
+
+        showMem: false,
+        checkedMemIds: [], // 选中的成员id
+        memList: [], // 成员列表
+        SelectMem: [], // 选中的成员
+        treeData: [], // 总部门树数据
+        selectedMems: [], // 选中的所有成员数据
+        itemList: [], // 当前树下的数据
+        pathList: [], // 当前路径
+        SelectWachAuthor: [], // 选好的微信成员
+        showTime: false,
+        dateIndex: 'hour',
+        showDateColumns: false,
+        dateColumns: [],
+        nowDate: [], // 当前选中的日期
+        NewDate: '', // 最终的日期
+        showDateTime: [], // 外面展示的日期格式
+      }
+    },
+    mounted() {
+      // 监听浏览器返回按钮
+      if (window.history && window.history.pushState) {
+        // 记录初始历史记录长度
+        this.initialHistoryLength = window.history.length;
+        history.pushState(null, null, document.URL);
+        this.pushStateCount = 1; // 记录初始 pushState
+        window.addEventListener('popstate', this.handleBack, false);
+      }
+
+      // 监听微信/企业微信返回按钮
+      if (typeof wx !== 'undefined' && wx.ready) {
+        wx.ready(() => {
+          wx.hideOptionMenu();
+        });
+      }
+      if (typeof ww !== 'undefined' && ww.ready) {
+        ww.ready(() => {
+          ww.hideOptionMenu();
+        });
+      }
+    },
+    beforeDestroy() {
+      // 移除事件监听
+      window.removeEventListener('popstate', this.handleBack, false);
+    },
+    created() {
+      this.bId = this.getQueryParam('bId')
+      this.env = this.getQueryParam('env')
+
+      if (!this.env || this.env === 'prod') {
+        this.httpUrl = 'https://wlapi.wefanbot.com'
+      } else {
+        this.httpUrl = 'http://test.wefanbot.com:18993'
+      }
+      this.memberId = this.getQueryParam('memberId')
+      this.token = localStorage.getItem('tokenValue')
+      this.tenancyId = localStorage.getItem('tenancyIdValue')
+      this.userId = localStorage.getItem('userId')
+      this.formValidate = localStorage.getItem('clientMassData') ? JSON.parse(localStorage.getItem('clientMassData')) : {
+        name: '',
+        contentText: '',
+        memberIds: [],
+        ctOthers: [],
+        matters: [],
+        type: 1,
+      }
+      this.SelectWachAuthor = localStorage.getItem('selectedMems') ? JSON.parse(localStorage.getItem('selectedMems')) : []
+      this.formValidate.matters = JSON.parse(localStorage.getItem('selectedMaters')) || []
+      if (this.formValidate.matters && this.formValidate.matters.length > 0) {
+        this.formValidate.matters.forEach(item => {
+          if (item.contentType === 19) {
+            this.matterImgList.push(item)
+          } else {
+            this.matterOthersList.push(item)
+          }
+        })
+      }
+    },
+    methods: {
+      handleBack(e) {
+        // 如果已经确认返回,直接返回,不显示弹框
+        if (this.isConfirmingBack) {
+          return;
+        }
+
+        // 如果弹框已经显示,阻止默认返回行为,但不重复显示弹框
+        if (this.showReturn) {
+          // 阻止返回,重新添加历史记录
+          if (window.history && window.history.pushState) {
+            history.pushState(null, null, document.URL);
+            this.pushStateCount++;
+          }
+          return;
+        }
+
+        // 阻止默认返回行为
+        if (window.history && window.history.pushState) {
+          history.pushState(null, null, document.URL);
+          this.pushStateCount++;
+        }
+
+        // 显示确认弹框
+        this.showReturn = true;
+      },
+      beforeClose(action, done) {
+        if (action === 'confirm') {
+          // 点击确定,设置确认返回标志
+          this.isConfirmingBack = true;
+          // 清理数据
+          localStorage.removeItem('selectedMaters');
+          localStorage.removeItem('selectedMems');
+          localStorage.removeItem('clientMassData');
+          // 移除事件监听,避免触发弹框
+          window.removeEventListener('popstate', this.handleBack, false);
+          // 关闭弹框
+          done();
+          // 直接跳转到 WeCom.html 页面
+          setTimeout(() => {
+            // 获取当前 URL 的查询参数,保留必要的参数
+            const params = new URLSearchParams(window.location.search);
+            const memberId = params.get('memberId') || this.memberId;
+            const bId = params.get('bId') || this.bId;
+            const env = params.get('env') || this.env;
+
+            // 构建跳转 URL
+            let targetUrl = 'clientGroupMassList.html';
+            if (memberId || bId || env) {
+              const queryParams = [];
+              if (memberId) queryParams.push(`memberId=${memberId}`);
+              if (bId) queryParams.push(`bId=${bId}`);
+              if (env) queryParams.push(`env=${env}`);
+              if (queryParams.length > 0) {
+                targetUrl += '?' + queryParams.join('&');
+              }
+            }
+
+            window.location.href = targetUrl;
+          }, 150);
+        } else {
+          // 点击取消,关闭弹框,重新添加历史记录防止返回
+          done();
+          if (window.history && window.history.pushState) {
+            history.pushState(null, null, document.URL);
+            this.pushStateCount++;
+          }
+        }
+      },
+      // 打开成员选择
+      handleAddMem() {
+        this.showMem = true
+        this.getTreeData(0)
+      },
+      // 获取树数据
+      getTreeData(id) {
+        this.treeData = []
+        if (id === 0) {
+          this.pathList = []
+          this.itemList = []
+        }
+        const headers = new Headers()
+        headers.append('tenancyId', this.tenancyId)
+        headers.append('token', this.token)
+        headers.append('userId', this.userId)
+        fetch(this.httpUrl + `/scrm/v1/wxcp-dept/m/findByParentId?parentId=${id}`, {
+          method: 'GET',
+          headers: headers
+        }).then(res => {
+          return res.json()
+        }).then(result => {
+          let { data, code, msg } = result
+          if (code === 1) {
+            this.treeData = data || []
+          } else {
+            vant.Toast.fail(msg)
+          }
+        })
+      },
+      // 点击树路径
+      handlePathClick(item) {
+        // 找到目标元素的索引
+        const index = this.pathList.findIndex(arr => arr.id === item.id)
+        // 如果找到了该元素
+        if (index !== -1) {
+          // 从该索引位置开始删除到数组末尾
+          this.pathList.splice(index)
+          this.handleDeptClick(item)
+        }
+      },
+      //点击部门
+      handleDeptClick(item) {
+        this.pathList.push(item)
+        this.treeData = []
+        this.itemList = []
+        this.getTreeData(item.id)
+        fetch(this.httpUrl + '/scrm/v1/wxcp-dept/m/findActiveDeptMemberListByPage', {
+          method: 'post',
+          body: JSON.stringify({
+            deptId: item.id,
+            page: 1,
+            pageCount: 1000,
+          }),
+          headers: {
+            'Content-Type': 'application/json',
+            'tenancyId': this.tenancyId,
+            'token': this.token,
+            'userId': this.userId,
+          }
+        }).then(res => {
+          return res.json()
+        }).then(result => {
+          let { data, code, msg } = result
+          if (code === 1) {
+            this.itemList = data.records || []
+            if (this.itemList.length > 0) {
+              // 回显已选择的数据
+              this.checkedMemIds = this.extractSameIds(this.itemList, this.selectedMems)
+            }
+          } else {
+            vant.Toast.fail(msg)
+          }
+        })
+      },
+      extractSameIds(itemList, selectedMems) {
+        const arr2Ids = new Set(selectedMems.map(item => item.memberId))
+        return itemList.filter(item => arr2Ids.has(item.memberId))
+          .map(item => item.memberId)
+      },
+      // 成员选择改变
+      onChangeMem(item) {
+        const currentSelected = this.itemList
+          .filter(item => this.checkedMemIds.includes(item.memberId))
+          .map(item => ({
+            ...item,
+          }))
+
+        // 先删除当前页面未选中的数据
+        const currentPageIds = new Set(this.itemList.map(item => item.memberId))
+        this.selectedMems = this.selectedMems.filter(item => {
+          // 如果是当前页面的数据,但未选中,则删除
+          if (currentPageIds.has(item.memberId)) {
+            return this.checkedMemIds.includes(item.memberId)
+          }
+          // 如果不是当前页面的数据,保留
+          return true
+        })
+
+        // 合并当前选中的和之前选中的,基于 id 去重(当前选中的优先,使用最新的类型)
+        const existingIdsMap = new Map()
+        this.selectedMems.forEach(item => {
+          existingIdsMap.set(item.memberId, item)
+        })
+
+        // 更新或添加当前选中的数据(优先使用当前页面的数据和类型)
+        currentSelected.forEach(item => {
+          existingIdsMap.set(item.memberId, item)
+        })
+
+        this.selectedMems = Array.from(existingIdsMap.values())
+
+        console.log('当前选中的所有成员数据: ', this.selectedMems)
+        localStorage.setItem('selectedMems', JSON.stringify(this.selectedMems))
+      },
+      // 取消成员选择
+      handleCancelMem() {
+        this.showMem = false
+        this.selectedMems = this.SelectWachAuthor
+        localStorage.setItem('selectedMems', JSON.stringify(this.selectedMems))
+      },
+      // 确定成员选择
+      handleMem() {
+        let selectData = this.selectedMems.map((item) => {
+          return {
+            name: item.name,
+            memberId: item.memberId,
+          }
+        })
+        const strings = selectData.map((item) => JSON.stringify(item))
+        this.SelectWachAuthor = [...new Set(strings)].map((item) => JSON.parse(item))
+        this.formValidate.memberIds = [...new Set(this.selectedMems)].map((item) => item.memberId)
+        this.formValidate.memberIds = Array.from(new Set(this.formValidate.memberIds))
+        console.log('最终成员选择: ', this.formValidate.memberIds)
+        this.showMem = false
+      },
+      handleRadioType(val) {
+        if (val === 2) {
+          this.showTime = true
+          if (!this.nowDate.length) {
+            this.getTimeInfo('hour')
+          }
+          this.dateColumns = [
+            {
+              values: this.generateDateArray(),
+            },
+            {
+              values: this.generateHourArrayEnhanced(),
+            },
+            {
+              values: this.generateMinuteArrayWithLoop(),
+            }
+          ]
+        } else {
+
+        }
+      },
+      // 生成日期数组第一组数据
+      generateDateArray() {
+        const result = [];
+        const today = new Date();
+
+        // 星期映射
+        const weekDays = ['日', '一', '二', '三', '四', '五', '六'];
+
+        // 前三天特殊处理
+        const dayNames = ['今天', '明天', '后天'];
+
+        for (let i = 0; i < 365; i++) {
+          const currentDate = new Date(today);
+          currentDate.setDate(today.getDate() + i);
+
+          const year = currentDate.getFullYear();
+          const month = currentDate.getMonth() + 1;
+          const date = currentDate.getDate();
+          const day = currentDate.getDay();
+
+          // 获取星期几的中文
+          const weekDay = `周${weekDays[day]}`;
+
+          if (i < 3) {
+            // 前三天用特殊格式
+            result.push(`${dayNames[i]} ${weekDay}`);
+          } else {
+            // 从第四天开始用正常日期格式
+            // 年份只显示后两位
+            const shortYear = year.toString().slice(-2);
+            result.push(`${shortYear}年${month}月${date}日 ${weekDay}`);
+          }
+        }
+
+        return result;
+      },
+      // 生成小时数组
+      generateHourArrayEnhanced() {
+        const now = new Date();
+        const currentHour = now.getHours(); // 获取当前小时(0-23)
+        const currentMinute = now.getMinutes(); // 获取当前分钟(0-59)
+        const result = [];
+
+        // 计算开始小时:如果当前分钟≥55,从下一小时开始
+        let startHour = currentHour;
+        if (currentMinute >= 55) {
+          startHour = currentHour + 1;
+        }
+
+        // 如果开始小时大于23,返回空数组(因为已经超过今天的小时范围)
+        if (startHour > 23) {
+          return [];
+        }
+
+        // 从开始小时到23时
+        for (let hour = startHour; hour <= 23; hour++) {
+          result.push(`${hour}时`);
+        }
+
+        return result;
+      },
+      // 生成分钟数组,从当前分钟开始,循环到59分
+      generateMinuteArrayWithLoop() {
+        const now = new Date();
+        const currentMinute = now.getMinutes(); // 获取当前分钟(0-59)
+        const startMinute = (currentMinute + 5) % 60; // 计算开始分钟,如果超过59则从0开始
+
+        const result = [];
+
+        // 从开始分钟到59分
+        for (let minute = startMinute; minute <= 59; minute++) {
+          result.push(`${minute}分`);
+        }
+
+        return result;
+      },
+      handleChangeDate(values, index) {
+        if (index[0].substring(0, 2) === '今天') {
+          this.dateColumns[1].values = this.generateHourArrayEnhanced()
+          index[1] = this.dateColumns[1].values[0]
+          this.dateColumns[2].values = this.generateMinuteArrayWithLoop()
+          index[2] = this.dateColumns[2].values[0]
+        } else {
+          this.dateColumns[1].values = Array.from({ length: 24 }, (_, i) => `${i}时`)
+          this.dateColumns[2].values = Array.from({ length: 60 }, (_, i) => `${i}分`)
+        }
+        this.dateIndex = ''
+        this.NewDate = this.convertArrayToDateTime(index)
+      },
+      // 将那4个选项转为相应的数据
+      getTimeInfo(interval) {
+        const weekDays = ['日', '一', '二', '三', '四', '五', '六'];
+        const now = new Date();
+        const result = new Date(now);
+
+        // 时间间隔映射
+        const intervals = {
+          'hour': () => result.setHours(result.getHours() + 1, result.getMinutes() + 5),
+          'day': () => result.setDate(result.getDate() + 1),
+          'week': () => result.setDate(result.getDate() + 7),
+          'month': () => result.setMonth(result.getMonth() + 1)
+        };
+
+        // 应用时间间隔
+        intervals[interval]?.();
+        if (interval !== 'hour') result.setMinutes(result.getMinutes() + 5);
+
+        // 将秒数设置为0(确保格式化为 "00" 秒)
+        result.setSeconds(0, 0);
+
+        // 格式化为 "2026-01-01 00:00:00" 格式
+        const year = result.getFullYear();
+        const month = String(result.getMonth() + 1).padStart(2, '0');
+        const day = String(result.getDate()).padStart(2, '0');
+        const hours = String(result.getHours()).padStart(2, '0');
+        const minutes = String(result.getMinutes()).padStart(2, '0');
+
+        // 赋值给 NewDate 变量
+        this.NewDate = `${year}-${month}-${day} ${hours}:${minutes}:00`;
+        // 格式化(原有逻辑保持不变)
+        const dayOfWeek = weekDays[result.getDay()];
+        const time = `${hours}:${minutes}`;
+
+        // 日期描述
+        let dateDesc = '';
+        if (interval === 'hour') {
+          const isSameDay = now.toDateString() === result.toDateString();
+          dateDesc = isSameDay ? '今天' : '明天';
+        } else if (interval === 'day') {
+          dateDesc = '明天';
+        } else {
+          dateDesc = `${result.getMonth() + 1}月${result.getDate()}日`;
+        }
+
+        this.dateIndex = interval;
+        this.nowDate = [dateDesc, `周${dayOfWeek}`, time];
+        this.showDateColumns = false;
+      },
+      // 将选择的日期时间数组转换为标准格式
+      convertArrayToDateTime(arr) {
+        // 获取当前日期和时间
+        const now = new Date();
+        const currentYear = now.getFullYear();
+        const currentMonth = now.getMonth() + 1;
+        const currentDate = now.getDate();
+
+        let targetDate;
+        const firstPart = arr[0];
+
+        // 解析小时和分钟
+        const hourStr = arr[1].replace('时', '');
+        const minuteStr = arr[2].replace('分', '');
+        const hour = parseInt(hourStr);
+        const minute = parseInt(minuteStr);
+
+        // 判断是哪种情况
+        if (firstPart.includes('今天')) {
+          // 今天的情况
+          targetDate = new Date(currentYear, currentMonth - 1, currentDate, hour, minute, 0);
+        } else if (firstPart.includes('明天')) {
+          // 明天的情况
+          const tomorrow = new Date(now);
+          tomorrow.setDate(currentDate + 1);
+          targetDate = new Date(tomorrow.getFullYear(), tomorrow.getMonth(), tomorrow.getDate(), hour, minute, 0);
+        } else if (firstPart.includes('后天')) {
+          // 后天的情况
+          const dayAfterTomorrow = new Date(now);
+          dayAfterTomorrow.setDate(currentDate + 2);
+          targetDate = new Date(dayAfterTomorrow.getFullYear(), dayAfterTomorrow.getMonth(), dayAfterTomorrow.getDate(), hour, minute, 0);
+        } else {
+          // 具体日期的情况,如 '26年1月1日 周四'
+          // 提取日期部分(去掉星期几)
+          const dateStr = firstPart.split(' ')[0];
+
+          // 解析日期字符串,如 "26年1月1日"
+          const dateMatch = dateStr.match(/(\d+)年(\d+)月(\d+)日/);
+
+          if (dateMatch) {
+            let year = parseInt(dateMatch[1]);
+            const month = parseInt(dateMatch[2]);
+            const day = parseInt(dateMatch[3]);
+
+            // 处理两位数年份:假设20xx年
+            if (year < 100) {
+              year += 2000;
+            }
+
+            targetDate = new Date(year, month - 1, day, hour, minute, 0);
+          } else {
+            throw new Error('日期格式解析错误');
+          }
+        }
+
+        // 格式化为 "YYYY-MM-DD HH:mm:00"
+        const year = targetDate.getFullYear();
+        const month = String(targetDate.getMonth() + 1).padStart(2, '0');
+        const day = String(targetDate.getDate()).padStart(2, '0');
+        const hours = String(targetDate.getHours()).padStart(2, '0');
+        const minutes = String(targetDate.getMinutes()).padStart(2, '0');
+
+        return `${year}-${month}-${day} ${hours}:${minutes}:00`;
+      },
+      //  将"2026-01-01 00:00:00"这种格式的数据转为['2026年1月1日',‘周四’,‘0时0分’]这种格式
+      formatDateTimeToArray(dateTimeStr) {
+        // 解析输入的时间字符串
+        let date;
+
+        try {
+          // 处理 "YYYY-MM-DD HH:mm:ss" 格式
+          date = new Date(dateTimeStr.replace(' ', 'T'));
+
+          // 验证日期是否有效
+          if (isNaN(date.getTime())) {
+            throw new Error('无效的日期时间格式');
+          }
+        } catch (error) {
+          throw new Error(`日期解析失败: ${error.message}`);
+        }
+
+        // 获取年、月、日
+        const year = date.getFullYear();
+        const month = date.getMonth() + 1; // getMonth() 返回 0-11
+        const day = date.getDate();
+
+        // 获取小时和分钟(24小时制)
+        const hour = date.getHours();  // 0-23
+        const minute = date.getMinutes();  // 0-59
+
+        // 获取星期几
+        const weekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
+        const weekDay = weekDays[date.getDay()];
+
+        // 构建数组
+        this.showDateTime = [
+          `${year}年${month}月${day}日`,
+          weekDay,
+          `${hour}时${minute}分`
+        ];
+      },
+      handleShowDateColumns() {
+        this.showDateColumns = true
+      },
+      handleTime() {
+        this.formatDateTimeToArray(this.NewDate)
+        this.formValidate.sendTime = this.NewDate
+        this.showTime = false
+      },
+      handleCloseMatter(item) {
+        this.formValidate.matters = this.formValidate.matters.filter(matter => matter.id !== item.id)
+        this.matterOthersList = this.matterOthersList.filter(matter => matter.id !== item.id)
+        this.matterImgList = this.matterImgList.filter(img => img.id !== item.id)
+        this.deleteItemFromLocalStorage('selectedMaters', item.id)
+      },
+      // 从localStorage中删除指定id的对象项
+      deleteItemFromLocalStorage(storageKey, idToDelete) {
+        try {
+          // 1. 从localStorage获取数据
+          const storedData = localStorage.getItem(storageKey);
+
+          if (!storedData) {
+            console.warn(`未找到键为 "${storageKey}" 的数据`);
+            return false;
+          }
+
+          // 2. 解析JSON数据
+          const dataArray = JSON.parse(storedData);
+
+          if (!Array.isArray(dataArray)) {
+            console.error(`"${storageKey}" 中存储的不是数组`);
+            return false;
+          }
+
+          // 3. 过滤掉要删除的项
+          const filteredArray = dataArray.filter(item => item.id !== idToDelete);
+
+          // 4. 检查是否有删除
+          if (filteredArray.length === dataArray.length) {
+            console.warn(`未找到id为 "${idToDelete}" 的项`);
+            return false;
+          }
+
+          // 5. 将过滤后的数组存回localStorage
+          localStorage.setItem(storageKey, JSON.stringify(filteredArray));
+
+          console.log(`成功删除id为 "${idToDelete}" 的项`);
+          return true;
+        } catch (error) {
+          console.error('删除localStorage项时出错:', error);
+          return false;
+        }
+      },
+      // 播放暂停视频
+      playPause() {
+        const video = document.getElementById('myVideo')
+        const playButton = document.getElementById("playButton")
+        if (video.paused) {
+          video.play()
+        } else {
+          video.pause()
+        }
+      },
+      // 一键群发
+      sendMass() {
+        if (!this.formValidate.name) {
+          vant.Toast.fail('请填写任务名称')
+          return
+        }
+        if (this.formValidate.memberIds && this.formValidate.memberIds.length === 0) {
+          vant.Toast.fail('请选择生效群主')
+          return
+        }
+        if (!this.formValidate.contentText && this.formValidate.ctOthers.length === 0 && this.formValidate.matters.length === 0) {
+          vant.Toast.fail('请添加要发送的内容')
+          return
+        }
+        if (this.formValidate.matters && this.formValidate.matters.length > 9) {
+          vant.Toast.fail('发送素材最多9个')
+          return
+        }
+        if (this.formValidate.type === 2 && !this.formValidate.sendTime) {
+          vant.Toast.fail('请设置群发时间再提交')
+          return
+        }
+        if (this.formValidate.type === 1) {
+          this.formValidate.sendTime = ''
+        }
+        fetch(this.httpUrl + '/scrm/v1/wxcp-group-send/m/add', {
+          method: 'post',
+          body: JSON.stringify({
+            ...this.formValidate,
+          }),
+          headers: {
+            'Content-Type': 'application/json',
+            'token': this.token,
+            'tenancyId': this.tenancyId,
+            'userId': this.userId,
+          }
+        }).then(res => {
+          return res.json()
+        }).then(result => {
+          let { data, code, msg } = result
+          if (code === 1) {
+            vant.Toast.success('发送成功')
+            localStorage.removeItem('selectedMems')
+            localStorage.removeItem('clientMassData')
+            localStorage.removeItem('selectedMaters')
+            this.beforeClose('confirm', () => { })
+          } else {
+            vant.Toast.fail(msg)
+          }
+        })
+      },
+      processData(data) {
+        return data.map(obj => {
+          // 过滤掉tags为空的条件项
+          const filteredTagCondList = obj.tagCondList.filter(cond => cond.tags.length > 0)
+
+          // 如果过滤后tagCondList不为空则保留该对象
+          return filteredTagCondList.length > 0
+            ? { ...obj, tagCondList: filteredTagCondList }
+            : null
+        }).filter(obj => obj !== null) // 剔除空对象
+      },
+      // 添加素材
+      handleAddMatter() {
+        if (this.materialType === 1) {
+          localStorage.setItem('clientMassData', JSON.stringify(this.formValidate))
+          window.location.href = `material.html?memberId=${this.memberId}&bId=${this.bId}&env=${this.env}`
+        } else {
+          // 创建一个input元素,用于选择相册中的图片
+          const input = document.createElement('input');
+          input.type = 'file';
+          input.accept = 'image/*';
+          // 添加change事件监听,当选择图片后触发回调函数
+          input.addEventListener('change', this.handleFileSelect);
+          // 触发input的点击事件,打开相册
+          input.click();
+        }
+      },
+      handleFileSelect(event) {
+        // 获取选择的图片
+        const file = event.target.files[0];
+        // 使用FileReader读取图片数据
+        const reader = new FileReader();
+        reader.onload = (e) => {
+          // 将读取的图片数据赋值给selectedImage,用于展示选择的图片
+          // this.selectedImage = e.target.result;
+          console.log('等待', e.target.result);
+
+        };
+        reader.readAsDataURL(file);
+      },
+      // 截取url中的数据
+      getQueryParam(paramName) {
+        // 获取当前URL的查询字符串部分  
+        const queryString = window.location.search;
+        // 创建一个URLSearchParams对象  
+        const urlParams = new URLSearchParams(queryString);
+        // 返回指定参数的值,如果不存在则返回null  
+        return urlParams.get(paramName);
+      },
+    }
+  })   
+</script>
+
+</html>

+ 714 - 0
lottery/qw/clientGroupMassDetail.html

@@ -0,0 +1,714 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport"
+    content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no, viewport-fit=cover" />
+  <title>任务详情</title>
+  <!-- 引入样式文件 -->
+  <link rel="stylesheet"
+    href="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012584633/vant.css" />
+  <link rel="stylesheet" href="../css/page-return.css">
+  <!-- 必须先引入vue,  后使用vant-ui -->
+  <script
+    src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742017957144/vue.js"></script>
+  <!-- 引入vant的组件库-->
+  <!-- 引入 Vant 的 JS 文件 -->
+  <script
+    src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012748487/vant.min.js"></script>
+
+  <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
+  <script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
+  <script src="../js/page-return.js"></script>
+  <!-- <script src="js/vconsole.min.js"></script>
+    <script>
+  		  var vConsole = new window.VConsole();
+  		</script> -->
+</head>
+<style>
+  body {
+    margin: 0;
+    padding: 0;
+  }
+
+  .box {
+    width: 100vw;
+    min-height: 100vh;
+    box-sizing: border-box;
+    background: #F7F9FC;
+  }
+
+  .page5 {
+    width: 100vw;
+    box-sizing: border-box;
+    padding-bottom: 39px;
+  }
+
+  .task_content {
+    padding: 15px 10px;
+  }
+
+  .task_item {
+    width: 100%;
+    background: #FFFFFF;
+    border-radius: 15px;
+    box-sizing: border-box;
+    padding: 15px 10px;
+  }
+
+  .task_item_title {
+    display: flex;
+    justify-content: space-between;
+    font-weight: 500;
+    font-size: 16px;
+    color: #222222;
+    line-height: 20px;
+  }
+
+  .client_tag {
+    font-size: 12px;
+    line-height: 17px;
+  }
+
+
+  .status1 {
+    color: #136DFB;
+  }
+
+  .status2 {
+    color: #FFA041;
+  }
+
+  .status3 {
+    color: #FF4141;
+  }
+
+  .detail_item {
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+  }
+
+  .time_item {
+    display: flex;
+    align-items: center;
+    font-size: 12px;
+    line-height: 17px;
+    padding-top: 12px;
+  }
+
+  .label {
+    color: #999999;
+  }
+
+  .isAll_type {
+    color: #136DFB;
+  }
+
+  .time {
+    color: #666666;
+  }
+
+  .item_space {
+    margin-right: 20px;
+  }
+
+  .mem_title {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 15px 0 10px;
+  }
+
+  .mem_title_left {
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+    padding-left: 5px;
+    position: relative;
+    display: flex;
+    align-items: center;
+  }
+
+  .mem_title_left::after {
+    position: absolute;
+    left: 0;
+    content: '';
+    width: 2px;
+    height: 12px;
+    background: #136DFB;
+    border-radius: 1px;
+  }
+
+  .mem_title_right {
+    display: flex;
+    align-items: center;
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .mem_title_right img {
+    width: 16px;
+    height: 16px;
+  }
+
+  .mem_tag {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    gap: 10px;
+  }
+
+  .mem_tag span {
+    padding: 2px 8px;
+    background: rgba(19, 109, 251, 0.05);
+    border-radius: 5px;
+    font-size: 12px;
+    line-height: 17px;
+    color: #136DFB;
+  }
+
+  .send_detail {
+    height: calc(100vh - 204px);
+    background: #FFFFFF;
+    border-radius: 15px 15px 0 0;
+  }
+
+  .van-tabs .van-tabs__wrap {
+    border-radius: 15px 15px 0 0;
+  }
+
+  .van-tabs--line .van-tabs__wrap {
+    height: 40px;
+  }
+
+  .van-tabs__nav {
+    padding: 0 25px 15px;
+  }
+
+  .van-tab--active {
+    color: #222222 !important;
+  }
+
+  .van-tab {
+    color: #999999;
+  }
+
+  .send_centent {
+    padding: 20px 15px;
+  }
+
+  .send_text {
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+    padding-bottom: 10px;
+  }
+
+  .send_contentText {
+    font-size: 14px;
+    line-height: 23px;
+    color: #666666;
+    padding-bottom: 20px;
+  }
+
+  .img_list {
+    display: flex;
+    flex-wrap: nowrap;
+    overflow-x: auto;
+    gap: 10px;
+    padding: 0 5px 10px;
+  }
+
+  .img_list img {
+    min-width: 105px;
+    height: 140px;
+    border-radius: 10px;
+    object-fit: cover;
+  }
+
+  .video_container {
+    position: relative;
+    width: 105px;
+    height: 140px;
+  }
+
+  .play_button {
+    width: 24px;
+    height: 24px;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+  }
+
+  .matters_item {
+    width: 163px;
+    height: 60px;
+    border-radius: 10px;
+    display: flex;
+    align-items: center;
+    padding: 10px;
+    box-sizing: border-box;
+    border: 1px solid #EFEFEF;
+  }
+
+  .matters_item img {
+    width: 40px;
+    height: 40px;
+    margin-right: 8px;
+  }
+
+  .matters_item_info {
+    display: flex;
+    flex-direction: column;
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .matters_item_title {
+    font-size: 12px;
+    color: #222222;
+    line-height: 17px;
+    width: 96px;
+    /* 必须设置宽度 */
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    padding-bottom: 4px;
+  }
+
+  .matters_list {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px;
+  }
+
+  .mem_centent {
+    padding: 10px 15px;
+  }
+
+  .filter_list {
+    display: flex;
+    flex-wrap: nowrap;
+    white-space: nowrap;
+    width: 100%;
+    overflow-x: auto;
+    gap: 10px;
+  }
+
+  .filter_span {
+    height: 25px;
+    box-sizing: border-box;
+    font-size: 12px;
+    color: #999999;
+    padding: 4px 12px;
+    background: #FAFAFA;
+    border-radius: 10px;
+  }
+
+  .active {
+    height: 25px;
+    box-sizing: border-box;
+    font-size: 12px;
+    color: #1677FF;
+    background: rgba(22, 119, 255, 0.1);
+    padding: 4px 12px;
+    border-radius: 10px;
+  }
+
+  .send_num_data {
+    display: flex;
+    align-items: center;
+    padding: 15px 5px 10px;
+    font-size: 12px;
+    color: #222222;
+    line-height: 17px;
+  }
+
+  .color1 {
+    color: #1677FF;
+    padding-right: 20px;
+  }
+
+  .color2 {
+    color: #FFA041;
+    padding-right: 20px;
+  }
+
+  .color3 {
+    color: #FF4E4E;
+    padding-right: 20px;
+  }
+
+  .color4 {
+    color: #7D97BF;
+    padding-right: 20px;
+  }
+
+  .send_mem_item {
+    height: 100px;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    padding: 15px;
+    background: #FAFAFA;
+    border-radius: 15px;
+    box-sizing: border-box;
+    margin-bottom: 10px;
+  }
+
+  .send_mem_name {
+    font-weight: 500;
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+  }
+
+  .send_mem_data {
+    display: flex;
+    align-items: center;
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .send_mem_time {
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+</style>
+
+<body>
+  <div id="box" class="box">
+    <div class="page5">
+      <div class="task_content">
+        <div class="task_item">
+          <div class="task_item_title">
+            <div>{{formValidate.name}}</div>
+            <div v-if="formValidate.isNotify === -2" class="client_tag status3">无符合条件客户</div>
+            <div v-else-if="formValidate.isNotify === -1" class="client_tag status3">创建失败</div>
+            <div v-else-if="formValidate.isNotify === 0" class="client_tag status2">待通知</div>
+            <div v-else-if="formValidate.isNotify === 1" class="client_tag status1">已通知</div>
+            <div v-else-if="formValidate.isNotify === 3" class="client_tag status2">创建中</div>
+          </div>
+          <div class="detail_item">
+            <div class="time_item item_space">
+              <div class="label">创建时间:</div>
+              <div class="time">{{ formValidate.createdTime }}</div>
+            </div>
+            <div class="time_item">
+              <div class="label">通知时间:</div>
+              <div class="time">{{ formValidate.notifyTime }}</div>
+            </div>
+          </div>
+          <div class="mem_title">
+            <div class="mem_title_left">生效群主</div>
+            <div class="mem_title_right" @click="handleShowClient">
+              <div>全部群主</div>
+              <img src="../img/qw/more_icon.png" alt="">
+            </div>
+          </div>
+          <div class="mem_tag">
+            <span v-for="(item, index) in formValidate.memberList" :key="index">{{item.name}}</span>
+          </div>
+        </div>
+      </div>
+      <div class="send_detail">
+        <van-tabs v-model="activeTab" ref="tabs" color="#1677FF" line-width="16px" line-height="3px"
+          @change="handleChange">
+          <van-tab title="群发内容" name="群发内容"></van-tab>
+          <van-tab title="成员详情" name="成员详情"></van-tab>
+        </van-tabs>
+        <div class="send_centent" v-if="activeTab === '群发内容'">
+          <div class="send_text">文本:</div>
+          <div class="send_contentText">{{formValidate.contentText}}</div>
+          <div class="send_text">素材:</div>
+          <template v-if="formValidate.ctOthers && formValidate.ctOthers.length > 0">
+            <div class="img_list" v-if="formValidate.ctOthers[0].matterType === 1">
+              <img :src="item.imgUrl" v-for="(item, index) in formValidate.ctOthers" :key="index" alt="">
+            </div>
+            <div class="video_container" v-if="formValidate.ctOthers[0].matterType === 2">
+              <video id="myVideo" style="width: 105px; height: 140px;"
+                :src="formValidate.ctOthers[0].videoPath"></video>
+              <img id="playButton" class="play_button" src="../img/qw/play_icon.png" alt="" @click="playPause">
+            </div>
+            <div class="matters_item" v-if="formValidate.ctOthers[0].matterType === 5">
+              <img src="../img/qw/link.png" alt="">
+              <div class="matters_item_info">
+                <div class="matters_item_title">{{formValidate.ctOthers[0].linkTitle}}</div>
+                <div>自定义链接</div>
+              </div>
+            </div>
+          </template>
+          <template v-if="formValidate.matters && formValidate.matters.length > 0">
+            <div class="img_list" v-if="matterImgList.length > 0">
+              <img :src="item.headUrl" v-for="(item, index) in matterImgList" :key="index" alt="">
+            </div>
+            <div class="matters_list">
+              <div class="matters_item" v-for="(item, index) in matterOthersList" :key="index">
+                <img v-if="item.contentType === 0" src="../img/qw/article.png" alt="">
+                <img v-else-if="item.contentType === 2" src="../img/qw/form.png" alt="">
+                <img v-else-if="item.contentType === 3" src="../img/qw/file.png" alt="">
+                <img v-else src="../img/qw/link.png" alt="">
+                <div class="matters_item_info">
+                  <div class="matters_item_title">{{item.title}}</div>
+                  <div>{{matterTypeList.find(type => type.contentType === item.contentType)?.name || '未知类型'}}</div>
+                </div>
+              </div>
+            </div>
+          </template>
+        </div>
+        <div class="mem_centent" v-if="activeTab === '群发详情'">
+          <div class="filter_list">
+            <span :class="filterIndex === null ? 'active' : 'filter_span'" @click="handleFilter('全部')">全部</span>
+            <span :class="filterIndex === 1 ? 'active' : 'filter_span'" @click="handleFilter(1)">已发送</span>
+            <span :class="filterIndex === 0 ? 'active' : 'filter_span'" @click="handleFilter(0)">未发送</span>
+            <span :class="filterIndex === 2 ? 'active' : 'filter_span'" @click="handleFilter(2)">发送失败</span>
+            <span :class="filterIndex === -1 ? 'active' : 'filter_span'" @click="handleFilter(-1)">无客户可发送</span>
+          </div>
+          <div class="send_num_data">
+            已发送群主:<span class="color1">{{memberExtra.sendSuccess}}</span>
+            未发送群主:<span class="color2">{{memberExtra.unSend}}</span>
+            已发送客户群:<span class="color3">{{memberExtra.sendGroup}}</span>
+          </div>
+          <div class="send_mem_list">
+            <div class="send_mem_item" v-for="(item, index) in sendMemberList" :key="index">
+              <div class="send_mem_name">{{item.groupName}}</div>
+              <div class="send_mem_data">
+                群主信息:<span class="color1">{{item.name}}</span>
+                发送状态:<span class="color1" v-if="item.sendStatus === -1">无可发送客户</span>
+                <span class="color2" v-if="item.sendStatus === 0">未发送</span>
+                <span class="color1" v-if="item.sendStatus === 1">已发送</span>
+                <span class="color3" v-if="item.sendStatus === 2">发送失败</span>
+              </div>
+              <div class="send_mem_time">发送时间:<span style="color: #666666;">{{item.sendTime}}</span></div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 底部返回栏 -->
+    <page-return></page-return>
+  </div>
+</body>
+<script>
+  new Vue({
+    el: '#box',
+    data() {
+      return {
+        httpUrl: '',
+        bId: null,
+        env: '',
+        token: null,
+        tenancyId: null,
+        userId: null,
+        taskId: null,
+        keyword: '',
+        formValidate: {
+          name: '',
+          memberList: [],
+          contentText: '',
+          ctOthers: [],
+          matters: [],
+          id: null,
+          type: 1,
+          sendTime: '',
+          notifyTime: '',
+          createdTime: ''
+        },
+        activeTab: '群发内容',
+        matterImgList: [],
+        matterOthersList: [],
+        matterTypeList: [
+          { contentType: 0, name: '文章' },
+          { contentType: 2, name: '表单' },
+          { contentType: 3, name: '文件' },
+          { contentType: 4, name: '外部链接' },
+          { contentType: 15, name: '视频' },
+          { contentType: 16, name: '视频链接' },
+          { contentType: 17, name: '图集链接' },
+        ],
+        filterIndex: null,
+        memberExtra: {
+          sendSuccess: null,
+          unSend: null,
+          sendGroup: null,
+        },
+        sendMemberList: [],
+      }
+    },
+    created() {
+      this.bId = this.getQueryParam('bId')
+      this.env = this.getQueryParam('env')
+
+      if (!this.env || this.env === 'prod') {
+        this.httpUrl = 'https://wlapi.wefanbot.com'
+      } else {
+        this.httpUrl = 'http://test.wefanbot.com:18993'
+      }
+      this.token = localStorage.getItem('tokenValue')
+      this.tenancyId = localStorage.getItem('tenancyIdValue')
+      this.userId = localStorage.getItem('userId')
+      this.taskId = this.getQueryParam('id')
+      this.getDetail()
+    },
+    methods: {
+      handleChange(tab) {
+        this.activeTab = tab
+        if (tab === '群发内容') {
+          this.getDetail()
+        } else if (tab === '群发详情') {
+          this.handleMember()
+        }
+      },
+      // 群发内容
+      getDetail() {
+        const headers = new Headers()
+        headers.append('token', this.token)
+        headers.append('tenancyId', this.tenancyId)
+        headers.append('userId', this.userId)
+        fetch(this.httpUrl + `/scrm/v1/wxcp-group-send/m/findById?id=${this.taskId}`, {
+          method: 'GET',
+          headers: headers
+        }).then(res => {
+          return res.json()
+        }).then(result => {
+          let { data, code, msg } = result
+          if (code === 1) {
+            this.formValidate = data
+            this.formValidate.createdTime = this.timeFormat(this.formValidate.createdTime)
+            this.formValidate.notifyTime = this.timeFormat(this.formValidate.notifyTime)
+            if (this.formValidate.matters && this.formValidate.matters.length > 0) {
+              this.formValidate.matters.forEach(item => {
+                if (item.contentType === 19) {
+                  this.matterImgList.push(item)
+                } else {
+                  this.matterOthersList.push(item)
+                }
+              })
+            }
+          } else {
+            vant.Toast.fail(msg)
+          }
+        })
+      },
+      // 播放暂停视频
+      playPause() {
+        const video = document.getElementById('myVideo')
+        const playButton = document.getElementById("playButton")
+        if (video.paused) {
+          video.play()
+        } else {
+          video.pause()
+        }
+      },
+      // 筛选发送状态
+      handleFilter(index) {
+        if (index === '全部') {
+          this.filterIndex = null
+        } else {
+          this.filterIndex = index
+        }
+        this.handleMember()
+      },
+      handleMember() {
+        const headers = new Headers()
+        headers.append('token', this.token)
+        headers.append('tenancyId', this.tenancyId)
+        headers.append('userId', this.userId)
+        fetch(this.httpUrl + '/scrm/v1/wxcp-group-send/m/findGroupsPage', {
+          method: 'post',
+          body: JSON.stringify({
+            sendId: this.taskId,
+            status: this.filterIndex,
+            page: 1,
+            pageCount: 1000,
+          }),
+          headers: {
+            'Content-Type': 'application/json',
+            'token': this.token,
+            'tenancyId': this.tenancyId,
+            'userId': this.userId,
+          }
+        }).then(res => {
+          return res.json()
+        }).then(result => {
+          let { data, code, msg } = result
+          if (code === 1) {
+            this.memberExtra = data.extra
+            this.sendMemberList = data.records || []
+          } else {
+            vant.Toast.fail(msg)
+          }
+        })
+      },
+      handleShowClient() {
+        localStorage.setItem('clientData', JSON.stringify(this.formValidate.memberList || []))
+        window.location.href = `showClientList.html`
+      },
+      timeFormat(time, format = 'yyyy-MM-dd hh:mm:ss') {
+        if (time === undefined || time === '' || time === null) {
+          return '/';
+        }
+
+        const date = new Date(time);
+        const o = {
+          'M+': date.getMonth() + 1, // 月份
+          'd+': date.getDate(),      // 日
+          'h+': date.getHours(),     // 小时
+          'm+': date.getMinutes(),   // 分钟
+          's+': date.getSeconds(),   // 秒
+          'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
+          'S': date.getMilliseconds() // 毫秒
+        };
+
+        // 处理年份
+        if (/(y+)/.test(format)) {
+          format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
+        }
+
+        // 处理日期和时间部分
+        for (let k in o) {
+          if (new RegExp('(' + k + ')').test(format)) {
+            let value = o[k];
+            let padding = RegExp.$1.length === 1 ? '' : '00'; // 根据格式字符串中的长度决定是否补零
+            format = format.replace(RegExp.$1, ('' + value).padStart(padding.length + value.toString().length - value.toString().length, '0'));
+          }
+        }
+
+        // 如果格式只包含时间部分,移除日期部分可能的占位符
+        if (!/(M+|d+)/.test(format)) {
+          // 移除任何可能存在的日期占位符(如:'yyyy-MM-dd ')
+          format = format.replace(/(\s*-\s*){2}/g, ''); // 移除两个'-'之间的任何内容
+          format = format.replace(/^\s*yyyy-\s*/, ''); // 移除开头的'yyyy-'
+        }
+
+        // 如果格式只包含日期部分,移除时间部分可能的占位符
+        if (!/(h+|m+|s+)/.test(format)) {
+          // 移除任何可能存在的时间占位符(如:' hh:mm:ss')
+          format = format.replace(/(\s*:\s*){2}/g, ''); // 移除两个':'之间的任何内容
+          format = format.replace(/\s*hh:\s*$/, ''); // 移除结尾的' hh:'
+        }
+
+        return format;
+      },
+      // 截取url中的数据
+      getQueryParam(paramName) {
+        // 获取当前URL的查询字符串部分  
+        const queryString = window.location.search;
+        // 创建一个URLSearchParams对象  
+        const urlParams = new URLSearchParams(queryString);
+        // 返回指定参数的值,如果不存在则返回null  
+        return urlParams.get(paramName);
+      },
+    }
+  })   
+</script>
+
+</html>

+ 393 - 0
lottery/qw/clientGroupMassList.html

@@ -0,0 +1,393 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport"
+    content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no, viewport-fit=cover" />
+  <title>群发列表</title>
+  <!-- 引入样式文件 -->
+  <link rel="stylesheet"
+    href="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012584633/vant.css" />
+  <link rel="stylesheet" href="../css/page-return.css">
+  <!-- 必须先引入vue,  后使用vant-ui -->
+  <script
+    src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742017957144/vue.js"></script>
+  <!-- 引入vant的组件库-->
+  <!-- 引入 Vant 的 JS 文件 -->
+  <script
+    src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012748487/vant.min.js"></script>
+
+  <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
+  <script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
+  <script src="../js/page-return.js"></script>
+  <!-- <script src="js/vconsole.min.js"></script>
+    <script>
+  		  var vConsole = new window.VConsole();
+  		</script> -->
+</head>
+<style>
+  body {
+    margin: 0;
+    padding: 0;
+  }
+
+  .box {
+    width: 100vw;
+    min-height: 100vh;
+    box-sizing: border-box;
+    background: #F7F9FC;
+  }
+
+  .page5 {
+    width: 100vw;
+    box-sizing: border-box;
+    padding: 15px;
+    padding-bottom: 39px;
+  }
+
+  .client_top {
+    width: 100%;
+    height: 70px;
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: 1;
+    background: #FFFFFF;
+  }
+
+  .client_top_box {
+    padding: 15px 15px 0px;
+  }
+
+  .search_icon {
+    width: 24px;
+    height: 24px;
+  }
+
+  .search_input {
+    padding: 0;
+  }
+
+  .search_input .van-search__content {
+    padding: 0;
+    border-radius: 19px;
+  }
+
+  .search_input .van-cell {
+    padding: 0;
+  }
+
+  .search_input .van-field__body {
+    display: flex;
+    align-items: center;
+    position: relative;
+  }
+
+  .search_input .van-field__body input {
+    border: none;
+    width: 100%;
+    height: 40px;
+    background: #FAFAFA;
+    padding: 10px 36px 10px 15px;
+    border-radius: 19px;
+  }
+
+  .search_input .van-field__body input:focus {
+    outline: none;
+  }
+
+  .search_input .van-field__body .van-field__right-icon {
+    position: absolute;
+    right: 12px;
+  }
+
+  .task_list {
+    width: 100%;
+    height: calc(100vh - 109px);
+    position: absolute;
+    top: 70px;
+    left: 0;
+    z-index: 1;
+    background: #F7F9FC;
+    overflow: auto;
+    padding-bottom: 60px;
+    box-sizing: border-box;
+  }
+
+  .task_content {
+    padding: 15px;
+  }
+
+  .task_item {
+    width: 100%;
+    background: #FFFFFF;
+    border-radius: 15px;
+    border: 1px solid #FFFFFF;
+    box-sizing: border-box;
+    margin-bottom: 10px;
+    padding: 15px;
+  }
+
+  .task_item:last-child {
+    margin-bottom: 0;
+  }
+
+  .task_item_title {
+    display: flex;
+    justify-content: space-between;
+    font-weight: 500;
+    font-size: 16px;
+    color: #222222;
+    line-height: 20px;
+  }
+
+  .task_item_name {
+    width: 160px;
+    /* 必须设置宽度 */
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+  }
+
+  .client_tag {
+    font-size: 12px;
+    line-height: 17px;
+  }
+
+  .task_item_time {
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+    padding-top: 8px;
+  }
+
+  .notask {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding-top: 198px;
+  }
+
+  .notask img {
+    width: 102px;
+    height: 90px;
+  }
+
+  .notask_text {
+    font-size: 14px;
+    color: #CCCCCC;
+    line-height: 20px;
+    padding-top: 20px;
+  }
+
+  .send_foot {
+    position: absolute;
+    bottom: 39px;
+    left: 0;
+    width: 100%;
+    z-index: 2;
+  }
+
+  .send_btn {
+    font-weight: 500;
+    font-size: 14px;
+    color: #FFFFFF;
+    line-height: 20px;
+    padding: 15px 0;
+    border-radius: 20px;
+    background: #1677FF;
+    margin: 0 35px;
+    text-align: center;
+  }
+
+  .status1 {
+    color: #136DFB;
+  }
+
+  .status2 {
+    color: #FFA041;
+  }
+
+  .status3 {
+    color: #FF4141;
+  }
+</style>
+
+<body>
+  <div id="box" class="box">
+    <div class="page5">
+      <div>
+        <div class="client_top">
+          <div class="client_top_box">
+            <van-search class="search_input" placeholder="搜索群发名称" v-model="keyword" :clearable="false"
+              left-icon="" @search="initData">
+              <!-- 自定义右侧图标 -->
+              <template v-slot:right-icon>
+                <img class="search_icon" src="../img/qw/search_icon.png" alt="" @click="initData" />
+              </template>
+            </van-search>
+          </div>
+        </div>
+        <div class="task_list" v-if="tableData.length">
+          <div class="task_content">
+            <div class="task_item" v-for="item in tableData" :key="item.id" @click="handleClientMassDetail(item)">
+              <div class="task_item_title">
+                <div class="task_item_name">{{item.name}}</div>
+                <div v-if="item.isNotify === -2" class="client_tag status3">无符合条件客户</div>
+                <div v-else-if="item.isNotify === -1" class="client_tag status3">创建失败</div>
+                <div v-else-if="item.isNotify === 0" class="client_tag status2">待通知</div>
+                <div v-else-if="item.isNotify === 1" class="client_tag status1">已通知</div>
+                <div v-else-if="item.isNotify === 3" class="client_tag status2">创建中</div>
+              </div>
+              <div class="task_item_time">创建时间:{{item.createdTime}}</div>
+            </div>
+          </div>
+        </div>
+        <div class="send_foot">
+          <div class="send_btn" @click="handleClientMass">创建客户群群发</div>
+        </div>
+      </div>
+      <div class="notask" v-else>
+        <img src="../img/qw/no_task.png" alt="">
+        <div class="notask_text">暂无数据</div>
+      </div>
+    </div>
+    <!-- 底部返回栏 -->
+    <page-return></page-return>
+  </div>
+</body>
+<script>
+  new Vue({
+    el: '#box',
+    data() {
+      return {
+        httpUrl: '',
+        bId: null,
+        env: '',
+        token: null,
+        tenancyId: null,
+        userId: null,
+        memberId: null,
+        keyword: '',
+        tableData: [],
+      }
+    },
+    created() {
+      this.bId = this.getQueryParam('bId')
+      this.env = this.getQueryParam('env')
+      this.memberId = this.getQueryParam('memberId')
+
+      if (!this.env || this.env === 'prod') {
+        this.httpUrl = 'https://wlapi.wefanbot.com'
+      } else {
+        this.httpUrl = 'http://test.wefanbot.com:18993'
+      }
+      this.token = localStorage.getItem('tokenValue')
+      this.tenancyId = localStorage.getItem('tenancyIdValue')
+      this.userId = localStorage.getItem('userId')
+      this.initData()
+    },
+    methods: {
+      initData() {
+        const headers = new Headers()
+        headers.append('token', this.token)
+        headers.append('tenancyId', this.tenancyId)
+        headers.append('userId', this.userId)
+        fetch(this.httpUrl + '/scrm/v1/wxcp-group-send/m/findListByPage', {
+          method: 'post',
+          body: JSON.stringify({
+            keyword: this.keyword,
+            page: 1,
+            pageCount: 1000,
+          }),
+          headers: {
+            'Content-Type': 'application/json',
+            'token': this.token,
+            'tenancyId': this.tenancyId,
+            'userId': this.userId,
+          }
+        }).then(res => {
+          return res.json()
+        }).then(result => {
+          let { data, code, msg } = result
+          if (code === 1) {
+            this.tableData = data.records || []
+            this.tableData.forEach(item => {
+              item.createdTime = this.timeFormat(item.createdTime)
+            })
+          } else {
+            vant.Toast.fail(msg)
+          }
+        })
+      },
+      onSearch() {
+        this.initData()
+      },
+      handleClientMassDetail(item) {
+        window.location.href = `clientGroupMassDetail.html?bId=${this.bId}&env=${this.env}&id=${item.id}`
+      },
+      handleClientMass() {
+        window.location.href = `clientGroupMass.html?bId=${this.bId}&env=${this.env}&memberId=${this.memberId}`
+      },
+      timeFormat(time, format = 'yyyy-MM-dd hh:mm:ss') {
+        if (time === undefined || time === '' || time === null) {
+          return '/';
+        }
+
+        const date = new Date(time);
+        const o = {
+          'M+': date.getMonth() + 1, // 月份
+          'd+': date.getDate(),      // 日
+          'h+': date.getHours(),     // 小时
+          'm+': date.getMinutes(),   // 分钟
+          's+': date.getSeconds(),   // 秒
+          'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
+          'S': date.getMilliseconds() // 毫秒
+        };
+
+        // 处理年份
+        if (/(y+)/.test(format)) {
+          format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
+        }
+
+        // 处理日期和时间部分
+        for (let k in o) {
+          if (new RegExp('(' + k + ')').test(format)) {
+            let value = o[k];
+            let padding = RegExp.$1.length === 1 ? '' : '00'; // 根据格式字符串中的长度决定是否补零
+            format = format.replace(RegExp.$1, ('' + value).padStart(padding.length + value.toString().length - value.toString().length, '0'));
+          }
+        }
+
+        // 如果格式只包含时间部分,移除日期部分可能的占位符
+        if (!/(M+|d+)/.test(format)) {
+          // 移除任何可能存在的日期占位符(如:'yyyy-MM-dd ')
+          format = format.replace(/(\s*-\s*){2}/g, ''); // 移除两个'-'之间的任何内容
+          format = format.replace(/^\s*yyyy-\s*/, ''); // 移除开头的'yyyy-'
+        }
+
+        // 如果格式只包含日期部分,移除时间部分可能的占位符
+        if (!/(h+|m+|s+)/.test(format)) {
+          // 移除任何可能存在的时间占位符(如:' hh:mm:ss')
+          format = format.replace(/(\s*:\s*){2}/g, ''); // 移除两个':'之间的任何内容
+          format = format.replace(/\s*hh:\s*$/, ''); // 移除结尾的' hh:'
+        }
+
+        return format;
+      },
+      // 截取url中的数据
+      getQueryParam(paramName) {
+        // 获取当前URL的查询字符串部分  
+        const queryString = window.location.search;
+        // 创建一个URLSearchParams对象  
+        const urlParams = new URLSearchParams(queryString);
+        // 返回指定参数的值,如果不存在则返回null  
+        return urlParams.get(paramName);
+      },
+    }
+  })   
+</script>
+
+</html>

+ 2 - 2
lottery/qw/clientMassDetail.html

@@ -674,8 +674,8 @@
         })
       },
       handleShowClient() {
-        // localStorage.setItem('clientData', JSON.stringify(this.formValidate.memberList || []))
-        // window.location.href = `showClientList.html`
+        localStorage.setItem('clientData', JSON.stringify(this.formValidate.memberList || []))
+        window.location.href = `showClientList.html`
       },
       timeFormat(time, format = 'yyyy-MM-dd hh:mm:ss') {
         if (time === undefined || time === '' || time === null) {

+ 1 - 1
lottery/qw/clientMassList.html

@@ -200,7 +200,7 @@
       <div v-if="tableData.length">
         <div class="client_top">
           <div class="client_top_box">
-            <van-search class="search_input" placeholder="搜索客户昵称/客户群昵称" v-model="keyword" :clearable="false" left-icon="" @search="initData">
+            <van-search class="search_input" placeholder="搜索群发名称" v-model="keyword" :clearable="false" left-icon="" @search="initData">
               <!-- 自定义右侧图标 -->
               <template v-slot:right-icon>
                 <img class="search_icon" src="../img/qw/search_icon.png" alt="" @click="initData" />

+ 1 - 0
lottery/qw/mass.html

@@ -663,6 +663,7 @@
         window.location.href = `material.html?memberId=${this.memberId}&bId=${this.bId}&env=${this.env}`
       },
       handleShowClient() {
+        localStorage.setItem('clientData', JSON.stringify(this.formValidate.clients))
         window.location.href = `showClientList.html`
       },
       handleCloseMatter(item) {

+ 58 - 45
lottery/qw/material.html

@@ -448,7 +448,7 @@
           <div class="filter_span" v-html="formatcontentTypes()"></div>
         </div>
         <div class="foot_btn">
-          <div class="btn_reset">重置</div>
+          <div class="btn_reset" @click="handleReset">重置</div>
           <div class="btn_confirm" @click="handleConfirm">确定</div>
         </div>
       </div>
@@ -650,51 +650,59 @@
       handleFolderClick(item) {
         this.pathList.push(item)
         this.treeData = []
-        this.itemList = []
-        let url = ''
-        if (this.contentType === 0) {
-          url = '/scrm/v1/wxcp-chat-tool/p/pageArticle'
-        } else if (this.contentType === 2) {
-          url = '/scrm/v1/wxcp-chat-tool/p/pageForm'
-        } else if (this.contentType === 3) {
-          url = '/scrm/v1/wxcp-chat-tool/p/pageFile'
-        } else if (this.contentType === 15) {
-          url = '/scrm/v1/wxcp-chat-tool/p/pageVideo'
-        } else if (this.contentType === 17) {
-          url = '/scrm/v1/wxcp-chat-tool/p/pageImg'
-        } else if (this.contentType === 4) {
-          url = '/scrm/v1/wxcp-chat-tool/p/pageUrl'
-        }
-        fetch(this.httpUrl + url, {
-          method: 'post',
-          body: JSON.stringify({
-            groupId: item.id,
-            page: 1,
-            pageCount: 1000,
-          }),
-          headers: {
-            'Content-Type': 'application/json',
-            'tenancyId': this.tenancyId,
+        this.handleSearch(item)
+      },
+      handleSearch(item) {
+        if (this.keyword === '') {
+          this.getTreeData()
+        } else {
+          this.itemList = []
+          let url = ''
+          if (this.contentType === 0) {
+            url = '/scrm/v1/wxcp-chat-tool/p/pageArticle'
+          } else if (this.contentType === 2) {
+            url = '/scrm/v1/wxcp-chat-tool/p/pageForm'
+          } else if (this.contentType === 3) {
+            url = '/scrm/v1/wxcp-chat-tool/p/pageFile'
+          } else if (this.contentType === 15) {
+            url = '/scrm/v1/wxcp-chat-tool/p/pageVideo'
+          } else if (this.contentType === 17) {
+            url = '/scrm/v1/wxcp-chat-tool/p/pageImg'
+          } else if (this.contentType === 4) {
+            url = '/scrm/v1/wxcp-chat-tool/p/pageUrl'
           }
-        }).then(res => {
-          return res.json()
-        }).then(result => {
-          let { data, code, msg } = result
-          if (code === 1) {
-            this.itemList = data.records || []
-            if (this.itemList.length > 0) {
-              // 回显已选择的数据
-              this.checkedMaterIds = this.extractSameIds(this.itemList, this.selectedMaters)
+          fetch(this.httpUrl + url, {
+            method: 'post',
+            body: JSON.stringify({
+              groupId: item ? item.id : null,
+              keyword: this.keyword,
+              page: 1,
+              pageCount: 1000,
+            }),
+            headers: {
+              'Content-Type': 'application/json',
+              'tenancyId': this.tenancyId,
             }
-            if (this.allTreeData.filter(all => all.id === item.id)[0] && this.allTreeData.filter(all => all.id === item.id)[0].children) {
-              this.treeData = this.allTreeData.filter(all => all.id === item.id)[0].children
+          }).then(res => {
+            return res.json()
+          }).then(result => {
+            let { data, code, msg } = result
+            if (code === 1) {
+              this.itemList = data.records || []
+              if (this.itemList.length > 0) {
+                // 回显已选择的数据
+                this.checkedMaterIds = this.extractSameIds(this.itemList, this.selectedMaters)
+              }
+              if (this.allTreeData.filter(all => all.id === item.id)[0] && this.allTreeData.filter(all => all.id === item.id)[0].children) {
+                this.treeData = this.allTreeData.filter(all => all.id === item.id)[0].children
+              } else {
+                this.treeData = []
+              }
             } else {
-              this.treeData = []
+              vant.Toast.fail(msg)
             }
-          } else {
-            vant.Toast.fail(msg)
-          }
-        })
+          })
+        }
       },
       extractSameIds(itemList, selectedMaters) {
         const arr2Ids = new Set(selectedMaters.map(item => item.id))
@@ -702,7 +710,8 @@
           .map(item => item.id)
       },
       // 点击类型,获取树数据
-      handleTypeClick(type) {        // 点击谁,就把谁的图标变成item.icon,其余的变成icon1
+      handleTypeClick(type) {
+        this.keyword = ''      // 点击谁,就把谁的图标变成item.icon,其余的变成icon1
         this.contentType = type
         this.getTreeData()
       },
@@ -745,8 +754,6 @@
         console.log('当前选中的所有素材数据: ', this.selectedMaters)
         this.contentTypeCount = this.countByType(this.selectedMaters)
       },
-      handleSearch() {
-      },
       // 统计数组中每个类型的数量
       countByType(arr) {
         return arr.reduce((countMap, item) => {
@@ -864,6 +871,12 @@
         this.showImgList = false
         this.contentTypeCount = this.countByType(this.selectedMaters)
       },
+      handleReset() {
+        this.selectedMaters = []
+        this.checkedMaterIds = []
+        this.contentTypeCount = {}
+        localStorage.removeItem('selectedMaters')
+      },
       // 截取url中的数据
       getQueryParam(paramName) {
         // 获取当前URL的查询字符串部分  

+ 1767 - 0
lottery/qw/pyqMass.html

@@ -0,0 +1,1767 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport"
+    content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no, viewport-fit=cover" />
+  <title>发布企微朋友圈</title>
+  <!-- 引入样式文件 -->
+  <link rel="stylesheet"
+    href="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012584633/vant.css" />
+  <link rel="stylesheet" href="../css/select-tag.css">
+  <link rel="stylesheet" href="../css/page-return.css">
+  <!-- 必须先引入vue,  后使用vant-ui -->
+  <script
+    src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742017957144/vue.js"></script>
+  <!-- 引入vant的组件库-->
+  <!-- 引入 Vant 的 JS 文件 -->
+  <script
+    src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012748487/vant.min.js"></script>
+
+  <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
+  <script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
+  <script src="../js/select-tag.js"></script>
+  <script src="../js/page-return.js"></script>
+  <!-- <script src="js/vconsole.min.js"></script>
+    <script>
+  		  var vConsole = new window.VConsole();
+  		</script> -->
+</head>
+<style>
+  body {
+    margin: 0;
+    padding: 0;
+  }
+
+  .box {
+    width: 100vw;
+    min-height: 100vh;
+    box-sizing: border-box;
+    background: #F7F9FC;
+  }
+
+  .page5 {
+    width: 100vw;
+    box-sizing: border-box;
+    padding-bottom: 39px;
+  }
+
+  .task_content {
+    padding: 15px 10px;
+  }
+
+  .send_item {
+    width: 100%;
+    background: #FFFFFF;
+    border-radius: 15px;
+    box-sizing: border-box;
+    padding: 15px 10px;
+    margin-bottom: 15px;
+  }
+
+
+  .client_tag {
+    font-size: 12px;
+    line-height: 17px;
+  }
+
+
+  .status1 {
+    color: #136DFB;
+  }
+
+  .status2 {
+    color: #FFA041;
+  }
+
+  .status3 {
+    color: #FF4141;
+  }
+
+  .mem_title {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+
+  .mem_title_left {
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+    padding-left: 5px;
+    position: relative;
+    display: flex;
+    align-items: center;
+  }
+
+  .mem_title_left::after {
+    position: absolute;
+    left: 0;
+    content: '';
+    width: 2px;
+    height: 12px;
+    background: #136DFB;
+    border-radius: 1px;
+  }
+
+  .mem_title_right {
+    display: flex;
+    align-items: center;
+    font-size: 12px;
+    color: #136DFB;
+    line-height: 17px;
+  }
+
+  .mem_title_right img {
+    width: 16px;
+    height: 16px;
+  }
+
+  .mem_tag_list {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    gap: 10px;
+    max-height: 52px;
+    overflow: hidden;
+  }
+
+  .mem_tag {
+    margin-top: 15px;
+  }
+
+  .mem_tag span {
+    padding: 2px 8px;
+    background: rgba(19, 109, 251, 0.05);
+    border-radius: 5px;
+    font-size: 12px;
+    line-height: 17px;
+    color: #136DFB;
+  }
+
+  .condition_mem_tag1 {
+    margin-top: 10px;
+  }
+
+  .condition_mem_tag2 {
+    margin-top: 10px;
+  }
+
+  .condition_mem_tag3 {
+    margin-top: 18px;
+  }
+
+  .condition_mem_tag1 span {
+    padding: 2px 8px;
+    background: #F2F6FC;
+    border-radius: 5px;
+    font-size: 12px;
+    line-height: 17px;
+    color: #7D97BF;
+  }
+
+  .condition_mem_tag2 span {
+    padding: 2px 8px;
+    background: #FCF7F2;
+    border-radius: 5px;
+    font-size: 12px;
+    line-height: 17px;
+    color: #BFA17D;
+  }
+
+  .condition_mem_tag3 span {
+    padding: 2px 8px;
+    background: #FCF2F2;
+    border-radius: 5px;
+    font-size: 12px;
+    line-height: 17px;
+    color: #BF7D7D;
+  }
+
+  .send_centent {
+    padding: 20px 15px;
+  }
+
+  .send_text {
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+    padding-bottom: 10px;
+  }
+
+  .send_contentText {
+    font-size: 14px;
+    line-height: 23px;
+    color: #666666;
+    padding-bottom: 20px;
+  }
+
+  .img_list {
+    display: flex;
+    flex-wrap: nowrap;
+    overflow-x: auto;
+    gap: 10px;
+    padding: 10px 5px 10px;
+  }
+
+  .img_box {
+    position: relative;
+    width: 105px;
+    height: 140px;
+  }
+
+  .close_imgMater {
+    width: 24px;
+    height: 24px;
+    position: absolute;
+    top: -8px;
+    right: -8px;
+  }
+
+  .img_url {
+    width: 105px;
+    height: 140px;
+    border-radius: 10px;
+    object-fit: cover;
+  }
+
+  .video_container {
+    position: relative;
+    width: 105px;
+    height: 140px;
+  }
+
+  .play_button {
+    width: 24px;
+    height: 24px;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+  }
+
+  .matters_item {
+    width: 163px;
+    height: 60px;
+    border-radius: 10px;
+    display: flex;
+    align-items: center;
+    padding: 10px;
+    box-sizing: border-box;
+    border: 1px solid #EFEFEF;
+    position: relative;
+  }
+
+  .matters_item_img {
+    width: 40px;
+    height: 40px;
+    margin-right: 8px;
+  }
+
+  .close_mater {
+    width: 24px;
+    height: 24px;
+    position: absolute;
+    top: -8px;
+    right: -8px;
+  }
+
+  .matters_item_info {
+    display: flex;
+    flex-direction: column;
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .matters_item_title {
+    font-size: 12px;
+    color: #222222;
+    line-height: 17px;
+    width: 96px;
+    /* 必须设置宽度 */
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    padding-bottom: 4px;
+  }
+
+  .matters_list {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px;
+  }
+
+  .mem_centent {
+    padding: 10px 15px;
+  }
+
+  .filter_list {
+    display: flex;
+    flex-wrap: nowrap;
+    white-space: nowrap;
+    width: 100%;
+    overflow-x: auto;
+    gap: 10px;
+  }
+
+  .filter_span {
+    height: 25px;
+    box-sizing: border-box;
+    font-size: 12px;
+    color: #999999;
+    padding: 4px 12px;
+    background: #FAFAFA;
+    border-radius: 10px;
+  }
+
+  .active {
+    height: 25px;
+    box-sizing: border-box;
+    font-size: 12px;
+    color: #1677FF;
+    background: rgba(22, 119, 255, 0.1);
+    padding: 4px 12px;
+    border-radius: 10px;
+  }
+
+  .send_num_data {
+    display: flex;
+    align-items: center;
+    padding: 15px 5px 10px;
+    font-size: 12px;
+    color: #222222;
+    line-height: 17px;
+  }
+
+  .color1 {
+    color: #1677FF;
+    padding-right: 20px;
+  }
+
+  .color2 {
+    color: #FFA041;
+    padding-right: 20px;
+  }
+
+  .color3 {
+    color: #FF4E4E;
+    padding-right: 20px;
+  }
+
+  .color4 {
+    color: #7D97BF;
+    padding-right: 20px;
+  }
+
+  .send_mem_item {
+    height: 100px;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    padding: 15px;
+    background: #FAFAFA;
+    border-radius: 15px;
+    box-sizing: border-box;
+    margin-bottom: 10px;
+  }
+
+  .send_mem_name {
+    font-weight: 500;
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+  }
+
+  .send_mem_data {
+    display: flex;
+    align-items: center;
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .send_mem_time {
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .van-cell {
+    padding: 15px 5px 0;
+  }
+
+  .matter_btn_box {
+    padding: 20px 0 10px;
+  }
+
+  .cond_btn_box {
+    padding-top: 15px;
+  }
+
+  .matter_btn {
+    height: 50px;
+    padding: 15px 0;
+    background: rgba(19, 109, 251, 0.1);
+    border-radius: 20px;
+    font-weight: 500;
+    font-size: 14px;
+    color: #136DFB;
+    text-align: center;
+    box-sizing: border-box;
+  }
+
+  .send_btn_box {
+    padding: 15px 25px 10px;
+  }
+
+  .send_btn {
+    height: 50px;
+    padding: 15px 0;
+    background: #1677FF;
+    border-radius: 20px;
+    font-weight: 500;
+    font-size: 14px;
+    color: #FFFFFF;
+    text-align: center;
+    box-sizing: border-box;
+  }
+
+  textarea {
+    height: 68px !important;
+    line-height: 23px;
+  }
+
+  .van-radio__icon {
+    width: 16px;
+    height: 16px;
+  }
+
+  .van-radio__label {
+    font-size: 14px;
+    line-height: 20px;
+    color: #222222;
+  }
+
+  .van-radio--horizontal {
+    margin-right: 40px;
+  }
+
+  .van-radio-group {
+    margin-top: 15px;
+  }
+
+  .check_div {
+    width: 16px;
+    height: 16px;
+    border-radius: 50%;
+    border: 1px solid #CCCCCC;
+    box-sizing: border-box;
+    margin-right: 8px;
+  }
+
+  .check_div_active {
+    width: 16px;
+    height: 16px;
+    border-radius: 50%;
+    border: 1px solid #136DFB;
+    box-sizing: border-box;
+    margin-right: 8px;
+  }
+
+  .check_div_active:after {
+    content: "";
+    display: block;
+    width: 10px;
+    height: 10px;
+    border-radius: 50%;
+    background: #136DFB;
+    position: relative;
+    top: 2px;
+    left: 2px;
+  }
+
+  .send_item_name {
+    font-size: 14px;
+    line-height: 20px;
+    color: #666666;
+    padding-top: 20px;
+  }
+
+  .data_item {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 20px 20px 10px;
+  }
+
+  .data_title {
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+    display: -webkit-box;
+    -webkit-line-clamp: 2;
+    -webkit-box-orient: vertical;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  .condition_box1 {
+    padding: 15px;
+    background: rgba(245, 249, 255, 0.5);
+    border-radius: 10px;
+    border: 1px solid #E2EAFF;
+    box-sizing: border-box;
+    margin-bottom: 10px;
+  }
+
+  .condition_box2 {
+    padding: 15px;
+    background: rgba(255, 252, 245, 0.5);
+    border-radius: 10px;
+    border: 1px solid #FFF5E2;
+    box-sizing: border-box;
+    margin-bottom: 10px;
+  }
+
+  .condition_box3 {
+    padding: 15px;
+    background: rgba(255, 245, 245, 0.5);
+    border-radius: 10px;
+    border: 1px solid #FFE2E2;
+    box-sizing: border-box;
+  }
+
+  .con_data {
+    display: flex;
+    align-items: center;
+  }
+
+  .con_data_title {
+    font-weight: 500;
+    font-size: 12px;
+    color: #222222;
+    padding-right: 24px;
+  }
+
+  .con_data_edit {
+    font-size: 12px;
+    color: #136DFB;
+    padding-right: 15px;
+  }
+
+  .con_data_del {
+    font-size: 12px;
+    color: #FF4141;
+  }
+
+  .tag_radio {
+    margin-top: 10px;
+  }
+
+  .tag_radio_item {
+    margin-right: 32px;
+  }
+
+  .condition_list {
+    margin-top: 15px;
+  }
+
+  .exc_title {
+    padding-right: 24px;
+  }
+
+  .filter_list {
+    height: 146px;
+    display: flex;
+    align-items: center;
+    gap: 15px;
+  }
+
+  .filter_or {
+    font-weight: 500;
+    font-size: 16px;
+    color: #FFA041;
+    width: 100%;
+    text-align: center;
+    background: rgba(255, 160, 65, 0.05);
+    padding: 49px 0 48px;
+    border-radius: 15px;
+  }
+
+  .filter_exc_active {
+    font-weight: 500;
+    font-size: 16px;
+    color: #FF4141;
+    width: 100%;
+    text-align: center;
+    padding: 49px 0 48px;
+    background: rgba(255, 65, 65, 0.05);
+    border-radius: 15px;
+  }
+
+  .filter_exc {
+    font-weight: 500;
+    font-size: 16px;
+    color: #999999;
+    width: 100%;
+    text-align: center;
+    padding: 49px 0 48px;
+    background: #FAFAFA;
+    border-radius: 15px;
+  }
+
+  .dev_left {
+    margin-left: 15px;
+  }
+
+  .dev_right {
+    margin-right: 15px;
+  }
+
+  .page_box {
+    padding: 15px 15px 0;
+    height: 446px;
+    box-sizing: border-box;
+  }
+
+  .path_list {
+    display: flex;
+    align-items: center;
+    flex-wrap: nowrap;
+    white-space: nowrap;
+    width: 100%;
+    overflow-x: auto;
+    margin-bottom: 25px;
+    height: 17px;
+  }
+
+  .path_span {
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .path_line {
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+    padding: 0 10px;
+  }
+
+  .path_item:last-child {
+    color: #222222;
+  }
+
+  .data_list {
+    height: 404px;
+    gap: 25px;
+    overflow-y: auto;
+  }
+
+  .mem_item {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-bottom: 20px;
+  }
+
+  .mem_item img {
+    width: 40px;
+    height: 40px;
+    margin-right: 10px;
+  }
+
+  .mem_title {
+    width: 224px;
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+    width: 238px;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  .dept_item {
+    display: flex;
+    align-items: center;
+  }
+
+  .time_list {
+    overflow-y: auto;
+    padding: 10px 20px 29px;
+    box-sizing: border-box;
+  }
+
+  .time_box {
+    height: 50px;
+    box-sizing: border-box;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 15px;
+    border-radius: 15px;
+    border: 1px solid #F1F1F1;
+  }
+
+  .time_box img {
+    width: 16px;
+    height: 16px;
+  }
+
+  .date_box {
+    height: 210px;
+    box-sizing: border-box;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    border-radius: 15px;
+    border: 1px solid #F1F1F1;
+  }
+
+  .date_box .van-ellipsis {
+    /* width: 100px; */
+    width: 102px;
+    text-align: center;
+    font-size: 14px;
+    color: #222222;
+    white-space: wrap;
+  }
+
+  .time_date {
+    display: flex;
+    align-items: center;
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+  }
+
+  .time_date_center {
+    padding: 0 10px;
+  }
+
+  .date_select {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-top: 20px;
+  }
+
+  .select_time {
+    width: 76px;
+    height: 37px;
+    line-height: 37px;
+    background: #FAFAFA;
+    border-radius: 10px;
+    font-size: 12px;
+    color: #222222;
+    text-align: center;
+  }
+
+  .select_time_ac {
+    width: 76px;
+    height: 37px;
+    line-height: 37px;
+    background: rgba(19, 109, 251, 0.05);
+    border-radius: 10px;
+    border: 1px solid #136DFB;
+    font-size: 12px;
+    color: #136DFB;
+    text-align: center;
+    box-sizing: border-box;
+  }
+
+  .now_date {
+    display: flex;
+    align-items: center;
+    font-weight: 500;
+    font-size: 16px;
+    color: #222222;
+    padding: 12px 20px;
+    background: #FAFAFA;
+    border-radius: 15px;
+    justify-content: space-between;
+    margin-top: 20px;
+  }
+</style>
+
+<body>
+  <div id="box" class="box">
+    <div class="page5">
+      <van-dialog v-model="showReturn" title="提示" show-cancel-button :before-close="beforeClose"
+        confirm-button-text="确定" cancel-button-text="取消">
+        <div style="padding: 20px; text-align: center;">确认返回吗?</div>
+      </van-dialog>
+      <!-- 选择群发时间 -->
+      <van-popup v-model="showTime" duration="0.2" round position="bottom" :close-on-click-overlay="false"
+        :style="{ width: '100%', height: showDateColumns ? '426px' : '266px' }">
+        <div class="clientTag_title">
+          <div class="close_icon"></div>
+          <div>选择时间</div>
+          <img class="close_icon" src="../img/qw/close_icon.png" alt="" @click="showTime = false" />
+        </div>
+        <div class="time_list" :style="{ height: showDateColumns ? '306px' : '146px' }">
+          <div class="date_box" v-if="showDateColumns">
+            <van-picker ref="vanPicker" :columns="dateColumns" @change="handleChangeDate" visible-item-count="4" />
+          </div>
+          <div class="time_box" @click="handleShowDateColumns" v-else>
+            <div class="close_icon"></div>
+            <div class="time_date">
+              <span>{{nowDate[0]}}</span>
+              <span class="time_date_center">{{nowDate[1]}}</span>
+              <span>{{nowDate[2]}}</span>
+            </div>
+            <img src="../img/qw/select_icon.png" alt="" @click="showTime = false">
+          </div>
+          <div class="date_select">
+            <span :class="dateIndex === 'hour' ? 'select_time_ac' : 'select_time'"
+              @click="getTimeInfo('hour')">一小时后</span>
+            <span :class="dateIndex === 'day' ? 'select_time_ac' : 'select_time'" @click="getTimeInfo('day')">一天后</span>
+            <span :class="dateIndex === 'week' ? 'select_time_ac' : 'select_time'"
+              @click="getTimeInfo('week')">一周后</span>
+            <span :class="dateIndex === 'month' ? 'select_time_ac' : 'select_time'"
+              @click="getTimeInfo('month')">一个月后</span>
+          </div>
+        </div>
+        <div class="tag_footers">
+          <div class="tag_re_btn" @click="showTime = false">取消</div>
+          <div class="tag_ok_btn" @click="handleTime">保存</div>
+        </div>
+      </van-popup>
+      <!-- 成员数据 -->
+      <van-popup v-model="showMem" duration="0.2" round position="bottom" :close-on-click-overlay="false"
+        :style="{ width: '100%', height: '566px' }">
+        <div class="clientTag_title">
+          <div class="close_icon"></div>
+          <div>添加成员</div>
+          <img class="close_icon" src="../img/qw/close_icon.png" alt="" @click="handleCancelMem">
+        </div>
+        <div class="page_box">
+          <div class="path_list">
+            <div class="path_span">
+              <span @click="getTreeData(0)">全部</span>
+              <span class="path_item" v-for="(item, index) in pathList" :key="index" @click="handlePathClick(item)">
+                <span class="path_line">/</span>{{item.text}}</span>
+            </div>
+          </div>
+          <div class="data_list">
+            <!-- 部门 -->
+            <div class="mem_item" v-for="item in treeData" :key="item.id">
+              <div class="dept_item" @click="handleDeptClick(item)">
+                <img src="../img/qw/dept_icon.png" alt="" />
+                <div class="mem_title">{{item.text}}</div>
+              </div>
+            </div>
+            <!-- 成员 -->
+            <van-checkbox-group v-model="checkedMemIds" @change="onChangeMem">
+              <div class="mem_item" v-for="item in itemList" :key="item.memberId">
+                <div class="dept_item">
+                  <img src="../img/qw/mem_icon.png" alt="" />
+                  <div class="mem_title">{{item.name}}</div>
+                </div>
+                <van-checkbox :name="item.memberId">
+                  <template #icon="props">
+                    <div :class="props.checked ? 'check_div_active' : 'check_div'"></div>
+                  </template>
+                </van-checkbox>
+              </div>
+            </van-checkbox-group>
+          </div>
+        </div>
+        <div class="tag_footer">
+          <div class="tag_re_btn" @click="handleCancelMem">取消</div>
+          <div class="tag_ok_btn" @click="handleMem">保存</div>
+        </div>
+      </van-popup>
+      <!-- 标签筛选组件 -->
+      <select-tag :show-Client-Tag.sync="showClientTag" :show-Label-Filter="false"
+        :select-Tag-List.sync="formValidate.tags" @add="handleAdd"></select-tag>
+      <div class="task_content">
+        <div class="send_item">
+          <div class="mem_title_left">朋友圈名称</div>
+          <van-field v-model="formValidate.name" maxlength="20" show-word-limit placeholder="请输入朋友圈名称" />
+        </div>
+        <div class="send_item">
+          <div class="mem_title_left">生效成员</div>
+          <div class="mem_tag mem_tag_list">
+            <span v-for="(item, index) in SelectWachAuthor" :key="index">{{item.name}}</span>
+          </div>
+          <div class="matter_btn_box">
+            <div class="matter_btn" @click="handleAddMem">{{SelectWachAuthor.length ? '编辑' : '添加'}}成员</div>
+          </div>
+        </div>
+        <div class="send_item">
+          <div class="mem_title_left">企业标签</div>
+          <div class="mem_tag mem_tag_list">
+            <span v-for="(item, index) in formValidate.tags" :key="index">{{item.name}}</span>
+          </div>
+          <div class="matter_btn_box">
+            <div class="matter_btn" @click="handleAddTag">{{formValidate.tags.length ? '编辑' : '添加'}}标签</div>
+          </div>
+        </div>
+        <div class="send_item">
+          <div class="mem_title_left">朋友圈内容</div>
+          <van-field v-model="formValidate.contentText" maxlength="500" show-word-limit type="textarea"
+            placeholder="请输入要发送给客户的文本" />
+        </div>
+        <div class="send_item">
+          <div class="mem_title_left">素材</div>
+          <van-radio-group class="tag_radio" v-model="materialType" direction="horizontal">
+            <van-radio :name="1">
+              素材库选择
+              <template #icon="props">
+                <div :class="props.checked ? 'check_div_active' : 'check_div'"></div>
+              </template>
+            </van-radio>
+            <!-- <van-radio :name="2">
+              自定义上传
+              <template #icon="props">
+                <div :class="props.checked ? 'check_div_active' : 'check_div'"></div>
+              </template>
+            </van-radio> -->
+          </van-radio-group>
+          <template v-if="formValidate.ctOthers && formValidate.ctOthers.length > 0">
+            <div class="img_list" v-if="formValidate.ctOthers[0].matterType === 1">
+              <div class="img_box" v-for="(item, index) in formValidate.ctOthers" :key="index">
+                <img class="img_url" :src="item.url" alt="">
+                <img class="close_imgMater" src="../img/qw/close_img.png" alt="" @click="handleCloseMatter(item)">
+              </div>
+            </div>
+            <div class="video_container" v-if="formValidate.ctOthers[0].matterType === 2">
+              <video id="myVideo" style="width: 105px; height: 140px;"
+                :src="formValidate.ctOthers[0].videoPath"></video>
+              <img id="playButton" class="play_button" src="../img/qw/play_icon.png" alt="" @click="playPause">
+            </div>
+            <div class="matters_item" v-if="formValidate.ctOthers[0].matterType === 5">
+              <img class="matters_item_img" src="../img/qw/link.png" alt="">
+              <div class="matters_item_info">
+                <div class="matters_item_title">{{formValidate.ctOthers[0].linkTitle}}</div>
+                <div>自定义链接</div>
+              </div>
+              <img class="close_mater" src="../img/qw/close_mater.png" alt="" @click="handleCloseMatter(item)">
+            </div>
+          </template>
+          <template v-if="formValidate.matters && formValidate.matters.length > 0">
+            <div class="img_list" v-if="matterImgList.length > 0">
+              <div class="img_box" v-for="(item, index) in matterImgList" :key="index">
+                <img class="img_url" :src="item.url" alt="">
+                <img class="close_imgMater" src="../img/qw/close_img.png" alt="" @click="handleCloseMatter(item)">
+              </div>
+            </div>
+            <div class="matters_list">
+              <div class="matters_item" v-for="(item, index) in matterOthersList" :key="index">
+                <img class="matters_item_img" v-if="item.contentType === 0" src="../img/qw/article.png" alt="">
+                <img class="matters_item_img" v-else-if="item.contentType === 2" src="../img/qw/form.png" alt="">
+                <img class="matters_item_img" v-else-if="item.contentType === 3" src="../img/qw/file.png" alt="">
+                <img class="matters_item_img" v-else src="../img/qw/link.png" alt="">
+                <div class="matters_item_info">
+                  <div class="matters_item_title">{{item.title}}</div>
+                  <div>{{matterTypeList.find(type => type.contentType === item.contentType)?.name || '未知类型'}}</div>
+                </div>
+                <img class="close_mater" src="../img/qw/close_mater.png" alt="" @click="handleCloseMatter(item)">
+              </div>
+            </div>
+          </template>
+          <div class="matter_btn_box">
+            <div class="matter_btn" @click="handleAddMatter">添加素材</div>
+          </div>
+        </div>
+        <div class="send_item">
+          <div class="mem_title_left">群发时间</div>
+          <van-radio-group class="tag_radio" v-model="formValidate.type" direction="horizontal"
+            @change="handleRadioType">
+            <van-radio :name="1">
+              立即群发
+              <template #icon="props">
+                <div :class="props.checked ? 'check_div_active' : 'check_div'"></div>
+              </template>
+            </van-radio>
+            <van-radio :name="2">
+              定时转发
+              <template #icon="props">
+                <div :class="props.checked ? 'check_div_active' : 'check_div'"></div>
+              </template>
+            </van-radio>
+          </van-radio-group>
+          <div class="now_date" v-if="showDateTime.length > 0" @click="showTime = true">
+            <span>{{showDateTime[0]}}</span>
+            <span>{{showDateTime[1]}}</span>
+            <span>{{showDateTime[2]}}</span>
+          </div>
+        </div>
+        <div class="send_btn_box">
+          <div class="send_btn" @click="sendMass">一键群发</div>
+        </div>
+      </div>
+    </div>
+    <!-- 底部返回栏 -->
+    <page-return></page-return>
+  </div>
+</body>
+<script>
+  new Vue({
+    el: '#box',
+    data() {
+      return {
+        httpUrl: '',
+        bId: null,
+        env: '',
+        memberId: null,
+        tenancyId: null,
+        token: null,
+        userId: null,
+        showReturn: false,
+        isConfirmingBack: false, // 标记是否已确认返回
+        pushStateCount: 0, // 记录 pushState 的次数
+        initialHistoryLength: 0, // 记录初始历史记录长度
+        materialType: 1,
+        formValidate: {
+          name: '',
+          contentText: '',
+          memberIds: [],
+          ctOthers: [],
+          matters: [],
+          type: 1,
+          sendTime: '',
+          tags: [],
+        },
+        matterImgList: [],
+        matterOthersList: [],
+        matterTypeList: [
+          { contentType: 0, name: '文章' },
+          { contentType: 2, name: '表单' },
+          { contentType: 3, name: '文件' },
+          { contentType: 4, name: '外部链接' },
+          { contentType: 15, name: '视频' },
+          { contentType: 17, name: '图集链接' },
+        ],
+        showMem: false,
+        checkedMemIds: [], // 选中的成员id
+        memList: [], // 成员列表
+        SelectMem: [], // 选中的成员
+        treeData: [], // 总部门树数据
+        selectedMems: [], // 选中的所有成员数据
+        itemList: [], // 当前树下的数据
+        pathList: [], // 当前路径
+        SelectWachAuthor: [], // 选好的微信成员
+        showClientTag: false,
+        showTime: false,
+        dateIndex: 'hour',
+        showDateColumns: false,
+        dateColumns: [],
+        nowDate: [], // 当前选中的日期
+        NewDate: '', // 最终的日期
+        showDateTime: [], // 外面展示的日期格式
+      }
+    },
+    mounted() {
+      // 监听浏览器返回按钮
+      if (window.history && window.history.pushState) {
+        // 记录初始历史记录长度
+        this.initialHistoryLength = window.history.length;
+        history.pushState(null, null, document.URL);
+        this.pushStateCount = 1; // 记录初始 pushState
+        window.addEventListener('popstate', this.handleBack, false);
+      }
+
+      // 监听微信/企业微信返回按钮
+      if (typeof wx !== 'undefined' && wx.ready) {
+        wx.ready(() => {
+          wx.hideOptionMenu();
+        });
+      }
+      if (typeof ww !== 'undefined' && ww.ready) {
+        ww.ready(() => {
+          ww.hideOptionMenu();
+        });
+      }
+    },
+    beforeDestroy() {
+      // 移除事件监听
+      window.removeEventListener('popstate', this.handleBack, false);
+    },
+    created() {
+      this.bId = this.getQueryParam('bId')
+      this.env = this.getQueryParam('env')
+
+      if (!this.env || this.env === 'prod') {
+        this.httpUrl = 'https://wlapi.wefanbot.com'
+      } else {
+        this.httpUrl = 'http://test.wefanbot.com:18993'
+      }
+      this.memberId = this.getQueryParam('memberId')
+      this.token = localStorage.getItem('tokenValue')
+      this.tenancyId = localStorage.getItem('tenancyIdValue')
+      this.userId = localStorage.getItem('userId')
+      this.formValidate = localStorage.getItem('clientMassData') ? JSON.parse(localStorage.getItem('clientMassData')) : {
+        name: '',
+        contentText: '',
+        memberIds: [],
+        ctOthers: [],
+        matters: [],
+        type: 1,
+        sendTime: '',
+        tags: [],
+      }
+      this.SelectWachAuthor = localStorage.getItem('selectedMems') ? JSON.parse(localStorage.getItem('selectedMems')) : []
+      this.formValidate.matters = JSON.parse(localStorage.getItem('selectedMaters')) || []
+      if (this.formValidate.matters && this.formValidate.matters.length > 0) {
+        this.formValidate.matters.forEach(item => {
+          if (item.contentType === 19) {
+            this.matterImgList.push(item)
+          } else {
+            this.matterOthersList.push(item)
+          }
+        })
+      }
+    },
+    methods: {
+      handleBack(e) {
+        // 如果已经确认返回,直接返回,不显示弹框
+        if (this.isConfirmingBack) {
+          return;
+        }
+
+        // 如果弹框已经显示,阻止默认返回行为,但不重复显示弹框
+        if (this.showReturn) {
+          // 阻止返回,重新添加历史记录
+          if (window.history && window.history.pushState) {
+            history.pushState(null, null, document.URL);
+            this.pushStateCount++;
+          }
+          return;
+        }
+
+        // 阻止默认返回行为
+        if (window.history && window.history.pushState) {
+          history.pushState(null, null, document.URL);
+          this.pushStateCount++;
+        }
+
+        // 显示确认弹框
+        this.showReturn = true;
+      },
+      beforeClose(action, done) {
+        if (action === 'confirm') {
+          // 点击确定,设置确认返回标志
+          this.isConfirmingBack = true;
+          // 清理数据
+          localStorage.removeItem('selectedMaters');
+          localStorage.removeItem('selectedMems');
+          localStorage.removeItem('clientMassData');
+          // 移除事件监听,避免触发弹框
+          window.removeEventListener('popstate', this.handleBack, false);
+          // 关闭弹框
+          done();
+          // 直接跳转到 WeCom.html 页面
+          setTimeout(() => {
+            // 获取当前 URL 的查询参数,保留必要的参数
+            const params = new URLSearchParams(window.location.search);
+            const memberId = params.get('memberId') || this.memberId;
+            const bId = params.get('bId') || this.bId;
+            const env = params.get('env') || this.env;
+
+            // 构建跳转 URL
+            let targetUrl = 'pyqMassList.html';
+            if (memberId || bId || env) {
+              const queryParams = [];
+              if (memberId) queryParams.push(`memberId=${memberId}`);
+              if (bId) queryParams.push(`bId=${bId}`);
+              if (env) queryParams.push(`env=${env}`);
+              if (queryParams.length > 0) {
+                targetUrl += '?' + queryParams.join('&');
+              }
+            }
+
+            window.location.href = targetUrl;
+          }, 150);
+        } else {
+          // 点击取消,关闭弹框,重新添加历史记录防止返回
+          done();
+          if (window.history && window.history.pushState) {
+            history.pushState(null, null, document.URL);
+            this.pushStateCount++;
+          }
+        }
+      },
+      // 打开成员选择
+      handleAddMem() {
+        this.showMem = true
+        this.getTreeData(0)
+      },
+      // 打开标签选择
+      handleAddTag() {
+        localStorage.setItem('clientMassData', JSON.stringify(this.formValidate))
+        this.showClientTag = true
+      },
+      // 接收标签数据
+      handleAdd(labelFilter, tagList) {
+        this.formValidate.tags = tagList.map(item => {
+          return {
+            id: item.id,
+            name: item.name,
+          }
+        })
+        this.showClientTag = false
+      },
+      // 获取树数据
+      getTreeData(id) {
+        this.treeData = []
+        if (id === 0) {
+          this.pathList = []
+          this.itemList = []
+        }
+        const headers = new Headers()
+        headers.append('tenancyId', this.tenancyId)
+        headers.append('token', this.token)
+        headers.append('userId', this.userId)
+        fetch(this.httpUrl + `/scrm/v1/wxcp-dept/m/findByParentId?parentId=${id}`, {
+          method: 'GET',
+          headers: headers
+        }).then(res => {
+          return res.json()
+        }).then(result => {
+          let { data, code, msg } = result
+          if (code === 1) {
+            this.treeData = data || []
+          } else {
+            vant.Toast.fail(msg)
+          }
+        })
+      },
+      // 点击树路径
+      handlePathClick(item) {
+        // 找到目标元素的索引
+        const index = this.pathList.findIndex(arr => arr.id === item.id)
+        // 如果找到了该元素
+        if (index !== -1) {
+          // 从该索引位置开始删除到数组末尾
+          this.pathList.splice(index)
+          this.handleDeptClick(item)
+        }
+      },
+      //点击部门
+      handleDeptClick(item) {
+        this.pathList.push(item)
+        this.treeData = []
+        this.itemList = []
+        this.getTreeData(item.id)
+        fetch(this.httpUrl + '/scrm/v1/wxcp-dept/m/findActiveDeptMemberListByPage', {
+          method: 'post',
+          body: JSON.stringify({
+            deptId: item.id,
+            page: 1,
+            pageCount: 1000,
+          }),
+          headers: {
+            'Content-Type': 'application/json',
+            'tenancyId': this.tenancyId,
+            'token': this.token,
+            'userId': this.userId,
+          }
+        }).then(res => {
+          return res.json()
+        }).then(result => {
+          let { data, code, msg } = result
+          if (code === 1) {
+            this.itemList = data.records || []
+            if (this.itemList.length > 0) {
+              // 回显已选择的数据
+              this.checkedMemIds = this.extractSameIds(this.itemList, this.selectedMems)
+            }
+          } else {
+            vant.Toast.fail(msg)
+          }
+        })
+      },
+      extractSameIds(itemList, selectedMems) {
+        const arr2Ids = new Set(selectedMems.map(item => item.memberId))
+        return itemList.filter(item => arr2Ids.has(item.memberId))
+          .map(item => item.memberId)
+      },
+      // 成员选择改变
+      onChangeMem(item) {
+        const currentSelected = this.itemList
+          .filter(item => this.checkedMemIds.includes(item.memberId))
+          .map(item => ({
+            ...item,
+          }))
+
+        // 先删除当前页面未选中的数据
+        const currentPageIds = new Set(this.itemList.map(item => item.memberId))
+        this.selectedMems = this.selectedMems.filter(item => {
+          // 如果是当前页面的数据,但未选中,则删除
+          if (currentPageIds.has(item.memberId)) {
+            return this.checkedMemIds.includes(item.memberId)
+          }
+          // 如果不是当前页面的数据,保留
+          return true
+        })
+
+        // 合并当前选中的和之前选中的,基于 id 去重(当前选中的优先,使用最新的类型)
+        const existingIdsMap = new Map()
+        this.selectedMems.forEach(item => {
+          existingIdsMap.set(item.memberId, item)
+        })
+
+        // 更新或添加当前选中的数据(优先使用当前页面的数据和类型)
+        currentSelected.forEach(item => {
+          existingIdsMap.set(item.memberId, item)
+        })
+
+        this.selectedMems = Array.from(existingIdsMap.values())
+
+        console.log('当前选中的所有成员数据: ', this.selectedMems)
+        localStorage.setItem('selectedMems', JSON.stringify(this.selectedMems))
+      },
+      // 取消成员选择
+      handleCancelMem() {
+        this.showMem = false
+        this.selectedMems = this.SelectWachAuthor
+        localStorage.setItem('selectedMems', JSON.stringify(this.selectedMems))
+      },
+      // 确定成员选择
+      handleMem() {
+        let selectData = this.selectedMems.map((item) => {
+          return {
+            name: item.name,
+            memberId: item.memberId,
+          }
+        })
+        const strings = selectData.map((item) => JSON.stringify(item))
+        this.SelectWachAuthor = [...new Set(strings)].map((item) => JSON.parse(item))
+        this.formValidate.memberIds = [...new Set(this.selectedMems)].map((item) => item.memberId)
+        this.formValidate.memberIds = Array.from(new Set(this.formValidate.memberIds))
+        console.log('最终成员选择: ', this.formValidate.memberIds)
+        this.showMem = false
+      },
+      handleRadioType(val) {
+        if (val === 2) {
+          this.showTime = true
+          if (!this.nowDate.length) {
+            this.getTimeInfo('hour')
+          }
+          this.dateColumns = [
+            {
+              values: this.generateDateArray(),
+            },
+            {
+              values: this.generateHourArrayEnhanced(),
+            },
+            {
+              values: this.generateMinuteArrayWithLoop(),
+            }
+          ]
+        } else {
+
+        }
+      },
+      // 生成日期数组第一组数据
+      generateDateArray() {
+        const result = [];
+        const today = new Date();
+
+        // 星期映射
+        const weekDays = ['日', '一', '二', '三', '四', '五', '六'];
+
+        // 前三天特殊处理
+        const dayNames = ['今天', '明天', '后天'];
+
+        for (let i = 0; i < 365; i++) {
+          const currentDate = new Date(today);
+          currentDate.setDate(today.getDate() + i);
+
+          const year = currentDate.getFullYear();
+          const month = currentDate.getMonth() + 1;
+          const date = currentDate.getDate();
+          const day = currentDate.getDay();
+
+          // 获取星期几的中文
+          const weekDay = `周${weekDays[day]}`;
+
+          if (i < 3) {
+            // 前三天用特殊格式
+            result.push(`${dayNames[i]} ${weekDay}`);
+          } else {
+            // 从第四天开始用正常日期格式
+            // 年份只显示后两位
+            const shortYear = year.toString().slice(-2);
+            result.push(`${shortYear}年${month}月${date}日 ${weekDay}`);
+          }
+        }
+
+        return result;
+      },
+      // 生成小时数组
+      generateHourArrayEnhanced() {
+        const now = new Date();
+        const currentHour = now.getHours(); // 获取当前小时(0-23)
+        const currentMinute = now.getMinutes(); // 获取当前分钟(0-59)
+        const result = [];
+
+        // 计算开始小时:如果当前分钟≥55,从下一小时开始
+        let startHour = currentHour;
+        if (currentMinute >= 55) {
+          startHour = currentHour + 1;
+        }
+
+        // 如果开始小时大于23,返回空数组(因为已经超过今天的小时范围)
+        if (startHour > 23) {
+          return [];
+        }
+
+        // 从开始小时到23时
+        for (let hour = startHour; hour <= 23; hour++) {
+          result.push(`${hour}时`);
+        }
+
+        return result;
+      },
+      // 生成分钟数组,从当前分钟开始,循环到59分
+      generateMinuteArrayWithLoop() {
+        const now = new Date();
+        const currentMinute = now.getMinutes(); // 获取当前分钟(0-59)
+        const startMinute = (currentMinute + 5) % 60; // 计算开始分钟,如果超过59则从0开始
+
+        const result = [];
+
+        // 从开始分钟到59分
+        for (let minute = startMinute; minute <= 59; minute++) {
+          result.push(`${minute}分`);
+        }
+
+        return result;
+      },
+      handleChangeDate(values, index) {
+        if (index[0].substring(0, 2) === '今天') {
+          this.dateColumns[1].values = this.generateHourArrayEnhanced()
+          index[1] = this.dateColumns[1].values[0]
+          this.dateColumns[2].values = this.generateMinuteArrayWithLoop()
+          index[2] = this.dateColumns[2].values[0]
+        } else {
+          this.dateColumns[1].values = Array.from({ length: 24 }, (_, i) => `${i}时`)
+          this.dateColumns[2].values = Array.from({ length: 60 }, (_, i) => `${i}分`)
+        }
+        this.dateIndex = ''
+        this.NewDate = this.convertArrayToDateTime(index)
+      },
+      // 将那4个选项转为相应的数据
+      getTimeInfo(interval) {
+        const weekDays = ['日', '一', '二', '三', '四', '五', '六'];
+        const now = new Date();
+        const result = new Date(now);
+
+        // 时间间隔映射
+        const intervals = {
+          'hour': () => result.setHours(result.getHours() + 1, result.getMinutes() + 5),
+          'day': () => result.setDate(result.getDate() + 1),
+          'week': () => result.setDate(result.getDate() + 7),
+          'month': () => result.setMonth(result.getMonth() + 1)
+        };
+
+        // 应用时间间隔
+        intervals[interval]?.();
+        if (interval !== 'hour') result.setMinutes(result.getMinutes() + 5);
+
+        // 将秒数设置为0(确保格式化为 "00" 秒)
+        result.setSeconds(0, 0);
+
+        // 格式化为 "2026-01-01 00:00:00" 格式
+        const year = result.getFullYear();
+        const month = String(result.getMonth() + 1).padStart(2, '0');
+        const day = String(result.getDate()).padStart(2, '0');
+        const hours = String(result.getHours()).padStart(2, '0');
+        const minutes = String(result.getMinutes()).padStart(2, '0');
+
+        // 赋值给 NewDate 变量
+        this.NewDate = `${year}-${month}-${day} ${hours}:${minutes}:00`;
+        // 格式化(原有逻辑保持不变)
+        const dayOfWeek = weekDays[result.getDay()];
+        const time = `${hours}:${minutes}`;
+
+        // 日期描述
+        let dateDesc = '';
+        if (interval === 'hour') {
+          const isSameDay = now.toDateString() === result.toDateString();
+          dateDesc = isSameDay ? '今天' : '明天';
+        } else if (interval === 'day') {
+          dateDesc = '明天';
+        } else {
+          dateDesc = `${result.getMonth() + 1}月${result.getDate()}日`;
+        }
+
+        this.dateIndex = interval;
+        this.nowDate = [dateDesc, `周${dayOfWeek}`, time];
+        this.showDateColumns = false;
+      },
+      // 将选择的日期时间数组转换为标准格式
+      convertArrayToDateTime(arr) {
+        // 获取当前日期和时间
+        const now = new Date();
+        const currentYear = now.getFullYear();
+        const currentMonth = now.getMonth() + 1;
+        const currentDate = now.getDate();
+
+        let targetDate;
+        const firstPart = arr[0];
+
+        // 解析小时和分钟
+        const hourStr = arr[1].replace('时', '');
+        const minuteStr = arr[2].replace('分', '');
+        const hour = parseInt(hourStr);
+        const minute = parseInt(minuteStr);
+
+        // 判断是哪种情况
+        if (firstPart.includes('今天')) {
+          // 今天的情况
+          targetDate = new Date(currentYear, currentMonth - 1, currentDate, hour, minute, 0);
+        } else if (firstPart.includes('明天')) {
+          // 明天的情况
+          const tomorrow = new Date(now);
+          tomorrow.setDate(currentDate + 1);
+          targetDate = new Date(tomorrow.getFullYear(), tomorrow.getMonth(), tomorrow.getDate(), hour, minute, 0);
+        } else if (firstPart.includes('后天')) {
+          // 后天的情况
+          const dayAfterTomorrow = new Date(now);
+          dayAfterTomorrow.setDate(currentDate + 2);
+          targetDate = new Date(dayAfterTomorrow.getFullYear(), dayAfterTomorrow.getMonth(), dayAfterTomorrow.getDate(), hour, minute, 0);
+        } else {
+          // 具体日期的情况,如 '26年1月1日 周四'
+          // 提取日期部分(去掉星期几)
+          const dateStr = firstPart.split(' ')[0];
+
+          // 解析日期字符串,如 "26年1月1日"
+          const dateMatch = dateStr.match(/(\d+)年(\d+)月(\d+)日/);
+
+          if (dateMatch) {
+            let year = parseInt(dateMatch[1]);
+            const month = parseInt(dateMatch[2]);
+            const day = parseInt(dateMatch[3]);
+
+            // 处理两位数年份:假设20xx年
+            if (year < 100) {
+              year += 2000;
+            }
+
+            targetDate = new Date(year, month - 1, day, hour, minute, 0);
+          } else {
+            throw new Error('日期格式解析错误');
+          }
+        }
+
+        // 格式化为 "YYYY-MM-DD HH:mm:00"
+        const year = targetDate.getFullYear();
+        const month = String(targetDate.getMonth() + 1).padStart(2, '0');
+        const day = String(targetDate.getDate()).padStart(2, '0');
+        const hours = String(targetDate.getHours()).padStart(2, '0');
+        const minutes = String(targetDate.getMinutes()).padStart(2, '0');
+
+        return `${year}-${month}-${day} ${hours}:${minutes}:00`;
+      },
+      //  将"2026-01-01 00:00:00"这种格式的数据转为['2026年1月1日',‘周四’,‘0时0分’]这种格式
+      formatDateTimeToArray(dateTimeStr) {
+        // 解析输入的时间字符串
+        let date;
+
+        try {
+          // 处理 "YYYY-MM-DD HH:mm:ss" 格式
+          date = new Date(dateTimeStr.replace(' ', 'T'));
+
+          // 验证日期是否有效
+          if (isNaN(date.getTime())) {
+            throw new Error('无效的日期时间格式');
+          }
+        } catch (error) {
+          throw new Error(`日期解析失败: ${error.message}`);
+        }
+
+        // 获取年、月、日
+        const year = date.getFullYear();
+        const month = date.getMonth() + 1; // getMonth() 返回 0-11
+        const day = date.getDate();
+
+        // 获取小时和分钟(24小时制)
+        const hour = date.getHours();  // 0-23
+        const minute = date.getMinutes();  // 0-59
+
+        // 获取星期几
+        const weekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
+        const weekDay = weekDays[date.getDay()];
+
+        // 构建数组
+        this.showDateTime = [
+          `${year}年${month}月${day}日`,
+          weekDay,
+          `${hour}时${minute}分`
+        ];
+      },
+      handleShowDateColumns() {
+        this.showDateColumns = true
+      },
+      handleTime() {
+        this.formatDateTimeToArray(this.NewDate)
+        this.formValidate.sendTime = this.NewDate
+        this.showTime = false
+      },
+      handleCloseMatter(item) {
+        this.formValidate.matters = this.formValidate.matters.filter(matter => matter.id !== item.id)
+        this.matterOthersList = this.matterOthersList.filter(matter => matter.id !== item.id)
+        this.matterImgList = this.matterImgList.filter(img => img.id !== item.id)
+        this.deleteItemFromLocalStorage('selectedMaters', item.id)
+      },
+      // 从localStorage中删除指定id的对象项
+      deleteItemFromLocalStorage(storageKey, idToDelete) {
+        try {
+          // 1. 从localStorage获取数据
+          const storedData = localStorage.getItem(storageKey);
+
+          if (!storedData) {
+            console.warn(`未找到键为 "${storageKey}" 的数据`);
+            return false;
+          }
+
+          // 2. 解析JSON数据
+          const dataArray = JSON.parse(storedData);
+
+          if (!Array.isArray(dataArray)) {
+            console.error(`"${storageKey}" 中存储的不是数组`);
+            return false;
+          }
+
+          // 3. 过滤掉要删除的项
+          const filteredArray = dataArray.filter(item => item.id !== idToDelete);
+
+          // 4. 检查是否有删除
+          if (filteredArray.length === dataArray.length) {
+            console.warn(`未找到id为 "${idToDelete}" 的项`);
+            return false;
+          }
+
+          // 5. 将过滤后的数组存回localStorage
+          localStorage.setItem(storageKey, JSON.stringify(filteredArray));
+
+          console.log(`成功删除id为 "${idToDelete}" 的项`);
+          return true;
+        } catch (error) {
+          console.error('删除localStorage项时出错:', error);
+          return false;
+        }
+      },
+      // 播放暂停视频
+      playPause() {
+        const video = document.getElementById('myVideo')
+        const playButton = document.getElementById("playButton")
+        if (video.paused) {
+          video.play()
+        } else {
+          video.pause()
+        }
+      },
+      // 一键群发
+      sendMass() {
+        if (!this.formValidate.name) {
+          vant.Toast.fail('请填写任务名称')
+          return
+        }
+        if (this.formValidate.memberIds && this.formValidate.memberIds.length === 0) {
+          vant.Toast.fail('请选择成员')
+          return
+        }
+        if (!this.formValidate.contentText && this.formValidate.ctOthers.length === 0 && this.formValidate.matters.length === 0) {
+          vant.Toast.fail('请添加要发送的内容')
+          return
+        }
+        if (this.formValidate.matters && this.formValidate.matters.length > 9) {
+          vant.Toast.fail('发送素材最多9个')
+          return
+        }
+        if (this.formValidate.type === 2 && !this.formValidate.sendTime) {
+          vant.Toast.fail('请设置群发时间再提交')
+          return
+        }
+        if (this.formValidate.type === 1) {
+          this.formValidate.sendTime = ''
+        }
+        fetch(this.httpUrl + '/scrm/v1/wxcp-moment/m/add', {
+          method: 'post',
+          body: JSON.stringify({
+            ...this.formValidate,
+          }),
+          headers: {
+            'Content-Type': 'application/json',
+            'token': this.token,
+            'tenancyId': this.tenancyId,
+            'userId': this.userId,
+          }
+        }).then(res => {
+          return res.json()
+        }).then(result => {
+          let { data, code, msg } = result
+          if (code === 1) {
+            vant.Toast.success('发布成功')
+            localStorage.removeItem('selectedMems')
+            localStorage.removeItem('clientMassData')
+            localStorage.removeItem('selectedMaters')
+            this.beforeClose('confirm', () => { })
+          } else {
+            vant.Toast.fail(msg)
+          }
+        })
+      },
+      processData(data) {
+        return data.map(obj => {
+          // 过滤掉tags为空的条件项
+          const filteredTagCondList = obj.tagCondList.filter(cond => cond.tags.length > 0)
+
+          // 如果过滤后tagCondList不为空则保留该对象
+          return filteredTagCondList.length > 0
+            ? { ...obj, tagCondList: filteredTagCondList }
+            : null
+        }).filter(obj => obj !== null) // 剔除空对象
+      },
+      // 添加素材
+      handleAddMatter() {
+        if (this.materialType === 1) {
+          localStorage.setItem('clientMassData', JSON.stringify(this.formValidate))
+          window.location.href = `material.html?memberId=${this.memberId}&bId=${this.bId}&env=${this.env}`
+        } else {
+          // 创建一个input元素,用于选择相册中的图片
+          const input = document.createElement('input');
+          input.type = 'file';
+          input.accept = 'image/*';
+          // 添加change事件监听,当选择图片后触发回调函数
+          input.addEventListener('change', this.handleFileSelect);
+          // 触发input的点击事件,打开相册
+          input.click();
+        }
+      },
+      handleFileSelect(event) {
+        // 获取选择的图片
+        const file = event.target.files[0];
+        // 使用FileReader读取图片数据
+        const reader = new FileReader();
+        reader.onload = (e) => {
+          // 将读取的图片数据赋值给selectedImage,用于展示选择的图片
+          // this.selectedImage = e.target.result;
+          console.log('等待', e.target.result);
+
+        };
+        reader.readAsDataURL(file);
+      },
+      // 截取url中的数据
+      getQueryParam(paramName) {
+        // 获取当前URL的查询字符串部分  
+        const queryString = window.location.search;
+        // 创建一个URLSearchParams对象  
+        const urlParams = new URLSearchParams(queryString);
+        // 返回指定参数的值,如果不存在则返回null  
+        return urlParams.get(paramName);
+      },
+    }
+  })   
+</script>
+
+</html>

+ 650 - 0
lottery/qw/pyqMassDetail.html

@@ -0,0 +1,650 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport"
+    content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no, viewport-fit=cover" />
+  <title>任务详情</title>
+  <!-- 引入样式文件 -->
+  <link rel="stylesheet"
+    href="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012584633/vant.css" />
+  <link rel="stylesheet" href="../css/page-return.css">
+  <!-- 必须先引入vue,  后使用vant-ui -->
+  <script
+    src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742017957144/vue.js"></script>
+  <!-- 引入vant的组件库-->
+  <!-- 引入 Vant 的 JS 文件 -->
+  <script
+    src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012748487/vant.min.js"></script>
+
+  <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
+  <script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
+  <script src="../js/page-return.js"></script>
+  <!-- <script src="js/vconsole.min.js"></script>
+    <script>
+  		  var vConsole = new window.VConsole();
+  		</script> -->
+</head>
+<style>
+  body {
+    margin: 0;
+    padding: 0;
+  }
+
+  .box {
+    width: 100vw;
+    min-height: 100vh;
+    box-sizing: border-box;
+    background: #F7F9FC;
+  }
+
+  .page5 {
+    width: 100vw;
+    box-sizing: border-box;
+    padding-bottom: 39px;
+  }
+
+  .task_content {
+    padding: 15px 10px;
+  }
+
+  .task_item {
+    width: 100%;
+    background: #FFFFFF;
+    border-radius: 15px;
+    box-sizing: border-box;
+    padding: 15px 10px;
+  }
+
+  .task_item_title {
+    display: flex;
+    justify-content: space-between;
+    font-weight: 500;
+    font-size: 16px;
+    color: #222222;
+    line-height: 20px;
+  }
+
+  .client_tag {
+    font-size: 12px;
+    line-height: 17px;
+  }
+
+
+  .status1 {
+    color: #136DFB;
+  }
+
+  .status2 {
+    color: #FFA041;
+  }
+
+  .status3 {
+    color: #FF4141;
+  }
+
+  .detail_item {
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+  }
+
+  .time_item {
+    display: flex;
+    align-items: center;
+    font-size: 12px;
+    line-height: 17px;
+    padding-top: 12px;
+  }
+
+  .label {
+    color: #999999;
+  }
+
+  .isAll_type {
+    color: #136DFB;
+  }
+
+  .time {
+    color: #666666;
+  }
+
+  .item_space {
+    margin-right: 20px;
+  }
+
+  .mem_title {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 15px 0 10px;
+  }
+
+  .mem_title_left {
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+    padding-left: 5px;
+    position: relative;
+    display: flex;
+    align-items: center;
+  }
+
+  .mem_title_left::after {
+    position: absolute;
+    left: 0;
+    content: '';
+    width: 2px;
+    height: 12px;
+    background: #136DFB;
+    border-radius: 1px;
+  }
+
+  .mem_title_right {
+    display: flex;
+    align-items: center;
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .mem_title_right img {
+    width: 16px;
+    height: 16px;
+  }
+
+  .mem_tag {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    gap: 10px;
+  }
+
+  .mem_tag span {
+    padding: 2px 8px;
+    background: rgba(19, 109, 251, 0.05);
+    border-radius: 5px;
+    font-size: 12px;
+    line-height: 17px;
+    color: #136DFB;
+  }
+
+  .send_detail {
+    height: calc(100vh - 204px);
+    background: #FFFFFF;
+    border-radius: 15px 15px 0 0;
+  }
+
+  .van-tabs .van-tabs__wrap {
+    border-radius: 15px 15px 0 0;
+  }
+
+  .van-tabs--line .van-tabs__wrap {
+    height: 40px;
+  }
+
+  .van-tabs__nav {
+    padding: 0 25px 15px;
+  }
+
+  .van-tab--active {
+    color: #222222 !important;
+  }
+
+  .van-tab {
+    color: #999999;
+  }
+
+  .send_centent {
+    padding: 20px 15px;
+  }
+
+  .send_text {
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+    padding-bottom: 10px;
+  }
+
+  .send_contentText {
+    font-size: 14px;
+    line-height: 23px;
+    color: #666666;
+    padding-bottom: 20px;
+  }
+
+  .img_list {
+    display: flex;
+    flex-wrap: nowrap;
+    overflow-x: auto;
+    gap: 10px;
+    padding: 0 5px 10px;
+  }
+
+  .img_list img {
+    min-width: 105px;
+    height: 140px;
+    border-radius: 10px;
+    object-fit: cover;
+  }
+
+  .video_container {
+    position: relative;
+    width: 105px;
+    height: 140px;
+  }
+
+  .play_button {
+    width: 24px;
+    height: 24px;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+  }
+
+  .matters_item {
+    width: 163px;
+    height: 60px;
+    border-radius: 10px;
+    display: flex;
+    align-items: center;
+    padding: 10px;
+    box-sizing: border-box;
+    border: 1px solid #EFEFEF;
+  }
+
+  .matters_item img {
+    width: 40px;
+    height: 40px;
+    margin-right: 8px;
+  }
+
+  .matters_item_info {
+    display: flex;
+    flex-direction: column;
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .matters_item_title {
+    font-size: 12px;
+    color: #222222;
+    line-height: 17px;
+    width: 96px;
+    /* 必须设置宽度 */
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    padding-bottom: 4px;
+  }
+
+  .matters_list {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px;
+  }
+
+  .mem_centent {
+    padding: 10px 15px;
+  }
+
+  .filter_list {
+    display: flex;
+    flex-wrap: nowrap;
+    white-space: nowrap;
+    width: 100%;
+    overflow-x: auto;
+    gap: 10px;
+  }
+
+  .filter_span {
+    height: 25px;
+    box-sizing: border-box;
+    font-size: 12px;
+    color: #999999;
+    padding: 4px 12px;
+    background: #FAFAFA;
+    border-radius: 10px;
+  }
+
+  .active {
+    height: 25px;
+    box-sizing: border-box;
+    font-size: 12px;
+    color: #1677FF;
+    background: rgba(22, 119, 255, 0.1);
+    padding: 4px 12px;
+    border-radius: 10px;
+  }
+
+  .send_num_data {
+    display: flex;
+    align-items: center;
+    padding: 15px 5px 10px;
+    font-size: 12px;
+    color: #222222;
+    line-height: 17px;
+  }
+
+  .color1 {
+    color: #1677FF;
+    padding-right: 20px;
+  }
+
+  .color2 {
+    color: #FFA041;
+    padding-right: 20px;
+  }
+
+  .color3 {
+    color: #FF4E4E;
+    padding-right: 20px;
+  }
+
+  .color4 {
+    color: #7D97BF;
+    padding-right: 20px;
+  }
+
+  .send_mem_item {
+    height: 100px;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    padding: 15px;
+    background: #FAFAFA;
+    border-radius: 15px;
+    box-sizing: border-box;
+    margin-bottom: 10px;
+  }
+
+  .send_mem_name {
+    font-weight: 500;
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+  }
+
+  .send_mem_data {
+    display: flex;
+    align-items: center;
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+
+  .send_mem_time {
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+  }
+</style>
+
+<body>
+  <div id="box" class="box">
+    <div class="page5">
+      <div class="task_content">
+        <div class="task_item">
+          <div class="task_item_title">
+            <div>{{formValidate.name}}</div>
+            <div v-if="formValidate.jobStatus === -1" class="client_tag status3">创建失败</div>
+            <div v-else-if="formValidate.jobStatus === 0" class="client_tag status2">待通知</div>
+            <div v-else-if="formValidate.jobStatus === 1" class="client_tag status2">开始创建任务</div>
+            <div v-else-if="formValidate.jobStatus === 2" class="client_tag status2">创建中</div>
+            <div v-else-if="formValidate.jobStatus === 3" class="client_tag status1">已通知</div>
+          </div>
+          <div class="detail_item">
+            <div class="time_item item_space">
+              <div class="label">创建人:</div>
+              <div class="isAll_type">{{ formValidate.creatorName }}</div>
+            </div>
+            <div class="time_item item_space">
+              <div class="label">内容类型:</div>
+              <div class="time">{{ formValidate.momentType }}</div>
+            </div>
+            <div class="time_item">
+              <div class="label">发表时间:</div>
+              <div class="time">{{ formValidate.momentTime }}</div>
+            </div>
+          </div>
+          <div class="mem_title">
+            <div class="mem_title_left">标签</div>
+            <div class="mem_title_right">
+              <div>全部标签</div>
+              <img src="../img/qw/more_icon.png" alt="">
+            </div>
+          </div>
+          <div class="mem_tag">
+            <span v-for="(item, index) in formValidate.tags" :key="index">{{item.name}}</span>
+          </div>
+        </div>
+      </div>
+      <div class="send_detail">
+        <van-tabs v-model="activeTab" ref="tabs" color="#1677FF" line-width="16px" line-height="3px">
+          <van-tab title="朋友圈内容" name="朋友圈内容"></van-tab>
+          <van-tab title="成员详情" name="成员详情"></van-tab>
+        </van-tabs>
+        <div class="send_centent" v-if="activeTab === '朋友圈内容'">
+          <div class="send_text">文本:</div>
+          <div class="send_contentText">{{formValidate.contentText}}</div>
+          <div class="send_text">素材:</div>
+          <template>
+            <div class="img_list" v-if="formValidate.momentType === '图片'">
+              <img :src="item.url" v-for="(item, index) in formValidate.contentList" :key="index" alt="">
+            </div>
+            <div class="video_container" v-if="formValidate.momentType === '视频'">
+              <video id="myVideo" style="width: 105px; height: 140px;"
+                :src="formValidate.contentList[0].url"></video>
+              <img id="playButton" class="play_button" src="../img/qw/play_icon.png" alt="" @click="playPause">
+            </div>
+            <div class="matters_item" v-if="formValidate.momentType === '链接'">
+              <img src="../img/qw/link.png" alt="">
+              <div class="matters_item_info">
+                <div class="matters_item_title">{{formValidate.title}}</div>
+                <div>自定义链接</div>
+              </div>
+            </div>
+          </template>
+        </div>
+        <div class="mem_centent" v-if="activeTab === '发送成员详情'">
+          <div class="filter_list">
+            <span :class="filterIndex === 2 ? 'active' : 'filter_span'" @click="handleFilter('全部')">全部</span>
+            <span :class="filterIndex === 1 ? 'active' : 'filter_span'" @click="handleFilter(1)">已发送</span>
+            <span :class="filterIndex === 0 ? 'active' : 'filter_span'" @click="handleFilter(0)">未发送</span>
+          </div>
+          <div class="send_num_data">
+            全部人员:<span class="color1">{{ sendMemberList ? sendMemberList.length : 0 }}</span>
+            已发送人员:<span class="color1">{{formValidate.send}}</span>
+            未发送人员:<span class="color3">{{formValidate.unSend}}</span>
+            触达客户数:<span class="color2">{{formValidate.clientNum}}</span>
+          </div>
+          <div class="send_mem_list">
+            <div class="send_mem_item" v-for="(item, index) in sendMemberList" :key="index">
+              <div class="send_mem_name">{{item.groupName}}</div>
+              <div class="send_mem_data">
+                成员名称:<span class="color1">{{item.name}}</span>
+                发送状态:
+                <span class="color2" v-if="item.status === 0">未发送</span>
+                <span class="color1" v-if="item.status === 1">已发送</span>
+                <span class="color3" v-if="item.status === 2">发送失败</span>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 底部返回栏 -->
+    <page-return></page-return>
+  </div>
+</body>
+<script>
+  new Vue({
+    el: '#box',
+    data() {
+      return {
+        httpUrl: '',
+        bId: null,
+        env: '',
+        token: null,
+        tenancyId: null,
+        userId: null,
+        taskId: null,
+        keyword: '',
+        formValidate: {
+          name: '',
+          momentType: '',
+          momentTime: '',
+          creatorName: '',
+          tags: [],
+          contentText: '',
+          contentList: [],
+          title: '',
+          send: '',
+          unSend: '',
+          clientNum: '',
+        },
+        activeTab: '朋友圈内容',
+        filterIndex: 2,
+        sendMemberList: [],
+        momentTypeEnumMap: [
+            { key: 0, name: '文本' },
+            { key: 1, name: '图片' },
+            { key: 2, name: '视频' },
+            { key: 3, name: '语音' },
+            { key: 4, name: '文件' },
+            { key: 5, name: '链接' },
+            { key: 7, name: '红包' },
+            { key: 8, name: '名片' },
+            { key: 33, name: '小程序' },
+            { key: 51, name: '视频号' },
+        ]
+      }
+    },
+    created() {
+      this.bId = this.getQueryParam('bId')
+      this.env = this.getQueryParam('env')
+
+      if (!this.env || this.env === 'prod') {
+        this.httpUrl = 'https://wlapi.wefanbot.com'
+      } else {
+        this.httpUrl = 'http://test.wefanbot.com:18993'
+      }
+      this.token = localStorage.getItem('tokenValue')
+      this.tenancyId = localStorage.getItem('tenancyIdValue')
+      this.userId = localStorage.getItem('userId')
+      this.taskId = this.getQueryParam('id')
+      this.getDetail()
+    },
+    methods: {
+      // 朋友圈内容
+      getDetail() {
+        const headers = new Headers()
+        headers.append('token', this.token)
+        headers.append('tenancyId', this.tenancyId)
+        headers.append('userId', this.userId)
+        fetch(this.httpUrl + `/scrm/v1/wxcp-moment/m/findById?id=${this.taskId}`, {
+          method: 'GET',
+          headers: headers
+        }).then(res => {
+          return res.json()
+        }).then(result => {
+          let { data, code, msg } = result
+          if (code === 1) {
+            this.formValidate = data
+            this.formValidate.momentType = this.momentTypeEnumMap.filter(item => item.key === data.momentType)[0].name
+            this.formValidate.momentTime = this.timeFormat(this.formValidate.momentTime)
+            this.sendMemberList = data.memberList || []
+          } else {
+            vant.Toast.fail(msg)
+          }
+        })
+      },
+      // 播放暂停视频
+      playPause() {
+        const video = document.getElementById('myVideo')
+        const playButton = document.getElementById("playButton")
+        if (video.paused) {
+          video.play()
+        } else {
+          video.pause()
+        }
+      },
+      // 筛选发送状态
+      handleFilter(index) {
+        this.filterIndex = index
+        if (index === 0) {
+            this.sendMemberList = this.formValidate.memberList.filter(item => item.status === 0)
+        } else if (index === 1) {
+            this.sendMemberList = this.formValidate.memberList.filter(item => item.status === 1)
+        } else if (index === 2) {
+            this.sendMemberList = this.formValidate.memberList
+        }
+      },
+      handleShowClient() {
+        // localStorage.setItem('clientData', JSON.stringify(this.formValidate.memberList || []))
+        // window.location.href = `showClientList.html`
+      },
+      timeFormat(time, format = 'yyyy-MM-dd hh:mm:ss') {
+        if (time === undefined || time === '' || time === null) {
+          return '/';
+        }
+
+        const date = new Date(time);
+        const o = {
+          'M+': date.getMonth() + 1, // 月份
+          'd+': date.getDate(),      // 日
+          'h+': date.getHours(),     // 小时
+          'm+': date.getMinutes(),   // 分钟
+          's+': date.getSeconds(),   // 秒
+          'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
+          'S': date.getMilliseconds() // 毫秒
+        };
+
+        // 处理年份
+        if (/(y+)/.test(format)) {
+          format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
+        }
+
+        // 处理日期和时间部分
+        for (let k in o) {
+          if (new RegExp('(' + k + ')').test(format)) {
+            let value = o[k];
+            let padding = RegExp.$1.length === 1 ? '' : '00'; // 根据格式字符串中的长度决定是否补零
+            format = format.replace(RegExp.$1, ('' + value).padStart(padding.length + value.toString().length - value.toString().length, '0'));
+          }
+        }
+
+        // 如果格式只包含时间部分,移除日期部分可能的占位符
+        if (!/(M+|d+)/.test(format)) {
+          // 移除任何可能存在的日期占位符(如:'yyyy-MM-dd ')
+          format = format.replace(/(\s*-\s*){2}/g, ''); // 移除两个'-'之间的任何内容
+          format = format.replace(/^\s*yyyy-\s*/, ''); // 移除开头的'yyyy-'
+        }
+
+        // 如果格式只包含日期部分,移除时间部分可能的占位符
+        if (!/(h+|m+|s+)/.test(format)) {
+          // 移除任何可能存在的时间占位符(如:' hh:mm:ss')
+          format = format.replace(/(\s*:\s*){2}/g, ''); // 移除两个':'之间的任何内容
+          format = format.replace(/\s*hh:\s*$/, ''); // 移除结尾的' hh:'
+        }
+
+        return format;
+      },
+      // 截取url中的数据
+      getQueryParam(paramName) {
+        // 获取当前URL的查询字符串部分  
+        const queryString = window.location.search;
+        // 创建一个URLSearchParams对象  
+        const urlParams = new URLSearchParams(queryString);
+        // 返回指定参数的值,如果不存在则返回null  
+        return urlParams.get(paramName);
+      },
+    }
+  })   
+</script>
+
+</html>

+ 394 - 0
lottery/qw/pyqMassList.html

@@ -0,0 +1,394 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport"
+    content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no, viewport-fit=cover" />
+  <title>群发列表</title>
+  <!-- 引入样式文件 -->
+  <link rel="stylesheet"
+    href="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012584633/vant.css" />
+  <link rel="stylesheet" href="../css/page-return.css">
+  <!-- 必须先引入vue,  后使用vant-ui -->
+  <script
+    src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742017957144/vue.js"></script>
+  <!-- 引入vant的组件库-->
+  <!-- 引入 Vant 的 JS 文件 -->
+  <script
+    src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012748487/vant.min.js"></script>
+
+  <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
+  <script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
+  <script src="../js/page-return.js"></script>
+  <!-- <script src="js/vconsole.min.js"></script>
+    <script>
+  		  var vConsole = new window.VConsole();
+  		</script> -->
+</head>
+<style>
+  body {
+    margin: 0;
+    padding: 0;
+  }
+
+  .box {
+    width: 100vw;
+    min-height: 100vh;
+    box-sizing: border-box;
+    background: #F7F9FC;
+  }
+
+  .page5 {
+    width: 100vw;
+    box-sizing: border-box;
+    padding: 15px;
+    padding-bottom: 39px;
+  }
+
+  .client_top {
+    width: 100%;
+    height: 70px;
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: 1;
+    background: #FFFFFF;
+  }
+
+  .client_top_box {
+    padding: 15px 15px 0px;
+  }
+
+  .search_icon {
+    width: 24px;
+    height: 24px;
+  }
+
+  .search_input {
+    padding: 0;
+  }
+
+  .search_input .van-search__content {
+    padding: 0;
+    border-radius: 19px;
+  }
+
+  .search_input .van-cell {
+    padding: 0;
+  }
+
+  .search_input .van-field__body {
+    display: flex;
+    align-items: center;
+    position: relative;
+  }
+
+  .search_input .van-field__body input {
+    border: none;
+    width: 100%;
+    height: 40px;
+    background: #FAFAFA;
+    padding: 10px 36px 10px 15px;
+    border-radius: 19px;
+  }
+
+  .search_input .van-field__body input:focus {
+    outline: none;
+  }
+
+  .search_input .van-field__body .van-field__right-icon {
+    position: absolute;
+    right: 12px;
+  }
+
+  .task_list {
+    width: 100%;
+    height: calc(100vh - 109px);
+    position: absolute;
+    top: 70px;
+    left: 0;
+    z-index: 1;
+    background: #F7F9FC;
+    overflow: auto;
+    padding-bottom: 60px;
+    box-sizing: border-box;
+  }
+
+  .task_content {
+    padding: 15px;
+  }
+
+  .task_item {
+    width: 100%;
+    background: #FFFFFF;
+    border-radius: 15px;
+    border: 1px solid #FFFFFF;
+    box-sizing: border-box;
+    margin-bottom: 10px;
+    padding: 15px;
+  }
+
+  .task_item:last-child {
+    margin-bottom: 0;
+  }
+
+  .task_item_title {
+    display: flex;
+    justify-content: space-between;
+    font-weight: 500;
+    font-size: 16px;
+    color: #222222;
+    line-height: 20px;
+  }
+
+  .task_item_name {
+    width: 160px;
+    /* 必须设置宽度 */
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+  }
+
+  .client_tag {
+    font-size: 12px;
+    line-height: 17px;
+  }
+
+  .task_item_time {
+    font-size: 12px;
+    color: #999999;
+    line-height: 17px;
+    padding-top: 8px;
+  }
+
+  .notask {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding-top: 198px;
+  }
+
+  .notask img {
+    width: 102px;
+    height: 90px;
+  }
+
+  .notask_text {
+    font-size: 14px;
+    color: #CCCCCC;
+    line-height: 20px;
+    padding-top: 20px;
+  }
+
+  .send_foot {
+    position: absolute;
+    bottom: 39px;
+    left: 0;
+    width: 100%;
+    z-index: 2;
+  }
+
+  .send_btn {
+    font-weight: 500;
+    font-size: 14px;
+    color: #FFFFFF;
+    line-height: 20px;
+    padding: 15px 0;
+    border-radius: 20px;
+    background: #1677FF;
+    margin: 0 35px;
+    text-align: center;
+  }
+
+  .status1 {
+    color: #136DFB;
+  }
+
+  .status2 {
+    color: #FFA041;
+  }
+
+  .status3 {
+    color: #FF4141;
+  }
+</style>
+
+<body>
+  <div id="box" class="box">
+    <div class="page5">
+      <div>
+        <div class="client_top">
+          <div class="client_top_box">
+            <van-search class="search_input" placeholder="搜索群发名称" v-model="keyword" :clearable="false" left-icon=""
+              @search="initData">
+              <!-- 自定义右侧图标 -->
+              <template v-slot:right-icon>
+                <img class="search_icon" src="../img/qw/search_icon.png" alt="" @click="initData" />
+              </template>
+            </van-search>
+          </div>
+        </div>
+        <div class="task_list" v-if="tableData.length">
+          <div class="task_content">
+            <div class="task_item" v-for="item in tableData" :key="item.id" @click="handleClientMassDetail(item)">
+              <div class="task_item_title">
+                <div class="task_item_name">{{item.name}}</div>
+                <div v-if="item.jobStatus === -1" class="client_tag status3">创建失败</div>
+                <div v-else-if="item.jobStatus === 0" class="client_tag status2">待通知</div>
+                <div v-else-if="item.jobStatus === 1" class="client_tag status2">开始创建任务</div>
+                <div v-else-if="item.jobStatus === 2" class="client_tag status2">创建中</div>
+                <div v-else-if="item.jobStatus === 3" class="client_tag status1">已通知</div>
+              </div>
+              <div class="task_item_time">发表时间:{{item.momentTime}}</div>
+            </div>
+          </div>
+        </div>
+        <div class="send_foot">
+          <div class="send_btn" @click="handleClientMass">创建朋友圈群发</div>
+        </div>
+      </div>
+      <div class="notask" v-else>
+        <img src="../img/qw/no_task.png" alt="">
+        <div class="notask_text">暂无数据</div>
+      </div>
+    </div>
+    <!-- 底部返回栏 -->
+    <page-return></page-return>
+  </div>
+</body>
+<script>
+  new Vue({
+    el: '#box',
+    data() {
+      return {
+        httpUrl: '',
+        bId: null,
+        env: '',
+        token: null,
+        tenancyId: null,
+        userId: null,
+        memberId: null,
+        keyword: '',
+        tableData: [],
+      }
+    },
+    created() {
+      this.bId = this.getQueryParam('bId')
+      this.env = this.getQueryParam('env')
+      this.memberId = this.getQueryParam('memberId')
+
+      if (!this.env || this.env === 'prod') {
+        this.httpUrl = 'https://wlapi.wefanbot.com'
+      } else {
+        this.httpUrl = 'http://test.wefanbot.com:18993'
+      }
+      this.token = localStorage.getItem('tokenValue')
+      this.tenancyId = localStorage.getItem('tenancyIdValue')
+      this.userId = localStorage.getItem('userId')
+      this.initData()
+    },
+    methods: {
+      initData() {
+        const headers = new Headers()
+        headers.append('token', this.token)
+        headers.append('tenancyId', this.tenancyId)
+        headers.append('userId', this.userId)
+        fetch(this.httpUrl + '/scrm/v1/wxcp-moment/m/findListByPage', {
+          method: 'post',
+          body: JSON.stringify({
+            keyword: this.keyword,
+            createType: 0,
+            page: 1,
+            pageCount: 1000,
+          }),
+          headers: {
+            'Content-Type': 'application/json',
+            'token': this.token,
+            'tenancyId': this.tenancyId,
+            'userId': this.userId,
+          }
+        }).then(res => {
+          return res.json()
+        }).then(result => {
+          let { data, code, msg } = result
+          if (code === 1) {
+            this.tableData = data.records || []
+            this.tableData.forEach(item => {
+              item.momentTime = this.timeFormat(item.momentTime)
+            })
+          } else {
+            vant.Toast.fail(msg)
+          }
+        })
+      },
+      onSearch() {
+        this.initData()
+      },
+      handleClientMassDetail(item) {
+        window.location.href = `pyqMassDetail.html?bId=${this.bId}&env=${this.env}&id=${item.id}`
+      },
+      handleClientMass() {
+        window.location.href = `pyqMass.html?bId=${this.bId}&env=${this.env}&memberId=${this.memberId}`
+      },
+      timeFormat(time, format = 'yyyy-MM-dd hh:mm:ss') {
+        if (time === undefined || time === '' || time === null) {
+          return '/';
+        }
+
+        const date = new Date(time);
+        const o = {
+          'M+': date.getMonth() + 1, // 月份
+          'd+': date.getDate(),      // 日
+          'h+': date.getHours(),     // 小时
+          'm+': date.getMinutes(),   // 分钟
+          's+': date.getSeconds(),   // 秒
+          'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
+          'S': date.getMilliseconds() // 毫秒
+        };
+
+        // 处理年份
+        if (/(y+)/.test(format)) {
+          format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
+        }
+
+        // 处理日期和时间部分
+        for (let k in o) {
+          if (new RegExp('(' + k + ')').test(format)) {
+            let value = o[k];
+            let padding = RegExp.$1.length === 1 ? '' : '00'; // 根据格式字符串中的长度决定是否补零
+            format = format.replace(RegExp.$1, ('' + value).padStart(padding.length + value.toString().length - value.toString().length, '0'));
+          }
+        }
+
+        // 如果格式只包含时间部分,移除日期部分可能的占位符
+        if (!/(M+|d+)/.test(format)) {
+          // 移除任何可能存在的日期占位符(如:'yyyy-MM-dd ')
+          format = format.replace(/(\s*-\s*){2}/g, ''); // 移除两个'-'之间的任何内容
+          format = format.replace(/^\s*yyyy-\s*/, ''); // 移除开头的'yyyy-'
+        }
+
+        // 如果格式只包含日期部分,移除时间部分可能的占位符
+        if (!/(h+|m+|s+)/.test(format)) {
+          // 移除任何可能存在的时间占位符(如:' hh:mm:ss')
+          format = format.replace(/(\s*:\s*){2}/g, ''); // 移除两个':'之间的任何内容
+          format = format.replace(/\s*hh:\s*$/, ''); // 移除结尾的' hh:'
+        }
+
+        return format;
+      },
+      // 截取url中的数据
+      getQueryParam(paramName) {
+        // 获取当前URL的查询字符串部分  
+        const queryString = window.location.search;
+        // 创建一个URLSearchParams对象  
+        const urlParams = new URLSearchParams(queryString);
+        // 返回指定参数的值,如果不存在则返回null  
+        return urlParams.get(paramName);
+      },
+    }
+  })   
+</script>
+
+</html>

+ 6 - 0
lottery/qw/showClientList.html

@@ -178,7 +178,13 @@
     created() {
       this.clientsList = localStorage.getItem('clientData') ? JSON.parse(localStorage.getItem('clientData')) : []
     },
+    mounted() {
+      window.addEventListener('beforeunload', e => this.beforeunloadFn(e))
+    },
     methods: {
+      beforeunloadFn(e) {
+        localStorage.removeItem('clientData')
+      },
       // 截取url中的数据
       getQueryParam(paramName) {
         // 获取当前URL的查询字符串部分  

+ 9 - 4
lottery/userProfile.html

@@ -10,7 +10,8 @@
   <!--引入 element-ui 的样式,-->
   <link rel="stylesheet"
     href="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742018383195/element-ui.css">
-  <!-- 必须先引入vue,  后使用element-ui -->
+  <link rel="stylesheet" href="css/page-return.css">
+    <!-- 必须先引入vue,  后使用element-ui -->
   <script
     src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742017957144/vue.js"></script>
   <!-- 引入element 的组件库-->
@@ -18,7 +19,8 @@
     src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742017747738/element-ui.js"></script>
   <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
   <script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
-    <script src="js/vconsole.min.js"></script>
+  <script src="js/page-return.js"></script>
+  <script src="js/vconsole.min.js"></script>
   <script>
 		  var vConsole = new window.VConsole();
 		</script>
@@ -39,6 +41,7 @@
   .page6 {
     width: 100vw;
     box-sizing: border-box;
+    padding-bottom: 39px;
   }
   .tab_list {
     width: 100%;
@@ -175,7 +178,7 @@
   }
   .client_followUp {
     width: 100vw;
-    height: calc(100vh - 48px);
+    height: calc(100vh - 48px - 39px);
     padding: 20px 10px 60px;
     box-sizing: border-box;
     overflow-y: auto;
@@ -340,7 +343,7 @@
   
   .foot_btn {
     position: fixed;
-    bottom: 10px;
+    bottom: 49px;
     padding: 0 35px;
     width: 100%;
     box-sizing: border-box;
@@ -623,6 +626,8 @@
         </div>
       </div>
     </div>
+    <!-- 底部返回栏 -->
+    <page-return></page-return>
     <el-dialog title="添加客户跟进" :visible.sync="showDialog">
       <el-form :model="form" class="prize_form">
         <el-form-item label="跟进方式:" required>