吴树波 vor 46 Minuten
Ursprung
Commit
41e1597230

+ 10 - 1
src/api/wx/wxSop.js

@@ -58,4 +58,13 @@ export function updateWxStatus(ids) {
     url: '/qw/sop/updateWxStatus/' + ids,
     method: 'get'
   })
-}
+}
+
+// 个微SOP一键群发
+export function sendWxSopMsg(data) {
+  return request({
+    url: '/wx/wxSop/sendMsg',
+    method: 'post',
+    data: data
+  })
+}

+ 89 - 59
src/views/company/wxAccount/index.vue

@@ -1,57 +1,86 @@
 <template>
-    <div class="app-container">
-        <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-            <el-form-item label="微信昵称" prop="wxNickName">
-                <el-input
-                    v-model="queryParams.wxNickName"
-                    placeholder="请输入微信昵称"
-                    clearable
-                    size="small"
-                    @keyup.enter.native="handleQuery"
-                />
-            </el-form-item>
-            <el-form-item label="微信号" prop="wxNo">
-                <el-input
-                    v-model="queryParams.wxNo"
-                    placeholder="请输入微信号"
-                    clearable
-                    size="small"
-                    @keyup.enter.native="handleQuery"
-                />
-            </el-form-item>
-            <el-form-item label="手机号" prop="wxNo">
-                <el-input
-                    :maxlength="11"
-                    v-model="queryParams.phone"
-                    placeholder="请输入手机号"
-                    clearable
-                    size="small"
-                    @keyup.enter.native="handleQuery"
-                />
-            </el-form-item>
-            <el-form-item label="员工" prop="companyUserId">
-                <el-select v-model="queryParams.companyUserId" clearable>
-                    <el-option v-for="item in qwUserList" :label="item.nickName" :value="item.userId" />
-                </el-select>
-            </el-form-item>
-            <el-form-item>
-                <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-                <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-            </el-form-item>
-        </el-form>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="微信昵称" prop="wxNickName">
+        <el-input
+          v-model="queryParams.wxNickName"
+          placeholder="请输入微信昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="微信号" prop="wxNo">
+        <el-input
+          v-model="queryParams.wxNo"
+          placeholder="请输入微信号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="手机号" prop="wxNo">
+        <el-input
+          :maxlength="11"
+          v-model="queryParams.phone"
+          placeholder="请输入手机号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="员工" prop="companyUserId">
+        <el-select v-model="queryParams.companyUserId" clearable>
+          <el-option v-for="item in qwUserList" :label="item.qwUserName" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
 
