Browse Source

style: 数据画像界面优化与配色统一

- 基本信息:主体卡 + 字段网格重排,标签/值分层,长文本换行,响应式 4/3/2/1 列
- 对象列表:侧栏加宽,搜索框带图标,列表项改为姓名 + 脱敏证件号两级信息与选中态
- 图表:常联系/常交易 TOP10 柱状图与交易趋势统一纯色,移除 ECharts 渐变与暖橙配色
- 全页去渐变:tooltip、亲密度徽标、对象编辑/分组弹窗背景改纯色
- 弹窗按钮统一 32px,主按钮统一 #2A50EC;亲密度配置「刷新配置」保持小号 24px
- 右侧快捷导航还原为悬浮样式;区块右上操作与「查看更多」改为文字按钮 #2A50EC
- 左侧「新增对象」/选中边框/选中头像/亲密度数值统一 #2A50EC,亲密度数字去底色改红字
cc 2 ngày trước cách đây
mục cha
commit
8948ecf850

+ 4 - 3
ai-electron/frontend/src/case/views/dm/components/IntimacyPanel.vue

@@ -1157,7 +1157,8 @@
       height: 42px;
       padding: 0 10px;
       border-radius: 12px;
-      background: linear-gradient(180deg, #1d4ed8 0%, #2563eb 100%);
+      // 纯色徽标:页面统一禁止渐变色
+      background: #1d4ed8;
       color: #fff;
       display: inline-flex;
       align-items: center;
@@ -1416,11 +1417,11 @@
       padding: 10px 14px;
       border: 1px solid #dbeafe;
       border-radius: 12px;
-      background: linear-gradient(180deg, #f8fbff 0%, #eff6ff 100%);
+      background: #f8fbff;
 
       &.is-error {
         border-color: #fecaca;
-        background: linear-gradient(180deg, #fff7f7 0%, #fef2f2 100%);
+        background: #fff7f7;
       }
     }
 

+ 535 - 51
ai-electron/frontend/src/case/views/dm/portrait.vue

@@ -9,7 +9,11 @@
               <div class="panel-heading__badge">{{ filteredPersonList.length }}</div>
             </div>
             <div class="search-box">
-              <Input v-model:value="personKeyword" placeholder="对象名称 / 证件号搜索" allow-clear />
+              <Input v-model:value="personKeyword" placeholder="搜索姓名 / 证件号" allow-clear>
+                <template #prefix>
+                  <SearchOutlined class="search-box__icon" />
+                </template>
+              </Input>
             </div>
             <div class="left-actions">
               <Button type="primary" block class="side-action-btn side-action-btn--primary" @click="openCreateModal"
@@ -39,10 +43,17 @@
                           class="person-avatar"
                           :src="getPersonPhoto(item.person)"
                           :alt="toPersonName(item.person)"
-                          :size="40"
+                          :size="36"
                         />
                       </div>
-                      <div class="person-name">{{ toPersonName(item.person) }}</div>
+                      <div class="person-info">
+                        <div class="person-name" :title="toPersonName(item.person)">{{
+                          toPersonName(item.person)
+                        }}</div>
+                        <div v-if="item.person.personCertNo" class="person-sub">
+                          {{ maskCertNo(item.person.personCertNo) }}
+                        </div>
+                      </div>
                     </div>
                   </Popover>
                 </div>
@@ -72,13 +83,16 @@
             </div>
             <div class="basic-content">
               <div class="basic-profile">
-                <PersonAvatar class="profile-avatar" :src="basicPhoto" :alt="basicName" :size="56" />
-                <div class="profile-name">{{ basicName }}</div>
+                <PersonAvatar class="profile-avatar" :src="basicPhoto" :alt="basicName" :size="72" />
+                <div class="profile-info">
+                  <div class="profile-name" :title="basicName">{{ basicName }}</div>
+                  <div class="profile-caption">画像主体</div>
+                </div>
               </div>
               <div class="info-grid">
                 <div v-for="item in basicInfo" :key="item.label" class="info-item">
-                  <span class="info-label">{{ item.label }}:</span>
-                  <span class="info-value">{{ item.value }}</span>
+                  <span class="info-label">{{ item.label }}</span>
+                  <span class="info-value" :title="item.value">{{ item.value }}</span>
                 </div>
               </div>
             </div>
@@ -885,7 +899,18 @@
 </template>
 
 <script lang="ts" setup name="ViewsDmPortrait">
-  import { computed, ref, onMounted, reactive, watch, nextTick, onBeforeUnmount, h } from 'vue';
+  import {
+    computed,
+    ref,
+    onMounted,
+    onActivated,
+    onDeactivated,
+    reactive,
+    watch,
+    nextTick,
+    onBeforeUnmount,
+    h,
+  } from 'vue';
   import { useRoute, useRouter } from 'vue-router';
   import {
     Button,
@@ -900,6 +925,7 @@
     Radio,
     Checkbox,
   } from 'ant-design-vue';
+  import { SearchOutlined } from '@ant-design/icons-vue';
   import componentSetting from '@/core/settings/componentSetting';
   import { useDesign } from '@/core/hooks/web/useDesign';
   import { useGlobSetting } from '@/core/hooks/setting';
@@ -3279,6 +3305,8 @@
   };
 
   onMounted(() => {
+    // 弹窗会被 teleport 到 body:用 body 标记把「弹窗按钮 32px」限定在本页
+    document.body.classList.add('case-portrait-active');
     fetchPersons();
     resetRightPanelData();
     void openGroupModalFromRoute();
@@ -3289,7 +3317,16 @@
     });
   });
 
