Explorar el Código

Merge remote-tracking branch 'origin/master'

yuhongqi hace 2 días
padre
commit
66ec48a600

+ 9 - 1
src/api/course/courseCouponUser.js

@@ -7,4 +7,12 @@ export function getRecordList(query) {
     method: 'get',
     params: query
   })
-}
+}
+
+export function getCourseCouponUserListVO(query) {
+    return request({
+        url: '/course/courseCouponUser/listVO',
+        method: 'get',
+        params: query
+    })
+}

+ 23 - 0
src/api/scrm/customer.js

@@ -0,0 +1,23 @@
+import request from '@/utils/request'
+
+/**
+ * 获取我的客户列表
+ */
+export function getMyCustomerList(query) {
+  return request({
+    url: '/scrm/customer/getMyCustomerList',
+    method: 'get',
+    params: query
+  })
+}
+
+/**
+ * 修改客户
+ */
+export function updateCustomer(data) {
+  return request({
+    url: '/scrm/customer/edit',
+    method: 'put',
+    data: data
+  })
+}

+ 42 - 0
src/api/scrm/customerFollowUp.js

@@ -0,0 +1,42 @@
+import request from '@/utils/request'
+
+/**
+ * 上传通话录音文件
+ * @param {FormData} formData - 包含 file, externalContactId, userId
+ */
+export function uploadFollowUpFile(formData) {
+  return request({
+    url: '/scrm/customer/followUp/upload',
+    method: 'post',
+    data: formData,
+    headers: { 'Content-Type': 'multipart/form-data' }
+  })
+}
+
+/**
+ * 保存跟进记录和录音(JSON方式)
+ * @param {Object} data
+ * @param {string} data.externalContactId - 企微客户ID
+ * @param {string} data.visitRecords - 跟进记录JSON字符串
+ * @param {string} data.recordings - 录音记录JSON字符串
+ */
+export function saveFollowUpRecord(data) {
+  return request({
+    url: '/scrm/customer/followUp/save',
+    method: 'post',
+    data: data
+  })
+}
+
+/**
+ * 获取跟进统计(未跟进天数、跟进次数)
+ * @param {Object} query
+ * @param {string} query.externalContactId
+ */
+export function getFollowUpStatistics(query) {
+  return request({
+    url: '/scrm/customer/followUp/statistics',
+    method: 'get',
+    params: query
+  })
+}

+ 11 - 9
src/views/company/companyUser/index.vue

@@ -173,7 +173,7 @@
               <dict-tag :options="qwStatusOptions" :value="scope.row.qwStatus"/>
             </template>
           </el-table-column>
-            <el-table-column label="客服语音回复方式" align="center">
+            <el-table-column label="客服语音回复方式" align="center" v-if="projectFrom != 'hst'">
                 <template slot-scope="scope">
                     <span v-if="scope.row.isCustomerVoice === 1" style="color: #67C23A;">客户语音销售回复语音</span>
                     <span v-else-if="scope.row.isCustomerVoice === 2" style="color: #409EFF;">客户语音销售回复文本</span>
@@ -250,7 +250,7 @@
                 type="text"
                 icon="el-icon-connection"
                 plain
-                v-if="scope.row.doctorId!=null"
+                v-if="scope.row.doctorId!=null && projectFrom != 'hst'"
                 @click="handleUpdateDoctor(scope.row)"
               >换绑医生</el-button>
               <el-button
@@ -258,7 +258,7 @@
                 type="text"
                 plain
                 icon="el-icon-link"
-                v-else
+                v-else-if="scope.row.doctorId == null && projectFrom != 'hst'"
                 @click="handleUpdateDoctor(scope.row)"
               >绑定医生</el-button>
               <el-button
@@ -293,6 +293,7 @@
                 icon="el-icon-user"
                 @click="handleBindMember(scope.row)"
                 v-hasPermi="['company:user:bindUser']"
+                v-if  = "projectFrom != 'hst'"
               >绑定员工用户</el-button>
 
               <el-button
@@ -301,10 +302,11 @@
                 icon="el-icon-user"
                 plain
                 @click="handleBindUser(scope.row)"
+                v-if=" projectFrom != 'hst'"
               >绑定用户</el-button>
 
               <el-button
-              v-if="!!scope.row.cidServerId"
+              v-if="!!scope.row.cidServerId && projectFrom != 'hst'"
                 size="mini"
                 type="text"
                 icon="el-icon-s-platform"
@@ -313,7 +315,7 @@
                 @click="handleUnbindCidServer(scope.row)"
               >取消绑定cid服务</el-button>
               <el-button
-              v-else
+              v-else-if="!!scope.row.cidServerId && projectFrom != 'hst'"
                 size="mini"
                 type="text"
                 icon="el-icon-s-platform"
@@ -326,10 +328,10 @@
               <el-button v-if="scope.row.userType !== '00'" size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['company:user:edit']">修改</el-button>
               <el-button v-if="scope.row.userType !== '00'" size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['company:user:remove']">删除</el-button>
               <el-button size="mini" type="text" icon="el-icon-key" @click="handleResetPwd(scope.row)" v-hasPermi="['company:user:resetPwd']">重置密码</el-button>
-              <el-button size="mini" type="text" icon="el-icon-edit" @click="checkBindSipCallUser(scope.row)" v-if="scope.row.aiSipCallUserId==null">绑定sip角色</el-button>
-              <el-button size="mini" type="text" icon="el-icon-search" @click="checkChangeSipCallUser(scope.row)" v-if="scope.row.aiSipCallUserId">修改sip角色</el-button>
+              <el-button size="mini" type="text" icon="el-icon-edit" @click="checkBindSipCallUser(scope.row)" v-if="scope.row.aiSipCallUserId==null && projectFrom != 'hst'">绑定sip角色</el-button>
+              <el-button size="mini" type="text" icon="el-icon-search" @click="checkChangeSipCallUser(scope.row)" v-if="scope.row.aiSipCallUserId && projectFrom != 'hst'">修改sip角色</el-button>
               <el-button
-                v-if="!scope.row.accountId"
+                v-if="!scope.row.accountId && projectFrom != 'hst'"
                 size="mini"
                 type="text"
                 icon="el-icon-link"
@@ -337,7 +339,7 @@
               >绑定销售易</el-button>
 
               <el-button
-                v-if="scope.row.accountId"
+                v-if="scope.row.accountId && projectFrom != 'hst'"
                 size="mini"
                 type="text"
                 icon="el-icon-close"

+ 192 - 0
src/views/crm/customer/qw/collection.vue

@@ -0,0 +1,192 @@
+<template>
+    <div class="app-container">
+        <el-form ref="form" :model="form" label-width="140px">
+            <el-button v-if="form.id" size="mini" type="text" @click="handleShare" icon="el-icon-coin"
+                v-hasPermi="['hisStore:collection:WxaCodeCollectionUnLimit']">分享
+            </el-button>
+            <el-form-item label="信息模板" prop="questionId">
+                <el-select @change="selectQuestion" v-model="form.questionId" placeholder="请选择问答">
+                    <el-option v-for="dict in questionOptions" :key="dict.dictValue" :label="dict.dictLabel"
+                        :value="parseInt(dict.dictValue)" />
+                </el-select>
+            </el-form-item>
+            <div v-for="(answer, index) in form.answers">
+                <div style="margin-bottom: 20px;margin-top: 20px;">
+                    <span style="font-size: 15px;font-weight: bold;    margin-left: 31px">{{ answer.title }}</span>
+                </div>
+                <div style="margin-left: 31px;">
+                    <el-checkbox-group :disabled="form.answers[index].flag" v-model="form.answers[index].value" size="mini" >
+                        <el-checkbox v-for="dict in answer.options" :label="dict.value" >{{ dict.name }}</el-checkbox>
+                    </el-checkbox-group>
+                    <!-- <el-radio-group :disabled="form.answers[index].flag" v-model="form.answers[index].value">
+                        <el-radio v-for="dict in answer.options" :label="dict.value">{{ dict.name }}</el-radio>
+                    </el-radio-group> -->
+                </div>
+
+            </div>
+            <el-form-item label="是否关联套餐包" prop="isPackage">
+                <el-radio-group v-model="form.isPackage">
+                    <el-radio :label="0">否</el-radio>
+                    <el-radio :label="1">是</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item v-if="form.isPackage == 1" label="套餐包" prop="packageId">
+                <el-select filterable v-model="form.packageId" placeholder="请选择套餐包">
+                    <el-option v-for="dict in privatePackageOptions" :key="dict.dictValue" :label="dict.dictLabel"
+                        :value="parseInt(dict.dictValue)" />
+                </el-select>
+            </el-form-item>
+            <el-form-item v-if="form.packageId && form.isPackage && form.isPackage == 1" label="支付类型" prop="payType">
+                <el-radio-group v-model="form.payType">
+                    <el-radio :label="1">全款</el-radio>
+                    <el-radio :label="2">物流代收</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item v-if="form.packageId && form.payType == 2 && form.isPackage &&   form.isPackage == 1" label="物流代收金额" prop="amount">
+                <el-input v-model="form.amount" placeholder="请输入物流代收金额" type="number" />
+            </el-form-item>
+        </el-form>
+        <div slot="footer" class="dialog-footer">
+            <el-button type="primary" @click="submitForm">确 定</el-button>
+            <!-- <el-button @click="cancel">取 消</el-button> -->
+        </div>
+
+
+        <el-dialog :title="collectionForm.title" v-if="collectionForm.open" :visible.sync="collectionForm.open"
+            width="450px" append-to-body>
+            <div style="padding-bottom:15px;">
+                <img :src="codeImage" width="400px">
+            </div>
+            <div slot="footer" class="dialog-footer">
+                <el-button @click="downloadImage(codeImage, collectionForm.name + '.png')">下载二维码</el-button>
+            </div>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+import { questionOptions, getAnswer } from "@/api/hisStore/answer";
+import { allPrivatePackage } from "@/api/store/package";
+import { getInfo, addCollection, updateCollection, getWxaCodeCollectionUnLimit } from "@/api/hisStore/collection";
+export default {
+    name: "collection",
+    components: {},
+    data() {
+        return {
+            form: {
+                answers: []
+            },
+            userId: null,
+            questionOptions: [],
+            privatePackageOptions: [],
+            collectionForm: {
+                open: false,
+                title: "用户信息采集分享",
+                name: null,
+            },
+            codeImage: null,
+        };
+    },
+    created() {
+        this.getQuestionOptions();
+        this.getAllPrivatePackge();
+    },
+    methods: {
+        downloadImage(imageSrc, fileName) {
+            const link = document.createElement('a');
+            link.href = imageSrc;
+            link.download = fileName || '付款二维码.png';
+            document.body.appendChild(link);
+            link.click();
+            document.body.removeChild(link);
+        },
+        handleShare() {
+            let loadingRock = this.$loading({
+                lock: true,
+                text: '生成二维码中~~请不要刷新页面!!',
+                spinner: 'el-icon-loading',
+                background: 'rgba(0, 0, 0, 0.7)'
+            });
+
+            getWxaCodeCollectionUnLimit(this.form.id).then(response => {
+                this.codeImage = response.url
+                this.collectionForm.open = true;
+                this.collectionForm.name = this.form.id;
+                loadingRock.close();
+            }).finally(res => {
+                loadingRock.close();
+            })
+        },
+        //获取问答模板
+        getQuestionOptions() {
+            console.log("this.userId", this.userId)
+            questionOptions().then(response => {
+                this.questionOptions = response.rows;
+            })
+        },
+        getAllPrivatePackge() {
+            allPrivatePackage().then(res => {
+                this.privatePackageOptions = res.rows;
+            })
+        },
+        getCollectionInfo(userId) {
+            const queryParams = {
+                userId: userId,
+            }
+            this.userId = userId;
+            getInfo(queryParams).then(res => {
+                this.form = res.data;
+            })
+        },
+        //选择问答模板
+        selectQuestion(val) {
+            console.log(val)
+            this.form = {
+                answers: []
+            };
+            const queryParams = {
+                userId: this.userId,
+                questionId: val
+            }
+            getInfo(queryParams).then(res => {
+                this.form = res.data;
+            })
+            // getAnswer(val).then(response =>{
+
+            //     this.form.answers = response.data.answers;
+            //     console.log(this.form)
+            // })
+        },
+
+        submitForm() {
+            console.log(this.form)
+            this.form.userId = this.userId;
+            this.$refs["form"].validate(valid => {
+                if (valid) {
+                    if (this.form.id != null) {
+                        updateCollection(this.form).then(res => {
+                            this.msgSuccess("修改成功");
+                            this.open = false;
+                            this.$parent.$parent.closeCollection();
+                        })
+
+                    } else {
+                        addCollection(this.form).then(res => {
+                            this.msgSuccess("添加成功");
+                            this.open = false;
+                            this.$parent.$parent.closeCollection();
+                        })
+                    }
+                }
+            });
+
+        },
+        cancel() {
+
+        },
+    },
+};
+
+
+
+</script>

+ 2304 - 0
src/views/crm/customer/qw/customerDetail.vue

