吴树波 16 часов назад
Родитель
Сommit
c583efa1cc

+ 1 - 1
.editorconfig

@@ -8,7 +8,7 @@ charset = utf-8
 # 缩进风格,可选space、tab
 indent_style = space
 # 缩进的空格数
-indent_size = 2
+indent_size = 4
 # 结尾换行符,可选lf、cr、crlf
 end_of_line = lf
 # 在文件结尾插入新行

+ 78 - 0
src/api/crm/customerProperty.js

@@ -0,0 +1,78 @@
+import request from '@/utils/request'
+
+export function listByCustomerId(customerId) {
+  return request({
+    url: '/crm/customerProperty/list/' + customerId,
+    method: 'get'
+  })
+}
+
+export function getById(id) {
+  return request({
+    url: '/crm/customerProperty/' + id,
+    method: 'get'
+  })
+}
+
+export function add(data) {
+  return request({
+    url: '/crm/customerProperty/add',
+    method: 'post',
+    data: data
+  })
+}
+
+export function addOrUpdate(data) {
+  return request({
+    url: '/crm/customerProperty/addOrUpdate',
+    method: 'post',
+    data: data
+  })
+}
+
+export function addByTemplateId(customerId, templateId, propertyValue) {
+  return request({
+    url: '/crm/customerProperty/addByTemplateId',
+    method: 'post',
+    params: { customerId, templateId, propertyValue }
+  })
+}
+
+export function addOrUpdateByTemplateId(customerId, templateId, propertyValue) {
+  return request({
+    url: '/crm/customerProperty/addOrUpdateByTemplateId',
+    method: 'post',
+    params: { customerId, templateId, propertyValue }
+  })
+}
+
+export function batchAddByTemplateIds(customerId, propertyMap) {
+  return request({
+    url: '/crm/customerProperty/batchAddByTemplateIds/' + customerId,
+    method: 'post',
+    data: propertyMap
+  })
+}
+
+export function update(data) {
+  return request({
+    url: '/crm/customerProperty',
+    method: 'put',
+    data: data
+  })
+}
+
+export function del(ids) {
+  return request({
+    url: '/crm/customerProperty/' + ids,
+    method: 'delete'
+  })
+}
+
+export function deleteByPropertyId(customerId, propertyId) {
+  return request({
+    url: '/crm/customerProperty/deleteByPropertyId',
+    method: 'delete',
+    params: { customerId, propertyId }
+  })
+}

+ 47 - 0
src/api/crm/propertyTemplate.js