+  onActivated(() => {
+    document.body.classList.add('case-portrait-active');
+  });
+
+  onDeactivated(() => {
+    document.body.classList.remove('case-portrait-active');
+  });
+
   onBeforeUnmount(() => {
+    document.body.classList.remove('case-portrait-active');
     revokeAvatarPreviewObjectUrl();
     navObserver?.disconnect();
     navObserver = null;
@@ -3678,7 +3715,7 @@
       ? `<div style="font-size:12px; line-height:18px; color:#94a3b8; margin-top:6px;">${subText}</div>`
       : '';
     return [
-      '<div style="padding:12px 14px; min-width:110px; background:linear-gradient(180deg, rgba(19,33,62,0.98) 0%, rgba(15,23,42,0.98) 100%); border:1px solid rgba(148,163,184,0.2); border-radius:12px; box-shadow:0 16px 34px rgba(2,6,23,0.3);">',
+      '<div style="padding:12px 14px; min-width:110px; background:#1f2937; border:1px solid rgba(148,163,184,0.25); border-radius:12px; box-shadow:0 16px 34px rgba(2,6,23,0.3);">',
       `<div style="font-size:14px; line-height:20px; color:#f8fafc; margin-bottom:8px;">${title}</div>`,
       '<div style="display:flex; align-items:center; gap:8px;">',
       `<span style="width:10px; height:10px; border-radius:50%; background:${color}; box-shadow:0 0 0 4px rgba(255,255,255,0.06); display:inline-block;"></span>`,
@@ -3740,7 +3777,7 @@
     if (!rowHtml) return '';
 
     return [
-      '<div style="padding:14px 16px; min-width:188px; background:linear-gradient(180deg, rgba(19,33,62,0.98) 0%, rgba(15,23,42,0.98) 100%); border:1px solid rgba(148,163,184,0.2); border-radius:14px; box-shadow:0 16px 34px rgba(2,6,23,0.32);">',
+      '<div style="padding:14px 16px; min-width:188px; background:#1f2937; border:1px solid rgba(148,163,184,0.25); border-radius:14px; box-shadow:0 16px 34px rgba(2,6,23,0.32);">',
       '<div style="display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:10px;">',
       `<span style="font-size:14px; line-height:20px; color:#f8fafc; font-weight:600;">${time}</span>`,
       `<span style="font-size:12px; line-height:18px; color:#8ac5ff; cursor:pointer;" onclick='window._handleTrendDetail(${JSON.stringify(time)})'>查看详情</span>`,
@@ -3880,7 +3917,8 @@
       name: `${item.name}:${Number(item.value || 0).toFixed(2)}%`,
       rawName: item.name,
       itemStyle: {
-        color: item.name === '主叫' ? '#4f7cff' : item.name === '被叫' ? '#39c7d9' : '#f6b659',
+        // 图表统一使用纯色,主叫取项目主蓝
+        color: item.name === '主叫' ? '#1677ff' : item.name === '被叫' ? '#39c7d9' : '#f6b659',
       },
     }));
 
@@ -3993,7 +4031,7 @@
           return buildTooltipCard({
             title: name,
             value: value.toLocaleString('zh-CN'),
-            color: '#62c4ff',
+            color: '#1677ff',
             subText: '联系次数',
           });
         },