@@ -0,0 +1,2304 @@
+<template>
+    <div class="customer-container">
+        <div class="main-grid-three-columns">
+            <div class="left-column">
+                <!-- 客户画像 (成交要素) -->
+                <div class="card">
+                    <div class="card-header">
+                        <h3><i class="fas fa-id-card"></i> 客户画像(成交要素)</h3>
+                    </div>
+                    <div class="profile-grid">
+                        <div class="profile-item profile-item-main">
+                            <span class="label"><i class="fas fa-user"></i> 客户姓名:</span>
+                            <span class="value highlight">{{ (customerData && (customerData.customerName || customerData.name)) || '-' }}</span>
+                        </div>
+                        <template v-for="(value, key) in customerPortraitData">
+                            <div
+                                v-if="key !== '需求'"
+                                :key="key"
+                                class="profile-item"
+                            >
+                                <span class="label">
+                                    <i class="fas fa-info-circle"></i> {{ key }}:
+                                </span>
+                                <span class="value">{{ value }}</span>
+                            </div>
+                        </template>
+                        <!-- 需求单独显示,占满整行 -->
+                        <div
+                            v-if="customerPortraitData['需求']"
+                            key="需求"
+                            class="profile-item profile-item-full"
+                        >
+                            <span class="label">
+                                <i class="fas fa-bullseye"></i> 需求:
+                            </span>
+                            <span class="value long-text">{{ customerPortraitData['需求'] }}</span>
+                        </div>
+                    </div>
+                </div>
+                <!-- AI 标签 -->
+                <div class="card">
+                    <div class="card-header">
+                        <h3>
+                            <i class="fas fa-tags"></i> AI 标签
+                        </h3>
+                        <!-- <el-button
+                            v-if="allAiTags.length === 0"
+                            size="mini"
+                            type="primary"
+                            @click="handleAnalyzeTag"
+                        >
+                            AI分析标签
+                        </el-button> -->
+                    </div>
+                    <div class="tags-container">
+                        <div v-if="allAiTags.length > 0" class="tags-list">
+                            <div
+                                v-for="(item, index) in visibleTags"
+                                :key="item.id"
+                                class="tag-item"
+                                :class="{ 'tag-highlight': index < 3 }"
+                            >
+                                <span class="tag-key">{{ item.propertyName }}</span>
+                                <span class="tag-separator">:</span>
+                                <span class="tag-value">{{ item.propertyValue }}</span>
+                            </div>
+                        </div>
+                        <div v-else class="empty-tags">
+                            <i class="fas fa-inbox"></i>
+                            <span>暂无 AI 标签</span>
+                        </div>
+
+                        <!-- 加载更多按钮 -->
+                        <div v-if="allAiTags.length > tagsPageSize" class="tags-actions">
+                            <button
+                                v-if="!isExpanded"
+                                @click="loadMoreTags"
+                                class="btn-expand-tags"
+                                type="button"
+                            >
+                                <i class="fas fa-chevron-down"></i> 展开全部 ({{ allAiTags.length - tagsPageSize }})
+                            </button>
+
+                            <!-- 收起按钮 -->
+                            <button
+                                v-else
+                                @click="collapseTags"
+                                class="btn-collapse-tags"
+                                type="button"
+                            >
+                                <i class="fas fa-chevron-up"></i> 收起标签
+                            </button>
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+            <div class="middle-column">
+                <!-- 沟通摘要 -->
+                <div class="card">
+                    <div class="card-header">
+                        <h3><i class="fas fa-comment-dots"></i> 沟通摘要</h3>
+                    </div>
+                    <div class="summary-text compact">
+                        {{ getCommunicationAbstract() }}
+                    </div>
+                </div>
+                <!-- AI 沟通总结 -->
+                <div class="card">
+                    <div class="card-header">
+                        <h3><i class="fas fa-robot"></i> AI 沟通总结</h3>
+                    </div>
+                    <div class="summary-text compact">
+                        {{ getCommunicationSummary() }}
+                    </div>
+                </div>
+                <!-- 沟通记录 -->
+                <div class="card card-table">
+                    <div class="card-header">
+                        <h3><i class="fas fa-history"></i> 沟通记录</h3>
+                    </div>
+                    <div class="records-table-wrapper">
+                        <table class="records-table">
+                            <thead>
+                            <tr>
+                                <th><i class="fas fa-user"></i> 客户名称</th>
+                                <th><i class="fas fa-chart-line"></i> 流失等级</th>
+                                <th><i class="fas fa-heart"></i> 客户意向度</th>
+                                <th><i class="far fa-clock"></i> 创建时间</th>
+                                <th><i class="fas fa-cog"></i> 操作</th>
+                            </tr>
+                            </thead>
+                            <tbody>
+                            <tr v-for="record in communicationRecords" :key="record.id" class="record-row">
+                                <td class="record-cell">{{ (customerData && (customerData.customerName || customerData.name)) || '-' }}</td>
+                                <td class="record-cell">
+                                        <span class="risk-level-tag" :class="getRecordRiskLevelClass(record)">
+                                            {{ getRecordRiskLevelLabel(record) }}
+                                        </span>
+                                </td>
+                                <td class="record-cell">
+                                        <span class="intention-degree">
+                                            {{ getIntentionDegreeFromRecord(record) }}
+                                        </span>
+                                </td>
+                                <td class="record-cell">{{ parseTime(record.createTime, '{y}-{m}-{d} {h}:{i}:{s}') || '-' }}</td>
+                                <td class="record-cell">
+                                    <button @click="viewChat(record)" class="btn-view-chat">
+                                        <i class="fas fa-comments"></i> 聊天详情
+                                    </button>
+                                </td>
+                            </tr>
+                            <tr v-if="!communicationRecords.length">
+                                <td colspan="5" class="empty-tip">
+                                    <i class="fas fa-inbox"></i> 暂无沟通记录
+                                </td>
+                            </tr>
+                            </tbody>
+                        </table>
+
+                        <!-- 分页组件 -->
+                        <div class="pagination-container" v-if="communicationRecordsTotal > 0">
+                            <el-pagination
+                                @current-change="handleCommunicationRecordsPageChange"
+                                @size-change="handleCommunicationRecordsSizeChange"
+                                :current-page="communicationRecordsPageNum"
+                                :page-sizes="[4, 10, 20, 50]"
+                                :page-size="communicationRecordsPageSize"
+                                layout="total, sizes, prev, pager, next, jumper"
+                                :total="communicationRecordsTotal"
+                            />
+                        </div>
+                    </div>
+                </div>
+                <!-- 微信风格聊天弹窗 -->
+                <div v-if="chatDialogVisible" class="chat-dialog-overlay" @click.self="closeChatDialog">
+                    <div class="chat-dialog">
+                        <div class="chat-dialog-header">
+                            <div class="chat-title">
+                                <i class="fas fa-comments"></i>
+                                <span>{{
+                                        (currentChatRecord && currentChatRecord.customerName) || (customerData && customerData.customerName)
+                                    }} - 历史聊天记录</span>
+                            </div>
+                            <button @click="closeChatDialog" class="btn-close">
+                                ×
+                            </button>
+                        </div>
+                        <div class="chat-dialog-body">
+                            <div class="chat-messages">
+                                <!-- 根据 aiChatRecord 数组循环显示聊天记录 -->
+                                <div
+                                    v-for="(msg, index) in parseChatMessages(currentChatRecord && currentChatRecord.aiChatRecord)"
+                                    :key="index"
+                                    class="message-item"
+                                    :class="msg.type === 'ai' ? 'message-left' : 'message-right'"
+                                >
+                                    <!-- AI 消息:头像在左,名称在聊天内容上方靠左 -->
+                                    <div v-if="msg.type === 'ai'" class="message-wrapper message-wrapper-left">
+                                        <div class="message-avatar message-avatar-ai">
+                                            <img src="/static/images/ai-avatar.svg" alt="AI"
+                                                 @error="handleAvatarError($event, 'ai')"/>
+                                        </div>
+                                        <div class="message-content">
+                                            <div class="message-name message-name-ai">AI</div>
+                                            <div class="message-bubble">
+                                                {{ msg.content }}
+                                            </div>
+                                        </div>
+                                    </div>
+
+                                    <!-- 客户消息:强制头像在右侧 -->
+                                    <div v-else class="message-item message-item-customer">
+                                        <div class="message-content-right">
+                                            <div class="message-bubble message-bubble-right">
+                                                {{ msg.content }}
+                                            </div>
+                                        </div>
+                                        <div class="message-avatar message-avatar-customer">
+                                            <img src="/static/images/customer-avatar.svg" alt="客户"
+                                                 @error="handleAvatarError($event, 'customer')"/>
+                                        </div>
+                                    </div>
+                                </div>
+
+                                <!-- 空数据提示 -->
+                                <div
+                                    v-if="!parseChatMessages(currentChatRecord && currentChatRecord.aiChatRecord).length"
+                                    class="empty-chat-tip">
+                                    <i class="fas fa-inbox"></i> 暂无聊天内容
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+            <!-- 流失风险等级 + 客户关注点 & 意向度 -->
+            <div class="right-column">
+                <!-- 流失风险等级 -->
+                <div class="card risk-card" :class="getRiskLevelClass()">
+                    <div class="card-header">
+                        <h3><i class="fas fa-chart-line"></i> 流失风险等级</h3>
+                        <span class="risk-badge" :class="getRiskLevelBadgeClass()">{{ getRiskLevelLabel() }}</span>
+                    </div>
+                    <div class="risk-analysis">
+                        <p class="risk-text">{{ getRiskLevelAnalysis() }}</p>
+                        <div class="risk-tip" v-if="getRiskLevelTip()">
+                            <i class="fas fa-exclamation-triangle"></i> {{ getRiskLevelTip() }}
+                        </div>
+                    </div>
+                </div>
+                <!-- 客户关注点 & 意向度 -->
+                <div class="card card-focus">
+                    <div class="card-header">
+                        <h3><i class="fas fa-lightbulb"></i> 客户关注点 & 意向度</h3>
+                    </div>
+                    <div class="focus-points">
+                        <div class="focus-title">
+                            <i class="fas fa-search"></i> 核心关注点:
+                        </div>
+                        <ul class="focus-list">
+                            <li class="focus-item">{{customerFocusPoints}}</li>
+                            <i class="fas fa-dot-circle"></i> {{ point }}
+                        </ul>
+                    </div>
+                    <div class="intention-section">
+                        <div class="intention-header">
+                            <span class="intention-label">客户意向度</span>
+                            <el-tooltip placement="top" effect="light">
+                                <i class="el-icon-info intention-info-icon"></i>
+                                <div slot="content" class="intention-tooltip">
+                                    <div><strong>A 级</strong> - 最高意向度</div>
+                                    <div><strong>B 级</strong> - 高意向度</div>
+                                    <div><strong>C 级</strong> - 中等意向度</div>
+                                    <div><strong>D 级</strong> - 较低意向度</div>
+                                    <div><strong>E 级</strong> - 低意向度</div>
+                                    <div><strong>F 级</strong> - 最低意向度</div>
+                                </div>
+                            </el-tooltip>
+                        </div>
+                        <div class="intention-watermark"
+                             v-if="getIntentionDegree()"
+                             :class="getIntentionColorClass(getIntentionDegree())">
+                            {{ getIntentionDegree() }}
+                        </div>
+                        <div class="no-intention-tip" v-else>
+                            暂无评级
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <el-dialog
+        title="AI分析标签"
+        :visible.sync="analyzeTagDialogVisible"
+        width="420px"
+        append-to-body
+    >
+        <el-form label-width="90px">
+            <el-form-item label="行业类型">
+                <el-select
+                    v-model="selectedTradeType"
+                    placeholder="请选择行业类型"
+                    clearable
+                    style="width: 100%;"
+                >
+                    <el-option
+                        v-for="item in tradeTypeOptions"
+                        :key="item.dictValue"
+                        :label="item.dictLabel"
+                        :value="item.dictValue"
+                    />
+                </el-select>
+            </el-form-item>
+        </el-form>
+        <div slot="footer" class="dialog-footer">
+            <el-button @click="analyzeTagDialogVisible = false">取 消</el-button>
+            <el-button type="primary" :loading="analyzeTagSubmitting" @click="confirmAnalyzeTag">确 定</el-button>
+        </div>
+    </el-dialog>
+    </div>
+
+
+</template>
+
+<script>
+
+import {listByCustomerId,analyzeAiTagByTrade} from "@/api/qw/customerProperty";
+import {listAnalyze} from "@/api/qw/qwAnalyze";
+
+export default {
+    props: {
+        // 抽屉模式参数(父组件传入)
+        analyzeUserId: {
+            type: [String, Number],
+            default: null
+        },
+        analyzeExternalUserId: {
+            type: String,
+            default: null
+        },
+        analyzeCorpId: {
+            type: String,
+            default: null
+        },
+        customerRow: {
+            type: Object,
+            default: null
+        }
+    },
+    data() {
+        return {
+            userId: null,
+            externalUserId: null,
+            corpId: null,
+            customerData: null, // 从列表页传递过来的完整客户数据
+            aiTags: [],// 需要显示的 AI 标签
+            allAiTags: [], // 存储所有 AI 标签
+            tagsPageSize: 5,//默认展开标签的数量
+            isExpanded: false, // 是否已展开显示全部标签
+            // 聊天记录分页相关
+            communicationRecords: [],
+            communicationRecordsTotal: 0,
+            communicationRecordsPageNum: 1,
+            communicationRecordsPageSize: 4,
+            // 聊天弹窗相关
+            chatDialogVisible: false, // 聊天弹窗是否显示
+            currentChatRecord: null, // 当前查看的聊天记录
+            analyzeTagDialogVisible: false,
+            analyzeTagSubmitting: false,
+            selectedTradeType: null,
+            tradeTypeOptions:[],
+        }
+    },
+    computed: {
+        // 根据是否展开控制显示的标签数量
+        visibleTags() {
+            if (this.isExpanded) {
+                return this.allAiTags;
+            } else {
+                // 未展开时只显示前 3 条
+                return this.allAiTags.slice(0, this.tagsPageSize);
+            }
+        },
+        // 客户画像数据(从最新的沟通记录中获取)
+        customerPortraitData() {
+            if (!this.communicationRecords || this.communicationRecords.length === 0) {
+                return {};
+            }
+            // 获取最新的沟通记录
+            const latestRecord = this.communicationRecords[0];
+            if (latestRecord && latestRecord.customerPortraitJson) {
+                try {
+                    // 如果是字符串,解析为 JSON 对象
+                    if (typeof latestRecord.customerPortraitJson === 'string') {
+                        return JSON.parse(latestRecord.customerPortraitJson);
+                    }
+                    // 如果已经是对象,直接返回
+                    return latestRecord.customerPortraitJson;
+                } catch (error) {
+                    console.error('解析客户画像 JSON 失败:', error);
+                    return {};
+                }
+            }
+            return {};
+        },
+        // 客户关注点数据(从最新的沟通记录中获取)
+        customerFocusPoints() {
+            if (!this.communicationRecords || this.communicationRecords.length === 0) {
+                return ['暂无分析数据'];
+            }
+            const latestRecord = this.communicationRecords[0];
+            if (latestRecord && latestRecord.customerFocusJson) {
+                return this.normalizeFocusPoints(latestRecord.customerFocusJson);
+            }
+            return ['暂无分析数据'];
+        }
+    },
+    created() {
+        this.initFromParentOrRoute();
+        this.getDicts("trade_type").then((response) => {
+      this.tradeTypeOptions = response.data;
+    });
+    },
+    watch: {
+        analyzeUserId: {
+            immediate: false,
+            handler() {
+                // 抽屉重复打开/切换客户时刷新
+                this.initFromParentOrRoute();
+            }
+        },
+        analyzeExternalUserId() {
+            this.initFromParentOrRoute();
+        },
+        analyzeCorpId() {
+            this.initFromParentOrRoute();
+        }
+    },
+    methods: {
+        normalizeFocusPoints(value) {
+            if (value === null || value === undefined) return [];
+            if (Array.isArray(value)) {
+                return value.map(v => String(v)).filter(Boolean);
+            }
+
+            // 字符串:可能是 JSON 数组字符串,也可能是普通字符串
+            if (typeof value === 'string') {
+                const raw = value.trim();
+                if (!raw) return [];
+
+                // JSON 数组 / JSON 字符串尝试解析
+                if (
+                    (raw.startsWith('[') && raw.endsWith(']')) ||
+                    (raw.startsWith('"') && raw.endsWith('"')) ||
+                    (raw.startsWith("'") && raw.endsWith("'"))
+                ) {
+                    try {
+                        const parsed = JSON.parse(raw);
+                        if (Array.isArray(parsed)) {
+                            return parsed.map(v => String(v)).map(s => s.trim()).filter(Boolean);
+                        }
+                        if (typeof parsed === 'string') {
+                            return this.normalizeFocusPoints(parsed);
+                        }
+                    } catch (e) {
+                        // ignore,走后面的兜底清洗
+                    }
+                }
+
+                // 兜底:去掉中括号/引号后按分隔符拆分
+                let cleaned = raw;
+                if (cleaned.startsWith('[') && cleaned.endsWith(']')) {
+                    cleaned = cleaned.slice(1, -1);
+                }
+                cleaned = cleaned.replace(/["']/g, '');
+
+                const parts = cleaned
+                    .split(/[,,、;;\n]/g)
+                    .map(s => s.trim())
+                    .filter(Boolean);
+
+                return parts.length ? parts : [cleaned.trim()].filter(Boolean);
+            }
+
+            // 其它类型兜底
+            return [String(value)].filter(Boolean);
+        },
+        initFromParentOrRoute() {
+            // 优先用父组件传参(抽屉模式)
+            if (
+                (this.analyzeUserId !== null && this.analyzeUserId !== undefined && this.analyzeUserId !== '') ||
+                (this.analyzeExternalUserId !== null && this.analyzeExternalUserId !== undefined && this.analyzeExternalUserId !== '')
+            ) {
+                this.userId = this.analyzeUserId;
+                this.externalUserId = this.analyzeExternalUserId || (this.customerRow && (this.customerRow.externalUserId || this.customerRow.id));
+                this.corpId = this.analyzeCorpId;
+                this.customerData = this.customerRow || null;
+            } else {
+                // 路由模式兜底
+                this.userId = this.$route.query.userId || this.$route.query.qwUserId || this.$route.params.userId || this.$route.params.qwUserId;
+                this.externalUserId = this.$route.query.externalUserId || this.$route.query.id || this.$route.params.externalUserId || this.$route.params.id;
+                this.corpId = this.$route.query.corpId || this.$route.params.corpId;
+                if (this.$route.query.customerData) {
+                    try {
+                        this.customerData = JSON.parse(this.$route.query.customerData);
+                    } catch (error) {
+                        console.error('解析客户数据失败:', error);
+                    }
+                }
+            }
+
+            // 重置分页(切换客户时)
+            this.communicationRecordsPageNum = 1;
+            // 获取客户标签
+            this.loadCustomerTags();
+            // 加载客户分析信息
+            this.getCustomerInfoList();
+        },
+        loadCustomerTags() {
+            const params = {
+                externalUserId: this.externalUserId,
+                corpId: this.corpId,
+                qwUserId: this.userId,
+            };
+            return listByCustomerId(params).then((response) => {
+                if (response.code === 200) {
+                    this.allAiTags = response.data || [];
+                    // 强制 Vue 更新视图
+                    this.$forceUpdate();
+                } else {
+                    console.error('获取 AI 标签失败:', response);
+                }
+            }).catch(error => {
+                console.error('获取 AI 标签异常:', error);
+            });
+        },
+        handleAnalyzeTag() {
+            this.analyzeTagDialogVisible = true;
+        },
+        confirmAnalyzeTag() {
+            if (!this.selectedTradeType) {
+                this.$message.warning('请选择行业类型');
+                return;
+            }
+            if (!this.externalUserId || !this.corpId || !this.userId) {
+                this.$message.warning('客户参数不完整,无法分析标签');
+                return;
+            }
+            const data = {
+                externalUserId: this.externalUserId,
+                corpId: this.corpId,
+                qwUserId: this.userId,
+                tradeType: this.selectedTradeType
+            };
+            this.analyzeTagSubmitting = true;
+            analyzeAiTagByTrade(data).then((res) => {
+                if (res && res.code === 200) {
+                    this.$message.success(res.msg || 'AI分析标签成功');
+                    this.analyzeTagDialogVisible = false;
+                    this.loadCustomerTags();
+                } else {
+                    this.$message.error((res && res.msg) || 'AI分析标签失败');
+                }
+            }).catch(() => {
+                this.$message.error('AI分析标签失败');
+            }).finally(() => {
+                this.analyzeTagSubmitting = false;
+            });
+        },
+        getCustomerInfoList() {
+            const params = {
+                pageNum: this.communicationRecordsPageNum,
+                pageSize: this.communicationRecordsPageSize,
+                qwUserId: this.userId,
+                externalUserId: this.externalUserId,
+                corpId: this.corpId
+            };
+            return listAnalyze(params).then((response) => {
+                if (response.code === 200) {
+                    this.communicationRecords = response.rows || [];
+                    this.communicationRecordsTotal = response.total || 0;
+                } else {
+                    console.error('获取客户信息失败:', response);
+                }
+            }).catch(error => {
+                console.error('获取客户信息异常:', error);
+            });
+        },
+        // 加载更多标签 - 显示全部
+        loadMoreTags() {
+            this.isExpanded = true;
+        },
+        // 收起标签 - 只显示前 3 条
+        collapseTags() {
+            this.isExpanded = false;
+        },
+        // 查看聊天内容
+        viewChat(record) {
+            this.currentChatRecord = record;
+            this.chatDialogVisible = true;
+        },
+        // 关闭聊天弹窗
+        closeChatDialog() {
+            this.chatDialogVisible = false;
+            this.currentChatRecord = null;
+        },
+        // 解析聊天消息数组
+        parseChatMessages(content) {
+            if (!content) {
+                return [];
+            }
+            // 如果 content 是字符串,尝试解析为 JSON 数组
+            if (typeof content === 'string') {
+                try {
+                    const parsed = JSON.parse(content);
+                    // 如果是数组,直接返回
+                    if (Array.isArray(parsed)) {
+                        return parsed.map(item => ({
+                            content: item.ai || item.user,
+                            type: item.ai ? 'ai' : 'user'
+                        }));
+                    }
+                    // 如果是对象,转换为数组
+                    return [{content: parsed.content, type: parsed.type || 'ai'}];
+                } catch (e) {
+                    // 解析失败,返回空数组
+                    console.error('解析聊天记录失败:', e);
+                    return [];
+                }
+            }
+            // 如果已经是数组,直接返回
+            if (Array.isArray(content)) {
+                return content;
+            }
+            // 如果是对象,转换为数组
+            return [content];
+        },
+        // 处理头像加载失败
+        handleAvatarError(event, type) {
+            const img = event.target;
+            if (type === 'ai') {
+                // AI 头像加载失败时,使用渐变色背景 + 机器人图标
+                img.style.display = 'none';
+                img.parentElement.innerHTML = '<i class="fas fa-robot" style="font-size: 24px; color: white;"></i>';
+            } else {
+                // 客户头像加载失败时,使用渐变色背景 + 用户图标
+                img.style.display = 'none';
+                img.parentElement.innerHTML = '<i class="fas fa-user" style="font-size: 24px; color: white;"></i>';
+            }
+        },
+
+        // 分页改变事件
+        handleCommunicationRecordsPageChange(pageNum) {
+            this.communicationRecordsPageNum = pageNum;
+            this.getCustomerInfoList();
+        },
+        // 每页条数改变事件
+        handleCommunicationRecordsSizeChange(pageSize) {
+            this.communicationRecordsPageSize = pageSize;
+            this.communicationRecordsPageNum = 1; // 重置为第一页
+            this.getCustomerInfoList();
+        },
+        // 获取沟通摘要
+        getCommunicationAbstract() {
+            if (!this.communicationRecords || this.communicationRecords.length === 0) {
+                return '暂无沟通记录';
+            }
+            const latestRecord = this.communicationRecords[0];
+            return latestRecord.communicationAbstract || '暂无沟通摘要';
+        },
+        // 获取 AI 沟通总结
+        getCommunicationSummary() {
+            if (!this.communicationRecords || this.communicationRecords.length === 0) {
+                return '暂无沟通记录';
+            }
+            const latestRecord = this.communicationRecords[0];
+            return latestRecord.communicationSummary || '暂无 AI 沟通总结';
+        },
+        // 获取最后更新时间
+        getUpdateTime() {
+            if (!this.communicationRecords || this.communicationRecords.length === 0) {
+                return '-';
+            }
+            const latestRecord = this.communicationRecords[0];
+            return latestRecord.createTime || '-';
+        },
+        // 获取流失风险等级数值
+        getAttritionLevel() {
+            if (!this.communicationRecords || this.communicationRecords.length === 0) {
+                return 0;
+            }
+            const latestRecord = this.communicationRecords[0];
+            return parseInt(latestRecord.attritionLevel) || 0;
+        },
+        // 获取流失风险等级标签
+        getRiskLevelLabel() {
+            const level = this.getAttritionLevel();
+            const labels = ['未知', '无风险', '低风险', '中风险', '高风险'];
+            return labels[level] || '未知';
+        },
+        // 获取流失风险等级徽章样式类
+        getRiskLevelBadgeClass() {
+            const level = this.getAttritionLevel();
+            const badgeClasses = [
+                'badge-unknown',
+                'badge-none',
+                'badge-low',
+                'badge-medium',
+                'badge-high'
+            ];
+            return badgeClasses[level] || 'badge-unknown';
+        },
+        // 获取客户意向度
+        getIntentionDegree() {
+            if (!this.communicationRecords || this.communicationRecords.length === 0) {
+                return '';
+            }
+            const latestRecord = this.communicationRecords[0];
+            return latestRecord.intentionDegree || '';
+        },
+        // 根据意向度等级获取颜色样式类
+        getIntentionColorClass(grade) {
+            if (!grade) return '';
+            const gradeUpper = grade.toUpperCase();
+            const colorMap = {
+                'A': 'intention-grade-a',
+                'B': 'intention-grade-b',
+                'C': 'intention-grade-c',
+                'D': 'intention-grade-d',
+                'E': 'intention-grade-e',
+                'F': 'intention-grade-f'
+            };
+            return colorMap[gradeUpper] || '';
+        },
+        // 获取单条记录的风险等级数值
+        getRecordAttritionLevel(record) {
+            if (!record) return 0;
+            return parseInt(record.attritionLevel) || 0;
+        },
+        // 获取单条记录的风险等级标签
+        getRecordRiskLevelLabel(record) {
+            const level = this.getRecordAttritionLevel(record);
+            const labels = ['未知', '无风险', '低风险', '中风险', '高风险'];
+            return labels[level] || '未知';
+        },
+        // 获取单条记录的风险等级样式类
+        getRecordRiskLevelClass(record) {
+            const level = this.getRecordAttritionLevel(record);
+            const classes = ['risk-unknown', 'risk-none', 'risk-low', 'risk-medium', 'risk-high'];
+            return classes[level] || 'risk-unknown';
+        },
+        // 获取单条记录的客户意向度
+        getIntentionDegreeFromRecord(record) {
+            if (!record) return 0;
+            return record.intentionDegree;
+        },
+        // 获取流失风险等级样式类
+        getRiskLevelClass() {
+            const level = this.getAttritionLevel();
+            const classes = ['risk-unknown', 'risk-none', 'risk-low', 'risk-medium', 'risk-high'];
+            return classes[level] || 'risk-unknown';
+        },
+        // 获取流失风险分析
+        getRiskLevelAnalysis() {
+            const level = this.getAttritionLevel();
+            if (!this.communicationRecords || this.communicationRecords.length === 0) {
+                return '暂无分析数据';
+            }
+            const latestRecord = this.communicationRecords[0];
+            return latestRecord.attritionLevelPrompt || "暂无分析数据";
+        },
+        // 获取流失风险提示
+        getRiskLevelTip() {
+            const level = this.getAttritionLevel();
+            const tips = [
+                '暂无分析',
+                '客户稳定,可以放心。',
+                '建议定期回访,了解客户最新需求。',
+                '建议安排专项跟进,深入了解客户痛点和需求。',
+                '建议立即联系客户,了解问题原因并提供解决方案。'
+            ];
+            return tips[level] || '';
+        },
+    }
+}</script>
+
+<style scoped>
+* {
+    box-sizing: border-box;
+}
+
+.left-column {
+    display: flex;
+    flex-direction: column;
+    gap: 12px;
+}
+
+.middle-column {
+    display: flex;
+    flex-direction: column;
+    gap: 12px;
+}
+
+.right-column {
+    display: flex;
+    flex-direction: column;
+    gap: 12px;
+}
+
+.customer-container {
+    max-width: 1600px;
+    margin: 0 auto;
+    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+    background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
+    padding: 8px;
+    min-height: calc(100vh - 50px);
+}
+
+@keyframes pulse {
+    0%, 100% {
+        transform: scale(1);
+    }
+    50% {
+        transform: scale(1.1);
+    }
+}
+
+.main-grid-three-columns {
+    display: grid;
+    grid-template-columns: 380px 1fr 340px;
+    gap: 12px;
+    animation: fadeIn 0.6s ease-in-out;
+    align-items: stretch;
+}
+
+@keyframes fadeIn {
+    from {
+        opacity: 0;
+        transform: translateY(20px);
+    }
+    to {
+        opacity: 1;
+        transform: translateY(0);
+    }
+}
+
+@media (max-width: 1400px) {
+    .main-grid-three-columns {
+        grid-template-columns: 360px 1fr 320px;
+        gap: 24px;
+    }
+}
+
+@media (max-width: 1200px) {
+    .main-grid-three-columns {
+        grid-template-columns: 1fr;
+    }
+}
+
+.card {
+    background: white;
+    border-radius: 12px;
+    padding: 12px;
+    margin-bottom: 12px;
+    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
+    transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
+    border: 1px solid rgba(226, 232, 240, 0.5);
+    position: relative;
+    overflow: hidden;
+}
+
+.card::before {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    height: 3px;
+    background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
+    transform: scaleX(0);
+    transition: transform 0.4s ease;
+}
+
+.card:hover::before {
+    transform: scaleX(1);
+}
+
+.card:hover {
+    box-shadow: 0 12px 48px rgba(0, 0, 0, 0.15);
+    transform: translateY(-4px);
+    border-color: rgba(102, 126, 234, 0.3);
+}
+
+/* 高亮卡片(AI 总结) */
+.card-highlight {
+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    color: white;
+    border: none;
+    box-shadow: 0 8px 32px rgba(102, 126, 234, 0.4);
+    position: relative;
+    overflow: hidden;
+}
+
+.card-highlight::after {
+    content: '';
+    position: absolute;
+    top: -50%;
+    right: -50%;
+    width: 200%;
+    height: 200%;
+    background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
+    animation: shimmer 3s infinite;
+}
+
+@keyframes shimmer {
+    0%, 100% {
+        transform: translate(0, 0);
+    }
+    50% {
+        transform: translate(-30%, -30%);
+    }
+}
+
+.card-highlight .card-header h3 {
+    color: white;
+}
+
+.card-highlight .summary-text {
+    color: white;
+    font-size: 17px;
+    line-height: 1.6;
+    max-height: 120px;
+    overflow-y: auto;
+    overflow-x: hidden;
+    padding-right: 4px;
+}
+
+.card-highlight .summary-text::-webkit-scrollbar {
+    width: 6px;
+}
+
+.card-highlight .summary-text::-webkit-scrollbar-track {
+    background: rgba(255, 255, 255, 0.2);
+    border-radius: 3px;
+}
+
+.card-highlight .summary-text::-webkit-scrollbar-thumb {
+    background: rgba(255, 255, 255, 0.4);
+    border-radius: 3px;
+}
+
+.card-highlight .summary-text::-webkit-scrollbar-thumb:hover {
+    background: rgba(255, 255, 255, 0.6);
+}
+
+.card-highlight .summary-meta span {
+    color: rgba(255, 255, 255, 0.9);
+}
+
+/* 表格卡片 */
+.card-table {
+    background: white;
+}
+
+/* 风险卡片 */
+.risk-card {
+    border-left: 4px solid #10b981;
+    background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
+    transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.risk-card.risk-unknown {
+    border-left-color: #6b7280;
+    background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%);
+}
+
+.risk-card.risk-unknown::before {
+    background: linear-gradient(90deg, #6b7280 0%, #4b5563 100%);
+}
+
+.risk-card::before {
+    background: linear-gradient(90deg, #10b981 0%, #34d399 100%);
+}
+
+.risk-unknown .risk-badge {
+    background: linear-gradient(135deg, #6b7280 0%, #4b5563 100%);
+    box-shadow: 0 2px 8px rgba(107, 114, 128, 0.3);
+}
+
+.risk-none .risk-badge {
+    background: linear-gradient(135deg, #10b981 0%, #34d399 100%);
+    box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3);
+}
+
+.risk-low .risk-badge {
+    background: linear-gradient(135deg, #3b82f6 0%, #60a5fa 100%);
+    box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
+}
+
+.risk-medium .risk-badge {
+    background: linear-gradient(135deg, #f59e0b 0%, #fbbf24 100%);
+    box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3);
+}
+
+.risk-high .risk-badge {
+    background: linear-gradient(135deg, #ef4444 0%, #f87171 100%);
+    box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3);
+}
+
+.risk-card:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 12px 48px rgba(0, 0, 0, 0.1);
+}
+
+/* 风险等级标签 */
+.risk-badge {
+    display: inline-flex;
+    align-items: center;
+    gap: 6px;
+    padding: 6px 14px;
+    border-radius: 8px;
+    font-size: 16px;
+    font-weight: 700;
+    color: white;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
+}
+
+.risk-badge::before {
+    content: '';
+    width: 6px;
+    height: 6px;
+    background: white;
+    border-radius: 50%;
+    animation: pulse 2s infinite;
+}
+
+@keyframes pulse {
+    0%, 100% {
+        opacity: 1;
+        transform: scale(1);
+    }
+    50% {
+        opacity: 0.5;
+        transform: scale(1.2);
+    }
+}
+
+.risk-card:hover .risk-badge {
+    transform: scale(1.05);
+}
+
+/* 风险分析内容 */
+.risk-analysis {
+    margin-top: 10px;
+    padding: 10px;
+    background: rgba(255, 255, 255, 0.7);
+    border-radius: 10px;
+    backdrop-filter: blur(10px);
+    max-height: 180px;
+    overflow-y: auto;
+    overflow-x: hidden;
+    padding-right: 4px;
+}
+
+.risk-analysis::-webkit-scrollbar {
+    width: 6px;
+}
+
+.risk-analysis::-webkit-scrollbar-track {
+    background: rgba(255, 255, 255, 0.5);
+    border-radius: 3px;
+}
+
+.risk-analysis::-webkit-scrollbar-thumb {
+    background: linear-gradient(180deg, #cbd5e1 0%, #94a3b8 100%);
+    border-radius: 3px;
+}
+
+.risk-analysis::-webkit-scrollbar-thumb:hover {
+    background: linear-gradient(180deg, #94a3b8 0%, #64748b 100%);
+}
+
+.risk-text {
+    font-size: 16px;
+    line-height: 1.7;
+    color: #475569;
+    margin: 0;
+}
+
+.risk-tip {
+    margin-top: 8px;
+    padding: 8px;
+    background: linear-gradient(135deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.9) 100%);
+    border-left: 3px solid #f59e0b;
+    border-radius: 6px;
+    font-size: 15px;
+    color: #92400e;
+    display: flex;
+    align-items: flex-start;
+    gap: 6px;
+}
+
+.risk-tip i {
+    font-size: 12px;
+    margin-top: 1px;
+    color: #f59e0b;
+}
+
+/* 关注点卡片 */
+.card-focus {
+    background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
+    border: 2px solid #bae6fd;
+    box-shadow: 0 4px 16px rgba(186, 230, 253, 0.3);
+}
+
+.card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    border-bottom: 1px solid #eef2ff;
+    padding-bottom: 6px;
+    margin-bottom: 10px;
+    flex-wrap: wrap;
+}
+
+.card-header h3 {
+    font-size: 19px;
+    font-weight: 700;
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    color: #0f172a;
+    letter-spacing: -0.02em;
+}
+
+.records-table-wrapper {
+    overflow-x: auto;
+}
+
+/* 分页容器样式 */
+.pagination-container {
+    padding: 16px 0 12px;
+    display: flex;
+    justify-content: center;
+    background: white;
+    border-top: 1px solid #f1f5f9;
+    margin-top: 12px;
+}
+
+/* Element UI 分页样式覆盖 */
+
+.pagination-container .el-pagination li {
+    min-width: 32px;
+    height: 32px;
+    line-height: 32px;
+    border-radius: 6px;
+    transition: all 0.3s ease;
+}
+
+.pagination-container .el-pagination li:hover {
+    background: linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(118, 75, 162, 0.1) 100%);
+    border-color: #667eea;
+}
+
+.records-table {
+    width: 100%;
+    border-collapse: collapse;
+    font-size: 15px;
+}
+
+.records-table thead {
+    background: transparent;
+    color: #475569;
+}
+
+.records-table th {
+    padding: 12px 16px;
+    text-align: center !important;
+    font-weight: 600;
+    font-size: 14px;
+    border-bottom: 2px solid #e2e8f0;
+    color: #64748b;
+}
+
+.records-table th i {
+    margin-right: 6px;
+    opacity: 0.8;
+}
+
+.records-table tbody tr {
+    border-bottom: 1px solid #f1f5f9;
+    transition: all 0.2s ease;
+}
+
+.records-table tbody tr:hover {
+    background-color: #f8fafc;
+    transform: none;
+    box-shadow: none;
+}
+
+.records-table td {
+    padding: 12px 16px;
+    vertical-align: middle;
+}
+
+.record-cell {
+    font-size: 15px;
+    color: #334155;
+    text-align: center !important;
+}
+
+/* 风险等级标签 */
+.risk-level-tag {
+    display: inline-block;
+    padding: 4px 12px;
+    border-radius: 6px;
+    font-size: 13px;
+    font-weight: 500;
+    border: 1px solid;
+}
+
+/* 客户意向度 */
+.intention-degree {
+    display: inline-block;
+    padding: 4px 12px;
+    border-radius: 6px;
+    font-size: 14px;
+    font-weight: 600;
+    color: #6366f1;
+    background: rgba(99, 102, 241, 0.08);
+    border: 1px solid rgba(99, 102, 241, 0.2);
+}
+
+.btn-view-chat {
+    background: transparent;
+    color: #667eea;
+    border: 1px solid #667eea;
+    padding: 6px 12px;
+    border-radius: 6px;
+    font-size: 14px;
+    cursor: pointer;
+    display: inline-flex;
+    align-items: center;
+    gap: 4px;
+    transition: all 0.2s ease;
+}
+
+.btn-view-chat:hover {
+    background: #f0f4ff;
+}
+
+.empty-tip {
+    color: #94a3b8;
+    font-size: 16px;
+    text-align: center;
+    padding: 40px 20px;
+    background: transparent;
+    border: none;
+}
+
+/* 沟通摘要样式 */
+.summary-text.compact {
+    max-height: 100px;
+    overflow-y: auto;
+    overflow-x: hidden;
+    line-height: 1.6;
+    font-size: 16px;
+    color: #475569;
+    padding-right: 4px;
+}
+
+.summary-text.compact::-webkit-scrollbar {
+    width: 6px;
+}
+
+.summary-text.compact::-webkit-scrollbar-track {
+    background: #f1f5f9;
+    border-radius: 3px;
+}
+
+.summary-text.compact::-webkit-scrollbar-thumb {
+    background: linear-gradient(180deg, #cbd5e1 0%, #94a3b8 100%);
+    border-radius: 3px;
+}
+
+.summary-text.compact::-webkit-scrollbar-thumb:hover {
+    background: linear-gradient(180deg, #94a3b8 0%, #64748b 100%);
+}
+
+/* AI 标签美化样式 */
+.tags-container {
+    padding: 0;
+    min-height: calc(16px * 5 + 6px * 4 + 12px * 2);
+    overflow-y: auto;
+    overflow-x: hidden;
+    display: flex;
+    flex-direction: column;
+}
+
+.tags-container::-webkit-scrollbar {
+    width: 6px;
+}
+
+.tags-container::-webkit-scrollbar-track {
+    background: #f1f5f9;
+    border-radius: 3px;
+}
+
+.tags-container::-webkit-scrollbar-thumb {
+    background: linear-gradient(180deg, #cbd5e1 0%, #94a3b8 100%);
+    border-radius: 3px;
+}
+
+.tags-container::-webkit-scrollbar-thumb:hover {
+    background: linear-gradient(180deg, #94a3b8 0%, #64748b 100%);
+}
+
+/* 标签列表 - 每行一个 */
+.tags-list {
+    display: flex;
+    flex-direction: column;
+    gap: 6px;
+    margin-bottom: 6px;
+}
+
+.tag-item {
+    display: flex;
+    align-items: center;
+    gap: 6px;
+    padding: 6px 10px;
+    background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
+    border: 1px solid #e2e8f0;
+    border-radius: 6px;
+    font-size: 15px;
+    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+    cursor: default;
+    position: relative;
+    overflow: hidden;
+}
+
+.tag-item::before {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 4px;
+    height: 100%;
+    background: linear-gradient(180deg, #94a3b8 0%, #64748b 100%);
+    transition: width 0.3s ease;
+}
+
+.tag-item:hover {
+    background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
+    border-color: #cbd5e1;
+    transform: translateX(6px);
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+}
+
+.tag-item:hover::before {
+    width: 5px;
+    background: linear-gradient(180deg, #3b82f6 0%, #2563eb 100%);
+}
+
+.tag-highlight {
+    background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
+    border-color: #bfdbfe;
+}
+
+.tag-highlight::before {
+    background: linear-gradient(180deg, #3b82f6 0%, #2563eb 100%);
+}
+
+.tag-key {
+    font-weight: 600;
+    color: #475569;
+    white-space: nowrap;
+    flex-shrink: 0;
+    font-size: 15px;
+}
+
+.tag-separator {
+    color: #94a3b8;
+    font-weight: 300;
+    flex-shrink: 0;
+    font-size: 15px;
+}
+
+.tag-value {
+    color: #1e293b;
+    font-weight: 500;
+    word-break: break-word;
+    flex: 1;
+    min-width: 0;
+    font-size: 15px;
+}
+
+.empty-tags {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    padding: 40px 20px;
+    color: #94a3b8;
+    font-size: 17px;
+    background: linear-gradient(135deg, rgba(248, 250, 252, 0.5) 0%, rgba(241, 245, 249, 0.5) 100%);
+    border-radius: 12px;
+    border: 2px dashed #e2e8f0;
+}
+
+.empty-tags i {
+    font-size: 32px;
+    margin-bottom: 12px;
+    opacity: 0.5;
+}
+
+.tags-actions {
+    display: flex;
+    justify-content: center;
+    padding: 16px 0;
+    border-top: 1px solid #f1f5f9;
+    margin-top: auto;
+    background: white;
+    position: sticky;
+    bottom: 0;
+    z-index: 10;
+}
+
+.btn-expand-tags,
+.btn-collapse-tags {
+    background: transparent;
+    color: #667eea;
+    border: 1px solid #667eea;
+    padding: 8px 16px;
+    border-radius: 6px;
+    font-size: 16px;
+    cursor: pointer;
+    display: inline-flex;
+    align-items: center;
+    gap: 6px;
+    transition: all 0.2s ease;
+}
+
+.btn-expand-tags:hover,
+.btn-collapse-tags:hover {
+    background: rgba(102, 126, 234, 0.05);
+    border-color: #5a67d8;
+    color: #5a67d8;
+}
+
+.btn-expand-tags:active,
+.btn-collapse-tags:active {
+    transform: scale(0.98);
+}
+
+/* 微信风格聊天弹窗 */
+.chat-dialog-overlay {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: rgba(0, 0, 0, 0.5);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    z-index: 9999;
+    backdrop-filter: blur(4px);
+}
+
+.chat-dialog {
+    background: white;
+    border-radius: 16px;
+    width: 90%;
+    max-width: 800px;
+    height: 600px;
+    display: flex;
+    flex-direction: column;
+    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
+    animation: slideIn 0.3s ease-out;
+    position: relative;
+}
+
+@keyframes slideIn {
+    from {
+        opacity: 0;
+        transform: translateY(-20px);
+    }
+    to {
+        opacity: 1;
+        transform: translateY(0);
+    }
+}
+
+.chat-dialog-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 16px 20px;
+    border-bottom: 1px solid #eef2ff;
+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    border-radius: 16px 16px 0 0;
+    color: white;
+}
+
+.chat-title {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+    font-size: 16px;
+    font-weight: 700;
+}
+
+.btn-close {
+    position: absolute;
+    top: 16px;
+    right: 16px;
+    background: white;
+    border: 2px solid #e2e8f0;
+    color: #1a202c;
+    width: 36px;
+    height: 36px;
+    border-radius: 50%;
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    transition: all 0.3s ease;
+    font-size: 24px;
+    font-weight: bold;
+    line-height: 1;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+    z-index: 10;
+}
+
+.btn-close:hover {
+    background: #ef4444;
+    border-color: #ef4444;
+    color: white;
+    transform: rotate(90deg) scale(1.1);
+    box-shadow: 0 4px 16px rgba(239, 68, 68, 0.4);
+}
+
+.chat-dialog-body {
+    flex: 1;
+    overflow-y: auto;
+    padding: 20px;
+    background: #f5f7fa;
+}
+
+.chat-messages {
+    display: flex;
+    flex-direction: column;
+    gap: 16px;
+}
+
+.message-item {
+    display: flex;
+    align-items: flex-start;
+    margin-bottom: 8px;
+}
+
+.message-left {
+    justify-content: flex-start;
+}
+
+.message-right {
+    justify-content: flex-end;
+}
+
+/* 客户消息强制布局:头像在右 */
+.message-item-customer {
+    display: flex !important;
+    flex-direction: row !important;
+    justify-content: flex-end !important;
+    gap: 10px !important;
+}
+
+.message-wrapper {
+    display: flex;
+    align-items: flex-start;
+    gap: 10px;
+    max-width: 75%;
+}
+
+.message-wrapper-left {
+    flex-direction: row;
+}
+
+.message-name {
+    font-size: 12px;
+    color: #94a3b8;
+    white-space: nowrap;
+    text-align: left;
+    margin-bottom: 4px;
+    line-height: 1.2;
+}
+
+.message-name-ai {
+    color: #667eea;
+    font-weight: 500;
+}
+
+.message-avatar {
+    width: 32px;
+    height: 32px;
+    border-radius: 6px;
+    overflow: hidden;
+    flex-shrink: 0;
+    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
+    background: #f0f0f0;
+}
+
+.message-avatar img {
+    width: 100%;
+    height: 100%;
+    object-fit: cover;
+    transition: transform 0.3s ease;
+}
+
+.message-avatar:hover img {
+    transform: scale(1.1);
+}
+
+.message-wrapper-left .message-avatar {
+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-shrink: 0;
+}
+
+.message-wrapper-right .message-avatar {
+    background: linear-gradient(135deg, #10b981 0%, #059669 100%);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-shrink: 0;
+}
+
+.message-content {
+    display: flex;
+    flex-direction: column;
+    max-width: calc(100% - 42px);
+}
+
+.message-wrapper-left .message-content {
+    align-items: flex-start;
+    margin-left: 4px;
+}
+
+.message-wrapper-right .message-content {
+    align-items: flex-end !important;
+    margin-right: 4px;
+}
+
+/* 客户聊天内容容器 */
+.message-content-right {
+    flex: 0 0 auto !important;
+    max-width: calc(100% - 42px) !important;
+    display: flex;
+    align-items: flex-start !important;
+}
+
+.message-bubble {
+    background: white;
+    padding: 9px 13px;
+    border-radius: 6px;
+    font-size: 14px;
+    line-height: 1.5;
+    color: #0f172a;
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
+    word-break: break-word;
+    position: relative;
+    max-width: 500px;
+}
+
+.message-bubble::before {
+    content: '';
+    position: absolute;
+    left: -6px;
+    top: 12px;
+    width: 0;
+    height: 0;
+    border-top: 5px solid transparent;
+    border-bottom: 5px solid transparent;
+    border-right: 6px solid white;
+}
+
+.message-bubble-right {
+    background: #d9fdd3;
+    color: #0f172a;
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
+    display: inline-block;
+    position: relative;
+}
+
+.message-bubble-right::before {
+    content: '';
+    position: absolute;
+    right: -6px;
+    left: auto;
+    top: 16px !important;
+    transform: none !important;
+    width: 0;
+    height: 0;
+    border-top: 5px solid transparent;
+    border-bottom: 5px solid transparent;
+    border-left: 6px solid #d9fdd3;
+    border-right: none;
+}
+
+.empty-chat-tip {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    padding: 60px 20px;
+    color: #94a3b8;
+    font-size: 14px;
+}
+
+.empty-chat-tip i {
+    font-size: 48px;
+    margin-bottom: 12px;
+    opacity: 0.5;
+}
+
+/* 客户画像样式 */
+.profile-grid {
+    display: flex;
+    flex-direction: column;
+    gap: 4px;
+    max-height: 350px;
+    overflow-y: auto;
+    overflow-x: hidden;
+    padding-right: 4px;
+    padding-top: 0;
+}
+
+.profile-grid::-webkit-scrollbar {
+    width: 6px;
+}
+
+.profile-grid::-webkit-scrollbar-track {
+    background: #f1f5f9;
+    border-radius: 3px;
+}
+
+.profile-grid::-webkit-scrollbar-thumb {
+    background: linear-gradient(180deg, #cbd5e1 0%, #94a3b8 100%);
+    border-radius: 3px;
+}
+
+.profile-grid::-webkit-scrollbar-thumb:hover {
+    background: linear-gradient(180deg, #94a3b8 0%, #64748b 100%);
+}
+
+.profile-item {
+    display: grid;
+    grid-template-columns: 42% 58%;
+    align-items: flex-start;
+    gap: 6px;
+    padding: 4px 10px;
+    border-radius: 6px;
+    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+    background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
+    border: 1px solid #e2e8f0;
+    word-break: break-word;
+}
+
+.profile-item:hover {
+    background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
+    transform: translateX(4px);
+    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
+    border-color: #cbd5e1;
+}
+
+.profile-item-main {
+    background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
+    border-color: #bfdbfe;
+    position: sticky;
+    top: 0;
+    z-index: 10;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+}
+
+.profile-item-main:hover {
+    background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
+}
+
+.profile-item-full {
+    grid-template-columns: 42% 58%;
+}
+
+.profile-item .label {
+    font-size: 15px;
+    color: #64748b;
+    font-weight: 600;
+    white-space: normal;
+    display: flex;
+    align-items: center;
+    gap: 4px;
+    line-height: 1.4;
+    min-width: 0;
+}
+
+.profile-item .label i {
+    color: #94a3b8;
+    font-size: 12px;
+    width: 14px;
+    text-align: center;
+    flex-shrink: 0;
+}
+
+.profile-item .value {
+    font-size: 16px;
+    color: #0f172a;
+    font-weight: 500;
+    word-break: break-word;
+    line-height: 1.4;
+    min-width: 0;
+}
+
+.profile-item .value.highlight {
+    color: #0369a1;
+    font-size: 16px;
+    font-weight: 600;
+}
+
+.profile-item .value.long-text {
+    color: #334155;
+    font-weight: 400;
+}
+
+.update-time-corner {
+    position: absolute;
+    bottom: 12px;
+    right: 16px;
+    font-size: 12px;
+    color: #94a3b8;
+    font-style: italic;
+}
+
+/* 客户关注点 & 意向度样式 */
+.focus-points {
+    padding: 0;
+    margin-bottom: 10px;
+}
+
+.focus-title {
+    font-size: 17px;
+    color: #64748b;
+    font-weight: 600;
+    margin-bottom: 8px;
+    display: flex;
+    align-items: center;
+    gap: 6px;
+}
+
+.focus-title i {
+    color: #3b82f6;
+    font-size: 14px;
+}
+
+.focus-list {
+    list-style: none;
+    padding: 0;
+    margin: 0;
+    max-height: 200px;
+    overflow-y: auto;
+    overflow-x: hidden;
+    padding-right: 4px;
+}
+
+.focus-list::-webkit-scrollbar {
+    width: 6px;
+}
+
+.focus-list::-webkit-scrollbar-track {
+    background: #f1f5f9;
+    border-radius: 3px;
+}
+
+.focus-list::-webkit-scrollbar-thumb {
+    background: linear-gradient(180deg, #cbd5e1 0%, #94a3b8 100%);
+    border-radius: 3px;
+}
+
+.focus-list::-webkit-scrollbar-thumb:hover {
+    background: linear-gradient(180deg, #94a3b8 0%, #64748b 100%);
+}
+
+.focus-item {
+    display: flex;
+    align-items: flex-start;
+    gap: 6px;
+    padding: 6px 10px;
+    margin-bottom: 6px;
+    background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
+    border-radius: 6px;
+    border: 1px solid #e2e8f0;
+    transition: all 0.3s ease;
+    font-size: 15px;
+    color: #334155;
+    line-height: 1.5;
+}
+
+.focus-item:hover {
+    background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
+    border-color: #bfdbfe;
+    transform: translateX(4px);
+    box-shadow: 0 2px 6px rgba(59, 130, 246, 0.1);
+}
+
+.focus-item i {
+    color: #3b82f6;
+    font-size: 10px;
+    margin-top: 1px;
+    flex-shrink: 0;
+}
+
+/* 意向度样式 - 水印风格 */
+.intention-section {
+    margin-top: 10px;
+    padding-top: 8px;
+    border-top: 1px solid #e2e8f0;
+}
+
+.intention-header {
+    margin-bottom: 6px;
+    display: flex;
+    align-items: center;
+    gap: 6px;
+}
+
+.intention-info-icon {
+    color: #94a3b8;
+    font-size: 16px;
+    cursor: pointer;
+    transition: all 0.3s ease;
+}
+
+.intention-info-icon:hover {
+    color: #3b82f6;
+}
+
+/* 意向度提示框样式 */
+.intention-tooltip {
+    line-height: 1.8;
+    font-size: 13px;
+}
+
+.intention-tooltip div {
+    padding: 2px 0;
+}
+
+.intention-tooltip strong {
+    color: #1e293b;
+    font-weight: 600;
+}
+
+.intention-label {
+    font-size: 16px;
+    font-weight: 600;
+    color: #64748b;
+    display: flex;
+    align-items: center;
+    gap: 4px;
+}
+
+.intention-label::before {
+    content: '';
+    width: 3px;
+    height: 14px;
+    background: linear-gradient(180deg, #3b82f6 0%, #2563eb 100%);
+    border-radius: 2px;
+}
+
+/* 水印风格意向度显示 - 按等级着色 */
+.intention-watermark {
+    font-size: 59px;
+    font-weight: 800;
+    text-align: center;
+    padding: 18px 12px;
+    border-radius: 10px;
+    border: 2px solid;
+    position: relative;
+    overflow: hidden;
+    letter-spacing: 6px;
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+    transition: all 0.3s ease;
+}
+
+/* A 级 - 金色/绿色,最高级别 */
+.intention-grade-a {
+    background: linear-gradient(135deg, #fef3c7 0%, #fde68a 50%, #fef3c7 100%);
+    border-color: #f59e0b;
+    color: #92400e;
+    text-shadow: 0 2px 4px rgba(146, 64, 14, 0.2);
+}
+
+.intention-grade-a::after {
+    content: 'A';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%) rotate(-25deg);
+    font-size: 90px;
+    font-weight: 900;
+    color: rgba(245, 158, 11, 0.08);
+    z-index: 0;
+    pointer-events: none;
+}
+
+/* B 级 - 蓝色 */
+.intention-grade-b {
+    background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 50%, #dbeafe 100%);
+    border-color: #3b82f6;
+    color: #1e40af;
+    text-shadow: 0 2px 4px rgba(30, 64, 175, 0.2);
+}
+
+.intention-grade-b::after {
+    content: 'B';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%) rotate(-25deg);
+    font-size: 90px;
+    font-weight: 900;
+    color: rgba(59, 130, 246, 0.08);
+    z-index: 0;
+    pointer-events: none;
+}
+
+/* C 级 - 紫色 */
+.intention-grade-c {
+    background: linear-gradient(135deg, #e9d5ff 0%, #d8b4fe 50%, #e9d5ff 100%);
+    border-color: #a855f7;
+    color: #6b21a8;
+    text-shadow: 0 2px 4px rgba(107, 33, 168, 0.2);
+}
+
+.intention-grade-c::after {
+    content: 'C';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%) rotate(-25deg);
+    font-size: 90px;
+    font-weight: 900;
+    color: rgba(168, 85, 247, 0.08);
+    z-index: 0;
+    pointer-events: none;
+}
+
+/* D 级 - 橙色 */
+.intention-grade-d {
+    background: linear-gradient(135deg, #fed7aa 0%, #fdba74 50%, #fed7aa 100%);
+    border-color: #f97316;
+    color: #9a3412;
+    text-shadow: 0 2px 4px rgba(154, 52, 18, 0.2);
+}
+
+.intention-grade-d::after {
+    content: 'D';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%) rotate(-25deg);
+    font-size: 90px;
+    font-weight: 900;
+    color: rgba(249, 115, 22, 0.08);
+    z-index: 0;
+    pointer-events: none;
+}
+
+/* E 级 - 粉红色 */
+.intention-grade-e {
+    background: linear-gradient(135deg, #fbcfe8 0%, #f9a8d4 50%, #fbcfe8 100%);
+    border-color: #ec4899;
+    color: #9d174d;
+    text-shadow: 0 2px 4px rgba(157, 23, 77, 0.2);
+}
+
+.intention-grade-e::after {
+    content: 'E';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%) rotate(-25deg);
+    font-size: 90px;
+    font-weight: 900;
+    color: rgba(236, 72, 153, 0.08);
+    z-index: 0;
+    pointer-events: none;
+}
+
+/* F 级 - 红色,最低级别 */
+.intention-grade-f {
+    background: linear-gradient(135deg, #fecaca 0%, #fca5a5 50%, #fecaca 100%);
+    border-color: #ef4444;
+    color: #991b1b;
+    text-shadow: 0 2px 4px rgba(153, 27, 27, 0.2);
+}
+
+.intention-grade-f::after {
+    content: 'F';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%) rotate(-25deg);
+    font-size: 90px;
+    font-weight: 900;
+    color: rgba(239, 68, 68, 0.08);
+    z-index: 0;
+    pointer-events: none;
+}
+
+.intention-watermark span {
+    position: relative;
+    z-index: 1;
+}
+
+/* 暂无评级提示 */
+.no-intention-tip {
+    text-align: center;
+    padding: 18px 12px;
+    font-size: 16px;
+    color: #94a3b8;
+    font-style: italic;
+    background: linear-gradient(135deg, rgba(248, 250, 252, 0.5) 0%, rgba(241, 245, 249, 0.5) 100%);
+    border-radius: 10px;
+    border: 2px dashed #e2e8f0;
+}
+
+.card-header h3 i {
+    font-size: 20px;
+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    -webkit-background-clip: text;
+    -webkit-text-fill-color: transparent;
+    background-clip: text;
+}
+
+.card-highlight .card-header h3 i {
+    color: white;
+    background: none;
+    -webkit-text-fill-color: white;
+}
+
+/* 统一为 CRM 客户分析报告风格(覆盖) */
+.customer-container {
+    max-width: 100%;
+    padding: 12px;
+    background: #f4f6fa;
+}
+
+.main-grid-three-columns {
+    grid-template-columns: 300px minmax(640px, 1fr) 320px;
+    gap: 12px;
+    align-items: start;
+}
+
+.card {
+    border-radius: 10px;
+    border: 1px solid #e6ebf2;
+    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
+    margin-bottom: 10px;
+    padding: 12px;
+    background: #fff;
+}
+
+.card::before {
+    display: none;
+}
+
+.card:hover {
+    transform: none;
+    box-shadow: 0 2px 8px rgba(15, 23, 42, 0.08);
+    border-color: #dbe4f0;
+}
+
+.card-header {
+    border-bottom: 1px solid #edf1f7;
+    margin-bottom: 10px;
+    padding-bottom: 8px;
+}
+
+.card-header h3 {
+    font-size: 16px;
+    font-weight: 600;
+    color: #1f2937;
+}
+
+.card-header h3 i {
+    width: 18px;
+    height: 18px;
+    border-radius: 4px;
+    font-size: 10px;
+    background: #4f7cff;
+    box-shadow: none;
+    -webkit-text-fill-color: #fff;
+}
+
+.summary-text.compact {
+    font-size: 14px;
+    line-height: 1.75;
+    color: #334155;
+    max-height: 132px;
+}
+
+.risk-card,
+.card-focus {
+    background: #fff;
+    border: 1px solid #e6ebf2;
+}
+
+.risk-analysis {
+    background: #f8fafc;
+    border: 1px solid #edf2f7;
+}
+
+/* 风险徽章改为标签风格 */
+.risk-badge {
+    display: inline-flex;
+    align-items: center;
+    gap: 6px;
+    padding: 5px 10px;
+    border-radius: 10px;
+    font-size: 13px;
+    font-weight: 600;
+    border: 1px solid #e5eaf1;
+    box-shadow: none;
+    transition: all 0.2s ease;
+    text-shadow: none;
+}
+
+.risk-badge::before {
+    content: '';
+    width: 8px;
+    height: 8px;
+    border-radius: 3px;
+    background: currentColor;
+    opacity: 0.35;
+}
+
+.risk-card:hover .risk-badge {
+    transform: translateY(-1px);
+}
+
+.risk-unknown .risk-badge {
+    background: #f8fafc;
+    border-color: #e5eaf1;
+    color: #64748b;
+}
+
+.risk-none .risk-badge {
+    background: #f0fdf4;
+    border-color: #bbf7d0;
+    color: #16a34a;
+}
+
+.risk-low .risk-badge {
+    background: #eff6ff;
+    border-color: #bfdbfe;
+    color: #2563eb;
+}
+
+.risk-medium .risk-badge {
+    background: #fffbeb;
+    border-color: #fde68a;
+    color: #d97706;
+}
+
+.risk-high .risk-badge {
+    background: #fef2f2;
+    border-color: #fecaca;
+    color: #dc2626;
+}
+
+/* 客户意向度:回滚为原来的“大水印渐变”样式(使用上方原始定义) */
+
+.tag-item,
+.focus-item,
+.profile-item {
+    background: #f8fafc;
+    border-color: #e5eaf1;
+}
+
+.records-table th {
+    background: #f8fafc;
+    color: #475569;
+}
+
+.records-table tbody tr:hover {
+    background: #f8fbff;
+}
+
+
+</style>

+ 2720 - 0
src/views/crm/customer/qw/externalContact.vue

@@ -0,0 +1,2720 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="企微公司" prop="corpId">
+            <el-select v-model="queryParams.corpId" placeholder="企微公司"  size="small" @change="updateCorpId()">
+              <el-option
+                v-for="dict in myQwCompanyList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              />
+            </el-select>
+      </el-form-item>
+      <el-form-item label="客户名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入客户名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="活码id" prop="wayId">
+        <el-input
+          v-model="queryParams.wayId"
+          placeholder="请输入活码id"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="销售企微昵称" prop="qwUserName">
+        <el-input
+          v-model="queryParams.qwUserName"
+          placeholder="请输入销售企微昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+          @input="searchQwUser"
+          @focus="showQwUserDropdown = true"
+          @blur="hideDropdownWithDelay"
+          @clear="onQwUserNameClear"
+        />
+        <!-- 下拉建议 -->
+        <div v-if="showQwUserDropdown && qwUserSuggestions.length > 0" class="suggestion-box"  @scroll="handleScroll">
+          <div
+            v-for="item in qwUserSuggestions"
+            :key="item.dictValue"
+            class="suggestion-item"
+            @click="selectQwUser(item.dictValue,item.dictLabel)"
+          >
+            {{ item.dictLabel }} ({{(item.dictValue)}})
+          </div>
+        </div>
+      </el-form-item>
+      <el-form-item label="用户类别" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择用户类别" clearable size="small">
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="所属销售" prop="companyUser">
+        <el-input
+          v-model="queryParams.companyUser"
+          placeholder="请输入昵称或者手机号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="性别" prop="gender">
+        <el-select v-model="queryParams.gender" placeholder="性别" clearable size="small">
+          <el-option
+            v-for="dict in genderOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否重粉" prop="userRepeat">
+        <el-select v-model="queryParams.userRepeat" placeholder="重粉" clearable size="small">
+          <el-option label="否" :value="0"/>
+          <el-option label="是" :value="1"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="客户等级" prop="level">
+        <el-select v-model="queryParams.level" placeholder="客户等级" clearable size="small">
+          <el-option
+            v-for="dict in ratingType"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="等级升降" prop="levelType">
+        <el-select v-model="queryParams.levelType" placeholder="等级升降" clearable size="small">
+          <el-option
+            v-for="dict in ratingUpFall"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+
+      <el-form-item label="电话号码" prop="remarkMobiles">
+        <el-input
+          v-model="queryParams.remarkMobiles"
+          placeholder="请输入备注电话号码"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="来源" prop="addWay">
+
+        <el-select v-model="queryParams.addWay" placeholder="来源" clearable size="small">
+          <el-option
+            v-for="dict in addWayOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+
+        <el-select v-model="queryParams.status" placeholder="状态" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="转接状态" prop="addWay">
+
+        <el-select v-model="queryParams.transferStatus" placeholder="转接状态" clearable size="small">
+          <el-option
+            v-for="dict in transferStatusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否绑定会员" prop="isBindMini">
+        <el-select v-model="queryParams.isBindMini" placeholder="是否绑定会员" clearable size="small" @change="handleQuery" >
+          <el-option
+            v-for="dict in isBindMiniOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="标签" prop="tagIds">
+        <div @click="hangleChangeTags()" style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 250px">
+          <div style="min-height: 35px; max-height: 200px; overflow-y: auto;">
+            <el-tag type="success"
+                    closable
+                    :disable-transitions="false"
+                    v-for="list in this.selectTags"
+                    :key="list.tagId"
+                    @close="handleCloseTags(list)"
+                    style="margin: 3px;"
+            >{{list.name}}
+            </el-tag>
+          </div>
+        </div>
+      </el-form-item>
+
+      <el-form-item label="排除标签" prop="outTagIds">
+        <div @click="hangleChangeOutTags()"
+             style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 250px">
+          <div style="min-height: 35px; max-height: 200px; overflow-y: auto;">
+            <el-tag type="success"
+                    closable
+                    :disable-transitions="false"
+                    v-for="list in this.outSelectTags"
+                    :key="list.tagId"
+                    @close="handleCloseOutTags(list)"
+                    style="margin: 3px;"
+            >{{ list.name }}
+            </el-tag>
+          </div>
+        </div>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input
+          v-model="queryParams.remark"
+          placeholder="请输入备注"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="添加时间" prop="createTime">
+        <el-date-picker
+          v-model="createTime"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          type="datetimerange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          @change="change"
+        ></el-date-picker>
+      </el-form-item>
+
+
+
+
+      <el-form-item label="流失时间" prop="lossTime">
+        <el-date-picker clearable size="small"
+                        v-model="queryParams.lossTime"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="选择流失时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="删除时间" prop="delTime">
+        <el-date-picker clearable size="small"
+                        v-model="queryParams.delTime"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="选择删除时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="是否下载APP" prop="isDownloadApp">
+        <el-select v-model="queryParams.isDownloadApp" placeholder="请选择是否下载app" clearable size="small">
+          <el-option label="是" :value="1" />
+          <el-option label="否" :value="0" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+<!--      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['qw:externalContact:add']"
+        >同步</el-button>
+      </el-col> -->
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          @click="handleBatchUpdateNotes"
+          v-hasPermi="['qw:externalContact:edit']"
+        >批量修改备注
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          @click="handleBatchUpdateNotesFilter"
+          v-hasPermi="['qw:externalContact:edit']"
+        >批量修改备注(筛选条件)
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['qw:externalContact:edit']"
+        >修改备注</el-button>
+      </el-col>
+
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['qw:externalContact:export']"
+        >导出</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="addUserTag"
+          v-hasPermi="['qw:externalContact:addTag']"
+        >批量添加标签</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="addUserTagFilter"
+          v-hasPermi="['qw:externalContact:addTag']"
+        >批量添加标签(筛选条件)</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="delUserTag"
+          v-hasPermi="['qw:externalContact:delTag']"
+        >批量移除标签</el-button>
+      </el-col>
+	  <el-col :span="1.5">
+	    <el-button
+	      type="primary"
+	      plain
+	      size="mini"
+	      @click="updateTalk"
+        v-hasPermi="['qw:externalContactInfo:updateTalk']"
+	    >批量更改交流状态</el-button>
+	  </el-col>
+<!--       <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="primary"-->
+<!--          plain-->
+<!--          size="mini"-->
+<!--          @click="setUserCourseSop"-->
+<!--          v-hasPermi="['qw:externalContact:setCourseSop']"-->
+<!--        >批量设置课程SOP</el-button>-->
+<!--      </el-col>-->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+<!--    <el-tabs type="card" v-model="isBindActiveName" @tab-click="handleClickX">-->
+<!--      <el-tab-pane label="全部" name="all"></el-tab-pane>-->
+<!--      <el-tab-pane label="已绑定CRM" name="isBind"></el-tab-pane>-->
+<!--      <el-tab-pane label="未绑定CRM" name="noBind"></el-tab-pane>-->
+<!--    </el-tabs>-->
+
+    <el-table v-loading="loading" :data="externalContactList" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="企微客户ID" align="center" prop="id" />
+      <el-table-column label="企微客户头像" align="center" prop="avatar" width="100px">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover">
+            <img slot="reference" :src="scope.row.avatar" width="60px">
+            <img :src="scope.row.avatar" style="max-width: 200px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="企微客户名称"  prop="name" width="110px"/>
+      <el-table-column label="客户称呼"  prop="stageStatus" width="110px"/>
+      <el-table-column label="销售企微昵称" align="center" prop="qwUserName" width="120px"/>
+      <el-table-column label="企微部门" align="center" prop="departmentName" width="120px"/>
+      <el-table-column label="用户类别" align="center" prop="type">
+        <template slot-scope="scope">
+          <dict-tag :options="typeOptions" :value="scope.row.type"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="性别" align="center" prop="gender">
+        <template slot-scope="scope">
+          <dict-tag :options="genderOptions" :value="scope.row.gender"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="描述信息" align="center" prop="description" />
+      <el-table-column label="标签" align="center" prop="tagIdsName" width="300px">
+        <template slot-scope="scope">
+          <div class="tag-container">
+            <div class="tag-list">
+              <el-tag
+                v-for="name in scope.row.tagIdsName"
+                :key="name"
+                type="success"
+                size="small"
+              >
+                {{ name }}
+              </el-tag>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="流失风险" align="center" prop="attritionLevel">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.attritionLevel == null" type="info">未分析</el-tag>
+          <el-tag v-if="scope.row.attritionLevel === 0" type="info">未知</el-tag>
+          <el-tag v-else-if="scope.row.attritionLevel === 1" type="success">无风险</el-tag>
+          <el-tag v-else-if="scope.row.attritionLevel === 2" type="info">低风险</el-tag>
+          <el-tag v-else-if="scope.row.attritionLevel === 3" type="warning">中风险</el-tag>
+          <el-tag v-else-if="scope.row.attritionLevel === 4" type="danger">高风险</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="意向度" align="center" prop="intentionDegree">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.intentionDegree !== null && scope.row.intentionDegree !== undefined && scope.row.intentionDegree !== ''">
+            {{ scope.row.intentionDegree }}
+          </el-tag>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="关注点" align="center" prop="customerFocusJson" width="220">
+        <template slot-scope="scope">
+          <div v-if="parseFocusPoints(scope.row.customerFocusJson).length" style="text-align: left;">
+            <el-tooltip
+              v-for="(item, index) in parseFocusPoints(scope.row.customerFocusJson).slice(0, 2)"
+              :key="index"
+              placement="top"
+              effect="light"
+            >
+              <div slot="content" style="max-width: 420px; word-break: break-word;">
+                {{ item }}
+              </div>
+              <el-tag style="margin: 0 6px 6px 0; max-width: 100%; background: #fff; border: 1px solid #dcdfe6; color: #606266;">
+                {{ shortenText(item, 14) }}
+              </el-tag>
+            </el-tooltip>
+            <el-tooltip
+              v-if="parseFocusPoints(scope.row.customerFocusJson).length > 2"
+              placement="top"
+              effect="light"
+            >
+              <div slot="content" style="max-width: 420px;">
+                <div
+                  v-for="(item, idx) in parseFocusPoints(scope.row.customerFocusJson).slice(2)"
+                  :key="'focus-more-' + idx"
+                  style="margin-bottom: 4px;"
+                >
+                  {{ item }}
+                </div>
+              </div>
+              <el-tag style="margin: 0 6px 6px 0; background: #fff; border: 1px solid #dcdfe6; color: #606266;">
+                +{{ parseFocusPoints(scope.row.customerFocusJson).length - 2 }}
+              </el-tag>
+            </el-tooltip>
+          </div>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否回复" align="center" prop="isReply" width="120px" >
+        <template slot-scope="scope">
+          <span v-if="scope.row.isReply === 1"><el-tag type="success">已回复</el-tag></span>
+          <span v-else-if="scope.row.isReply === 0"><el-tag type="info">未回复</el-tag></span>
+          <span v-else>{{ scope.row.isReply }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="客户等级" align="center" prop="level" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="ratingType" :value="scope.row.level"/>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="state参数" align="center" prop="state" width="100px" />
+
+      <el-table-column label="等级状态" align="center" prop="levelType" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="ratingUpFall" :value="scope.row.levelType"/>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="添加时间" align="center" prop="createTime" width="100px" />
+      <el-table-column label="流失时间" align="center" prop="lossTime" width="100px" />
+      <el-table-column label="删除时间" align="center" prop="delTime" width="100px" />
+      <el-table-column label="注册时间" align="center" prop="registerTime" width="100px" />
+      <el-table-column label="备注电话号码" align="center" prop="remarkMobiles" width="150px">
+        <template slot-scope="scope">
+          <div v-for="i in JSON.parse(scope.row.remarkMobiles)" :key="i">{{i}}</div>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注企业名称" align="center" prop="remarkCorpName" />
+      <el-table-column label="来源" align="center" prop="addWay" width="100px">
+        <template slot-scope="scope">
+          <dict-tag :options="addWayOptions" :value="scope.row.addWay"/>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="转接状态" align="center" prop="transferStatus" width="100px" >
+        <template slot-scope="scope">
+          <dict-tag :options="transferStatusOptions" :value="scope.row.transferStatus"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="企业id" align="center" prop="corpId" />
+      <el-table-column label="广告业务ID" align="center" prop="traceId" />
+      <el-table-column label="重粉看课历史" width="100px" align="center" fixed="right">
+        <template slot-scope="scope">
+          <div v-if="scope.row.fsUserId">
+            <el-tag type="success" v-if="scope.row.userRepeat == 0">正常</el-tag>
+            <el-tag type="danger" v-if="scope.row.userRepeat == 1">重粉</el-tag>
+            <el-button
+              size="mini"
+              type="text"
+              @click="showLog(scope.row)"
+            >重粉看课历史
+            </el-button>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否绑定会员" width="100px" align="center" fixed="right">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.fsUserId" >已绑定<br/>{{scope.row.fsUserId}}</el-tag>
+          <el-tag v-else type="info"> 未绑定</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否下载APP" width="100px" align="center" fixed="right">
+        <template slot-scope="scope">
+          <el-tag :type="scope.row.isDownloadApp === 1 ? 'success' : 'info'">
+            {{ scope.row.isDownloadApp === 1 ? '已下载' : '未下载' }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="重粉记录" align="center" width="100px" fixed="right">
+        <template slot-scope="scope">
+            <el-button
+                size="mini"
+                type="text"
+                @click="showRepeatRecord(scope.row)"
+            >重粉记录</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="修改" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-shopping-bag-2"
+              :disabled="!scope.row.fsUserId"
+              @click="handleCreateOrder(scope.row)"
+
+            >制单</el-button>
+          <el-button
+            v-if="scope.row.status==0||scope.row.status==2"
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['qw:externalContact:edit']"
+          >修改备注</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-user-solid"
+            @click="handleAppellation(scope.row)"
+          >修改客户称呼</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+<!--          <el-button-->
+<!--            size="mini"-->
+<!--            type="text"-->
+<!--            icon="el-icon-edit-outline"-->
+<!--            @click="handleUpdateCustomer(scope.row)"-->
+<!--            >-->
+<!--            <span v-if="scope.row.customerId">换绑CRM</span>-->
+<!--            <span v-else>绑定CRM</span>-->
+<!--          </el-button>-->
+
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit-outline"
+            @click="handleUpdateUser(scope.row)"
+            >
+            <span v-if="scope.row.fsUserId">换绑会员</span>
+            <span v-else>绑定会员</span>
+          </el-button>
+
+          <el-button
+            v-if="scope.row.fsUserId"
+            size="mini"
+            type="text"
+            icon="el-icon-thumb"
+            @click="handleUnBindUserId(scope.row)"
+            v-hasPermi="['qw:externalContact:unBindUserId']"
+          >
+            <span>解除会员绑定</span>
+          </el-button>
+
+
+<!--          <el-button v-if="scope.row.customerId"-->
+<!--            size="mini"-->
+<!--            type="text"-->
+<!--            icon="el-icon-paperclip"-->
+<!--            @click="handleShow(scope.row)"-->
+<!--          >CRM客户详情</el-button>-->
+          <el-button
+             size="mini"
+             type="text"
+             @click="handledetails(scope.row)"
+             >AI获取用户信息
+          </el-button>
+          <el-button
+             size="mini"
+             type="text"
+             @click="handleMemberdetails(scope.row)"
+             v-if="scope.row.fsUserId"
+             >
+             <span>会员详情</span>
+          </el-button>
+          <el-button
+             size="mini"
+             type="text"
+             @click="handleInfoCollection(scope.row)"
+             v-if="false"
+             >
+             <span>信息采集</span>
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleChangeStatus(scope.row)"
+            v-hasPermi="['qw:externalContact:changeStatus']"
+          >
+            修改状态
+          </el-button>
+          <el-button
+                v-if="scope.row.attritionLevel !== null && scope.row.attritionLevel !== undefined"
+                size="mini"
+                type="text"
+                @click="openAiDrawer(scope.row)"
+                v-hasPermi="['qw:externalContact:analyze:list']"
+              >AI 分析</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+    <el-drawer
+    size="75%"
+    :title="aiAnalyze.title"
+    :visible.sync="aiAnalyze.open"
+    append-to-body
+  >
+    <customer-detail
+      ref="customerAiDetail"
+      :analyze-user-id="aiAnalyze.userId"
+      :analyze-external-user-id="aiAnalyze.externalUserId"
+      :analyze-corp-id="aiAnalyze.corpId"
+      :customer-row="aiAnalyze.customerRow"
+    />
+  </el-drawer>
+    <el-drawer size="75%" :title="show.title" :visible.sync="show.open">
+      <customer-details  ref="customerDetails" @refreshList="refreshList"/>
+    </el-drawer>
+
+    <el-drawer
+        :with-header="false"
+        size="75%"
+          :title="show.title" :visible.sync="show.open">
+      <userDetails  ref="userDetails" />
+    </el-drawer>
+
+
+    <!--  搜索标签   -->
+    <el-dialog :title="changeTagDialog.title" :visible.sync="changeTagDialog.open" style="width:100%;height: 100%" append-to-body>
+
+      <div>搜索标签:
+        <el-input v-model="queryTagParams.name" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(queryTagParams.name)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <div v-for="item in tagGroupList" :key="item.id"  >
+        <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+          <span class="name-background">{{ item.name }}</span>
+        </div>
+        <!-- 添加外层滚动容器 -->
+        <div class="scroll-wrapper">
+          <div class="tag-container">
+            <a
+              v-for="tagItem in item.tag"
+              class="tag-box"
+              @click="tagSelection(tagItem)"
+              :class="{ 'tag-selected': tagItem.isSelected }"
+            >
+              {{ tagItem.name }}
+            </a>
+          </div>
+        </div>
+      </div>
+
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="tagSubmitForm(changeTagDialog.type)">确 定</el-button>
+        <el-button @click="tagCancel(changeTagDialog.type)">取消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="批量添加标签" :visible.sync="tagOpen" width="800px" append-to-body>
+      <div>搜索标签:
+        <el-input v-model="tagChange.tagName" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(tagChange.tagName)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <el-form ref="form" :model="addTagForm"  label-width="80px">
+        <div v-for="item in tagGroupList" :key="item.id" >
+          <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+            <span class="name-background">{{ item.name }}</span>
+          </div>
+          <!-- 添加外层滚动容器 -->
+          <div class="scroll-wrapper">
+            <div class="tag-container">
+              <a
+                v-for="tagItem in item.tag"
+                class="tag-box"
+                @click="tagSelection(tagItem)"
+                :class="{ 'tag-selected': tagItem.isSelected }"
+              >
+                {{ tagItem.name }}
+              </a>
+            </div>
+          </div>
+        </div>
+      </el-form>
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="addTagSubmitForm()">确 定</el-button>
+        <el-button @click="addTagCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+    <el-dialog title="批量添加客户备注" :visible.sync="notesOpen.open" width="800px" append-to-body>
+      <el-card>
+        <el-row>
+          <el-col>
+            <el-radio-group v-model="notesOpen.nameType" style="margin-bottom: 2%">
+              <el-radio :label="1">
+                客户名称添加在【新备注】【前】
+              </el-radio>
+              <el-radio :label="2">
+                客户名称添加在【新备注】【后】
+              </el-radio>
+              <el-radio :label="3">
+                不添加客户名称
+              </el-radio>
+            </el-radio-group>
+          </el-col>
+          <el-col>
+            <el-radio-group v-model="notesOpen.type">
+              <el-radio
+                :label="1"
+              >添加【新备注】在最【前】面
+              </el-radio>
+              <el-radio
+                :label="2"
+              >添加【新备注】在最【后】面
+              </el-radio>
+              <el-radio
+                :label="3"
+              >替换所有备注
+              </el-radio>
+            </el-radio-group>
+          </el-col>
+          <el-col>
+            <el-input v-model="notesOpen.notes" placeholder="请输入客户备注(最多20个字,含已有的)" clearable size="small"
+                      maxlength="20" show-word-limit style="width: 500px;margin-top: 3%"/>
+            <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
+              <i class="el-icon-info"></i>
+              由于企业微信官方限制,备注最多20个字,且自动会去除末尾超出的字
+            </div>
+          </el-col>
+        </el-row>
+      </el-card>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="notesSubmitForm()">确 定</el-button>
+        <el-button @click="notesCancel()">取消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="批量移除标签" :visible.sync="tagDelOpen" width="800px" append-to-body>
+      <div>搜索标签:
+        <el-input v-model="queryTagParams.name" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(queryTagParams.name)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <el-form ref="form" :model="addTagForm"  label-width="80px">
+        <div v-for="item in tagGroupList" :key="item.id" >
+          <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+            <span class="name-background">{{ item.name }}</span>
+          </div>
+          <!-- 添加外层滚动容器 -->
+          <div class="scroll-wrapper">
+            <div class="tag-container">
+              <a
+                v-for="tagItem in item.tag"
+                class="tag-box"
+                @click="tagSelection(tagItem)"
+                :class="{ 'tag-selected': tagItem.isSelected }"
+              >
+                {{ tagItem.name }}
+              </a>
+            </div>
+          </div>
+        </div>
+      </el-form>
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="tagDelSubmitForm()">确 定</el-button>
+        <el-button @click="DelTagCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 添加或修改企业微信客户对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+
+
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="描述信息" prop="description">
+          <el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入描述信息" />
+        </el-form-item>
+
+        <el-form-item label="备注电话号码" prop="remarkMobiles">
+
+          <el-tag
+            :key="tag"
+            v-for="tag in remarkMobiles"
+            closable
+            :disable-transitions="false"
+            @close="handleClose(tag)">
+            {{tag}}
+          </el-tag>
+          <el-input
+            style="width:110px"
+            class="input-new-tag"
+            v-if="inputVisible"
+            v-model="inputValue"
+            ref="saveTagInput"
+            size="small"
+            @keyup.enter.native="handleInputConfirm"
+            @blur="handleInputConfirm"
+          >
+          </el-input>
+          <el-button v-else class="button-new-tag" size="small" style="width: 110px" @click="showInput">新增电话</el-button>
+
+        </el-form-item>
+
+
+        <el-form-item label="备注企业名称" prop="remarkCorpName">
+          <el-input v-model="form.remarkCorpName" placeholder="请输入备注企业名称" />
+        </el-form-item>
+
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog :title="callOpen.title" :visible.sync="callOpen.open" width="500px" append-to-body>
+      <el-form ref="callOpenFrom" :model="callOpenFrom" :rules="callOpenRule" label-width="110px">
+        <el-form-item label="客户称呼" prop="stageStatus">
+          <el-input v-model="callOpenFrom.stageStatus" placeholder="请输入客户称呼" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer" >
+        <el-button type="primary" @click="submitCallOpenFrom">确 定</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 绑定客户   -->
+    <el-dialog :title="bindCustomer.title" :visible.sync="bindCustomer.open"  width="1200px" append-to-body>
+      <mycustomer ref="mycustomer"  @bindCustomerId="bindCustomerId"></mycustomer>
+    </el-dialog>
+
+    <!-- 重粉看课记录   -->
+    <el-drawer title="重粉看课历史" :visible.sync="log.open" size="75%" append-to-body>
+      <div style="padding: 10px">
+        <el-form :model="log.queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+          <el-form-item label="所属项目" prop="project">
+            <el-select v-model="log.queryParams.project" placeholder="请选择项目" filterable clearable size="small">
+              <el-option
+                v-for="dict in projectOptions"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="课程" prop="courseId">
+            <el-select filterable v-model="log.queryParams.courseId" placeholder="请选择课程" clearable size="small"
+                       @change="courseChange(log.queryParams.courseId)">
+              <el-option
+                v-for="dict in courseLists"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="小节" prop="videoId">
+            <el-select filterable v-model="log.queryParams.videoId" placeholder="请选择小节" clearable size="small">
+              <el-option
+                v-for="dict in videoList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQueryWatchLog">搜索</el-button>
+          </el-form-item>
+        </el-form>
+        <el-table v-loading="log.loading" :data="log.list">
+          <el-table-column label="编号" align="center" prop="id"/>
+          <el-table-column label="所属企微主体" align="center" prop="corpName"/>
+          <el-table-column label="所属企微" align="center" prop="qwUserName"/>
+          <!--          <el-table-column label="企微" align="center" prop="qwUserName"/>-->
+          <el-table-column label="项目" align="center" prop="projectName"/>
+          <el-table-column label="课程" align="center" prop="courseName"/>
+          <el-table-column label="小节" align="aligner" prop="videoName"/>
+          <el-table-column label="记录时间" align="center" prop="createTime"/>
+          <el-table-column label="是否完课" align="center" prop="logType">
+            <template slot-scope="scope">
+              <el-tag v-if="scope.row.logType == 2" type="success">已完课</el-tag>
+              <el-tag v-else type="success">未完课</el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="完课时间" align="center" prop="finishTime"/>
+        </el-table>
+
+        <pagination
+          v-show="log.total>0"
+          :total="log.total"
+          :page.sync="log.queryParams.pageNum"
+          :limit.sync="log.queryParams.pageSize"
+          @pagination="logList"
+        />
+      </div>
+    </el-drawer>
+
+    <!-- 重粉记录 -->
+    <el-drawer title="重粉记录" :visible.sync="repeatRecord.open" size="75%" append-to-body>
+      <div style="padding: 10px">
+        <el-form :model="repeatRecord.queryParams" ref="repeatRecordQueryForm" :inline="true" label-width="110px">
+          <el-form-item label="销售企微ID" prop="qwUserId">
+            <el-input
+              v-model="repeatRecord.queryParams.qwUserId"
+              placeholder="请输入销售企微ID"
+              clearable
+              size="small"
+              @keyup.enter.native="handleQueryRepeatRecord"
+            />
+          </el-form-item>
+          <el-form-item label="销售企微昵称" prop="qwUserName">
+            <el-input
+              v-model="repeatRecord.queryParams.qwUserName"
+              placeholder="请输入销售企微昵称"
+              clearable
+              size="small"
+              @keyup.enter.native="handleQueryRepeatRecord"
+            />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQueryRepeatRecord">搜索</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="resetRepeatRecordQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+        <el-table v-loading="repeatRecord.loading" :data="repeatRecord.list" border>
+          <el-table-column label="企微客户ID" align="center" prop="externalUserId" min-width="140" />
+          <el-table-column label="企微客户昵称" align="center" prop="externalUserName" min-width="120" />
+          <el-table-column label="销售企微ID" align="center" prop="qwUserId" min-width="120" />
+          <el-table-column label="销售企微昵称" align="center" prop="qwUserName" min-width="120" />
+          <el-table-column label="企微部门" align="center" prop="deptName" min-width="120" />
+          <el-table-column label="添加时间" align="center" prop="createTime" width="170" />
+          <el-table-column label="注册时间" align="center" prop="registerTime" width="170" />
+        </el-table>
+        <pagination
+          v-show="repeatRecord.total > 0"
+          :total="repeatRecord.total"
+          :page.sync="repeatRecord.queryParams.pageNum"
+          :limit.sync="repeatRecord.queryParams.pageSize"
+          @pagination="repeatRecordList"
+        />
+      </div>
+    </el-drawer>
+
+<!--    设置一个课程sop-->
+    <el-dialog :title="setSop.title" :visible.sync="setSop.open"  width="1200px" append-to-body>
+      <SopDialog ref="SopDialog"  @bindCourseSop="bindCourseSop"></SopDialog>
+    </el-dialog>
+
+    <el-dialog :title="user.title" :visible.sync="user.open" width="800px" append-to-body>
+      <selectUser ref="selectUser" @bindMiniCustomerId="bindMiniCustomerId"></selectUser>
+    </el-dialog>
+
+	<el-dialog :title="info.title" :visible.sync="info.open"   width="1100px" append-to-body>
+	  <info  ref="Details" />
+	</el-dialog>
+
+  <el-dialog :title="collection.title" :visible.sync="collection.open"   width="1100px" append-to-body>
+	  <collection   ref="collection" />
+	</el-dialog>
+
+    <!--  制单页面组件    -->
+    <create-oder ref="createOder" />
+
+  <el-dialog title="修改客户状态" :visible.sync="statusDialog.open" width="500px" append-to-body>
+    <el-form ref="statusForm" :model="statusForm" :rules="statusRules" label-width="100px">
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="statusForm.status" placeholder="请选择状态" size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+    </el-form>
+    <div slot="footer" class="dialog-footer">
+      <el-button @click="statusDialog.open = false">取 消</el-button>
+      <el-button type="primary" @click="submitStatusForm">提 交</el-button>
+    </div>
+  </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  bindUserId,
+  addTag,
+  delTag,
+  batchUpdateExternalContactNotes,
+  listExternalContact,
+  getExternalContact,
+  delExternalContact,
+  addExternalContact,
+  updateExternalContact,
+  exportExternalContact,
+  editbindCustomer,
+  setCustomerCourseSop,
+  getCustomerCourseSop,
+  setCustomerCourseSopList,
+  unBindUserId, updateExternalContactCall,updateExternalContactStatus,getWatchLogList,getRepeatRecordList
+} from '@/api/qw/externalContact'
+import {getMyQwUserList, getMyQwCompanyList, updateUser,getQwUserListLikeName} from "@/api/qw/user";
+import {listTag, getTag, searchTags} from "@/api/qw/tag";
+import { allListTagGroup,allListTagGroupPage} from "@/api/qw/tagGroup";
+import mycustomer from '@/views/qw/externalContact/mycustomer.vue'
+import customerDetails from '@/views/qw/externalContact/customerDetails.vue'
+import SopDialog from '@/views/course/sop/SopDialog.vue'
+import  selectUser  from "@/views/qw/externalContact/selectUser.vue";
+import  collection  from "@/views/qw/externalContact/collection.vue";
+import info from "@/views/qw/externalContact/info.vue";
+import { editTalk } from "@/api/qw/externalContactInfo";
+import PaginationMore from "../../../../components/PaginationMore/index.vue";
+import userDetails from '@/views/store/components/userDetails.vue';
+import {courseList, videoList} from "@/api/course/courseRedPacketLog";
+import Collection from './collection.vue';
+import customerDetail from '../customerDetail.vue';
+import createOder from '@/views/components/order/createOder.vue';
+export default {
+  name: "ExternalContact",
+  components:{PaginationMore, mycustomer,customerDetails,customerDetail,SopDialog,selectUser,info,userDetails,collection,createOder},
+  data() {
+    return {
+      projectOptions: [],
+      courseLists: [],
+      videoList: [],
+      //重粉记录的参数
+      log: {
+        open: false,
+        loading: true,
+        list: [],
+        total: 0,
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          externalUserId: null,
+          fsUserId: null,
+          projectId: null,
+          courseId: null,
+          videoId: null,
+        },
+      },
+      repeatRecord: {
+        open: false,
+        loading: false,
+        list: [],
+        total: 0,
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          corpId: null,
+          externalUserId: null,
+          qwUserId: null,
+          qwUserName: null
+        }
+      },
+      statusDialog: {
+        open: false,
+        title: "修改客户状态"
+      },
+      statusForm: {
+        id: null,
+        status: null
+      },
+      statusRules: {
+        status: [
+          {required: true, message: '状态不能为空', trigger: 'change'}
+        ]
+      },
+      notesOpen: {
+        type: 1,
+        nameType: 3,
+        addType: 0,
+        filter: false,
+        open: false,
+        notes: null,
+      },
+      user:{
+        open:false,
+        title:"修改客户"
+      },
+      userForm:{
+        id:null,
+        fsUserId:null,
+      },
+      info:{
+        title:"用户信息",
+        open:false,
+      },
+      collection:{
+        titile:"信息采集",
+        open:false,
+      },
+      // ...其他已有数据
+      qwUserSuggestions: [],       // 已展示的数据
+      showQwUserDropdown: false,   // 控制下拉框显示
+      qwUserLoading: false,        // 加载状态
+      qwUserNoMore: false,         // 是否还有更多数据
+      qwUserPageNum: 1,            // 当前页码
+      qwUserPageSize: 10,          // 每页数量
+      qwUserTotal: 0,               // 总数
+      isBindMiniOptions:[
+        {dictLabel:"已绑定",dictValue:'isBindMini'},
+        {dictLabel:"未绑定",dictValue:'noBindMini'},
+      ],
+      //标签弹窗选择
+      tagChange:{
+        open:false,
+        index:null,
+      },
+	  sTime:null,
+	  eTime:null,
+	  createTime:null,
+      // 遮罩层
+      loading: false,
+      // 导出遮罩层
+      exportLoading: false,
+      tagOpen:false,
+      tagDelOpen:false,
+      // 选中数组
+      ids: [],
+      isBindActiveName:"all",
+      remarkMobiles: [],
+      inputVisible: false,
+      inputValue: '',
+      // 非单个禁用
+      single: true,
+      tagGroupList: [],
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企业微信客户表格数据
+      externalContactList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 用户类别字典
+      typeOptions: [],
+      ratingType: [],
+      ratingUpFall: [],
+      // 性别字典
+      genderOptions: [],
+
+      addTagForm:{
+        userIds:[],
+        tagIds:[],
+        filter: false,
+        addType: 0,
+      },
+
+      myQwCompanyList:[],
+      show:{
+        title:"客户详情",
+        open:false,
+      },
+
+      //存储选择的客户
+      chooseCustomerSOP:null,
+
+      setSop:{
+        title:"选择课节SOP",
+        open:false,
+        //区分单选1还是多选2
+        type:null,
+      },
+      //合成的客户-课节SOP参数
+      customerCourseForm:{},
+
+      //查询是否已经设置过客户-某个课节的SOP
+      customerCourseFormLogs:{},
+      //绑定客户
+      bindCustomer:{
+        title:null,
+        open:false,
+      },
+      callOpen:{
+        open:false,
+        title: '修改客户称呼',
+      },
+      callOpenFrom:{
+        id:null,
+        stageStatus:null,
+      },
+      callOpenRule:{
+        stageStatus:[{required:true,message:"员工称呼不能为空",trigger:"blur"}]
+      },
+      //绑定的参数表
+      qwFormCustomer:{
+        externalContactId:null,
+        customerId:null,
+      },
+      // 来源字典
+      addWayOptions: [],
+
+      //标签
+      changeTagDialog:{
+        title:"",
+        open:false,
+        type: null,
+      },
+
+      queryTagParams:{
+        pageNum: 1,
+        pageSize: 5,
+        total:0,
+        name:null,
+        corpId:null,
+      },
+
+      tagTotal:0,
+      tagFilter:false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        qwUserName:null,
+        externalUserId: null,
+        name: null,
+        avatar: null,
+        type: null,
+        qwUserId:null,
+        gender: null,
+        description: null,
+        tagIds: null,
+        outTagIds: null,
+        remark:null,
+        remarkMobiles: null,
+        remarkCorpName: null,
+        addWay: null,
+        operUserid: null,
+        corpId: null,
+        companyId: null,
+        status:null,
+        transferStatus:null,
+        isBind:null,
+        isBindMini:null,
+        lossTime:null,
+        sTime:null,
+        eTime:null,
+        createTime:null,
+        level:null,
+        wayId:null,
+        levelType:null,
+        companyUser:null,
+        userRepeat: null,
+        delTime: null,
+        isDownloadApp: null
+      },
+      //选择的标签
+      selectTags:[],
+      //排除的标签
+      outSelectTags:[],
+      // 表单参数
+      form: {},
+      tagList:[],
+      transferStatusOptions:[],
+      statusOptions:[],
+      // 表单校验
+      rules: {
+      },
+      userId:null,
+      aiAnalyze: {
+        title: "AI 分析",
+        open: false,
+        userId: null,
+        externalUserId: null,
+        corpId: null,
+        customerRow: null,
+      },
+    };
+  },
+  created() {
+    this.getDicts("sys_course_project").then(response => {
+      this.projectOptions = response.data;
+    });
+
+    this.getDicts("sys_qw_externalContact_type").then(response => {
+      this.typeOptions = response.data;
+    });
+
+    this.getDicts("sys_qw_sop_rating_type").then(response => {
+      this.ratingType = response.data;
+    });
+
+    this.getDicts("sys_qw_sop_rating_upFall").then(response => {
+      this.ratingUpFall = response.data;
+    });
+
+    getMyQwCompanyList().then(response => {
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+
+              var listTagFrom={corpId:this.queryParams.corpId}
+              listTag(listTagFrom).then(response => {
+                this.tagList = response.rows;
+              });
+              this.getList();
+
+            }
+    });
+
+
+    this.getDicts("sys_sex").then(response => {
+      this.genderOptions = response.data;
+    });
+    this.getDicts("sys_qw_externalContact_addWay").then(response => {
+      this.addWayOptions = response.data;
+    });
+
+
+
+    this.getDicts("sys_qw_external_contact_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_qw_transfer_status").then(response => {
+      this.transferStatusOptions = response.data;
+    });
+
+  },
+  methods: {
+    handleCreateOrder(row) {
+      this.$refs.createOder.show(row);
+    },
+    shortenText(text, maxLen = 16) {
+      const str = text == null ? '' : String(text);
+      if (str.length <= maxLen) return str;
+      return str.slice(0, maxLen) + '...';
+    },
+    parseFocusPoints(value) {
+      if (!value) return [];
+      if (Array.isArray(value)) {
+        return value.map(item => String(item).trim()).filter(Boolean);
+      }
+      if (typeof value === 'string') {
+        const raw = value.trim();
+        if (!raw) return [];
+        try {
+          const parsed = JSON.parse(raw);
+          if (Array.isArray(parsed)) {
+            return parsed.map(item => String(item).trim()).filter(Boolean);
+          }
+          if (typeof parsed === 'string') {
+            return [parsed.trim()].filter(Boolean);
+          }
+        } catch (e) {
+          // ignore parse error and use raw fallback
+        }
+        return [raw.replace(/^\[|\]$/g, '').replace(/["']/g, '').trim()].filter(Boolean);
+      }
+      return [String(value).trim()].filter(Boolean);
+    },
+    openAiDrawer(row) {
+      this.aiAnalyze.userId = row.userId;
+      this.aiAnalyze.externalUserId = row.operUserid ;
+      this.aiAnalyze.corpId = row.corpId ;
+      this.aiAnalyze.customerRow = row;
+      this.aiAnalyze.open = true;
+    },
+    /** 重粉查看操作 */
+    showLog(row) {
+      this.log.queryParams.fsUserId = row.fsUserId;
+      this.log.open = true;
+      this.log.loading = true;
+      courseList().then(response => {
+        this.courseLists = response.list;
+        this.logList();
+      })
+    },
+    handleQueryWatchLog() {
+      this.log.queryParams.pageNum = 1;
+      this.log.queryParams.pageSize = 10;
+      this.logList();
+    },
+    logList() {
+      getWatchLogList(this.log.queryParams).then(e => {
+        this.log.loading = false;
+        this.log.list = e.rows;
+        this.log.total = e.total;
+      });
+    },
+    /** 重粉记录 */
+    showRepeatRecord(row) {
+      this.repeatRecord.queryParams.corpId = row.corpId;
+      this.repeatRecord.queryParams.externalUserId = row.externalUserId;
+      this.repeatRecord.queryParams.qwUserId = null;
+      this.repeatRecord.queryParams.qwUserName = null;
+      this.repeatRecord.queryParams.pageNum = 1;
+      this.repeatRecord.queryParams.pageSize = 10;
+      this.repeatRecord.open = true;
+      this.repeatRecordList();
+    },
+    handleQueryRepeatRecord() {
+      this.repeatRecord.queryParams.pageNum = 1;
+      this.repeatRecordList();
+    },
+    resetRepeatRecordQuery() {
+      this.repeatRecord.queryParams.qwUserId = null;
+      this.repeatRecord.queryParams.qwUserName = null;
+      this.repeatRecord.queryParams.pageNum = 1;
+      this.repeatRecordList();
+    },
+    repeatRecordList() {
+      this.repeatRecord.loading = true;
+      getRepeatRecordList(this.repeatRecord.queryParams).then(res => {
+        this.repeatRecord.list = res.rows || [];
+        this.repeatRecord.total = res.total || 0;
+      }).finally(() => {
+        this.repeatRecord.loading = false;
+      });
+    },
+    courseChange(row) {
+      this.log.queryParams.videoId = null;
+      if (row === '') {
+        this.videoList = [];
+        return
+      }
+      videoList(row).then(response => {
+        this.videoList = response.list
+      });
+    },
+    handleMemberdetails(row){
+            this.show.open=true;
+            setTimeout(() => {
+                 this.$refs.userDetails.getDetails(row.fsUserId);
+            }, 1);
+    },
+    handleInfoCollection(row){
+      this.collection.title = "信息采集";
+      this.collection.open = true;
+      this.userId = row.fsUserId;
+      setTimeout(() => {
+                 this.$refs.collection.getCollectionInfo(row.fsUserId);
+            }, 1);
+    },
+    closeCollection(){
+      this.collection.open = false;
+    },
+    onQwUserNameClear() {
+      this.queryParams.qwUserId = null;  // 同时清空 qwUserId
+    },
+    // 搜索企微用户
+    searchQwUser(query) {
+      if (!query.trim()) {
+        this.qwUserSuggestions = [];
+        this.showQwUserDropdown = false;
+        this.qwUserNoMore = false;
+        this.qwUserPageNum = 1;
+        return;
+      }
+
+      this.queryParams.qwUserName = query;
+      this.qwUserPageNum = 1;
+      this.qwUserNoMore = false;
+      this.qwUserSuggestions = [];
+      this.fetchQwUsers(query);
+    },
+
+    fetchQwUsers(query) {
+      const params = {
+        qwUserName: query,
+        pageNum: this.qwUserPageNum,
+        pageSize: this.qwUserPageSize
+      };
+
+      this.qwUserLoading = true;
+
+      getQwUserListLikeName(params).then(res => {
+        const list = res.data.list || [];
+        const total = res.data.total || 0;
+
+        this.qwUserSuggestions = [...this.qwUserSuggestions, ...list];
+        this.qwUserTotal = total;
+
+        // 判断是否还有更多数据
+        if (this.qwUserSuggestions.length >= total) {
+          this.qwUserNoMore = true;
+        }
+
+        this.showQwUserDropdown = true;
+      }).finally(() => {
+        this.qwUserLoading = false;
+      });
+    },
+
+    // 选择企微用户
+    selectQwUser(key,value) {
+      this.queryParams.qwUserName = value;
+      this.queryParams.qwUserId = key;
+      this.showQwUserDropdown = false;
+      this.handleQuery(); // 可选:自动触发查询
+    },
+
+    // 延迟隐藏下拉框,防止点击失效
+    hideDropdownWithDelay() {
+      setTimeout(() => {
+        this.showQwUserDropdown = false;
+      }, 200);
+    },
+    handleScroll(e) {
+      const container = e.target;
+      const scrollTop = container.scrollTop;
+      const scrollHeight = container.scrollHeight;
+      const clientHeight = container.clientHeight;
+
+      // 距离底部小于 20px 触发加载
+      if (scrollHeight - scrollTop - clientHeight < 20 && !this.qwUserLoading && !this.qwUserNoMore) {
+        this.qwUserPageNum += 1;
+        this.fetchQwUsers(this.queryParams.qwUserName);
+      }
+    },
+
+
+	  change(){
+			if(this.createTime!=null){
+			  this.queryParams.sTime=this.createTime[0];
+			  this.queryParams.eTime=this.createTime[1];
+			}else{
+			  this.queryParams.sTime=null;
+			  this.queryParams.eTime=null;
+			}
+
+		  },
+    updateCorpId(){
+      var listTagFrom={corpId:this.queryParams.corpId}
+        listTag(listTagFrom).then(response => {
+          this.tagList = response.rows;
+        });
+        this.getList();
+     },
+     handleChangeStatus(row) {
+      this.statusForm = {
+        id: row.id,
+        status: String(row.status) // 保证与 dictValue 类型一致
+      };
+      this.statusDialog.open = true;
+    },
+    submitStatusForm() {
+      this.$refs["statusForm"].validate(valid => {
+        if (valid) {
+          const params = {
+            id: this.statusForm.id,
+            status: this.statusForm.status
+          };
+
+          // 调用接口更新状态
+          updateExternalContactStatus(params).then(response => {
+            this.msgSuccess("状态修改成功");
+            this.statusDialog.open = false;
+            this.getList(); // 刷新列表
+          }).catch(error => {
+            console.error('状态修改失败:', error);
+            this.$message.error('状态修改失败');
+          });
+        }
+      });
+    },
+    /** 查询企业微信客户列表 */
+    getList() {
+      this.loading = true;
+      const { qwUserName, ...queryParams } = this.queryParams;
+      listExternalContact(queryParams).then(response => {
+        this.externalContactList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    bindMiniCustomerId(row){
+      console.log(row)
+      this.userForm.fsUserId=row;
+      bindUserId(this.userForm).then(res=>{
+         if (res.code==200){
+           this.$message.success('绑定成功')
+         }else {
+           this.$message.error('绑定失败:',res.msg)
+         }
+         this.getList()
+         this.user.open=false;
+      })
+    },
+    /** 查看客户详情 */
+    handleShow(row){
+      this.show.open=true;
+      var that=this;
+      const tab = "visit";
+      setTimeout(() => {
+        that.$refs.customerDetails.getDetails(row.customerId);
+        that.$refs.customerDetails.handleClick(tab);
+
+      }, 200);
+    },
+
+	handledetails(row){
+		this.info.open=true;
+		setTimeout(() => {
+			 this.$refs.Details.getDetails(row.id);
+		}, 1);
+	},
+
+	closeInfo(){
+		this.info.open=false
+	},
+    handleClickX(tab, event) {
+
+      this.queryParams.isBind=tab.name;
+      this.handleQuery();
+    },
+
+    handleClose(tag) {
+      this.remarkMobiles.splice(this.remarkMobiles.indexOf(tag), 1);
+    },
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick(_ => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.remarkMobiles.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = '';
+    },
+
+    addUserTag(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要添加标签的客户');
+      }
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected=false;
+          }
+        }
+      }, 200);
+
+
+      this.tagOpen = true;
+      this.tagFilter = false;
+
+    },
+
+    addUserTagFilter(){
+
+      if(this.externalContactList.length == 0){
+        return  this.$message('无可添加标签客户');
+      }
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected=false;
+          }
+        }
+      }, 200);
+
+
+      this.tagOpen = true;
+      this.tagFilter = true;
+    },
+
+
+    getPageListTagGroup(){
+
+      this.queryTagParams.corpId=this.queryParams.corpId
+      allListTagGroupPage(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.tagTotal = response.total;
+      });
+    },
+
+    delUserTag(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要移除标签的客户');
+      }
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected=false;
+          }
+        }
+      }, 200);
+
+      this.tagDelOpen = true;
+
+    },
+
+
+    //搜索的标签
+    hangleChangeTags(){
+
+      this.changeTagDialog.title="搜索的标签"
+      this.changeTagDialog.open=true;
+      this.changeTagDialog.type = 1;
+
+      // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
+      const selectedTagIds = new Set(
+        (this.selectTags || []).map(tagItem => tagItem?.tagId)
+      );
+
+      this.queryTagParams.name=null;
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
+          }
+        }
+      }, 200);
+
+    },
+
+
+    //选择排除标签
+    hangleChangeOutTags() {
+      this.changeTagDialog.title="搜索的标签"
+      this.changeTagDialog.open=true;
+      this.changeTagDialog.type = 2;
+
+      // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
+      const selectedTagIds = new Set(
+        (this.outSelectTags || []).map(tagItem => tagItem?.tagId)
+      );
+
+      this.queryTagParams.name=null;
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
+          }
+        }
+      }, 200);
+
+    },
+
+    //删除一些选择的标签
+    handleCloseTags(list){
+      const ls = this.selectTags.findIndex(t => t.tagId === list.tagId);
+      if (ls !== -1) {
+        this.selectTags.splice(ls, 1);
+        this.selectTags = [...this.selectTags];
+      }
+
+      if (this.selectTags!=null && this.selectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.tagIds) {
+          this.queryParams.tagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.tagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.selectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.tagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.tagIds=this.queryParams.tagIds.join(",");
+      }else {
+        this.queryParams.tagIds=null;
+      }
+
+    },
+
+    //删除一些排除的标签
+    handleCloseOutTags(list){
+      const ls = this.outSelectTags.findIndex(t => t.tagId === list.tagId);
+      if (ls !== -1) {
+        this.outSelectTags.splice(ls, 1);
+        this.outSelectTags = [...this.selectTags];
+      }
+
+      if (this.outSelectTags!=null && this.outSelectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.outTagIds) {
+          this.queryParams.outTagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.outTagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.outSelectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.outTagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.outTagIds=this.queryParams.outTagIds.join(",");
+      }else {
+        this.queryParams.outTagIds=null;
+      }
+
+    },
+
+    //重新获取页面数据
+    refreshList(){
+      this.getList();
+    },
+
+    //批量设置课程sop
+    setUserCourseSop(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要设置课程SOP的客户');
+      }
+
+      this.$confirm('批量设置客户课节SOP可能会存在重复,确定要批量设置吗?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+          this.setSop.open = true;
+          this.setSop.type = 2;
+        })
+        .catch(() => {
+          // 可以处理用户点击“取消”的逻辑
+        });
+
+    },
+    tagSelection(row){
+
+      row.isSelected= !row.isSelected;
+      this.$forceUpdate();
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    addTagCancel() {
+
+      this.tagOpen = false;
+
+      this.addTagForm={
+        userIds:[],
+        tagIds:[]
+      };
+    },
+
+    DelTagCancel() {
+      this.tagDelOpen = false;
+
+      this.addTagForm={
+        userIds:[],
+        tagIds:[]
+      };
+    },
+    addTagSubmitForm(){
+
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if(this.tagGroupList[i].tag[x].isSelected==true){
+            this.addTagForm.tagIds.push(this.tagGroupList[i].tag[x].tagId)
+          }
+        }
+      }
+      if(this.addTagForm.tagIds==[]||this.addTagForm.tagIds==null||this.addTagForm.tagIds==""){
+        return  this.$message('请选择标签');
+      }
+
+      this.addTagForm.corpId=this.queryParams.corpId
+      this.addTagForm.userIds=this.ids;
+      this.addTagForm.filter = this.tagFilter;
+
+      // 修改这里:正确处理参数对象
+      let obj = JSON.parse(JSON.stringify(this.queryParams));
+
+      // 将逗号分隔的字符串转换为数组
+      if(obj.tagIds && typeof obj.tagIds === 'string') {
+        obj.tagIds = obj.tagIds.split(",");
+      }
+      if(obj.outTagIds && typeof obj.outTagIds === 'string') {
+        obj.outTagIds = obj.outTagIds.split(",");
+      }
+
+      this.addTagForm.param = obj;
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '正在执行中请稍后~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      addTag(this.addTagForm).then(response => {
+       this.msgSuccess(response.msg);
+       this.tagOpen = false;
+        loadingRock.close();
+       this.addTagForm={
+        filter: false,
+        addType: 0,
+        userIds:[],
+        tagIds:[]
+       };
+       this.getList()
+     }).finally(res=>{
+        loadingRock.close();
+      });
+
+    },
+    tagDelSubmitForm(){
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if(this.tagGroupList[i].tag[x].isSelected==true){
+            this.addTagForm.tagIds.push(this.tagGroupList[i].tag[x].tagId)
+          }
+
+        }
+      }
+      if(this.addTagForm.tagIds==[]||this.addTagForm.tagIds==null||this.addTagForm.tagIds==""){
+        return  this.$message('请选择标签');
+      }
+       this.addTagForm.corpId=this.queryParams.corpId
+      this.addTagForm.userIds=this.ids;
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '正在执行中请稍后~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      delTag(this.addTagForm).then(response => {
+       this.msgSuccess(response.msg);
+       this.tagDelOpen = false;
+        loadingRock.close();
+       this.addTagForm={
+         userIds:[],
+         tagIds:[]
+       };
+       this.getList()
+     }).finally(res=>{
+        loadingRock.close();
+      });
+    },
+
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        userId: null,
+        externalUserId: null,
+        name: null,
+        companyUserId:null,
+        customerId:null,
+        avatar: null,
+        type: null,
+        gender: null,
+        remark: null,
+        description: null,
+        tagIds: null,
+        remarkMobiles: null,
+        remarkCorpName: null,
+        addWay: null,
+        operUserid: null,
+        corpId: null,
+        companyId: null,
+        transferStatus:null,
+        status:null,
+        sTime:null,
+        eTime:null,
+        createTime:null,
+        transferTime:null,
+        transferNum:null,
+        lossTime:null,
+        delTime:null,
+        state:null,
+        wayId:null,
+        stageStatus:null,
+        customerName:null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+
+      if (this.selectTags!=null && this.selectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.tagIds) {
+          this.queryParams.tagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.tagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.selectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.tagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.tagIds=this.queryParams.tagIds.join(",");
+      }else {
+        this.queryParams.tagIds=null;
+      }
+
+
+      if (this.outSelectTags!=null && this.outSelectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.outTagIds) {
+          this.queryParams.outTagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.outTagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.outSelectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.outTagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.outTagIds=this.queryParams.outTagIds.join(",");
+      }else {
+        this.queryParams.outTagIds=null;
+      }
+
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    handleSearchTags(name){
+
+      if (!name){
+        return this.$message.error("请输入要搜索的标签")
+      }
+
+      this.queryTagParams.name=name;
+      this.queryTagParams.corpId=this.queryParams.corpId;
+
+      searchTags(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.tagTotal = response.total;
+      });
+
+    },
+
+    cancelSearchTags(){
+      this.resetSearchQueryTag()
+
+      this.getPageListTagGroup();
+    },
+    //确定选择标签
+    tagSubmitForm(type){
+
+      if (type==1){
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            if (this.tagGroupList[i].tag[x].isSelected === true) {
+
+              if (!this.selectTags) {
+                this.selectTags = [];
+              }
+
+              // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
+              let tagExists = this.selectTags.some(
+                tag => tag.id === this.tagGroupList[i].tag[x].id
+              );
+
+              // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
+              if (!tagExists) {
+                this.selectTags.push(this.tagGroupList[i].tag[x]);
+              }
+            }
+          }
+        }
+        if (!this.selectTags || this.selectTags.length === 0) {
+          return this.$message('请选择标签');
+        }
+      }else if (type == 2) {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            if (this.tagGroupList[i].tag[x].isSelected === true) {
+
+              if (!this.outSelectTags) {
+                this.outSelectTags = [];
+              }
+
+              // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
+              let tagExists = this.outSelectTags.some(
+                tag => tag.id === this.tagGroupList[i].tag[x].id
+              );
+
+              // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
+              if (!tagExists) {
+                this.outSelectTags.push(this.tagGroupList[i].tag[x]);
+              }
+            }
+          }
+        }
+        if (!this.outSelectTags || this.outSelectTags.length === 0) {
+          return this.$message('请选择标签');
+        }
+      }
+      this.changeTagDialog.open = false;
+    },
+
+    //取消选择标签
+    tagCancel(){
+      this.changeTagDialog.open = false;
+    },
+
+
+    resetSearchQueryTag(){
+
+      this.queryTagParams= {
+        pageNum: 1,
+        pageSize: 10,
+        total:0,
+        name:null,
+      };
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.transferStatus=null;
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue;
+      this.selectTags=[];
+      this.outSelectTags=[];
+	   this.createTime=null;
+	  this.queryParams.sTime=null;
+	  this.queryParams.eTime=null;
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.loading=true;
+      this.form.corpId=this.queryParams.corpId
+     addExternalContact(this.form).then(response => {
+       this.msgSuccess("同步成功");
+       this.getList();
+     }).finally(()=>{
+       this.loading=false;
+     });
+
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getExternalContact(id).then(response => {
+        this.form = response.data;
+        if(this.form.remarkMobiles!=null){
+          this.remarkMobiles=JSON.parse(this.form.remarkMobiles)
+        }else{
+          this.remarkMobiles=[]
+        }
+
+        this.open = true;
+        this.title = "修改企业微信客户";
+      });
+    },
+
+    handleAppellation(val){
+      this.callOpen.open=true;
+      this.callOpenFrom.stageStatus=val.stageStatus;
+      this.callOpenFrom.id=val.id;
+    },
+
+    /** 绑定客户操作 */
+    handleUpdateCustomer(row){
+       this.bindCustomer.title="绑定客户"
+        this.bindCustomer.open=true;
+        this.form.id=row.id
+        this.form.externalUserId=row.externalUserId
+        this.form.name=row.name
+    },
+
+    handleUpdateUser(row){
+        this.user.title="绑定客户"
+        this.user.open=true;
+        this.userForm.id=row.id;
+    },
+
+    handleUnBindUserId(val){
+
+      this.$confirm(
+        '确认解绑客户:<span style="color: green;">' + val.name + '' +
+        '</span> 的小程序用户?<br><span style="color: red;">【ps:可能会导致客户无法看课】</span>',
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+          dangerouslyUseHTMLString: true // 允许使用 HTML 字符串
+        }
+      ).then(() => {
+        return unBindUserId(val.id);
+      }).then(response => {
+        this.getList();
+        this.msgSuccess("解绑成功");
+      }).finally(res=>{
+        this.getList();
+      })
+    },
+
+    bindCustomerId(row){
+
+      console.log("row",row)
+      // this.qwFormCustomer.customerId=row;
+      this.form.customerId=row;
+      this.form.corpId=this.queryParams.corpId;
+      this.msgWarning("绑定中.....同步信息中.....");
+
+      editbindCustomer(this.form).then(res=>{
+        //清空表单
+        this.reset();
+        this.bindCustomer.open = false;
+        this.msgSuccess("绑定成功");
+        this.getList();
+
+      })
+
+    },
+    //设置一个SOP
+    setCourseSOP(row) {
+
+      // 检查 row.miniUserId 是否为 null
+      if (row.miniUserId === null || row.miniUserId === undefined) {
+        return this.$confirm('当前客户【CRM客户详情】中 未绑定小程序客户,请先绑定', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).catch(error => {
+          this.msgWarning("操作取消:", error);
+        });
+      } else {
+        this.chooseCustomerSOP = row;
+        this.setSop.open = true;
+        this.setSop.type=1;
+      }
+    },
+
+    //选择课程SOP
+    // 用于设置 customerCourseForm 和 customerCourseFormLogs 的共同属性
+    setCommonProperties(form, row) {
+      form.qwUserid = this.chooseCustomerSOP.userId;
+      form.companyUserId = this.chooseCustomerSOP.companyUserId;
+      form.externalUserId = this.chooseCustomerSOP.externalUserId;
+      form.customerId = this.chooseCustomerSOP.customerId;
+      form.miniUserId = this.chooseCustomerSOP.miniUserId;
+      form.businessId = row.businessId;
+    },
+
+    bindCourseSop(row,days) {
+
+      if (this.setSop.type==2){
+        this.setSop.open = false;
+        this.loading=true;
+        this.msgWarning("设定中.....同步信息中.....");
+
+        setCustomerCourseSopList({ids:this.ids,fsCourseSopId:row.id,days:days}).then(res=>{
+
+          let msg=" 批量设置成功数【" + res.successNum + "】,<br>"
+
+          if (res.failCRM.length>0){
+            msg+="失败的客户【" + res.failCRM + "】,原因是未绑定CRM客户。<br>"
+          }
+          if (res.failMiNi.length>0){
+            msg+="失败的客户【" + res.failMiNi + "】,原因是CRM中未绑定小程序客户。<br>"
+          }
+          if (res.failCompany.length>0){
+            msg+="失败的客户【" + res.failCompany + "】,原因是客户没有所属成员。<br>"
+          }
+
+
+          return this.$confirm(msg, "提示", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning",
+            dangerouslyUseHTMLString: true // 允许使用HTML标签
+          }).catch(error => {
+            this.msgSuccess("操作完成~");
+          });
+
+        }).finally(()=>{
+          this.loading = false;
+          this.getList();
+        })
+      }else if (this.setSop.type==1){
+
+      // 设置 customerCourseFormLogs 的属性
+      this.setCommonProperties(this.customerCourseFormLogs, row);
+
+      // 设置 customerCourseForm 的属性
+      this.setCommonProperties(this.customerCourseForm, row);
+      this.customerCourseForm.sopId = row.id;
+      this.customerCourseForm.sopType = row.sopType;
+      this.customerCourseForm.setting = row.setting;
+      this.customerCourseForm.days = days;
+
+      // 执行异步操作
+      getCustomerCourseSop(this.customerCourseFormLogs)
+        .then(res => {
+          if (res) {
+            return this.$confirm('当前客户已设置过相同课程课节SOP,确定还要再次设置吗?', "警告", {
+              confirmButtonText: "确定",
+              cancelButtonText: "取消",
+              type: "warning"
+            });
+          } else {
+            return Promise.resolve(); // 如果没有设置过,直接执行后续操作
+          }
+        })
+        .then(() => {
+          this.loading = true;
+          this.setSop.open = false;
+          this.msgSuccess("设定中.....同步信息中.....");
+
+          return setCustomerCourseSop(this.customerCourseForm);
+        })
+        .then(() => {
+          this.msgSuccess("设定成功");
+        })
+        .catch(error => {
+          this.msgWarning("操作取消:", error);
+        })
+        .finally(() => {
+          this.loading = false;
+          this.getList();
+        });
+      }
+    },
+    submitCallOpenFrom(){
+
+      this.$refs["callOpenFrom"].validate(valid => {
+        if (valid) {
+
+          if (this.callOpenFrom.id != null && this.callOpenFrom.stageStatus != null) {
+            updateExternalContactCall(this.callOpenFrom).then(res=>{
+              this.$message.success('修改成功');
+              this.callOpen.open=false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            this.form.remarkMobiles=JSON.stringify(this.remarkMobiles)
+            updateExternalContact(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addExternalContact(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除企业微信客户编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delExternalContact(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+
+	updateTalk(row){
+		const ids = row.id || this.ids;
+		this.$confirm('是否确认批量更改用户信息为非首次交流', "警告", {
+		    confirmButtonText: "确定",
+		    cancelButtonText: "取消",
+		    type: "warning"
+		  }).then(function() {
+		    return editTalk(ids);
+		  }).then(() => {
+		    this.getList();
+		    this.msgSuccess("成功");
+		  }).catch(() => {});
+	},
+    /** 导出按钮操作 */
+    handleExport() {
+      const { qwUserName, ...queryParams } = this.queryParams;
+      this.$confirm('是否确认导出所有企业微信客户数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportExternalContact(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    },
+    handleBatchUpdateNotesFilter() {
+      this.notesOpen.open = true;
+      this.notesOpen.filter = true;
+    },
+    handleBatchUpdateNotes() {
+
+      if (this.ids == null || this.ids == "") {
+        return this.$message('请选择需要添加备注的客户');
+      }
+
+      this.notesOpen.open = true;
+      this.notesOpen.filter = false;
+
+    },
+    notesCancel(){
+      this.notesOpen={
+        open: false,
+        notes: null,
+        type: 1,
+        nameType:3,
+      }
+    },
+    notesSubmitForm() {
+
+      if (this.notesOpen.notes == null || this.notesOpen.notes == "") {
+        return this.$message.error("请输入备注内容");
+      }
+
+      // let loadingRock = this.$loading({
+      //   lock: true,
+      //   text: '正在执行中请稍后~~请不要刷新页面!!',
+      //   spinner: 'el-icon-loading',
+      //   background: 'rgba(0, 0, 0, 0.7)'
+      // });
+
+      let obj = JSON.parse(JSON.stringify(this.queryParams))
+      console.log(obj);
+      if(obj.tagIds !== null && obj.tagIds !== undefined && obj.tagIds !== ''){
+        obj.tagIds = obj.tagIds.split(",");
+      }
+      batchUpdateExternalContactNotes({
+        addType: 0,
+        userIds: this.ids,
+        notes: this.notesOpen.notes,
+        type: this.notesOpen.type,
+        nameType: this.notesOpen.nameType,
+        filter: this.notesOpen.filter,
+        param: obj
+      }).then(res => {
+
+        this.resultMessage = res.msg;
+        this.$message.success("正在执行中...");
+        // this.resultDialogVisible = true; // 显示弹窗
+        // this.resultTitle = '批量修改备注结果';
+
+      }).finally(res => {
+        this.getList();
+        // loadingRock.close();
+        this.notesCancel();
+      })
+
+    },
+  }
+};
+
+</script>
+<style scoped>
+/* CSS 样式 */
+.tag-container {
+  display: flex;
+  flex-wrap: wrap; /* 超出宽度时自动换行 */
+  gap: 8px; /* 设置标签之间的间距 */
+}
+.name-background {
+  display: inline-block;
+  background-color: #abece6; /* 背景颜色 */
+  padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
+  border-radius: 4px; /* 可选:设置圆角 */
+}
+/* CSS 样式 */
+.tag-container {
+  display: flex;
+  flex-wrap: wrap; /* 超出宽度时自动换行 */
+  gap: 8px; /* 设置标签之间的间距 */
+}
+.name-background {
+  display: inline-block;
+  background-color: #abece6; /* 背景颜色 */
+  padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
+  border-radius: 4px; /* 可选:设置圆角 */
+}
+.tag-box {
+  padding: 8px 12px;
+  border: 1px solid #989797;
+  border-radius: 4px;
+  cursor: pointer;
+  display: inline-block;
+}
+
+.tag-selected {
+  background-color: #00bc98;
+  color: #fff;
+  border-color: #00bc98;
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+
+
+.button-new-tag {
+      margin-left: 10px;
+      height: 32px;
+      line-height: 30px;
+      padding-top: 0;
+      padding-bottom: 0;
+    }
+    .input-new-tag {
+      width: 90px;
+      margin-left: 10px;
+      vertical-align: bottom;
+    }
+
+
+.suggestion-box {
+  position: absolute;
+  z-index: 999;
+  background: #fff;
+  border: 1px solid #ddd;
+  max-height: 200px;
+  overflow-y: auto;
+  width: 100%;
+}
+
+.suggestion-item {
+  padding: 10px;
+  cursor: pointer;
+}
+.suggestion-item:hover {
+  background-color: #f5f7fa;
+}
+/* 新增的滚动容器样式(不影响原有样式) */
+.scroll-wrapper {
+  max-height: 130px; /* 大约三行的高度 */
+  overflow-y: auto;  /* 垂直滚动 */
+  padding-right: 5px; /* 为滚动条留出空间 */
+}
+
+/* 美化滚动条(可选) */
+.scroll-wrapper::-webkit-scrollbar {
+  width: 6px;
+}
+.scroll-wrapper::-webkit-scrollbar-thumb {
+  background: rgba(0, 0, 0, 0.2);
+  border-radius: 3px;
+}
+
+.tag-container {
+  max-height: 200px;
+  overflow-y: auto;
+  padding: 1px;
+  border: 1px solid #ebeef5;
+  border-radius: 1px;
+  background-color: #fafafa;
+}
+.tag-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+.scroll-hint {
+  text-align: center;
+  color: #909399;
+  font-size: 12px;
+  padding: 1px 0;
+}
+.container {
+  max-width: 800px;
+  margin: 0 auto;
+  padding: 10px;
+}
+.title {
+  text-align: center;
+  color: #303133;
+  margin-bottom: 30px;
+}
+.demo-table {
+  width: 100%;
+  margin-bottom: 30px;
+}
+.instructions {
+  background-color: #f5f7fa;
+  padding: 15px;
+  border-radius: 1px;
+  margin-bottom: 20px;
+}
+</style>

+ 3642 - 0
src/views/crm/customer/qw/myExternalContact.vue

@@ -0,0 +1,3642 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="企微账号" prop="qwUserId">
+              <el-select v-model="queryParams.qwUserId" placeholder="企微账号"  size="small" @change="updateQwuser()">
+                <el-option
+                  v-for="dict in myQwUserList"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel+'('+dict.corpName+')'"
+                  :value="dict.dictValue"
+                />
+              </el-select>
+      </el-form-item>
+
+      <el-form-item label="企微客户ID" prop="id">
+        <el-input
+          v-model="queryParams.id"
+          placeholder="请输入企微客户ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="客户名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入客户名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+
+      <el-form-item label="用户类别" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择用户类别" clearable size="small">
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="性别" prop="gender">
+        <el-select v-model="queryParams.gender" placeholder="性别" clearable size="small">
+          <el-option
+            v-for="dict in genderOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="电话号码" prop="remarkMobiles">
+        <el-input
+          v-model="queryParams.remarkMobiles"
+          placeholder="请输入备注电话号码"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="来源" prop="addWay">
+
+        <el-select v-model="queryParams.addWay" placeholder="来源" clearable size="small">
+          <el-option
+            v-for="dict in addWayOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+
+        <el-select v-model="queryParams.status" placeholder="状态" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否重粉" prop="userRepeat">
+        <el-select v-model="queryParams.userRepeat" placeholder="重粉" clearable size="small">
+          <el-option label="否" :value="0"/>
+          <el-option label="是" :value="1"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="客户等级" prop="level">
+        <el-select v-model="queryParams.level" placeholder="客户等级" clearable size="small">
+          <el-option
+            v-for="dict in ratingType"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="等级升降" prop="levelType">
+        <el-select v-model="queryParams.levelType" placeholder="等级升降" clearable size="small">
+          <el-option
+            v-for="dict in ratingUpFall"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+
+      <el-form-item label="转接状态" prop="addWay">
+
+        <el-select v-model="queryParams.transferStatus" placeholder="转接状态" clearable size="small">
+          <el-option
+            v-for="dict in transferStatusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否绑定会员" prop="isBindMini">
+        <el-select v-model="queryParams.isBindMini" placeholder="是否绑定会员" clearable size="small" @change="handleQuery" >
+          <el-option
+            v-for="dict in isBindMiniOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="标签" prop="tagIds">
+<!--        <el-select v-model="selectTags" remote multiple placeholder="请选择" filterable  style="width: 100%;">-->
+<!--          <el-option-->
+<!--            v-for="dict in tagList"-->
+<!--            :label="dict.name"-->
+<!--            :value="dict.tagId">-->
+<!--          </el-option>-->
+<!--          </el-select>-->
+
+        <div @click="hangleChangeTags()" style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 250px">
+          <div style="min-height: 35px; max-height: 200px; overflow-y: auto;">
+            <el-tag type="success"
+                    closable
+                    :disable-transitions="false"
+                    v-for="list in this.selectTags"
+                    :key="list.tagId"
+                    @close="handleCloseTags(list)"
+                    style="margin: 3px;"
+            >{{list.name}}
+            </el-tag>
+          </div>
+        </div>
+
+      </el-form-item>
+      <el-form-item label="排除标签" prop="outTagIds">
+        <div @click="hangleChangeOutTags()"
+             style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 250px">
+          <div style="min-height: 35px; max-height: 200px; overflow-y: auto;">
+            <el-tag type="success"
+                    closable
+                    :disable-transitions="false"
+                    v-for="list in this.outSelectTags"
+                    :key="list.tagId"
+                    @close="handleCloseOutTags(list)"
+                    style="margin: 3px;"
+            >{{ list.name }}
+            </el-tag>
+          </div>
+        </div>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input
+          v-model="queryParams.remark"
+          placeholder="请输入备注"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="添加时间" prop="createTime">
+          <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
+      </el-form-item>
+      <el-form-item label="流失时间" prop="lossTime">
+        <el-date-picker clearable size="small"
+                        v-model="queryParams.lossTime"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="选择流失时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="删除时间" prop="delTime">
+        <el-date-picker clearable size="small"
+                        v-model="queryParams.delTime"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="选择删除时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          @click="handleBatchUpdateNotes"
+          v-hasPermi="['qw:externalContact:edit']"
+        >批量修改备注
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          @click="handleBatchUpdateNotesFilter"
+          v-hasPermi="['qw:externalContact:edit']"
+        >批量修改备注(筛选条件)
+        </el-button>
+      </el-col>
+      <!-- <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['qw:externalContact:add']"
+        >同步</el-button>
+      </el-col> -->
+      <!--   去掉此按钮,此按钮也是单选修改备注,列表上已经存在此按钮了   -->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="success"-->
+      <!--          plain-->
+      <!--          icon="el-icon-edit"-->
+      <!--          size="mini"-->
+      <!--          :disabled="single"-->
+      <!--          @click="handleUpdate"-->
+
+      <!--        >修改备注</el-button>-->
+      <!--      </el-col>-->
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleSyncMyExternalContact"
+
+        >同步我的客户</el-button>
+		<el-button
+		  type="warning"
+		  plain
+		  icon="el-icon-download"
+		  size="mini"
+		  :loading="exportLoading"
+		  @click="handleSyncAddMyExternalContact"
+
+		>新客同步</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['qw:externalContact:myExport']"
+        >导出</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="addUserTag"
+          v-hasPermi="['qw:externalContact:myAddTag']"
+        >批量添加标签</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="delUserTag"
+          v-hasPermi="['qw:externalContact:myDelTag']"
+        >批量移除标签</el-button>
+      </el-col>
+	  <el-col :span="1.5">
+	    <el-button
+	      type="primary"
+	      plain
+	      size="mini"
+	      @click="updateTalk"
+        v-hasPermi="['qw:externalContactInfo:myUpdateTalk']"
+	    >批量更改交流状态</el-button>
+	  </el-col>
+	  <el-col :span="1.5">
+	    <el-button
+	      type="primary"
+	      plain
+	      size="mini"
+	      @click="updateAllTalk"
+        v-hasPermi="['qw:externalContactInfo:myUpdateAllTalk']"
+	    >更改全部交流状态</el-button>
+	  </el-col>
+<!--     <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="primary"-->
+<!--          plain-->
+<!--          size="mini"-->
+<!--          @click="setUserCourseSop"-->
+<!--          v-hasPermi="['qw:externalContact:setCourseSop']"-->
+<!--        >批量设置SOP</el-button>-->
+<!--      </el-col>-->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+<!--    <el-tabs type="card" v-model="isBindActiveName" @tab-click="handleClickX">-->
+<!--      <el-tab-pane label="全部" name="all"></el-tab-pane>-->
+<!--      <el-tab-pane label="已绑定CRM" name="isBind"></el-tab-pane>-->
+<!--      <el-tab-pane label="未绑定CRM" name="noBind"></el-tab-pane>-->
+<!--    </el-tabs>-->
+
+    <el-table v-loading="loading" :data="externalContactList" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="企微客户ID" align="center" prop="id"/>
+      <el-table-column label="企微客户头像" align="center" prop="avatar" width="100px">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover">
+            <img slot="reference" :src="scope.row.avatar" width="60px">
+            <img :src="scope.row.avatar" style="max-width: 200px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="企微客户名称"  prop="name" width="110px"/>
+      <el-table-column label="客户称呼"  prop="stageStatus" width="110px"/>
+      <el-table-column label="销售企微昵称" align="center" prop="qwUserName" width="120px"/>
+      <el-table-column label="企微部门" align="center" prop="departmentName" width="120px"/>
+      <el-table-column label="用户类别" align="center" prop="type">
+        <template slot-scope="scope">
+          <dict-tag :options="typeOptions" :value="scope.row.type"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="性别" align="center" prop="gender">
+        <template slot-scope="scope">
+          <dict-tag :options="genderOptions" :value="scope.row.gender"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="描述信息" align="center" prop="description" />
+      <el-table-column label="标签" align="center" prop="tagIdsName" width="300px">
+        <template slot-scope="scope">
+          <div class="tag-container">
+            <div class="tag-list">
+              <el-tag
+                v-for="name in scope.row.tagIdsName"
+                :key="name"
+                type="success"
+                size="small"
+              >
+                {{ name }}
+              </el-tag>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="流失风险" align="center" prop="attritionLevel">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.attritionLevel == null" type="info">未分析</el-tag>
+          <el-tag v-if="scope.row.attritionLevel === 0" type="info">未知</el-tag>
+          <el-tag v-else-if="scope.row.attritionLevel === 1" type="success">无风险</el-tag>
+          <el-tag v-else-if="scope.row.attritionLevel === 2" type="info">低风险</el-tag>
+          <el-tag v-else-if="scope.row.attritionLevel === 3" type="warning">中风险</el-tag>
+          <el-tag v-else-if="scope.row.attritionLevel === 4" type="danger">高风险</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="意向度" align="center" prop="intentionDegree">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.intentionDegree !== null && scope.row.intentionDegree !== undefined && scope.row.intentionDegree !== ''">
+            {{ scope.row.intentionDegree }}
+          </el-tag>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="关注点" align="center" prop="customerFocusJson" width="220">
+        <template slot-scope="scope">
+          <div v-if="parseFocusPoints(scope.row.customerFocusJson).length" style="text-align: left;">
+            <el-tooltip
+              v-for="(item, index) in parseFocusPoints(scope.row.customerFocusJson).slice(0, 2)"
+              :key="index"
+              placement="top"
+              effect="light"
+            >
+              <div slot="content" style="max-width: 420px; word-break: break-word;">
+                {{ item }}
+              </div>
+              <el-tag style="margin: 0 6px 6px 0; max-width: 100%; background: #fff; border: 1px solid #dcdfe6; color: #606266;">
+                {{ shortenText(item, 14) }}
+              </el-tag>
+            </el-tooltip>
+            <el-tooltip
+              v-if="parseFocusPoints(scope.row.customerFocusJson).length > 2"
+              placement="top"
+              effect="light"
+            >
+              <div slot="content" style="max-width: 420px;">
+                <div
+                  v-for="(item, idx) in parseFocusPoints(scope.row.customerFocusJson).slice(2)"
+                  :key="'focus-more-' + idx"
+                  style="margin-bottom: 4px;"
+                >
+                  {{ item }}
+                </div>
+              </div>
+              <el-tag style="margin: 0 6px 6px 0; background: #fff; border: 1px solid #dcdfe6; color: #606266;">
+                +{{ parseFocusPoints(scope.row.customerFocusJson).length - 2 }}
+              </el-tag>
+            </el-tooltip>
+          </div>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否回复" align="center" prop="isReply" width="120px" >
+        <template slot-scope="scope">
+          <span v-if="scope.row.isReply === 1"><el-tag type="success">已回复</el-tag></span>
+          <span v-else-if="scope.row.isReply === 0"><el-tag type="info">未回复</el-tag></span>
+          <span v-else>{{ scope.row.isReply }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="客户等级" align="center" prop="level" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="ratingType" :value="scope.row.level"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="下单次数" align="center" width="100px">
+        <template #default="scope">
+          {{ scope.row.orderCount && scope.row.orderCount !== 0 ? scope.row.orderCount : '' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="state参数" align="center" prop="state" width="100px" />
+      <el-table-column label="等级状态" align="center" prop="levelType" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="ratingUpFall" :value="scope.row.levelType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="添加时间" align="center" prop="createTime" width="100px" />
+      <el-table-column label="流失时间" align="center" prop="lossTime" width="100px" />
+      <el-table-column label="删除时间" align="center" prop="delTime" width="100px" />
+      <el-table-column label="注册时间" align="center" prop="registerTime" width="100px" />
+      <el-table-column label="备注电话号码" align="center" prop="remarkMobiles" width="150px">
+        <template slot-scope="scope">
+          <div v-for="i in JSON.parse(scope.row.remarkMobiles)" :key="i">{{i}}</div>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注企业名称" align="center" prop="remarkCorpName" />
+      <el-table-column label="来源" align="center" prop="addWay" width="100px">
+        <template slot-scope="scope">
+          <dict-tag :options="addWayOptions" :value="scope.row.addWay"/>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="转接状态" align="center" prop="transferStatus" width="100px" >
+        <template slot-scope="scope">
+          <dict-tag :options="transferStatusOptions" :value="scope.row.transferStatus"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="企业id" align="center" prop="corpId" />
+      <el-table-column label="重粉看课历史" width="100px" align="center" fixed="right">
+        <template slot-scope="scope">
+          <div v-if="scope.row.fsUserId">
+            <el-tag type="success" v-if="scope.row.userRepeat == 0">正常</el-tag>
+            <el-tag type="danger" v-if="scope.row.userRepeat == 1">重粉</el-tag>
+            <el-button
+              size="mini"
+              type="text"
+              @click="showLog(scope.row)"
+            >重粉看课历史
+            </el-button>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否绑定会员" width="100px" align="center" fixed="right">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.fsUserId" >已绑定<br/>{{scope.row.fsUserId}}</el-tag>
+          <el-tag v-else type="info"> 未绑定</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否下载APP" width="100px" align="center" fixed="right">
+        <template slot-scope="scope">
+          <el-tag :type="scope.row.isDownloadApp === 1 ? 'success' : 'info'">
+            {{ scope.row.isDownloadApp === 1 ? '已下载' : '未下载' }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="重粉记录" align="center" width="100px" fixed="right">
+        <template slot-scope="scope">
+            <el-button
+                size="mini"
+                type="text"
+                @click="showRepeatRecord(scope.row)"
+            >重粉记录</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="修改" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-shopping-bag-2"
+              :disabled="!scope.row.fsUserId"
+              @click="handleCreateOrder(scope.row)"
+
+            >制单</el-button>
+            <el-button
+                size="mini"
+                type="text"
+                icon="el-icon-microphone"
+                :disabled="!scope.row.fsUserId"
+                @click="openFollowUpDrawer(scope.row)"
+              >客户跟进记录</el-button>
+          <el-button
+            v-show="scope.row.status==0||scope.row.status==2"
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['qw:externalContact:edit']"
+          >修改备注</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-user-solid"
+            @click="handleAppellation(scope.row)"
+          >修改客户称呼</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+<!--          <el-button-->
+<!--            size="mini"-->
+<!--            type="text"-->
+<!--            icon="el-icon-edit-outline"-->
+<!--            @click="handleUpdateCustomer(scope.row)"-->
+<!--            >-->
+<!--            <span v-if="scope.row.customerId">换绑CRM</span>-->
+<!--            <span v-else>绑定CRM</span>-->
+<!--          </el-button>-->
+
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit-outline"
+            @click="handleUpdateUser(scope.row)"
+            >
+            <span v-if="scope.row.fsUserId">换绑会员</span>
+            <span v-else>绑定会员</span>
+          </el-button>
+
+          <el-button v-show="scope.row.fsUserId"
+            size="mini"
+            type="text"
+            icon="el-icon-thumb"
+            @click="handleUnBindUserId(scope.row)"
+            v-hasPermi="['qw:externalContact:unBindUserId']"
+          >
+            <span>解除会员绑定</span>
+          </el-button>
+          <el-button v-show="scope.row.fsUserId"
+            size="mini"
+            type="text"
+            @click="handleDiagnosis(scope.row)"
+          >
+            <span>初诊单</span>
+          </el-button>
+          <el-button
+             size="mini"
+             type="text"
+             @click="handleMemberdetails(scope.row)"
+             v-if="scope.row.fsUserId"
+             >
+             <span>会员详情</span>
+          </el-button>
+          <el-button
+
+             size="mini"
+             type="text"
+             @click="handleInfoCollection(scope.row)"
+          v-if="false"
+             >
+             <span>信息采集</span>
+          </el-button>
+
+<!--          <el-button v-if="scope.row.customerId"-->
+<!--            size="mini"-->
+<!--            type="text"-->
+<!--            icon="el-icon-paperclip"-->
+<!--            @click="handleShow(scope.row)"-->
+<!--          >CRM客户详情</el-button>-->
+		  <el-button
+		     size="mini"
+		     type="text"
+		     @click="handledetails(scope.row)"
+		     >用户信息
+		  </el-button>
+<!--          <el-button v-if="scope.row.customerId"
+                     size="mini"
+                     type="text"
+                     icon="el-icon-setting"
+                     @click="setCourseSOP(scope.row)"
+          >设置课程SOP</el-button> -->
+        <el-button
+          size="mini"
+          type="text"
+          icon="el-icon-edit"
+          @click="handleChangeStatus(scope.row)"
+          v-hasPermi="['qw:externalContact:changeStatus']"
+        >
+          修改状态
+        </el-button>
+        <el-button
+                v-if="scope.row.attritionLevel !== null && scope.row.attritionLevel !== undefined"
+                size="mini"
+                type="text"
+                @click="openAiDrawer(scope.row)"
+                v-hasPermi="['qw:externalContact:analyze:list']"
+              >AI 分析</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination-more
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改初诊单对话框 -->
+    <el-dialog title="初诊单" :visible.sync="diagnosisOpen" width="1000px" append-to-body>
+      <el-form ref="diagnosisForm" :model="diagnosisForm" :rules="diagnosisRules" label-width="110px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="患者姓名" prop="patientName">
+              <el-input v-model="diagnosisForm.patientName" placeholder="请输入患者姓名" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="年龄" prop="age">
+              <el-input-number v-model="diagnosisForm.age"  :min="1" label="年龄"></el-input-number>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="患者电话" prop="phone">
+              <el-input v-model="diagnosisForm.phone" placeholder="请输入电话" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="性别" prop="gender">
+              <el-select  v-model="diagnosisForm.gender">
+                <el-option label="未知" :value = "0"></el-option>
+                <el-option label="男性" :value = "1"></el-option>
+                <el-option label="女性" :value = "2"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="日期" prop="dateTime">
+              <el-date-picker clearable size="small"
+                v-model="diagnosisForm.dateTime"
+                type="date"
+                value-format="yyyy-MM-dd"
+                placeholder="选择日期">
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="医生" prop="doctorId">
+              <el-select v-model="diagnosisForm.doctorId" placeholder="选择医生"  size="small" @change="doctorChange">
+                <el-option
+                  v-for="dict in doctorList"
+                  :key="dict.id"
+                  :label="dict.name"
+                  :value="dict.id"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="身体状况" prop="physicalCondition">
+          <el-input v-model="diagnosisForm.physicalCondition" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+
+        <el-form-item label="初步诊断" prop="firstDiagnosis">
+          <el-input v-model="diagnosisForm.firstDiagnosis" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+
+        <el-form-item label="医生职称" prop="doctorDep">
+          <el-input disabled v-model="diagnosisForm.doctorDep" placeholder="医生职称" />
+        </el-form-item>
+        <el-form-item label="医生证号" prop="doctorCertificate">
+          <el-input disabled v-model="diagnosisForm.doctorCertificate" placeholder="医生证号" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="diagnosisSubmitForm">确 定</el-button>
+        <el-button @click="diagnosisCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-drawer size="75%" :title="show.title" :visible.sync="show.open">
+      <customer-details  ref="customerDetails" @refreshList="refreshList"/>
+    </el-drawer>
+
+
+    <!--  搜索标签   -->
+    <el-dialog :title="changeTagDialog.title" :visible.sync="changeTagDialog.open" style="width:100%;height: 100%" append-to-body>
+
+      <div>搜索标签:
+        <el-input v-model="queryTagParams.name" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(queryTagParams.name)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <div v-for="item in tagGroupList" :key="item.id">
+        <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+          <span class="name-background">{{ item.name }}</span>
+        </div>
+
+        <!-- 添加外层滚动容器 -->
+        <div class="scroll-wrapper">
+          <div class="tag-container">
+            <a
+              v-for="tagItem in item.tag"
+              class="tag-box"
+              @click="tagSelection(tagItem)"
+              :class="{ 'tag-selected': tagItem.isSelected }"
+            >
+              {{ tagItem.name }}
+            </a>
+          </div>
+        </div>
+      </div>
+<!--      <div v-for="item in tagGroupList" :key="item.id"  >-->
+<!--        <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">-->
+<!--          <span class="name-background">{{ item.name }}</span>-->
+<!--        </div>-->
+<!--        <div class="tag-container">-->
+<!--          <a-->
+<!--            v-for="tagItem in item.tag"-->
+<!--            class="tag-box"-->
+<!--            @click="tagSelection(tagItem)"-->
+<!--            :class="{ 'tag-selected': tagItem.isSelected }"-->
+<!--          >-->
+<!--            {{ tagItem.name }}-->
+<!--          </a>-->
+<!--        </div>-->
+<!--      </div>-->
+
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="tagSubmitForm(changeTagDialog.type)">确 定</el-button>
+        <el-button @click="tagCancel(changeTagDialog.type)">取消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="批量添加标签" :visible.sync="tagOpen" width="800px" append-to-body>
+      <div>搜索标签:
+        <el-input v-model="tagChange.tagName" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(tagChange.tagName)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <el-form ref="form" :model="addTagForm"  label-width="80px">
+        <div v-for="item in tagGroupList" :key="item.id" >
+          <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+            <span class="name-background">{{ item.name }}</span>
+          </div>
+          <div class="scroll-wrapper">
+            <div class="tag-container">
+              <a
+                v-for="tagItem in item.tag"
+                class="tag-box"
+                @click="tagSelection(tagItem)"
+                :class="{ 'tag-selected': tagItem.isSelected }"
+              >
+                {{ tagItem.name }}
+              </a>
+            </div>
+          </div>
+        </div>
+      </el-form>
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="addTagSubmitForm()">确 定</el-button>
+        <el-button @click="addTagCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+    <el-dialog title="批量添加客户备注" :visible.sync="notesOpen.open" width="800px" append-to-body>
+      <el-card>
+        <el-row>
+          <el-col>
+            <el-radio-group v-model="notesOpen.nameType" style="margin-bottom: 2%">
+              <el-radio :label="1">
+                客户名称添加在【新备注】【前】
+              </el-radio>
+              <el-radio :label="2">
+                客户名称添加在【新备注】【后】
+              </el-radio>
+              <el-radio :label="3">
+                不添加客户名称
+              </el-radio>
+            </el-radio-group>
+          </el-col>
+          <el-col>
+            <el-radio-group v-model="notesOpen.type">
+              <el-radio
+                :label="1"
+              >添加【新备注】在最【前】面
+              </el-radio>
+              <el-radio
+                :label="2"
+              >添加【新备注】在最【后】面
+              </el-radio>
+              <el-radio
+                :label="3"
+              >替换所有备注
+              </el-radio>
+            </el-radio-group>
+          </el-col>
+          <el-col>
+            <el-input v-model="notesOpen.notes" placeholder="请输入客户备注(最多20个字,含已有的)" clearable size="small"
+                      maxlength="20" show-word-limit style="width: 500px;margin-top: 3%"/>
+            <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
+              <i class="el-icon-info"></i>
+              由于企业微信官方限制,备注最多20个字,且自动会去除末尾超出的字
+            </div>
+          </el-col>
+        </el-row>
+      </el-card>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="notesSubmitForm()">确 定</el-button>
+        <el-button @click="notesCancel()">取消</el-button>
+      </div>
+    </el-dialog>
+    <el-dialog title="批量移除标签" :visible.sync="tagDelOpen" width="800px" append-to-body>
+      <div>搜索标签:
+        <el-input v-model="tagChange.tagName" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(tagChange.tagName)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <el-form ref="form" :model="addTagForm"  label-width="80px">
+        <div v-for="item in tagGroupList" :key="item.id" >
+          <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+            <span class="name-background">{{ item.name }}</span>
+          </div>
+          <div class="scroll-wrapper">
+            <div class="tag-container">
+              <a
+                v-for="tagItem in item.tag"
+                class="tag-box"
+                @click="tagSelection(tagItem)"
+                :class="{ 'tag-selected': tagItem.isSelected }"
+              >
+                {{ tagItem.name }}
+              </a>
+            </div>
+          </div>
+        </div>
+      </el-form>
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="tagDelSubmitForm()">确 定</el-button>
+        <el-button @click="DelTagCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+    <!-- 添加或修改企业微信客户对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+
+
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="描述信息" prop="description">
+          <el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入描述信息" />
+        </el-form-item>
+
+        <el-form-item label="备注电话号码" prop="remarkMobiles">
+
+          <el-tag
+            :key="tag"
+            v-for="tag in remarkMobiles"
+            closable
+            :disable-transitions="false"
+            @close="handleClose(tag)">
+            {{tag}}
+          </el-tag>
+          <el-input
+            style="width:110px"
+            class="input-new-tag"
+            v-if="inputVisible"
+            v-model="inputValue"
+            ref="saveTagInput"
+            size="small"
+            @keyup.enter.native="handleInputConfirm"
+            @blur="handleInputConfirm"
+          >
+          </el-input>
+          <el-button v-else class="button-new-tag" size="small" style="width: 110px" @click="showInput">新增电话</el-button>
+
+        </el-form-item>
+
+
+        <el-form-item label="备注企业名称" prop="remarkCorpName">
+          <el-input v-model="form.remarkCorpName" placeholder="请输入备注企业名称" />
+        </el-form-item>
+
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog :title="callOpen.title" :visible.sync="callOpen.open" width="500px" append-to-body>
+      <el-form ref="callOpenFrom" :model="callOpenFrom" :rules="callOpenRule" label-width="110px">
+        <el-form-item label="客户称呼" prop="stageStatus">
+          <el-input v-model="callOpenFrom.stageStatus" placeholder="请输入客户称呼" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer" >
+        <el-button type="primary" @click="submitCallOpenFrom">确 定</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 重粉看课记录   -->
+    <el-drawer title="重粉看课历史" :visible.sync="log.open" size="75%" append-to-body>
+      <div style="padding: 10px">
+        <el-form :model="log.queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+          <el-form-item label="所属项目" prop="project">
+            <el-select v-model="log.queryParams.project" placeholder="请选择项目" filterable clearable size="small">
+              <el-option
+                v-for="dict in projectOptions"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="课程" prop="courseId">
+            <el-select filterable v-model="log.queryParams.courseId" placeholder="请选择课程" clearable size="small"
+                       @change="courseChange(log.queryParams.courseId)">
+              <el-option
+                v-for="dict in courseLists"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="小节" prop="videoId">
+            <el-select filterable v-model="log.queryParams.videoId" placeholder="请选择小节" clearable size="small">
+              <el-option
+                v-for="dict in videoList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQueryWatchLog">搜索</el-button>
+          </el-form-item>
+        </el-form>
+        <el-table v-loading="log.loading" :data="log.list">
+          <el-table-column label="编号" align="center" prop="id"/>
+          <el-table-column label="所属企微主体" align="center" prop="corpName"/>
+          <el-table-column label="所属企微" align="center" prop="qwUserName"/>
+          <el-table-column label="项目" align="center" prop="projectName"/>
+          <el-table-column label="课程" align="center" prop="courseName"/>
+          <el-table-column label="小节" align="aligner" prop="videoName"/>
+          <el-table-column label="记录时间" align="center" prop="createTime"/>
+          <el-table-column label="是否完课" align="center" prop="logType">
+            <template slot-scope="scope">
+              <el-tag v-if="scope.row.logType == 2" type="success">已完课</el-tag>
+              <el-tag v-else type="success">未完课</el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="完课时间" align="center" prop="finishTime"/>
+        </el-table>
+
+        <pagination
+          v-show="log.total>0"
+          :total="log.total"
+          :page.sync="log.queryParams.pageNum"
+          :limit.sync="log.queryParams.pageSize"
+          @pagination="logList"
+        />
+      </div>
+    </el-drawer>
+
+    <!-- 重粉记录 -->
+    <el-drawer title="重粉记录" :visible.sync="repeatRecord.open" size="75%" append-to-body>
+      <div style="padding: 10px">
+        <el-form :model="repeatRecord.queryParams" ref="repeatRecordQueryForm" :inline="true" label-width="110px">
+          <el-form-item label="销售企微ID" prop="qwUserId">
+            <el-input
+              v-model="repeatRecord.queryParams.qwUserId"
+              placeholder="请输入销售企微ID"
+              clearable
+              size="small"
+              @keyup.enter.native="handleQueryRepeatRecord"
+            />
+          </el-form-item>
+          <el-form-item label="销售企微昵称" prop="qwUserName">
+            <el-input
+              v-model="repeatRecord.queryParams.qwUserName"
+              placeholder="请输入销售企微昵称"
+              clearable
+              size="small"
+              @keyup.enter.native="handleQueryRepeatRecord"
+            />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQueryRepeatRecord">搜索</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="resetRepeatRecordQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+        <el-table v-loading="repeatRecord.loading" :data="repeatRecord.list" border>
+          <el-table-column label="企微客户ID" align="center" prop="externalUserId" min-width="140" />
+          <el-table-column label="企微客户昵称" align="center" prop="externalUserName" min-width="120" />
+          <el-table-column label="销售企微ID" align="center" prop="qwUserId" min-width="120" />
+          <el-table-column label="销售企微昵称" align="center" prop="qwUserName" min-width="120" />
+          <el-table-column label="企微部门" align="center" prop="deptName" min-width="120" />
+          <el-table-column label="添加时间" align="center" prop="createTime" width="170" />
+          <el-table-column label="注册时间" align="center" prop="registerTime" width="170" />
+        </el-table>
+        <pagination
+          v-show="repeatRecord.total > 0"
+          :total="repeatRecord.total"
+          :page.sync="repeatRecord.queryParams.pageNum"
+          :limit.sync="repeatRecord.queryParams.pageSize"
+          @pagination="repeatRecordList"
+        />
+      </div>
+    </el-drawer>
+
+    <el-drawer
+        :with-header="false"
+        size="75%"
+          :title="member.title" :visible.sync="member.open">
+      <userDetails  ref="userDetails" />
+    </el-drawer>
+
+    <!-- 绑定客户   -->
+    <el-dialog :title="bindCustomer.title" :visible.sync="bindCustomer.open"  width="1200px" append-to-body>
+      <mycustomer ref="mycustomer"  @bindCustomerId="bindCustomerId"></mycustomer>
+    </el-dialog>
+
+<!--    设置一个课程sop-->
+    <el-dialog :title="setSop.title" :visible.sync="setSop.open"  width="1200px" append-to-body>
+      <SopDialog ref="SopDialog"  @bindCourseSop="bindCourseSop"></SopDialog>
+    </el-dialog>
+	<el-drawer
+			:with-header="false"
+	 size="75%"
+	 :title="show.title" :visible.sync="show.open">
+	  <info  ref="Details" />
+	</el-drawer>
+  <el-drawer
+  size="75%"
+  :title="aiAnalyze.title"
+  :visible.sync="aiAnalyze.open"
+  append-to-body
+>
+  <customer-detail
+    ref="customerAiDetail"
+    :analyze-user-id="aiAnalyze.userId"
+    :analyze-external-user-id="aiAnalyze.externalUserId"
+    :analyze-corp-id="aiAnalyze.corpId"
+    :customer-row="aiAnalyze.customerRow"
+  />
+</el-drawer>
+    <el-dialog :title="user.title" :visible.sync="user.open" width="800px" append-to-body>
+      <selectUser ref="selectUser" @bindMiniCustomerId="bindMiniCustomerId"></selectUser>
+    </el-dialog>
+    <el-dialog :title="collection.title" :visible.sync="collection.open"   width="1100px" append-to-body>
+	  <collection   ref="collection" />
+	</el-dialog>
+
+    <!--  制单页面组件    -->
+    <create-oder ref="createOder" />
+
+  <el-dialog title="修改客户状态" :visible.sync="statusDialog.open" width="500px" append-to-body>
+    <el-form ref="statusForm" :model="statusForm" :rules="statusRules" label-width="100px">
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="statusForm.status" placeholder="请选择状态" size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+    </el-form>
+    <div slot="footer" class="dialog-footer">
+      <el-button @click="statusDialog.open = false">取 消</el-button>
+      <el-button type="primary" @click="submitStatusForm">提 交</el-button>
+    </div>
+  </el-dialog>
+
+  <!-- 客户跟进记录抽屉 -->
+  <el-drawer
+    title="客户跟进记录"
+    :visible.sync="followUpDrawer.open"
+    size="850px"
+    append-to-body
+  >
+    <div class="follow-up-drawer" v-loading="followUpDrawer.loading">
+      <!-- 统计信息 -->
+      <div class="follow-up-header">
+        <div class="stat-item">
+          <span class="stat-label">未跟进天数</span>
+          <span class="stat-value" :class="{ 'stat-warn': followUpDrawer.unfollowDays > 7 }">
+            {{ followUpDrawer.unfollowDays }} 天
+          </span>
+        </div>
+        <div class="stat-item">
+          <span class="stat-label">跟进次数</span>
+          <span class="stat-value stat-primary">{{ followUpDrawer.followCount }} 次</span>
+        </div>
+      </div>
+
+      <!-- SCRM客户信息 -->
+      <div class="customer-edit-panel">
+        <div class="edit-panel-title">客户信息</div>
+        <el-form :model="followUpDrawer.customerInfo" label-width="100px" size="small" class="customer-edit-form">
+          <el-row :gutter="16">
+            <el-col :span="12">
+              <el-form-item label="AI外呼呼出次数">
+                <span class="readonly-value">{{ followUpDrawer.customerInfo.roboticCallOutCount == null ? 0 : followUpDrawer.customerInfo.roboticCallOutCount }}</span>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="客户来源">
+                <el-select v-model="followUpDrawer.customerInfo.source" placeholder="请选择" clearable style="width:100%">
+                  <el-option v-for="item in followUpSourceOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="16">
+            <el-col :span="12">
+              <el-form-item label="客户类型">
+                <el-select v-model="followUpDrawer.customerInfo.customerType" placeholder="请选择" clearable style="width:100%">
+                  <el-option v-for="item in followUpTypeOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="16">
+            <el-col :span="12">
+              <el-form-item label="标签">
+                <div class="tags-container">
+                  <el-tag
+                    :key="tag"
+                    v-for="tag in followUpTags"
+                    closable
+                    :disable-transitions="false"
+                    class="selected-tag"
+                    @close="followUpTagHandleClose(tag)"
+                  >
+                    {{tag}}
+                  </el-tag>
+                  <el-input
+                    class="input-new-tag"
+                    v-if="followUpTagInputVisible"
+                    v-model="followUpTagInputValue"
+                    ref="saveFollowUpTagInput"
+                    size="small"
+                    placeholder="输入新标签"
+                    @keyup.enter.native="followUpTagInputConfirm"
+                    @blur="followUpTagInputConfirm"
+                  >
+                  </el-input>
+                  <el-button v-else class="button-new-tag" size="small" icon="el-icon-plus" @click="followUpTagShowInput">自定义标签</el-button>
+                  <el-select v-model="followUpTagId" @change="followUpTagChange" style="width:140px;margin-left: 10px;" placeholder="选择标签" clearable size="small">
+                    <el-option
+                      v-for="item in followUpTagsOptions"
+                      :key="item.dictValue"
+                      :label="item.dictLabel"
+                      :value="item.dictValue"
+                    />
+                  </el-select>
+                </div>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="备注">
+                <el-input v-model="followUpDrawer.customerInfo.remark" placeholder="请输入备注" clearable />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="16">
+            <el-col :span="24">
+              <el-form-item label="跟进内容">
+                <el-input v-model="followUpDrawer.followContent" type="textarea" :rows="3" placeholder="请输入跟进内容..." maxlength="500" show-word-limit />
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-form-item>
+            <el-button type="primary" size="small" :loading="followUpDrawer.saving" @click="saveCustomerInfo">保 存</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+
+      <!-- 跟进记录 -->
+      <div class="follow-up-address-section" style="margin-top: 20px; border-top: 1px solid #ebeef5; padding-top: 16px;">
+        <div class="edit-panel-title">跟进记录</div>
+        <div class="visit-records-list">
+          <div
+            v-for="(record, rIndex) in followUpDrawer.visitRecords"
+            :key="record._key"
+            class="recording-item"
+          >
+            <div class="recording-header">
+              <span class="recording-index">跟进记录 {{ rIndex + 1 }}</span>
+              <el-button
+                size="mini"
+                type="danger"
+                icon="el-icon-delete"
+                circle
+                @click="deleteVisitRecord(rIndex)"
+              />
+            </div>
+            <div class="recording-content-area">
+              <el-form label-width="100px" size="small">
+                <el-form-item label="进线客户详情">
+                  <el-input v-model="record.registerDesc" type="textarea" :rows="2" placeholder="请输入进线客户详情" />
+                </el-form-item>
+                <el-form-item label="跟进阶段">
+                  <el-select v-model="record.visitStatus" placeholder="请选择" clearable style="width:100%">
+                    <el-option v-for="item in followUpStatusOptions" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
+                  </el-select>
+                </el-form-item>
+                <el-form-item label="跟进时间">
+                  <el-date-picker
+                    v-model="record.visitTime"
+                    type="datetime"
+                    placeholder="选择日期时间"
+                    value-format="yyyy-MM-dd HH:mm:ss"
+                    style="width:100%"
+                  />
+                </el-form-item>
+              </el-form>
+            </div>
+          </div>
+        </div>
+        <div class="add-recording-area" style="margin-top: 12px;">
+          <el-button
+            type="primary"
+            plain
+            icon="el-icon-plus"
+            @click="addVisitRecordSlot"
+          >新增跟进记录</el-button>
+          <el-button
+            type="primary"
+            size="small"
+            :loading="followUpDrawer.visitSaving"
+            @click="saveVisitRecords"
+            style="margin-left: 10px;"
+          >保存跟进记录</el-button>
+        </div>
+      </div>
+
+      <!-- 用户收货地址 -->
+      <div class="follow-up-address-section" style="margin-top: 20px; border-top: 1px solid #ebeef5; padding-top: 16px;">
+        <div class="edit-panel-title">用户收货地址</div>
+        <userAddDetails ref="followUpUserAddDetailsRef" />
+      </div>
+
+      <!-- 录音列表 -->
+      <div class="recording-list">
+        <div
+          v-for="(item, index) in followUpDrawer.recordings"
+          :key="item._key"
+          class="recording-item"
+        >
+          <div class="recording-header">
+            <span class="recording-index">录音 {{ index + 1 }}</span>
+            <el-button
+              size="mini"
+              type="danger"
+              icon="el-icon-delete"
+              circle
+              @click="deleteRecording(index)"
+            />
+          </div>
+
+          <!-- 上传区域 / 已上传文件显示 -->
+          <div class="recording-file-area">
+            <template v-if="!item.fileUrl">
+              <el-upload
+                class="recording-upload"
+                :action="uploadAction"
+                :headers="uploadHeaders"
+                :data="uploadData"
+                :before-upload="(file) => beforeUploadRecording(file, index)"
+                :on-success="(res, file) => onUploadSuccess(res, file, index)"
+                :on-error="onUploadError"
+                :show-file-list="false"
+                accept=".mp3,.wav,.m4a,.aac,.ogg,.wma,.amr"
+                drag
+              >
+                <i class="el-icon-upload"></i>
+                <div class="el-upload__text">
+                  将录音文件拖到此处,或<em>点击上传</em>
+                </div>
+                <div class="el-upload__tip" slot="tip">
+                  支持 mp3/wav/m4a/aac/ogg/wma/amr 格式,最大50MB
+                </div>
+              </el-upload>
+            </template>
+            <template v-else>
+              <div class="recording-play-area">
+                <div class="recording-info">
+                  <i class="el-icon-video-play recording-play-icon"></i>
+                  <span class="recording-name" :title="item.fileName">{{ item.fileName }}</span>
+                  <span class="recording-size">{{ formatFileSize(item.fileSize) }}</span>
+                  <span class="recording-time">{{ item.uploadTime }}</span>
+                </div>
+                <audio
+                  :ref="'audio_' + index"
+                  :src="getAudioPlayUrl(item)"
+                  controls
+                  preload="metadata"
+                  class="recording-audio"
+                  @loadedmetadata="onAudioLoaded($event, index)"
+                />
+              </div>
+            </template>
+          </div>
+        </div>
+      </div>
+
+      <!-- 新增录音按钮 -->
+      <div class="add-recording-area" v-if="followUpDrawer.recordings.length > 0">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          @click="addRecordingSlot"
+        >新增录音</el-button>
+        <el-button
+          type="primary"
+          size="small"
+          :loading="followUpDrawer.recordingSaving"
+          @click="saveRecordings"
+          style="margin-left: 10px;"
+        >保存录音</el-button>
+      </div>
+
+      <!-- 无录音时的初始上传区域 -->
+      <div class="recording-list" v-if="followUpDrawer.recordings.length === 0 && !followUpDrawer.loading">
+        <div class="recording-item">
+          <div class="recording-header">
+            <span class="recording-index">录音 1</span>
+          </div>
+          <div class="recording-file-area">
+            <el-upload
+              class="recording-upload"
+              :action="uploadAction"
+              :headers="uploadHeaders"
+              :data="uploadData"
+              :before-upload="(file) => beforeUploadRecording(file, 0)"
+              :on-success="(res, file) => onFirstUploadSuccess(res, file)"
+              :on-error="onUploadError"
+              :show-file-list="false"
+              accept=".mp3,.wav,.m4a,.aac,.ogg,.wma,.amr"
+              drag
+            >
+              <i class="el-icon-upload"></i>
+              <div class="el-upload__text">
+                将录音文件拖到此处,或<em>点击上传</em>
+              </div>
+              <div class="el-upload__tip" slot="tip">
+                支持 mp3/wav/m4a/aac/ogg/wma/amr 格式,最大50MB
+              </div>
+            </el-upload>
+          </div>
+        </div>
+        <div class="add-recording-area" style="margin-top: 12px;">
+          <el-button
+            type="primary"
+            size="small"
+            :loading="followUpDrawer.recordingSaving"
+            @click="saveRecordings"
+          >保存录音</el-button>
+        </div>
+      </div>
+    </div>
+  </el-drawer>
+  </div>
+</template>
+
+<script>
+import {
+  myList,
+  bindUserId,
+  addTag,
+  batchUpdateExternalContactNotes,
+  delTag,
+  listExternalContact,
+  getExternalContact,
+  delExternalContact,
+  addExternalContact,
+  updateExternalContact,
+  exportExternalContact,
+  editbindCustomer,
+  syncMyAddExternalContact,
+  setCustomerCourseSop,
+  getCustomerCourseSop,
+  setCustomerCourseSopList,
+  syncMyExternalContact, unBindUserId, updateExternalContactCall,exportMyExternalContact,updateExternalContactStatus,getWatchLogList,getRepeatRecordList
+} from '@/api/qw/externalContact'
+import info from "@/views/qw/externalContact/info.vue";
+import {getMyQwUserList, getMyQwCompanyList, handleInputAuthAppKey, updateUser} from "@/api/qw/user";
+import {addFsFirstDiagnosis, updateFsFirstDiagnosis, getFsFirstDiagnosis} from "@/api/company/firstDiagnosis";
+import {listTag, getTag, searchTags,} from "@/api/qw/tag";
+import { allListTagGroup} from "@/api/qw/tagGroup";
+import mycustomer from '@/views/qw/externalContact/mycustomer'
+import customerDetails from '@/views/qw/externalContact/customerDetails'
+import SopDialog from '@/views/course/sop/SopDialog.vue'
+import  selectUser  from "@/views/qw/externalContact/selectUser.vue";
+import { editTalk,editAllTalk } from "@/api/qw/externalContactInfo";
+import {createLinkUrl} from "@/api/course/sopCourseLink";
+import {docList} from "@/api/doctor/doctor";
+import PaginationMore from "@/components/PaginationMore/index.vue";
+import Collection from './collection.vue';
+import {courseList, videoList} from "@/api/course/courseRedPacketLog";
+import userDetails from '@/views/store/components/userDetails.vue';
+import userAddDetails from '@/views/store/components/userAddDetails.vue';
+import customerDetail from './customerDetail.vue';
+import createOder from '@/views/components/order/createOder.vue';
+import { uploadFollowUpFile, saveFollowUpRecord, getFollowUpStatistics } from '@/api/scrm/customerFollowUp';
+import { getMyCustomerList, updateCustomer } from '@/api/scrm/customer';
+import { getToken } from '@/utils/auth';
+export default {
+  name: "ExternalContact",
+  components:{PaginationMore, mycustomer,customerDetails,SopDialog,selectUser,info,Collection,userDetails,userAddDetails,customerDetail,createOder},
+  data() {
+    return {
+      aiAnalyze: {
+        title: "AI 分析",
+        open: false,
+        userId: null,
+        externalUserId: null,
+        corpId: null,
+        customerRow: null,
+      },
+      member:{
+        title:"客户详情",
+        open:false,
+      },
+      projectOptions: [],
+      courseLists: [],
+      videoList: [],
+      //重粉记录的参数
+      log: {
+        open: false,
+        loading: true,
+        list: [],
+        total: 0,
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          externalUserId: null,
+          fsUserId: null,
+          projectId: null,
+          courseId: null,
+          videoId: null,
+        },
+      },
+      repeatRecord: {
+        open: false,
+        loading: false,
+        list: [],
+        total: 0,
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          corpId: null,
+          externalUserId: null,
+          qwUserId: null,
+          qwUserName: null
+        }
+      },
+      statusDialog: {
+        open: false,
+        title: "修改客户状态"
+      },
+      statusForm: {
+        id: null,
+        status: null
+      },
+      statusRules: {
+        status: [
+          {required: true, message: '状态不能为空', trigger: 'change'}
+        ]
+      },
+      collection:{
+        titile:"信息采集",
+        open:false,
+      },
+      doctorList:[],
+      diagnosisForm:{},
+      diagnosisOpen:false,
+      diagnosisRules:{},
+      // 客户跟进记录
+      followUpDrawer: {
+        open: false,
+        loading: false,
+        externalContactId: null,
+        userId: null,
+        unfollowDays: 0,
+        followCount: 0,
+        recordings: [],
+        customerInfo: {},
+        followContent: '',
+        visitRecords: [],
+        saving: false,
+        visitSaving: false,
+        recordingSaving: false
+      },
+      uploadAction: process.env.VUE_APP_BASE_API + '/scrm/customer/followUp/upload',
+      uploadHeaders: {},
+      // CRM 客户字典
+      followUpSourceOptions: [],
+      followUpStatusOptions: [],
+      followUpTypeOptions: [],
+      // 标签管理
+      followUpTags: [],
+      followUpTagId: null,
+      followUpTagsOptions: [],
+      followUpTagInputVisible: false,
+      followUpTagInputValue: '',
+      notesOpen: {
+        type: 1,
+        nameType: 3,
+        addType: 0,
+        filter: false,
+        open: false,
+        notes: null,
+      },
+      user:{
+        open:false,
+        title:"修改客户"
+      },
+      userForm:{
+        id:null,
+        fsUserId:null,
+      },
+	    myQwUserList:[],
+      // 遮罩层
+      loading: false,
+      // 导出遮罩层
+      exportLoading: false,
+      tagOpen:false,
+      tagDelOpen:false,
+	  sTime:null,
+	  eTime:null,
+	  createTime:null,
+      // 选中数组
+      ids: [],
+      isBindMiniOptions:[
+        {dictLabel:"已绑定",dictValue:'isBindMini'},
+        {dictLabel:"未绑定",dictValue:'noBindMini'},
+      ],
+      isBindActiveName:"all",
+      remarkMobiles: [],
+      inputVisible: false,
+      inputValue: '',
+      // 非单个禁用
+      single: true,
+      tagGroupList: [],
+      //标签弹窗选择
+      tagChange:{
+        open:false,
+        index:null,
+      },
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+
+      // 企业微信客户表格数据
+      externalContactList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 用户类别字典
+      typeOptions: [],
+      ratingType: [],
+      ratingUpFall: [],
+      // 性别字典
+      genderOptions: [],
+
+      addTagForm:{
+        userIds:[],
+        tagIds:[]
+      },
+
+      myQwCompanyList:[],
+      // show:{
+      //   title:"客户详情",
+      //   open:false,
+      // },
+
+      //存储选择的客户
+      chooseCustomerSOP:null,
+
+      setSop:{
+        title:"选择课节SOP",
+        open:false,
+        //区分单选1还是多选2
+        type:null,
+      },
+      //合成的客户-课节SOP参数
+      customerCourseForm:{},
+
+      //查询是否已经设置过客户-某个课节的SOP
+      customerCourseFormLogs:{},
+      //绑定客户
+      bindCustomer:{
+        title:null,
+        open:false,
+      },
+      callOpen:{
+        open:false,
+        title: '修改客户称呼',
+
+      },
+      callOpenFrom:{
+        id:null,
+        stageStatus:null,
+      },
+
+      callOpenRule:{
+        stageStatus:[{required:true,message:"员工称呼不能为空",trigger:"blur"}]
+      },
+
+      //绑定的参数表
+      qwFormCustomer:{
+        externalContactId:null,
+        customerId:null,
+      },
+	  show:{
+	  		  title:"用户信息",
+	  		  open:false,
+	  },
+      // 来源字典
+      addWayOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        id:  null,
+        userId: null,
+        qwUserName:null,
+        externalUserId: null,
+        name: null,
+        avatar: null,
+        type: null,
+        qwUserId:null,
+        gender: null,
+        description: null,
+        tagIds: null,
+        outTagIds: null,
+        remark:null,
+        remarkMobiles: null,
+        remarkCorpName: null,
+        addWay: null,
+        operUserid: null,
+        corpId: null,
+        companyId: null,
+        status:null,
+        transferStatus:null,
+        isBind:null,
+        isBindMini:null,
+        lossTime:null,
+        createTime:null,
+        level:null,
+        levelType:null,
+        companyUser:null,
+        userRepeat: null
+      },
+
+      queryTagParams:{
+        pageNum: 1,
+        pageSize: 5,
+        total:0,
+        name:null,
+        corpId:null,
+      },
+
+      tagTotal:0,
+
+      //标签
+      changeTagDialog:{
+        title:"",
+        open:false,
+        type: null,
+      },
+      selectTags:[],
+      //排除的标签
+      outSelectTags:[],
+      // 表单参数
+      form: {},
+      tagList:[],
+      transferStatusOptions:[],
+      statusOptions:[],
+      // 表单校验
+      rules: {
+      },
+      fsUserId: null,
+    };
+  },
+  created() {
+    this.getDicts("sys_course_project").then(response => {
+      this.projectOptions = response.data;
+    });
+
+    this.getDicts("sys_qw_externalContact_type").then(response => {
+      this.typeOptions = response.data;
+    });
+
+    this.getDicts("sys_qw_sop_rating_type").then(response => {
+      this.ratingType = response.data;
+    });
+
+    this.getDicts("sys_qw_sop_rating_upFall").then(response => {
+      this.ratingUpFall = response.data;
+    });
+
+    this.handleGetMyQwUserList();
+
+    this.getDicts("sys_sex").then(response => {
+      this.genderOptions = response.data;
+    });
+    this.getDicts("sys_qw_externalContact_addWay").then(response => {
+      this.addWayOptions = response.data;
+    });
+
+
+
+    this.getDicts("sys_qw_external_contact_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_qw_transfer_status").then(response => {
+      this.transferStatusOptions = response.data;
+    });
+    // CRM 客户字典 - 跟进记录
+    this.getDicts("crm_customer_source").then(response => {
+      this.followUpSourceOptions = response.data;
+    });
+    this.getDicts("crm_customer_user_status").then(response => {
+      this.followUpStatusOptions = response.data;
+    });
+    this.getDicts("crm_customer_type").then(response => {
+      this.followUpTypeOptions = response.data;
+    });
+    this.getDicts("crm_customer_tag").then(response => {
+      this.followUpTagsOptions = response.data;
+    });
+    this.getDocList();
+    this.uploadHeaders = { Authorization: 'Bearer ' + getToken() };
+
+  },
+  computed: {
+    uploadData() {
+      return { externalContactId: this.followUpDrawer.externalContactId || '' };
+    },
+    baseApi() {
+      return process.env.VUE_APP_BASE_API || '';
+    }
+  },
+  methods: {
+    shortenText(text, maxLen = 16) {
+      const str = text == null ? '' : String(text);
+      if (str.length <= maxLen) return str;
+      return str.slice(0, maxLen) + '...';
+    },
+    parseFocusPoints(value) {
+      if (!value) return [];
+      if (Array.isArray(value)) {
+        return value.map(item => String(item).trim()).filter(Boolean);
+      }
+      if (typeof value === 'string') {
+        const raw = value.trim();
+        if (!raw) return [];
+        try {
+          const parsed = JSON.parse(raw);
+          if (Array.isArray(parsed)) {
+            return parsed.map(item => String(item).trim()).filter(Boolean);
+          }
+          if (typeof parsed === 'string') {
+            return [parsed.trim()].filter(Boolean);
+          }
+        } catch (e) {
+          // ignore parse error and use raw fallback
+        }
+        return [raw.replace(/^\[|\]$/g, '').replace(/["']/g, '').trim()].filter(Boolean);
+      }
+      return [String(value).trim()].filter(Boolean);
+    },
+    openAiDrawer(row) {
+      this.aiAnalyze.userId = row.userId;
+      this.aiAnalyze.externalUserId = row.operUserid ;
+      this.aiAnalyze.corpId = row.corpId ;
+      this.aiAnalyze.customerRow = row;
+      console.log(this.aiAnalyze);
+      this.aiAnalyze.open = true;
+    },
+    /** 重粉查看操作 */
+    showLog(row) {
+      this.log.queryParams.fsUserId = row.fsUserId;
+      this.log.open = true;
+      this.log.loading = true;
+      courseList().then(response => {
+        this.courseLists = response.list;
+        this.log.queryParams.externalUserId = row.id;
+        this.logList();
+      })
+    },
+    handleQueryWatchLog() {
+      this.log.queryParams.pageNum = 1;
+      this.log.queryParams.pageSize = 10;
+      this.logList();
+    },
+    logList() {
+      getWatchLogList(this.log.queryParams).then(e => {
+        this.log.loading = false;
+        this.log.list = e.rows;
+        this.log.total = e.total;
+      });
+    },
+    handleCreateOrder(row) {
+      this.$refs.createOder.show(row);
+    },
+    /** 重粉记录 */
+    showRepeatRecord(row) {
+      this.repeatRecord.queryParams.corpId = row.corpId;
+      this.repeatRecord.queryParams.externalUserId = row.externalUserId;
+      this.repeatRecord.queryParams.qwUserId = null;
+      this.repeatRecord.queryParams.qwUserName = null;
+      this.repeatRecord.queryParams.pageNum = 1;
+      this.repeatRecord.queryParams.pageSize = 10;
+      this.repeatRecord.open = true;
+      this.repeatRecordList();
+    },
+    handleQueryRepeatRecord() {
+      this.repeatRecord.queryParams.pageNum = 1;
+      this.repeatRecordList();
+    },
+    resetRepeatRecordQuery() {
+      this.repeatRecord.queryParams.qwUserId = null;
+      this.repeatRecord.queryParams.qwUserName = null;
+      this.repeatRecord.queryParams.pageNum = 1;
+      this.repeatRecordList();
+    },
+    repeatRecordList() {
+      this.repeatRecord.loading = true;
+      getRepeatRecordList(this.repeatRecord.queryParams).then(res => {
+        this.repeatRecord.list = res.rows || [];
+        this.repeatRecord.total = res.total || 0;
+      }).finally(() => {
+        this.repeatRecord.loading = false;
+      });
+    },
+    courseChange(row) {
+      this.log.queryParams.videoId = null;
+      if (row === '') {
+        this.videoList = [];
+        return
+      }
+      videoList(row).then(response => {
+        this.videoList = response.list
+      });
+    },
+
+    handleMemberdetails(row){
+            this.member.open=true;
+            setTimeout(() => {
+                 this.$refs.userDetails.getDetails(row.fsUserId);
+            }, 1);
+    },
+
+    handleInfoCollection(row){
+      this.collection.title = "信息采集";
+      this.collection.open = true;
+      this.userId = row.fsUserId;
+      setTimeout(() => {
+                 this.$refs.collection.getCollectionInfo(row.fsUserId);
+            }, 1);
+    },
+    closeCollection(){
+      this.collection.open = false;
+    },
+    doctorChange(val){
+      for(const doctor of this.doctorList) {
+        if(doctor.id == val) {
+          this.diagnosisForm.doctorDep = doctor.position;
+          this.diagnosisForm.doctorCertificate = doctor.certificateCode;
+          this.diagnosisForm.doctorName = doctor.name;
+          break;
+        }
+      }
+      console.log(this.diagnosisForm)
+    },
+    getDocList(){
+      docList().then(res => {
+        this.doctorList = res.rows;
+      })
+    },
+    handleDiagnosis(row){
+      getFsFirstDiagnosis(row.fsUserId).then(res => {
+        this.diagnosisForm = res.data;
+      });
+      this.fsUserId = row.fsUserId;
+      this.diagnosisOpen = true;
+    },
+   diagnosisSubmitForm(){
+    this.$refs["diagnosisForm"].validate(valid => {
+        if (valid) {
+          this.diagnosisForm.qwUserId = this.queryParams.qwUserId;
+          this.diagnosisForm.userId = this.fsUserId;
+          if (this.diagnosisForm.id != null) {
+            updateFsFirstDiagnosis(this.diagnosisForm).then(response => {
+              this.msgSuccess("修改成功");
+              this.diagnosisOpen = false;
+            });
+          } else {
+            addFsFirstDiagnosis(this.diagnosisForm).then(response => {
+              this.msgSuccess("新增成功");
+              this.diagnosisOpen = false;
+            });
+          }
+        }
+      });
+   },
+   diagnosisCancel(){
+    this.diagnosisOpen = false;
+   },
+	 change(){
+		if(this.createTime!=null){
+		  this.queryParams.sTime=this.createTime[0];
+		  this.queryParams.eTime=this.createTime[1];
+		}else{
+		  this.queryParams.sTime=null;
+		  this.queryParams.eTime=null;
+		}
+
+	  },
+    handledetails(row){
+      this.show.open=true;
+      setTimeout(() => {
+         this.$refs.Details.getDetails(row.id);
+      }, 1);
+    },
+    updateQwuser(){
+
+      for (const user of this.myQwUserList) {
+          if (user.dictValue == this.queryParams.qwUserId) {
+             this.queryParams.corpId=user.corpId;
+             break;
+          }
+      }
+      var listTagFrom={corpId:this.queryParams.corpId}
+
+        listTag(listTagFrom).then(response => {
+          this.tagList = response.rows;
+        });
+
+        this.getList();
+     },
+
+    //搜索的标签
+    hangleChangeTags(){
+
+      this.changeTagDialog.title="搜索的标签"
+      this.changeTagDialog.open=true;
+      this.changeTagDialog.type = 1;
+
+      // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
+      const selectedTagIds = new Set(
+        (this.selectTags || []).map(tagItem => tagItem?.tagId)
+      );
+
+      this.queryTagParams.name=null;
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
+          }
+        }
+      }, 200);
+
+
+    },
+
+
+    //选择排除标签
+    hangleChangeOutTags() {
+      this.changeTagDialog.title="搜索的标签"
+      this.changeTagDialog.open=true;
+      this.changeTagDialog.type = 2;
+
+      // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
+      const selectedTagIds = new Set(
+        (this.outSelectTags || []).map(tagItem => tagItem?.tagId)
+      );
+
+      this.queryTagParams.name=null;
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
+          }
+        }
+      }, 200);
+
+    },
+
+    //确定选择标签
+    tagSubmitForm(type){
+
+      if (type==1) {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            if (this.tagGroupList[i].tag[x].isSelected === true) {
+
+              if (!this.selectTags) {
+                this.selectTags = [];
+              }
+
+              // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
+              let tagExists = this.selectTags.some(
+                tag => tag.id === this.tagGroupList[i].tag[x].id
+              );
+
+              // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
+              if (!tagExists) {
+                this.selectTags.push(this.tagGroupList[i].tag[x]);
+              }
+            }
+          }
+        }
+        if (!this.selectTags || this.selectTags.length === 0) {
+          return this.$message('请选择标签');
+        }
+      }else if (type == 2) {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            if (this.tagGroupList[i].tag[x].isSelected === true) {
+
+              if (!this.outSelectTags) {
+                this.outSelectTags = [];
+              }
+
+              // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
+              let tagExists = this.outSelectTags.some(
+                tag => tag.id === this.tagGroupList[i].tag[x].id
+              );
+
+              // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
+              if (!tagExists) {
+                this.outSelectTags.push(this.tagGroupList[i].tag[x]);
+              }
+            }
+          }
+        }
+        if (!this.outSelectTags || this.outSelectTags.length === 0) {
+          return this.$message('请选择标签');
+        }
+      }
+      this.changeTagDialog.open = false;
+    },
+
+    //取消选择标签
+    tagCancel(){
+      this.changeTagDialog.open = false;
+    },
+
+    //删除一些选择的标签
+    handleCloseTags(list){
+      const ls = this.selectTags.findIndex(t => t.tagId === list.tagId);
+      if (ls !== -1) {
+        this.selectTags.splice(ls, 1);
+        this.selectTags = [...this.selectTags];
+      }
+
+      if (this.selectTags!=null && this.selectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.tagIds) {
+          this.queryParams.tagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.tagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.selectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.tagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.tagIds=this.queryParams.tagIds.join(",");
+      }else {
+        this.queryParams.tagIds=null;
+      }
+
+    },
+
+    //删除一些排除的标签
+    handleCloseOutTags(list){
+      const ls = this.outSelectTags.findIndex(t => t.tagId === list.tagId);
+      if (ls !== -1) {
+        this.outSelectTags.splice(ls, 1);
+        this.outSelectTags = [...this.selectTags];
+      }
+
+      if (this.outSelectTags!=null && this.outSelectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.outTagIds) {
+          this.queryParams.outTagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.outTagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.outSelectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.outTagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.outTagIds=this.queryParams.outTagIds.join(",");
+      }else {
+        this.queryParams.outTagIds=null;
+      }
+
+    },
+
+    handleChangeStatus(row) {
+      this.statusForm = {
+        id: row.id,
+        status: String(row.status) // 保证与 dictValue 类型一致
+      };
+      this.statusDialog.open = true;
+    },
+    submitStatusForm() {
+      this.$refs["statusForm"].validate(valid => {
+        if (valid) {
+          const params = {
+            id: this.statusForm.id,
+            status: this.statusForm.status
+          };
+
+          // 调用接口更新状态
+          updateExternalContactStatus(params).then(response => {
+            this.msgSuccess("状态修改成功");
+            this.statusDialog.open = false;
+            this.getList(); // 刷新列表
+          }).catch(error => {
+            console.error('状态修改失败:', error);
+            this.$message.error('状态修改失败');
+          });
+        }
+      });
+    },
+
+    /** 查询企业微信客户列表 */
+    getList() {
+      this.loading = true;
+      myList(this.queryParams).then(response => {
+        this.externalContactList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+
+    getPageListTagGroup(){
+      this.queryTagParams.corpId=this.queryParams.corpId
+      allListTagGroup(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.tagTotal = response.total;
+      });
+    },
+
+    handleSearchTags(name){
+
+      if (!name){
+        return this.$message.error("请输入要搜索的标签")
+      }
+
+      this.queryTagParams.name=name;
+      this.queryTagParams.corpId=this.queryParams.corpId;
+
+      searchTags(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.tagTotal = response.total;
+      });
+
+      // searchTags({name:name,corpId:this.queryParams.corpId}).then(response => {
+      //   this.tagGroupList = response.rows;
+      // });
+
+    },
+
+    handleGetMyQwUserList(){
+
+      getMyQwUserList().then(response => {
+        this.myQwUserList = response.data;
+        if(this.myQwUserList!=null){
+          this.queryParams.qwUserId=this.myQwUserList[0].dictValue
+          this.queryParams.corpId=this.myQwUserList[0].corpId
+          this.handleGetTagsList();
+          this.getList();
+        }
+      });
+
+    },
+
+    cancelSearchTags(){
+
+      this.resetSearchQueryTag()
+
+      this.getPageListTagGroup();
+
+    },
+
+    resetSearchQueryTag(){
+
+      this.queryTagParams= {
+        pageNum: 1,
+        pageSize: 5,
+        total:0,
+        name:null,
+      };
+    },
+
+
+    handleGetTagsList(){
+      var listTagFrom={corpId:this.queryParams.corpId}
+      listTag(listTagFrom).then(response => {
+        this.tagList = response.rows;
+      });
+    },
+
+    bindMiniCustomerId(row){
+
+      this.userForm.fsUserId=row;
+      bindUserId(this.userForm).then(res=>{
+         if (res.code==200){
+           this.$message.success('绑定成功')
+         }else {
+           this.$message.error('绑定失败:',res.msg)
+         }
+         this.getList()
+         this.user.open=false;
+      })
+    },
+    /** 查看客户详情 */
+    handleShow(row){
+      this.show.open=true;
+      var that=this;
+      const tab = "visit";
+      setTimeout(() => {
+        that.$refs.customerDetails.getDetails(row.customerId);
+        that.$refs.customerDetails.handleClick(tab);
+
+      }, 200);
+    },
+
+
+
+    handleClickX(tab, event) {
+
+      this.queryParams.isBind=tab.name;
+      this.handleQuery();
+    },
+
+    handleClose(tag) {
+      this.remarkMobiles.splice(this.remarkMobiles.indexOf(tag), 1);
+    },
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick(_ => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.remarkMobiles.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = '';
+    },
+
+    addUserTag(){
+
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要添加标签的客户');
+      }
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected=false;
+          }
+        }
+      }, 200);
+
+      this.tagOpen = true;
+
+    },
+
+    delUserTag(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要移除标签的客户');
+      }
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected=false;
+          }
+        }
+      }, 200);
+
+      this.tagDelOpen = true;
+
+    },
+
+    //重新获取页面数据
+    refreshList(){
+      this.getList();
+    },
+
+    //批量设置课程sop
+    setUserCourseSop(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要设置课程SOP的客户');
+      }
+
+      this.$confirm('批量设置客户课节SOP可能会存在重复,确定要批量设置吗?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+          this.setSop.open = true;
+          this.setSop.type = 2;
+        })
+        .catch(() => {
+          // 可以处理用户点击“取消”的逻辑
+        });
+
+    },
+    tagSelection(row){
+
+      row.isSelected= !row.isSelected;
+      this.$forceUpdate();
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    addTagCancel() {
+
+      this.tagOpen = false;
+
+      this.addTagForm={
+        userIds:[],
+        tagIds:[]
+      };
+    },
+
+    DelTagCancel() {
+      this.tagDelOpen = false;
+
+      this.addTagForm={
+        userIds:[],
+        tagIds:[]
+      };
+    },
+    addTagSubmitForm(){
+
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if(this.tagGroupList[i].tag[x].isSelected==true){
+            this.addTagForm.tagIds.push(this.tagGroupList[i].tag[x].tagId)
+          }
+
+        }
+      }
+      if(this.addTagForm.tagIds==[]||this.addTagForm.tagIds==null||this.addTagForm.tagIds==""){
+        return  this.$message('请选择标签');
+      }
+
+      this.addTagForm.corpId=this.queryParams.corpId
+      this.addTagForm.userIds=this.ids;
+
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '正在执行中请稍后~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      addTag(this.addTagForm).then(response => {
+       this.msgSuccess(response.msg);
+       this.tagOpen = false;
+        loadingRock.close();
+       this.addTagForm={
+         userIds:[],
+         tagIds:[]
+       };
+       this.getList()
+     }).finally(res=>{
+        loadingRock.close();
+      });
+
+    },
+    tagDelSubmitForm(){
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if(this.tagGroupList[i].tag[x].isSelected==true){
+            this.addTagForm.tagIds.push(this.tagGroupList[i].tag[x].tagId)
+          }
+
+        }
+      }
+      if(this.addTagForm.tagIds==[]||this.addTagForm.tagIds==null||this.addTagForm.tagIds==""){
+        return  this.$message('请选择标签');
+      }
+       this.addTagForm.corpId=this.queryParams.corpId
+      this.addTagForm.userIds=this.ids;
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '正在执行中请稍后~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      delTag(this.addTagForm).then(response => {
+       this.msgSuccess(response.msg);
+       this.tagDelOpen = false;
+        loadingRock.close();
+       this.addTagForm={
+         userIds:[],
+         tagIds:[]
+       };
+       this.getList()
+     }).finally(res=>{
+        loadingRock.close();
+      });
+    },
+
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        userId: null,
+        externalUserId: null,
+        name: null,
+        companyUserId:null,
+        customerId:null,
+        avatar: null,
+        type: null,
+        gender: null,
+        remark: null,
+        description: null,
+        tagIds: null,
+        remarkMobiles: null,
+        remarkCorpName: null,
+        addWay: null,
+        operUserid: null,
+        corpId: null,
+        companyId: null,
+        transferStatus:null,
+        status:null,
+        createTime:null,
+        transferTime:null,
+        transferNum:null,
+        lossTime:null,
+        delTime:null,
+        state:null,
+        wayId:null,
+        stageStatus:null,
+        customerName:null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+
+
+      if (this.selectTags!=null && this.selectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.tagIds) {
+          this.queryParams.tagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.tagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.selectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.tagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.tagIds=this.queryParams.tagIds.join(",");
+      }else {
+        this.queryParams.tagIds=null;
+      }
+
+
+      if (this.outSelectTags!=null && this.outSelectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.outTagIds) {
+          this.queryParams.outTagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.outTagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.outSelectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.outTagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.outTagIds=this.queryParams.outTagIds.join(",");
+      }else {
+        this.queryParams.outTagIds=null;
+      }
+
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.qwUserId=this.myQwUserList[0].dictValue;
+      this.queryParams.corpId=this.myQwUserList[0].corpId;
+      this.queryParams.transferStatus = null;
+      this.selectTags=[];
+      this.outSelectTags=[];
+	   this.createTime=null;
+	  this.queryParams.sTime=null;
+	  this.queryParams.eTime=null;
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.loading=true;
+      this.form.corpId=this.queryParams.corpId
+     addExternalContact(this.form).then(response => {
+       this.msgSuccess("同步成功");
+       this.getList();
+     }).finally(()=>{
+       this.loading=false;
+     });
+
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getExternalContact(id).then(response => {
+        this.form = response.data;
+        if(this.form.remarkMobiles!=null){
+          this.remarkMobiles=JSON.parse(this.form.remarkMobiles)
+        }else{
+          this.remarkMobiles=[]
+        }
+
+        this.open = true;
+        this.title = "修改企业微信客户";
+      });
+    },
+
+    handleAppellation(val){
+      this.callOpen.open=true;
+      this.callOpenFrom.stageStatus=val.stageStatus;
+      this.callOpenFrom.id=val.id;
+    },
+    /** 绑定客户操作 */
+    handleUpdateCustomer(row){
+       this.bindCustomer.title="绑定客户"
+        this.bindCustomer.open=true;
+        this.form.id=row.id
+        this.form.externalUserId=row.externalUserId
+        this.form.name=row.name
+    },
+
+    handleUpdateUser(row){
+        this.user.title="绑定客户"
+        this.user.open=true;
+        this.userForm.id=row.id;
+    },
+
+    handleUnBindUserId(val){
+
+      this.$confirm(
+        '确认解绑客户:<span style="color: green;">' + val.name + '' +
+        '</span> 的小程序用户?<br><span style="color: red;">【ps:可能会导致客户无法看课】</span>',
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+          dangerouslyUseHTMLString: true // 允许使用 HTML 字符串
+        }
+      ).then(() => {
+        return unBindUserId(val.id);
+      }).then(response => {
+        this.getList();
+        this.msgSuccess("解绑成功");
+      }).finally(res=>{
+        this.getList();
+      })
+    },
+
+    bindCustomerId(row){
+
+      console.log("row",row)
+      // this.qwFormCustomer.customerId=row;
+      this.form.customerId=row;
+      this.form.corpId=this.queryParams.corpId;
+      this.msgWarning("绑定中.....同步信息中.....");
+
+      editbindCustomer(this.form).then(res=>{
+        //清空表单
+        this.reset();
+        this.bindCustomer.open = false;
+        this.msgSuccess("绑定成功");
+        this.getList();
+
+      })
+
+    },
+    //设置一个SOP
+    setCourseSOP(row) {
+
+      // 检查 row.miniUserId 是否为 null
+      if (row.miniUserId === null || row.miniUserId === undefined) {
+        return this.$confirm('当前客户【CRM客户详情】中 未绑定小程序客户,请先绑定', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).catch(error => {
+          this.msgWarning("操作取消:", error);
+        });
+      } else {
+        this.chooseCustomerSOP = row;
+        this.setSop.open = true;
+        this.setSop.type=1;
+      }
+    },
+
+    //选择课程SOP
+    // 用于设置 customerCourseForm 和 customerCourseFormLogs 的共同属性
+    setCommonProperties(form, row) {
+      form.qwUserid = this.chooseCustomerSOP.userId;
+      form.companyUserId = this.chooseCustomerSOP.companyUserId;
+      form.externalUserId = this.chooseCustomerSOP.externalUserId;
+      form.customerId = this.chooseCustomerSOP.customerId;
+      form.miniUserId = this.chooseCustomerSOP.miniUserId;
+      form.businessId = row.businessId;
+    },
+
+    bindCourseSop(row,days) {
+
+      if (this.setSop.type==2){
+        this.setSop.open = false;
+        this.loading=true;
+        this.msgWarning("设定中.....同步信息中.....");
+
+        setCustomerCourseSopList({ids:this.ids,fsCourseSopId:row.id,days:days}).then(res=>{
+
+          let msg=" 批量设置成功数【" + res.successNum + "】,<br>"
+
+          if (res.failCRM.length>0){
+            msg+="失败的客户【" + res.failCRM + "】,原因是未绑定CRM客户。<br>"
+          }
+          if (res.failMiNi.length>0){
+            msg+="失败的客户【" + res.failMiNi + "】,原因是CRM中未绑定小程序客户。<br>"
+          }
+          if (res.failCompany.length>0){
+            msg+="失败的客户【" + res.failCompany + "】,原因是客户没有所属成员。<br>"
+          }
+
+
+          return this.$confirm(msg, "提示", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning",
+            dangerouslyUseHTMLString: true // 允许使用HTML标签
+          }).catch(error => {
+            this.msgSuccess("操作完成~");
+          });
+
+        }).finally(()=>{
+          this.loading = false;
+          this.getList();
+        })
+      }else if (this.setSop.type==1){
+
+      // 设置 customerCourseFormLogs 的属性
+      this.setCommonProperties(this.customerCourseFormLogs, row);
+
+      // 设置 customerCourseForm 的属性
+      this.setCommonProperties(this.customerCourseForm, row);
+      this.customerCourseForm.sopId = row.id;
+      this.customerCourseForm.sopType = row.sopType;
+      this.customerCourseForm.setting = row.setting;
+      this.customerCourseForm.days = days;
+
+      // 执行异步操作
+      getCustomerCourseSop(this.customerCourseFormLogs)
+        .then(res => {
+          if (res) {
+            return this.$confirm('当前客户已设置过相同课程课节SOP,确定还要再次设置吗?', "警告", {
+              confirmButtonText: "确定",
+              cancelButtonText: "取消",
+              type: "warning"
+            });
+          } else {
+            return Promise.resolve(); // 如果没有设置过,直接执行后续操作
+          }
+        })
+        .then(() => {
+          this.loading = true;
+          this.setSop.open = false;
+          this.msgSuccess("设定中.....同步信息中.....");
+
+          return setCustomerCourseSop(this.customerCourseForm);
+        })
+        .then(() => {
+          this.msgSuccess("设定成功");
+        })
+        .catch(error => {
+          this.msgWarning("操作取消:", error);
+        })
+        .finally(() => {
+          this.loading = false;
+          this.getList();
+        });
+      }
+    },
+    submitCallOpenFrom(){
+
+      this.$refs["callOpenFrom"].validate(valid => {
+        if (valid) {
+
+          if (this.callOpenFrom.id != null && this.callOpenFrom.stageStatus != null) {
+            updateExternalContactCall(this.callOpenFrom).then(res=>{
+              this.$message.success('修改成功');
+              this.callOpen.open=false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            this.form.remarkMobiles=JSON.stringify(this.remarkMobiles)
+            updateExternalContact(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addExternalContact(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除企业微信客户编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delExternalContact(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    handleSyncMyExternalContact(){
+      this.loading=true;
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '正在执行中请稍后~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      syncMyExternalContact(this.queryParams.qwUserId).then(res => {
+        this.msgSuccess("同步成功");
+        this.loading=false;
+        loadingRock.close();
+        this.getList();
+      }).catch(res=>{
+        console.log("asdasdwaaw ")
+        loadingRock.close();
+      }).finally(res=>{
+        loadingRock.close();
+        this.loading=false;
+      })
+    },
+
+    handleSyncAddMyExternalContact(){
+        this.loading=true;
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '正在执行中请稍后~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+    syncMyAddExternalContact(this.queryParams.qwUserId).then(res => {
+        this.msgSuccess("同步成功");
+        this.loading=false;
+        loadingRock.close();
+        this.getList();
+      }).finally(()=>{
+        loadingRock.close();
+        this.loading=false;
+    })
+    },
+
+	updateTalk(row){
+		const ids = row.id || this.ids;
+		this.$confirm('是否确认批量更改用户信息为非首次交流', "警告", {
+		    confirmButtonText: "确定",
+		    cancelButtonText: "取消",
+		    type: "warning"
+		  }).then(function() {
+		    return editTalk(ids);
+		  }).then(() => {
+		    this.getList();
+		    this.msgSuccess("成功");
+		  }).catch(() => {});
+	},
+	updateAllTalk(row){
+		const id =	this.queryParams.qwUserId
+		this.$confirm('是否确认更改全部用户信息为非首次交流', "警告", {
+		    confirmButtonText: "确定",
+		    cancelButtonText: "取消",
+		    type: "warning"
+		  }).then(function() {
+		    return editAllTalk(id);
+		  }).then(() => {
+		    this.getList();
+		    this.msgSuccess("成功");
+		  }).catch(() => {});
+	},
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有企业微信客户数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportMyExternalContact(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    },
+    handleBatchUpdateNotesFilter() {
+      this.notesOpen.open = true;
+      this.notesOpen.filter = true;
+    },
+    handleBatchUpdateNotes() {
+
+      if (this.ids == null || this.ids == "") {
+        return this.$message('请选择需要添加备注的客户');
+      }
+
+      this.notesOpen.open = true;
+      this.notesOpen.filter = false;
+
+    },
+    notesCancel(){
+      this.notesOpen={
+        open: false,
+        notes: null,
+        type: 1,
+        nameType:3,
+      }
+    },
+    notesSubmitForm() {
+
+      if (this.notesOpen.notes == null || this.notesOpen.notes == "") {
+        return this.$message.error("请输入备注内容");
+      }
+
+      // let loadingRock = this.$loading({
+      //   lock: true,
+      //   text: '正在执行中请稍后~~请不要刷新页面!!',
+      //   spinner: 'el-icon-loading',
+      //   background: 'rgba(0, 0, 0, 0.7)'
+      // });
+
+      let obj = JSON.parse(JSON.stringify(this.queryParams))
+      console.log(obj);
+      if(obj.tagIds !== null && obj.tagIds !== undefined && obj.tagIds !== ''){
+        obj.tagIds = obj.tagIds.split(",");
+      }
+      batchUpdateExternalContactNotes({
+        addType: 0,
+        userIds: this.ids,
+        notes: this.notesOpen.notes,
+        type: this.notesOpen.type,
+        nameType: this.notesOpen.nameType,
+        filter: this.notesOpen.filter,
+        param: obj
+      }).then(res => {
+
+        this.resultMessage = res.msg;
+        this.$message.success("正在执行中...");
+        // this.resultDialogVisible = true; // 显示弹窗
+        // this.resultTitle = '批量修改备注结果';
+
+      }).finally(res => {
+        this.getList();
+        // loadingRock.close();
+        this.notesCancel();
+      })
+
+    },
+    // ==================== 客户跟进记录 ====================
+    /** 打开跟进记录抽屉 */
+    openFollowUpDrawer(row) {
+      this.followUpDrawer = {
+        open: true,
+        loading: true,
+        externalContactId: row.id,
+        userId: row.fsUserId,
+        unfollowDays: 0,
+        followCount: 0,
+        recordings: [],
+        customerInfo: {},
+        followContent: '',
+        visitRecords: [],
+        saving: false
+      };
+      this.followUpTags = [];
+      this.loadFollowUpData();
+      // 加载SCRM客户详情
+      if (row.fsUserId) {
+        this.loadCustomerInfo(row.fsUserId);
+        this.$nextTick(() => {
+          if (this.$refs.followUpUserAddDetailsRef) {
+            this.$refs.followUpUserAddDetailsRef.getAddList(row.fsUserId);
+          }
+        });
+      }
+    },
+    /** 新增跟进记录槽位 */
+    addVisitRecordSlot() {
+      this.followUpDrawer.visitRecords.push({
+        _key: 'v_' + Date.now() + '_' + Math.random(),
+        registerDesc: '',
+        visitStatus: '',
+        visitTime: ''
+      });
+    },
+    /** 删除跟进记录槽位 */
+    deleteVisitRecord(index) {
+      this.followUpDrawer.visitRecords.splice(index, 1);
+    },
+    /** 保存所有跟进记录(JSON方式) */
+    saveVisitRecords() {
+      this.followUpDrawer.visitSaving = true;
+      const visitRecords = this.followUpDrawer.visitRecords.map(r => ({
+        registerDesc: r.registerDesc || '',
+        visitStatus: r.visitStatus || '',
+        visitTime: r.visitTime || ''
+      }));
+      saveFollowUpRecord({
+        externalContactId: this.followUpDrawer.externalContactId,
+        visitRecords: JSON.stringify(visitRecords)
+      }).then(res => {
+        if (res.code === 200) {
+          this.$message.success('跟进记录保存成功');
+        } else {
+          this.$message.error(res.msg || '保存失败');
+        }
+      }).catch(() => {
+        this.$message.error('保存失败,请重试');
+      }).finally(() => {
+        this.followUpDrawer.visitSaving = false;
+      });
+    },
+    /** 加载SCRM客户信息 */
+    loadCustomerInfo(fsUserId) {
+      getMyCustomerList({ fsUserId: fsUserId, pageNum: 1, pageSize: 1 }).then(response => {
+        if (response.rows && response.rows.length > 0) {
+          this.followUpDrawer.customerInfo = response.rows[0];
+          this.followUpTags = response.rows[0].tags ? response.rows[0].tags.split(',').filter(t => t) : [];
+        } else {
+          this.followUpTags = [];
+        }
+      }).catch(() => {});
+    },
+    /** 标签管理 - 显示自定义标签输入 */
+    followUpTagShowInput() {
+      this.followUpTagInputVisible = true;
+      this.$nextTick(_ => {
+        this.$refs.saveFollowUpTagInput && this.$refs.saveFollowUpTagInput.focus();
+      });
+    },
+    /** 标签管理 - 自定义标签输入确认 */
+    followUpTagInputConfirm() {
+      let inputValue = this.followUpTagInputValue.trim();
+      if (inputValue && !this.followUpTags.includes(inputValue)) {
+        this.followUpTags.push(inputValue);
+        this.syncFollowUpTags();
+      }
+      this.followUpTagInputVisible = false;
+      this.followUpTagInputValue = '';
+    },
+    /** 标签管理 - 删除标签 */
+    followUpTagHandleClose(tag) {
+      this.followUpTags.splice(this.followUpTags.indexOf(tag), 1);
+      this.syncFollowUpTags();
+    },
+    /** 标签管理 - 下拉选择标签 */
+    followUpTagChange(e) {
+      var item = this.followUpTagsOptions.find(val => val.dictValue === e);
+      if (item && !this.followUpTags.includes(item.dictLabel)) {
+        this.followUpTags.push(item.dictLabel);
+        this.syncFollowUpTags();
+      }
+      this.followUpTagId = null;
+    },
+    /** 标签管理 - 同步标签到 customerInfo.tags */
+    syncFollowUpTags() {
+      this.followUpDrawer.customerInfo.tags = this.followUpTags.join(',');
+    },
+    /** 保存SCRM客户信息 */
+    saveCustomerInfo() {
+      const info = this.followUpDrawer.customerInfo;
+      if (!info) return;
+      this.followUpDrawer.saving = true;
+      updateCustomer({
+        externalContactId: this.followUpDrawer.externalContactId,
+        source: info.source,
+        visitStatus: info.visitStatus,
+        customerType: info.customerType,
+        tags: info.tags,
+        remark: info.remark,
+        lastTime: info.lastTime,
+        followContent: this.followUpDrawer.followContent || ''
+      }).then(res => {
+        if (res.code === 200) {
+          this.$message.success('客户信息保存成功');
+        } else {
+          this.$message.error(res.msg || '保存失败');
+        }
+      }).catch(() => {
+        this.$message.error('保存失败,请重试');
+      }).finally(() => {
+        this.followUpDrawer.saving = false;
+      });
+    },
+    /** 加载跟进记录数据(从scrm_customer_info的JSON字段解析) */
+    loadFollowUpData() {
+      const params = {
+        externalContactId: this.followUpDrawer.externalContactId
+      };
+      getFollowUpStatistics(params).then(statRes => {
+        if (statRes.data) {
+          this.followUpDrawer.unfollowDays = statRes.data.unfollowDays || 0;
+          this.followUpDrawer.followCount = statRes.data.followCount || 0;
+        }
+      }).catch(() => {});
+      // 从 customerInfo 中解析 JSON 字段
+      getMyCustomerList({ externalContactId: this.followUpDrawer.externalContactId, pageNum: 1, pageSize: 1 }).then(response => {
+        this.followUpDrawer.loading = false;
+        if (response.rows && response.rows.length > 0) {
+          const info = response.rows[0];
+          // 解析跟进记录
+          if (info.visitRecords) {
+            try {
+              const parsed = typeof info.visitRecords === 'string' ? JSON.parse(info.visitRecords) : info.visitRecords;
+              this.followUpDrawer.visitRecords = (parsed || []).map((r, i) => ({
+                _key: 'v_' + Date.now() + '_' + i,
+                registerDesc: r.registerDesc || '',
+                visitStatus: r.visitStatus || '',
+                visitTime: r.visitTime || ''
+              }));
+            } catch (e) {
+              this.followUpDrawer.visitRecords = [];
+            }
+          } else {
+            this.followUpDrawer.visitRecords = [];
+          }
+          // 解析录音记录
+          if (info.recordings) {
+            try {
+              const parsed = typeof info.recordings === 'string' ? JSON.parse(info.recordings) : info.recordings;
+              this.followUpDrawer.recordings = (parsed || []).map((r, i) => ({
+                _key: 'rec_' + Date.now() + '_' + i,
+                fileName: r.fileName || '',
+                fileUrl: r.fileUrl || '',
+                fileSize: r.fileSize || 0,
+                duration: r.duration || 0,
+                uploadTime: r.uploadTime || ''
+              }));
+            } catch (e) {
+              this.followUpDrawer.recordings = [];
+            }
+          } else {
+            this.followUpDrawer.recordings = [];
+          }
+        } else {
+          this.followUpDrawer.visitRecords = [];
+          this.followUpDrawer.recordings = [];
+        }
+      }).catch(() => {
+        this.followUpDrawer.loading = false;
+      });
+    },
+    /** 生成唯一key */
+    _genKey() {
+      return 'new_' + Date.now() + '_' + Math.random();
+    },
+    /** 新增录音空位 */
+    addRecordingSlot() {
+      this.followUpDrawer.recordings.push({
+        _key: this._genKey(),
+        fileName: '',
+        fileUrl: '',
+        fileSize: 0,
+        duration: 0,
+        uploadTime: ''
+      });
+    },
+    /** 删除录音记录 */
+    deleteRecording(index) {
+      this.followUpDrawer.recordings.splice(index, 1);
+    },
+    /** 保存所有录音记录(JSON方式) */
+    saveRecordings() {
+      this.followUpDrawer.recordingSaving = true;
+      const recordings = this.followUpDrawer.recordings.map(r => ({
+        fileName: r.fileName || '',
+        fileUrl: r.fileUrl || '',
+        fileSize: r.fileSize || 0,
+        duration: r.duration || 0,
+        uploadTime: r.uploadTime || ''
+      }));
+      saveFollowUpRecord({
+        externalContactId: this.followUpDrawer.externalContactId,
+        recordings: JSON.stringify(recordings)
+      }).then(res => {
+        if (res.code === 200) {
+          this.$message.success('录音保存成功');
+        } else {
+          this.$message.error(res.msg || '保存失败');
+        }
+      }).catch(() => {
+        this.$message.error('保存失败,请重试');
+      }).finally(() => {
+        this.followUpDrawer.recordingSaving = false;
+      });
+    },
+    /** 上传前校验 */
+    beforeUploadRecording(file, index) {
+      const maxSize = 50 * 1024 * 1024; // 50MB
+      if (file.size > maxSize) {
+        this.$message.error('录音文件大小不能超过50MB');
+        return false;
+      }
+      const ext = file.name.substring(file.name.lastIndexOf('.')).toLowerCase();
+      const allowed = ['.mp3', '.wav', '.m4a', '.aac', '.ogg', '.wma', '.amr'];
+      if (!allowed.includes(ext)) {
+        this.$message.error('不支持的文件格式,请上传音频文件');
+        return false;
+      }
+      return true;
+    },
+    /** 首个上传成功 */
+    onFirstUploadSuccess(res, file) {
+      if (res.code === 200) {
+        const data = res.data || {};
+        this.followUpDrawer.recordings.push({
+          _key: this._genKey(),
+          fileName: data.fileName || file.name,
+          fileUrl: data.fileUrl || '',
+          fileSize: data.fileSize || file.size,
+          duration: data.duration || 0,
+          uploadTime: data.uploadTime || this._formatNow()
+        });
+        this.$message.success('录音上传成功');
+      } else {
+        this.$message.error(res.msg || '上传失败');
+      }
+    },
+    /** 上传成功回调 */
+    onUploadSuccess(res, file, index) {
+      if (res.code === 200) {
+        const data = res.data || {};
+        const item = this.followUpDrawer.recordings[index];
+        if (item) {
+          item.fileName = data.fileName || file.name;
+          item.fileUrl = data.fileUrl || '';
+          item.fileSize = data.fileSize || file.size;
+          item.duration = data.duration || 0;
+          item.uploadTime = data.uploadTime || this._formatNow();
+          this.$set(this.followUpDrawer.recordings, index, { ...item });
+        }
+        this.$message.success('录音上传成功');
+      } else {
+        this.$message.error(res.msg || '上传失败');
+      }
+    },
+    /** 上传失败 */
+    onUploadError(err) {
+      this.$message.error('录音上传失败,请重试');
+      console.error('Upload error:', err);
+    },
+    /** 音频加载完成,获取时长 */
+    onAudioLoaded(event, index) {
+      const duration = Math.round(event.target.duration || 0);
+      const item = this.followUpDrawer.recordings[index];
+      if (item && !item.duration) {
+        item.duration = duration;
+      }
+    },
+    /** 格式化文件大小 */
+    formatFileSize(bytes) {
+      if (!bytes || bytes === 0) return '0 B';
+      const k = 1024;
+      const sizes = ['B', 'KB', 'MB', 'GB'];
+      const i = Math.floor(Math.log(bytes) / Math.log(k));
+      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+    },
+    /** 获取音频播放URL(OSS直链,可直接播放) */
+    getAudioPlayUrl(item) {
+      if (item.fileUrl) {
+        return item.fileUrl;
+      }
+      return '';
+    },
+    _formatNow() {
+      const d = new Date();
+      const pad = n => n.toString().padStart(2, '0');
+      return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) +
+        ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds());
+    },
+  }
+};
+</script>
+<style scoped>
+/* CSS 样式 */
+.tag-container {
+  display: flex;
+  flex-wrap: wrap; /* 超出宽度时自动换行 */
+  gap: 8px; /* 设置标签之间的间距 */
+}
+.name-background {
+  display: inline-block;
+  background-color: #abece6; /* 背景颜色 */
+  padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
+  border-radius: 4px; /* 可选:设置圆角 */
+}
+.tag-box {
+  padding: 8px 12px;
+  border: 1px solid #989797;
+  border-radius: 4px;
+  cursor: pointer;
+  display: inline-block;
+}
+
+.tag-selected {
+  background-color: #00bc98;
+  color: #fff;
+  border-color: #00bc98;
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+
+.button-new-tag {
+  margin-left: 10px;
+  height: 32px;
+  line-height: 30px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+.input-new-tag {
+  width: 90px;
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+
+/* 新增的滚动容器样式(不影响原有样式) */
+.scroll-wrapper {
+  max-height: 130px; /* 大约三行的高度 */
+  overflow-y: auto;  /* 垂直滚动 */
+  padding-right: 5px; /* 为滚动条留出空间 */
+}
+
+/* 美化滚动条(可选) */
+.scroll-wrapper::-webkit-scrollbar {
+  width: 6px;
+}
+.scroll-wrapper::-webkit-scrollbar-thumb {
+  background: rgba(0, 0, 0, 0.2);
+  border-radius: 3px;
+}
+
+
+.tag-container {
+  max-height: 200px;
+  overflow-y: auto;
+  padding: 1px;
+  border: 1px solid #ebeef5;
+  border-radius: 1px;
+  background-color: #fafafa;
+}
+.tag-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+.scroll-hint {
+  text-align: center;
+  color: #909399;
+  font-size: 12px;
+  padding: 1px 0;
+}
+.container {
+  max-width: 800px;
+  margin: 0 auto;
+  padding: 10px;
+}
+.title {
+  text-align: center;
+  color: #303133;
+  margin-bottom: 30px;
+}
+.demo-table {
+  width: 100%;
+  margin-bottom: 30px;
+}
+.instructions {
+  background-color: #f5f7fa;
+  padding: 15px;
+  border-radius: 1px;
+  margin-bottom: 20px;
+}
+
+/* ========== 客户跟进记录抽屉 ========== */
+.follow-up-drawer {
+  padding: 0 20px 20px;
+}
+
+.follow-up-header {
+  display: flex;
+  justify-content: space-around;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  border-radius: 10px;
+  padding: 20px;
+  margin-bottom: 20px;
+}
+
+.stat-item {
+  text-align: center;
+}
+
+.stat-label {
+  display: block;
+  font-size: 13px;
+  color: rgba(255, 255, 255, 0.8);
+  margin-bottom: 6px;
+}
+
+.stat-value {
+  display: block;
+  font-size: 28px;
+  font-weight: bold;
+  color: #fff;
+}
+
+.stat-warn {
+  color: #ffd54f;
+}
+
+.stat-primary {
+  color: #69f0ae;
+}
+
+.recording-list {
+  margin-bottom: 16px;
+}
+
+.recording-item {
+  border: 1px solid #e4e7ed;
+  border-radius: 8px;
+  padding: 16px;
+  margin-bottom: 12px;
+  background: #fafbfc;
+  transition: box-shadow 0.2s;
+}
+
+.recording-item:hover {
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+}
+
+.recording-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 12px;
+  padding-bottom: 8px;
+  border-bottom: 1px dashed #e4e7ed;
+}
+
+.recording-index {
+  font-size: 14px;
+  font-weight: 600;
+  color: #303133;
+}
+
+.recording-file-area {
+  margin-bottom: 12px;
+}
+
+.recording-upload {
+  width: 100%;
+}
+
+.recording-upload .el-upload-dragger {
+  width: 100%;
+}
+
+.recording-play-area {
+  background: #fff;
+  border: 1px solid #e4e7ed;
+  border-radius: 6px;
+  padding: 12px;
+}
+
+.recording-info {
+  display: flex;
+  align-items: center;
+  margin-bottom: 8px;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+
+.recording-play-icon {
+  font-size: 18px;
+  color: #409eff;
+}
+
+.recording-name {
+  font-size: 13px;
+  color: #303133;
+  max-width: 200px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.recording-size {
+  font-size: 12px;
+  color: #909399;
+}
+
+.recording-time {
+  font-size: 12px;
+  color: #909399;
+  margin-left: auto;
+}
+
+.recording-audio {
+  width: 100%;
+  height: 36px;
+  outline: none;
+}
+
+.recording-content-area {
+  margin-top: 12px;
+  padding-top: 12px;
+  border-top: 1px solid #e4e7ed;
+}
+
+.recording-actions {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 8px;
+}
+
+.add-recording-area {
+  text-align: center;
+  padding: 16px 0;
+}
+
+/* ========== 可编辑客户信息面板 ========== */
+.customer-edit-panel {
+  background: #fff;
+  border: 1px solid #e4e7ed;
+  border-radius: 8px;
+  padding: 16px 20px;
+  margin-bottom: 20px;
+}
+
+.edit-panel-title {
+  font-size: 15px;
+  font-weight: 600;
+  color: #303133;
+  margin-bottom: 12px;
+  padding-bottom: 8px;
+  border-bottom: 1px solid #ebeef5;
+}
+
+.customer-edit-form {
+  padding: 0;
+}
+
+.customer-edit-form .el-form-item {
+  margin-bottom: 12px;
+}
+
+.readonly-value {
+  font-size: 13px;
+  color: #606266;
+  line-height: 32px;
+}
+</style>

+ 28 - 26
src/views/live/liveData/index.vue

@@ -563,21 +563,23 @@
             </el-table-column>
             <el-table-column prop="rewardType" label="领取类型" min-width="160">
                 <template slot-scope="scope">
-                    <dict-tag :options="liveRewardTypeList" :value="scope.row.rewardType"/>
-                    <el-button
-                        v-if="scope.row.rewardType != 4 && scope.row.rewardType != 99"
-                        type="text"
-                        size="small"
-                        style="margin-left: 8px;"
-                        @click="handleOpenRedPacketLog(scope.row)"
-                    >红包/积分领取详细</el-button>
-                    <el-button
-                        v-if="scope.row.rewardType == 4 || scope.row.rewardType == 5 || scope.row.rewardType == 6 || scope.row.rewardType == 7"
-                        type="text"
-                        size="small"
-                        style="margin-left: 8px;"
-                        @click="handleOpenCouponLog(scope.row)"
-                    >核销卷领取详情</el-button>
+                    <div v-if="scope.row.isCompleted == 1">
+                        <dict-tag :options="liveRewardTypeList" :value="scope.row.rewardType"/>
+                        <el-button
+                            v-if="scope.row.rewardType != 4 && scope.row.rewardType != 99"
+                            type="text"
+                            size="small"
+                            style="margin-left: 8px;"
+                            @click="handleOpenRedPacketLog(scope.row)"
+                        >红包/积分领取详细</el-button>
+                        <el-button
+                            v-if="scope.row.rewardType == 4 || scope.row.rewardType == 5 || scope.row.rewardType == 6 || scope.row.rewardType == 7"
+                            type="text"
+                            size="small"
+                            style="margin-left: 8px;"
+                            @click="handleOpenCouponLog(scope.row)"
+                        >核销卷领取详情</el-button>
+                    </div>
                 </template>
             </el-table-column>
         </el-table>
@@ -650,14 +652,11 @@
               style="width: 100%"
           >
               <el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
-              <el-table-column prop="nickname" label="会员昵称" min-width="120"></el-table-column>
-              <el-table-column prop="phone" label="会员手机号" min-width="120"></el-table-column>
+              <el-table-column prop="nickName" label="会员昵称" min-width="120"></el-table-column>
               <el-table-column prop="couponTitle" label="优惠券名称" min-width="120"></el-table-column>
-              <el-table-column prop="couponPrice" label="优惠券面值" min-width="100" align="center"></el-table-column>
-              <el-table-column prop="useMinPrice" label="最低消费" min-width="100" align="center"></el-table-column>
-              <el-table-column prop="limitTime" label="优惠券结束时间" min-width="160" align="center"></el-table-column>
-              <el-table-column prop="createTime" label="领取时间" min-width="160" align="center"></el-table-column>
-              <el-table-column prop="useTime" label="使用时间" min-width="160" align="center"></el-table-column>
+              <el-table-column prop="limitTime" label="优惠券有效期" min-width="160" align="center"></el-table-column>
+              <el-table-column prop="startTime" label="开始时间" min-width="160" align="center"></el-table-column>
+              <el-table-column prop="updateTime" label="更新时间" min-width="160" align="center"></el-table-column>
               <el-table-column prop="status" label="状态" min-width="100" align="center">
                   <template slot-scope="scope">
                       <el-tag v-if="scope.row.status == 1" type="success">已使用</el-tag>
@@ -692,6 +691,7 @@ import {
 import {listLiveRedPacketLog} from '@/api/live/liveRedPacketLog';
 import { selectDictLabel } from '@/utils/common'
 import { listStoreCouponUser } from '@/api/live/liveCouponUser'
+import { getCourseCouponUserListVO } from '@/api/course/courseCouponUser'
 
 export default {
   name: "LiveData",
@@ -788,7 +788,8 @@ export default {
             pageNum: 1,
             pageSize: 10,
             userId: null,
-            type: null
+            liveId: null,
+            sendType:2,
         }
     };
   },
@@ -1118,7 +1119,7 @@ export default {
       handleOpenCouponLog(row){
           this.couponLogDrawerVisible = true;
           this.couponLogQueryParams.userId = row.userId;
-          this.couponLogQueryParams.type = '4-live-' + this.currentLiveId;
+          this.couponLogQueryParams.liveId = this.currentLiveId;
           this.couponLogQueryParams.pageNum = 1;
           this.loadCouponLogList();
       },
@@ -1126,11 +1127,12 @@ export default {
       /** 加载核销卷领取详情列表 */
       loadCouponLogList() {
           this.couponLogLoading = true;
-          listStoreCouponUser({
+          getCourseCouponUserListVO({
               pageNum: this.couponLogQueryParams.pageNum,
               pageSize: this.couponLogQueryParams.pageSize,
               userId: this.couponLogQueryParams.userId,
-              type: this.couponLogQueryParams.type
+              sendType: this.couponLogQueryParams.sendType,
+              liveId: this.couponLogQueryParams.liveId
           }).then(response => {
               this.couponLogList = response.rows || [];
               this.couponLogTotal = response.total || 0;