index.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. }
  62. },
  63. async toggleStatus() {
  64. if (this.loading) return;
  65. // 确定目标状态
  66. const targetStatus = this.status === 'busy' ? 'resting' : 'busy';
  67. const actionText = targetStatus === 'busy' ? '恢复接单' : '停止接单';
  68. try {
  69. uni.showLoading({ title: '处理中...', mask: true });
  70. this.loading = true;
  71. // 向后端发送请求
  72. await updateStatus(targetStatus);
  73. // 成功后重新获取用户信息以更新本地状态
  74. await this.fetchLatestProfile();
  75. uni.hideLoading();
  76. uni.showToast({ title: actionText + '成功', icon: 'success' });
  77. } catch (err) {
  78. uni.hideLoading();
  79. console.error('切换状态失败:', err);
  80. uni.showToast({ title: err.message || '操作失败', icon: 'none' });
  81. } finally {
  82. this.loading = false;
  83. }
  84. }
  85. }
  86. }
  87. </script>
  88. <style>
  89. page {
  90. background-color: #fff;
  91. }
  92. .container {
  93. display: flex;
  94. flex-direction: column;
  95. align-items: center;
  96. padding-top: 100rpx;
  97. }
  98. /* 挂牌动画区域 */
  99. .signboard-container {
  100. position: relative;
  101. width: 400rpx;
  102. height: 300rpx;
  103. display: flex;
  104. justify-content: center;
  105. margin-bottom: 60rpx;
  106. }
  107. .rope {
  108. position: absolute;
  109. top: 0;
  110. width: 200rpx;
  111. height: 100rpx;
  112. border-top: 4rpx solid #FFC107; /* Yellow rope */
  113. border-radius: 50% 50% 0 0 / 100% 100% 0 0;
  114. z-index: 1;
  115. }
  116. .nail {
  117. position: absolute;
  118. top: -10rpx;
  119. width: 24rpx;
  120. height: 24rpx;
  121. background-color: #FFC107;
  122. border-radius: 50%;
  123. z-index: 2;
  124. box-shadow: 0 2rpx 4rpx rgba(0,0,0,0.2);
  125. }
  126. .board {
  127. position: absolute;
  128. top: 80rpx;
  129. width: 360rpx;
  130. height: 200rpx;
  131. background-color: #FF7043; /* Orange for working */
  132. border-radius: 20rpx;
  133. display: flex;
  134. justify-content: center;
  135. align-items: center;
  136. box-shadow: 0 10rpx 0 #E64A19;
  137. transition: all 0.3s;
  138. }
  139. .board.resting {
  140. background-color: #BDBDBD; /* Gray for resting */
  141. box-shadow: 0 10rpx 0 #9E9E9E;
  142. }
  143. .board-inner {
  144. width: 280rpx;
  145. height: 120rpx;
  146. background-color: #fff;
  147. border-radius: 10rpx;
  148. display: flex;
  149. justify-content: center;
  150. align-items: center;
  151. transform: rotate(-2deg); /* Slightly tilted inner paper */
  152. }
  153. .status-text {
  154. font-size: 48rpx;
  155. font-weight: bold;
  156. color: #FF5722;
  157. }
  158. .board.resting .status-text {
  159. color: #757575;
  160. }
  161. .screw {
  162. position: absolute;
  163. width: 16rpx;
  164. height: 16rpx;
  165. background-color: #fff;
  166. border-radius: 50%;
  167. opacity: 0.8;
  168. }
  169. .top-left { top: 20rpx; left: 20rpx; }
  170. .top-right { top: 20rpx; right: 20rpx; }
  171. .bottom-left { bottom: 20rpx; left: 20rpx; }
  172. .bottom-right { bottom: 20rpx; right: 20rpx; }
  173. /* 文本描述 */
  174. .status-desc {
  175. margin-bottom: 100rpx;
  176. color: #333;
  177. font-size: 30rpx;
  178. font-weight: 500;
  179. }
  180. /* 按钮区域 */
  181. .action-area {
  182. width: 80%;
  183. display: flex;
  184. flex-direction: column;
  185. align-items: center;
  186. }
  187. .action-btn {
  188. width: 100%;
  189. height: 88rpx;
  190. line-height: 88rpx;
  191. border-radius: 44rpx;
  192. color: #fff;
  193. font-size: 32rpx;
  194. font-weight: bold;
  195. margin-bottom: 30rpx;
  196. border: none;
  197. }
  198. .action-btn::after { border: none; }
  199. .action-btn.stop {
  200. background: linear-gradient(90deg, #FF9800 0%, #FF5722 100%);
  201. box-shadow: 0 10rpx 20rpx rgba(255, 87, 34, 0.3);
  202. }
  203. .action-btn.start {
  204. background: linear-gradient(90deg, #4CAF50 0%, #2E7D32 100%);
  205. box-shadow: 0 10rpx 20rpx rgba(76, 175, 80, 0.3);
  206. }
  207. .tips {
  208. font-size: 24rpx;
  209. color: #999;
  210. text-align: center;
  211. line-height: 1.5;
  212. }
  213. </style>