@@ -0,0 +1,47 @@
+import request from '@/utils/request'
+
+export function listPropertyTemplate(query) {
+  return request({
+    url: '/crm/customerPropertyTemplate/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function getPropertyTemplate(id) {
+  return request({
+    url: '/crm/customerPropertyTemplate/' + id,
+    method: 'get'
+  })
+}
+
+export function addPropertyTemplate(data) {
+  return request({
+    url: '/crm/customerPropertyTemplate',
+    method: 'post',
+    data: data
+  })
+}
+
+export function updatePropertyTemplate(data) {
+  return request({
+    url: '/crm/customerPropertyTemplate',
+    method: 'put',
+    data: data
+  })
+}
+
+export function delPropertyTemplate(id) {
+  return request({
+    url: '/crm/customerPropertyTemplate/' + id,
+    method: 'delete'
+  })
+}
+
+export function exportPropertyTemplate(query) {
+  return request({
+    url: '/crm/customerPropertyTemplate/export',
+    method: 'get',
+    params: query
+  })
+}

+ 466 - 0
src/views/crm/components/AiTagPanel.vue

@@ -0,0 +1,466 @@
+<template>
+  <div class="info-section">
+    <div class="section-header">
+      <span class="section-title"><i class="el-icon-magic-sticker"></i> AI 标签</span>
+      <div class="header-actions">
+        <el-button type="primary" size="mini" icon="el-icon-plus" @click="handleAddTag">添加维度</el-button>
+      </div>
+    </div>
+    <div class="section-content" v-loading="loading">
+      <div v-if="tagList.length === 0" class="empty-tips">
+        <span>暂无标签,点击"添加维度"开始设置</span>
+      </div>
+
+      <el-row :gutter="24" v-else>
+        <el-col :span="6" v-for="tag in tagList" :key="tag.id" class="tag-col">
+          <div class="info-item">
+            <span class="info-label">
+              {{ tag.propertyName }}
+              <el-button type="text" icon="el-icon-delete" size="mini" @click="handleDeleteTag(tag)" style="color: #f56c6c; margin-left: 4px;"></el-button>
+            </span>
+            <span class="info-value">
+              <el-tag
+                v-if="tag.propertyValue"
+                size="mini"
+                @click="handleEditTag(tag)"
+                style="cursor: pointer;"
+                :type="getIntentionTagType(tag.intention)"
+              >
+                <span v-if="Array.isArray(tag.propertyValue)">{{ tag.propertyValue.join('、') }}</span>
+                <span v-else>{{ tag.propertyValue }}</span>
+              </el-tag>
+              <span v-else class="no-value">
+                未设置
+                <el-button type="text" size="mini" icon="el-icon-edit" @click="handleEditTag(tag)" style="margin-left: 4px;">批注</el-button>
+              </span>
+            </span>
+            <div class="tag-extra-info">
+              <el-tag v-if="tag.intention" size="mini" effect="plain">
+                <i class="el-icon-star-on"></i> {{ getIntentionText(tag.intention) }}
+              </el-tag>
+              <el-tag v-if="tag.likeRatio !== null && tag.likeRatio !== undefined" size="mini" type="success" effect="plain">
+                <i class="el-icon-trend-chart"></i> {{ tag.likeRatio }}%
+              </el-tag>
+            </div>
+          </div>
+        </el-col>
+      </el-row>
+    </div>
+
+    <!-- 添加/编辑标签弹窗 -->
+    <el-dialog
+      :title="dialogTitle"
+      :visible.sync="dialogVisible"
+      width="600px"
+      append-to-body
+      :close-on-click-modal="false"
+    >
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="标签维度" prop="propertyId">
+          <el-select
+            v-model="form.propertyId"
+            placeholder="请选择标签维度"
+            style="width: 100%"
+            :disabled="isEdit"
+            @change="handlePropertyChange"
+          >
+            <el-option
+              v-for="item in propertyTemplateList"
+              :key="item.id"
+              :label="item.name"
+              :value="item.id"
+            >
+              <span style="float: left">{{ item.name }}</span>
+              <span style="float: right; color: #8492a6; font-size: 13px">{{ getValueTypeText(item.valueType) }}</span>
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="标签值" prop="propertyValue">
+          <el-input
+            v-if="currentValueType === 'text'"
+            v-model="form.propertyValue"
+            placeholder="请输入标签值"
+            maxlength="100"
+            show-word-limit
+          />
+          <el-select
+            v-else-if="currentValueType === 'select'"
+            v-model="form.propertyValue"
+            placeholder="请选择标签值"
+            style="width: 100%"
+            clearable
+          >
+            <el-option label="是" value="是" />
+            <el-option label="否" value="否" />
+          </el-select>
+          <el-select
+            v-else-if="currentValueType === 'multiSelect'"
+            v-model="form.propertyValue"
+            placeholder="请选择标签值(可多选)"
+            style="width: 100%"
+            multiple
+            collapse-tags
+            clearable
+          >
+            <el-option label="喜欢" value="喜欢" />
+            <el-option label="不喜欢" value="不喜欢" />
+            <el-option label="一般" value="一般" />
+            <el-option label="观望" value="观望" />
+            <el-option label="有意向" value="有意向" />
+            <el-option label="无意向" value="无意向" />
+          </el-select>
+          <el-input
+            v-else-if="currentValueType === 'number'"
+            v-model="form.propertyValue"
+            placeholder="请输入数字"
+            maxlength="20"
+          />
+          <el-input
+            v-else-if="currentValueType === 'date'"
+            v-model="form.propertyValue"
+            type="date"
+            placeholder="选择日期"
+            style="width: 100%"
+          />
+          <span v-else class="unknown-type">未知的属性类型</span>
+        </el-form-item>
+        <el-form-item label="意向登记" prop="intention">
+          <el-select v-model="form.intention" placeholder="请选择意向程度" style="width: 100%" clearable>
+            <el-option label="高意向(80-100%)" value="high" />
+            <el-option label="中意向(50-79%)" value="medium" />
+            <el-option label="低意向(20-49%)" value="low" />
+            <el-option label="无意向(0-19%)" value="none" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="喜欢占比" prop="likeRatio">
+          <el-slider v-model="form.likeRatio" :min="0" :max="100" show-input input-size="small" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input
+            v-model="form.remark"
+            type="textarea"
+            :rows="2"
+            placeholder="请输入备注"
+            maxlength="200"
+            show-word-limit
+          />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="dialogVisible = false">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listPropertyTemplate } from "@/api/crm/propertyTemplate";
+import { listByCustomerId, addOrUpdateByTemplateId, deleteByPropertyId, addOrUpdate } from "@/api/crm/customerProperty";
+
+export default {
+  name: "AiTagPanel",
+  props: {
+    customerId: {
+      type: Number,
+      required: true,
+      default: null
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      tagList: [],
+      propertyTemplateList: [],
+      dialogVisible: false,
+      dialogTitle: "",
+      isEdit: false,
+      currentValueType: "text",
+      form: {
+        customerId: null,
+        propertyId: null,
+        propertyName: null,
+        propertyValue: null,
+        propertyValueType: null,
+        tradeType: null,
+        intention: null,
+        likeRatio: null,
+        remark: null
+      },
+      rules: {
+        propertyId: [
+          { required: true, message: "请选择标签维度", trigger: "change" }
+        ],
+        propertyValue: [
+          { required: true, message: "请输入标签值", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    if (this.customerId) {
+      this.loadTags();
+    }
+  },
+  watch: {
+    customerId(newVal) {
+      if (newVal) {
+        this.loadTags();
+      }
+    },
+    'form.likeRatio'(newVal) {
+      if (newVal !== null && newVal !== undefined) {
+        this.autoSetIntention(newVal);
+      }
+    }
+  },
+  methods: {
+    autoSetIntention(likeRatio) {
+      let intention = null;
+      if (likeRatio >= 80) {
+        intention = 'high';
+      } else if (likeRatio >= 50) {
+        intention = 'medium';
+      } else if (likeRatio >= 20) {
+        intention = 'low';
+      } else {
+        intention = 'none';
+      }
+      this.form.intention = intention;
+    },
+    loadTags() {
+      this.loading = true;
+      listByCustomerId(this.customerId).then(response => {
+        let tagList = response.data || [];
+        console.log('加载的标签数据:', tagList);
+        tagList.forEach(tag => {
+          if (tag.propertyValueType === 'multiSelect' && tag.propertyValue && typeof tag.propertyValue === 'string') {
+            tag.propertyValue = tag.propertyValue.split(',');
+          }
+        });
+        this.tagList = tagList;
+        this.loading = false;
+      }).catch(() => {
+        this.loading = false;
+      });
+    },
+    loadPropertyTemplates() {
+      listPropertyTemplate({ pageNum: 1, pageSize: 100 }).then(response => {
+        this.propertyTemplateList = response.rows || [];
+      });
+    },
+
+    handleAddTag() {
+      this.loadPropertyTemplates();
+      this.reset();
+      this.dialogTitle = "添加标签";
+      this.isEdit = false;
+      this.dialogVisible = true;
+    },
+    handleEditTag(tag) {
+      this.loadPropertyTemplates();
+      let propertyValue = tag.propertyValue;
+      if (tag.propertyValueType === 'multiSelect' && propertyValue && typeof propertyValue === 'string') {
+        propertyValue = propertyValue.split(',');
+      }
+      this.form = {
+        customerId: tag.customerId,
+        propertyId: tag.propertyId,
+        propertyName: tag.propertyName,
+        propertyValue: propertyValue,
+        propertyValueType: tag.propertyValueType,
+        tradeType: tag.tradeType,
+        intention: tag.intention || null,
+        likeRatio: tag.likeRatio || null,
+        remark: tag.remark
+      };
+      this.currentValueType = tag.propertyValueType || "text";
+      this.dialogTitle = "编辑标签";
+      this.isEdit = true;
+      this.dialogVisible = true;
+    },
+    handleDeleteTag(tag) {
+      this.$confirm(`确认删除标签"${tag.propertyName}"吗?`, "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        return deleteByPropertyId(this.customerId, tag.propertyId);
+      }).then(() => {
+        this.$message.success("删除成功");
+        this.loadTags();
+        this.$emit("tag-change");
+      }).catch(() => {});
+    },
+    handlePropertyChange(propertyId) {
+      const template = this.propertyTemplateList.find(item => item.id === propertyId);
+      if (template) {
+        this.form.propertyName = template.name;
+        this.form.propertyValueType = template.valueType;
+        this.form.tradeType = template.tradeType;
+        this.currentValueType = template.valueType;
+      }
+    },
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.customerId = this.customerId;
+          const requestData = {
+            customerId: this.customerId,
+            propertyId: this.form.propertyId,
+            propertyName: this.form.propertyName,
+            propertyValue: Array.isArray(this.form.propertyValue) ? this.form.propertyValue.join(',') : this.form.propertyValue,
+            propertyValueType: this.form.propertyValueType,
+            tradeType: this.form.tradeType,
+            intention: this.form.intention,
+            likeRatio: this.form.likeRatio,
+            remark: this.form.remark
+          };
+          
+          addOrUpdate(requestData).then(response => {
+            if (response.code === 200) {
+              this.$message.success("保存成功");
+              this.dialogVisible = false;
+              this.loadTags();
+              this.$emit("tag-change");
+            }
+          });
+        }
+      });
+    },
+    reset() {
+      this.form = {
+        customerId: this.customerId,
+        propertyId: null,
+        propertyName: null,
+        propertyValue: null,
+        propertyValueType: null,
+        tradeType: null,
+        intention: null,
+        likeRatio: null,
+        remark: null
+      };
+      this.currentValueType = "text";
+      this.isEdit = false;
+      if (this.$refs.form) {
+        this.$refs.form.clearValidate();
+      }
+    },
+    getValueTypeText(valueType) {
+      const typeMap = {
+        text: "文本",
+        number: "数字",
+        date: "日期",
+        select: "单选",
+        multiSelect: "多选"
+      };
+      return typeMap[valueType] || valueType;
+    },
+    getIntentionText(intention) {
+      const intentionMap = {
+        high: "高意向",
+        medium: "中意向",
+        low: "低意向",
+        none: "无意向"
+      };
+      return intentionMap[intention] || intention;
+    },
+    getIntentionTagType(intention) {
+      const typeMap = {
+        high: "success",
+        medium: "warning",
+        low: "info",
+        none: "danger"
+      };
+      return typeMap[intention] || "";
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.info-section {
+  background: #fff;
+  border-radius: 8px;
+  margin-bottom: 16px;
+  overflow: hidden;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+
+  .section-header {
+    padding: 16px 20px;
+    border-bottom: 1px solid #ebeef5;
+    background: #fafbfc;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+
+    .section-title {
+      font-size: 15px;
+      font-weight: 600;
+      color: #303133;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+
+      i {
+        color: #409eff;
+      }
+    }
+
+    .header-actions {
+      display: flex;
+      align-items: center;
+    }
+  }
+
+  .section-content {
+    padding: 20px;
+    min-height: 80px;
+
+    .empty-tips {
+      text-align: center;
+      color: #909399;
+      padding: 20px 0;
+      font-size: 14px;
+    }
+
+    .tag-col {
+      margin-bottom: 0;
+    }
+  }
+}
+
+.info-item {
+  margin-bottom: 16px;
+
+  .info-label {
+    display: block;
+    font-size: 12px;
+    color: #909399;
+    margin-bottom: 6px;
+    display: flex;
+    align-items: center;
+  }
+
+  .info-value {
+    font-size: 14px;
+    color: #303133;
+    display: flex;
+    align-items: center;
+
+    .no-value {
+      color: #c0c4cc;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+    }
+  }
+
+  .tag-extra-info {
+    margin-top: 6px;
+    display: flex;
+    align-items: center;
+    gap: 8px;
+  }
+}
+</style>

+ 721 - 463
src/views/crm/components/customerDetails.vue

@@ -1,210 +1,332 @@
 <template>
-    <div class="contents" v-if="item!=null">
-        <div class="customer-title"  >
-            <div class="customer-name">
-                {{ showDuplicate?item.customerName+"[从]":item.customerName}}
-                 <el-button size="mini"  v-if="showDuplicate"  v-hasPermi="['crm:customer:lookDuplicate']"  @click=" getDetails" >主客户</el-button>
+    <div class="customer-detail-container" v-if="item!=null">
+        <!-- 顶部客户信息卡片 -->
+        <div class="customer-header-card">
+            <div class="customer-avatar">
+                <el-avatar :size="64" icon="el-icon-user-solid"></el-avatar>
+            </div>
+            <div class="customer-info">
+                <div class="customer-main-info">
+                    <h2 class="customer-name-title">
+                        {{ showDuplicate ? item.customerName + '[从]' : item.customerName }}
+                        <el-tag v-if="item.status" :type="getStatusType(item.status)" size="medium"
+                                style="margin-left: 12px;"
+                        >
+                            {{ getStatusText(item.status) }}
+                        </el-tag>
+                    </h2>
+                    <div class="customer-meta">
+                        <span class="meta-item">
+                            <i class="el-icon-phone"></i>
+                            {{ item.mobile || '未填写' }}
+                            <el-button type="text" v-if="isReceive" size="mini"
+                                       @click="callNumber(item.customerId,null,null,null)" icon="el-icon-phone-outline"
+                            >拨打</el-button>
+                            <el-button type="text" v-if="isReceive" size="mini" @click="handleSms(item.mobile)"
+                                       icon="el-icon-message"
+                            >短信</el-button>
+                        </span>
+                        <span class="meta-item">
+                            <i class="el-icon-location"></i>
+                            {{ item.address || '未填写' }}
+                        </span>
+                        <span class="meta-item">
+                            <i class="el-icon-time"></i>
+                            创建于 {{ item.createTime }}
+                        </span>
+                    </div>
+                </div>
+                <div class="customer-actions">
+                    <el-button type="primary" size="small" icon="el-icon-edit" v-hasPermi="['crm:customer:edit']"
+                               @click="handleEdit()"
+                    >编辑客户
+                    </el-button>
+                    <el-button type="warning" size="small" icon="el-icon-price-tag" v-hasPermi="['crm:customer:addTag']"
+                               @click="handleAddTag()"
+                    >打标签
+                    </el-button>
+                    <el-button type="info" size="small" icon="el-icon-document" v-hasPermi="['crm:customer:addRemark']"
+                               @click="handleAddRemark()"
+                    >备注
+                    </el-button>
+                    <el-button size="small" v-if="showDuplicate" v-hasPermi="['crm:customer:lookDuplicate']"
+                               @click="getDetails"
+                    >
+                        主客户
+                    </el-button>
+                </div>
+            </div>
+        </div>
+
+        <!-- 标签展示区 -->
+        <div class="customer-tags-section" v-if="item && item.tags">
+            <span class="tags-label">客户标签:</span>
+            <el-tag v-for="tag in item.tags.split(',')" :key="tag" size="small" effect="plain"
+                    style="margin-right: 8px;"
+            >
+                {{ tag }}
+            </el-tag>
+        </div>
+
+        <!-- 信息分组展示 -->
+        <div class="info-sections">
+            <!-- 基本信息 -->
+            <div class="info-section">
+                <div class="section-header">
+                    <span class="section-title"><i class="el-icon-user"></i> 基本信息</span>
+                </div>
+                <div class="section-content">
+                    <el-row :gutter="24">
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">客户编号</span>
+                                <span class="info-value">{{ item.customerCode || '-' }}</span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">客户名称</span>
+                                <span class="info-value">{{ item.customerName || '-' }}</span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">性别</span>
+                                <span class="info-value">
+                                    <el-tag v-for="dict in sexOptions" :key="dict.dictValue"
+                                            v-if="item.sex==dict.dictValue" size="mini"
+                                    >{{ dict.dictLabel }}</el-tag>
+                                    <span v-if="!item.sex">-</span>
+                                </span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">微信号</span>
+                                <span class="info-value">{{ item.weixin || '-' }}</span>
+                            </div>
+                        </el-col>
+                    </el-row>
+                    <el-row :gutter="24">
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">客户来源</span>
+                                <span class="info-value">
+                                    <el-tag v-for="dict in sourceOptions" :key="dict.dictValue"
+                                            v-if="item.source==dict.dictValue" size="mini" type="info"
+                                    >{{ dict.dictLabel }}</el-tag>
+                                    <span v-if="!item.source">-</span>
+                                </span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">客户类型</span>
+                                <span class="info-value">
+                                    <el-tag v-for="dict in typeOptions" :key="dict.dictValue"
+                                            v-if="item.customerType==dict.dictValue" size="mini" type="warning"
+                                    >{{ dict.dictLabel }}</el-tag>
+                                    <span v-if="!item.customerType">-</span>
+                                </span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">最后一次跟进</span>
+                                <span class="info-value">{{ item.visitTime || '-' }}</span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">入公海时间</span>
+                                <span class="info-value">{{ item.poolTime || '-' }}</span>
+                            </div>
+                        </el-col>
+                    </el-row>
+                </div>
+            </div>
+
+            <!-- 购买信息 -->
+            <div class="info-section">
+                <div class="section-header">
+                    <span class="section-title"><i class="el-icon-shopping-cart-2"></i> 购买信息</span>
+                </div>
+                <div class="section-content">
+                    <el-row :gutter="24">
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">购买渠道</span>
+                                <span class="info-value">{{ item.platformName || '-' }}</span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">购买商品</span>
+                                <span class="info-value">{{ item.goodsName || '-' }} {{
+                                        item.goodsSpecification || ''
+                                    }}</span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">购买店铺</span>
+                                <span class="info-value">{{ item.shopName || '-' }}</span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">消费金额</span>
+                                <span class="info-value highlight">¥{{ item.payMoney || '0' }}</span>
+                            </div>
+                        </el-col>
+                    </el-row>
+                    <el-row :gutter="24">
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">购买次数</span>
+                                <span class="info-value">{{ item.buyCount || '0' }} 次</span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">来源渠道编码</span>
+                                <span class="info-value">{{ item.sourceCode || '-' }}</span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">推荐编码</span>
+                                <span class="info-value">{{ item.pushCode || '-' }}</span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">推荐时间</span>
+                                <span class="info-value">{{ item.pushTime || '-' }}</span>
+                            </div>
+                        </el-col>
+                    </el-row>
+                </div>
+            </div>
+
+            <!-- 进线信息 -->
+            <div class="info-section">
+                <div class="section-header">
+                    <span class="section-title"><i class="el-icon-connection"></i> 进线信息</span>
+                </div>
+                <div class="section-content">
+                    <el-row :gutter="24">
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">进线日期</span>
+                                <span class="info-value">{{ item.registerDate || '-' }}</span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">进线方式</span>
+                                <span class="info-value">{{ item.registerType || '-' }}</span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">进线填写时间</span>
+                                <span class="info-value">{{ item.registerSubmitTime || '-' }}</span>
+                            </div>
+                        </el-col>
+                        <el-col :span="6">
+                            <div class="info-item">
+                                <span class="info-label">进线链接</span>
+                                <span class="info-value text-ellipsis" :title="item.registerLinkUrl">{{
+                                        item.registerLinkUrl || '-'
+                                    }}</span>
+                            </div>
+                        </el-col>
+                    </el-row>
+                    <el-row :gutter="24">
+                        <el-col :span="24">
+                            <div class="info-item">
+                                <span class="info-label">进线客户详情</span>
+                                <span class="info-value">{{ item.registerDesc || '-' }}</span>
+                            </div>
+                        </el-col>
+                    </el-row>
+                </div>
+            </div>
+
+            <!-- 扩展信息 -->
+            <div class="info-section" v-if="exts && exts.length > 0">
+                <div class="section-header">
+                    <span class="section-title"><i class="el-icon-tickets"></i> 扩展信息</span>
+                </div>
+                <div class="section-content">
+                    <el-row :gutter="24">
+                        <el-col :span="6" v-for="ext in exts" :key="ext.extId">
+                            <div class="info-item">
+                                <span class="info-label">{{ ext.name }}</span>
+                                <span class="info-value">{{ ext.value || '-' }}</span>
+                            </div>
+                        </el-col>
+                    </el-row>
+                </div>
+            </div>
+
+            <!-- 备注信息 -->
+            <div class="info-section" v-if="item.remark">
+                <div class="section-header">
+                    <span class="section-title"><i class="el-icon-document"></i> 备注信息</span>
+                </div>
+                <div class="section-content">
+                    <div class="remark-content">{{ item.remark }}</div>
+                </div>
             </div>
-            <div>
-                <el-button size="mini"  v-hasPermi="['crm:customer:edit']"  @click=" handleEdit()">修改客户</el-button>
-                <el-button size="mini"  v-hasPermi="['crm:customer:addTag']"  @click=" handleAddTag()" >打标签</el-button>
-                <el-button size="mini"  v-hasPermi="['crm:customer:addRemark']"  @click=" handleAddRemark()" >修改备注</el-button>
 
+            <!-- AI标签 -->
+            <div class="info-section">
+                <div class="ai-tag-wrapper" v-if="item && item.customerId">
+                    <ai-tag-panel ref="aiTagPanel" :customer-id="item.customerId" @tag-change="handleTagChange"
+                    ></ai-tag-panel>
+                </div>
             </div>
         </div>
-        <el-descriptions title="" :column="3" border>
-            <el-descriptions-item label="客户编号"  >
-                <span v-if="item!=null">{{item.customerCode}}</span>
-            </el-descriptions-item>
-            <el-descriptions-item label="客户名称" >
-                <span v-if="item!=null">{{item.customerName}}</span>
-            </el-descriptions-item>
-            <el-descriptions-item label="手机号" >
-                <span v-if="item!=null">{{item.mobile}}</span>
-                 <el-button type="text"  v-if="isReceive" size="mini" @click="callNumber(item.customerId,null,null,null)">拨号</el-button>
-                 <el-button type="text" v-if="isReceive" size="mini" @click="handleSms(item.mobile)">短信</el-button>
-                 <el-button icon="el-icon-search" size="mini" @click="handleMobile" style="margin-left: 20px;" circle v-hasPermi="['crm:customer:query2']"></el-button>
-            </el-descriptions-item>
-            <el-descriptions-item label="性别" >
-                <span v-if="item!=null">
-                    <el-tag  v-for="(dict, index) in sexOptions"    v-if="item.sex==dict.dictValue">{{dict.dictLabel}}</el-tag>
-                </span>
-            </el-descriptions-item>
-            <el-descriptions-item label="微信号" >
-                <span v-if="item!=null">
-                    {{item.weixin}}
-                </span>
-            </el-descriptions-item>
-            <el-descriptions-item label="所在地">
-                <span v-if="item!=null">
-                    {{item.address}}
-                </span>
-            </el-descriptions-item>
-            <el-descriptions-item label="客户来源" >
-                <span v-if="item!=null">
-                    <el-tag  v-for="(dict, index) in sourceOptions"    v-if="item.source==dict.dictValue">{{dict.dictLabel}}</el-tag>
-                </span>
-            </el-descriptions-item>
-            <el-descriptions-item label="客户类型" >
-                <span v-if="item!=null">
-                    <el-tag  v-for="(dict, index) in typeOptions"    v-if="item.customerType==dict.dictValue">{{dict.dictLabel}}</el-tag>
-                </span>
-            </el-descriptions-item>
-            <el-descriptions-item label="客户状态" >
-                <span v-if="item!=null">
-                    <el-tag  v-for="(dict, index) in statusOptions"    v-if="item.status==dict.dictValue">{{dict.dictLabel}}</el-tag>
-                </span>
-            </el-descriptions-item>
-            <el-descriptions-item label="创建时间" >
-                <span v-if="item!=null">
-                    {{item.createTime}}
-                </span>
-            </el-descriptions-item>
-            <el-descriptions-item label="最后一次跟进时间" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.visitTime}}
-                </span>
-            </el-descriptions-item>
-            <el-descriptions-item label="入公海时间" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.poolTime}}
-                </span>
-            </el-descriptions-item>
-
-            <el-descriptions-item label="标签" label-class-name="my-label">
-                <span v-if="item!=null && item.tags != null">
-                    <el-tag v-for="tag in item.tags.split(',')" size="mini">{{ tag }}</el-tag>
-                </span>
-                <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
-            </el-descriptions-item>
-
-            <el-descriptions-item label="进线日期" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.registerDate}}
-                </span>
-                <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
-            </el-descriptions-item>
-            <el-descriptions-item label="进线链接" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.registerLinkUrl}}
-                </span>
-                <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
-            </el-descriptions-item>
-            <el-descriptions-item label="进线客户详情" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.registerDesc}}
-                </span>
-                <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
-            </el-descriptions-item>
-            <el-descriptions-item label="进线客户填写时间" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.registerSubmitTime}}
-                </span>
-                <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
-            </el-descriptions-item>
-            <el-descriptions-item label="进线方式" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.registerType}}
-                </span>
-                <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
-            </el-descriptions-item>
-          <el-descriptions-item label="购买渠道" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.platformName || ''}}
-                </span>
-
-          </el-descriptions-item>
-          <el-descriptions-item label="购买商品" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.goodsName || ''}} - {{item.goodsSpecification || ''}}
-                </span>
-
-          </el-descriptions-item>
-          <el-descriptions-item label="购买店铺" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.shopName || ''}}
-                </span>
-
-          </el-descriptions-item>
-            <el-descriptions-item label="消费金额" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.payMoney}}
-                </span>
-                <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
-            </el-descriptions-item>
-            <el-descriptions-item label="购买次数" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.buyCount}}
-                </span>
-                <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
-            </el-descriptions-item>
-            <el-descriptions-item label="来源渠道编码" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.sourceCode}}
-                </span>
-                <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
-            </el-descriptions-item>
-            <el-descriptions-item label="推荐编码" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.pushCode}}
-                </span>
-                <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
-            </el-descriptions-item>
-            <el-descriptions-item label="推荐时间" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.pushTime}}
-                </span>
-                <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
-            </el-descriptions-item>
-
-            <el-descriptions-item :label="ext.name" v-for="ext in exts" label-class-name="my-label">
-                <span >
-                    {{ext.value}}
-                </span>
-            </el-descriptions-item>
-            <el-descriptions-item label="备注" label-class-name="my-label">
-                <span v-if="item!=null">
-                    {{item.remark}}
-                </span>
-                <!-- <el-button size="mini" icon="el-icon-edit"></el-button> -->
-            </el-descriptions-item>
-
-        </el-descriptions>
-
-        <el-tabs style="margin-top:15px;"  z-index = "99" type="border-card" v-model="activeName" @tab-click="handleClick">
-            <el-tab-pane label="跟进记录" name="visit">
-                <customer-visit-list ref="visit"></customer-visit-list>
-            </el-tab-pane>
-            <el-tab-pane label="联系人" name="contacts">
-                <customer-contacts ref="contacts"></customer-contacts>
-            </el-tab-pane>
-            <el-tab-pane label="订单记录" name="storeOrder">
-                <customer-store-order-list ref="storeOrder"></customer-store-order-list>
-            </el-tab-pane>
-
-            <el-tab-pane label="通话记录" name="voiceLogs">
-                <customer-voice-logs-list ref="voiceLogs"></customer-voice-logs-list>
-            </el-tab-pane>
-            <el-tab-pane label="短信记录" name="smsLogs">
-                <customer-sms-logs-list ref="smsLogs"></customer-sms-logs-list>
-            </el-tab-pane>
-            <el-tab-pane label="客户日志" name="logs">
-                <customer-logs-list ref="logs"></customer-logs-list>
-            </el-tab-pane>
-            <el-tab-pane label="历史订单" name="hisOrder">
-                <customer-his-order-list ref="hisOrder"></customer-his-order-list>
-            </el-tab-pane>
-            <el-tab-pane label="AI通话记录" name="aiVoiceLogs">
-                <ai-call-voice-log ref="aiVoiceRef"></ai-call-voice-log>
-            </el-tab-pane>
-             <el-tab-pane label="AI加微记录" name="aiAddWxLogs">
-                <ai-add-wx-log ref="aiAddWxRef"></ai-add-wx-log>
-            </el-tab-pane>
-             <el-tab-pane label="AI短信记录" name="aiSendMsgLogs">
-                <ai-send-msg-log ref="aiSendMsgRef"></ai-send-msg-log>
-            </el-tab-pane>
-        </el-tabs>
 
