ShareDialog.vue 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. <template>
  2. <div
  3. v-if="modelValue"
  4. class="fixed inset-0 bg-black/50 flex items-center justify-center z-50"
  5. @click.self="closeDialog"
  6. >
  7. <div
  8. class="bg-surface border border-white/10 rounded-2xl p-6 w-full max-w-md mx-4"
  9. >
  10. <div class="text-center mb-4">
  11. <h3 class="text-lg font-semibold text-white/90 mb-2">分享链接</h3>
  12. <p class="text-sm text-white/70">将链接分享给朋友,每天最多获得三部免费观看</p>
  13. </div>
  14. <!-- 分享链接显示区域 -->
  15. <div class="mb-4">
  16. <label class="block text-sm text-white/70 mb-2">分享链接:</label>
  17. <div class="flex items-center gap-2">
  18. <input
  19. :value="shareUrl"
  20. readonly
  21. class="flex-1 px-3 py-2 bg-white/5 border border-white/10 rounded-lg text-white/90 text-sm"
  22. />
  23. <button
  24. @click="copyShareLink"
  25. class="px-4 py-2 bg-brand text-slate-900 rounded-lg hover:bg-brand/90 transition text-sm font-medium"
  26. >
  27. 复制
  28. </button>
  29. </div>
  30. </div>
  31. <!-- 分享提示 -->
  32. <div class="mb-4 p-3 bg-green-500/10 rounded-lg border border-green-500/20">
  33. <p class="text-xs text-green-400">
  34. 💡 提示:朋友通过此链接访问并观看视频,即可计入您的分享次数
  35. </p>
  36. </div>
  37. <!-- 操作按钮 -->
  38. <div class="flex justify-center">
  39. <button
  40. @click="closeDialog"
  41. class="px-6 py-2 border border-white/20 text-white/70 rounded-lg hover:bg-white/5 transition"
  42. >
  43. 关闭
  44. </button>
  45. </div>
  46. </div>
  47. <!-- 成功提示弹窗 -->
  48. <div
  49. v-if="showSuccessToast"
  50. class="fixed inset-0 bg-black/50 flex items-center justify-center z-[9999]"
  51. @click.self="showSuccessToast = false"
  52. >
  53. <div class="bg-surface border border-white/10 rounded-2xl p-6 w-full max-w-sm mx-4 text-center">
  54. <!-- 成功图标 -->
  55. <div class="mb-4">
  56. <div class="w-12 h-12 mx-auto bg-green-500/20 rounded-full flex items-center justify-center">
  57. <svg class="w-6 h-6 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  58. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
  59. </svg>
  60. </div>
  61. </div>
  62. <!-- 成功信息 -->
  63. <h3 class="text-lg font-semibold text-white/90 mb-2">复制成功</h3>
  64. <p class="text-sm text-white/70 mb-6">{{ successMessage }}</p>
  65. <!-- 确认按钮 -->
  66. <button
  67. @click="showSuccessToast = false"
  68. class="w-full px-4 py-2 bg-brand text-slate-900 rounded-lg hover:bg-brand/90 transition"
  69. >
  70. 确定
  71. </button>
  72. </div>
  73. </div>
  74. <!-- 错误提示弹窗 -->
  75. <div
  76. v-if="showErrorToast"
  77. class="fixed inset-0 bg-black/50 flex items-center justify-center z-[9999]"
  78. @click.self="showErrorToast = false"
  79. >
  80. <div class="bg-surface border border-white/10 rounded-2xl p-6 w-full max-w-sm mx-4 text-center">
  81. <!-- 错误图标 -->
  82. <div class="mb-4">
  83. <div class="w-12 h-12 mx-auto bg-red-500/20 rounded-full flex items-center justify-center">
  84. <svg class="w-6 h-6 text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  85. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"/>
  86. </svg>
  87. </div>
  88. </div>
  89. <!-- 错误信息 -->
  90. <h3 class="text-lg font-semibold text-white/90 mb-2">复制失败</h3>
  91. <p class="text-sm text-white/70 mb-6">{{ errorMessage }}</p>
  92. <!-- 确认按钮 -->
  93. <button
  94. @click="showErrorToast = false"
  95. class="w-full px-4 py-2 bg-brand text-slate-900 rounded-lg hover:bg-brand/90 transition"
  96. >
  97. 确定
  98. </button>
  99. </div>
  100. </div>
  101. </div>
  102. </template>
  103. <script setup lang="ts">
  104. import { computed, watch, ref } from 'vue';
  105. import { generateShareLink } from '@/services/shareApi';
  106. import { useUserStore } from '@/store/user';
  107. const props = defineProps<{
  108. modelValue: boolean;
  109. shareUrl?: string;
  110. shareTitle?: string;
  111. resourceId?: string;
  112. }>();
  113. const emit = defineEmits<{
  114. (e: 'update:modelValue', value: boolean): void;
  115. (e: 'success', message: string): void;
  116. (e: 'error', message: string): void;
  117. }>();
  118. const userStore = useUserStore();
  119. // 提示弹窗状态
  120. const showSuccessToast = ref(false);
  121. const showErrorToast = ref(false);
  122. const successMessage = ref('');
  123. const errorMessage = ref('');
  124. // 计算分享链接
  125. const shareUrl = computed(() => {
  126. console.log('🔄 shareUrl 计算属性执行:', {
  127. shareUrl: props.shareUrl,
  128. resourceId: props.resourceId,
  129. userId: userStore.userInfo?.id
  130. });
  131. if (props.shareUrl) {
  132. return props.shareUrl + "&inviter=" + userStore.userInfo?.id + "&resource=" + props.resourceId;
  133. }
  134. // 如果有resourceId,生成带分享参数的链接
  135. if (props.resourceId && userStore.userInfo?.id) {
  136. const generatedUrl = generateShareLink(userStore.userInfo.id, props.resourceId);
  137. console.log('✅ 生成分享链接:', generatedUrl);
  138. return generatedUrl;
  139. }
  140. console.log('⚠️ 使用默认URL:', window.location.href);
  141. return window.location.href;
  142. });
  143. // 关闭弹窗
  144. const closeDialog = () => {
  145. emit('update:modelValue', false);
  146. };
  147. // 复制分享链接
  148. const copyShareLink = async () => {
  149. try {
  150. // 检查是否支持 Clipboard API
  151. if (navigator.clipboard && navigator.clipboard.writeText) {
  152. await navigator.clipboard.writeText(shareUrl.value);
  153. showSuccessMessage('链接已复制到剪贴板!');
  154. } else {
  155. // 降级方案:使用传统的复制方法
  156. fallbackCopyToClipboard(shareUrl.value);
  157. }
  158. } catch (error) {
  159. console.error('复制失败:', error);
  160. // 尝试降级方案
  161. try {
  162. fallbackCopyToClipboard(shareUrl.value);
  163. } catch (fallbackError) {
  164. console.error('降级复制也失败:', fallbackError);
  165. showErrorMessage('复制失败,请手动复制链接');
  166. }
  167. }
  168. };
  169. // 降级复制方案
  170. const fallbackCopyToClipboard = (text: string) => {
  171. // 创建临时文本区域
  172. const textArea = document.createElement('textarea');
  173. textArea.value = text;
  174. textArea.style.position = 'fixed';
  175. textArea.style.left = '-999999px';
  176. textArea.style.top = '-999999px';
  177. document.body.appendChild(textArea);
  178. try {
  179. // 选择文本
  180. textArea.focus();
  181. textArea.select();
  182. textArea.setSelectionRange(0, 99999); // 移动端支持
  183. // 执行复制命令
  184. const successful = document.execCommand('copy');
  185. document.body.removeChild(textArea);
  186. if (successful) {
  187. showSuccessMessage('链接已复制到剪贴板!');
  188. } else {
  189. throw new Error('execCommand failed');
  190. }
  191. } catch (error) {
  192. document.body.removeChild(textArea);
  193. throw error;
  194. }
  195. };
  196. // 显示成功消息
  197. const showSuccessMessage = (message: string) => {
  198. successMessage.value = message;
  199. showSuccessToast.value = true;
  200. // 不发送事件给父组件,避免重复提示
  201. };
  202. // 显示错误消息
  203. const showErrorMessage = (message: string) => {
  204. errorMessage.value = message;
  205. showErrorToast.value = true;
  206. // 不发送事件给父组件,避免重复提示
  207. };
  208. // 移除分享行为记录逻辑
  209. // 分享者点击分享按钮时不需要调用recordShare接口
  210. // 只有被分享者点击分享链接时才调用recordShareClick接口
  211. // 监听弹窗显示状态(移除自动记录分享行为)
  212. watch(() => props.modelValue, (newVal) => {
  213. if (newVal) {
  214. // 弹窗打开时,确保用户信息已加载
  215. console.log('ShareDialog 打开,用户信息:', userStore.userInfo);
  216. console.log('resourceId:', props.resourceId);
  217. console.log('生成的分享链接:', shareUrl.value);
  218. }
  219. });
  220. </script>