| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775 |
- <template>
- <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>
- <!-- 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>
- <!-- 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 :show-close="true" class="customer-dialog">
- <add-tag ref="tag" @close="closeTag()"></add-tag>
- <span slot="footer" class="dialog-footer">
- <el-button @click="addTag.open = false">取 消</el-button>
- <el-button type="primary" @click="$refs.tag.submitForm()">确 定</el-button>
- </span>
- </el-dialog>
- <el-dialog :title="addRemark.title" :visible.sync="addRemark.open" width="600px" append-to-body :show-close="true" class="customer-dialog">
- <add-remark ref="remark" @close="closeRemark()"></add-remark>
- <span slot="footer" class="dialog-footer">
- <el-button @click="addRemark.open = false">取 消</el-button>
- <el-button type="primary" @click="$refs.remark.submitForm()">确 定</el-button>
- </span>
- </el-dialog>
- <el-dialog :title="addSms.title" :visible.sync="addSms.open" width="800px" append-to-body class="customer-dialog">
- <add-sms ref="sms" @close="closeSms()"></add-sms>
- </el-dialog>
- <el-dialog :title="customer.title" :visible.sync="customer.open" width="1000px" append-to-body :show-close="true" class="customer-dialog">
- <add-or-edit-customer ref="customer" @close="closeCustomer()"></add-or-edit-customer>
- <span slot="footer" class="dialog-footer">
- <el-button @click="customer.open = false">取 消</el-button>
- <el-button type="primary" @click="$refs.customer.submitForm()">确 定</el-button>
- </span>
- </el-dialog>
- <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 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'
- },
- 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()
- },
- 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)
- })
- })
- getCustomerDetails1(data).then(response => {
- this.item = response.customer
- this.isReceive = response.isReceive
- if (this.item && 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 (this.item) {
- 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
- 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>
- .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-tags-section {
- background: #fff;
- border-radius: 8px;
- padding: 16px 20px;
- margin-bottom: 20px;
- display: flex;
- align-items: center;
- .tags-label {
- font-weight: 500;
- color: #606266;
- margin-right: 12px;
- }
- }
- .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>
|