order.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. <template>
  2. <Theme>
  3. <view class="wrap">
  4. <Navbar fixed border :navShow="navShow">
  5. <template #center>
  6. <view class="nav_search">
  7. <Search
  8. v-model="searchValue"
  9. @confirm="searchConfirm"
  10. :placeholder="t('名称订单号商品名称')"
  11. >
  12. <template #prefix>
  13. <i class="icon-font icon-search"></i>
  14. </template>
  15. </Search>
  16. </view>
  17. </template>
  18. <template #right>
  19. <navFilter @submit="filterSubmit" v-if="tabActive == 0" />
  20. <navMenu
  21. :options="{ icon: 'icon-home', text: '主页' }"
  22. page="order"
  23. />
  24. </template>
  25. </Navbar>
  26. <view class="content1">
  27. <view class="cont_tab">
  28. <up-tabs
  29. :key="tabActive"
  30. :current="tabActive"
  31. :list="tabList"
  32. keyName="text"
  33. @click="tabConfirm"
  34. lineColor="var(--black)"
  35. :activeStyle="{
  36. color: 'var(--black)',
  37. fontWeight: 'bold',
  38. transform: 'scale(1.05)',
  39. }"
  40. :inactiveStyle="{
  41. color: '#606266',
  42. transform: 'scale(1)',
  43. }"
  44. >
  45. </up-tabs>
  46. </view>
  47. <view
  48. class="cont"
  49. :style="{ '--height': footerHeight + tabbarHeight + 'px' }"
  50. >
  51. <List
  52. url="/shop/order/list"
  53. :topHeight="tabHeight"
  54. :defaultParams="{ keywords: searchValue, ...params }"
  55. ref="listRef"
  56. @datas="getAllData"
  57. >
  58. <template #item="{ item }">
  59. <view class="order_list">
  60. <view class="order_header">
  61. <template v-if="tabActive == 1 && navShow">
  62. <up-checkbox-group
  63. :modelValue="ids"
  64. activeColor="var(--black)"
  65. labelSize="14"
  66. labelColor="#676969"
  67. iconSize="16"
  68. @change="checkedChanges(item.id)"
  69. >
  70. <up-checkbox :name="item.id" />
  71. </up-checkbox-group>
  72. </template>
  73. <view class="header_img">
  74. <image
  75. :src="`../../static/shop/icon_${item.channel}.png`"
  76. class="img"
  77. ></image>
  78. </view>
  79. <view class="create_time">
  80. <trans _t="创建时间" />:
  81. {{ useGlobal().$format(item.indate) }}
  82. </view>
  83. </view>
  84. <view class="order_item">
  85. <view
  86. class="order_item_wrapper"
  87. v-for="(val, num) in item.goods"
  88. :key="num"
  89. @click="listClick(item)"
  90. >
  91. <view class="_item_wrapper">
  92. <view class="thumb_img">
  93. <image :src="val.pic_url" class="_img"></image>
  94. </view>
  95. <view class="goods_info">
  96. <view class="info_name">
  97. <view class="_name">{{ val.goodTitle }}</view>
  98. <view class="_price"
  99. >{{ symbol.symbol }}&nbsp;{{
  100. Moneyhtml(val.price)
  101. }}</view
  102. >
  103. </view>
  104. <view class="spec_info">
  105. <view class="spec_desc">{{ val.sku_desc }}</view>
  106. <view class="spec_num">x{{ val.total }}</view>
  107. </view>
  108. </view>
  109. </view>
  110. <view class="order_status">
  111. <text>{{ item.status_txt }}&nbsp;</text>
  112. <!-- <i class="icon-font icon-question2"></i> -->
  113. </view>
  114. </view>
  115. <view class="order_footer">
  116. <view class="order_price">
  117. <view class="price_text"> <trans _t="总价" />: </view>
  118. <text
  119. >{{ symbol.symbol }}{{ Moneyhtml(item.amount) }}</text
  120. >
  121. <!-- <i class="icon-font icon-question2"></i> -->
  122. </view>
  123. <view class="end_time" v-if="item.payStatus == 100">
  124. <trans _t="结束时间" />:
  125. {{ useGlobal().$format(item.enddate) }}
  126. </view>
  127. <view class="order_btns" v-if="item.status == 900">
  128. <view class="btn">
  129. <trans _t="删除订单" />
  130. </view>
  131. </view>
  132. <view class="order_btns" v-if="item.status == 100">
  133. <view class="btn" @click.stop="orderCancel(item)">
  134. <trans _t="取消" />
  135. </view>
  136. <view class="btn pay_btn" @click.stop="paySubmit(item)">
  137. <trans _t="支付" />
  138. </view>
  139. </view>
  140. </view>
  141. </view>
  142. </view>
  143. </template>
  144. </List>
  145. </view>
  146. <view
  147. class="cont_footer"
  148. id="footer"
  149. v-if="tabActive == 1 && navShow"
  150. :style="{ '--tabbarHeight': tabbarHeight + 'px' }"
  151. >
  152. <up-checkbox
  153. :label="t('全选')"
  154. :disabled="!allId.length"
  155. activeColor="var(--black)"
  156. labelSize="14"
  157. labelColor="#676969"
  158. iconSize="16"
  159. name="agree"
  160. usedAlone
  161. v-model:checked="selectAllChecked"
  162. @change="selectAllChange"
  163. >
  164. </up-checkbox>
  165. <view
  166. class="total_btn"
  167. @click.stop="submit"
  168. :style="{ opacity: ids.length ? 1 : 0.5 }"
  169. >
  170. <trans _t="合并付款" />
  171. </view>
  172. </view>
  173. </view>
  174. </view>
  175. <cancelModel ref="cancelModelRef" />
  176. </Theme>
  177. </template>
  178. <script setup>
  179. import Navbar from "@/components/navbar";
  180. import navMenu from "@/components/nav_menu";
  181. import navFilter from "@/components/nav_filter";
  182. import Search from "@/components/input";
  183. import Tab from "@/components/tabs";
  184. import List from "@/components/list";
  185. import cancelModel from "./components/cancelModel.vue";
  186. import { ref, onMounted, nextTick, computed, watch, watchEffect } from "vue";
  187. import { t } from "@/locale";
  188. import { useGlobal, Toast, Moneyhtml, query } from "@/utils";
  189. import { useSystemStore, useShopStore } from "@/store";
  190. import { SHOP_ORDER_GETPAY } from "@/api";
  191. import { onShow, onReachBottom } from "@dcloudio/uni-app";
  192. const props = defineProps({
  193. tabHeight: {
  194. type: Number,
  195. default: 0,
  196. },
  197. tabbarHeight: {
  198. type: Number,
  199. default: 0,
  200. },
  201. tabParams: {
  202. type: Object,
  203. },
  204. navShow: Boolean,
  205. });
  206. const useSystem = useSystemStore();
  207. const useShop = useShopStore();
  208. const searchValue = ref("");
  209. const tabActive = ref(0);
  210. const footerHeight = ref(0);
  211. const listRef = ref(null);
  212. const tabList = ref([]);
  213. watchEffect(() => {
  214. tabList.value = [
  215. { text: t("全部"), status: 0 },
  216. { text: t("待付款"), status: 100 },
  217. { text: t("运输中"), status: 200 },
  218. { text: t("待入库"), status: 500 },
  219. { text: t("待质检"), status: 520 },
  220. { text: t("退款和售后"), status: 40 },
  221. ];
  222. });
  223. const params = ref({
  224. status: 0,
  225. });
  226. const symbol = computed(() => useSystem.getSymbol);
  227. const selectAllChecked = ref(false);
  228. const allId = ref([]);
  229. const ids = ref([]);
  230. watch(
  231. () => props.tabParams,
  232. (newVal) => {
  233. if (newVal && newVal.tab == 0) {
  234. tabActive.value = newVal.type;
  235. params.value.status = newVal.status;
  236. useShop.setTabParams(null);
  237. nextTick(() => {
  238. listRef.value?.handleRefresh();
  239. getHeight();
  240. });
  241. }
  242. },
  243. { immediate: true }
  244. );
  245. const searchConfirm = () => {
  246. nextTick(() => {
  247. listRef.value && listRef.value.handleRefresh();
  248. });
  249. };
  250. const getAllData = (list) => {
  251. if (tabActive.value == 0) return;
  252. if (!list.length) return (selectAllChecked.value = false);
  253. allId.value = list.reduce((acc, item) => {
  254. acc.push(item.id);
  255. return acc;
  256. }, []);
  257. };
  258. const checkedChanges = (id) => {
  259. let arr = JSON.parse(JSON.stringify(ids.value));
  260. let findIndex = ids.value.findIndex((item) => item == id);
  261. if (findIndex != -1) {
  262. arr = arr.filter((item) => item != id);
  263. } else {
  264. arr.push(id);
  265. }
  266. ids.value = arr;
  267. let flag = allId.value.every((value) => arr.includes(value));
  268. selectAllChecked.value = flag;
  269. };
  270. const selectAllChange = (e) => {
  271. selectAllChecked.value = e;
  272. ids.value = e ? allId.value : [];
  273. };
  274. const paySubmit = (item) => {
  275. ids.value = [item.id];
  276. nextTick(() => {
  277. shopConfirm();
  278. });
  279. };
  280. const cancelModelRef = ref(null);
  281. const orderCancel = (item) => {
  282. cancelModelRef.value && cancelModelRef.value.open(item.id);
  283. };
  284. const listClick = (item) => {
  285. uni.navigateTo({ url: `/pages/order/details?oid=${item.id}` });
  286. // uni.navigateTo({ url: `/pages/dashboard/order_detail?orderid=${item.id}` })
  287. };
  288. const submit = () => {
  289. if (!ids.value.length) return;
  290. shopConfirm();
  291. };
  292. const tabConfirm = (item, index) => {
  293. if (!item) return;
  294. tabActive.value = index;
  295. params.value.status = item.status;
  296. nextTick(() => {
  297. listRef.value && listRef.value.handleRefresh();
  298. });
  299. };
  300. const filterSubmit = (obj) => {
  301. params.value = obj;
  302. nextTick(() => {
  303. listRef.value && listRef.value.handleRefresh();
  304. });
  305. };
  306. const shopConfirm = async () => {
  307. try {
  308. const res = await SHOP_ORDER_GETPAY(ids.value.join(","));
  309. uni.navigateTo({
  310. url: `/pages/shop/payment?oid=${res.data.oid}&type=order`,
  311. });
  312. ids.value = [];
  313. selectAllChecked.value = false;
  314. } catch (error) {
  315. Toast(error.msg);
  316. }
  317. };
  318. const getHeight = async () => {
  319. try {
  320. const res = await query("#footer");
  321. nextTick(() => {
  322. footerHeight.value = res.height;
  323. });
  324. } catch (error) {}
  325. };
  326. onMounted(() => {
  327. // listRef.value && listRef.value.getData();
  328. });
  329. onShow(() => {
  330. nextTick(() => {
  331. listRef.value && listRef.value.getData();
  332. });
  333. });
  334. onReachBottom(() => {
  335. nextTick(() => {
  336. listRef.value && listRef.value.scrolltolower();
  337. });
  338. });
  339. </script>
  340. <style lang="less" scoped>
  341. @import url("@/style.less");
  342. .wrap {
  343. max-height: calc(100vh - 44rpx);
  344. background-color: var(--bg);
  345. .flex();
  346. flex-direction: column;
  347. /deep/ .u-navbar__content {
  348. justify-content: unset;
  349. .u-navbar__content__left {
  350. position: unset;
  351. }
  352. }
  353. .nav_search {
  354. .icon-search {
  355. color: #a8abb2;
  356. .size(28px);
  357. }
  358. }
  359. .content1 {
  360. flex-grow: 1;
  361. flex-direction: column;
  362. .flex();
  363. // height: calc(100vh - 44px - var(--height));
  364. .cont_tab {
  365. background-color: var(--light);
  366. padding: 0 48rpx;
  367. :deep(.tab) {
  368. .active {
  369. color: var(--text) !important;
  370. &::before {
  371. background-color: var(--text) !important;
  372. }
  373. }
  374. }
  375. }
  376. .cont {
  377. flex-grow: 1;
  378. overflow: hidden scroll;
  379. padding: 0 24rpx var(--height);
  380. .order_list {
  381. margin-top: 24rpx;
  382. padding: 16rpx 24rpx;
  383. background-color: var(--light);
  384. border-radius: 16rpx;
  385. .order_header {
  386. .ver();
  387. margin-bottom: 16rpx;
  388. .header_img {
  389. width: 48rpx;
  390. height: 48rpx;
  391. .img {
  392. width: inherit;
  393. height: inherit;
  394. border-radius: 8rpx;
  395. }
  396. }
  397. .create_time {
  398. margin-left: 16rpx;
  399. .size(24rpx);
  400. color: var(--text);
  401. font-weight: 700;
  402. text {
  403. font-weight: 500;
  404. }
  405. }
  406. }
  407. .order_item {
  408. &_wrapper {
  409. margin-top: 16rpx;
  410. ._item_wrapper {
  411. .flex();
  412. .thumb_img {
  413. width: 140rpx;
  414. height: 140rpx;
  415. ._img {
  416. width: inherit;
  417. height: inherit;
  418. border-radius: 16rpx;
  419. }
  420. }
  421. .goods_info {
  422. margin-left: 16rpx;
  423. flex: 1;
  424. .info_name {
  425. color: var(--text);
  426. .size(24rpx);
  427. font-weight: 700;
  428. line-height: 44rpx;
  429. .ver();
  430. ._name {
  431. flex: 1;
  432. .ellipsis();
  433. margin-right: 8rpx;
  434. }
  435. }
  436. .spec_info {
  437. .flex();
  438. flex: 1;
  439. margin-top: 8rpx;
  440. color: var(--text-01);
  441. .size(24rpx);
  442. line-height: 40rpx;
  443. .spec_desc {
  444. flex: 1;
  445. margin-right: 8rpx;
  446. }
  447. }
  448. .no_return {
  449. border: var(--danger-bor);
  450. border-radius: 40rpx;
  451. color: var(--danger);
  452. cursor: pointer;
  453. .size(24rpx);
  454. line-height: 40rpx;
  455. margin-top: 16rpx;
  456. padding: 0 24rpx;
  457. width: max-content;
  458. }
  459. }
  460. }
  461. .order_status {
  462. color: var(--primary);
  463. .size(24rpx);
  464. height: 40rpx;
  465. .flex_position(flex-end);
  466. margin-top: 16rpx;
  467. .icon-question2 {
  468. .size(36rpx);
  469. }
  470. }
  471. .order-cancel {
  472. margin-top: 16rpx;
  473. color: var(--text-01);
  474. .size(24rpx);
  475. line-height: 40rpx;
  476. .time {
  477. color: var(--danger);
  478. font-weight: 700;
  479. }
  480. .content {
  481. margin-top: 8rpx;
  482. color: var(--text);
  483. font-weight: 500;
  484. }
  485. }
  486. }
  487. .order_footer {
  488. margin-top: 16rpx;
  489. border-top: 1px solid #f5f6f7;
  490. .order_price {
  491. padding-top: 16rpx;
  492. .flex_position(flex-end);
  493. color: var(--primary);
  494. color: var(--red);
  495. .size();
  496. font-weight: 700;
  497. height: 48rpx;
  498. line-height: 1;
  499. .price_text {
  500. color: var(--text);
  501. .size(24rpx);
  502. font-weight: 400;
  503. }
  504. .icon-question2 {
  505. font-weight: 400;
  506. color: var(--text-01);
  507. margin-left: 8rpx;
  508. }
  509. }
  510. .end_time {
  511. .flex_position(flex-end);
  512. margin-top: 16rpx;
  513. color: #e62e2e;
  514. font-weight: 700;
  515. .size(24rpx);
  516. text {
  517. font-weight: 400;
  518. }
  519. }
  520. .order_btns {
  521. .flex_position(flex-end);
  522. margin-top: 16rpx;
  523. gap: 16rpx;
  524. .btn {
  525. .flex_center();
  526. border-radius: 16rpx;
  527. padding: 0 30rpx;
  528. .size(24rpx);
  529. height: 48rpx;
  530. border: 1px solid var(--black);
  531. background-color: var(--light);
  532. color: var(--black);
  533. }
  534. .pay_btn {
  535. color: var(--light);
  536. background-color: var(--black);
  537. }
  538. }
  539. }
  540. }
  541. }
  542. }
  543. .cont_footer {
  544. position: fixed;
  545. bottom: var(--tabbarHeight);
  546. left: 0;
  547. right: 0;
  548. line-height: 100rpx;
  549. background-color: var(--light);
  550. box-shadow: 0 -4px 6px #0000000d;
  551. padding: 0 24rpx;
  552. .flex_position(space-between);
  553. .total_btn {
  554. .size(24rpx);
  555. height: 38px;
  556. margin-left: 16rpx;
  557. min-width: 180rpx;
  558. background-color: var(--primary);
  559. background-color: var(--black);
  560. color: var(--light);
  561. border-radius: 16rpx;
  562. padding: 16rpx 30rpx;
  563. text-align: center;
  564. .flex_center();
  565. margin-left: 24rpx;
  566. }
  567. }
  568. }
  569. }
  570. </style>