share.vue 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. <template>
  2. <view class="container">
  3. <!-- 未登录 -->
  4. <view v-if="!isLoggedIn" class="empty-state">
  5. <text class="empty-icon">👤</text>
  6. <text class="empty-title">请先登录</text>
  7. <text class="empty-desc">登录后即可生成您的专属推广码</text>
  8. <button class="btn-login" @click="goLogin">去登录</button>
  9. </view>
  10. <!-- 已登录 -->
  11. <view v-else class="content">
  12. <!-- 头部 -->
  13. <view class="header">
  14. <text class="title">分享推广码</text>
  15. <text class="subtitle">将二维码分享给好友,扫码注册即成为您的下线</text>
  16. </view>
  17. <!-- 我的推广码 -->
  18. <view class="code-card">
  19. <view class="code-label">
  20. <text class="label-text">我的推广码</text>
  21. <view class="copy-btn" @click="copyCode">
  22. <text class="copy-icon">📋</text>
  23. <text class="copy-text">{{ copied ? '已复制' : '复制' }}</text>
  24. </view>
  25. </view>
  26. <text class="code-value">{{ referralCode || '加载中...' }}</text>
  27. </view>
  28. <!-- 二维码区域 -->
  29. <view class="qrcode-section" v-if="qrLoading || qrBase64">
  30. <view class="qrcode-label">
  31. <text class="label-text">扫码进入首页</text>
  32. </view>
  33. <view class="qrcode-wrap">
  34. <image
  35. v-if="qrBase64"
  36. class="qrcode-img"
  37. :src="qrBase64"
  38. mode="aspectFit"
  39. />
  40. <view v-else class="qrcode-loading">
  41. <text class="loading-spinner">⏳</text>
  42. <text class="loading-text">生成中...</text>
  43. </view>
  44. </view>
  45. </view>
  46. <!-- 操作按钮 -->
  47. <view class="actions" v-if="qrBase64">
  48. <view class="action-btn save-btn" @click="saveQrcode">
  49. <text class="action-icon">💾</text>
  50. <text class="action-text">保存图片</text>
  51. </view>
  52. <view class="action-btn share-btn" @click="shareToWeixin">
  53. <text class="action-icon">📤</text>
  54. <text class="action-text">分享给朋友</text>
  55. </view>
  56. </view>
  57. <!-- 说明 -->
  58. <view class="tips">
  59. <view class="tip-item">
  60. <text class="tip-icon">💡</text>
  61. <text class="tip-text">好友扫码后自动绑定推荐关系</text>
  62. </view>
  63. <view class="tip-item">
  64. <text class="tip-icon">💡</text>
  65. <text class="tip-text">好友注册后您将获得积分奖励</text>
  66. </view>
  67. <view class="tip-item">
  68. <text class="tip-icon">💡</text>
  69. <text class="tip-text">推广码可长期使用,无过期时间</text>
  70. </view>
  71. </view>
  72. </view>
  73. </view>
  74. </template>
  75. <script>
  76. import { getReferralCode, extractReferralCode, getShareQrCode } from '../../utils/api.js'
  77. export default {
  78. data() {
  79. return {
  80. referralCode: '',
  81. qrBase64: '',
  82. qrLoading: false,
  83. copied: false
  84. }
  85. },
  86. computed: {
  87. isLoggedIn() {
  88. return !!uni.getStorageSync('token')
  89. }
  90. },
  91. onLoad() {
  92. this.loadReferralCode()
  93. this._onLoadFired = true
  94. },
  95. onShow() {
  96. if (this._onLoadFired) {
  97. this._onLoadFired = false
  98. } else if (this.isLoggedIn && !this.referralCode) {
  99. this.loadReferralCode()
  100. }
  101. },
  102. methods: {
  103. async loadReferralCode() {
  104. if (!this.isLoggedIn) return
  105. try {
  106. var res = await getReferralCode()
  107. var code = extractReferralCode(res)
  108. this.referralCode = code || ''
  109. if (this.referralCode) {
  110. this.generateQrcode()
  111. }
  112. } catch (e) {
  113. console.error('获取推广码失败', e)
  114. }
  115. },
  116. generateQrcode() {
  117. if (!this.referralCode) return
  118. this.qrLoading = true
  119. var scene = 'ref=' + this.referralCode
  120. // 首页路径,扫码后进入首页并绑定推荐人
  121. getShareQrCode('/pages/index-home/index', scene)
  122. .then(function(res) {
  123. if (res && res.code === 200 && res.data) {
  124. this.qrBase64 = res.data.qrCodeBase64
  125. }
  126. }.bind(this))
  127. .catch(function(e) {
  128. console.error('生成二维码失败', e)
  129. uni.showToast({ title: '生成失败,请重试', icon: 'none' })
  130. })
  131. .finally(function() {
  132. this.qrLoading = false
  133. }.bind(this))
  134. },
  135. copyCode() {
  136. if (!this.referralCode) return
  137. this.copied = true
  138. uni.setClipboardData({
  139. data: this.referralCode,
  140. success: function() {
  141. uni.showToast({ title: '推广码已复制', icon: 'success' })
  142. setTimeout(function() {
  143. this.copied = false
  144. }.bind(this), 2000)
  145. }.bind(this)
  146. })
  147. },
  148. saveQrcode() {
  149. if (!this.qrBase64) return
  150. // 将 base64 转为临时文件再保存
  151. var self = this
  152. var rawBase64 = this.qrBase64.indexOf('base64,') >= 0
  153. ? this.qrBase64.split('base64,')[1]
  154. : this.qrBase64
  155. var fsm = uni.getFileSystemManager()
  156. var tempPath = wx.env.USER_DATA_PATH + '/share_qrcode_' + Date.now() + '.png'
  157. fsm.writeFileSync(tempPath, rawBase64, 'base64')
  158. uni.saveImageToPhotosAlbum({
  159. filePath: tempPath,
  160. success: function() {
  161. uni.showToast({ title: '保存成功', icon: 'success' })
  162. },
  163. fail: function() {
  164. uni.showToast({ title: '保存失败', icon: 'none' })
  165. }
  166. })
  167. },
  168. shareToWeixin() {
  169. if (!this.referralCode) return
  170. // 通过 uni.share 分享小程序卡片
  171. var path = '/pages/index-home/index?refCode=' + this.referralCode
  172. uni.share({
  173. provider: 'weixin',
  174. scene: { type: 0 },
  175. type: 5,
  176. imageUrl: this.qrBase64,
  177. path: path,
  178. title: '浠艾福 — 邀请你加入',
  179. success: function() {
  180. uni.showToast({ title: '分享成功', icon: 'success' })
  181. },
  182. fail: function() {
  183. uni.showToast({ title: '分享失败', icon: 'none' })
  184. }
  185. })
  186. },
  187. goLogin() {
  188. uni.navigateTo({ url: '/pages/login/login' })
  189. }
  190. }
  191. }
  192. </script>
  193. <style scoped>
  194. .container {
  195. min-height: 100vh;
  196. background: #F8F4EF;
  197. padding-bottom: 60rpx;
  198. }
  199. /* 未登录 */
  200. .empty-state {
  201. display: flex;
  202. flex-direction: column;
  203. align-items: center;
  204. justify-content: center;
  205. min-height: 70vh;
  206. padding: 60rpx;
  207. }
  208. .empty-icon { font-size: 100rpx; margin-bottom: 24rpx; }
  209. .empty-title { font-size: 36rpx; font-weight: bold; color: #333; margin-bottom: 12rpx; }
  210. .empty-desc { font-size: 26rpx; color: #999; margin-bottom: 40rpx; }
  211. .btn-login {
  212. width: 60%;
  213. height: 80rpx;
  214. line-height: 80rpx;
  215. background: linear-gradient(135deg, #667eea, #764ba2);
  216. color: #fff;
  217. font-size: 30rpx;
  218. font-weight: bold;
  219. border-radius: 40rpx;
  220. text-align: center;
  221. border: none;
  222. }
  223. .btn-login::after { border: none; }
  224. /* 内容区 */
  225. .content { padding: 0 30rpx; }
  226. .header {
  227. text-align: center;
  228. padding: 60rpx 0 40rpx;
  229. }
  230. .title {
  231. font-size: 44rpx;
  232. font-weight: bold;
  233. color: #1E293B;
  234. display: block;
  235. margin-bottom: 12rpx;
  236. }
  237. .subtitle {
  238. font-size: 26rpx;
  239. color: #94A3B8;
  240. display: block;
  241. }
  242. /* 推广码卡片 */
  243. .code-card {
  244. background: #fff;
  245. border-radius: 20rpx;
  246. padding: 32rpx;
  247. margin-bottom: 30rpx;
  248. box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
  249. }
  250. .code-label {
  251. display: flex;
  252. justify-content: space-between;
  253. align-items: center;
  254. margin-bottom: 16rpx;
  255. }
  256. .label-text {
  257. font-size: 26rpx;
  258. color: #94A3B8;
  259. }
  260. .copy-btn {
  261. display: flex;
  262. align-items: center;
  263. gap: 8rpx;
  264. padding: 8rpx 20rpx;
  265. background: #FFF7ED;
  266. border-radius: 20rpx;
  267. border: 1rpx solid #FED7AA;
  268. }
  269. .copy-icon { font-size: 24rpx; }
  270. .copy-text { font-size: 24rpx; color: #F97316; }
  271. .code-value {
  272. font-size: 48rpx;
  273. font-weight: bold;
  274. color: #F97316;
  275. font-family: monospace;
  276. text-align: center;
  277. display: block;
  278. letter-spacing: 8rpx;
  279. }
  280. /* 二维码区域 */
  281. .qrcode-section {
  282. background: #fff;
  283. border-radius: 20rpx;
  284. padding: 32rpx;
  285. margin-bottom: 30rpx;
  286. box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
  287. display: flex;
  288. flex-direction: column;
  289. align-items: center;
  290. }
  291. .qrcode-label {
  292. margin-bottom: 24rpx;
  293. }
  294. .qrcode-wrap {
  295. width: 360rpx;
  296. height: 360rpx;
  297. display: flex;
  298. align-items: center;
  299. justify-content: center;
  300. background: #FAFAFA;
  301. border-radius: 16rpx;
  302. border: 2rpx dashed #E5E7EB;
  303. }
  304. .qrcode-img {
  305. width: 340rpx;
  306. height: 340rpx;
  307. border-radius: 12rpx;
  308. }
  309. .qrcode-loading {
  310. display: flex;
  311. flex-direction: column;
  312. align-items: center;
  313. gap: 16rpx;
  314. }
  315. .loading-spinner { font-size: 48rpx; }
  316. .loading-text { font-size: 24rpx; color: #94A3B8; }
  317. /* 操作按钮 */
  318. .actions {
  319. display: flex;
  320. gap: 20rpx;
  321. margin-bottom: 30rpx;
  322. }
  323. .action-btn {
  324. flex: 1;
  325. display: flex;
  326. flex-direction: column;
  327. align-items: center;
  328. gap: 12rpx;
  329. padding: 32rpx;
  330. border-radius: 20rpx;
  331. }
  332. .save-btn {
  333. background: #fff;
  334. box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
  335. }
  336. .share-btn {
  337. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  338. }
  339. .action-icon { font-size: 48rpx; }
  340. .action-text {
  341. font-size: 26rpx;
  342. font-weight: bold;
  343. }
  344. .save-btn .action-text { color: #333; }
  345. .share-btn .action-text { color: #fff; }
  346. /* 说明 */
  347. .tips {
  348. background: #fff;
  349. border-radius: 20rpx;
  350. padding: 32rpx;
  351. box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
  352. }
  353. .tip-item {
  354. display: flex;
  355. align-items: flex-start;
  356. gap: 12rpx;
  357. margin-bottom: 16rpx;
  358. }
  359. .tip-item:last-child { margin-bottom: 0; }
  360. .tip-icon { font-size: 28rpx; flex-shrink: 0; }
  361. .tip-text {
  362. font-size: 24rpx;
  363. color: #64748B;
  364. line-height: 1.6;
  365. }
  366. </style>