+        <!-- Tab 和 AI 标签区域 -->
+        <div class="content-area">
+            <el-tabs v-model="activeName" type="card" @tab-click="handleClick" class="customer-tabs">
+                <el-tab-pane label="跟进记录" name="visit">
+                    <customer-visit-list ref="visit"></customer-visit-list>
+                </el-tab-pane>
+                <el-tab-pane label="联系人" name="contacts">
+                    <customer-contacts ref="contacts"></customer-contacts>
+                </el-tab-pane>
+                <el-tab-pane label="订单记录" name="storeOrder">
+                    <customer-store-order-list ref="storeOrder"></customer-store-order-list>
+                </el-tab-pane>
+                <el-tab-pane label="通话记录" name="voiceLogs">
+                    <customer-voice-logs-list ref="voiceLogs"></customer-voice-logs-list>
+                </el-tab-pane>
+                <el-tab-pane label="短信记录" name="smsLogs">
+                    <customer-sms-logs-list ref="smsLogs"></customer-sms-logs-list>
+                </el-tab-pane>
+                <el-tab-pane label="客户日志" name="logs">
+                    <customer-logs-list ref="logs"></customer-logs-list>
+                </el-tab-pane>
+                <el-tab-pane label="历史订单" name="hisOrder">
+                    <customer-his-order-list ref="hisOrder"></customer-his-order-list>
+                </el-tab-pane>
+                <el-tab-pane label="AI 通话" name="aiVoiceLogs">
+                    <ai-call-voice-log ref="aiVoiceRef"></ai-call-voice-log>
+                </el-tab-pane>
+                <el-tab-pane label="AI 加微" name="aiAddWxLogs">
+                    <ai-add-wx-log ref="aiAddWxRef"></ai-add-wx-log>
+                </el-tab-pane>
+                <el-tab-pane label="AI 短信" name="aiSendMsgLogs">
+                    <ai-send-msg-log ref="aiSendMsgRef"></ai-send-msg-log>
+                </el-tab-pane>
+            </el-tabs>
+        </div>
+
+        <!-- 弹窗 -->
         <el-dialog :title="addTag.title" :visible.sync="addTag.open" width="600px" append-to-body>
             <add-tag ref="tag" @close="closeTag()"></add-tag>
         </el-dialog>