@@ -4058,14 +4096,12 @@
           data: yData,
           itemStyle: {
             borderRadius: [6, 6, 0, 0],
-            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-              { offset: 0, color: '#4d7dff' },
-              { offset: 1, color: '#61c8ff' },
-            ]),
+            // 纯色柱:不使用任何渐变
+            color: '#1677ff',
           },
           emphasis: {
             itemStyle: {
-              color: '#4f8cff',
+              color: '#0958d9',
             },
           },
         },
@@ -4194,7 +4230,7 @@
           return buildTooltipCard({
             title: name,
             value: formatTradeTopValue(value),
-            color: '#7b8cff',
+            color: '#1677ff',
             subText: tradeTopQuery.dimension,
           });
         },
@@ -4252,14 +4288,12 @@
           data: yData,
           itemStyle: {
             borderRadius: [6, 6, 0, 0],
-            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-              { offset: 0, color: '#7b8cff' },
-              { offset: 1, color: '#58b1ff' },
-            ]),
+            // 纯色柱:常交易对象 TOP10 使用项目主蓝,禁止渐变
+            color: '#1677ff',
           },
           emphasis: {
             itemStyle: {
-              color: '#6978ff',
+              color: '#0958d9',
             },
           },
         },
@@ -4309,7 +4343,8 @@
         axisPointer: {
           type: 'line',
           lineStyle: {
-            color: 'rgba(255, 148, 104, 0.42)',
+            // 指示线跟随项目主蓝,替代原来的暖橙色
+            color: 'rgba(22, 119, 255, 0.36)',
             width: 1.5,
             type: 'dashed',
           },
@@ -4349,13 +4384,13 @@
         boundaryGap: false,
         data: trendLabels.value,
         nameTextStyle: {
-          color: '#7b8797',
+          color: '#9ca3af',
           fontSize: 12,
           padding: [18, 0, 0, 0],
         },
         axisLine: {
           lineStyle: {
-            color: 'rgba(206, 214, 229, 0.96)',
+            color: '#e5e7eb',
           },
         },
         axisTick: { show: false },
@@ -4383,7 +4418,7 @@
         nameRotate: 0,
         nameGap: 16,
         nameTextStyle: {
-          color: '#7b8797',
+          color: '#9ca3af',
           fontSize: 12,
           align: 'left',
           padding: [0, 0, 0, -6],
@@ -4399,7 +4434,7 @@
         splitNumber: 5,
         splitLine: {
           lineStyle: {
-            color: 'rgba(217, 225, 238, 0.92)',
+            color: '#eef2f7',
             type: 'dashed',
           },
         },
@@ -4410,21 +4445,17 @@
           type: 'line',
           smooth: true,
           symbol: 'circle',
-          symbolSize: 10,
+          symbolSize: 8,
           showSymbol: true,
           itemStyle: {
             color: '#2ac8a0',
             borderColor: '#ffffff',
             borderWidth: 2,
-            shadowBlur: 10,
-            shadowColor: 'rgba(42, 200, 160, 0.22)',
           },
-          lineStyle: { width: 3, color: '#2ac8a0' },
+          lineStyle: { width: 2.5, color: '#2ac8a0' },
           areaStyle: {
-            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-              { offset: 0, color: 'rgba(42, 200, 160, 0.22)' },
-              { offset: 1, color: 'rgba(42, 200, 160, 0.02)' },
-            ]),
+            // 纯色低透明度填充(禁止渐变)
+            color: 'rgba(42, 200, 160, 0.10)',
           },
           emphasis: {
             focus: 'series',
@@ -4436,21 +4467,17 @@
           type: 'line',
           smooth: true,
           symbol: 'circle',
-          symbolSize: 10,
+          symbolSize: 8,
           showSymbol: true,
           itemStyle: {
             color: '#ff8a66',
             borderColor: '#ffffff',
             borderWidth: 2,
-            shadowBlur: 10,
-            shadowColor: 'rgba(255, 138, 102, 0.22)',
           },
-          lineStyle: { width: 3, color: '#ff8a66' },
+          lineStyle: { width: 2.5, color: '#ff8a66' },
           areaStyle: {
-            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-              { offset: 0, color: 'rgba(255, 138, 102, 0.2)' },
-              { offset: 1, color: 'rgba(255, 138, 102, 0.02)' },
-            ]),
+            // 纯色低透明度填充(禁止渐变)
+            color: 'rgba(255, 138, 102, 0.10)',
           },
           emphasis: {
             focus: 'series',
@@ -7929,20 +7956,20 @@
     }
 
     .left-panel .panel-card .side-action-btn--primary.ant-btn {
-      border-color: #1677ff;
-      background: #1677ff;
+      border-color: #2a50ec;
+      background: #2a50ec;
       color: #fff;
 
       &:hover,
       &:focus {
-        border-color: #4096ff;
-        background: #4096ff;
+        border-color: #4b6bf0;
+        background: #4b6bf0;
         color: #fff;
       }
 
       &:active {
-        border-color: #0958d9;
-        background: #0958d9;
+        border-color: #1e3ed0;
+        background: #1e3ed0;
         color: #fff;
       }
     }