-        <el-row :gutter="10" class="mb8">
-            <el-col :span="1.5">
-                <el-button
-                    type="primary"
-                    icon="el-icon-plus"
-                    size="mini"
-                    @click="handleAdd"
-                    v-hasPermi="['company:companyWx:add']"
-                >新增</el-button>
-            </el-col>
-            <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-        </el-row>
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['company:companyWx:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['company:companyWx:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['company:companyWx:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['company:companyWx:export']"
+        >导出</el-button>
+      </el-col>
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
 
         <el-table v-loading="loading" :data="companyAccountList" @selection-change="handleSelectionChange">
             <el-table-column label="微信昵称" align="center" prop="wxNickName" />
@@ -124,13 +153,13 @@
             </el-table-column>
         </el-table>
 
-        <pagination
-            v-show="total>0"
-            :total="total"
-            :page.sync="queryParams.pageNum"
-            :limit.sync="queryParams.pageSize"
-            @pagination="getList"
-        />
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
 
     <!-- 添加或修改个微账号对话框 -->
     <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
@@ -238,6 +267,7 @@ import {
     wxLoginOut,
     bindService
 } from '@/api/company/companyAccount'
+import {getAllUserlist} from "@/api/company/companyUser";
 import { qrCodeStatus } from '@/api/qw/user'
 import { listWxContact } from "@/api/wx/wxContact"
 import { listWxMsgLog } from "@/api/wx/wxMsgLog"

+ 2 - 2
src/views/gw/gwAccount/index.vue

@@ -199,7 +199,7 @@
     </el-dialog>
 
     <!-- 联系人列表弹窗 -->
-    <el-drawer title="联系人列表" :visible.sync="contactOpen" width="800px" append-to-body >
+    <el-dialog title="联系人列表" :visible.sync="contactOpen" width="800px" append-to-body>
       <el-table :data="contactList">
         <el-table-column label="头像" align="center" width="70">
           <template slot-scope="scope">
@@ -234,7 +234,7 @@
         :limit.sync="contactQueryParams.pageSize"
         @pagination="getContactList"
       />
-    </el-drawer>
+    </el-dialog>
 
     <!-- 聊天记录弹窗 -->
     <el-dialog :title="'聊天记录 - ' + (currentContact.nickName || '')" :visible.sync="chatOpen" width="700px" append-to-body>

+ 135 - 15
src/views/wx/wxSop/index.vue

@@ -93,6 +93,16 @@
           v-hasPermi="['qw:sop:batchExecuteWx']"
         >批量执行个微SOP</el-button>
       </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-s-promotion"
+          size="mini"
+          :disabled="multiple"
+          @click="handleSendMsg"
+        >SOP营期一键群发</el-button>
+      </el-col>
     </el-row>
 
     <el-table border v-loading="loading" :data="wxSopList" @selection-change="handleSelectionChange">
@@ -361,18 +371,87 @@
 
       <qw-user-select @success="selectQwUserFun" ref="qwUserSelect" />
     </el-dialog>
+
+    <!-- 一键群发弹窗 -->
+    <el-dialog title="一键批量群发" :visible.sync="sendMsgOpen" width="600px" append-to-body>
+      <el-alert
+        title="此功能用于给 选中的 SOP营期 内【所有的】客户 发送 消息"
+        type="error"
+        :closable="false"
+        show-icon
+        style="margin-bottom: 20px;"
+      />
+
+      <el-form label-width="80px">
+        <el-form-item label="规则">
+          <div style="border: 1px solid #DCDFE6; border-radius: 4px; padding: 15px;">
+            <div style="margin-bottom: 10px;">
+              <span style="margin-right: 10px;">内容类别</span>
+              <el-radio :value="'1'" :label="'1'" disabled>文本</el-radio>
+            </div>
+            <el-form-item label="内容" label-width="60px" style="margin-bottom: 0;">
+              <el-input
+                v-model="sendMsgForm.content"
+                type="textarea"
+                :rows="4"
+                placeholder="内容"
+                maxlength="500"
+                show-word-limit
+              />
+              <div style="margin-top: 8px;">
+                <el-link type="primary" :underline="false" @click="addPlaceholder('#销售称呼#')">添加#销售称呼#</el-link>
+                <span style="margin: 0 10px;"></span>
+                <el-link type="primary" :underline="false" @click="addPlaceholder('#客户称呼#')">添加#客户称呼#</el-link>
+              </div>
+            </el-form-item>
+          </div>
+        </el-form-item>
+
+        <el-form-item label="发送时间">
+          <el-time-picker
+            v-model="sendMsgForm.sendTime"
+            format="HH:mm"
+            value-format="HH:mm"
+            placeholder="时间"
+            size="small"
+            style="width: 120px;"
+          />
+          <span style="margin-left: 10px; color: #909399; font-size: 13px;">不填时,默认为系统当前时间(立即发送)</span>
+        </el-form-item>
+      </el-form>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitSendMsg">确 定</el-button>
+        <el-button @click="sendMsgOpen = false">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 执行详情抽屉 -->
+    <el-drawer
+      :title="'执行详情 - ' + (detailRow ? detailRow.name : '')"
+      :visible.sync="detailDrawerVisible"
+      direction="rtl"
+      size="75%"
+      destroy-on-close
+    >
+      <sop-logs-list
+        v-if="detailDrawerVisible && detailRow"
+        :row-detail-from="detailRow"
+      />
+    </el-drawer>
   </div>
 </template>
 
 <script>
-import { listWxSop, getWxSop, delWxSop, addWxSop, updateWxSop, exportWxSop, updateWxStatus } from "@/api/wx/wxSop";
+import { listWxSop, getWxSop, delWxSop, addWxSop, updateWxSop, exportWxSop, updateWxStatus, sendWxSopMsg } from "@/api/wx/wxSop";
 import { listSopTemp } from "@/api/qw/sopTemp";
 import Tip from "@/components/Tip";
 import QwUserSelect from "@/views/components/QwUserSelect.vue";
+import SopLogsList from "./sopLogsList.vue";
 
 export default {
   name: "WxSop",
-  components: { Tip, QwUserSelect },
+  components: { Tip, QwUserSelect, SopLogsList },
   data() {
     return {
       // 遮罩层
@@ -426,6 +505,15 @@ export default {
         { dictValue: "0", dictLabel: "否" },
         { dictValue: "1", dictLabel: "是" },
       ],
+      // 执行详情抽屉
+      detailDrawerVisible: false,
+      detailRow: null,
+      // 一键群发
+      sendMsgOpen: false,
+      sendMsgForm: {
+        content: '',
+        sendTime: null
+      },
       // 表单参数
       form: {},
       // 表单校验
@@ -613,13 +701,8 @@ export default {
     },
     /** 查看执行详情按钮操作 */
     handleViewDetail(row) {
-      this.$router.push({
-        path: '/wxSop/wxSop/sopLogsList/' + row.id,
-        query: {
-          name: row.name,
-          tempId: row.tempId
-        }
-      });
+      this.detailRow = row;
+      this.detailDrawerVisible = true;
     },
     /** 删除按钮操作 */
     handleDelete(row) {
@@ -643,7 +726,7 @@ export default {
       }
 
       // 过滤出启用状态的SOP
-      const enabledSops = this.wxSopList.filter(item => 
+      const enabledSops = this.wxSopList.filter(item =>
         this.ids.includes(item.id) && item.status === 1
       );
 
@@ -670,25 +753,25 @@ export default {
         return updateWxStatus(enabledIds.join(","));
       }).then(response => {
         this.loading = false;
-        
+
         console.log('批量执行个微SOP接口返回数据:', response);
-        
+
         // 解析后端返回的统计信息
         if (response && response.msg) {
           const successCount = response.data?.successCount || enabledIds.length;
           const failCount = response.data?.failCount || 0;
-          
+
           let msg = `批量执行完成!`;
           msg += `\n成功:${successCount}条`;
           if (failCount > 0) {
             msg += `\n失败:${failCount}条`;
           }
-          
+
           this.msgSuccess(msg);
         } else {
           this.msgSuccess(`已成功执行${enabledIds.length}条个微SOP`);
         }
-        
+
         // 刷新列表
         this.getList();
       }).catch(error => {
@@ -699,6 +782,43 @@ export default {
         }
       });
     },
+    /** 一键群发按钮操作 */
+    handleSendMsg() {
+      if (this.ids.length === 0) {
+        this.$message.warning("请至少选择一条SOP记录");
+        return;
+      }
+      this.sendMsgForm.content = '';
+      this.sendMsgForm.sendTime = null;
+      this.sendMsgOpen = true;
+    },
+    /** 添加占位符 */
+    addPlaceholder(text) {
+      this.sendMsgForm.content += text;
+    },
+    /** 提交一键群发 */
+    submitSendMsg() {
+      if (!this.sendMsgForm.content || !this.sendMsgForm.content.trim()) {
+        this.$message.warning("请输入发送内容");
+        return;
+      }
+
+      this.$confirm('确认对选中的SOP营期内所有客户发送消息吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        const param = {
+          sopIds: this.ids,
+          setting: JSON.stringify([{ contentType: '1', value: this.sendMsgForm.content }]),
+          sendTime: this.sendMsgForm.sendTime || ''
+        };
+        sendWxSopMsg(param).then(response => {
+          this.msgSuccess("一键群发成功");
+          this.sendMsgOpen = false;
+        });
+      }).catch(() => {});
+    },
     handleExport() {
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有个微SOP数据项?', "警告", {

+ 381 - 272
src/views/wx/wxSop/sopLogsList.vue

@@ -1,295 +1,404 @@
 <template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
-      <el-form-item label="个微账号昵称" prop="accountName">
-        <el-input
-          v-model="queryParams.accountName"
-          placeholder="请输入个微账号昵称"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="客户昵称" prop="wxContactName">
-        <el-input
-          v-model="queryParams.wxContactName"
-          placeholder="请输入客户昵称"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="发送状态" prop="sendStatus">
-        <el-select v-model="queryParams.sendStatus" placeholder="请选择发送状态" clearable size="small">
-          <el-option
-            v-for="dict in sendStatusOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="发送类型" prop="sendType">
-        <el-select v-model="queryParams.sendType" placeholder="请选择发送类型" clearable size="small">
-          <el-option
-            v-for="dict in sysQwSopType"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="消息类型" prop="type">
-        <el-select v-model="queryParams.type" placeholder="请选择消息类型" clearable size="small">
-          <el-option label="个人" :value="0" />
-          <el-option label="群" :value="1" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="预计发送时间" prop="scheduleTime">
-        <el-date-picker
-          clearable
-          size="small"
-          v-model="scheduleTime"
-          type="datetimerange"
-          range-separator="至"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
-          placeholder="选择预计发送时间"
-          @change="handleScheduleTimeChange"
-        >
-        </el-date-picker>
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
+    <div class="app-container">
+        <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
+            <el-form-item label="个微账号昵称" prop="accountName">
+                <el-input
+                    v-model="queryParams.accountName"
+                    placeholder="请输入个微账号昵称"
+                    clearable
+                    size="small"
+                    @keyup.enter.native="handleQuery"
+                />
+            </el-form-item>
+            <el-form-item label="客户昵称" prop="wxContactName">
+                <el-input
+                    v-model="queryParams.wxContactName"
+                    placeholder="请输入客户昵称"
+                    clearable
+                    size="small"
+                    @keyup.enter.native="handleQuery"
+                />
+            </el-form-item>
+            <el-form-item label="发送状态" prop="sendStatus">
+                <el-select v-model="queryParams.sendStatus" placeholder="请选择发送状态" clearable size="small">
+                    <el-option
+                        v-for="dict in sendStatusOptions"
+                        :key="dict.dictValue"
+                        :label="dict.dictLabel"
+                        :value="dict.dictValue"
+                    />
+                </el-select>
+            </el-form-item>
+            <el-form-item label="发送类型" prop="sendType">
+                <el-select v-model="queryParams.sendType" placeholder="请选择发送类型" clearable size="small">
+                    <el-option
+                        v-for="dict in sysQwSopType"
+                        :key="dict.dictValue"
+                        :label="dict.dictLabel"
+                        :value="dict.dictValue"
+                    />
+                </el-select>
+            </el-form-item>
+            <el-form-item label="消息类型" prop="type">
+                <el-select v-model="queryParams.type" placeholder="请选择消息类型" clearable size="small">
+                    <el-option label="个人" :value="0"/>
+                    <el-option label="群" :value="1"/>
+                </el-select>
+            </el-form-item>
+            <el-form-item label="预计发送时间" prop="scheduleTime">
+                <el-date-picker
+                    clearable
+                    size="small"
+                    v-model="scheduleTime"
+                    type="datetimerange"
+                    range-separator="至"
+                    start-placeholder="开始日期"
+                    end-placeholder="结束日期"
+                    placeholder="选择预计发送时间"
+                    @change="handleScheduleTimeChange"
+                >
+                </el-date-picker>
+            </el-form-item>
+            <el-form-item>
+                <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+                <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+            </el-form-item>
+        </el-form>
+
+        <el-row :gutter="10" class="mb8">
+            <el-col :span="1.5">
+                <el-button
+                    type="warning"
+                    plain
+                    icon="el-icon-download"
+                    size="mini"
+                    :loading="exportLoading"
+                    @click="handleExport"
+                    v-hasPermi="['wx:wxSopLogs:export']"
+                >导出
+                </el-button>
+            </el-col>
+            <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
 
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          :loading="exportLoading"
-          @click="handleExport"
-          v-hasPermi="['wx:wxSopLogs:export']"
-        >导出</el-button>
-      </el-col>
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
+        <el-table border v-loading="loading" :data="wxSopLogsList">
+            <el-table-column label="编号" align="center" prop="id" width="80"/>
+            <el-table-column label="个微账号昵称" align="center" prop="accountName"/>
+            <el-table-column label="客户昵称" align="center" prop="wxContactName"/>
+            <el-table-column label="客户标签" align="center" prop="tagNames" show-overflow-tooltip>
+                <template slot-scope="scope">
+                    <span v-if="scope.row.tagNames">{{ scope.row.tagNames }}</span>
+                    <span v-else style="color: #909399;">-</span>
+                </template>
+            </el-table-column>
+            <el-table-column label="发送状态" align="center" prop="sendStatus" width="100">
+                <template slot-scope="scope">
+                    <el-tag type="info" v-if="scope.row.sendStatus === 0">待发送</el-tag>
+                    <el-tag type="success" v-else-if="scope.row.sendStatus === 1">发送成功</el-tag>
+                    <el-tag type="danger" v-else-if="scope.row.sendStatus === 2">发送失败</el-tag>
+                    <el-tag type="warning" v-else-if="scope.row.sendStatus === 3">消息作废</el-tag>
+                    <el-tag v-else>未知</el-tag>
+                </template>
+            </el-table-column>
+            <el-table-column label="发送类型" align="center" prop="sendType" width="100">
+                <template slot-scope="scope">
+                    <dict-tag :options="sysQwSopType" :value="scope.row.sendType"/>
+                </template>
+            </el-table-column>
+            <el-table-column label="生成类型" align="center" prop="generateType" width="100">
+                <template slot-scope="scope">
+                    <el-tag type="success" v-if="scope.row.generateType === 0">自动</el-tag>
+                    <el-tag type="primary" v-else-if="scope.row.generateType === 1">手动</el-tag>
+                    <el-tag v-else>未知</el-tag>
+                </template>
+            </el-table-column>
+            <el-table-column label="生成时间" align="center" prop="createTime" width="165"/>
+            <el-table-column label="预计发送时间" align="center" prop="sendTime" width="165">
+                <template slot-scope="scope">
+                    <span v-if="scope.row.sendTime">{{ scope.row.sendTime }}</span>
+                    <span v-else style="color: #909399;">-</span>
+                </template>
+            </el-table-column>
+            <el-table-column label="实际发送时间" align="center" prop="realSendTime" width="165">
+                <template slot-scope="scope">
+                    <span v-if="scope.row.realSendTime">{{ scope.row.realSendTime }}</span>
+                    <span v-else style="color: #909399;">-</span>
+                </template>
+            </el-table-column>
+            <el-table-column label="操作" align="center" width="100">
+                <template slot-scope="scope">
+                    <el-button
+                        v-if="scope.row.contentJson"
+                        type="text"
+                        size="mini"
+                        @click="showContentDialog(scope.row.contentJson)"
+                    >查看详情
+                    </el-button>
+                    <span v-else style="color: #909399;">-</span>
+                </template>
+            </el-table-column>
+        </el-table>
 
-    <el-table border v-loading="loading" :data="wxSopLogsList">
-      <el-table-column label="编号" align="center" prop="id" width="80" />
-      <el-table-column label="个微账号昵称" align="center" prop="accountName" />
-      <el-table-column label="客户昵称" align="center" prop="wxContactName" />
-      <el-table-column label="客户标签" align="center" prop="tagNames" show-overflow-tooltip>
-        <template slot-scope="scope">
-          <span v-if="scope.row.tagNames">{{ scope.row.tagNames }}</span>
-          <span v-else style="color: #909399;">-</span>
-        </template>
-      </el-table-column>
-      <el-table-column label="发送状态" align="center" prop="sendStatus" width="100">
-        <template slot-scope="scope">
-          <el-tag type="info" v-if="scope.row.sendStatus === 0">待发送</el-tag>
-          <el-tag type="success" v-else-if="scope.row.sendStatus === 1">发送成功</el-tag>
-          <el-tag type="danger" v-else-if="scope.row.sendStatus === 2">发送失败</el-tag>
-          <el-tag type="warning" v-else-if="scope.row.sendStatus === 3">消息作废</el-tag>
-          <el-tag v-else>未知</el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column label="发送类型" align="center" prop="sendType" width="100">
-        <template slot-scope="scope">
-          <dict-tag :options="sysQwSopType" :value="scope.row.sendType"/>
-        </template>
-      </el-table-column>
-      <el-table-column label="生成类型" align="center" prop="generateType" width="100">
-        <template slot-scope="scope">
-          <el-tag type="success" v-if="scope.row.generateType === 0">自动</el-tag>
-          <el-tag type="primary" v-else-if="scope.row.generateType === 1">手动</el-tag>
-          <el-tag v-else>未知</el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column label="生成时间" align="center" prop="createTime" width="165" />
-      <el-table-column label="实际发送时间" align="center" prop="realSendTime" width="165">
-        <template slot-scope="scope">
-          <span v-if="scope.row.realSendTime">{{ scope.row.realSendTime }}</span>
-          <span v-else style="color: #909399;">-</span>
-        </template>
-      </el-table-column>
-      <el-table-column label="消息过期时间" align="center" prop="expirationTime" width="165">
-        <template slot-scope="scope">
-          <span v-if="scope.row.expirationTime">{{ scope.row.expirationTime }}</span>
-          <span v-else style="color: #909399;">-</span>
-        </template>
-      </el-table-column>
-      <el-table-column label="发送备注" align="center" prop="sendRemark" show-overflow-tooltip>
-        <template slot-scope="scope">
-          <span v-if="scope.row.sendRemark">{{ scope.row.sendRemark }}</span>
-          <span v-else style="color: #909399;">-</span>
-        </template>
-      </el-table-column>
-    </el-table>
+        <!-- 消息详情弹窗 -->
+        <el-dialog title="发送消息详情" :visible.sync="contentDialogVisible" width="800px" append-to-body>
+            <div v-if="contentDialogData && contentDialogData.length > 0" class="content-detail">
+                <div v-for="(item, index) in contentDialogData" :key="index" class="content-item">
+                    <div class="content-type-tag">
+                        <el-tag size="small" :type="getContentTypeTag(item.contentType).type">
+                            {{ getContentTypeTag(item.contentType).label }}
+                        </el-tag>
+                        <el-tag
+                            v-if="item.sendStatus !== undefined && item.sendStatus !== null"
+                            size="small"
+                            :type="item.sendStatus === 1 ? 'success' : item.sendStatus === 2 ? 'danger' : 'warning'"
+                            style="margin-left: 8px;"
+                        >
+                            {{ item.sendStatus === 0 ? '待发送' : item.sendStatus === 1 ? '发送成功' : '发送失败' }}
+                        </el-tag>
+                    </div>
+                    <div v-if="item.sendStatus === 2 && item.sendRemarks" style="color: #F56C6C; font-size: 13px; margin-bottom: 8px;">
+                        <i class="el-icon-warning-outline"></i> {{ item.sendRemarks }}
+                    </div>
+                    <div class="content-body">
+                        <!-- 文本内容 -->
+                        <div v-if="item.contentType === '1' || item.contentType === 1" class="text-content">
+                            {{ item.value }}
+                        </div>
+                        <!-- 图片 -->
+                        <div v-else-if="item.contentType === '2' || item.contentType === 2">
+                            <el-image :src="item.imgUrl || item.value" style="max-width: 200px; max-height: 200px;"
+                                      fit="contain"
+                            />
+                        </div>
+                        <!-- 其他类型显示JSON -->
+                        <div v-else class="text-content">
+                            <pre style="white-space: pre-wrap; word-break: break-all; margin: 0;"
+                            >{{ JSON.stringify(item, null, 2) }}</pre>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div v-else style="text-align: center; color: #909399; padding: 20px;">暂无消息内容</div>
+        </el-dialog>
 
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNum"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
-  </div>
+        <pagination
+            v-show="total>0"
+            :total="total"
+            :page.sync="queryParams.pageNum"
+            :limit.sync="queryParams.pageSize"
+            @pagination="getList"
+        />
+    </div>
 </template>
 
 <script>
-import { listWxSopLogsCVO, exportWxSopLogsCVO } from "@/api/wx/wxSopLogs";
+import { listWxSopLogsCVO, exportWxSopLogsCVO } from '@/api/wx/wxSopLogs'
 
 export default {
-  name: "WxSopLogsList",
-  props: {
-    rowDetailFrom: {
-      type: Object,
-      default: () => ({})
-    }
-  },
-  watch: {
-    rowDetailFrom: {
-      handler(newVal) {
-        // 当formData变化时重新查询
-        this.getList(newVal);
-      },
-      deep: true
-    }
-  },
-  data() {
-    return {
-      // 时间选择
-      scheduleTime: null,
-      // 遮罩层
-      loading: true,
-      // 导出遮罩层
-      exportLoading: false,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // 个微SOP执行详情表格数据
-      wxSopLogsList: [],
-      // 发送状态字典
-      sendStatusOptions: [
-        { dictValue: '0', dictLabel: '待发送', listClass: 'default' },
-        { dictValue: '1', dictLabel: '发送成功', listClass: 'success' },
-        { dictValue: '2', dictLabel: '发送失败', listClass: 'danger' },
-        { dictValue: '3', dictLabel: '消息作废', listClass: 'warning' }
-      ],
-      // 企微SOP发送类型
-      sysQwSopType: [],
-      // 查询参数
-      queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        sopId: null,
-        accountName: null,
-        wxContactName: null,
-        sendStatus: null,
-        sendType: null,
-        type: null,
-        scheduleStartTime: null,
-        scheduleEndTime: null
-      }
-    };
-  },
-  created() {
-    this.getList(this.rowDetailFrom);
-    
-    // 发送消息类型
-    this.getDicts("sys_qw_sop_course_type").then(response => {
-      this.sysQwSopType = response.data;
-    });
-  },
-  methods: {
-    /** 查询个微SOP执行详情列表 */
-    getList(val) {
-      this.queryParams.sopId = val?.id || this.rowDetailFrom?.id;
-      this.loading = true;
-
-      listWxSopLogsCVO(this.queryParams).then(response => {
-        console.log('个微SOP执行详情接口返回数据:', response);
-        this.wxSopLogsList = response.rows;
-        this.total = response.total;
-        this.loading = false;
-      }).catch(error => {
-        console.error('查询个微SOP执行详情失败:', error);
-        this.loading = false;
-      });
+    name: 'WxSopLogsList',
+    props: {
+        rowDetailFrom: {
+            type: Object,
+            default: () => ({})
+        }
+    },
+    watch: {
+        rowDetailFrom: {
+            handler(newVal) {
+                // 当formData变化时重新查询
+                this.getList(newVal)
+            },
+            deep: true
+        }
+    },
+    data() {
+        return {
+            // 时间选择
+            scheduleTime: null,
+            // 遮罩层
+            loading: true,
+            // 导出遮罩层
+            exportLoading: false,
+            // 显示搜索条件
+            showSearch: true,
+            // 总条数
+            total: 0,
+            // 个微SOP执行详情表格数据
+            wxSopLogsList: [],
+            // 发送状态字典
+            sendStatusOptions: [
+                { dictValue: '0', dictLabel: '待发送', listClass: 'default' },
+                { dictValue: '1', dictLabel: '发送成功', listClass: 'success' },
+                { dictValue: '2', dictLabel: '发送失败', listClass: 'danger' },
+                { dictValue: '3', dictLabel: '消息作废', listClass: 'warning' }
+            ],
+            // 企微SOP发送类型
+            sysQwSopType: [],
+            // 消息详情弹窗
+            contentDialogVisible: false,
+            contentDialogData: [],
+            // 查询参数
+            queryParams: {
+                pageNum: 1,
+                pageSize: 10,
+                sopId: null,
+                accountName: null,
+                wxContactName: null,
+                sendStatus: null,
+                sendType: null,
+                type: null,
+                scheduleStartTime: null,
+                scheduleEndTime: null
+            }
+        }
     },
+    created() {
+        this.getList(this.rowDetailFrom)
 
-    handleScheduleTimeChange(val) {
-      if (val) {
-        this.queryParams.scheduleStartTime = this.formatDateTime(val[0]);
-        this.queryParams.scheduleEndTime = this.formatDateTime(val[1]);
-      } else {
-        this.queryParams.scheduleStartTime = null;
-        this.queryParams.scheduleEndTime = null;
-      }
+        // 发送消息类型
+        this.getDicts('sys_qw_sop_course_type').then(response => {
+            this.sysQwSopType = response.data
+        })
     },
+    methods: {
+        /** 查询个微SOP执行详情列表 */
+        getList(val) {
+            this.queryParams.sopId = val?.id || this.rowDetailFrom?.id
+            this.loading = true
 
-    // 格式化日期为 yyyy-MM-dd HH:mm:ss 的北京时间
-    formatDateTime(date) {
-      if (!date) return null;
+            listWxSopLogsCVO(this.queryParams).then(response => {
+                console.log('个微SOP执行详情接口返回数据:', response)
+                this.wxSopLogsList = response.rows
+                this.total = response.total
+                this.loading = false
+            }).catch(error => {
+                console.error('查询个微SOP执行详情失败:', error)
+                this.loading = false
+            })
+        },
 
-      const options = {
-        timeZone: 'Asia/Shanghai',
-        year: 'numeric',
-        month: '2-digit',
-        day: '2-digit',
-        hour: '2-digit',
-        minute: '2-digit',
-        second: '2-digit',
-        hour12: false,
-      };
+        handleScheduleTimeChange(val) {
+            if (val) {
+                this.queryParams.scheduleStartTime = this.formatDateTime(val[0])
+                this.queryParams.scheduleEndTime = this.formatDateTime(val[1])
+            } else {
+                this.queryParams.scheduleStartTime = null
+                this.queryParams.scheduleEndTime = null
+            }
+        },
 
-      const formattedDate = new Intl.DateTimeFormat('zh-CN', options).format(new Date(date));
-      const [datePart, timePart] = formattedDate.replace(',', '').split(' ');
-      return `${datePart} ${timePart}`;
-    },
+        // 格式化日期为 yyyy-MM-dd HH:mm:ss 的北京时间
+        formatDateTime(date) {
+            if (!date) return null
 
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList(this.rowDetailFrom);
-    },
+            const options = {
+                timeZone: 'Asia/Shanghai',
+                year: 'numeric',
+                month: '2-digit',
+                day: '2-digit',
+                hour: '2-digit',
+                minute: '2-digit',
+                second: '2-digit',
+                hour12: false
+            }
 
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.resetForm("queryForm");
-      this.queryParams.scheduleStartTime = null;
-      this.queryParams.scheduleEndTime = null;
-      this.scheduleTime = null;
-      this.handleQuery();
-    },
+            const formattedDate = new Intl.DateTimeFormat('zh-CN', options).format(new Date(date))
+            const [datePart, timePart] = formattedDate.replace(',', '').split(' ')
+            return `${datePart} ${timePart}`
+        },
+
+        /** 搜索按钮操作 */
+        handleQuery() {
+            this.queryParams.pageNum = 1
+            this.getList(this.rowDetailFrom)
+        },
+
+        /** 重置按钮操作 */
+        resetQuery() {
+            this.resetForm('queryForm')
+            this.queryParams.scheduleStartTime = null
+            this.queryParams.scheduleEndTime = null
+            this.scheduleTime = null
+            this.handleQuery()
+        },
 
-    /** 导出按钮操作 */
-    handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有个微SOP执行详情数据项?', "警告", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning"
-      }).then(() => {
-        this.exportLoading = true;
-        return exportWxSopLogsCVO(queryParams);
-      }).then(response => {
-        this.download(response.msg);
-        this.exportLoading = false;
-      }).catch(() => {
-        this.exportLoading = false;
-      });
+        /** 显示消息详情弹窗 */
+        showContentDialog(contentJson) {
+            if (!contentJson) return
+            try {
+                const sanitizedJson = contentJson.replace(/[\u0000-\u001F\u007F]/g, '')
+                const parsedData = JSON.parse(sanitizedJson)
+                if (Array.isArray(parsedData)) {
+                    this.contentDialogData = parsedData
+                } else if (parsedData.setting) {
+                    this.contentDialogData = parsedData.setting
+                } else {
+                    this.contentDialogData = [parsedData]
+                }
+                this.contentDialogVisible = true
+            } catch (e) {
+                this.$message.error('消息内容解析失败')
+                console.error('解析contentJson失败:', e)
+            }
+        },
+        /** 获取内容类型标签 */
+        getContentTypeTag(contentType) {
+            const typeMap = {
+                '1': { label: '文本', type: '' },
+                '2': { label: '图片', type: 'success' },
+                '3': { label: '链接', type: 'warning' },
+                '5': { label: '文件', type: 'info' },
+                '6': { label: '视频', type: 'danger' }
+            }
+            return typeMap[String(contentType)] || { label: '其他(' + contentType + ')', type: 'info' }
+        },
+        /** 导出按钮操作 */
+        handleExport() {
+            const queryParams = this.queryParams
+            this.$confirm('是否确认导出所有个微SOP执行详情数据项?', '警告', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning'
+            }).then(() => {
+                this.exportLoading = true
+                return exportWxSopLogsCVO(queryParams)
+            }).then(response => {
+                this.download(response.msg)
+                this.exportLoading = false
+            }).catch(() => {
+                this.exportLoading = false
+            })
+        }
     }
-  }
-};
+}
 </script>
 
 <style scoped>
+.content-detail {
+    max-height: 400px;
+    overflow-y: auto;
+}
+
+.content-item {
+    padding: 12px 16px;
+    margin-bottom: 12px;
+    background: #f8f9fa;
+    border-radius: 8px;
+    border: 1px solid #ebeef5;
+}
+
+.content-type-tag {
+    margin-bottom: 8px;
+}
+
+.content-body {
+    font-size: 14px;
+    line-height: 1.6;
+    color: #303133;
+}
+
+.text-content {
+    white-space: pre-wrap;
+    word-break: break-all;
+}
 </style>