phone-dial-inline.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <script>
  2. export default {
  3. options: { virtualHost: true }
  4. }
  5. </script>
  6. <script setup>
  7. import { computed } from 'vue'
  8. // #ifdef H5
  9. import VanIcon from 'vant/es/icon'
  10. import 'vant/es/icon/style'
  11. // #endif
  12. // #ifdef MP-WEIXIN
  13. import UniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.vue'
  14. // #endif
  15. import { dialPhone, normalizeDialNumber } from '@/utils/phone-dial'
  16. const props = defineProps({
  17. phone: { type: [String, null], default: null },
  18. dialPhone: { type: [String, null], default: undefined },
  19. emptyText: { type: String, default: '暂无' },
  20. /** 仅作用于号码/占位文字;拨号图标固定黑色,见 `dialIconColor` */
  21. color: { type: String, default: '' },
  22. iconSize: { type: [String, Number], default: 18 },
  23. iconOnly: { type: Boolean, default: false },
  24. hideIcon: { type: Boolean, default: false },
  25. expand: { type: Boolean, default: false },
  26. endAlign: { type: Boolean, default: false }
  27. })
  28. const displayLine = computed(() => String(props.phone ?? '').trim())
  29. const dialRaw = computed(() =>
  30. normalizeDialNumber(props.dialPhone !== undefined && props.dialPhone !== null ? props.dialPhone : props.phone)
  31. )
  32. const canDial = computed(() => !!dialRaw.value)
  33. const displayText = computed(() => {
  34. if (props.iconOnly) return ''
  35. return displayLine.value || props.emptyText
  36. })
  37. /** 拨号图标颜色(与号码文字 `color` 解耦,统一黑色) */
  38. const dialIconColor = '#000000'
  39. /** 号码文字色:`icon-only` 无文字时不应用 */
  40. const textStyle = computed(() => {
  41. if (props.iconOnly)
  42. return {}
  43. const c = String(props.color ?? '').trim()
  44. if (!c)
  45. return {}
  46. return { color: c }
  47. })
  48. /** App 等非 H5、非微信小程序端:Unicode 兜底(小程序用 uni-icons,见模板) */
  49. const iconStyle = computed(() => {
  50. const n = Number(props.iconSize)
  51. const px = Number.isFinite(n) ? n : 18
  52. return { color: dialIconColor, fontSize: `${px * 2}rpx`, lineHeight: 1 }
  53. })
  54. function onDial() {
  55. dialPhone(props.dialPhone !== undefined && props.dialPhone !== null ? props.dialPhone : props.phone)
  56. }
  57. function onTextClick(e) {
  58. if (!props.hideIcon || !canDial.value) return
  59. e.stopPropagation()
  60. onDial()
  61. }
  62. </script>
  63. <template>
  64. <view
  65. class="phone-dial-inline"
  66. :class="{
  67. 'phone-dial-inline--icon-only': iconOnly,
  68. 'phone-dial-inline--hide-icon': hideIcon,
  69. 'phone-dial-inline--expand': expand,
  70. 'phone-dial-inline--end': endAlign
  71. }"
  72. >
  73. <text v-if="!iconOnly" class="phone-dial-inline__text" :style="textStyle" @click="onTextClick">{{ displayText }}</text>
  74. <view v-if="canDial && !hideIcon" class="phone-dial-inline__btn" @click.stop="onDial">
  75. <!-- #ifdef H5 -->
  76. <VanIcon name="phone-o" :size="iconSize" :color="dialIconColor" />
  77. <!-- #endif -->
  78. <!-- #ifdef MP-WEIXIN -->
  79. <UniIcons type="phone" :color="dialIconColor" :size="iconSize" />
  80. <!-- #endif -->
  81. <!-- #ifndef H5 -->
  82. <!-- #ifndef MP-WEIXIN -->
  83. <text class="phone-dial-inline__icon" :style="iconStyle">☎</text>
  84. <!-- #endif -->
  85. <!-- #endif -->
  86. </view>
  87. </view>
  88. </template>
  89. <style scoped>
  90. .phone-dial-inline {
  91. display: inline-flex;
  92. align-items: center;
  93. gap: 10rpx;
  94. min-width: 0;
  95. max-width: 100%;
  96. box-sizing: border-box;
  97. }
  98. .phone-dial-inline--expand {
  99. flex: 1;
  100. min-width: 0;
  101. }
  102. .phone-dial-inline--icon-only.phone-dial-inline--expand {
  103. flex: 0 0 auto;
  104. }
  105. .phone-dial-inline--end {
  106. justify-content: flex-end;
  107. }
  108. .phone-dial-inline--end .phone-dial-inline__text {
  109. text-align: right;
  110. }
  111. .phone-dial-inline__text {
  112. flex: 1;
  113. min-width: 0;
  114. word-break: break-all;
  115. line-height: 1.4;
  116. }
  117. .phone-dial-inline--icon-only .phone-dial-inline__text {
  118. display: none;
  119. }
  120. .phone-dial-inline__btn {
  121. flex-shrink: 0;
  122. min-width: 44rpx;
  123. min-height: 44rpx;
  124. display: flex;
  125. align-items: center;
  126. justify-content: center;
  127. }
  128. .phone-dial-inline__icon {
  129. font-weight: 600;
  130. }
  131. </style>