| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- <template>
- <view v-if="visible" class="agreement-card">
- <view class="agreement-card__inner" @click="toggle">
- <view :class="['agreement-card__box', { 'agreement-card__box--on': modelValue }]">
- <u-icon v-if="modelValue" name="checkmark" color="#fff" size="12" />
- </view>
- <view class="agreement-card__text">
- <template v-if="useStructured">
- <text class="agreement-card__plain">我已阅读并同意</text>
- <text
- v-if="hasContent"
- class="agreement-card__link"
- @click.stop="openPopup"
- >《{{ agreementTitle }}》</text>
- <!-- <text v-if="displayVersion" class="agreement-card__ver">{{ displayVersion }}</text> -->
- </template>
- <text v-else class="agreement-card__fallback">{{ checkboxLabel }}</text>
- </view>
- </view>
- <!-- <text v-if="hasContent && useStructured" class="agreement-card__action" @click="openPopup">
- 查看全文
- </text> -->
- <u-popup :show="popupShow" mode="bottom" round="16" @close="popupShow = false">
- <view class="agreement-popup">
- <view class="agreement-popup__head">
- <text class="agreement-popup__title">{{ agreementTitle || '服务协议' }}</text>
- <u-icon name="close" size="20" @click="popupShow = false" />
- </view>
- <scroll-view v-if="popupShow" class="agreement-popup__scroll" scroll-y>
- <rich-text class="agreement-rich" :nodes="richHtml" />
- </scroll-view>
- </view>
- </u-popup>
- </view>
- </template>
- <script setup>
- import { ref, computed } from 'vue'
- import { prepareRichHtml } from '@/utils/htmlContent'
- const props = defineProps({
- modelValue: { type: Boolean, default: false },
- checkboxLabel: { type: String, default: '我已阅读并同意相关服务协议' },
- agreementTitle: { type: String, default: '' },
- versionLabel: { type: String, default: '' },
- content: { type: String, default: '' },
- enabled: { type: Boolean, default: true }
- })
- const emit = defineEmits(['update:modelValue'])
- const popupShow = ref(false)
- const visible = computed(() => props.enabled)
- const hasContent = computed(() => !!(props.content || '').trim())
- /** 有协议标题时用分行排版,避免整段 checkboxLabel 撑破布局 */
- const useStructured = computed(() => !!(props.agreementTitle || '').trim())
- /**
- * 与商品详情一致用 rich-text 渲染 HTML(平台 Quill 输出)
- * up-parse 在 Vue3 下内部仍用 this.$set,易出现标签被当纯文本显示
- */
- const richHtml = computed(() => prepareRichHtml(props.content))
- function toggle() {
- emit('update:modelValue', !props.modelValue)
- }
- function openPopup() {
- if (hasContent.value) {
- popupShow.value = true
- }
- }
- </script>
- <style lang="scss" scoped>
- .agreement-card {
- margin-top: 24rpx;
- // padding: 20rpx 24rpx;
- background: #f5faf6;
- border: 1rpx solid #e8f5e9;
- border-radius: 12rpx;
- box-sizing: border-box;
- }
- .agreement-card__inner {
- display: flex;
- align-items: flex-start;
- }
- .agreement-card__box {
- width: 36rpx;
- height: 36rpx;
- margin-top: 2rpx;
- margin-right: 16rpx;
- border: 2rpx solid #a5d6a7;
- border-radius: 8rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- flex-shrink: 0;
- background: #fff;
- }
- .agreement-card__box--on {
- background: #2e7d32;
- border-color: #2e7d32;
- }
- .agreement-card__text {
- flex: 1;
- min-width: 0;
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- line-height: 40rpx;
- }
- .agreement-card__plain,
- .agreement-card__ver {
- font-size: 24rpx;
- color: #666;
- }
- .agreement-card__ver {
- margin-left: 4rpx;
- }
- .agreement-card__link {
- font-size: 24rpx;
- color: #2e7d32;
- font-weight: 500;
- text-decoration: underline;
- }
- .agreement-card__fallback {
- font-size: 24rpx;
- color: #666;
- line-height: 1.6;
- word-break: break-all;
- white-space: normal;
- }
- .agreement-card__action {
- display: block;
- margin-top: 12rpx;
- margin-left: 52rpx;
- font-size: 24rpx;
- color: #43a047;
- }
- .agreement-popup {
- max-height: 70vh;
- display: flex;
- flex-direction: column;
- }
- .agreement-popup__head {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 28rpx 32rpx;
- border-bottom: 1rpx solid #eee;
- }
- .agreement-popup__title {
- flex: 1;
- margin-right: 16rpx;
- font-size: 30rpx;
- font-weight: 600;
- color: #333;
- }
- .agreement-popup__scroll {
- max-height: 60vh;
- padding: 24rpx 32rpx 48rpx;
- box-sizing: border-box;
- }
- .agreement-rich {
- display: block;
- width: 100%;
- font-size: 28rpx;
- color: #444;
- line-height: 1.7;
- word-break: break-word;
- }
- </style>
|