CustomerDetail.vue 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068
  1. <template>
  2. <div class="customer-container">
  3. <div class="main-grid-three-columns">
  4. <div class="left-column">
  5. <!-- 用户信息 -->
  6. <div class="card">
  7. <div class="card-header">
  8. <h3><i class="fas fa-id-card"></i>用户信息</h3>
  9. </div>
  10. <div class="profile-grid">
  11. <template v-if="Object.keys(customerPortraitData).length > 0">
  12. <div
  13. v-if="customerPortraitData[key]"
  14. v-for="(value, key) in userFieldComments"
  15. :key="key"
  16. class="profile-item"
  17. :class="key === 'name' ? 'profile-item-main' : ''"
  18. >
  19. <template
  20. v-if="key === 'name'"
  21. >
  22. <span class="label"><i class="fas fa-user"></i> 姓名:</span>
  23. <span class="value highlight">{{ customerPortraitData[key] }}</span>
  24. </template>
  25. <template
  26. v-else
  27. >
  28. <span class="label" :title="value">
  29. <i class="fas fa-info-circle"></i> {{ value }}:
  30. </span>
  31. <span class="value">{{ customerPortraitData[key] }}</span>
  32. </template>
  33. </div>
  34. </template>
  35. <template v-else>
  36. <div style="width: 100%; text-align: center;">
  37. 暂无数据
  38. </div>
  39. </template>
  40. </div>
  41. </div>
  42. <!-- 标签 -->
  43. <div class="card">
  44. <div class="card-header">
  45. <h3>
  46. <i class="fas fa-tags"></i> 用户画像标签
  47. </h3>
  48. </div>
  49. <div class="tags-container">
  50. <div v-if="userTags.length > 0" class="tags-list">
  51. <div
  52. v-for="(item, index) in userTags"
  53. :key="index"
  54. class="tag-item tag-highlight"
  55. >
  56. <span class="tag-key">{{ item.name }}</span>
  57. <span class="tag-separator">:</span>
  58. <span class="tag-value">{{ item.weight }}</span>
  59. </div>
  60. </div>
  61. <div v-else class="empty-tags">
  62. <i class="fas fa-inbox"></i>
  63. <span>暂无标签</span>
  64. </div>
  65. </div>
  66. </div>
  67. </div>
  68. <div class="middle-column">
  69. <!-- 沟通摘要 -->
  70. <div class="card">
  71. <div class="card-header">
  72. <h3><i class="fas fa-comment-dots"></i>客户信息汇总</h3>
  73. </div>
  74. <div class="summary-text compact">
  75. {{ getSummaryInfo() }}
  76. </div>
  77. </div>
  78. <!-- AI 本次沟通建议 -->
  79. <div class="card">
  80. <div class="card-header">
  81. <h3><i class="fas fa-robot"></i>本次沟通建议</h3>
  82. </div>
  83. <div class="summary-text compact">
  84. {{ getCommunicationSuggestion() }}
  85. </div>
  86. </div>
  87. <!-- 沟通记录 -->
  88. <div class="card card-table">
  89. <div class="card-header">
  90. <h3><i class="fas fa-history"></i> 沟通记录</h3>
  91. </div>
  92. <div class="records-table-wrapper">
  93. <table class="records-table">
  94. <thead>
  95. <tr>
  96. <th><i class="fas fa-user"></i> 客户名称</th>
  97. <th><i class="fas fa-chart-line"></i> 流失等级</th>
  98. <th><i class="fas fa-heart"></i> 外呼人员</th>
  99. <th><i class="far fa-clock"></i> 创建时间</th>
  100. <th><i class="fas fa-cog"></i> 操作</th>
  101. </tr>
  102. </thead>
  103. <tbody>
  104. <tr v-for="record in communicationRecords" :key="record.id" class="record-row">
  105. <td class="record-cell">{{ 'customerData.customerName' }}</td>
  106. <td class="record-cell">
  107. <span class="risk-level-tag" :class="getRecordRiskLevelClass(record)">
  108. {{ getRecordRiskLevelLabel(record) }}
  109. </span>
  110. </td>
  111. <td class="record-cell">
  112. <span class="intention-degree">
  113. {{ getIntentionDegreeFromRecord(record) }}
  114. </span>
  115. </td>
  116. <td class="record-cell">{{ parseTime(record.createTime, '{y}-{m}-{d} {h}:{i}:{s}') || '-' }}</td>
  117. <td class="record-cell">
  118. <button @click="viewChat(record)" class="btn-view-chat">
  119. <i class="fas fa-comments"></i> 聊天详情
  120. </button>
  121. </td>
  122. </tr>
  123. <tr v-if="!communicationRecords.length">
  124. <td colspan="5" class="empty-tip">
  125. <i class="fas fa-inbox"></i> 暂无沟通记录
  126. </td>
  127. </tr>
  128. </tbody>
  129. </table>
  130. <!-- 分页组件 -->
  131. <div class="pagination-container" v-if="communicationRecordsTotal > 0">
  132. <el-pagination
  133. @current-change="handleCommunicationRecordsPageChange"
  134. @size-change="handleCommunicationRecordsSizeChange"
  135. :current-page="communicationRecordsPageNum"
  136. :page-sizes="[4, 10, 20, 50]"
  137. :page-size="communicationRecordsPageSize"
  138. layout="total, sizes, prev, pager, next, jumper"
  139. :total="communicationRecordsTotal"
  140. />
  141. </div>
  142. </div>
  143. </div>
  144. <!-- 微信风格聊天弹窗 -->
  145. <div v-if="chatDialogVisible" class="chat-dialog-overlay" @click.self="closeChatDialog">
  146. <div class="chat-dialog">
  147. <div class="chat-dialog-header">
  148. <div class="chat-title">
  149. <i class="fas fa-comments"></i>
  150. <span>{{
  151. (currentChatRecord && currentChatRecord.customerName) || ('customerData && customerData.customerName')
  152. }} - 历史聊天记录</span>
  153. </div>
  154. <button @click="closeChatDialog" class="btn-close">
  155. ×
  156. </button>
  157. </div>
  158. <div class="chat-dialog-body">
  159. <div class="chat-messages">
  160. <!-- 根据 aiChatRecord 数组循环显示聊天记录 -->
  161. <div
  162. v-for="(msg, index) in parseChatMessages(currentChatRecord && currentChatRecord.aiChatRecord)"
  163. :key="index"
  164. class="message-item"
  165. :class="msg.type === 'ai' ? 'message-left' : 'message-right'"
  166. >
  167. <!-- AI 消息:头像在左,名称在聊天内容上方靠左 -->
  168. <div v-if="msg.type === 'ai'" class="message-wrapper message-wrapper-left">
  169. <div class="message-avatar message-avatar-ai">
  170. <img src="/static/images/ai-avatar.svg" alt="AI"
  171. @error="handleAvatarError($event, 'ai')"/>
  172. </div>
  173. <div class="message-content">
  174. <div class="message-name message-name-ai">AI</div>
  175. <div class="message-bubble">
  176. {{ msg.content }}
  177. </div>
  178. </div>
  179. </div>
  180. <!-- 客户消息:强制头像在右侧 -->
  181. <div v-else class="message-item message-item-customer">
  182. <div class="message-content-right">
  183. <div class="message-bubble message-bubble-right">
  184. {{ msg.content }}
  185. </div>
  186. </div>
  187. <div class="message-avatar message-avatar-customer">
  188. <img src="/static/images/customer-avatar.svg" alt="客户"
  189. @error="handleAvatarError($event, 'customer')"/>
  190. </div>
  191. </div>
  192. </div>
  193. <!-- 空数据提示 -->
  194. <div
  195. v-if="!parseChatMessages(currentChatRecord && currentChatRecord.aiChatRecord).length"
  196. class="empty-chat-tip">
  197. <i class="fas fa-inbox"></i> 暂无聊天内容
  198. </div>
  199. </div>
  200. </div>
  201. </div>
  202. </div>
  203. </div>
  204. <div class="right-column">
  205. <div class="card card-focus">
  206. <div class="card-header">
  207. <h3><i class="fas fa-lightbulb"></i>操作</h3>
  208. </div>
  209. <div class="focus-points">
  210. <el-button type="primary" plain @click="toggleStatus">点击处理</el-button>
  211. <el-button
  212. type="success"
  213. plain
  214. @click="doChat"
  215. :loading="imLoading"
  216. :disabled="imLoading"
  217. >
  218. 聊天
  219. </el-button>
  220. </div>
  221. </div>
  222. <div class="card card-focus">
  223. <div class="card-header">
  224. <h3><i class="fas fa-lightbulb"></i>活跃度 & 注册时间</h3>
  225. </div>
  226. <div class="focus-points">
  227. <div class="focus-title">
  228. <i class="fas fa-search"></i>活跃度
  229. </div>
  230. <ul class="focus-list">
  231. <li class="focus-item">
  232. <i class="fas fa-dot-circle"></i>{{ activityLevel }}
  233. </li>
  234. </ul>
  235. <div class="focus-title">
  236. <i class="fas fa-search"></i>注册时间
  237. </div>
  238. <ul class="focus-list">
  239. <li class="focus-item">
  240. <i class="fas fa-dot-circle"></i> {{ registerTime }}
  241. </li>
  242. </ul>
  243. </div>
  244. <div class="intention-section">
  245. <div class="card-header" style="justify-content: left;">
  246. <h3><i class="fas fa-lightbulb"></i>客户消费等级</h3>
  247. </div>
  248. <div class="intention-watermark"
  249. v-if="consumptionLevel != '--'"
  250. :class="getIntentionColorClass(consumptionLevel)">
  251. {{ consumptionLevel }}
  252. </div>
  253. <div class="no-intention-tip" v-else>
  254. 暂无评级
  255. </div>
  256. </div>
  257. </div>
  258. </div>
  259. </div>
  260. </div>
  261. </template>
  262. <script>
  263. import { getAIUserInfoByUserId, getUserTags, } from "@/api/app/user/userInfo";
  264. export default {
  265. props: {
  266. userInfo: {
  267. type: Object,
  268. default: null,
  269. },
  270. refreshCount: {
  271. type: Number,
  272. default: 0,
  273. },
  274. imLoading: {
  275. type: Boolean,
  276. default: false,
  277. },
  278. },
  279. data() {
  280. return {
  281. // 聊天记录分页相关
  282. communicationRecords: [],
  283. communicationRecordsTotal: 0,
  284. communicationRecordsPageNum: 1,
  285. communicationRecordsPageSize: 4,
  286. // 聊天弹窗相关
  287. chatDialogVisible: false, // 聊天弹窗是否显示
  288. currentChatRecord: null, // 当前查看的聊天记录
  289. customerPortraitData: {},//用户信息
  290. userFieldComments: {},//用户信息字段描述
  291. //标签信息
  292. userTags: [],
  293. comsumptionLevelMapper: {
  294. 'S+': 'S+',
  295. 'S': 'S',
  296. 'A': 'A',
  297. 'B': 'B',
  298. 'C': 'C',
  299. 'D': 'D',
  300. 'E': 'E',
  301. 'F': '代客下单'
  302. },
  303. }
  304. },
  305. computed: {
  306. // 根据是否展开控制显示的标签数量
  307. visibleTags() {
  308. if (this.isExpanded) {
  309. return this.allAiTags;
  310. } else {
  311. // 未展开时只显示前 3 条
  312. return this.allAiTags.slice(0, this.tagsPageSize);
  313. }
  314. },
  315. //活跃度
  316. activityLevel() {
  317. return !this.isEmpty(this.customerPortraitData) && !this.isEmpty(this.customerPortraitData.activityLevel) ? this.customerPortraitData.activityLevel : "--";
  318. },
  319. //注册时间
  320. registerTime() {
  321. return !this.isEmpty(this.customerPortraitData) && !this.isEmpty(this.customerPortraitData.registerTime) ? this.customerPortraitData.registerTime : "--";
  322. },
  323. //消费等级
  324. consumptionLevel() {
  325. return !this.isEmpty(this.customerPortraitData) && !this.isEmpty(this.customerPortraitData.consumptionLevel) ? this.comsumptionLevelMapper[this.customerPortraitData.consumptionLevel] : "--";
  326. },
  327. },
  328. created() {
  329. this.init();
  330. },
  331. watch: {
  332. refreshCount: {
  333. immediate: true,
  334. async handler(n, o) {
  335. //获取用户信息,注册时间,消费等级,活跃度
  336. this.getUserInfo();
  337. //获取用户标签
  338. this.getUserTags();
  339. //客户信息汇总
  340. //todo
  341. //本次沟通建议
  342. //todo
  343. //沟通记录
  344. //todo
  345. }
  346. },
  347. },
  348. methods: {
  349. /**
  350. * 初始化
  351. */
  352. async init() {
  353. //初始化用户字段信息描述
  354. let userFieldComments = {
  355. name: "姓名",
  356. sex: "性别",
  357. age: "年龄",
  358. address: "地区",
  359. habits: "行为习惯",
  360. illnessTime: "患病时间",
  361. body: "身体状态",
  362. disease: "疾病",
  363. family: "提及的家人",
  364. isLine: "是否线下就诊",
  365. familyDisease: "家人的疾病",
  366. userType: "用户分类",
  367. isSelf: "是否本人会诊",
  368. intensify: "什么情况加重或缓解",
  369. isCold: "是否怕热或者怕冷",
  370. coldBody: "怕冷或怕热的部位",
  371. sweat: "出汗情况",
  372. other: "其他情况",
  373. toilet: "大小便情况",
  374. eat: "饮食情况",
  375. menses: "经期如何",
  376. medicine: "现在使用的药品",
  377. constitution: "体质",
  378. recommendMedicine: "推荐用药",
  379. consultProduct: "咨询产品",
  380. isBuy: "是否已经购买产品",
  381. buyProduct: "已经购买的产品",
  382. productTalk: "产品交流",
  383. diseaseTalk: "疾病交流",
  384. channelType: "渠道类型"
  385. };
  386. this.$set(this, 'userFieldComments', userFieldComments);
  387. },
  388. /**
  389. * 获取用户信息
  390. */
  391. async getUserInfo() {
  392. let fsUser = await getAIUserInfoByUserId(this.userInfo.fsUserId);
  393. if (fsUser.data) {
  394. this.customerPortraitData = fsUser.data;
  395. }
  396. },
  397. isEmpty(value) {
  398. return value === null || value === undefined || value.length === 0;
  399. },
  400. /**
  401. * 获取用户兴趣标签
  402. */
  403. async getUserTags() {
  404. let userTag = await getUserTags(this.userInfo.fsUserId);
  405. if (userTag.data) {
  406. this.userTags = userTag.data;
  407. }
  408. },
  409. toggleStatus() {
  410. this.$emit('toggleStatus', this.userInfo, 1);
  411. },
  412. doChat() {
  413. this.$emit('chat', this.userInfo);
  414. },
  415. // 查看聊天内容
  416. viewChat(record) {
  417. this.currentChatRecord = record;
  418. this.chatDialogVisible = true;
  419. },
  420. // 关闭聊天弹窗
  421. closeChatDialog() {
  422. this.chatDialogVisible = false;
  423. this.currentChatRecord = null;
  424. },
  425. // 解析聊天消息数组
  426. parseChatMessages(content) {
  427. if (!content) {
  428. return [];
  429. }
  430. // 如果 content 是字符串,尝试解析为 JSON 数组
  431. if (typeof content === 'string') {
  432. try {
  433. const parsed = JSON.parse(content);
  434. // 如果是数组,直接返回
  435. if (Array.isArray(parsed)) {
  436. return parsed.map(item => ({
  437. content: item.ai || item.user,
  438. type: item.ai ? 'ai' : 'user'
  439. }));
  440. }
  441. // 如果是对象,转换为数组
  442. return [{content: parsed.content, type: parsed.type || 'ai'}];
  443. } catch (e) {
  444. // 解析失败,返回空数组
  445. console.error('解析聊天记录失败:', e);
  446. return [];
  447. }
  448. }
  449. // 如果已经是数组,直接返回
  450. if (Array.isArray(content)) {
  451. return content;
  452. }
  453. // 如果是对象,转换为数组
  454. return [content];
  455. },
  456. // 处理头像加载失败
  457. handleAvatarError(event, type) {
  458. const img = event.target;
  459. if (type === 'ai') {
  460. // AI 头像加载失败时,使用渐变色背景 + 机器人图标
  461. img.style.display = 'none';
  462. img.parentElement.innerHTML = '<i class="fas fa-robot" style="font-size: 24px; color: white;"></i>';
  463. } else {
  464. // 客户头像加载失败时,使用渐变色背景 + 用户图标
  465. img.style.display = 'none';
  466. img.parentElement.innerHTML = '<i class="fas fa-user" style="font-size: 24px; color: white;"></i>';
  467. }
  468. },
  469. // 分页改变事件
  470. handleCommunicationRecordsPageChange(pageNum) {
  471. this.communicationRecordsPageNum = pageNum;
  472. this.getCustomerInfoList();
  473. },
  474. // 每页条数改变事件
  475. handleCommunicationRecordsSizeChange(pageSize) {
  476. this.communicationRecordsPageSize = pageSize;
  477. this.communicationRecordsPageNum = 1; // 重置为第一页
  478. this.getCustomerInfoList();
  479. },
  480. // 获取汇总信息
  481. getSummaryInfo() {
  482. //todo
  483. return '暂无汇总信息';
  484. },
  485. // 获取 AI 沟通建议
  486. getCommunicationSuggestion() {
  487. //todo
  488. return '暂无沟通建议';
  489. },
  490. // 根据意向度等级获取颜色样式类
  491. getIntentionColorClass(grade) {
  492. if (!grade) return '';
  493. const gradeUpper = grade.toUpperCase();
  494. const colorMap = {
  495. 'S+': 'intention-grade-s0',
  496. 'S': 'intention-grade-s',
  497. '代客下单': 'intention-grade-f',
  498. 'A': 'intention-grade-a',
  499. 'B': 'intention-grade-b',
  500. 'C': 'intention-grade-c',
  501. 'D': 'intention-grade-d',
  502. 'E': 'intention-grade-e'
  503. };
  504. return colorMap[gradeUpper] || '';
  505. },
  506. // 获取单条记录的风险等级数值
  507. getRecordAttritionLevel(record) {
  508. if (!record) return 0;
  509. return parseInt(record.attritionLevel) || 0;
  510. },
  511. // 获取单条记录的风险等级标签
  512. getRecordRiskLevelLabel(record) {
  513. const level = this.getRecordAttritionLevel(record);
  514. const labels = ['未知', '无风险', '低风险', '中风险', '高风险'];
  515. return labels[level] || '未知';
  516. },
  517. // 获取单条记录的风险等级样式类
  518. getRecordRiskLevelClass(record) {
  519. const level = this.getRecordAttritionLevel(record);
  520. const classes = ['risk-unknown', 'risk-none', 'risk-low', 'risk-medium', 'risk-high'];
  521. return classes[level] || 'risk-unknown';
  522. },
  523. // 获取单条记录的客户意向度
  524. getIntentionDegreeFromRecord(record) {
  525. if (!record) return 0;
  526. return record.intentionDegree;
  527. },
  528. }
  529. }
  530. </script>
  531. <style scoped lang="scss">
  532. * {
  533. box-sizing: border-box;
  534. }
  535. .left-column {
  536. display: flex;
  537. flex-direction: column;
  538. gap: 12px;
  539. }
  540. .middle-column {
  541. display: flex;
  542. flex-direction: column;
  543. gap: 12px;
  544. }
  545. .right-column {
  546. display: flex;
  547. flex-direction: column;
  548. gap: 12px;
  549. }
  550. .customer-container {
  551. max-width: 1600px;
  552. margin: 0 auto;
  553. font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  554. background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
  555. padding: 8px;
  556. min-height: calc(100vh - 50px);
  557. }
  558. @keyframes pulse {
  559. 0%, 100% {
  560. transform: scale(1);
  561. }
  562. 50% {
  563. transform: scale(1.1);
  564. }
  565. }
  566. .toolbar {
  567. padding: 5px 0px;
  568. text-align: right;
  569. }
  570. .main-grid-three-columns {
  571. display: grid;
  572. grid-template-columns: 380px 1fr 340px;
  573. gap: 12px;
  574. animation: fadeIn 0.6s ease-in-out;
  575. align-items: stretch;
  576. }
  577. @keyframes fadeIn {
  578. from {
  579. opacity: 0;
  580. transform: translateY(20px);
  581. }
  582. to {
  583. opacity: 1;
  584. transform: translateY(0);
  585. }
  586. }
  587. @media (max-width: 1400px) {
  588. .main-grid-three-columns {
  589. grid-template-columns: 360px 1fr 320px;
  590. gap: 24px;
  591. }
  592. }
  593. @media (max-width: 1200px) {
  594. .main-grid-three-columns {
  595. grid-template-columns: 1fr;
  596. }
  597. }
  598. .card {
  599. background: white;
  600. border-radius: 12px;
  601. padding: 12px;
  602. margin-bottom: 12px;
  603. box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
  604. transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  605. border: 1px solid rgba(226, 232, 240, 0.5);
  606. position: relative;
  607. overflow: hidden;
  608. }
  609. .card::before {
  610. content: '';
  611. position: absolute;
  612. top: 0;
  613. left: 0;
  614. right: 0;
  615. height: 3px;
  616. background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
  617. transform: scaleX(0);
  618. transition: transform 0.4s ease;
  619. }
  620. .card:hover::before {
  621. transform: scaleX(1);
  622. }
  623. .card:hover {
  624. box-shadow: 0 12px 48px rgba(0, 0, 0, 0.15);
  625. transform: translateY(-4px);
  626. border-color: rgba(102, 126, 234, 0.3);
  627. }
  628. /* 高亮卡片(AI 总结) */
  629. .card-highlight {
  630. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  631. color: white;
  632. border: none;
  633. box-shadow: 0 8px 32px rgba(102, 126, 234, 0.4);
  634. position: relative;
  635. overflow: hidden;
  636. }
  637. .card-highlight::after {
  638. content: '';
  639. position: absolute;
  640. top: -50%;
  641. right: -50%;
  642. width: 200%;
  643. height: 200%;
  644. background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
  645. animation: shimmer 3s infinite;
  646. }
  647. @keyframes shimmer {
  648. 0%, 100% {
  649. transform: translate(0, 0);
  650. }
  651. 50% {
  652. transform: translate(-30%, -30%);
  653. }
  654. }
  655. .card-highlight .card-header h3 {
  656. color: white;
  657. }
  658. .card-highlight .summary-text {
  659. color: white;
  660. font-size: 17px;
  661. line-height: 1.6;
  662. max-height: 120px;
  663. overflow-y: auto;
  664. overflow-x: hidden;
  665. padding-right: 4px;
  666. }
  667. .card-highlight .summary-text::-webkit-scrollbar {
  668. width: 6px;
  669. }
  670. .card-highlight .summary-text::-webkit-scrollbar-track {
  671. background: rgba(255, 255, 255, 0.2);
  672. border-radius: 3px;
  673. }
  674. .card-highlight .summary-text::-webkit-scrollbar-thumb {
  675. background: rgba(255, 255, 255, 0.4);
  676. border-radius: 3px;
  677. }
  678. .card-highlight .summary-text::-webkit-scrollbar-thumb:hover {
  679. background: rgba(255, 255, 255, 0.6);
  680. }
  681. .card-highlight .summary-meta span {
  682. color: rgba(255, 255, 255, 0.9);
  683. }
  684. /* 表格卡片 */
  685. .card-table {
  686. background: white;
  687. }
  688. /* 风险卡片 */
  689. .risk-card {
  690. border-left: 4px solid #10b981;
  691. background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
  692. transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  693. }
  694. .risk-card.risk-unknown {
  695. border-left-color: #6b7280;
  696. background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%);
  697. }
  698. .risk-card.risk-unknown::before {
  699. background: linear-gradient(90deg, #6b7280 0%, #4b5563 100%);
  700. }
  701. .risk-card::before {
  702. background: linear-gradient(90deg, #10b981 0%, #34d399 100%);
  703. }
  704. /* 徽章改为“标签”风格(类似 AI 标签) */
  705. .risk-unknown .risk-badge {
  706. background: #f8fafc;
  707. border-color: #e5eaf1;
  708. color: #64748b;
  709. }
  710. .risk-none .risk-badge {
  711. background: #f0fdf4;
  712. border-color: #bbf7d0;
  713. color: #16a34a;
  714. }
  715. .risk-low .risk-badge {
  716. background: #eff6ff;
  717. border-color: #bfdbfe;
  718. color: #2563eb;
  719. }
  720. .risk-medium .risk-badge {
  721. background: #fffbeb;
  722. border-color: #fde68a;
  723. color: #d97706;
  724. }
  725. .risk-high .risk-badge {
  726. background: #fef2f2;
  727. border-color: #fecaca;
  728. color: #dc2626;
  729. }
  730. .risk-card:hover {
  731. transform: translateY(-2px);
  732. box-shadow: 0 12px 48px rgba(0, 0, 0, 0.1);
  733. }
  734. /* 风险等级标签 */
  735. .risk-badge {
  736. display: inline-flex;
  737. align-items: center;
  738. gap: 6px;
  739. padding: 5px 10px;
  740. border-radius: 10px;
  741. font-size: 13px;
  742. font-weight: 600;
  743. border: 1px solid #e5eaf1;
  744. box-shadow: none;
  745. transition: all 0.2s ease;
  746. }
  747. .risk-badge::before {
  748. content: '';
  749. width: 8px;
  750. height: 8px;
  751. border-radius: 3px;
  752. background: currentColor;
  753. opacity: 0.35;
  754. }
  755. .risk-card:hover .risk-badge {
  756. transform: translateY(-1px);
  757. }
  758. /* 风险分析内容 */
  759. .risk-analysis {
  760. margin-top: 10px;
  761. padding: 10px;
  762. background: rgba(255, 255, 255, 0.7);
  763. border-radius: 10px;
  764. backdrop-filter: blur(10px);
  765. max-height: 180px;
  766. overflow-y: auto;
  767. overflow-x: hidden;
  768. padding-right: 4px;
  769. }
  770. .risk-analysis::-webkit-scrollbar {
  771. width: 6px;
  772. }
  773. .risk-analysis::-webkit-scrollbar-track {
  774. background: rgba(255, 255, 255, 0.5);
  775. border-radius: 3px;
  776. }
  777. .risk-analysis::-webkit-scrollbar-thumb {
  778. background: linear-gradient(180deg, #cbd5e1 0%, #94a3b8 100%);
  779. border-radius: 3px;
  780. }
  781. .risk-analysis::-webkit-scrollbar-thumb:hover {
  782. background: linear-gradient(180deg, #94a3b8 0%, #64748b 100%);
  783. }
  784. .risk-text {
  785. font-size: 16px;
  786. line-height: 1.7;
  787. color: #475569;
  788. margin: 0;
  789. }
  790. .risk-tip {
  791. margin-top: 8px;
  792. padding: 8px;
  793. background: linear-gradient(135deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.9) 100%);
  794. border-left: 3px solid #f59e0b;
  795. border-radius: 6px;
  796. font-size: 15px;
  797. color: #92400e;
  798. display: flex;
  799. align-items: flex-start;
  800. gap: 6px;
  801. }
  802. .risk-tip i {
  803. font-size: 12px;
  804. margin-top: 1px;
  805. color: #f59e0b;
  806. }
  807. /* 关注点卡片 */
  808. .card-focus {
  809. background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
  810. border: 2px solid #bae6fd;
  811. box-shadow: 0 4px 16px rgba(186, 230, 253, 0.3);
  812. }
  813. .card-header {
  814. display: flex;
  815. justify-content: space-between;
  816. align-items: center;
  817. border-bottom: 1px solid #eef2ff;
  818. padding-bottom: 6px;
  819. margin-bottom: 10px;
  820. flex-wrap: wrap;
  821. }
  822. .card-header h3 {
  823. font-size: 19px;
  824. font-weight: 700;
  825. display: flex;
  826. align-items: center;
  827. gap: 8px;
  828. color: #0f172a;
  829. letter-spacing: -0.02em;
  830. }
  831. .records-table-wrapper {
  832. overflow-x: auto;
  833. }
  834. /* 分页容器样式 */
  835. .pagination-container {
  836. padding: 16px 0 12px;
  837. display: flex;
  838. justify-content: center;
  839. background: white;
  840. border-top: 1px solid #f1f5f9;
  841. margin-top: 12px;
  842. }
  843. /* Element UI 分页样式覆盖 */
  844. .pagination-container .el-pagination li {
  845. min-width: 32px;
  846. height: 32px;
  847. line-height: 32px;
  848. border-radius: 6px;
  849. transition: all 0.3s ease;
  850. }
  851. .pagination-container .el-pagination li:hover {
  852. background: linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(118, 75, 162, 0.1) 100%);
  853. border-color: #667eea;
  854. }
  855. .records-table {
  856. width: 100%;
  857. border-collapse: collapse;
  858. font-size: 15px;
  859. }
  860. .records-table thead {
  861. background: transparent;
  862. color: #475569;
  863. }
  864. .records-table th {
  865. padding: 12px 16px;
  866. text-align: center !important;
  867. font-weight: 600;
  868. font-size: 14px;
  869. border-bottom: 2px solid #e2e8f0;
  870. color: #64748b;
  871. }
  872. .records-table th i {
  873. margin-right: 6px;
  874. opacity: 0.8;
  875. }
  876. .records-table tbody tr {
  877. border-bottom: 1px solid #f1f5f9;
  878. transition: all 0.2s ease;
  879. }
  880. .records-table tbody tr:hover {
  881. background-color: #f8fafc;
  882. transform: none;
  883. box-shadow: none;
  884. }
  885. .records-table td {
  886. padding: 12px 16px;
  887. vertical-align: middle;
  888. }
  889. .record-cell {
  890. font-size: 15px;
  891. color: #334155;
  892. text-align: center !important;
  893. }
  894. /* 风险等级标签 */
  895. .risk-level-tag {
  896. display: inline-block;
  897. padding: 4px 12px;
  898. border-radius: 6px;
  899. font-size: 13px;
  900. font-weight: 500;
  901. border: 1px solid;
  902. }
  903. /* 客户意向度 */
  904. .intention-degree {
  905. display: inline-block;
  906. padding: 4px 12px;
  907. border-radius: 6px;
  908. font-size: 14px;
  909. font-weight: 600;
  910. color: #6366f1;
  911. background: rgba(99, 102, 241, 0.08);
  912. border: 1px solid rgba(99, 102, 241, 0.2);
  913. }
  914. .btn-view-chat {
  915. background: transparent;
  916. color: #667eea;
  917. border: 1px solid #667eea;
  918. padding: 6px 12px;
  919. border-radius: 6px;
  920. font-size: 14px;
  921. cursor: pointer;
  922. display: inline-flex;
  923. align-items: center;
  924. gap: 4px;
  925. transition: all 0.2s ease;
  926. }
  927. .btn-view-chat:hover {
  928. background: #f0f4ff;
  929. }
  930. .empty-tip {
  931. color: #94a3b8;
  932. font-size: 16px;
  933. text-align: center;
  934. padding: 40px 20px;
  935. background: transparent;
  936. border: none;
  937. }
  938. /* 沟通摘要样式 */
  939. .summary-text.compact {
  940. max-height: 100px;
  941. overflow-y: auto;
  942. overflow-x: hidden;
  943. line-height: 1.6;
  944. font-size: 16px;
  945. color: #475569;
  946. padding-right: 4px;
  947. }
  948. .summary-text.compact::-webkit-scrollbar {
  949. width: 6px;
  950. }
  951. .summary-text.compact::-webkit-scrollbar-track {
  952. background: #f1f5f9;
  953. border-radius: 3px;
  954. }
  955. .summary-text.compact::-webkit-scrollbar-thumb {
  956. background: linear-gradient(180deg, #cbd5e1 0%, #94a3b8 100%);
  957. border-radius: 3px;
  958. }
  959. .summary-text.compact::-webkit-scrollbar-thumb:hover {
  960. background: linear-gradient(180deg, #94a3b8 0%, #64748b 100%);
  961. }
  962. /* AI 标签美化样式 */
  963. .tags-container {
  964. padding: 0;
  965. min-height: calc(16px * 5 + 6px * 4 + 12px * 2);
  966. overflow-y: auto;
  967. overflow-x: hidden;
  968. display: flex;
  969. flex-direction: column;
  970. }
  971. .tags-container::-webkit-scrollbar {
  972. width: 6px;
  973. }
  974. .tags-container::-webkit-scrollbar-track {
  975. background: #f1f5f9;
  976. border-radius: 3px;
  977. }
  978. .tags-container::-webkit-scrollbar-thumb {
  979. background: linear-gradient(180deg, #cbd5e1 0%, #94a3b8 100%);
  980. border-radius: 3px;
  981. }
  982. .tags-container::-webkit-scrollbar-thumb:hover {
  983. background: linear-gradient(180deg, #94a3b8 0%, #64748b 100%);
  984. }
  985. /* 标签列表 - 每行一个 */
  986. .tags-list {
  987. display: flex;
  988. flex-direction: column;
  989. gap: 6px;
  990. margin-bottom: 6px;
  991. }
  992. .tag-item {
  993. display: flex;
  994. align-items: center;
  995. gap: 6px;
  996. padding: 6px 10px;
  997. background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
  998. border: 1px solid #e2e8f0;
  999. border-radius: 6px;
  1000. font-size: 15px;
  1001. transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  1002. cursor: default;
  1003. position: relative;
  1004. overflow: hidden;
  1005. }
  1006. .tag-item::before {
  1007. content: '';
  1008. position: absolute;
  1009. top: 0;
  1010. left: 0;
  1011. width: 4px;
  1012. height: 100%;
  1013. background: linear-gradient(180deg, #94a3b8 0%, #64748b 100%);
  1014. transition: width 0.3s ease;
  1015. }
  1016. .tag-item:hover {
  1017. background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
  1018. border-color: #cbd5e1;
  1019. transform: translateX(6px);
  1020. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  1021. }
  1022. .tag-item:hover::before {
  1023. width: 5px;
  1024. background: linear-gradient(180deg, #3b82f6 0%, #2563eb 100%);
  1025. }
  1026. .tag-highlight {
  1027. background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
  1028. border-color: #bfdbfe;
  1029. }
  1030. .tag-highlight::before {
  1031. background: linear-gradient(180deg, #3b82f6 0%, #2563eb 100%);
  1032. }
  1033. .tag-key {
  1034. font-weight: 600;
  1035. color: #475569;
  1036. white-space: nowrap;
  1037. flex-shrink: 0;
  1038. font-size: 15px;
  1039. }
  1040. .tag-separator {
  1041. color: #94a3b8;
  1042. font-weight: 300;
  1043. flex-shrink: 0;
  1044. font-size: 15px;
  1045. }
  1046. .tag-value {
  1047. color: #1e293b;
  1048. font-weight: 500;
  1049. word-break: break-word;
  1050. flex: 1;
  1051. min-width: 0;
  1052. font-size: 15px;
  1053. }
  1054. .empty-tags {
  1055. display: flex;
  1056. flex-direction: column;
  1057. align-items: center;
  1058. justify-content: center;
  1059. padding: 40px 20px;
  1060. color: #94a3b8;
  1061. font-size: 17px;
  1062. background: linear-gradient(135deg, rgba(248, 250, 252, 0.5) 0%, rgba(241, 245, 249, 0.5) 100%);
  1063. border-radius: 12px;
  1064. border: 2px dashed #e2e8f0;
  1065. }
  1066. .empty-tags i {
  1067. font-size: 32px;
  1068. margin-bottom: 12px;
  1069. opacity: 0.5;
  1070. }
  1071. .tags-actions {
  1072. display: flex;
  1073. justify-content: center;
  1074. padding: 16px 0;
  1075. border-top: 1px solid #f1f5f9;
  1076. margin-top: auto;
  1077. background: white;
  1078. position: sticky;
  1079. bottom: 0;
  1080. z-index: 10;
  1081. }
  1082. .btn-expand-tags,
  1083. .btn-collapse-tags {
  1084. background: transparent;
  1085. color: #667eea;
  1086. border: 1px solid #667eea;
  1087. padding: 8px 16px;
  1088. border-radius: 6px;
  1089. font-size: 16px;
  1090. cursor: pointer;
  1091. display: inline-flex;
  1092. align-items: center;
  1093. gap: 6px;
  1094. transition: all 0.2s ease;
  1095. }
  1096. .btn-expand-tags:hover,
  1097. .btn-collapse-tags:hover {
  1098. background: rgba(102, 126, 234, 0.05);
  1099. border-color: #5a67d8;
  1100. color: #5a67d8;
  1101. }
  1102. .btn-expand-tags:active,
  1103. .btn-collapse-tags:active {
  1104. transform: scale(0.98);
  1105. }
  1106. /* 微信风格聊天弹窗 */
  1107. .chat-dialog-overlay {
  1108. position: fixed;
  1109. top: 0;
  1110. left: 0;
  1111. right: 0;
  1112. bottom: 0;
  1113. background: rgba(0, 0, 0, 0.5);
  1114. display: flex;
  1115. align-items: center;
  1116. justify-content: center;
  1117. z-index: 9999;
  1118. backdrop-filter: blur(4px);
  1119. }
  1120. .chat-dialog {
  1121. background: white;
  1122. border-radius: 16px;
  1123. width: 90%;
  1124. max-width: 800px;
  1125. height: 600px;
  1126. display: flex;
  1127. flex-direction: column;
  1128. box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
  1129. animation: slideIn 0.3s ease-out;
  1130. position: relative;
  1131. }
  1132. @keyframes slideIn {
  1133. from {
  1134. opacity: 0;
  1135. transform: translateY(-20px);
  1136. }
  1137. to {
  1138. opacity: 1;
  1139. transform: translateY(0);
  1140. }
  1141. }
  1142. .chat-dialog-header {
  1143. display: flex;
  1144. justify-content: space-between;
  1145. align-items: center;
  1146. padding: 16px 20px;
  1147. border-bottom: 1px solid #eef2ff;
  1148. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  1149. border-radius: 16px 16px 0 0;
  1150. color: white;
  1151. }
  1152. .chat-title {
  1153. display: flex;
  1154. align-items: center;
  1155. gap: 10px;
  1156. font-size: 16px;
  1157. font-weight: 700;
  1158. }
  1159. .btn-close {
  1160. position: absolute;
  1161. top: 16px;
  1162. right: 16px;
  1163. background: white;
  1164. border: 2px solid #e2e8f0;
  1165. color: #1a202c;
  1166. width: 36px;
  1167. height: 36px;
  1168. border-radius: 50%;
  1169. cursor: pointer;
  1170. display: flex;
  1171. align-items: center;
  1172. justify-content: center;
  1173. transition: all 0.3s ease;
  1174. font-size: 24px;
  1175. font-weight: bold;
  1176. line-height: 1;
  1177. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  1178. z-index: 10;
  1179. }
  1180. .btn-close:hover {
  1181. background: #ef4444;
  1182. border-color: #ef4444;
  1183. color: white;
  1184. transform: rotate(90deg) scale(1.1);
  1185. box-shadow: 0 4px 16px rgba(239, 68, 68, 0.4);
  1186. }
  1187. .chat-dialog-body {
  1188. flex: 1;
  1189. overflow-y: auto;
  1190. padding: 20px;
  1191. background: #f5f7fa;
  1192. }
  1193. .chat-messages {
  1194. display: flex;
  1195. flex-direction: column;
  1196. gap: 16px;
  1197. }
  1198. .message-item {
  1199. display: flex;
  1200. align-items: flex-start;
  1201. margin-bottom: 8px;
  1202. }
  1203. .message-left {
  1204. justify-content: flex-start;
  1205. }
  1206. .message-right {
  1207. justify-content: flex-end;
  1208. }
  1209. /* 客户消息强制布局:头像在右 */
  1210. .message-item-customer {
  1211. display: flex !important;
  1212. flex-direction: row !important;
  1213. justify-content: flex-end !important;
  1214. gap: 10px !important;
  1215. }
  1216. .message-wrapper {
  1217. display: flex;
  1218. align-items: flex-start;
  1219. gap: 10px;
  1220. max-width: 75%;
  1221. }
  1222. .message-wrapper-left {
  1223. flex-direction: row;
  1224. }
  1225. .message-name {
  1226. font-size: 12px;
  1227. color: #94a3b8;
  1228. white-space: nowrap;
  1229. text-align: left;
  1230. margin-bottom: 4px;
  1231. line-height: 1.2;
  1232. }
  1233. .message-name-ai {
  1234. color: #667eea;
  1235. font-weight: 500;
  1236. }
  1237. .message-avatar {
  1238. width: 32px;
  1239. height: 32px;
  1240. border-radius: 6px;
  1241. overflow: hidden;
  1242. flex-shrink: 0;
  1243. box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
  1244. background: #f0f0f0;
  1245. }
  1246. .message-avatar img {
  1247. width: 100%;
  1248. height: 100%;
  1249. object-fit: cover;
  1250. transition: transform 0.3s ease;
  1251. }
  1252. .message-avatar:hover img {
  1253. transform: scale(1.1);
  1254. }
  1255. .message-wrapper-left .message-avatar {
  1256. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  1257. display: flex;
  1258. align-items: center;
  1259. justify-content: center;
  1260. flex-shrink: 0;
  1261. }
  1262. .message-wrapper-right .message-avatar {
  1263. background: linear-gradient(135deg, #10b981 0%, #059669 100%);
  1264. display: flex;
  1265. align-items: center;
  1266. justify-content: center;
  1267. flex-shrink: 0;
  1268. }
  1269. .message-content {
  1270. display: flex;
  1271. flex-direction: column;
  1272. max-width: calc(100% - 42px);
  1273. }
  1274. .message-wrapper-left .message-content {
  1275. align-items: flex-start;
  1276. margin-left: 4px;
  1277. }
  1278. .message-wrapper-right .message-content {
  1279. align-items: flex-end !important;
  1280. margin-right: 4px;
  1281. }
  1282. /* 客户聊天内容容器 */
  1283. .message-content-right {
  1284. flex: 0 0 auto !important;
  1285. max-width: calc(100% - 42px) !important;
  1286. display: flex;
  1287. align-items: flex-start !important;
  1288. }
  1289. .message-bubble {
  1290. background: white;
  1291. padding: 9px 13px;
  1292. border-radius: 6px;
  1293. font-size: 14px;
  1294. line-height: 1.5;
  1295. color: #0f172a;
  1296. box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
  1297. word-break: break-word;
  1298. position: relative;
  1299. max-width: 500px;
  1300. }
  1301. .message-bubble::before {
  1302. content: '';
  1303. position: absolute;
  1304. left: -6px;
  1305. top: 12px;
  1306. width: 0;
  1307. height: 0;
  1308. border-top: 5px solid transparent;
  1309. border-bottom: 5px solid transparent;
  1310. border-right: 6px solid white;
  1311. }
  1312. .message-bubble-right {
  1313. background: #d9fdd3;
  1314. color: #0f172a;
  1315. box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
  1316. display: inline-block;
  1317. position: relative;
  1318. }
  1319. .message-bubble-right::before {
  1320. content: '';
  1321. position: absolute;
  1322. right: -6px;
  1323. left: auto;
  1324. top: 16px !important;
  1325. transform: none !important;
  1326. width: 0;
  1327. height: 0;
  1328. border-top: 5px solid transparent;
  1329. border-bottom: 5px solid transparent;
  1330. border-left: 6px solid #d9fdd3;
  1331. border-right: none;
  1332. }
  1333. .empty-chat-tip {
  1334. display: flex;
  1335. flex-direction: column;
  1336. align-items: center;
  1337. justify-content: center;
  1338. padding: 60px 20px;
  1339. color: #94a3b8;
  1340. font-size: 14px;
  1341. }
  1342. .empty-chat-tip i {
  1343. font-size: 48px;
  1344. margin-bottom: 12px;
  1345. opacity: 0.5;
  1346. }
  1347. /* 客户画像样式 */
  1348. .profile-grid {
  1349. display: flex;
  1350. flex-direction: column;
  1351. gap: 4px;
  1352. max-height: 350px;
  1353. overflow-y: auto;
  1354. overflow-x: hidden;
  1355. padding-right: 4px;
  1356. padding-top: 0;
  1357. }
  1358. .profile-grid::-webkit-scrollbar {
  1359. width: 6px;
  1360. }
  1361. .profile-grid::-webkit-scrollbar-track {
  1362. background: #f1f5f9;
  1363. border-radius: 3px;
  1364. }
  1365. .profile-grid::-webkit-scrollbar-thumb {
  1366. background: linear-gradient(180deg, #cbd5e1 0%, #94a3b8 100%);
  1367. border-radius: 3px;
  1368. }
  1369. .profile-grid::-webkit-scrollbar-thumb:hover {
  1370. background: linear-gradient(180deg, #94a3b8 0%, #64748b 100%);
  1371. }
  1372. .profile-item {
  1373. display: grid;
  1374. grid-template-columns: 35% 65%;
  1375. align-items: flex-start;
  1376. gap: 6px;
  1377. padding: 4px 10px;
  1378. border-radius: 6px;
  1379. transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  1380. background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
  1381. border: 1px solid #e2e8f0;
  1382. word-break: break-word;
  1383. }
  1384. .profile-item:hover {
  1385. background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
  1386. transform: translateX(4px);
  1387. box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
  1388. border-color: #cbd5e1;
  1389. }
  1390. .profile-item-main {
  1391. background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
  1392. border-color: #bfdbfe;
  1393. position: sticky;
  1394. top: 0;
  1395. z-index: 10;
  1396. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  1397. }
  1398. .profile-item-main:hover {
  1399. background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
  1400. }
  1401. .profile-item-full {
  1402. grid-template-columns: 35% 65%;
  1403. }
  1404. .profile-item .label {
  1405. font-size: 15px;
  1406. color: #64748b;
  1407. font-weight: 600;
  1408. white-space: normal;
  1409. display: flex;
  1410. align-items: center;
  1411. gap: 4px;
  1412. line-height: 1.4;
  1413. min-width: 0;
  1414. }
  1415. .profile-item .label i {
  1416. color: #94a3b8;
  1417. font-size: 12px;
  1418. width: 14px;
  1419. text-align: center;
  1420. flex-shrink: 0;
  1421. }
  1422. .profile-item .value {
  1423. font-size: 16px;
  1424. color: #0f172a;
  1425. font-weight: 500;
  1426. word-break: break-word;
  1427. line-height: 1.4;
  1428. min-width: 0;
  1429. }
  1430. .profile-item .value.highlight {
  1431. color: #0369a1;
  1432. font-size: 16px;
  1433. font-weight: 600;
  1434. }
  1435. .profile-item .value.long-text {
  1436. color: #334155;
  1437. font-weight: 400;
  1438. }
  1439. .update-time-corner {
  1440. position: absolute;
  1441. bottom: 12px;
  1442. right: 16px;
  1443. font-size: 12px;
  1444. color: #94a3b8;
  1445. font-style: italic;
  1446. }
  1447. /* 客户关注点 & 意向度样式 */
  1448. .focus-points {
  1449. padding: 0;
  1450. margin-bottom: 10px;
  1451. }
  1452. .focus-title {
  1453. font-size: 17px;
  1454. color: #64748b;
  1455. font-weight: 600;
  1456. margin-bottom: 8px;
  1457. display: flex;
  1458. align-items: center;
  1459. gap: 6px;
  1460. }
  1461. .focus-title i {
  1462. color: #3b82f6;
  1463. font-size: 14px;
  1464. }
  1465. .focus-list {
  1466. list-style: none;
  1467. padding: 0;
  1468. margin: 0;
  1469. max-height: 200px;
  1470. overflow-y: auto;
  1471. overflow-x: hidden;
  1472. padding-right: 4px;
  1473. }
  1474. .focus-list::-webkit-scrollbar {
  1475. width: 6px;
  1476. }
  1477. .focus-list::-webkit-scrollbar-track {
  1478. background: #f1f5f9;
  1479. border-radius: 3px;
  1480. }
  1481. .focus-list::-webkit-scrollbar-thumb {
  1482. background: linear-gradient(180deg, #cbd5e1 0%, #94a3b8 100%);
  1483. border-radius: 3px;
  1484. }
  1485. .focus-list::-webkit-scrollbar-thumb:hover {
  1486. background: linear-gradient(180deg, #94a3b8 0%, #64748b 100%);
  1487. }
  1488. .focus-item {
  1489. display: flex;
  1490. align-items: flex-start;
  1491. gap: 6px;
  1492. padding: 6px 10px;
  1493. margin-bottom: 6px;
  1494. background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
  1495. border-radius: 6px;
  1496. border: 1px solid #e2e8f0;
  1497. transition: all 0.3s ease;
  1498. font-size: 15px;
  1499. color: #334155;
  1500. line-height: 1.5;
  1501. }
  1502. .focus-item:hover {
  1503. background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
  1504. border-color: #bfdbfe;
  1505. transform: translateX(4px);
  1506. box-shadow: 0 2px 6px rgba(59, 130, 246, 0.1);
  1507. }
  1508. .focus-item i {
  1509. color: #3b82f6;
  1510. font-size: 10px;
  1511. margin-top: 1px;
  1512. flex-shrink: 0;
  1513. }
  1514. /* 意向度样式 - 水印风格 */
  1515. .intention-section {
  1516. margin-top: 10px;
  1517. padding-top: 8px;
  1518. border-top: 1px solid #e2e8f0;
  1519. }
  1520. .intention-header {
  1521. margin-bottom: 6px;
  1522. display: flex;
  1523. align-items: center;
  1524. gap: 6px;
  1525. }
  1526. .intention-info-icon {
  1527. color: #94a3b8;
  1528. font-size: 16px;
  1529. cursor: pointer;
  1530. transition: all 0.3s ease;
  1531. }
  1532. .intention-info-icon:hover {
  1533. color: #3b82f6;
  1534. }
  1535. /* 意向度提示框样式 */
  1536. .intention-tooltip {
  1537. line-height: 1.8;
  1538. font-size: 13px;
  1539. }
  1540. .intention-tooltip div {
  1541. padding: 2px 0;
  1542. }
  1543. .intention-tooltip strong {
  1544. color: #1e293b;
  1545. font-weight: 600;
  1546. }
  1547. .intention-label {
  1548. font-size: 16px;
  1549. font-weight: 600;
  1550. color: #64748b;
  1551. display: flex;
  1552. align-items: center;
  1553. gap: 6px;
  1554. }
  1555. .intention-label::before {
  1556. content: '';
  1557. width: 3px;
  1558. height: 14px;
  1559. background: linear-gradient(180deg, #3b82f6 0%, #2563eb 100%);
  1560. border-radius: 2px;
  1561. }
  1562. .intention-label i {
  1563. width: 20px;
  1564. height: 20px;
  1565. border-radius: 6px;
  1566. display: inline-flex;
  1567. align-items: center;
  1568. justify-content: center;
  1569. font-size: 12px;
  1570. color: #fff;
  1571. background: linear-gradient(135deg, #f59e0b 0%, #ef4444 100%);
  1572. box-shadow: 0 2px 6px rgba(245, 158, 11, 0.35);
  1573. }
  1574. /* 水印风格意向度显示 - 按等级着色 */
  1575. .intention-watermark {
  1576. font-size: 59px;
  1577. font-weight: 800;
  1578. text-align: center;
  1579. padding: 18px 12px;
  1580. border-radius: 10px;
  1581. border: 2px solid;
  1582. position: relative;
  1583. overflow: hidden;
  1584. letter-spacing: 6px;
  1585. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  1586. transition: all 0.3s ease;
  1587. }
  1588. /* S/S+ 级 - 金色/绿色,最高级别 */
  1589. .intention-grade-s {
  1590. background: linear-gradient(135deg, #fef3c7 0%, #fde68a 50%, #fef3c7 100%);
  1591. border-color: #f59e0b;
  1592. color: #92400e;
  1593. text-shadow: 0 2px 4px rgba(146, 64, 14, 0.2);
  1594. }
  1595. .intention-grade-s::after {
  1596. content: 'S';
  1597. position: absolute;
  1598. top: 50%;
  1599. left: 50%;
  1600. transform: translate(-50%, -50%) rotate(-25deg);
  1601. font-size: 90px;
  1602. font-weight: 900;
  1603. color: rgba(245, 158, 11, 0.08);
  1604. z-index: 0;
  1605. pointer-events: none;
  1606. }
  1607. .intention-grade-s0 {
  1608. background: linear-gradient(135deg, #fef3c7 0%, #fde68a 50%, #fef3c7 100%);
  1609. border-color: #f59e0b;
  1610. color: #92400e;
  1611. text-shadow: 0 2px 4px rgba(146, 64, 14, 0.2);
  1612. }
  1613. .intention-grade-s0::after {
  1614. content: 'S+';
  1615. position: absolute;
  1616. top: 50%;
  1617. left: 50%;
  1618. transform: translate(-50%, -50%) rotate(-25deg);
  1619. font-size: 90px;
  1620. font-weight: 900;
  1621. color: rgba(245, 158, 11, 0.08);
  1622. z-index: 0;
  1623. pointer-events: none;
  1624. }
  1625. /* A 级 - 蓝色 */
  1626. .intention-grade-a {
  1627. background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 50%, #dbeafe 100%);
  1628. border-color: #3b82f6;
  1629. color: #1e40af;
  1630. text-shadow: 0 2px 4px rgba(30, 64, 175, 0.2);
  1631. }
  1632. .intention-grade-a::after {
  1633. content: 'A';
  1634. position: absolute;
  1635. top: 50%;
  1636. left: 50%;
  1637. transform: translate(-50%, -50%) rotate(-25deg);
  1638. font-size: 90px;
  1639. font-weight: 900;
  1640. color: rgba(59, 130, 246, 0.08);
  1641. z-index: 0;
  1642. pointer-events: none;
  1643. }
  1644. /* F 级 - 蓝色 */
  1645. .intention-grade-f {
  1646. background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 50%, #dbeafe 100%);
  1647. border-color: #3b82f6;
  1648. color: #1e40af;
  1649. text-shadow: 0 2px 4px rgba(30, 64, 175, 0.2);
  1650. font-size: 40px !important;
  1651. }
  1652. .intention-grade-f::after {
  1653. content: '代客下单';
  1654. position: absolute;
  1655. top: 50%;
  1656. left: 50%;
  1657. transform: translate(-50%, -50%) rotate(-25deg);
  1658. font-size: 30px;
  1659. font-weight: 800;
  1660. color: rgba(59, 130, 246, 0.08);
  1661. z-index: 0;
  1662. pointer-events: none;
  1663. }
  1664. /* B 级 - 紫色 */
  1665. .intention-grade-b {
  1666. background: linear-gradient(135deg, #e9d5ff 0%, #d8b4fe 50%, #e9d5ff 100%);
  1667. border-color: #a855f7;
  1668. color: #6b21a8;
  1669. text-shadow: 0 2px 4px rgba(107, 33, 168, 0.2);
  1670. }
  1671. .intention-grade-b::after {
  1672. content: 'B';
  1673. position: absolute;
  1674. top: 50%;
  1675. left: 50%;
  1676. transform: translate(-50%, -50%) rotate(-25deg);
  1677. font-size: 90px;
  1678. font-weight: 900;
  1679. color: rgba(168, 85, 247, 0.08);
  1680. z-index: 0;
  1681. pointer-events: none;
  1682. }
  1683. /* C 级 - 橙色 */
  1684. .intention-grade-c {
  1685. background: linear-gradient(135deg, #fed7aa 0%, #fdba74 50%, #fed7aa 100%);
  1686. border-color: #f97316;
  1687. color: #9a3412;
  1688. text-shadow: 0 2px 4px rgba(154, 52, 18, 0.2);
  1689. }
  1690. .intention-grade-c::after {
  1691. content: 'C';
  1692. position: absolute;
  1693. top: 50%;
  1694. left: 50%;
  1695. transform: translate(-50%, -50%) rotate(-25deg);
  1696. font-size: 90px;
  1697. font-weight: 900;
  1698. color: rgba(249, 115, 22, 0.08);
  1699. z-index: 0;
  1700. pointer-events: none;
  1701. }
  1702. /* D 级 - 粉红色 */
  1703. .intention-grade-d {
  1704. background: linear-gradient(135deg, #fbcfe8 0%, #f9a8d4 50%, #fbcfe8 100%);
  1705. border-color: #ec4899;
  1706. color: #9d174d;
  1707. text-shadow: 0 2px 4px rgba(157, 23, 77, 0.2);
  1708. }
  1709. .intention-grade-d::after {
  1710. content: 'D';
  1711. position: absolute;
  1712. top: 50%;
  1713. left: 50%;
  1714. transform: translate(-50%, -50%) rotate(-25deg);
  1715. font-size: 90px;
  1716. font-weight: 900;
  1717. color: rgba(236, 72, 153, 0.08);
  1718. z-index: 0;
  1719. pointer-events: none;
  1720. }
  1721. /* E 级 - 红色,最低级别 */
  1722. .intention-grade-e {
  1723. background: linear-gradient(135deg, #fecaca 0%, #fca5a5 50%, #fecaca 100%);
  1724. border-color: #ef4444;
  1725. color: #991b1b;
  1726. text-shadow: 0 2px 4px rgba(153, 27, 27, 0.2);
  1727. }
  1728. .intention-grade-e::after {
  1729. content: 'E';
  1730. position: absolute;
  1731. top: 50%;
  1732. left: 50%;
  1733. transform: translate(-50%, -50%) rotate(-25deg);
  1734. font-size: 90px;
  1735. font-weight: 900;
  1736. color: rgba(239, 68, 68, 0.08);
  1737. z-index: 0;
  1738. pointer-events: none;
  1739. }
  1740. .intention-watermark span {
  1741. position: relative;
  1742. z-index: 1;
  1743. }
  1744. /* 暂无评级提示 */
  1745. .no-intention-tip {
  1746. text-align: center;
  1747. padding: 18px 12px;
  1748. font-size: 16px;
  1749. color: #94a3b8;
  1750. font-style: italic;
  1751. background: linear-gradient(135deg, rgba(248, 250, 252, 0.5) 0%, rgba(241, 245, 249, 0.5) 100%);
  1752. border-radius: 10px;
  1753. border: 2px dashed #e2e8f0;
  1754. }
  1755. .card-header h3 i {
  1756. width: 24px;
  1757. height: 24px;
  1758. border-radius: 7px;
  1759. display: inline-flex;
  1760. align-items: center;
  1761. justify-content: center;
  1762. font-size: 13px;
  1763. color: #fff;
  1764. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  1765. box-shadow: 0 3px 8px rgba(102, 126, 234, 0.35);
  1766. -webkit-text-fill-color: #fff;
  1767. }
  1768. .card-highlight .card-header h3 i {
  1769. color: white;
  1770. background: none;
  1771. -webkit-text-fill-color: white;
  1772. }
  1773. /* 模仿参考图的企业微信分析台风格(覆盖) */
  1774. .customer-container {
  1775. max-width: 100%;
  1776. padding: 12px;
  1777. background: #f4f6fa;
  1778. }
  1779. .main-grid-three-columns {
  1780. grid-template-columns: 300px minmax(640px, 1fr) 320px;
  1781. gap: 12px;
  1782. align-items: start;
  1783. }
  1784. .card {
  1785. border-radius: 10px;
  1786. border: 1px solid #e6ebf2;
  1787. box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
  1788. margin-bottom: 10px;
  1789. padding: 12px;
  1790. background: #fff;
  1791. }
  1792. .card::before {
  1793. display: none;
  1794. }
  1795. .card:hover {
  1796. transform: none;
  1797. box-shadow: 0 2px 8px rgba(15, 23, 42, 0.08);
  1798. border-color: #dbe4f0;
  1799. }
  1800. .card-header {
  1801. border-bottom: 1px solid #edf1f7;
  1802. margin-bottom: 10px;
  1803. padding-bottom: 8px;
  1804. }
  1805. .card-header h3 {
  1806. font-size: 16px;
  1807. font-weight: 600;
  1808. color: #1f2937;
  1809. }
  1810. .card-header h3 i {
  1811. width: 18px;
  1812. height: 18px;
  1813. border-radius: 4px;
  1814. font-size: 10px;
  1815. background: #4f7cff;
  1816. box-shadow: none;
  1817. }
  1818. .summary-text.compact {
  1819. font-size: 14px;
  1820. line-height: 1.75;
  1821. color: #334155;
  1822. max-height: 132px;
  1823. }
  1824. .risk-card,
  1825. .card-focus {
  1826. background: #fff;
  1827. border: 1px solid #e6ebf2;
  1828. }
  1829. .risk-analysis {
  1830. background: #f8fafc;
  1831. border: 1px solid #edf2f7;
  1832. }
  1833. .tag-item,
  1834. .focus-item,
  1835. .profile-item {
  1836. background: #f8fafc;
  1837. border-color: #e5eaf1;
  1838. }
  1839. .intention-label i {
  1840. width: 18px;
  1841. height: 18px;
  1842. border-radius: 4px;
  1843. font-size: 10px;
  1844. background: #4f7cff;
  1845. box-shadow: none;
  1846. }
  1847. .records-table th {
  1848. background: #f8fafc;
  1849. color: #475569;
  1850. }
  1851. .records-table tbody tr:hover {
  1852. background: #f8fbff;
  1853. }
  1854. </style>