瑶都万能墙
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

251 lines
5.2 KiB

  1. <template>
  2. <view class="qrcode-container">
  3. <navbar title="店铺二维码" leftClick @leftClick="$utils.navigateBack"/>
  4. <!-- 加载状态 -->
  5. <view class="loading-container" v-if="loading">
  6. <view class="loading-spinner"></view>
  7. <text class="loading-text">加载中...</text>
  8. </view>
  9. <!-- 二维码图片 -->
  10. <view class="qrcode-wrapper" v-if="qrCodeUrl">
  11. <image
  12. class="qrcode-image"
  13. :src="qrCodeUrl"
  14. mode="widthFix"
  15. @load="imageLoaded"
  16. @error="imageError"
  17. ></image>
  18. <text class="qrcode-tip" v-if="!loading && qrCodeUrl">扫描二维码查看店铺详情</text>
  19. <text class="save-tip" v-if="!loading && qrCodeUrl">长按图片可保存到相册</text>
  20. </view>
  21. <!-- 错误状态 -->
  22. <view class="error-container" v-if="!loading && !qrCodeUrl && hasError">
  23. <text class="error-text">二维码加载失败请重试</text>
  24. <button class="retry-button" @click="loadQrCode">重新加载</button>
  25. </view>
  26. </view>
  27. </template>
  28. <script>
  29. export default {
  30. data() {
  31. return {
  32. shopId: '',
  33. qrCodeUrl: '',
  34. loading: true,
  35. hasError: false,
  36. }
  37. },
  38. onLoad(options) {
  39. if (options.id) {
  40. this.shopId = options.id;
  41. this.loadQrCode();
  42. } else {
  43. this.loading = false;
  44. this.hasError = true;
  45. uni.showToast({
  46. title: '缺少店铺ID参数',
  47. icon: 'none'
  48. });
  49. }
  50. },
  51. methods: {
  52. // 加载二维码
  53. loadQrCode() {
  54. if (!this.shopId) return;
  55. this.loading = true;
  56. this.hasError = false;
  57. // 直接使用图片链接请求二维码
  58. this.qrCodeUrl = `${this.$config.baseUrl}/city/shop/shopQrCode?id=${this.shopId}`;
  59. // 由于image标签会自动处理加载状态,我们在imageLoaded和imageError中处理状态变化
  60. },
  61. // 图片加载成功
  62. imageLoaded() {
  63. this.loading = false;
  64. },
  65. // 图片加载失败
  66. imageError() {
  67. this.loading = false;
  68. this.hasError = true;
  69. this.qrCodeUrl = '';
  70. uni.showToast({
  71. title: '二维码加载失败',
  72. icon: 'none'
  73. });
  74. },
  75. // 保存图片到相册
  76. saveImage() {
  77. if (!this.qrCodeUrl) return;
  78. uni.showLoading({
  79. title: '保存中...'
  80. });
  81. // 下载图片
  82. uni.downloadFile({
  83. url: this.qrCodeUrl,
  84. success: (res) => {
  85. if (res.statusCode === 200) {
  86. // 保存图片到相册
  87. uni.saveImageToPhotosAlbum({
  88. filePath: res.tempFilePath,
  89. success: () => {
  90. uni.hideLoading();
  91. uni.showToast({
  92. title: '保存成功',
  93. icon: 'success'
  94. });
  95. },
  96. fail: (err) => {
  97. uni.hideLoading();
  98. console.error('保存图片失败:', err);
  99. // 如果是用户拒绝授权导致的失败
  100. if (err.errMsg.indexOf('auth deny') >= 0 || err.errMsg.indexOf('authorize') >= 0) {
  101. this.showAuthModal();
  102. } else {
  103. uni.showToast({
  104. title: '保存失败',
  105. icon: 'none'
  106. });
  107. }
  108. }
  109. });
  110. } else {
  111. uni.hideLoading();
  112. uni.showToast({
  113. title: '图片下载失败',
  114. icon: 'none'
  115. });
  116. }
  117. },
  118. fail: () => {
  119. uni.hideLoading();
  120. uni.showToast({
  121. title: '图片下载失败',
  122. icon: 'none'
  123. });
  124. }
  125. });
  126. },
  127. // 显示授权提示弹窗
  128. showAuthModal() {
  129. uni.showModal({
  130. title: '提示',
  131. content: '保存图片需要您授权访问相册权限',
  132. confirmText: '去授权',
  133. cancelText: '取消',
  134. success: (res) => {
  135. if (res.confirm) {
  136. // 打开设置页面
  137. uni.openSetting({
  138. success: (settingRes) => {
  139. console.log('设置页面成功打开:', settingRes);
  140. }
  141. });
  142. }
  143. }
  144. });
  145. }
  146. }
  147. }
  148. </script>
  149. <style lang="scss" scoped>
  150. .qrcode-container {
  151. display: flex;
  152. flex-direction: column;
  153. align-items: center;
  154. min-height: 100vh;
  155. background-color: #f5f5f5;
  156. padding: 30rpx;
  157. }
  158. .loading-container {
  159. display: flex;
  160. flex-direction: column;
  161. justify-content: center;
  162. align-items: center;
  163. margin-top: 200rpx;
  164. .loading-spinner {
  165. width: 80rpx;
  166. height: 80rpx;
  167. border: 6rpx solid #f3f3f3;
  168. border-top: 6rpx solid #3B5CF0;
  169. border-radius: 50%;
  170. animation: spin 1s linear infinite;
  171. margin-bottom: 20rpx;
  172. }
  173. .loading-text {
  174. font-size: 28rpx;
  175. color: #666;
  176. }
  177. @keyframes spin {
  178. 0% { transform: rotate(0deg); }
  179. 100% { transform: rotate(360deg); }
  180. }
  181. }
  182. .qrcode-wrapper {
  183. display: flex;
  184. flex-direction: column;
  185. align-items: center;
  186. // background-color: #fff;
  187. // border-radius: 16rpx;
  188. // box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
  189. .qrcode-image {
  190. width: 700rpx;
  191. margin-bottom: 30rpx;
  192. }
  193. .qrcode-tip {
  194. font-size: 28rpx;
  195. color: #666;
  196. margin-top: 20rpx;
  197. }
  198. .save-tip {
  199. font-size: 24rpx;
  200. color: $uni-color-primary;
  201. margin-top: 10rpx;
  202. }
  203. }
  204. .error-container {
  205. display: flex;
  206. flex-direction: column;
  207. align-items: center;
  208. margin-top: 200rpx;
  209. .error-text {
  210. font-size: 28rpx;
  211. color: #999;
  212. margin-bottom: 30rpx;
  213. }
  214. .retry-button {
  215. background-color: #3B5CF0;
  216. color: #fff;
  217. font-size: 28rpx;
  218. padding: 16rpx 40rpx;
  219. border-radius: 40rpx;
  220. border: none;
  221. }
  222. }
  223. </style>