@@ -214,290 +336,426 @@
         <el-dialog :title="addSms.title" :visible.sync="addSms.open" width="800px" append-to-body>
             <add-sms ref="sms" @close="closeSms()"></add-sms>
         </el-dialog>
-
         <el-dialog :title="customer.title" :visible.sync="customer.open" width="1000px" append-to-body>
             <add-or-edit-customer ref="customer" @close="closeCustomer()"></add-or-edit-customer>
         </el-dialog>
-
-        <!-- <el-dialog :title="duplicate.title" :visible.sync="duplicate.open" width="800px" append-to-body>
-            <duplicate-customer ref="duplicateCustomer" @close="closeDuplicate()"></duplicate-customer>
-        </el-dialog> -->
-
-       <el-drawer size="75%" :modal="false" :title="duplicate.title" :visible.sync="duplicate.open">
-            <duplicate-customer  ref="duplicateCustomer" />
+        <el-drawer size="75%" :modal="false" :title="duplicate.title" :visible.sync="duplicate.open">
+            <duplicate-customer ref="duplicateCustomer"/>
         </el-drawer>
-
     </div>
 </template>
 
 <script>
-    import { listCustomerExt } from "@/api/crm/customerExt";
-    import customerVisitList from '../components/customerVisitList.vue';
-    import customerLogsList from '../components/customerLogsList.vue';
-    import customerSmsLogsList from '../components/customerSmsLogsList.vue';
-    import customerVoiceLogsList from '../components/customerVoiceLogsList.vue';
-    import customerStoreOrderList from '../components/customerStoreOrderList.vue';
-    import duplicateCustomer from '../components/duplicateCustomer.vue';
-    import customerContacts from './customerContacts.vue';
-    import customerHisOrderList from '../components/customerHisOrderList.vue';
-    import aiCallVoiceLog from './aiCallVoiceLog';
-    import aiAddWxLog from './aiAddWxLog';
-    import aiSendMsgLog from './aiSendMsgLog';
-    import { getCustomerDetails1,updateCustomer,getCustomer1 } from "@/api/crm/customer";
-    import addTag from './addTag.vue';
-    import addRemark from './addRemark.vue';
-    import addSms from './addSms.vue';
-    import addOrEditCustomer from '../components/addOrEditCustomer.vue';
-    export default {
-        name: "customer",
-        components: {customerHisOrderList,addOrEditCustomer,addSms,addTag,addRemark, customerContacts,customerVisitList,customerLogsList,
-        customerVoiceLogsList,customerStoreOrderList,customerSmsLogsList,duplicateCustomer,aiCallVoiceLog,aiAddWxLog,aiSendMsgLog },
-        data() {
-            return {
-                calleesId:null,
-                roboticId:null,
-                customer:{
-                    open:false,
-                    title:"修改客户"
-                },
-                isReceive:false,
-                tagId:null,
-                tagsOptions:[],
-                addSms:{
-                    open:false,
-                    title:"发短信"
-                },
-                addTag:{
-                    open:false,
-                    title:"打标签"
-                },
-                addRemark:{
-                    open:false,
-                    title:"客户备注"
-                },
-                duplicate:{
-                    open:false,
-                    title:"客户详情"
-                },
-                customerId:null,
-                 // 弹出层标题
-                title: "",
-                // 是否显示弹出层
-                open: false,
-                cityIds:[],
-                citys:[],
-                tags:[],
-                inputVisible: false,
-                inputValue: '',
-                receiveOptions:[],
-                statusOptions:[],
-                typeOptions:[],
-                sourceOptions:[],
-                sexOptions:[],
-                customerExts:[],
-                activeName:"",
-                item:null,
-                showDuplicate:false,
-                dCustomerId:null,
-
-            };
-        },
-        created() {
-            this.getDicts("crm_customer_source").then((response) => {
-                this.sourceOptions = response.data;
-            });
-            this.getDicts("sys_sex").then((response) => {
-                this.sexOptions = response.data;
-            });
-            this.getDicts("crm_customer_tag").then((response) => {
-                this.tagsOptions = response.data;
-            });
-            this.getDicts("crm_customer_status").then((response) => {
-                this.statusOptions = response.data;
-            });
-            this.getDicts("crm_customer_type").then((response) => {
-                this.typeOptions = response.data;
-            });
-            this.getDicts("crm_customer_is_receive").then((response) => {
-                this.receiveOptions = response.data;
-            });
+import { listCustomerExt } from '@/api/crm/customerExt'
+import customerVisitList from '../components/customerVisitList.vue'
+import customerLogsList from '../components/customerLogsList.vue'
+import customerSmsLogsList from '../components/customerSmsLogsList.vue'
+import customerVoiceLogsList from '../components/customerVoiceLogsList.vue'
+import customerStoreOrderList from '../components/customerStoreOrderList.vue'
+import duplicateCustomer from '../components/duplicateCustomer.vue'
+import customerContacts from './customerContacts.vue'
+import customerHisOrderList from '../components/customerHisOrderList.vue'
+import aiCallVoiceLog from './aiCallVoiceLog'
+import aiAddWxLog from './aiAddWxLog'
+import aiSendMsgLog from './aiSendMsgLog'
+import AiTagPanel from './AiTagPanel.vue'
+import { getCustomerDetails1, updateCustomer, getCustomer1 } from '@/api/crm/customer'
+import addTag from './addTag.vue'
+import addRemark from './addRemark.vue'
+import addSms from './addSms.vue'
+import addOrEditCustomer from '../components/addOrEditCustomer.vue'
 
+export default {
+    name: 'customer',
+    components: {
+        customerHisOrderList,
+        addOrEditCustomer,
+        addSms,
+        addTag,
+        addRemark,
+        customerContacts,
+        customerVisitList,
+        customerLogsList,
+        customerVoiceLogsList,
+        customerStoreOrderList,
+        customerSmsLogsList,
+        duplicateCustomer,
+        aiCallVoiceLog,
+        aiAddWxLog,
+        aiSendMsgLog,
+        AiTagPanel
+    },
+    data() {
+        return {
+            calleesId: null,
+            roboticId: null,
+            customer: { open: false, title: '修改客户' },
+            isReceive: false,
+            tagId: null,
+            tagsOptions: [],
+            addSms: { open: false, title: '发短信' },
+            addTag: { open: false, title: '打标签' },
+            addRemark: { open: false, title: '客户备注' },
+            duplicate: { open: false, title: '客户详情' },
+            customerId: null,
+            title: '',
+            open: false,
+            cityIds: [],
+            citys: [],
+            tags: [],
+            inputVisible: false,
+            inputValue: '',
+            receiveOptions: [],
+            statusOptions: [],
+            typeOptions: [],
+            sourceOptions: [],
+            sexOptions: [],
+            customerExts: [],
+            activeName: '',
+            item: null,
+            showDuplicate: false,
+            dCustomerId: null
+        }
+    },
+    created() {
+        this.getDicts('crm_customer_source').then((response) => {
+            this.sourceOptions = response.data
+        })
+        this.getDicts('sys_sex').then((response) => {
+            this.sexOptions = response.data
+        })
+        this.getDicts('crm_customer_tag').then((response) => {
+            this.tagsOptions = response.data
+        })
+        this.getDicts('crm_customer_status').then((response) => {
+            this.statusOptions = response.data
+        })
+        this.getDicts('crm_customer_type').then((response) => {
+            this.typeOptions = response.data
+        })
+        this.getDicts('crm_customer_is_receive').then((response) => {
+            this.receiveOptions = response.data
+        })
+    },
+    methods: {
+        getStatusType(status) {
+            const statusMap = { '1': 'success', '2': 'warning', '3': 'danger', '4': 'info' }
+            return statusMap[status] || 'info'
         },
-        mounted(){
-
+        getStatusText(status) {
+            const item = this.statusOptions.find(d => d.dictValue === status)
+            return item ? item.dictLabel : status
+        },
+        handleMobile() {
+            const customerId = this.item.customerId
+            getCustomer1(customerId).then(response => {
+                this.item.mobile = response.mobile
+            })
+        },
+        handleEdit() {
+            this.customer.open = true
+            var that = this
+            setTimeout(() => {
+                that.$refs.customer.handleUpdate(that.customerId)
+            }, 200)
+        },
+        closeCustomer() {
+            this.customer.open = false
+            this.getDetails(this.customerId)
+        },
+        tagsChange(e) {
+            var item = this.tagsOptions.find(val => val.dictValue === e)
+            this.tags.push(item.dictLabel)
+            this.form.tags = this.tags.toString()
         },
-        methods: {
-            handleMobile(){
-                const customerId = this.item.customerId;
-                getCustomer1(customerId).then(response =>{
-                    this.item.mobile = response.mobile;
+        closeSms() {
+            this.addSms.open = false
+            this.getDetails(this.customerId)
+        },
+        handleSms(mobile) {
+            this.addSms.open = true
+            var that = this
+            setTimeout(() => {
+                that.$refs.sms.reset(this.item.customerId, mobile, 1)
+            }, 500)
+        },
+        closeRemark() {
+            this.addRemark.open = false
+            this.getDetails(this.customerId)
+        },
+        handleAddRemark() {
+            this.addRemark.open = true
+            var that = this
+            setTimeout(() => {
+                that.$refs.remark.reset(this.item)
+            }, 500)
+        },
+        closeTag() {
+            this.addTag.open = false
+            this.getDetails(this.customerId)
+        },
+        handleAddTag() {
+            this.addTag.open = true
+            var that = this
+            setTimeout(() => {
+                that.$refs.tag.reset(this.item)
+            }, 500)
+        },
+        handleClick(tab, event) {
+            if (tab.name == 'contacts') {
+                this.$refs.contacts.getData(this.item.customerId)
+            }
+            if (tab.name == 'visit') {
+                this.$refs.visit.getData(this.item.customerId, this.isReceive)
+            }
+            if (tab.name == 'logs') {
+                this.$refs.logs.getData(this.item.customerId)
+            }
+            if (tab.name == 'voiceLogs') {
+                this.$refs.voiceLogs.getData(this.item.customerId)
+            }
+            if (tab.name == 'storeOrder') {
+                this.$refs.storeOrder.getData(this.item.customerId)
+            }
+            if (tab.name == 'smsLogs') {
+                this.$refs.smsLogs.getData(this.item.customerId)
+            }
+            if (tab.name == 'hisOrder') {
+                this.$refs.hisOrder.getData(this.item.customerId)
+            }
+            if (tab.name == 'aiVoiceLogs') {
+                this.$refs.aiVoiceRef.getData(this.item.customerId, this.calleesId)
+            } else if (tab.name == 'aiAddWxLogs') {
+                this.$refs.aiAddWxRef.getData(this.item.customerId, this.roboticId)
+            } else if (tab.name == 'aiSendMsgLogs') {
+                this.$refs.aiSendMsgRef.getData(this.item.customerId, this.calleesId, this.roboticId)
+            }
+        },
+        getDetails(customerId, calleesId, roboticId) {
+            if (!!calleesId) {
+                this.calleesId = calleesId
+            }
+            if (!!roboticId) {
+                this.roboticId = roboticId
+            }
+            var data = { customerId: customerId }
+            this.customerId = customerId
+            var that = this
+            this.exts = []
+            listCustomerExt(data).then(response => {
+                this.customerExts = response.data
+                this.customerExts.forEach(element => {
+                    var data = { extId: element.extId, name: element.name, value: '' }
+                    this.exts.push(data)
                 })
-            },
-            handleEdit() {
-                this.customer.open = true;
-                var that=this;
-                setTimeout(() => {
-                    that.$refs.customer.handleUpdate(that.customerId);
-                }, 200);
-            },
-            closeCustomer(){
-                this.customer.open=false;
-                this.getDetails(this.customerId)
-            },
-            tagsChange(e){
-                var item=this.tagsOptions.find(val => val.dictValue === e);
-                console.log(item);
-                this.tags.push(item.dictLabel);
-                this.form.tags=this.tags.toString();
-            },
-            closeSms(){
-                this.addSms.open=false;
-                this.getDetails(this.customerId)
-            },
-            handleSms(mobile){
-                this.addSms.open=true;
-                var that=this;
-                setTimeout(() => {
-                    that.$refs.sms.reset(this.item.customerId,mobile,1);
-                }, 500);
-
-            },
-            closeRemark(){
-                this.addRemark.open=false;
-                this.getDetails(this.customerId)
-            },
-            handleAddRemark(){
-                this.addRemark.open=true;
-                var that=this;
-                setTimeout(() => {
-                    that.$refs.remark.reset(this.item);
-                }, 500);
-            },
-            closeTag(){
-                this.addTag.open=false;
-                this.getDetails(this.customerId)
-            },
-            handleAddTag(){
-                this.addTag.open=true;
-                var that=this;
-                setTimeout(() => {
-                    that.$refs.tag.reset(this.item);
-                }, 500);
-
-            },
-            handleClick(tab, event) {
-                if(tab.name=="contacts"){
-                    this.$refs.contacts.getData(this.item.customerId);
-                }
-                if(tab.name == "visit"){
-                    this.$refs.visit.getData(this.item.customerId,this.isReceive);
-                }
-                if(tab.name=="logs"){
-                    this.$refs.logs.getData(this.item.customerId);
+            })
+            getCustomerDetails1(data).then(response => {
+                this.item = response.customer
+                this.isReceive = response.isReceive
+                if (this.item.extJson != null) {
+                    var extList = JSON.parse(this.item.extJson)
+                    that.exts.forEach(item => {
+                        extList.forEach(element => {
+                            if (item.extId == element.extId) {
+                                item.value = element.value
+                            }
+                        })
+                    })
                 }
-                if(tab.name=="voiceLogs"){
-                    this.$refs.voiceLogs.getData(this.item.customerId);
-                }
-                if(tab.name=="storeOrder"){
-                    this.$refs.storeOrder.getData(this.item.customerId);
-                }
-                if(tab.name=="smsLogs"){
-                    this.$refs.smsLogs.getData(this.item.customerId);
-                }
-                if(tab.name=="hisOrder"){
-                    this.$refs.hisOrder.getData(this.item.customerId);
-                }
-                if(tab.name=="aiVoiceLogs"){
-                    console.log(this.item.customerId);
-                    this.$refs.aiVoiceRef.getData(this.item.customerId,this.calleesId);
-                } else if(tab.name=="aiAddWxLogs"){
-                    console.log(this.item.customerId);
-                    this.$refs.aiAddWxRef.getData(this.item.customerId,this.roboticId);
-                } else if(tab.name=="aiSendMsgLogs"){
-                    console.log(this.item.customerId);
-                    this.$refs.aiSendMsgRef.getData(this.item.customerId,this.calleesId,this.roboticId);
-                }
-            },
-            getDetails(customerId,calleesId,roboticId) {
-                if(!!calleesId){
-                    this.calleesId = calleesId;
-                    console.log(this.calleesId);
-                }
-                if(!!roboticId){
-                    this.roboticId = roboticId;
-                    console.log(this.roboticId);
-                }
-                var data={customerId:customerId}
-                this.customerId=customerId;
-                var that=this;
-                this.exts=[];
-                listCustomerExt(data).then(response => {
-                    this.customerExts = response.data;
-                    this.customerExts.forEach(element => {
-                        var data={extId:element.extId,name:element.name,value:""};
-                        this.exts.push(data)
-                    });
-                });
-                getCustomerDetails1(data).then(response => {
-                    this.item = response.customer;
-                    this.isReceive=response.isReceive;
-                    if(this.item.extJson!=null){
-                        var extList=JSON.parse(this.item.extJson);
-                        that.exts.forEach(item => {
-                            extList.forEach(element => {
-                                if(item.extId==element.extId){
-                                    item.value=element.value
-                                }
-                            });
-
-                        });
-                    }
-                    this.activeName="visit"
-                    setTimeout(() => {
-                        that.$refs.visit.getData(customerId);
-                    }, 500);
-                });
-            },
-            initDuplicate(isDuplicate,dCustomerId){
-
-                this.showDuplicate=isDuplicate;
-                this.dCustomerId=dCustomerId;
-            },
-            handleDuplicate(){
-                this.duplicate.open=true;
-                var that=this;
-
+                this.activeName = 'visit'
                 setTimeout(() => {
-                    that.$refs.duplicateCustomer.getDetails(that.dCustomerId);
-                }, 200);
-            },
-            closeDuplicate(){
-                this.duplicate.open=false;
-                this.getDetails(this.customerId)
-            },
+                    that.$refs.visit.getData(customerId)
+                }, 500)
+            })
+        },
+        initDuplicate(isDuplicate, dCustomerId) {
+            this.showDuplicate = isDuplicate
+            this.dCustomerId = dCustomerId
+        },
+        handleDuplicate() {
+            this.duplicate.open = true
+            var that = this
+            setTimeout(() => {
+                that.$refs.duplicateCustomer.getDetails(that.dCustomerId)
+            }, 200)
+        },
+        closeDuplicate() {
+            this.duplicate.open = false
+            this.getDetails(this.customerId)
+        },
+        handleTagChange() {
+            console.log('AI 标签发生变化')
         }
-    };
+    }
+}
 </script>
+
 <style lang="scss" scoped>
-.contents{
-    height: 100%;
-    background-color: #fff;
-    padding: 0px 20px;
+.customer-detail-container {
+    background-color: #f5f7fa;
+    min-height: 100%;
+    padding: 20px;
+}
+
+.customer-header-card {
+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    border-radius: 12px;
+    padding: 24px;
+    display: flex;
+    align-items: center;
+    margin-bottom: 20px;
+    box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
+
+    .customer-avatar {
+        margin-right: 20px;
+    }
+
+    .customer-info {
+        flex: 1;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+    }
+
+    .customer-main-info {
+        .customer-name-title {
+            color: #fff;
+            font-size: 24px;
+            margin: 0 0 12px 0;
+            display: flex;
+            align-items: center;
+        }
+
+        .customer-meta {
+            display: flex;
+            gap: 24px;
 
+            .meta-item {
+                color: rgba(255, 255, 255, 0.9);
+                font-size: 14px;
+                display: flex;
+                align-items: center;
+                gap: 6px;
+
+                i {
+                    font-size: 16px;
+                }
+
+                .el-button {
+                    color: rgba(255, 255, 255, 0.9);
+                    padding: 0 8px;
+
+                    &:hover {
+                        color: #fff;
+                    }
+                }
+            }
+        }
+    }
+
+    .customer-actions {
+        display: flex;
+        gap: 12px;
+    }
 }
-.customer-title{
-    margin-bottom: 15px;
+
+.customer-tags-section {
+    background: #fff;
+    border-radius: 8px;
+    padding: 16px 20px;
+    margin-bottom: 20px;
     display: flex;
     align-items: center;
-    justify-content: space-between;
-    .customer-name{
-        font-size: 28px;
+
+    .tags-label {
+        font-weight: 500;
+        color: #606266;
+        margin-right: 12px;
     }
 }
-</style>
-<style>
-  .el-descriptions-item__label.is-bordered-label{
-    font-weight: normal;
-  }
 
+.info-sections {
+    margin-bottom: 20px;
+}
+
+.info-section {
+    background: #fff;
+    border-radius: 8px;
+    margin-bottom: 16px;
+    overflow: hidden;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+
+    .section-header {
+        padding: 16px 20px;
+        border-bottom: 1px solid #ebeef5;
+        background: #fafbfc;
+
+        .section-title {
+            font-size: 15px;
+            font-weight: 600;
+            color: #303133;
+            display: flex;
+            align-items: center;
+            gap: 8px;
+
+            i {
+                color: #409eff;
+            }
+        }
+    }
+
+    .section-content {
+        padding: 20px;
+    }
+}
+
+.info-item {
+    margin-bottom: 16px;
+
+    .info-label {
+        display: block;
+        font-size: 12px;
+        color: #909399;
+        margin-bottom: 6px;
+    }
+
+    .info-value {
+        font-size: 14px;
+        color: #303133;
+
+        &.highlight {
+            color: #f56c6c;
+            font-weight: 600;
+            font-size: 16px;
+        }
+
+        &.text-ellipsis {
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+        }
+    }
+}
+
+.remark-content {
+    background: #fafbfc;
+    padding: 16px;
+    border-radius: 6px;
+    color: #606266;
+    line-height: 1.6;
+}
+
+.content-area {
+    .customer-tabs {
+        background: #fff;
+        border-radius: 8px;
+        padding: 16px;
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+    }
+
+    .ai-tag-wrapper {
+        position: sticky;
+        top: 20px;
+    }
+}
 </style>