SharePopup.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. <template>
  2. <view class="share-modal" v-show="visible">
  3. <view class="modal-overlay" @click="handleClose"></view>
  4. <transition name="fade-up">
  5. <view v-if="visible" class="modal-content">
  6. <view class="share-options">
  7. <view v-for="option in shareOptions" :key="option.id" class="share-item" @click="handleShare(option.id)">
  8. <view class="share-icon">
  9. <image :src="option.icon" :alt="option.title" mode="aspectFit"></image>
  10. </view>
  11. <text class="option-title">{{ option.title }}</text>
  12. </view>
  13. </view>
  14. </view>
  15. </transition>
  16. </view>
  17. </template>
  18. <script>
  19. import { generateSecureUrlParams } from '@/common/encryption.js'
  20. export default {
  21. name: 'ShareModal',
  22. props: {
  23. visible: {
  24. type: Boolean,
  25. default: false
  26. },
  27. userId: {
  28. default: 0
  29. },
  30. shareTitle: {
  31. type: String,
  32. default: ''
  33. },
  34. shareDesc: {
  35. type: String,
  36. default: '快来加入萌创星球吧!'
  37. },
  38. shareImg: {
  39. type: String,
  40. default: ''
  41. },
  42. view: {
  43. type: String,
  44. default: ''
  45. }
  46. },
  47. data() {
  48. return {
  49. shareOptions: [
  50. { id: 'wechat', title: '微信好友', icon: '/static/icon/sy_icon_weixin.png' },
  51. { id: 'moments', title: '朋友圈', icon: '/static/icon/sy_icon_pengyouquan.png' },
  52. // { id: 'qq', title: 'QQ好友', icon: '../../static/icon/sy_icon_qq.png' },
  53. { id: 'copy', title: '复制链接', icon: '/static/icon/sy_icon_fuzhilianjie.png' },
  54. { id: 'report', title: '举报', icon: '/static/icon/sy_icon_jubao01.png' },
  55. // { id: 'more', title: '更多', icon: '../../static/icon/sy_icon_gengduo.png' }
  56. ],
  57. from_id: 0
  58. }
  59. },
  60. computed: {
  61. shareUrl() {
  62. const urlParams = {
  63. userId: this.userId,
  64. action: this.view,
  65. timestamp: new Date().getTime(),
  66. from_id: this.from_id
  67. }
  68. const secureParams = generateSecureUrlParams(urlParams)
  69. return `${this.$shareUrl}?params=${secureParams}`
  70. }
  71. },
  72. created() {
  73. uni.$emit('check_login', () => {
  74. this.from_id = getApp().globalData.user_id
  75. })
  76. },
  77. methods: {
  78. handleClose() {
  79. this.$emit('close')
  80. },
  81. handleShare(type) {
  82. switch (type) {
  83. case 'copy':
  84. this.copyToClipboard(this.shareUrl)
  85. break
  86. case 'wechat':
  87. this.shareToWechat()
  88. break
  89. case 'moments':
  90. this.shareToMoments()
  91. break
  92. case 'report':
  93. this.handleReport()
  94. break
  95. case 'qq':
  96. this.qqShare()
  97. break
  98. case 'more':
  99. this.moreShare()
  100. break
  101. }
  102. },
  103. copyToClipboard(text) {
  104. // #ifdef H5
  105. const input = document.createElement('input')
  106. input.value = text
  107. document.body.appendChild(input)
  108. input.select()
  109. document.execCommand('copy')
  110. document.body.removeChild(input)
  111. // #endif
  112. // #ifdef APP-PLUS || MP
  113. uni.setClipboardData({
  114. data: text,
  115. success: () => {
  116. uni.showToast({
  117. title: '链接已复制',
  118. icon: 'success'
  119. })
  120. },
  121. fail: () => {
  122. uni.showToast({
  123. title: '复制失败',
  124. icon: 'none'
  125. })
  126. }
  127. })
  128. // #endif
  129. },
  130. shareToWechat() {
  131. // #ifdef APP-PLUS
  132. uni.share({
  133. provider: 'weixin',
  134. scene: 'WXSceneSession',
  135. type: 0,
  136. title: this.shareTitle,
  137. summary: this.shareDesc,
  138. imageUrl: this.shareImg || this.$icon,
  139. href: this.shareUrl,
  140. success: () => {
  141. uni.showToast({
  142. title: '分享成功',
  143. icon: 'success'
  144. })
  145. },
  146. fail: (err) => {
  147. uni.showToast({
  148. title: '分享失败',
  149. icon: 'none'
  150. })
  151. console.error('分享失败:', err)
  152. }
  153. })
  154. // #endif
  155. // #ifdef H5
  156. if (typeof wx !== 'undefined') {
  157. wx.ready(() => {
  158. wx.updateAppMessageShareData({
  159. title: this.shareTitle,
  160. desc: this.shareDesc,
  161. link: this.shareUrl,
  162. imgUrl: this.shareImg || this.$icon,
  163. success: () => {
  164. uni.showToast({
  165. title: '分享成功',
  166. icon: 'success'
  167. })
  168. },
  169. fail: (err) => {
  170. uni.showToast({
  171. title: '分享失败',
  172. icon: 'none'
  173. })
  174. console.error('分享失败:', err)
  175. }
  176. })
  177. })
  178. } else {
  179. uni.showToast({
  180. title: '请在微信中打开',
  181. icon: 'none'
  182. })
  183. }
  184. // #endif
  185. // #ifdef MP-WEIXIN
  186. uni.showShareMenu({
  187. withShareTicket: true,
  188. menus: ['shareAppMessage'],
  189. success: () => {
  190. uni.updateShareMenu({
  191. withShareTicket: true,
  192. isPrivateMessage: true
  193. })
  194. }
  195. })
  196. // #endif
  197. },
  198. shareToMoments() {
  199. // #ifdef APP-PLUS
  200. uni.share({
  201. provider: 'weixin',
  202. scene: 'WXSenceTimeline',
  203. type: 0,
  204. title: this.shareTitle,
  205. summary: this.shareDesc,
  206. imageUrl: this.shareImg || this.$icon,
  207. href: this.shareUrl,
  208. success: () => {
  209. uni.showToast({
  210. title: '分享成功',
  211. icon: 'success'
  212. })
  213. },
  214. fail: (err) => {
  215. uni.showToast({
  216. title: '分享失败',
  217. icon: 'none'
  218. })
  219. console.error('分享失败:', err)
  220. }
  221. })
  222. // #endif
  223. // #ifdef H5
  224. if (typeof wx !== 'undefined') {
  225. wx.ready(() => {
  226. wx.updateTimelineShareData({
  227. title: this.shareTitle,
  228. link: this.shareUrl,
  229. imgUrl: this.shareImg || this.$icon,
  230. success: () => {
  231. uni.showToast({
  232. title: '分享成功',
  233. icon: 'success'
  234. })
  235. },
  236. fail: (err) => {
  237. uni.showToast({
  238. title: '分享失败',
  239. icon: 'none'
  240. })
  241. console.error('分享失败:', err)
  242. }
  243. })
  244. })
  245. } else {
  246. uni.showToast({
  247. title: '请在微信中打开',
  248. icon: 'none'
  249. })
  250. }
  251. // #endif
  252. // #ifdef MP-WEIXIN
  253. uni.showShareMenu({
  254. withShareTicket: true,
  255. menus: ['shareTimeline']
  256. })
  257. // #endif
  258. },
  259. handleReport() {
  260. // 实现举报功能
  261. uni.$emit('check_login', () => {
  262. uni.navigateTo({
  263. url: '/pages/my/feedback'
  264. })
  265. })
  266. },
  267. qqShare() {
  268. // #ifdef APP-PLUS
  269. uni.share({
  270. provider: 'qq',
  271. type: 0,
  272. title: this.shareTitle,
  273. summary: this.shareDesc,
  274. imageUrl: this.shareImg || this.$icon,
  275. href: this.shareUrl,
  276. success: () => {
  277. uni.showToast({
  278. title: '分享成功',
  279. icon: 'success'
  280. })
  281. }
  282. })
  283. // #endif
  284. },
  285. moreShare() {
  286. // 更多分享方式
  287. uni.showToast({
  288. title: '更多分享功能开发中',
  289. icon: 'none'
  290. })
  291. }
  292. }
  293. }
  294. </script>
  295. <style scoped>
  296. .share-modal {
  297. position: fixed;
  298. left: 0;
  299. right: 0;
  300. top: 0;
  301. bottom: 0;
  302. z-index: 1000;
  303. }
  304. .modal-overlay {
  305. position: absolute;
  306. left: 0;
  307. right: 0;
  308. top: 0;
  309. bottom: 0;
  310. background-color: rgba(0, 0, 0, 0.4);
  311. }
  312. .modal-content {
  313. position: absolute;
  314. left: 0;
  315. right: 0;
  316. bottom: 0;
  317. background-color: #f2f6f2;
  318. border-top-left-radius: 12px;
  319. border-top-right-radius: 12px;
  320. padding: 16px;
  321. }
  322. /* 弹出动画 */
  323. .fade-up-enter-active, .fade-up-leave-active {
  324. transition: all 0.3s cubic-bezier(.55,0,.1,1);
  325. }
  326. .fade-up-enter, .fade-up-leave-to {
  327. opacity: 0;
  328. transform: translateY(100%);
  329. }
  330. .fade-up-leave, .fade-up-enter-to {
  331. opacity: 1;
  332. transform: translateY(0);
  333. }
  334. .share-options {
  335. display: flex;
  336. flex-wrap: wrap;
  337. padding: 8px 16px;
  338. }
  339. .share-item {
  340. width: 25%;
  341. display: flex;
  342. flex-direction: column;
  343. align-items: center;
  344. gap: 8px;
  345. padding: 8px 0;
  346. }
  347. .share-icon {
  348. width: 44px;
  349. height: 44px;
  350. display: flex;
  351. justify-content: center;
  352. align-items: center;
  353. }
  354. .share-icon image {
  355. width: 100%;
  356. height: 100%;
  357. }
  358. .option-title {
  359. font-size: 13px;
  360. color: #333333;
  361. text-align: center;
  362. }
  363. </style>