shopManage.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. <template>
  2. <view class="u-wrap">
  3. <view class="top-box">
  4. <view class="switch-box">
  5. <u-tabs :list="list1" lineWidth="30" lineColor="$uni-bg-color-primary" @click='handlerChangeTab' :activeStyle="{
  6. color: '#000',
  7. fontSize: '28rpx',
  8. transform: 'scale(1.05)',
  9. marginBottom: '15rpx',
  10. }" :inactiveStyle="{
  11. color: '#333',
  12. fontSize: '30rpx',
  13. transform: 'scale(1)',
  14. marginBottom: '15rpx',
  15. }" itemStyle="width:50%;padding:0;margin:5px 0;"></u-tabs>
  16. </view>
  17. <view class="search-box">
  18. <u--input v-model='search' prefixIcon="search" prefixIconStyle="font-size: 22px;color: #909399"
  19. class="search-ipt" placeholder="请输入内容" border="surround" clearable></u--input>
  20. <button class="btn" @click="handlerSearchBtn">搜索</button>
  21. </view>
  22. </view>
  23. <!-- 在售中 -->
  24. <view class="u-menu-wrap" v-if="delete_type == 0">
  25. <scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop"
  26. :scroll-into-view="itemId">
  27. <view v-for="(item,index) in tabbar" :key="index" class="u-tab-item"
  28. :class="[current == index ? 'u-tab-item-active' : '']" @tap.stop="swichMenu(index)">
  29. <text class="u-line-1">{{item.name}}</text>
  30. </view>
  31. </scroll-view>
  32. <scroll-view :scroll-top="scrollRightTop" scroll-y scroll-with-animation class="right-box" @scroll="rightScroll">
  33. <view class="page-view">
  34. <view class="class-item" :id="'item' + index" v-for="(item , index) in tabbar" :key="index">
  35. <view class="item-title">
  36. <text>{{item.name}}</text>
  37. </view>
  38. <view class="item-box" v-for="itm of item.foods" :key="idx">
  39. <view class="item-l">
  40. <img class="l-img" src="@/static/QR57a.jpg" alt="">
  41. </view>
  42. <view class="item-r">
  43. <p class='p1'>yizhiyang的鲜花{{itm.name}}11111111111111</p>
  44. <p class='p2'>月售100</p>
  45. <p class='p2'>库存90</p>
  46. <p class='p3'>¥100起</p>
  47. </view>
  48. </view>
  49. </view>
  50. </view>
  51. </scroll-view>
  52. </view>
  53. <!-- 已下架 -->
  54. <view class="u-menu-wrap" v-if="delete_type == 1">
  55. <scroll-view :scroll-top="scrollRightTop" scroll-y scroll-with-animation class="right-box" @scroll="rightScroll">
  56. <view class="page-view">
  57. <view class="class-item2" :id="'item' + index" v-for="(item , index) in tabbar" :key="index">
  58. <view class="item-box" v-for="itm of item.foods" :key="idx">
  59. <u-checkbox-group>
  60. <u-checkbox v-model="checked" shape="circle" ></u-checkbox>
  61. </u-checkbox-group>
  62. <view class="item-l">
  63. <img class="l-img" src="@/static/QR57a.jpg" alt="">
  64. </view>
  65. <view class="item-r">
  66. <p class='type_p1'>yizhiyang的鲜花{{itm.name}}11111111111111</p>
  67. <p class='p2'>月售100</p>
  68. <p class='p2'>库存90</p>
  69. <p class='p3'>¥100起</p>
  70. </view>
  71. </view>
  72. </view>
  73. </view>
  74. </scroll-view>
  75. </view>
  76. <view class="bottom-box" v-if="delete_type == 1">
  77. <p>批量上架</p>
  78. <p>批量删除</p>
  79. </view>
  80. </view>
  81. </template>
  82. <script>
  83. export default {
  84. data() {
  85. return {
  86. scrollTop: 0, //tab标题的滚动条位置
  87. oldScrollTop: 0, // tab标题的滚动条旧位置
  88. current: 0, // 预设当前项的值
  89. menuHeight: 0, // 左边菜单的高度
  90. menuItemHeight: 0, // 左边菜单item的高度
  91. itemId: '', // 栏目右边scroll-view用于滚动的id
  92. arr: [], // 储存距离顶部高度的数组
  93. scrollRightTop: 0, // 右边栏目scroll-view的滚动条高度
  94. timer: null, // 定时器
  95. tabbar: [{
  96. "name": "蔬菜水果",
  97. "foods": [{
  98. "cat": 383,
  99. "name": "蔬菜",
  100. "icon": "http://nq348.com/uploads/category/20220315/1aeed6fa43b54cd68cce0c4883160f91.png",
  101. "key": "蔬菜"
  102. },
  103. {
  104. "cat": 384,
  105. "name": "食用菌",
  106. "icon": "http://nq348.com/uploads/category/20220418/09839c618b35b510d50151f9a17793ee.png",
  107. "key": "食用菌"
  108. },
  109. {
  110. "cat": 385,
  111. "name": "水果",
  112. "icon": "http://nq348.com/uploads/category/20220418/5294ad2fc7effc9629cbfdb8baf41773.png",
  113. "key": "水果"
  114. }
  115. ]
  116. },
  117. {
  118. "name": "畜禽养殖",
  119. "foods": [{
  120. "cat": 388,
  121. "name": "禽类",
  122. "icon": "http://nq348.com/uploads/category/20220418/da31895fc5a9aacf93fea6f27f08afd7.png",
  123. "key": "禽类"
  124. },
  125. {
  126. "cat": 389,
  127. "name": "畜类",
  128. "icon": "http://nq348.com/uploads/category/20220418/6352081e3f3b36f9360a933676e9452c.png",
  129. "key": "畜类"
  130. },
  131. {
  132. "cat": 391,
  133. "name": "蛋类",
  134. "icon": "http://nq348.com/uploads/category/20220418/d2e7ab4224679c0c796ba3ddd8a68e2f.png",
  135. "key": "蛋类"
  136. },
  137. {
  138. "cat": 390,
  139. "name": "水产",
  140. "icon": "http://nq348.com/uploads/category/20220418/52a1f1baa7617ef4d4e1a4b344b2fce7.png",
  141. "key": "水产"
  142. }
  143. ]
  144. },
  145. {
  146. "name": "粮油副食",
  147. "foods": [{
  148. "cat": 393,
  149. "name": "米面粮油",
  150. "icon": "http://nq348.com/uploads/category/20220418/1bb32e319ecf5aa352b7fe26fc265004.png",
  151. "key": "米面粮油"
  152. },
  153. {
  154. "cat": 394,
  155. "name": "坚果干果",
  156. "icon": "http://nq348.com/uploads/category/20220418/6ded13eae4a3b113b5225ca8b99bbfdd.png",
  157. "key": "坚果干果"
  158. },
  159. {
  160. "cat": 395,
  161. "name": "加工食品",
  162. "icon": "http://nq348.com/uploads/category/20220418/1e1c10838799de5834aa77f0f9eb8f40.png",
  163. "key": "加工食品"
  164. },
  165. {
  166. "cat": 396,
  167. "name": "茶烟酒",
  168. "icon": "http://nq348.com/uploads/category/20220418/c43cd994e49023c7efdf2b18b1bca30b.png",
  169. "key": "茶烟酒"
  170. }
  171. ]
  172. },
  173. {
  174. "name": "花卉苗木",
  175. "foods": [{
  176. "cat": 398,
  177. "name": "鲜花盆景",
  178. "icon": "http://nq348.com/uploads/category/20220418/b21c44045daaa8b8d148981ba9efc2e0.png",
  179. "key": "鲜花盆景"
  180. },
  181. {
  182. "cat": 399,
  183. "name": "果树苗",
  184. "icon": "http://nq348.com/uploads/category/20220418/63ee2b902ff0f4d638d8a5ad770f7641.png",
  185. "key": "果树苗"
  186. },
  187. {
  188. "cat": 400,
  189. "name": "蔬瓜种子",
  190. "icon": "http://nq348.com/uploads/category/20220418/2df521877616ee44fd01aae0434a5815.png",
  191. "key": "蔬瓜种子"
  192. },
  193. {
  194. "cat": 401,
  195. "name": "经济作物",
  196. "icon": "http://nq348.com/uploads/category/20220418/f85be72a98694befd889f30de45a1d64.png",
  197. "key": "经济作物"
  198. }
  199. ]
  200. },
  201. {
  202. "name": "中草药材",
  203. "foods": [{
  204. "cat": 403,
  205. "name": "全草类",
  206. "icon": "http://nq348.com/uploads/category/20220418/01812c1a83f5db7eafbf3bdae927f134.png",
  207. "key": "全草类"
  208. },
  209. {
  210. "cat": 405,
  211. "name": "根茎皮叶花",
  212. "icon": "http://nq348.com/uploads/category/20220418/dca8dcc814401474d4f19ae7394cc209.png",
  213. "key": "根茎皮叶花"
  214. },
  215. {
  216. "cat": 406,
  217. "name": "滋补品类",
  218. "icon": "http://nq348.com/uploads/category/20220418/33b965295811fdd6f5e672e9a3ce34a2.png",
  219. "key": "滋补品类"
  220. },
  221. {
  222. "cat": 404,
  223. "name": "果实籽仁类",
  224. "icon": "http://nq348.com/uploads/category/20220418/1dc8c46c66b4625d458a7f45787ecef9.png",
  225. "key": "果实籽仁类"
  226. }
  227. ]
  228. },
  229. {
  230. "name": "其他",
  231. "foods": [{
  232. "cat": 434,
  233. "name": "包装",
  234. "icon": "http://nq348.com/uploads/category/20220418/ebdfd326333344825adbe81dbd89e2c9.png",
  235. "key": "包装"
  236. },
  237. {
  238. "cat": 435,
  239. "name": "安全溯源",
  240. "icon": "http://nq348.com/uploads/category/20220418/03230c63f066f46005abf5f576df0ed1.png",
  241. "key": "安全溯源"
  242. },
  243. {
  244. "cat": 436,
  245. "name": "农用百货",
  246. "icon": "http://nq348.com/uploads/category/20220418/93393f2df3264faba86bb449a0c10a79.png",
  247. "key": "农用百货"
  248. },
  249. {
  250. "cat": 437,
  251. "name": "仓储物流",
  252. "icon": "http://nq348.com/uploads/category/20220418/f553505ebabbcb1bf762b288716cf1e7.png",
  253. "key": "仓储物流"
  254. }
  255. ]
  256. }
  257. ],
  258. list1: [{
  259. name: '在售中',
  260. }, {
  261. name: '已下架',
  262. }],
  263. checked:false,
  264. search: '',
  265. delete_type: false,
  266. }
  267. },
  268. /**
  269. * 获取一个目标元素的高度
  270. * @elClass 元素的类名
  271. * @dataVal 储存高度的对象
  272. */
  273. onReady() {
  274. this.getMenuItemTop()
  275. },
  276. watch: {
  277. delete_type(newValue) {
  278. this.scrollRightTop = 0
  279. this.current = 0
  280. }
  281. },
  282. methods: {
  283. getElRect(elClass, dataVal) {
  284. new Promise((resolve, reject) => {
  285. const query = uni.createSelectorQuery().in(this);
  286. query.select('.' + elClass).fields({
  287. size: true
  288. }, res => {
  289. // 如果节点尚未生成,res值为null,循环调用执行
  290. if (!res) {
  291. setTimeout(() => {
  292. this.getElRect(elClass);
  293. }, 10);
  294. return;
  295. }
  296. this[dataVal] = res.height;
  297. resolve();
  298. }).exec();
  299. })
  300. },
  301. getMenuItemTop() {
  302. new Promise(resolve => {
  303. let selectorQuery = uni.createSelectorQuery();
  304. selectorQuery.selectAll('.class-item').boundingClientRect((rects) => {
  305. // 如果节点尚未生成,rects值为[](因为用selectAll,所以返回的是数组),循环调用执行
  306. if (!rects.length) {
  307. setTimeout(() => {
  308. this.getMenuItemTop();
  309. }, 10);
  310. return;
  311. }
  312. rects.forEach((rect) => {
  313. // 视情况而定,这里减去rects[0].top,是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况)
  314. this.arr.push(rect.top - rects[0].top);
  315. // this.arr.push(rect.top)
  316. resolve();
  317. })
  318. }).exec()
  319. })
  320. },
  321. /**
  322. * 观测元素相交状态
  323. * 检测右边scroll-view的id为itemxx的元素与right-box的相交状态
  324. * 如果跟.right-box底部相交,就动态设置左边栏目的活动状态
  325. */
  326. async observer() {
  327. this.tabbar.map((val, index) => {
  328. let observer = uni.createIntersectionObserver(this);
  329. observer.relativeTo('.right-box', {
  330. top: 0
  331. }).observe('#item' + index, res => {
  332. if (res.intersectionRatio > 0) {
  333. let id = res.id.substring(4);
  334. this.leftMenuStatus(id);
  335. }
  336. })
  337. })
  338. },
  339. /**
  340. * 设置左边菜单的滚动状态
  341. * @index 传入的 ID
  342. */
  343. async leftMenuStatus(index) {
  344. this.current = index;
  345. // 如果为0,意味着尚未初始化
  346. if (this.menuHeight == 0 || this.menuItemHeight == 0) {
  347. await this.getElRect('menu-scroll-view', 'menuHeight');
  348. await this.getElRect('u-tab-item', 'menuItemHeight');
  349. }
  350. // 将菜单活动item垂直居中
  351. this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
  352. },
  353. /**
  354. * 点击左边的栏目切换
  355. * @index 传入的 ID
  356. */
  357. async swichMenu(index) {
  358. if (this.arr.length == 0) {
  359. await this.getMenuItemTop();
  360. }
  361. if (index == this.current) return;
  362. this.scrollRightTop = this.oldScrollTop;
  363. this.$nextTick(function() {
  364. this.scrollRightTop = this.arr[index];
  365. this.current = index;
  366. this.leftMenuStatus(index);
  367. })
  368. },
  369. /**
  370. * 右边菜单滚动
  371. * 如果不存在height2,意味着数据循环已经到了最后一个,设置左边菜单为最后一项即可
  372. */
  373. async rightScroll(e) {
  374. this.oldScrollTop = e.detail.scrollTop;
  375. if (this.arr.length == 0) {
  376. await this.getMenuItemTop();
  377. }
  378. if (this.timer) return;
  379. if (!this.menuHeight) {
  380. await this.getElRect('menu-scroll-view', 'menuHeight');
  381. }
  382. setTimeout(() => { // 节流
  383. this.timer = null;
  384. // scrollHeight为右边菜单垂直中点位置
  385. // let scrollHeight = e.detail.scrollTop + this.menuHeight / 2;
  386. // scrollHeight为右边菜单头部位置
  387. let scrollHeight = e.detail.scrollTop + 20;
  388. for (let i = 0; i < this.arr.length; i++) {
  389. let height1 = this.arr[i];
  390. let height2 = this.arr[i + 1];
  391. if (!height2 || scrollHeight >= height1 && scrollHeight < height2) {
  392. this.leftMenuStatus(i);
  393. return;
  394. }
  395. }
  396. }, 10)
  397. },
  398. // 搜索按钮
  399. handlerSearchBtn() {
  400. console.log('search', this.search);
  401. },
  402. // 切换tab
  403. handlerChangeTab(e) {
  404. if (e.index == 1) {
  405. this.delete_type = true
  406. } else {
  407. this.delete_type = false
  408. }
  409. }
  410. }
  411. }
  412. </script>
  413. <style lang="scss" scoped>
  414. .top-box {
  415. padding: 0 0 20rpx;
  416. width: 100%;
  417. .switch-box {
  418. width: 100%;
  419. }
  420. .search-box {
  421. display: flex;
  422. justify-content: space-around;
  423. width: 90%;
  424. margin: 20rpx auto 0;
  425. .btn {
  426. width: 160rpx;
  427. height: 70rpx;
  428. background-color: #5992BB;
  429. color: #fff;
  430. text-align: center;
  431. line-height: 70rpx;
  432. font-size: 26rpx;
  433. border-radius: 30rpx;
  434. margin-left: 20rpx;
  435. }
  436. }
  437. }
  438. .u-wrap {
  439. /* #ifdef H5 */
  440. height: calc(100vh - var(--window-top));
  441. /* #endif */
  442. display: flex;
  443. flex-direction: column;
  444. height: 100vh;
  445. }
  446. .u-search-box {
  447. padding: 18rpx 30rpx;
  448. }
  449. .u-menu-wrap {
  450. flex: 1;
  451. display: flex;
  452. overflow: hidden;
  453. }
  454. .u-tab-view {
  455. width: 200rpx;
  456. background-color: #f6f6f6;
  457. }
  458. .u-tab-item {
  459. height: 110rpx;
  460. background: #f6f6f6;
  461. box-sizing: border-box;
  462. display: flex;
  463. align-items: center;
  464. justify-content: center;
  465. font-size: 26rpx;
  466. color: #444;
  467. font-weight: 400;
  468. line-height: 1;
  469. padding: 16rpx 0;
  470. }
  471. .u-tab-item-active {
  472. position: relative;
  473. color: #5F96BE;
  474. font-size: 30rpx;
  475. font-weight: 500;
  476. background: #FFF;
  477. }
  478. .u-tab-item-active::before {
  479. content: "";
  480. position: absolute;
  481. border-left: 4px solid #5F96BE;
  482. height: 52rpx;
  483. left: 0;
  484. top: 29rpx;
  485. }
  486. .u-tab-view {
  487. height: 100%;
  488. }
  489. .right-box {
  490. background-color: rgb(250, 250, 250);
  491. }
  492. .page-view {
  493. padding: 16rpx;
  494. }
  495. .class-item,
  496. .class-item2 {
  497. margin-bottom: 30rpx;
  498. background-color: #fff;
  499. padding: 16rpx;
  500. border-radius: 8rpx;
  501. }
  502. .class-item2 {
  503. margin-bottom: 0;
  504. }
  505. .item-title {
  506. font-size: 26rpx;
  507. text-align: center;
  508. color: #5F96BE;
  509. margin-bottom: 20rpx;
  510. }
  511. .item-box {
  512. display: flex;
  513. margin-bottom: 10rpx;
  514. .item-l {
  515. border: 2rpx solid #EEF0F0;
  516. border-radius: 20rpx;
  517. margin-right: 20rpx;
  518. .l-img {
  519. width: 140rpx;
  520. height: 130rpx;
  521. border-radius: 20rpx;
  522. }
  523. }
  524. .item-r {
  525. .p1,
  526. .type_p1 {
  527. width: 350rpx;
  528. font-size: 28rpx;
  529. color: #000;
  530. margin-bottom: 5rpx;
  531. overflow-x: hidden;
  532. text-overflow: ellipsis;
  533. white-space: nowrap;
  534. }
  535. .type_p1 {
  536. width: 480rpx;
  537. }
  538. .p2 {
  539. font-size: 24rpx;
  540. color: #A4A5AD;
  541. }
  542. .p3 {
  543. font-size: 26rpx;
  544. color: #D6534D;
  545. }
  546. }
  547. }
  548. .bottom-box {
  549. width: 100%;
  550. background-color: #fff;
  551. padding: 10rpx 20rpx;
  552. height: 100rpx;
  553. border-top: 2rpx solid #F7F7F7;
  554. box-shadow: 0px 7px 10px 7px rgba(0, 0, 0, 0.1);
  555. display: flex;
  556. justify-content: space-around;
  557. line-height: 100rpx;
  558. font-size: 28rpx;
  559. }
  560. ::v-deep .u-input--radius.data-v-fdbb9fe6,
  561. .u-input--square.data-v-fdbb9fe6 {
  562. background-color: #F7F7F7 !important;
  563. padding: 40rpx;
  564. border-radius: 50rpx;
  565. }
  566. </style>