SharePopup.vue 8.1 KB

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