增加产品回答卡片

master
jiangjunjie 2 weeks ago
parent 2dfd94a5e3
commit d86cb71a0e
  1. 9
      src/components/chat-content.vue
  2. 33
      src/components/history-content.vue
  3. 259
      src/components/product-card-list.vue
  4. 670
      src/components/product/index.vue
  5. 6
      src/router/index.js

@ -827,7 +827,7 @@
</div> </div>
</div> </div>
<!-- 产品模板--> <!-- 产品模板-->
<!-- <div <div
class="chat-content-left" class="chat-content-left"
v-if="item.cmd === 'CPZX'" v-if="item.cmd === 'CPZX'"
> >
@ -845,10 +845,7 @@
</div> </div>
<div class="chat-items"> <div class="chat-items">
<div <div
class="content-left-main text-folding-box" class="content-left-main noPadding"
:class="{
'question-text': item.cmd != 'RGFWHS' && item.cmd != 'QXRGPJ',
}"
> >
<Product <Product
:responseData="item.specialData" :responseData="item.specialData"
@ -878,7 +875,7 @@
</div> </div>
</div> </div>
</div> </div>
</div> --> </div>
<!-- 展开收起类型 ---> <!-- 展开收起类型 --->
<!-- 问题评价---> <!-- 问题评价--->

@ -15,6 +15,7 @@ import BusinessHandle from '@/components/business-handle.vue'
import EditAddress from '@/components/edit-address.vue' import EditAddress from '@/components/edit-address.vue'
import PolicyList from '@/components/policyList.vue' import PolicyList from '@/components/policyList.vue'
import XuqiPolicyList from '@/components/xuqiPolicyList.vue' import XuqiPolicyList from '@/components/xuqiPolicyList.vue'
import ProductCardList from '@/components/product-card-list.vue'
import imageService from '@/utils/imageService' import imageService from '@/utils/imageService'
import { FormatDate } from '@/utils/filters' import { FormatDate } from '@/utils/filters'
@ -148,7 +149,33 @@ onMounted(() => { processedEmoji() })
</div> </div>
<!-- 左边机器人/坐席消息 --> <!-- 左边机器人/坐席消息 -->
<div class="chat-room-cont" v-if="item.fromFlag == '2'"> <!-- 多轮 买保险咨询 产品卡片 -->
<div class="chat-room-cont" v-if="item.fromFlag == '2' && !!item.cmd && item.cmd.includes('CPLB')">
<div class="chat-content-left">
<div class="content-left-icon">
<DynamicImage :image-key="headerAvatar.robotUrl" class="avatarUrl-img" />
<div class="chat-name" v-if="item.seatNum && item.seatNum != '调度员'">{{ item.seatNum }}</div>
</div>
<div class="chat-items">
<div class="content-left-main">
<!-- 产品卡片组件 -->
<ProductCardList :products="item.specialData" />
<!--问题反馈 -->
<div class="help-button-box flex flex-align-center before-top"
v-if="item.cmd != 'RGFWHS' && item.cmd != 'QXRGPJ'">
<button class="help-button-item" disabled="disabled" :data-ref="`u_${item.timestamp}`">
<em class="help-button-icon"></em>没有帮助
</button>
<button class="help-button-item" disabled="disabled" :data-ref="`r_${item.timestamp}`">
<em class="help-button-icon"></em>有帮助
</button>
</div>
</div>
</div>
</div>
</div>
<div class="chat-room-cont" v-else-if="item.fromFlag == '2'">
<div class="chat-content-left"> <div class="chat-content-left">
<div class="content-left-icon"> <div class="content-left-icon">
<DynamicImage :image-key="headerAvatar.robotUrl" class="avatarUrl-img" /> <DynamicImage :image-key="headerAvatar.robotUrl" class="avatarUrl-img" />
@ -261,3 +288,7 @@ onMounted(() => { processedEmoji() })
border-radius: 4px 16px 16px 16px; border-radius: 4px 16px 16px 16px;
} }
</style> </style>
<style>
@import "@/assets/style/chat.css";
</style>

