2026-01-26 15:55:13 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<view class="bubble-container" :class="{ 'mine': isMine, 'other': !isMine }">
|
2026-07-19 16:08:04 +08:00
|
|
|
|
<!-- 头像:非己方可点进医生详情 -->
|
|
|
|
|
|
<image class="avatar" :src="avatar" mode="aspectFill" @click.stop="onAvatarClick"></image>
|
2026-01-26 15:55:13 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 消息内容包裹 -->
|
|
|
|
|
|
<view class="content-wrapper">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 文本/语音/视频/图片 气泡 -->
|
|
|
|
|
|
<view class="message-bubble"
|
|
|
|
|
|
:class="['type-' + msg.message_type, { 'no-padding': isMediaOrCard || isSystemPriceUpdate }]"
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 0. 文本 -->
|
2026-05-06 16:41:19 +08:00
|
|
|
|
<text v-if="msg.message_type === 0" class="text-content" user-select="true">{{ parsedContent }}</text>
|
2026-01-26 15:55:13 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 1. 图片 -->
|
|
|
|
|
|
<image v-else-if="msg.message_type === 1"
|
|
|
|
|
|
:src="parsedContent"
|
|
|
|
|
|
mode="widthFix"
|
|
|
|
|
|
class="media-content image"
|
|
|
|
|
|
@click="$emit('previewImage', parsedContent)">
|
|
|
|
|
|
</image>
|
|
|
|
|
|
|
2026-02-02 16:10:46 +08:00
|
|
|
|
<!-- 2. 语音 (优化:动态宽度 + 播放动画) -->
|
|
|
|
|
|
<view v-else-if="msg.message_type === 2"
|
|
|
|
|
|
class="audio-content"
|
|
|
|
|
|
:style="{ width: getAudioWidth(msg.duration) }"
|
|
|
|
|
|
@click="$emit('playAudio', msg)">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 我发的:时长在左,图标在右 -->
|
2026-01-26 15:55:13 +08:00
|
|
|
|
<block v-if="isMine">
|
|
|
|
|
|
<text class="duration">{{ msg.duration }}''</text>
|
2026-02-02 16:10:46 +08:00
|
|
|
|
<view class="voice-icon-wrap mine" :class="{ 'playing': isPlaying }">
|
|
|
|
|
|
<u-icon name="volume-fill" size="20" color="#fff"></u-icon>
|
2026-01-26 15:55:13 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</block>
|
2026-02-02 16:10:46 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 别人发的:图标在左,时长在右 -->
|
2026-01-26 15:55:13 +08:00
|
|
|
|
<block v-else>
|
2026-02-02 16:10:46 +08:00
|
|
|
|
<view class="voice-icon-wrap other" :class="{ 'playing': isPlaying }">
|
|
|
|
|
|
<u-icon name="volume-fill" size="20" color="#333"></u-icon>
|
2026-01-26 15:55:13 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
<text class="duration">{{ msg.duration }}''</text>
|
|
|
|
|
|
</block>
|
2026-02-02 16:10:46 +08:00
|
|
|
|
|
2026-01-26 15:55:13 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 3. 视频 -->
|
|
|
|
|
|
<video v-else-if="msg.message_type === 3"
|
|
|
|
|
|
:src="parsedContent"
|
|
|
|
|
|
controls
|
|
|
|
|
|
class="media-content video">
|
|
|
|
|
|
</video>
|
|
|
|
|
|
|
2026-02-02 16:10:46 +08:00
|
|
|
|
<!-- 9. 系统消息 (优化:回归原生服务通知风格) -->
|
2026-01-26 15:55:13 +08:00
|
|
|
|
<block v-else-if="msg.message_type === 9">
|
2026-02-02 16:10:46 +08:00
|
|
|
|
<!-- 改价通知卡片 -->
|
|
|
|
|
|
<view
|
|
|
|
|
|
v-if="parsedContent.type === 'price_update' || parsedContent.type === 'price_adjust'"
|
|
|
|
|
|
class="service-notify-card"
|
|
|
|
|
|
@click="parsedContent.order_id && $emit('viewOrder', parsedContent.order_id, parsedContent.order_no)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<!-- 卡片头部 -->
|
|
|
|
|
|
<view class="sn-header">
|
|
|
|
|
|
<text class="sn-title">{{ parsedContent.type === 'price_update' ? '订单改价通知' : '费用调整提醒' }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 卡片内容区:标准键值对列表 -->
|
|
|
|
|
|
<view class="sn-body">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 场景A: 运费/总价更新 -->
|
|
|
|
|
|
<block v-if="parsedContent.type === 'price_update'">
|
|
|
|
|
|
<view class="sn-row">
|
|
|
|
|
|
<text class="sn-label">变动说明</text>
|
|
|
|
|
|
<text class="sn-value">{{ parsedContent.message }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="sn-row">
|
|
|
|
|
|
<text class="sn-label">最新应付</text>
|
|
|
|
|
|
<text class="sn-value price">¥{{ parsedContent.total_pay_price }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="sn-row">
|
|
|
|
|
|
<text class="sn-label">订单编号</text>
|
|
|
|
|
|
<text class="sn-value sub">{{ parsedContent.order_no }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</block>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 场景B: 单品/明细调整 -->
|
|
|
|
|
|
<block v-else-if="parsedContent.type === 'price_adjust'">
|
|
|
|
|
|
<view class="sn-row">
|
|
|
|
|
|
<text class="sn-label">调整项目</text>
|
|
|
|
|
|
<text class="sn-value truncate">{{ parsedContent.drug_name || '医疗服务' }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="sn-row">
|
|
|
|
|
|
<text class="sn-label">价格变动</text>
|
|
|
|
|
|
<view class="sn-value-group">
|
|
|
|
|
|
<text class="old">¥{{ parsedContent.old_price }}</text>
|
|
|
|
|
|
<u-icon name="arrow-right" size="10" color="#999" style="margin:0 4rpx;"></u-icon>
|
|
|
|
|
|
<text class="new">¥{{ parsedContent.new_price }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="sn-row">
|
|
|
|
|
|
<text class="sn-label">变动金额</text>
|
|
|
|
|
|
<text class="sn-value" :class="parsedContent.adjust_amount >= 0 ? 'color-orange' : 'color-green'">
|
|
|
|
|
|
{{ parsedContent.adjust_amount >= 0 ? '增加' : '减少' }} ¥{{ Math.abs(parsedContent.adjust_amount) }}
|
|
|
|
|
|
</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="sn-row">
|
|
|
|
|
|
<text class="sn-label">当前总额</text>
|
|
|
|
|
|
<text class="sn-value strong">¥{{ parsedContent.total_pay_price }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</block>
|
|
|
|
|
|
|
2026-01-26 15:55:13 +08:00
|
|
|
|
</view>
|
2026-02-02 16:10:46 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 底部操作栏 -->
|
|
|
|
|
|
<view class="sn-footer">
|
|
|
|
|
|
<text>查看详情</text>
|
|
|
|
|
|
<u-icon name="arrow-right" size="12" color="#ccc"></u-icon>
|
2026-01-26 15:55:13 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
2026-02-02 16:10:46 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 普通系统文本 (保持原样) -->
|
2026-01-26 15:55:13 +08:00
|
|
|
|
<view v-else class="system-inner">
|
|
|
|
|
|
<text>{{ msg.message_content }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</block>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 卡片类消息 (4, 10, 11, 12, 13) -->
|
|
|
|
|
|
<view v-else-if="isCardType" class="card-content">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 类型10: 挂号 -->
|
|
|
|
|
|
<block v-if="msg.message_type === 10">
|
|
|
|
|
|
<view class="card-header bg-green">
|
|
|
|
|
|
<view class="title-group"><u-icon name="calendar-fill" size="16" color="#059669"></u-icon><text class="card-title">预约挂号</text></view>
|
|
|
|
|
|
<text class="status-tag" :class="'status-' + parsedContent.status">{{ getRegisterStatusText(parsedContent.status) }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="card-body">
|
|
|
|
|
|
<view class="info-row"><text class="label">订单号</text><text class="value order-font">{{ parsedContent.order_no }}</text></view>
|
|
|
|
|
|
<view class="info-row"><text class="label">就诊人</text><text class="value">{{ (parsedContent.user_patient && parsedContent.user_patient.name) || '未知' }}</text></view>
|
|
|
|
|
|
<view class="info-row highlight"><text class="label">费用</text><text class="value price">¥{{ parsedContent.price }}</text></view>
|
2026-05-06 16:41:19 +08:00
|
|
|
|
<view class="text-block" v-if="parsedContent.chief_complaint">
|
|
|
|
|
|
<text class="block-label">主诉</text>
|
|
|
|
|
|
<text class="block-content">{{ parsedContent.chief_complaint }}</text>
|
|
|
|
|
|
</view>
|
2026-07-19 16:08:04 +08:00
|
|
|
|
<view v-if="registerCardDrugRows.length" class="drug-list-block">
|
|
|
|
|
|
<text class="block-label">所选药品</text>
|
|
|
|
|
|
<view v-for="row in registerCardDrugRows" :key="row._wxKey" class="info-row drug-spec-row">
|
|
|
|
|
|
<image
|
|
|
|
|
|
v-if="row.image"
|
|
|
|
|
|
class="drug-thumb"
|
|
|
|
|
|
:src="row.image"
|
|
|
|
|
|
mode="aspectFill"
|
|
|
|
|
|
@click.stop="$emit('previewImage', row.image)"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<view class="drug-name-wrap">
|
|
|
|
|
|
<text class="label">{{ row.name || '药品' }}</text>
|
|
|
|
|
|
<text v-if="row.specification" class="spec-text">{{ row.specification }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<text class="value">×{{ row.quantity }}</text>
|
|
|
|
|
|
</view>
|
2026-05-06 16:41:19 +08:00
|
|
|
|
</view>
|
2026-01-26 15:55:13 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
<view class="card-footer"><button class="action-btn" @click="$emit('viewRegister', parsedContent.id)">查看详情</button></view>
|
|
|
|
|
|
</block>
|
|
|
|
|
|
|
2026-05-06 16:41:19 +08:00
|
|
|
|
<!-- 类型11: 复诊用药确认(扩展 flow,与药店购药 type11 互斥展示) -->
|
|
|
|
|
|
<block v-else-if="msg.message_type === 11 && parsedContent && parsedContent.flow === 'follow_up_drug'">
|
|
|
|
|
|
<view class="card-header bg-gray">
|
|
|
|
|
|
<view class="title-group"><u-icon name="question-circle-fill" size="16" color="#64748B"></u-icon><text class="card-title">医生助理</text></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="card-body">
|
|
|
|
|
|
<view class="text-block" v-if="parsedContent.question">
|
|
|
|
|
|
<text class="block-content">{{ parsedContent.question }}</text>
|
|
|
|
|
|
</view>
|
2026-07-07 08:50:17 +08:00
|
|
|
|
<view class="info-row" v-for="(row, idx) in (parsedContent.drugs || [])" :key="idx">
|
2026-05-06 16:41:19 +08:00
|
|
|
|
<text class="label">{{ row.name || '药品' }}</text>
|
|
|
|
|
|
<text class="value">×{{ row.quantity != null ? row.quantity : 1 }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view v-if="followUpAnsweredLabel" class="info-row">
|
|
|
|
|
|
<text class="label">您的选择</text>
|
|
|
|
|
|
<text class="value">{{ followUpAnsweredLabel }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view v-if="parsedContent.answer_status === 'pending'" class="follow-up-pending-readonly">
|
|
|
|
|
|
<text class="follow-up-pending-tip">请在挂号后的用药确认页完成选择,此处不可更改</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</block>
|
|
|
|
|
|
|
2026-01-26 15:55:13 +08:00
|
|
|
|
<!-- 类型11: 患者就诊经历 -->
|
|
|
|
|
|
<block v-else-if="msg.message_type === 11">
|
|
|
|
|
|
<view class="card-header bg-gray">
|
|
|
|
|
|
<view class="title-group"><u-icon name="file-text-fill" size="16" color="#64748B"></u-icon><text class="card-title">患者就诊经历</text></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="card-body">
|
|
|
|
|
|
<view class="info-row" v-if="parsedContent.drug_name">
|
|
|
|
|
|
<text class="label">药品名称</text>
|
|
|
|
|
|
<text class="value">{{ parsedContent.drug_name }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="text-block" v-if="parsedContent.illness_info">
|
|
|
|
|
|
<text class="block-label">症状描述</text>
|
|
|
|
|
|
<text class="block-content">{{ parsedContent.illness_info }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="info-row"><text class="label">是否就诊过</text><text class="value">{{ parsedContent.has_visited === '1' ? '是' : '否' }}</text></view>
|
|
|
|
|
|
<view class="info-row"><text class="label">是否使用过药品</text><text class="value">{{ parsedContent.has_used_drug === '1' ? '是' : '否' }}</text></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</block>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 类型4: 电子处方 -->
|
|
|
|
|
|
<block v-else-if="msg.message_type === 4">
|
|
|
|
|
|
<view class="card-header bg-blue">
|
|
|
|
|
|
<view class="title-group"><u-icon name="order" size="16" color="#0A84FF"></u-icon><text class="card-title">电子处方</text></view>
|
|
|
|
|
|
<text class="status-tag blue">{{ getStatusText(parsedContent.status) }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="card-body">
|
|
|
|
|
|
<view class="info-row"><text class="label">诊断单号</text><text class="value small">{{ parsedContent.order_no }}</text></view>
|
|
|
|
|
|
<view class="info-row"><text class="label">金额</text><text class="value price">¥{{ parsedContent.total_pay_price }}</text></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="card-footer split">
|
|
|
|
|
|
<text class="link-btn" @click="$emit('viewPrescription', parsedContent.id, parsedContent.order_no)">详情</text>
|
|
|
|
|
|
<button class="action-btn primary" @click="$emit('goToOrderMedicine', parsedContent.order_id, parsedContent.order_no)">一键购药</button>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</block>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 类型12: 商品 -->
|
|
|
|
|
|
<block v-else-if="msg.message_type === 12">
|
|
|
|
|
|
<view class="card-header bg-blue">
|
|
|
|
|
|
<view class="title-group"><u-icon name="shopping-cart-fill" size="16" color="#0A84FF"></u-icon><text class="card-title">推荐商品</text></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="card-body">
|
|
|
|
|
|
<view class="info-row"><text class="label">名称</text><text class="value">{{ parsedContent.product_name }}</text></view>
|
|
|
|
|
|
<view class="info-row"><text class="label">价格</text><text class="value price">¥{{ parsedContent.price }}</text></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</block>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 类型13: 结束问诊 -->
|
|
|
|
|
|
<block v-else-if="msg.message_type === 13">
|
|
|
|
|
|
<view class="card-header bg-green">
|
|
|
|
|
|
<view class="title-group"><u-icon name="checkmark-circle-fill" size="16" color="#059669"></u-icon><text class="card-title">问诊结束</text></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="card-body">
|
|
|
|
|
|
<text class="desc-text">{{ parsedContent.reason || '本次服务已完成' }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</block>
|
|
|
|
|
|
|
2026-02-07 09:42:08 +08:00
|
|
|
|
<!-- 类型14: 转诊消息 -->
|
|
|
|
|
|
<block v-else-if="msg.message_type === 14">
|
|
|
|
|
|
<TransferMessageBubble
|
|
|
|
|
|
:message-data="parsedContent"
|
|
|
|
|
|
@agree="handleTransferAgree"
|
|
|
|
|
|
@reject="handleTransferReject"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</block>
|
|
|
|
|
|
|
2026-01-26 15:55:13 +08:00
|
|
|
|
<block v-else>
|
|
|
|
|
|
<view class="card-body"><text>不支持的消息类型</text></view>
|
|
|
|
|
|
</block>
|
|
|
|
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 其他未知类型默认显示文本 -->
|
|
|
|
|
|
<text v-else class="text-content">{{ parsedContent }}</text>
|
|
|
|
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
2026-02-07 09:42:08 +08:00
|
|
|
|
import TransferMessageBubble from './TransferMessageBubble.vue'
|
|
|
|
|
|
import {
|
|
|
|
|
|
agreeTransferPrescriptionApi,
|
|
|
|
|
|
rejectTransferPrescriptionApi
|
|
|
|
|
|
} from '@/request/api/transferPrescription'
|
2026-01-26 15:55:13 +08:00
|
|
|
|
export default {
|
|
|
|
|
|
name: "MessageBubble",
|
2026-02-07 09:42:08 +08:00
|
|
|
|
components: {
|
|
|
|
|
|
TransferMessageBubble
|
|
|
|
|
|
},
|
2026-01-26 15:55:13 +08:00
|
|
|
|
props: {
|
|
|
|
|
|
msg: {
|
|
|
|
|
|
type: Object,
|
|
|
|
|
|
required: true
|
|
|
|
|
|
},
|
|
|
|
|
|
isMine: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: false
|
|
|
|
|
|
},
|
|
|
|
|
|
avatar: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: ''
|
|
|
|
|
|
},
|
|
|
|
|
|
isPlaying: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: false
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
// 纯文本、图片、语音、视频以外的特殊类型,不需要默认的气泡背景/Padding
|
|
|
|
|
|
isMediaOrCard() {
|
2026-02-07 09:42:08 +08:00
|
|
|
|
// 1:图片, 3:视频, 4,10,11,12,13,14: 卡片 (9单独处理)
|
|
|
|
|
|
return [1, 3, 4, 10, 11, 12, 13, 14].includes(this.msg.message_type);
|
2026-01-26 15:55:13 +08:00
|
|
|
|
},
|
|
|
|
|
|
// 是否是系统消息且为价格变动(需要独立卡片样式)
|
|
|
|
|
|
isSystemPriceUpdate() {
|
2026-02-02 16:10:46 +08:00
|
|
|
|
return this.msg.message_type === 9 && (this.parsedContent.type === 'price_update' || this.parsedContent.type === 'price_adjust');
|
2026-01-26 15:55:13 +08:00
|
|
|
|
},
|
|
|
|
|
|
isCardType() {
|
2026-02-07 09:42:08 +08:00
|
|
|
|
return [4, 10, 11, 12, 13, 14].includes(this.msg.message_type);
|
2026-01-26 15:55:13 +08:00
|
|
|
|
},
|
|
|
|
|
|
parsedContent() {
|
|
|
|
|
|
const { message_type, message_content } = this.msg;
|
|
|
|
|
|
// 包含9(System)在内的复杂类型尝试解析 JSON
|
2026-02-07 09:42:08 +08:00
|
|
|
|
if ([4, 9, 10, 11, 12, 13, 14].includes(message_type)) {
|
2026-01-26 15:55:13 +08:00
|
|
|
|
try {
|
|
|
|
|
|
return typeof message_content === 'object' ? message_content : JSON.parse(message_content);
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
return message_content;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return message_content;
|
2026-05-06 16:41:19 +08:00
|
|
|
|
},
|
2026-07-19 16:08:04 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 预约挂号卡片药品行:药名 + 规格 + 数量(与医生端一致,去掉底部「各 X 盒」)
|
|
|
|
|
|
*/
|
|
|
|
|
|
registerCardDrugRows() {
|
|
|
|
|
|
if (this.msg.message_type !== 10) return [];
|
2026-05-06 16:41:19 +08:00
|
|
|
|
const pc = this.parsedContent;
|
2026-07-19 16:08:04 +08:00
|
|
|
|
if (!pc || typeof pc !== 'object') return [];
|
|
|
|
|
|
const fallbackQty = pc.number != null && pc.number !== '' ? Number(pc.number) : 1;
|
2026-05-06 16:41:19 +08:00
|
|
|
|
const arr = pc.selected_western_drugs;
|
|
|
|
|
|
if (Array.isArray(arr) && arr.length) {
|
2026-07-19 16:08:04 +08:00
|
|
|
|
return arr.map((d, idx) => {
|
|
|
|
|
|
const q = d && d.quantity != null ? Number(d.quantity) : fallbackQty;
|
|
|
|
|
|
const id = d && (d.drug_id || d.id);
|
|
|
|
|
|
return {
|
|
|
|
|
|
_wxKey: 'rd-' + (id != null ? id : idx),
|
|
|
|
|
|
name: (d && d.name) || '',
|
|
|
|
|
|
specification: (d && (d.specification || d.spec || d.drug_spec)) || '',
|
|
|
|
|
|
image: (d && (d.image || d.drug_image)) || '',
|
|
|
|
|
|
quantity: q >= 1 ? q : 1,
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
2026-05-06 16:41:19 +08:00
|
|
|
|
}
|
2026-07-19 16:08:04 +08:00
|
|
|
|
if (pc.drug && pc.drug.name) {
|
|
|
|
|
|
return [{
|
|
|
|
|
|
_wxKey: 'rd-' + (pc.drug.drug_id || pc.drug.id || 0),
|
|
|
|
|
|
name: pc.drug.name,
|
|
|
|
|
|
specification: pc.drug.specification || pc.drug.spec || '',
|
|
|
|
|
|
image: pc.drug.image || pc.drug.drug_image || '',
|
|
|
|
|
|
quantity: fallbackQty >= 1 ? fallbackQty : 1,
|
|
|
|
|
|
}];
|
|
|
|
|
|
}
|
|
|
|
|
|
return [];
|
2026-05-06 16:41:19 +08:00
|
|
|
|
},
|
|
|
|
|
|
followUpAnsweredLabel() {
|
|
|
|
|
|
const pc = this.parsedContent;
|
|
|
|
|
|
if (!pc || pc.flow !== 'follow_up_drug') return '';
|
|
|
|
|
|
const st = pc.answer_status;
|
|
|
|
|
|
if (st === 'yes' || st === '1') return '是,曾使用过';
|
|
|
|
|
|
if (st === 'no' || st === '0') return '否,未使用过';
|
|
|
|
|
|
return '';
|
2026-01-26 15:55:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
2026-07-19 16:08:04 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 非己方头像点击:通知父页跳转医生详情;己方头像不响应
|
|
|
|
|
|
*/
|
|
|
|
|
|
onAvatarClick() {
|
|
|
|
|
|
if (this.isMine) return;
|
|
|
|
|
|
this.$emit('avatarClick');
|
|
|
|
|
|
},
|
2026-02-02 16:10:46 +08:00
|
|
|
|
// 计算语音条宽度 (Min: 100rpx, Max: 350rpx, Unit: 10rpx/sec)
|
|
|
|
|
|
getAudioWidth(duration) {
|
|
|
|
|
|
const min = 120;
|
|
|
|
|
|
const max = 350;
|
|
|
|
|
|
const unit = 12;
|
|
|
|
|
|
let w = min + (parseInt(duration) || 0) * unit;
|
|
|
|
|
|
return Math.min(w, max) + 'rpx';
|
|
|
|
|
|
},
|
2026-01-26 15:55:13 +08:00
|
|
|
|
getStatusText(status) { const map = { 0: '待审核', 1: '已审核', 2: '未通过' }; return map[status] || '状态未知'; },
|
|
|
|
|
|
getRegisterStatusText(status) { const map = { 0: '待就诊', 1: '已缴费', 2: '已就诊', 3: '已取消', 4: '已退费' }; return map[status] || '状态未知'; },
|
2026-02-07 09:42:08 +08:00
|
|
|
|
// 处理转诊同意
|
|
|
|
|
|
handleTransferAgree(messageData) {
|
|
|
|
|
|
if (!messageData || !messageData.transfer_id) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '转诊信息不完整',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uni.showModal({
|
|
|
|
|
|
title: '确认转诊',
|
|
|
|
|
|
content: '确定同意转诊吗?',
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
|
agreeTransferPrescriptionApi({ id: messageData.transfer_id }).then((result) => {
|
|
|
|
|
|
if (result.data.code == 0) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '同意转诊成功',
|
|
|
|
|
|
icon: 'success'
|
|
|
|
|
|
})
|
2026-02-07 14:17:30 +08:00
|
|
|
|
// 跳转到咨询页面
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
uni.redirectTo({
|
|
|
|
|
|
url: `/subPackages/transfer/transfer-consultation?transfer_id=${messageData.transfer_id}`,
|
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
|
console.error('跳转失败:', err)
|
|
|
|
|
|
uni.showToast({ title: '跳转失败,请重试', icon: 'none' })
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}, 1000)
|
2026-02-07 09:42:08 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: result.data.message || '操作失败',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}).catch((error) => {
|
|
|
|
|
|
console.error('同意转诊失败:', error)
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '操作失败,请重试',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
// 处理转诊拒绝
|
|
|
|
|
|
handleTransferReject(messageData) {
|
|
|
|
|
|
if (!messageData || !messageData.transfer_id) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '转诊信息不完整',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uni.showModal({
|
|
|
|
|
|
title: '拒绝转诊',
|
|
|
|
|
|
content: '确定拒绝转诊吗?',
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
|
rejectTransferPrescriptionApi({ id: messageData.transfer_id }).then((result) => {
|
|
|
|
|
|
if (result.data.code == 0) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '已拒绝转诊',
|
|
|
|
|
|
icon: 'success'
|
|
|
|
|
|
})
|
|
|
|
|
|
// 触发消息更新事件
|
|
|
|
|
|
uni.$emit('chat-message-update')
|
|
|
|
|
|
} else {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: result.data.message || '操作失败',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}).catch((error) => {
|
|
|
|
|
|
console.error('拒绝转诊失败:', error)
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '操作失败,请重试',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2026-01-26 15:55:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
// 变量
|
|
|
|
|
|
$primary: #0A84FF;
|
|
|
|
|
|
$bg-mine: #0A84FF;
|
|
|
|
|
|
$bg-other: #FFFFFF;
|
|
|
|
|
|
$text-main: #333333;
|
|
|
|
|
|
$text-sub: #666666;
|
|
|
|
|
|
$radius-bubble: 12rpx;
|
2026-02-02 16:10:46 +08:00
|
|
|
|
$price-color: #FF4D4F; // 价格红
|
|
|
|
|
|
$success-color: #059669;
|
2026-01-26 15:55:13 +08:00
|
|
|
|
|
|
|
|
|
|
.bubble-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
margin-bottom: 30rpx;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
|
|
|
|
.avatar {
|
|
|
|
|
|
width: 72rpx; height: 72rpx;
|
|
|
|
|
|
border-radius: 10rpx;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
background: #f2f2f2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.content-wrapper {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
max-width: 72%; // 稍微放宽一点
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.other {
|
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
.avatar { margin-right: 16rpx; }
|
|
|
|
|
|
.message-bubble {
|
|
|
|
|
|
background-color: $bg-other;
|
|
|
|
|
|
color: $text-main;
|
|
|
|
|
|
border-radius: 4rpx $radius-bubble $radius-bubble $radius-bubble;
|
|
|
|
|
|
|
|
|
|
|
|
// 添加小箭头
|
|
|
|
|
|
&::before {
|
|
|
|
|
|
content: ''; position: absolute; top: 20rpx; left: -10rpx;
|
|
|
|
|
|
width: 0; height: 0;
|
|
|
|
|
|
border-top: 10rpx solid transparent;
|
|
|
|
|
|
border-bottom: 10rpx solid transparent;
|
|
|
|
|
|
border-right: 12rpx solid $bg-other;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 卡片或特殊系统消息不需要箭头
|
|
|
|
|
|
&.no-padding::before { display: none; }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.mine {
|
|
|
|
|
|
flex-direction: row-reverse;
|
|
|
|
|
|
.avatar { margin-left: 16rpx; }
|
|
|
|
|
|
.message-bubble {
|
|
|
|
|
|
background-color: $bg-mine;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
border-radius: $radius-bubble 4rpx $radius-bubble $radius-bubble;
|
|
|
|
|
|
|
|
|
|
|
|
&::after {
|
|
|
|
|
|
content: ''; position: absolute; top: 20rpx; right: -10rpx;
|
|
|
|
|
|
width: 0; height: 0;
|
|
|
|
|
|
border-top: 10rpx solid transparent;
|
|
|
|
|
|
border-bottom: 10rpx solid transparent;
|
|
|
|
|
|
border-left: 12rpx solid $bg-mine;
|
|
|
|
|
|
}
|
|
|
|
|
|
&.no-padding::after { display: none; }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-bubble {
|
|
|
|
|
|
padding: 18rpx 24rpx;
|
|
|
|
|
|
font-size: 30rpx;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
|
box-shadow: 0 2rpx 4rpx rgba(0,0,0,0.05);
|
|
|
|
|
|
min-height: 72rpx;
|
|
|
|
|
|
display: flex; align-items: center;
|
|
|
|
|
|
|
|
|
|
|
|
&.no-padding {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
&::before, &::after { display: none; }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 图片/视频
|
|
|
|
|
|
.media-content {
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
&.image { max-width: 300rpx; display: block; }
|
|
|
|
|
|
&.video { width: 300rpx; height: 170rpx; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-02 16:10:46 +08:00
|
|
|
|
// ========== 语音条样式 (Audio) ==========
|
2026-01-26 15:55:13 +08:00
|
|
|
|
.audio-content {
|
2026-02-02 16:10:46 +08:00
|
|
|
|
display: flex; align-items: center;
|
|
|
|
|
|
// 宽度由 style 动态控制,这里不要锁死 width
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
|
|
|
|
|
|
.duration {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.voice-icon-wrap {
|
|
|
|
|
|
display: flex; align-items: center; justify-content: center;
|
|
|
|
|
|
width: 44rpx; height: 44rpx;
|
|
|
|
|
|
|
|
|
|
|
|
// 对方发的消息,图标在左,波纹向右(默认)
|
|
|
|
|
|
&.other {
|
|
|
|
|
|
margin-right: 6rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 我发的消息,图标在右,波纹需要转向左侧 (rotate 180)
|
|
|
|
|
|
&.mine {
|
|
|
|
|
|
margin-left: 6rpx;
|
|
|
|
|
|
transform: rotate(180deg);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 播放时的动画:呼吸/波动效果
|
|
|
|
|
|
&.playing {
|
|
|
|
|
|
animation: voice-pulse 1.2s infinite ease-in-out;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 语音播放动画关键帧
|
|
|
|
|
|
@keyframes voice-pulse {
|
|
|
|
|
|
0% { opacity: 1; transform: scale(1) rotate(var(--rotate-angle, 0deg)); }
|
|
|
|
|
|
50% { opacity: 0.4; transform: scale(0.92) rotate(var(--rotate-angle, 0deg)); }
|
|
|
|
|
|
100% { opacity: 1; transform: scale(1) rotate(var(--rotate-angle, 0deg)); }
|
2026-01-26 15:55:13 +08:00
|
|
|
|
}
|
2026-02-02 16:10:46 +08:00
|
|
|
|
// 为了解决 rotate 和 scale 同时作用的问题,分别定义 mine 和 other
|
|
|
|
|
|
.voice-icon-wrap.mine.playing { --rotate-angle: 180deg; animation: voice-pulse 1.2s infinite ease-in-out; }
|
|
|
|
|
|
.voice-icon-wrap.other.playing { --rotate-angle: 0deg; animation: voice-pulse 1.2s infinite ease-in-out; }
|
2026-01-26 15:55:13 +08:00
|
|
|
|
|
2026-02-02 16:10:46 +08:00
|
|
|
|
|
|
|
|
|
|
// ========== 卡片样式 (通用) ==========
|
2026-01-26 15:55:13 +08:00
|
|
|
|
.card-content {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
border: 1rpx solid #eee;
|
|
|
|
|
|
width: 480rpx; // 卡片定宽
|
|
|
|
|
|
|
|
|
|
|
|
.card-header {
|
|
|
|
|
|
padding: 16rpx 20rpx;
|
|
|
|
|
|
display: flex; justify-content: space-between; align-items: center;
|
|
|
|
|
|
border-bottom: 1rpx solid #f9f9f9;
|
|
|
|
|
|
|
|
|
|
|
|
&.bg-green { background: #F0FDF4; }
|
|
|
|
|
|
&.bg-blue { background: #EFF6FF; }
|
|
|
|
|
|
&.bg-gray { background: #F8FAFC; }
|
|
|
|
|
|
|
|
|
|
|
|
.title-group { display: flex; align-items: center; gap: 8rpx; .card-title { font-size: 26rpx; font-weight: 600; color: #333; } }
|
|
|
|
|
|
.status-tag { font-size: 20rpx; padding: 2rpx 10rpx; border-radius: 6rpx; background: #fff; color: $text-sub; border: 1rpx solid rgba(0,0,0,0.05); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-body {
|
|
|
|
|
|
padding: 20rpx; display: flex; flex-direction: column; gap: 12rpx;
|
|
|
|
|
|
.info-row {
|
|
|
|
|
|
display: flex; justify-content: space-between; font-size: 24rpx;
|
|
|
|
|
|
.label { color: #888; }
|
|
|
|
|
|
.value { color: #333; font-weight: 500; text-align: right; max-width: 70%; }
|
|
|
|
|
|
.order-font { font-family: Courier, monospace; letter-spacing: 0.5rpx; }
|
|
|
|
|
|
.price { color: #ef4444; font-size: 28rpx; font-weight: bold; }
|
|
|
|
|
|
.small { font-size: 22rpx; color: #999; }
|
|
|
|
|
|
}
|
2026-07-19 16:08:04 +08:00
|
|
|
|
.drug-spec-row {
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
.drug-thumb {
|
|
|
|
|
|
width: 64rpx;
|
|
|
|
|
|
height: 64rpx;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
background: #f3f4f6;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
margin-right: 12rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
.drug-name-wrap {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
gap: 4rpx;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.spec-text {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
font-size: 22rpx;
|
|
|
|
|
|
color: #9ca3af;
|
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.drug-list-block {
|
|
|
|
|
|
.block-label {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
font-size: 22rpx;
|
|
|
|
|
|
color: #888;
|
|
|
|
|
|
margin-bottom: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-26 15:55:13 +08:00
|
|
|
|
.desc-text { font-size: 26rpx; color: #333; }
|
|
|
|
|
|
.text-block {
|
|
|
|
|
|
background: #f5f5f5; padding: 16rpx; border-radius: 8rpx;
|
|
|
|
|
|
.block-label { display: block; font-size: 22rpx; color: #999; margin-bottom: 6rpx; }
|
|
|
|
|
|
.block-content { font-size: 26rpx; color: #333; line-height: 1.4; }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-footer {
|
|
|
|
|
|
padding: 16rpx 20rpx; border-top: 1rpx solid #f0f0f0;
|
|
|
|
|
|
.action-btn {
|
|
|
|
|
|
width: 100%; height: 60rpx; line-height: 60rpx; font-size: 26rpx; border-radius: 30rpx; background: #fff; border: 1rpx solid #ddd; color: #555;
|
|
|
|
|
|
&.primary { background: $primary; color: #fff; border: none; }
|
|
|
|
|
|
&::after { border: none; }
|
|
|
|
|
|
}
|
|
|
|
|
|
&.split { display: flex; justify-content: space-between; align-items: center; .link-btn { font-size: 24rpx; color: $primary; padding: 10rpx; } .action-btn { width: 160rpx; } }
|
|
|
|
|
|
}
|
2026-05-06 16:41:19 +08:00
|
|
|
|
|
|
|
|
|
|
.follow-up-pending-readonly {
|
|
|
|
|
|
margin-top: 12rpx;
|
|
|
|
|
|
padding: 16rpx 20rpx;
|
|
|
|
|
|
background: #f7f8fa;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
.follow-up-pending-tip {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-26 15:55:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-02 16:10:46 +08:00
|
|
|
|
// ========== 原生风格服务通知 (Service Notify Card) ==========
|
|
|
|
|
|
// 这是一个非常经典、耐看的布局,模仿微信/支付宝的服务通知
|
|
|
|
|
|
.service-notify-card {
|
|
|
|
|
|
background: #FFFFFF;
|
|
|
|
|
|
border-radius: 12rpx; // 稍微调小圆角,更正式
|
|
|
|
|
|
width: 480rpx;
|
|
|
|
|
|
border: 1rpx solid #eaeaea; // 纯粹的边框
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
|
|
// 头部:极简
|
|
|
|
|
|
.sn-header {
|
|
|
|
|
|
padding: 24rpx 24rpx 16rpx 24rpx;
|
|
|
|
|
|
border-bottom: 1rpx solid #f5f5f5;
|
|
|
|
|
|
.sn-title {
|
|
|
|
|
|
font-size: 30rpx;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 内容区:标准的左key右value列表
|
|
|
|
|
|
.sn-body {
|
|
|
|
|
|
padding: 20rpx 24rpx;
|
|
|
|
|
|
display: flex; flex-direction: column; gap: 16rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.sn-row {
|
|
|
|
|
|
display: flex; justify-content: space-between; align-items: flex-start;
|
|
|
|
|
|
line-height: 1.4;
|
|
|
|
|
|
|
|
|
|
|
|
.sn-label {
|
|
|
|
|
|
font-size: 26rpx; color: #999; // 经典的标签灰
|
|
|
|
|
|
min-width: 110rpx; // 保证对齐
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sn-value {
|
|
|
|
|
|
font-size: 26rpx; color: #333; text-align: right; flex: 1;
|
|
|
|
|
|
&.truncate {
|
|
|
|
|
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 320rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
&.price { color: #333; font-weight: 600; font-size: 28rpx; } // 普通金额强调
|
|
|
|
|
|
&.sub { color: #999; font-family: monospace; }
|
|
|
|
|
|
&.strong { color: #333; font-weight: bold; font-size: 30rpx; }
|
|
|
|
|
|
|
|
|
|
|
|
// 涨跌颜色
|
|
|
|
|
|
&.color-orange { color: #fa8c16; }
|
|
|
|
|
|
&.color-green { color: #52c41a; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 价格变化组合
|
|
|
|
|
|
.sn-value-group {
|
|
|
|
|
|
display: flex; align-items: center; justify-content: flex-end;
|
|
|
|
|
|
.old { color: #999; text-decoration: line-through; font-size: 24rpx; }
|
|
|
|
|
|
.new { color: #333; font-weight: 600; font-size: 26rpx; }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 底部:通用的查看详情
|
|
|
|
|
|
.sn-footer {
|
|
|
|
|
|
border-top: 1rpx solid #f5f5f5;
|
|
|
|
|
|
padding: 18rpx 24rpx;
|
|
|
|
|
|
display: flex; justify-content: space-between; align-items: center;
|
|
|
|
|
|
font-size: 24rpx; color: #666;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
background: #f9f9f9; // 仅底栏有点击态
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-26 15:55:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.system-inner {
|
|
|
|
|
|
background: rgba(0,0,0,0.05); padding: 8rpx 20rpx; border-radius: 10rpx; font-size: 22rpx; color: #999; align-self: center; margin: 0 auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|