@@ -8804,6 +8831,330 @@
     }
   }
 
+  /* ==========================================================================
+   * 数据画像界面优化:对象列表 / 基本信息排版 / 图表配色
+   * 约束:全部使用纯色,不出现任何渐变;主色沿用界面现有的项目蓝 #1677ff
+   * ========================================================================== */
+  .@{prefix-cls}.case-portrait-page {
+    // ---------------- 左侧对象列表 ----------------
+    .page-layout {
+      grid-template-columns: 208px minmax(0, 1fr);
+      gap: 12px;
+    }
+
+    .left-panel .panel-card {
+      padding: 12px 10px;
+      gap: 10px;
+      border-radius: 14px;
+    }
+
+    .panel-heading {
+      padding: 2px 4px 0;
+    }
+
+    .panel-heading__title {
+      font-size: 14px;
+      font-weight: 600;
+      color: #111827;
+    }
+
+    .panel-heading__badge {
+      min-width: 24px;
+      height: 22px;
+      padding: 0 7px;
+      background: #eff6ff;
+      color: #1d4ed8;
+      font-variant-numeric: tabular-nums;
+    }
+
+    .search-box :deep(.ant-input-affix-wrapper),
+    .search-box :deep(.ant-input) {
+      height: 36px;
+      padding-inline: 10px;
+      border-radius: 8px;
+      border-color: #e5e7eb;
+      background: #f8fafc;
+      box-shadow: none;
+      transition:
+        border-color 0.2s ease,
+        background-color 0.2s ease;
+    }
+
+    .search-box :deep(.ant-input-affix-wrapper:hover),
+    .search-box :deep(.ant-input:hover) {
+      border-color: #cbd5e1;
+      background: #fff;
+    }
+
+    .search-box :deep(.ant-input-affix-wrapper-focused),
+    .search-box :deep(.ant-input:focus) {
+      border-color: #1677ff;
+      background: #fff;
+      box-shadow: 0 0 0 2px rgb(22 119 255 / 10%);
+    }
+
+    .search-box :deep(.ant-input-affix-wrapper .ant-input) {
+      background: transparent;
+    }
+
+    .search-box__icon {
+      color: #9ca3af;
+      font-size: 13px;
+    }
+
+    .left-actions .side-action-btn--primary.ant-btn {
+      height: 36px;
+      border-radius: 8px;
+    }
+
+    .person-list {
+      gap: 2px;
+      padding: 2px 0 0;
+    }
+
+    .person-card {
+      min-height: 52px;
+      padding: 8px;
+      gap: 8px;
+      border: 1px solid transparent;
+      border-radius: 10px;
+      background: transparent;
+    }
+
+    .person-card:hover {
+      border-color: #eef2f7;
+      background: #f8fafc;
+      box-shadow: none;
+    }
+
+    // 选中态:边框/头像/姓名统一使用项目主色(选择器需覆盖旧版 .left-panel .person-list 层级样式)
+    .left-panel .person-list .person-card.active {
+      border-color: #2a50ec;
+      box-shadow: none;
+    }
+
+    .person-trigger {
+      gap: 9px;
+    }
+
+    .person-avatar-wrap {
+      width: 34px;
+      height: 34px;
+      flex: 0 0 34px;
+    }
+
+    .person-info {
+      display: flex;
+      flex: 1;
+      min-width: 0;
+      flex-direction: column;
+      gap: 1px;
+    }
+
+    .person-name {
+      display: block;
+      min-width: 0;
+      overflow: hidden;
+      font-size: 13px;
+      line-height: 18px;
+      font-weight: 500;
+      color: #374151;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+      -webkit-line-clamp: unset;
+      word-break: normal;
+    }
+
+    .person-card:hover .person-name {
+      color: #1f2937;
+    }
+
+    .left-panel .person-list .person-card.active .person-name {
+      color: #2a50ec;
+      font-weight: 600;
+    }
+
+    .person-sub {
+      overflow: hidden;
+      font-size: 11px;
+      line-height: 15px;
+      color: #94a3b8;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+      font-variant-numeric: tabular-nums;
+    }
+
+    .person-card.active .person-sub {
+      color: #3b82f6;
+    }
+
+    // 头像:默认浅蓝底 + 主蓝图标,悬浮/选中为主蓝实底(纯色,替换原渐变)
+    .person-avatar .jeesite-person-avatar__media {
+      color: #1677ff;
+      background: #eff6ff;
+      border-color: #dbeafe;
+      box-shadow: none;
+    }
+
+    .left-panel .person-list .person-card:hover .person-avatar .jeesite-person-avatar__media,
+    .left-panel .person-list .person-card.active .person-avatar .jeesite-person-avatar__media {
+      color: #fff;
+      background: #2a50ec;
+      border-color: #2a50ec;
+      box-shadow: none;
+    }
+
+    // 空态:纯色占位,去掉原来的渐变底与渐变图标
+    .left-panel .person-list .empty-tip {
+      border: 1px dashed #e5e7eb;
+      border-radius: 12px;
+      background: #fafafa;
+      box-shadow: none;
+    }
+
+    .left-panel .person-list .empty-tip::before {
+      content: none;
+      display: none;
+    }
+
+    // ---------------- 基本信息 ----------------
+    .basic-content {
+      grid-template-columns: 184px minmax(0, 1fr);
+      gap: 12px;
+      align-items: stretch;
+    }
+
+    .basic-profile {
+      justify-content: center;
+      gap: 6px;
+      padding: 18px 12px;
+      border: 1px solid #eef2f7;
+      border-radius: 12px;
+      background: #f8fafc;
+    }
+
+    .profile-avatar {
+      width: 72px;
+      height: 72px;
+    }
+
+    .profile-info {
+      display: flex;
+      max-width: 100%;
+      min-width: 0;
+      flex-direction: column;
+      align-items: center;
+      gap: 2px;
+    }
+
+    .profile-name {
+      display: -webkit-box;
+      max-width: 100%;
+      overflow: hidden;
+      font-size: 15px;
+      line-height: 20px;
+      font-weight: 600;
+      color: #111827;
+      text-align: center;
+      word-break: break-all;
+      -webkit-box-orient: vertical;
+      -webkit-line-clamp: 2;
+    }
+
+    .profile-caption {
+      font-size: 11px;
+      line-height: 15px;
+      color: #94a3b8;
+    }
+
+    .info-grid {
+      grid-template-columns: repeat(4, minmax(0, 1fr));
+      gap: 8px;
+    }
+
+    .info-item {
+      min-height: 52px;
+      justify-content: center;
+      gap: 3px;
+      padding: 9px 12px;
+      border: 1px solid #eef2f7;
+      border-radius: 10px;
+      background: #f8fafc;
+    }
+
+    .info-label {
+      font-size: 11px;
+      line-height: 15px;
+      color: #94a3b8;
+      letter-spacing: 0.02em;
+    }
+
+    .info-value {
+      font-size: 13px;
+      line-height: 18px;
+      font-weight: 500;
+      color: #111827;
+      word-break: break-all;
+      overflow-wrap: anywhere;
+    }
+
+    // ---------------- 头像 / 亲密度数字配色 ----------------
+    // 基本信息主体头像、亲密关系人头像统一使用项目主色
+    .profile-avatar,
+    .profile-avatar .jeesite-person-avatar__media,
+    .relation-avatar,
+    .relation-avatar .jeesite-person-avatar__media {
+      background: #2a50ec;
+      border-color: #2a50ec;
+    }
+
+    // 亲密度数字:去掉底色,改为红色字体
+    .intimacy-card__score-badge {
+      background: transparent;
+      color: #dc2626;
+      box-shadow: none;
+    }
+
+    // 亲密度详情中的数值:同样是红色字体
+    .intimacy-detail .value--accent,
+    .intimacy-detail .detail-value--clickable {
+      color: #dc2626;
+    }
+
+    // ---------------- 图表标题:纯色旗标 ----------------
+    .chart-title .flag,
+    .trade-section .chart-title .flag {
+      background: #1677ff;
+      box-shadow: none;
+    }
+
+    // ---------------- 右侧操作统一为文字按钮:无边框/无底色,主色 #2a50ec ----------------
+    .section-action.ant-btn-link,
+    .chart-more-link.ant-btn-link {
+      height: auto;
+      padding: 0 4px;
+      border: 0;
+      border-radius: 0;
+      background: transparent;
+      box-shadow: none;
+      color: #2a50ec;
+      font-weight: 500;
+      line-height: 20px;
+
+      &:hover,
+      &:focus {
+        border: 0;
+        background: transparent;
+        color: #4b6bf0;
+        box-shadow: none;
+      }
+
+      &:active {
+        color: #1e3ed0;
+      }
+    }
+  }
+
   @media (max-width: 1440px) {
     .@{prefix-cls}.case-portrait-page {
       .comm-chart-row,
@@ -8812,7 +9163,7 @@
       }
 
       .basic-content {
-        grid-template-columns: 92px minmax(0, 1fr);
+        grid-template-columns: 160px minmax(0, 1fr);
       }
 
       .info-grid {
@@ -8836,6 +9187,10 @@
         max-height: 100%;
       }
 
+      .basic-content {
+        grid-template-columns: 148px minmax(0, 1fr);
+      }
+
       .info-grid,
       .comm-grid {
         grid-template-columns: repeat(2, minmax(0, 1fr));
@@ -8886,6 +9241,25 @@
         grid-template-columns: 1fr;
       }
 
+      .basic-content {
+        grid-template-columns: 1fr;
+      }
+
+      .basic-profile {
+        flex-direction: row;
+        justify-content: flex-start;
+        gap: 12px;
+        padding: 12px;
+      }
+
+      .profile-info {
+        align-items: flex-start;
+      }
+
+      .profile-name {
+        text-align: left;
+      }
+
       .comm-top-tools,
       .trade-top-tools,
       .trade-trend-filters,
@@ -8934,6 +9308,116 @@
       .tag {
         background: #1f2937;
       }
+
+      .basic-profile,
+      .info-item {
+        border-color: #1f2937;
+        background: #1f2937;
+      }
+
+      .info-label,
+      .profile-caption,
+      .person-sub {
+        color: #94a3b8;
+      }
+
+      .info-value,
+      .person-name {
+        color: #e5e7eb;
+      }
+
+      .left-panel .person-list .empty-tip {
+        border-color: #1f2937;
+        background: #111827;
+      }
+
+      .person-card.active {
+        border-color: #2a50ec;
+        background: #172554;
+      }
+
+      .person-avatar .jeesite-person-avatar__media {
+        color: #60a5fa;
+        background: #1e293b;
+        border-color: #334155;
+      }
     }
   }