@ -1,115 +1,206 @@
<template> <template>
<div class="product-card-container" v-if="productList && productList.length > 0"> <div class="product-card-list">
<div class="product-card" v-for="(product, index) in productList" :key="index"> <!-- 空状态 -->
<div class="card-header"> <div v-if="!products || products.length === 0" class="empty-state">
<h3 class="product-name">{{ product.productName || product.name }}</h3> 暂未配置,请稍后再来看吧~
<span class="product-code" v-if="product.productCode">{{ product.productCode }}</span> </div>
</div>
<div class="card-body"> <!-- 产品列表 -->
<div class="product-desc" v-if="product.description">{{ product.description }}</div> <template v-else>
<div class="product-features" v-if="product.features && product.features.length"> <div class="product-card" v-for="item in displayProducts" :key="item.id">
<span class="feature-tag" v-for="(tag, idx) in product.features" :key="idx">{{ tag }}</span> <div class="product-info">
<div class="product-name">{{ item.productName }}</div>
<div class="product-desc">
<span v-if="shouldTruncate(item)">
{{ item.productDesc.substring(0, textLimit) }}...
<span class="expand-btn" @click.stop="expandItem(item.id)">点击查看全部</span>
</span>
<span v-else>
{{ item.productDesc }}
</span>
</div>
<!-- 按钮区域 -->
<div class="product-actions">
<button v-if="item.introQuestion" class="action-btn"
@click="handleActionClick(item.productName, item.productCode, item.introQuestion, '产品咨询')">
产品咨询
</button>
<button v-if="item.reserveQuestion" class="action-btn"
@click="handleActionClick(item.productName, item.productCode, item.reserveQuestion, '投保预约')">
投保预约
</button>
</div>
</div> </div>
</div> </div>
<div class="card-footer" v-if="product.price || product.actionText">
<span class="price" v-if="product.price">{{ product.price }}</span> <!-- 查看更多按钮 -->
<button class="action-btn" v-if="product.actionText" @click="handleAction(product)">{{ product.actionText <div v-if="products.length > maxDisplay" class="view-more" @click="handleViewMore">
}}</button> 查看更多
</div> </div>
</div> </template>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, computed, inject } from 'vue'
import { messageSend } from '@/utils/api'
const props = defineProps({ const props = defineProps({
productList: { type: Array, default: () => [] } products: { type: Array, default: () => [] },
}) })
const emit = defineEmits(['action']) const store = inject('appStore', null)
const maxDisplay = ref(3)
const expandedMap = ref({})
const textLimit = 25
function handleAction(product) { const displayProducts = computed(() => props.products.slice(0, maxDisplay.value))
emit('action', product)
}
</script>
<style scoped> function handleViewMore() {
.product-card-container { maxDisplay.value += 3
padding: 8px 0;
} }
.product-card { // 是否需要截断
background: #fff; function shouldTruncate(item) {
border-radius: 12px; if (!item.productDesc) return false
padding: 16px; if (expandedMap.value[item.id]) return false
margin-bottom: 12px; return item.productDesc.length > textLimit
border: 1px solid #f0f0f0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
} }
.card-header { // 展开单个条目
display: flex; function expandItem(id) {
align-items: center; expandedMap.value[id] = true
justify-content: space-between;
margin-bottom: 8px;
} }
.product-name { // 处理按钮点击事件
font-size: 16px; function handleActionClick(productName, productCode, question, buttonName) {
font-weight: 600; if (!question) {
color: #333; console.warn('问句为空,无法发送')
margin: 0; return
}
sendQuestion(question)
} }
.product-code { // 发送问句
font-size: 12px; function sendQuestion(text) {
color: #999; // sendingRobot 内部 addSendMessageList 会把用户消息写入 chatArr,无需重复 pushUserMessage
messageSend(text, { questionType: 10 })
.then(() => {
console.log('产品卡片问句发送成功')
})
.catch((err) => {
console.log(err)
})
} }
</script>
.card-body { <style lang="scss" scoped>
margin-bottom: 12px; .product-card-list {
} width: 100%;
.product-desc { .empty-state {
font-size: 13px; padding: 24px 16px;
color: #666; text-align: center;
line-height: 1.5; color: #999;
} font-size: 14px;
background: #f9f9f9;
border-radius: 8px;
}
.product-features { .product-card {
display: flex; display: flex;
flex-wrap: wrap; align-items: flex-start;
gap: 6px; background: #fff;
margin-top: 8px; border-radius: 8px;
} overflow: hidden;
margin-bottom: 10px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
.feature-tag { .product-cover {
display: inline-block; width: 80px;
padding: 2px 8px; height: 80px;
background: #f0f6ff; flex-shrink: 0;
color: #025CEA; background: linear-gradient(135deg, #1a2b4a 0%, #2c3e5d 100%);
border-radius: 4px;
font-size: 11px;
}
.card-footer { img {
display: flex; width: 100%;
align-items: center; height: 100%;
justify-content: space-between; object-fit: cover;
} }
}
.price { .product-info {
font-size: 18px; flex: 1;
font-weight: 600; padding: 8px 12px;
color: #ff4757; min-width: 0;
}
.product-name {
font-size: 15px;
font-weight: 600;
color: #333;
margin-bottom: 10px;
word-break: break-all;
}
.product-desc {
font-size: 13px;
color: #777;
line-height: 1.4;
word-break: break-all;
.expand-btn {
color: #4f95fd;
cursor: pointer;
margin-left: 2px;
display: inline-block;
}
}
.product-actions {
display: flex;
flex-wrap: wrap;
gap: 7px;
margin-top: 10px;
}
.action-btn {
height: auto;
padding: 4px 0;
width: 77px;
text-align: center;
border-radius: 15px;
font-family: PingFangSC-Regular, "PingFang SC", sans-serif;
font-size: 12px;
letter-spacing: -1px;
background: #ffffff;
color: #17204D;
border: 1px solid #7E849F;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
justify-content: center;
align-items: center;
}
.action-btn:active {
background: #f5f5f5;
}
}
}
.view-more {
text-align: center;
padding: 12px;
color: #4f95fd;
font-size: 14px;
background: #f0f7ff;
border-radius: 8px;
cursor: pointer;
.action-btn { &:active {
padding: 6px 16px; background: #e0efff;
background: #025CEA; }
color: #fff; }
border: none;
border-radius: 20px;
font-size: 13px;
cursor: pointer;
} }
</style> </style>

@ -1,131 +1,629 @@
<template> <template>
<div class="product-component"> <div>
<div class="product-wrapper" v-if="productData"> <div class="product_body">
<div class="product-header" v-if="productData.title"> <div :class="{ hiddenMore: showTotal }" class="bg_white" ref="productEl">
<h3>{{ productData.title }}</h3> <!-- 产品头部 -->
</div> <div class="product_top">
<div class="product-body"> <div class="title_body">
<div class="product-item" v-for="(item, index) in productData.list" :key="index" <div class="title">
@click="handleProductClick(item)"> <span class="text_content">{{ resultData.productName }}</span>
<div class="product-icon" v-if="item.icon"> <span class="mark">{{ resultData.isSale }}</span>
<img :src="item.icon" :alt="item.name" /> </div>
</div>
<div class="labels_body">
<div class="label" v-if="!!resultData.coreOne">
<img :src="labelesImg" />
<span>{{ resultData.coreOne }}</span>
</div>
<div class="label" v-if="!!resultData.coreTwo">
<img :src="labelesImg" />
<span>{{ resultData.coreTwo }}</span>
</div>
</div> </div>
<div class="product-info"> </div>
<div class="product-title">{{ item.name }}</div> <div v-if="!!resultData.insClausesFlag" class="product_exemption">
<div class="product-subtitle" v-if="item.subtitle">{{ item.subtitle }}</div> 此险种有多个版本,点击“条款原文”查看其它历史版本
</div>
<!-- 产品内容部分 -->
<div class="product_main">
<div class="product_modules">
<div class="base_module">
<!-- 列表集合 -->
<div class="list" v-for="item in baseModuleData" :key="item.id" v-show="!!item.val">
<div class="list_label">{{ item.key }}:</div>
<div class="list_content">
<span class="value" :class="{ noBtn: !item.tkywValue }" v-html="item.val"></span>
<div @click="showGraph(item)" v-show="!!item.tkywValue" class="tkk_btn">
条款原文
</div>
</div>
</div>
</div>
<!-- 保险责任 -->
<div class="more_module">
<div class="top_right_bg">
<!-- 列表集合 -->
<div class="list" v-for="item in resultData.insDuty" :key="item.key">
<div class="list_label">
<span class="list_label_span">
{{ item.key }}:
</span>
</div>
<div class="list_content" v-if="item.isRender" v-html="item.completedData"></div>
<div class="list_content" v-else>
<template v-for="(completedItem, cIdx) in item.completedData" :key="cIdx">
<span class="more_text" v-if="typeof completedItem === 'string'"
v-html="completedItem"></span>
<span class="more_button" v-else @click="showImgPopup(completedItem.urlValue)">
{{ completedItem.urlkey }}
</span>
</template>
</div>
</div>
<div class="tip">具体以条款为准</div>
</div>
</div>
</div> </div>
<div class="product-arrow"> </div>
<van-icon name="arrow" /> <!-- 产品底部 -->
<div class="product_bottom">
<div class="bottom_modules">
<div class="img_module" :class="bottomModuleNum ? 'min_witch' : ''" v-show="!!item.url"
v-for="item in bottomModulesData" :key="item.id">
<img @click="clickBottomBtn(item.name)" :src="item.src" />
</div>
</div> </div>
</div> </div>
<!-- 关联问 -->
<div class="content-question-answer" v-if="intents && intents.length > 0">
<button :class="hasClicked ? 'answer-items setGrey' : 'answer-items'"
v-for="(items, index) in intents" :key="index" @click.stop="richCallAnswer(items)">
{{ items.intent }}
</button>
</div>
</div> </div>
<!-- 展开拉起 -->
<div class="unfold-box" :class="exchangeButton ? 'unfold-bg' : 'unfold-style'" v-if="showExchangeButton">
<a href="javascript:;" @click="showTotalIntro">{{ exchangeButton ? "展开" : "收起"
}}<em class="look-more-icon" :class="!exchangeButton ? 'active' : ''"></em></a>
</div>
<!-- 弹出层 -->
<van-popup class="popup" :style="{ height: '85%', borderRadius: '10px 10px 0px 0px' }"
v-model:show="popUpFlag" teleport="body" position="bottom">
<div class="detaill_body">
<div class="detaill_title">
{{ detaillTitle }}
</div>
<!-- 条款原文 -->
<div class="detaill_content" v-show="nowPopType === 'tkyw'">
<div v-html="tkywValue"></div>
</div>
<img :style="{ width: '100%', maxWidth: 'none' }" class="product_img" :src="productImgUrl"
v-if="!!productImgUrl && nowPopType === 'img'" />
</div>
</van-popup>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, inject, onMounted } from 'vue' import { ref, computed, inject } from 'vue'
import { Icon } from 'vant' import { useRouter } from 'vue-router'
import _ from 'lodash'
import wx from 'weixin-js-sdk'
import Utils from '@/utils/utils'
import labelesImg from '@/assets/images/product/icon_yes.png'
import bottomTkywImg from '@/assets/images/product/bottom_tkyw.png'
const props = defineProps({ const props = defineProps({
data: { type: Object, default: () => ({}) }, responseData: { type: Object, default: () => ({}) },
productId: { type: String, default: '' } intents: { type: Array, default: () => [] },
itemlist: { type: Object, default: () => ({}) },
}) })
const router = useRouter()
const store = inject('appStore', null) const store = inject('appStore', null)
const productData = ref(null)
onMounted(() => { const resultData = ref({}) // 处理后的数据
if (props.data && props.data.specialData) { const baseModuleData = ref([])
productData.value = { const popUpFlag = ref(false)
title: props.data.specialData.title || '', const productImgUrl = ref('')
list: props.data.specialData.list || props.data.specialData.data || [] const bottomModulesData = ref([
} { id: 1, name: 'TKYW', src: bottomTkywImg, url: '' },
} ])
}) const exchangeButton = ref(true) // 是否显示展开收起按钮
const showExchangeButton = ref(true)
const showTotal = ref(true) // 显示展开还是收起
const isBtnsubmit = ref(true) // 防止关联问发送
const nowPopType = ref('')
const tkywValue = ref('')
const detaillTitle = ref('')
const hasClicked = ref(false)
function handleProductClick(item) { const bottomModuleNum = computed(
if (item.url) { () => bottomModulesData.value.filter((item) => !!item.url).length > 3,
window.location.href = item.url )
}
if (item.cmd) { // —— created:解析产品模板数据 ——
store?.dispatch?.('sendingRobot', { const allData = _.cloneDeep(_.get(props.responseData, 'productInfo')) || {}
reqAndResType: '1', const originProDuctData = allData.insDuty || {}
msgText: item.cmd, const originalText = _.cloneDeep(_.get(props.responseData, 'originalText')) // 图谱数据
msgSource: '1' resultData.value = allData
// 格式化保险责任:按 | 与 ; 拆分为文本/链接
const dutyList = []
for (const i in originProDuctData) {
const result = {}
result.key = i
const productVal = originProDuctData[i]
if (String(productVal).includes('|')) {
result.isRender = false
const beforeData = String(productVal).split('|')
result.completedData = beforeData.map((item) => {
if (item.includes(':')) {
const urlData = item.split(';')
return { urlkey: urlData[0], urlValue: urlData[1] }
}
return item
}) })
} else {
result.isRender = true
result.completedData = originProDuctData[i]
} }
dutyList.push(result)
} }
</script> allData.insDuty = dutyList
resultData.value = allData
<style scoped> // 基本保额等模块,其中含条款原文对应数据
.product-component { baseModuleData.value = [
padding: 0; { key: '保险类型', val: _.get(resultData.value, 'insType'), id: 0 },
} { key: '开停办时间', val: _.get(resultData.value, 'osTime'), id: 1 },
{ key: '投保年龄', val: _.get(resultData.value, 'insdAge'), id: 2 },
.product-wrapper { { key: '保险期间', val: _.get(resultData.value, 'insPeriod'), id: 3 },
background: #fff; { key: '交费方式', val: _.get(resultData.value, 'payType'), id: 4 },
border-radius: 12px; { key: '犹豫期', val: _.get(resultData.value, 'hesPeriod'), id: 5 },
overflow: hidden; { key: '观察期', val: _.get(resultData.value, 'obsPeriod'), id: 6 },
{ key: '销售地区', val: _.get(resultData.value, 'saleArea'), id: 7 },
{ key: '销售渠道', val: _.get(resultData.value, 'salesChannels'), id: 8 },
{ key: '基本保额', val: _.get(resultData.value, 'basicInsAmo'), id: 9 },
{ key: '每份保费', val: _.get(resultData.value, 'basicPremium'), id: 10 },
{ key: '最低保证利率', val: _.get(resultData.value, 'minGuaRate'), id: 11 },
{ key: '红利领取方式', val: _.get(resultData.value, 'bonClaType'), id: 12 },
{ key: '免赔额', val: _.get(resultData.value, 'deductible'), id: 13 },
]
const originalArr = _.get(originalText, '[0].properties')
if (Array.isArray(originalArr) && originalArr.length > 0) {
baseModuleData.value.forEach((item) => {
originalArr.forEach((tkyw) => {
if (tkyw.propName === item.key) {
item.tkywValue = tkyw.propValue
}
})
})
} }
// 设置模块的url
bottomModulesData.value.forEach((item) => {
if (item.name === 'TKYW') item.url = resultData.value.clauseText
})
.product-header { function showImgPopup(url) {
padding: 16px 16px 8px; popUpFlag.value = true
productImgUrl.value = url
nowPopType.value = 'img'
} }
.product-header h3 { function clickBottomBtn(name) {
margin: 0; let url = ''
font-size: 16px; if (name === 'TKYW') {
color: #333; url = resultData.value.clauseText
font-weight: 600; }
if (/\.pdf$/.test(url)) {
// 安卓/鸿蒙小程序环境跳转预览页
let isMiniProgram = false
try {
wx.miniProgram.getEnv((res) => {
if (res.miniprogram) {
isMiniProgram = true
}
})
} catch (e) {
console.log(e)
}
if ((Utils.getSystemType() === 'android' || Utils.getSystemType() === 'harmonyos') && isMiniProgram) {
router.push({
name: 'previewPdf',
params: {
url: url,
},
})
} else {
location.href = url
}
return
}
} }
.product-item { function showTotalIntro() {
display: flex; showTotal.value = !showTotal.value
align-items: center; exchangeButton.value = !exchangeButton.value
padding: 14px 16px;
border-bottom: 1px solid #f5f5f5;
cursor: pointer;
} }
.product-item:last-child { // 点击关联问按钮发送问句
border-bottom: none; function richCallAnswer(item) {
const sendParmas = {
reqAndResType: '1', // 1文本 2图片 3问提评价
msgText: item.intent,
intentId: item.intentId,
msgSource: store?.manualService, // 1机器人 2人工
questionType:
props.itemlist?.reqAndResType == '02'
? 5
: props.itemlist?.reqAndResType == '06'
? 4
: props.itemlist?.reqAndResType == '11'
? 8
: '',
}
if (isBtnsubmit.value) {
isBtnsubmit.value = false
const request = store?.sendingRobot?.(sendParmas)
if (request && typeof request.then === 'function') {
request
.then(() => {
isBtnsubmit.value = true
})
.catch((err) => {
isBtnsubmit.value = true
console.log(err)
})
} else {
isBtnsubmit.value = true
}
}
} }
.product-item:active { function showGraph(item) {
background: #f9f9f9; popUpFlag.value = true
nowPopType.value = 'tkyw'
detaillTitle.value = item.key
tkywValue.value = String(item.tkywValue || '').replace(/(\n)/g, '<br/>')
} }
</script>
.product-icon { <style lang="scss" scoped>
width: 40px; .hiddenMore {
height: 40px; height: 205px;
margin-right: 12px;
} }
.product-icon img { .product_body {
line-height: normal;
letter-spacing: 0.5px;
word-break: break-all;
word-wrap: break-word;
width: 100%; width: 100%;
height: 100%; position: relative;
border-radius: 8px; margin-bottom: 6px;
object-fit: cover;
} .bg_white {
background: #fff;
border-radius: 16px;
overflow: hidden;
}
.product_top {
color: #fff;
border-bottom: #f0ecec 0.01rem solid;
.title_body {
font-size: 13px;
width: 100%;
min-height: 0.5rem;
background-image: url('../../assets/images/product/banner.png');
background-size: cover;
background-repeat: no-repeat;
border-radius: 0.36rem 0.36rem 0 0;
padding: 0.3rem 0 0.3rem 0.36rem;
display: flex;
align-items: center;
.title {
font-size: 15px;
display: flex;
align-items: center;
font-weight: 500;
position: relative;
.text_content {
transform: scale(1, 1.05);
max-width: 270px;
}
.mark {
font-size: 12px;
background: #fff;
letter-spacing: 0px;
color: #4f95fd;
padding: 0px 4px 0px 4px;
border-radius: 5px 5px 5px 0px;
font-weight: 700;
position: absolute;
top: 1px;
right: -4px;
transform: translate(100%, 0%);
}
}
}
.labels_body {
padding: 0.25rem 0.36rem 0.25rem 0.36rem;
display: flex;
flex-direction: column;
.label {
display: flex;
align-items: center;
img {
width: 0.5rem;
height: 0.5rem;
margin-right: 10px;
}
span {
flex: 1;
font-size: 12px;
color: #777777;
letter-spacing: 0.1px;
}
}
}
.label:nth-child(n):not(:last-child) {
margin-bottom: 5px;
}
}
.product_exemption {
font-size: 12px;
color: red;
font-weight: 700;
margin-top: 11px;
padding-left: 16px;
letter-spacing: 0px;
}
.product_main {
padding: 0.31rem 0rem;
.product_modules {
.base_module {
background: #fef8ed;
background-image: url('../../assets/images/product/base.png');
background-size: 65px;
background-repeat: no-repeat;
background-position: top right;
padding: 0.36rem;
border-radius: 0.3rem;
margin-bottom: 11px;
letter-spacing: 0;
}
.more_module {
border-radius: 0.3rem;
.top_right_bg {
background-image: url('../../assets/images/product/more.png');
background-size: 65px;
background-repeat: no-repeat;
background-position: top right;
padding: 0.36rem;
border-radius: 0.3rem;
letter-spacing: 0;
}
background: #edf4ff;
background-image: url('../../assets/images/product/productBg.png');
background-size: 470px;
background-repeat: no-repeat;
background-position: top right;
.tip {
color: #aaa;
text-align: right;
font-size: 12px;
}
}
.list {
color: #5b5b5b;
display: flex;
line-height: 18px;
.list_label {
width: 80px;
font-weight: 700;
font-size: 14px;
color: #000;
}
.list_content {
flex: 1;
font-weight: 400;
font-size: 14px;
display: flex;
align-items: center;
word-break: normal;
word-wrap: normal;
.value {
max-width: 168px;
}
.noBtn {
max-width: unset !important;
}
.more_text {
margin-right: 5px;
font-size: 14px;
font-weight: 400;
}
.more_button {
font-weight: 400;
background: #ddeaff;
color: #4f95fd;
display: inline-block;
padding: 0.13rem 0.55rem 0.13rem 0.18rem;
margin: 2px 0;
font-size: 13px;
border-radius: 11px;
position: relative;
line-height: initial;
}
.more_button::after {
content: "";
width: 0.35rem;
height: 0.35rem;
background-image: url('../../assets/images/product/arrow.png');
background-repeat: no-repeat;
background-size: contain;
position: absolute;
right: 4%;
top: 50%;
transform: translate(0, -50%);
}
}
.tkk_btn {
border-radius: 11px;
border: 1px solid #d4d8dc;
font-size: 12px;
padding: 1px 6px;
color: #4661f4;
white-space: nowrap;
margin-left: 7px;
}
}
.list:nth-child(1) {
padding-right: 20px;
}
.list:nth-child(n):not(:last-child) {
margin-bottom: 15px;
}
.top_right_bg > .list:nth-child(n):not(:last-child) {
margin-bottom: 10px;
}
.top_right_bg > .list {
flex-direction: column;
.list_content {
font-size: 14px;
}
.product-info { .list_label {
flex: 1; min-width: unset;
width: unset;
line-height: 18px;
margin-bottom: 7px;
.list_label_span {
font-weight: 700;
border-bottom: 1px solid #000;
}
}
}
.top_right_bg {
.more_button:nth-child(n):not(:last-child) {
margin-right: 5px;
}
}
}
}
.product_bottom {
padding-left: 0.3rem;
.bottom_modules {
width: 100%;
overflow-x: auto;
white-space: nowrap;
.img_module:nth-child(n):not(:last-child) {
margin-right: 8px;
}
.min_witch {
width: 28% !important;
}
.img_module {
width: 30%;
height: 50px;
border-radius: 8px;
display: inline-block;
img {
width: 100%;
height: 100%;
}
}
}
.bottom_modules::-webkit-scrollbar {
display: none;
}
}
.questions {
padding: 0rem 0.36rem 0.31rem 0.36rem;
}
} }
.product-title { .hidden_more {
font-size: 14px; height: 175px !important;
color: #333;
font-weight: 500;
} }
.product-subtitle { .noHidden {
font-size: 12px; height: unset !important;
color: #999; padding-bottom: 15px;
margin-top: 4px;
} }
.product-arrow { .detaill_body {
color: #ccc; font-size: 18px;
padding: 10px 16px;
background-size: 5rem;
background-repeat: no-repeat;
background-position: 66% 100%;
height: 100%;
.detaill_title {
font-size: 20px;
font-weight: 600;
letter-spacing: 1px;
margin-bottom: 20px;
position: relative;
&::after {
content: " ";
position: absolute;
bottom: -6px;
left: 0;
width: 75%;
height: 1px;
background: #d2d2d7;
}
}
.detaill_content {
word-break: break-all;
line-height: 30px;
text-indent: 29px;
}
} }
</style> </style>

@ -12,6 +12,12 @@ const router = createRouter({
component: () => import('../views/history.vue'), component: () => import('../views/history.vue'),
meta: { title: '洋洋客服-历史记录查询' }, meta: { title: '洋洋客服-历史记录查询' },
}, },
{
path: '/previewPdf',
name: 'previewPdf',
component: () => import('../components/previewPDF/index.vue'),
meta: { title: '预览PDF' },
},
// { path: '/uploadPage', name: 'uploadPage', component: () => import('../views/uploadPage.vue') }, // { path: '/uploadPage', name: 'uploadPage', component: () => import('../views/uploadPage.vue') },
// { path: '/claimPage', name: 'claimPage', component: () => import('../views/claimPage/index.vue'), }, // { path: '/claimPage', name: 'claimPage', component: () => import('../views/claimPage/index.vue'), },
// { path: '/outView', name: 'outView', component: () => import('../views/outView.vue') }, // { path: '/outView', name: 'outView', component: () => import('../views/outView.vue') },

Loading…
Cancel
Save