建材商城系统20241014
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.

336 lines
9.8 KiB

  1. <template>
  2. <movable-area class="movable-area">
  3. <movable-view
  4. class="movable-view"
  5. :x="x"
  6. :y="y"
  7. direction="all"
  8. @click="handleClick"
  9. :animation="false"
  10. :damping="200"
  11. @change="handleChange"
  12. @longpress="handleLongPress">
  13. <view class="quick-order-container">
  14. <view class="new-message" v-if="innerHasNewMessage" @click.stop="goToOrderList">
  15. 你有新的快捷下单信息
  16. </view>
  17. <view class="quick-order">
  18. <view class="number-order" v-if="innerMessageCount > 0">
  19. {{ innerMessageCount }}
  20. </view>
  21. <image :src="imageUrl" mode=""></image>
  22. <view class="long-press-hint">长按查看更多</view>
  23. </view>
  24. </view>
  25. </movable-view>
  26. </movable-area>
  27. </template>
  28. <script>
  29. export default {
  30. name: 'QuickOrderEntry',
  31. props: {
  32. // 图标路径
  33. imageUrl: {
  34. type: String,
  35. default: '/static/image/home/7.png'
  36. },
  37. // 点击跳转的页面
  38. targetUrl: {
  39. type: String,
  40. default: '/pages_order/order/fastCreateOrder'
  41. },
  42. // 是否自动获取快捷下单信息
  43. autoFetch: {
  44. type: Boolean,
  45. default: true
  46. }
  47. },
  48. data() {
  49. return {
  50. orderInfo: null,
  51. innerHasNewMessage: false,
  52. innerMessageCount: 0,
  53. isInitialized: false,
  54. timer: null, // 定时器ID
  55. x: 0, // 拖拽位置x
  56. y: 0 // 拖拽位置y
  57. }
  58. },
  59. mounted() {
  60. // 初始化拖拽位置
  61. this.initDragPosition()
  62. this.getQuickOrderInfo()
  63. // 开启定时器,每30秒更新一次数据
  64. this.startTimer()
  65. uni.$on('getQuickOrderInfo', this.getQuickOrderInfo)
  66. },
  67. beforeDestroy() {
  68. // 组件销毁前清除定时器
  69. this.clearTimer()
  70. uni.$off('getQuickOrderInfo', this.getQuickOrderInfo)
  71. },
  72. methods: {
  73. // 初始化拖拽位置
  74. initDragPosition() {
  75. // 尝试从本地存储恢复保存的位置
  76. const savedPosition = uni.getStorageSync('quickOrderPosition')
  77. if (savedPosition && savedPosition.x !== undefined && savedPosition.y !== undefined) {
  78. // 如果有保存的位置,使用保存的位置
  79. this.x = savedPosition.x
  80. this.y = savedPosition.y
  81. }
  82. },
  83. // 处理拖拽位置变化
  84. handleChange(e) {
  85. const { x, y, source } = e.detail
  86. // 只保存用户主动拖拽的位置,不保存系统自动调整的位置
  87. if (source === 'touch') {
  88. // 保存位置到本地存储
  89. uni.setStorageSync('quickOrderPosition', { x, y })
  90. }
  91. },
  92. // 处理点击事件
  93. async handleClick() {
  94. // 发出点击事件,便于父组件监听
  95. this.$emit('click');
  96. await this.getQuickOrderInfo()
  97. // 如果有订单信息,提供订单列表
  98. if (Array.isArray(this.orderInfo) && this.orderInfo.length > 0) {
  99. this.$emit('order-info', this.orderInfo);
  100. this.navigateTo('/pages_order/order/firmOrder');
  101. return
  102. }
  103. // 如果有目标页面,则跳转
  104. if (this.targetUrl) {
  105. this.navigateTo(this.targetUrl);
  106. }
  107. },
  108. // 处理长按事件 - 跳转到快捷订单列表
  109. handleLongPress() {
  110. // 震动反馈
  111. uni.vibrateShort();
  112. // 显示操作菜单
  113. uni.showActionSheet({
  114. itemList: ['快捷下单', '我的快捷订单'],
  115. success: (res) => {
  116. if (res.tapIndex === 0) {
  117. // 跳转到快捷下单页面
  118. this.navigateTo(this.targetUrl);
  119. } else if (res.tapIndex === 1) {
  120. // 跳转到快捷订单列表
  121. this.navigateTo('/pages_order/order/fastOrderList');
  122. }
  123. }
  124. });
  125. },
  126. // 直接跳转到快捷订单列表
  127. goToOrderList() {
  128. this.navigateTo('/pages_order/order/fastOrderList');
  129. },
  130. // 获取快捷下单的信息
  131. getQuickOrderInfo() {
  132. if(!uni.getStorageSync('token')){
  133. return
  134. }
  135. // 调用接口获取快捷下单信息
  136. return this.$api('getOrderInfo', {}, res => {
  137. if (res.code === 200 && res.result) {
  138. // 处理返回的订单列表
  139. const orderList = Array.isArray(res.result) ? res.result : [res.result];
  140. if (orderList.length > 0) {
  141. // 保存订单列表
  142. this.orderInfo = orderList;
  143. // 设置消息数量为订单列表长度
  144. this.innerHasNewMessage = true;
  145. this.innerMessageCount = orderList.length;
  146. // 通知父组件获取到了数据
  147. this.$emit('order-loaded', this.orderInfo);
  148. } else {
  149. this.innerHasNewMessage = false;
  150. this.innerMessageCount = 0;
  151. this.orderInfo = [];
  152. }
  153. } else {
  154. this.innerHasNewMessage = false;
  155. this.innerMessageCount = 0;
  156. this.orderInfo = [];
  157. }
  158. this.isInitialized = true;
  159. }, err => {
  160. console.error('获取快捷下单信息失败', err);
  161. this.innerHasNewMessage = false;
  162. this.innerMessageCount = 0;
  163. this.orderInfo = [];
  164. this.isInitialized = true;
  165. });
  166. },
  167. // 导航到指定页面
  168. navigateTo(url) {
  169. // 如果有订单列表,则优先使用第一个订单的ID
  170. if (Array.isArray(this.orderInfo) && this.orderInfo.length > 0 && this.orderInfo[0].id && url.indexOf('?') === -1) {
  171. url += `?orderId=${this.orderInfo[0].id}`;
  172. }
  173. this.$utils.navigateTo(url);
  174. },
  175. // 刷新快捷下单信息
  176. refresh() {
  177. this.getQuickOrderInfo();
  178. return this; // 链式调用
  179. },
  180. // 清除消息提示
  181. clearMessage() {
  182. this.innerHasNewMessage = false;
  183. this.innerMessageCount = 0;
  184. return this; // 链式调用
  185. },
  186. // 检查是否有新消息
  187. hasNewMessage() {
  188. return this.innerHasNewMessage;
  189. },
  190. // 获取消息数量
  191. getMessageCount() {
  192. return this.innerMessageCount;
  193. },
  194. // 开启定时器
  195. startTimer() {
  196. // 清除之前的定时器(如果存在)
  197. this.clearTimer()
  198. // 设置新的定时器,每30秒执行一次
  199. this.timer = setInterval(() => {
  200. // 只有在有token的情况下才更新数据
  201. if (uni.getStorageSync('token')) {
  202. this.getQuickOrderInfo()
  203. }
  204. }, 30000)
  205. },
  206. // 清除定时器
  207. clearTimer() {
  208. if (this.timer) {
  209. clearInterval(this.timer)
  210. this.timer = null
  211. }
  212. },
  213. },
  214. }
  215. </script>
  216. <style scoped lang="scss">
  217. .movable-area {
  218. height: 100vh;
  219. width: 750rpx;
  220. top: 0;
  221. position: fixed;
  222. pointer-events: none; // 此处要加,鼠标事件可以渗透
  223. z-index: 99;
  224. .movable-view {
  225. width: 230rpx;
  226. height: 160rpx;
  227. pointer-events: auto; // 恢复鼠标事件
  228. transition: transform 0.3s;
  229. left: 600rpx;
  230. top: 50%;
  231. &:active {
  232. transform: scale(0.95);
  233. }
  234. }
  235. }
  236. .quick-order-container {
  237. width: 100%;
  238. height: 100%;
  239. position: relative;
  240. .new-message {
  241. position: absolute;
  242. top: 50rpx;
  243. right: 100%;
  244. white-space: nowrap;
  245. background-color: #DC2828;
  246. border-radius: 20rpx;
  247. font-size: 25rpx;
  248. color: #ffffff;
  249. padding: 5rpx 15rpx;
  250. margin-bottom: 10rpx;
  251. box-shadow: 0 5rpx 10rpx rgba(220, 40, 40, 0.3);
  252. animation: pulse 2s infinite;
  253. }
  254. .quick-order {
  255. position: relative;
  256. width: 230rpx;
  257. height: 160rpx;
  258. image {
  259. width: 100%;
  260. height: 100%;
  261. }
  262. .number-order {
  263. background-color: #DC2828;
  264. position: absolute;
  265. font-size: 30rpx;
  266. height: 40rpx;
  267. width: 40rpx;
  268. text-align: center;
  269. border-radius: 20rpx;
  270. color: #ffffff;
  271. top: 10rpx;
  272. left: 25rpx;
  273. }
  274. .long-press-hint {
  275. position: absolute;
  276. bottom: -30rpx;
  277. left: 50%;
  278. transform: translateX(-50%);
  279. background-color: rgba(0, 0, 0, 0.7);
  280. color: #fff;
  281. font-size: 20rpx;
  282. padding: 4rpx 12rpx;
  283. border-radius: 12rpx;
  284. white-space: nowrap;
  285. opacity: 0.8;
  286. }
  287. }
  288. }
  289. @keyframes pulse {
  290. 0% {
  291. transform: scale(1);
  292. }
  293. 50% {
  294. transform: scale(1.05);
  295. }
  296. 100% {
  297. transform: scale(1);
  298. }
  299. }
  300. </style>