index.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <template>
  2. <view class="container">
  3. <!-- 挂牌看板区域 -->
  4. <view class="signboard-container">
  5. <view class="rope"></view>
  6. <view class="nail"></view>
  7. <view class="board" :class="{ 'resting': status !== 'busy' }">
  8. <view class="screw top-left"></view>
  9. <view class="screw top-right"></view>
  10. <view class="screw bottom-left"></view>
  11. <view class="screw bottom-right"></view>
  12. <view class="board-inner">
  13. <text class="status-text">{{ status === 'busy' ? '接单中' : '休息中' }}</text>
  14. </view>
  15. </view>
  16. </view>
  17. <!-- 状态描述 -->
  18. <view class="status-desc">
  19. <text>{{ status === 'busy' ? '当前处于工作接单中,正常接收新订单' : '当前处于休息状态,暂停接收新订单' }}</text>
  20. </view>
  21. <!-- 操作按钮 -->
  22. <view class="action-area">
  23. <button class="action-btn" :class="{ 'stop': status === 'busy', 'start': status !== 'busy' }" @click="toggleStatus">
  24. {{ status === 'busy' ? '停止接单' : '开始接单' }}
  25. </button>
  26. <view class="tips">
  27. <text v-if="status === 'busy'">当您希望长时间不再接收订单时,请点击上方按钮停止接单,开启后需手动恢复。</text>
  28. <text v-else>点击上方按钮恢复接单,开始接收新的任务推送。</text>
  29. </view>
  30. </view>
  31. </view>
  32. </template>
  33. <script>
  34. import { updateStatus, getMyProfile } from '@/api/fulfiller/fulfiller'
  35. export default {
  36. data() {
  37. return {
  38. status: 'resting', // resting | busy | disabled
  39. loading: false
  40. }
  41. },
  42. onShow() {
  43. // 优先从本地缓存读取,保证视觉即时性
  44. const savedStatus = uni.getStorageSync('workStatus');
  45. if (savedStatus) {
  46. this.status = savedStatus;
  47. }
  48. // 同时拉取最新 profile 确保同步
  49. this.fetchLatestProfile();
  50. },
  51. methods: {
  52. async fetchLatestProfile() {
  53. try {
  54. const res = await getMyProfile();
  55. if (res.data && res.data.status) {
  56. this.status = res.data.status;
  57. uni.setStorageSync('workStatus', this.status);
  58. }
  59. } catch (err) {
  60. console.error('获取状态失败:', err);
  61. uni.showToast({ title: err.message || err.msg || '请求失败', icon: 'none' });
  62. }
  63. },
  64. async toggleStatus() {
  65. if (this.loading) return;
  66. // 确定目标状态
  67. const targetStatus = this.status === 'busy' ? 'resting' : 'busy';
  68. const actionText = targetStatus === 'busy' ? '恢复接单' : '停止接单';
  69. try {
  70. uni.showLoading({ title: '处理中...', mask: true });
  71. this.loading = true;
  72. // 向后端发送请求
  73. await updateStatus(targetStatus);
  74. // 成功后重新获取用户信息以更新本地状态
  75. await this.fetchLatestProfile();
  76. uni.hideLoading();
  77. uni.showToast({ title: actionText + '成功', icon: 'success' });
  78. } catch (err) {
  79. uni.hideLoading();
  80. console.error('切换状态失败:', err);
  81. uni.showToast({ title: err.message || err.msg || '请求失败', icon: 'none' });
  82. } finally {
  83. this.loading = false;
  84. }
  85. }
  86. }
  87. }
  88. </script>
  89. <style>
  90. page {
  91. background-color: #fff;
  92. }
  93. .container {
  94. display: flex;
  95. flex-direction: column;
  96. align-items: center;
  97. padding-top: 100rpx;
  98. }
  99. /* 挂牌动画区域 */
  100. .signboard-container {
  101. position: relative;
  102. width: 400rpx;
  103. height: 300rpx;
  104. display: flex;
  105. justify-content: center;
  106. margin-bottom: 60rpx;
  107. }
  108. .rope {
  109. position: absolute;
  110. top: 0;
  111. width: 200rpx;
  112. height: 100rpx;
  113. border-top: 4rpx solid #FFC107; /* Yellow rope */
  114. border-radius: 50% 50% 0 0 / 100% 100% 0 0;
  115. z-index: 1;
  116. }
  117. .nail {
  118. position: absolute;
  119. top: -10rpx;
  120. width: 24rpx;
  121. height: 24rpx;
  122. background-color: #FFC107;
  123. border-radius: 50%;
  124. z-index: 2;
  125. box-shadow: 0 2rpx 4rpx rgba(0,0,0,0.2);
  126. }
  127. .board {
  128. position: absolute;
  129. top: 80rpx;
  130. width: 360rpx;
  131. height: 200rpx;
  132. background-color: #FF7043; /* Orange for working */
  133. border-radius: 20rpx;
  134. display: flex;
  135. justify-content: center;
  136. align-items: center;
  137. box-shadow: 0 10rpx 0 #E64A19;
  138. transition: all 0.3s;
  139. }
  140. .board.resting {
  141. background-color: #BDBDBD; /* Gray for resting */
  142. box-shadow: 0 10rpx 0 #9E9E9E;
  143. }
  144. .board-inner {
  145. width: 280rpx;
  146. height: 120rpx;
  147. background-color: #fff;
  148. border-radius: 10rpx;
  149. display: flex;
  150. justify-content: center;
  151. align-items: center;
  152. transform: rotate(-2deg); /* Slightly tilted inner paper */
  153. }
  154. .status-text {
  155. font-size: 48rpx;
  156. font-weight: bold;
  157. color: #FF5722;
  158. }
  159. .board.resting .status-text {
  160. color: #757575;
  161. }
  162. .screw {
  163. position: absolute;
  164. width: 16rpx;
  165. height: 16rpx;
  166. background-color: #fff;
  167. border-radius: 50%;
  168. opacity: 0.8;
  169. }
  170. .top-left { top: 20rpx; left: 20rpx; }
  171. .top-right { top: 20rpx; right: 20rpx; }
  172. .bottom-left { bottom: 20rpx; left: 20rpx; }
  173. .bottom-right { bottom: 20rpx; right: 20rpx; }
  174. /* 文本描述 */
  175. .status-desc {
  176. margin-bottom: 100rpx;
  177. color: #333;
  178. font-size: 30rpx;
  179. font-weight: 500;
  180. }
  181. /* 按钮区域 */
  182. .action-area {
  183. width: 80%;
  184. display: flex;
  185. flex-direction: column;
  186. align-items: center;
  187. }
  188. .action-btn {
  189. width: 100%;
  190. height: 88rpx;
  191. line-height: 88rpx;
  192. border-radius: 44rpx;
  193. color: #fff;
  194. font-size: 32rpx;
  195. font-weight: bold;
  196. margin-bottom: 30rpx;
  197. border: none;
  198. }
  199. .action-btn::after { border: none; }
  200. .action-btn.stop {
  201. background: linear-gradient(90deg, #FF9800 0%, #FF5722 100%);
  202. box-shadow: 0 10rpx 20rpx rgba(255, 87, 34, 0.3);
  203. }
  204. .action-btn.start {
  205. background: linear-gradient(90deg, #4CAF50 0%, #2E7D32 100%);
  206. box-shadow: 0 10rpx 20rpx rgba(76, 175, 80, 0.3);
  207. }
  208. .tips {
  209. font-size: 24rpx;
  210. color: #999;
  211. text-align: center;
  212. line-height: 1.5;
  213. }
  214. </style>