+
+  /* 数据画像页相关弹窗统一纯色:不出现任何渐变 */
+  .create-group-modal .ant-modal-content,
+  .add-group-person-modal .ant-modal-content,
+  .person-edit-modal .ant-modal-content,
+  .person-edit-modal .person-form-section,
+  .person-edit-modal .person-avatar-upload,
+  .add-group-person-modal .add-object-modal__search,
+  .add-group-person-modal .add-object-modal__empty {
+    background: #fff;
+  }
+
+  .create-group-modal .create-group-section {
+    background: #f8fafc;
+  }
+
+  .add-group-person-modal .add-object-item__avatar {
+    background: #e0ecff;
+  }
+
+  .add-group-person-modal .add-object-item.is-selected {
+    background: #eff6ff;
+  }
+
+  .object-group-modal .group-modal-actions .head-btn {
+    background: #fff;
+  }
+
+  .object-group-modal .group-modal-actions .head-btn:hover,
+  .object-group-modal .group-modal-actions .head-btn:focus {
+    background: #f3f6fb;
+  }
+
+  .object-group-modal .group-modal-actions .head-btn--primary,
+  .object-group-modal .group-modal-actions .head-btn--accent,
+  .object-group-modal .group-modal-actions .head-btn--danger {
+    background: #fff;
+  }
+
+  .object-group-modal .group-select-btn.ant-btn-primary {
+    background: #2a50ec;
+  }
+
+  /* 数据画像页所有弹窗:按钮高度统一 32px。
+     弹窗被 teleport 到 body,用本页挂载时加的 body 标记限定作用域,避免影响其他页面弹窗。
+     需要 !important:全局弹窗页脚样式(core/design/ant/index.less)把页脚按钮定成了 36px,
+     选择器层级更高,普通覆盖不生效。 */
+  body.case-portrait-active .ant-modal-wrap .ant-btn {
+    height: 32px !important;
+  }
+
+  /* 亲密弹框里的「刷新配置」本身是小号按钮:保持原有小尺寸(24px),不参与上面的 32px 统一 */
+  body.case-portrait-active .ant-modal-wrap.intimacy-config-modal .ant-btn-sm {
+    height: 24px !important;
+  }
+
+  /* 数据画像页弹窗主按钮:统一使用项目主色 #2a50ec。
+     组件内部(ModalFooter / QueryTableModal 等)对主按钮有更高优先级的历史配色覆盖,
+     这里用 !important 统一成本页要求的项目主色。 */
+  body.case-portrait-active .ant-modal-wrap .ant-btn-primary {
+    border-color: #2a50ec !important;
+    background: #2a50ec !important;
+    color: #fff;
+  }
+
+  body.case-portrait-active .ant-modal-wrap .ant-btn-primary:not(:disabled):hover,
+  body.case-portrait-active .ant-modal-wrap .ant-btn-primary:not(:disabled):focus {
+    border-color: #4b6bf0 !important;
+    background: #4b6bf0 !important;
+    color: #fff;
+  }
+
+  body.case-portrait-active .ant-modal-wrap .ant-btn-primary:not(:disabled):active {
+    border-color: #1e3ed0 !important;
+    background: #1e3ed0 !important;
+    color: #fff;
+  }
 </style>