index.vue 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967
  1. <template>
  2. <!-- 订单中心 -->
  3. <div class="orderPage flex-col">
  4. <s-header :name="$t('orderCenter.orderCenter')" :noback="false"></s-header>
  5. <div class="orderBox">
  6. <van-list v-model:loading="loading" v-model:error="error" :error-text="$t('public.requestFailed')"
  7. :finished="finished" :finished-text="$t('public.noMore')" offset="300" :immediate-check="false" @load="onLoad">
  8. <div class="main3 flex-col justify-center">
  9. <!-- <div class="outer1 flex-col justify-between"> -->
  10. <div class="group4 flex-row justify-between">
  11. <div class="ImageText1 flex-col">
  12. <div class="outer2 flex-row justify-between">
  13. <div class="block1 flex-col"></div>
  14. <div class="TextGroup1 flex-col">
  15. <span class="txt1">{{ $t('orderCenter.dataOverview') }}</span>
  16. </div>
  17. </div>
  18. </div>
  19. <div class="flex-col">
  20. <div class="main5 flex-row justify-between" @click="searchClick()">
  21. <img class="label2" src="@/assets/device/searchIcon.png" />
  22. </div>
  23. </div>
  24. </div>
  25. </div>
  26. <!-- <img class="img1" referrerpolicy="no-referrer" src="@/assets/line.png" /> -->
  27. <dateSelectList @update="update($event)"></dateSelectList>
  28. <typeDownMenu @upselectdata="upselectdata($event)"></typeDownMenu>
  29. <div v-if="!noData(salesVolume, salesNumber, orderNumber)" class="o-plr-8 o-pt-15">
  30. <div class="outer5 flex-col">
  31. <div class="block5 flex-col">
  32. <div class="outerBox flex-row">
  33. <div class="main4 flex-col justify-between">
  34. <div class="main5 flex-row justify-center">
  35. <!-- <span class="word8">&yen;</span> -->
  36. <span class="word8">{{ currencySymbol }}</span>
  37. <span class="word9">{{ salesVolume.toFixed(2) }}</span>
  38. </div>
  39. <span class="info5">{{ $t("home.totalIncome") }}</span>
  40. </div>
  41. <div class="TextGroup7 flex-col">
  42. <div class="mod3 flex-col justify-between">
  43. <span class="txt8">{{ salesNumber }}</span>
  44. <span class="info6">{{ $t("home.productNum") }}</span>
  45. </div>
  46. </div>
  47. <div class="TextGroup8 flex-col">
  48. <div class="outer6 flex-col justify-between">
  49. <span class="txt9">{{ orderNumber }}</span>
  50. <span class="word10">{{ $t("home.numberOfOrders") }}</span>
  51. </div>
  52. </div>
  53. </div>
  54. </div>
  55. </div>
  56. </div>
  57. <kNoData v-else></kNoData>
  58. <!-- 时间 -->
  59. <div class="c-text-c" style="font-size: 18px; margin-top: 5px;">
  60. {{ Format_time(searchParams.startDate, 'YYYY/MM/DD') }}-{{ Format_time(searchParams.endDate, 'YYYY/MM/DD')
  61. }}
  62. </div>
  63. <div class="group7 flex-col justify-center">
  64. <div class="main9 flex-col justify-between">
  65. <div class="wrap1 flex-row justify-between">
  66. <div class="ImageText7 flex-col">
  67. <div class="mod5 flex-row justify-between">
  68. <div class="block3 flex-col"></div>
  69. <div class="TextGroup7 flex-col">
  70. <span class="info3">
  71. {{ $t('orderCenter.total') }}
  72. <span style="color: #df5e4c; font-size: 18px;">{{ total }}</span>
  73. {{ $t('orderCenter.records') }}
  74. </span>
  75. </div>
  76. </div>
  77. </div>
  78. <div class="ImageText8 flex-col" @click="gotoOrderExcel()">
  79. <div class="bd3 flex-row justify-between">
  80. <span class="info4 flex-col">{{ $t('orderCenter.exportToExcel') }}</span>
  81. <div class="outer3 flex-col"></div>
  82. </div>
  83. </div>
  84. </div>
  85. </div>
  86. </div>
  87. <div class="section1 flex-col">
  88. <div class="group8 flex-col">
  89. <div class="section4 flex-col">
  90. <div v-for="(item, index) in orderList" :key="index">
  91. <div class="section5 flex-col" @click="orderClick(item)">
  92. <van-card :thumb="showSugerPhoto(item)">
  93. <template #title>
  94. <span class="word13">{{ $t('orderCenter.tradeName') }}:{{ item.productName }}</span>
  95. </template>
  96. <template #desc>
  97. <span class="word11">{{ $t('orderCenter.equipmentName') }}:{{ item.es }}</span>
  98. </template>
  99. <template #price>
  100. <div class="pricBox flex-row align-end" :class="{ orderError: item.status === 0 }">
  101. <span class="txt9">{{ item.statusText }}:
  102. <span v-if="user.ifForeign === '0'" class="word14 o-ptb-8">
  103. {{ $t('orderCenter.dividingDomesticService') }} :{{ currencySymbol }}{{ showSubcom(item) }}
  104. </span>
  105. </span>
  106. <!-- 订单明细 - 线下支付 ¥ -->
  107. <span class="info5">{{ currencySymbol }}</span>
  108. <span class="word12" v-if="item.status === 3">{{ item.price.toFixed(2) }}</span>
  109. <span class="word12" v-else>{{ item.refundAmount == null ? item.price.toFixed(2) : (item.price -
  110. item.refundAmount).toFixed(2) }}</span>
  111. </div>
  112. <!-- <span v-if="user.ifForeign === '0' && user.isDistribution === '1'" class="giveAway">
  113. {{ $t('orderCenter.dividingDomesticService') }} :{{ currencySymbol }}{{ showSubcom(item) }}
  114. </span> -->
  115. </template>
  116. <template #price-top>
  117. <span class="time_01"
  118. :style="user.ifForeign == '0' ? 'margin-top: 20px;' : 'margin-top: 40px;'">{{
  119. $t('orderCenter.paymentTime') }}:{{ showOrderTime(item, 1) }}</span>
  120. </template>
  121. <template #footer>
  122. <span v-if="item.status === 3">x{{ item.refundQuantity }}</span>
  123. <span v-else>x{{ item.refundQuantity == null ? item.productNumber : (item.productNumber -
  124. item.refundQuantity) }}</span>
  125. </template>
  126. </van-card>
  127. <div v-if="typeof item.status === 'undefined'" class="main11 flex-col orderSuccess"></div>
  128. <div v-else class="main11 flex-col" :class="{
  129. orderSuccess: item.status === 1 && (user.ifForeign == '0' || user.ifForeign == null),
  130. coinOrderSuccess: item.status === 1 && user.ifForeign == '1',
  131. orderError: item.status === 0,
  132. refunding: item.status === 2,
  133. refunded: item.status === 3,
  134. }"></div>
  135. </div>
  136. <!-- <div class="section6 flex-col"></div> -->
  137. </div>
  138. <van-back-top style="background-color: #2d87c8;" />
  139. </div>
  140. </div>
  141. </div>
  142. </van-list>
  143. </div>
  144. <!-- 搜索弹出框 -->
  145. <orderSearch ref="searchRef" @search="search($event)"></orderSearch>
  146. <!-- 退款弹窗 -->
  147. <van-popup v-model:show="refundType" position="bottom" round closeable>
  148. <div class="orderPopBox flex-col">
  149. <!-- <div class="section1 flex-col"> -->
  150. <!-- <div class="group3 flex-col"> -->
  151. <div class="popTopBox l-flex-center">
  152. <div class="popTopTxtBox flex-col">
  153. <!-- <span class="txt4">这里是设备名称</span> -->
  154. <span class="business">{{ $t('orderCenter.business') }}</span>
  155. <span class="incomePrice">+ {{ refundObject.refundAmount == null ? refundObject.price.toFixed(2) :
  156. (refundObject.price - refundObject.refundAmount).toFixed(2) }}</span>
  157. </div>
  158. </div>
  159. <div class="line flex-col"></div>
  160. <!-- <div class="layer2 flex-row justify-between">
  161. <span class="info2">{{ $t('orderCenter.accountBalance') }}</span>
  162. <span class="txt6">{{ accountDetail.altAvilBalance }}</span>
  163. </div> -->
  164. <div class="orderDetailBox flex-row justify-between">
  165. <span class="title">{{ $t('orderCenter.orderNo') }}</span>
  166. <!-- <span class="content">{{ refundObject.sn }}</span> -->
  167. <van-text-ellipsis class="content" :content="refundObject.sn" :expand-text="$t('orderCenter.seeMore')" :collapse-text="$t('orderCenter.stow')" />
  168. </div>
  169. <div v-if="refundObject.status != 0 && user.ifForeign === '0'" class="orderDetailBox flex-row justify-between">
  170. <span class="title">{{ $t('orderCenter.orderSerialNumberLabel') }}</span>
  171. <!-- <span class="content">{{ refundObject.trxNo }}</span> -->
  172. <van-text-ellipsis class="content" :content="refundObject.trxNo" :expand-text="$t('orderCenter.seeMore')" :collapse-text="$t('orderCenter.stow')" />
  173. </div>
  174. <div class="orderDetailBox flex-row justify-between">
  175. <span class="title">{{ $t('orderCenter.commodity') }}</span>
  176. <!-- <span class="content">{{ refundObject.productName }}</span> -->
  177. <van-text-ellipsis class="content" :content="refundObject.productName" :expand-text="$t('orderCenter.seeMore')" :collapse-text="$t('orderCenter.stow')" />
  178. </div>
  179. <div v-if="user.ifForeign === '0' && user.isDistribution === '1'" class="orderDetailBox flex-row justify-between">
  180. <span class="title">{{ $t('orderCenter.distribution') }}</span>
  181. <span class="content">{{ showSubcom(refundObject) }}</span>
  182. </div>
  183. <div class="orderDetailBox flex-row justify-between">
  184. <span class="title">{{ $t('orderCenter.equipmentNo') }}</span>
  185. <!-- <span class="content">{{ refundObject.clientId }}</span> -->
  186. <van-text-ellipsis class="content" :content="refundObject.clientId" :expand-text="$t('orderCenter.seeMore')" :collapse-text="$t('orderCenter.stow')" />
  187. </div>
  188. <div class="orderDetailBox flex-row justify-between">
  189. <span class="title">{{ $t('orderCenter.state') }}</span>
  190. <span class="content">{{ showStatus(refundObject) }}</span>
  191. </div>
  192. <div class="orderDetailBox flex-row justify-between">
  193. <span class="title">{{ $t('orderCenter.paymentMethod') }}</span>
  194. <!-- <span class="content">{{ showPayType(refundObject) }}</span> -->
  195. <van-text-ellipsis class="content" :content="showPayType(refundObject)" :expand-text="$t('orderCenter.seeMore')" :collapse-text="$t('orderCenter.stow')" />
  196. </div>
  197. <div class="orderDetailBox flex-row justify-between">
  198. <span class="title">
  199. {{ refundObject.status === 1 ? $t('orderCenter.paymentTime') : refundObject.status === 3 ?
  200. $t('orderCenter.refundTime') : $t('orderCenter.creationTime') }}
  201. </span>
  202. <!-- <span class="content">{{ showOrderTime(refundObject, 1) }}</span> -->
  203. <van-text-ellipsis class="content" :content="showOrderTime(refundObject, 1)" :expand-text="$t('orderCenter.seeMore')" :collapse-text="$t('orderCenter.stow')" />
  204. </div>
  205. <div v-if="refundObject.status === 3" class="orderDetailBox flex-row justify-between">
  206. <span class="title">{{ $t('orderCenter.refunded') }}</span>
  207. <span class="content">{{ refundObject.refundAmount }}</span>
  208. </div>
  209. <div v-if="refundObject.status === 3 && orderType == '3'" class="orderDetailBox flex-row justify-between">
  210. <span class="title">退款原因</span>
  211. <span class="content">{{ refundObject.refundReason }}</span>
  212. </div>
  213. <div class="orderDetailBox flex-row justify-between l-flex-center"
  214. v-if="(refundObject.status != 0 && refundObject.status != 2) && orderType == '3'">
  215. <span class="title">是否开发票</span>
  216. <van-radio-group v-model="isInvoice" direction="horizontal">
  217. <van-radio :name="1">是</van-radio>
  218. <van-radio :name="0">否</van-radio>
  219. </van-radio-group>
  220. <van-button color="#2c87c8" type="primary" size="small" class="o-p-20" @click="updateInvoice(refundObject.id)"
  221. style="padding: 10px; margin-left: 20px;">更新</van-button>
  222. </div>
  223. <van-field v-if="refundObject.status === 1 && user.ifForeign === '0' && user.type < 2 && orderType != '3'"
  224. v-model="customerPhone" center label="联系方式" placeholder="消费者联系方式,没有则不填">
  225. </van-field>
  226. <!-- 发起退款 -->
  227. <!-- 非已付款订单,线下订单要隐藏按钮 -->
  228. <div style="display: flex; justify-content: center; padding-bottom: 20px;">
  229. <van-button size="small"
  230. v-if="refundObject.status === 1 && user.ifForeign === '0' && user.type < 2 && orderType != '3'"
  231. @click="sentRefundMessage(refundObject)" round type="primary" style="padding: 15px 15px; margin-top: 20px;"
  232. color="#4dc193">
  233. 退款提醒
  234. </van-button>
  235. <div v-if="refundObject.status === 1 && user.ifForeign === '0' && user.type < 2" style="width: 20px;">
  236. </div>
  237. <van-button size="small"
  238. v-if="refundObject.status === 1 && user.ifForeign === '0' && isRefund"
  239. @click="noticeClk(refundObject)" round type="primary" style="padding: 15px 15px; margin-top: 20px;">
  240. {{ $t('orderCenter.initiateRefund') }}
  241. </van-button>
  242. </div>
  243. </div>
  244. </van-popup>
  245. <!-- 退款弹窗 -->
  246. <kDialog :isCloseForConfirm="false" :dialogTitle="$t('orderCenter.refundTip')"
  247. :confirmBtnTxt="$t('orderCenter.refundSubmit')" ref="kDialogRef" @confirmclk="confirmClk">
  248. <template #content>
  249. <div class="refundBox l-flex-RC" style="overflow-y: auto; overflow-x: hidden; max-height: 40vh;">
  250. <div v-for="(item, index) in orderDetails" :key="index" class="card01">
  251. <van-checkbox :disabled="item.price.toFixed(2) <= 0" checked-color="#2c87c8" v-model="isChecked[index]" @change="checkGood(index)"
  252. icon-size="0.5rem"></van-checkbox>
  253. <van-card :price="item.price.toFixed(2)" :title="item.productName" :thumb="showSugarPic(item.productNo)">
  254. <template #footer>
  255. <van-stepper v-if="item.price.toFixed(2) > 0" v-model="refundNum[index]" @plus="plusRefundGood(index)"
  256. @minus="minusRefundGood(index)" theme="round" button-size="22" disable-input
  257. :max="item.refundQuantity == null ? item.productNumber : (item.productNumber - item.refundQuantity)" />
  258. <span v-else>
  259. 已优惠减免
  260. </span>
  261. </template>
  262. </van-card>
  263. </div>
  264. </div>
  265. <div class="o-mt-5" style="height: 1px; background: #d7d7e2"></div>
  266. <van-field v-if="orderType === '3'" v-model="cofficentForm.refundReason" rows="2" autosize label="退款原因"
  267. type="textarea" maxlength="30" :clearable="true" placeholder="请输入退款原因" show-word-limit />
  268. <div class="btnFooter">
  269. <!-- <van-checkbox class="checkAllBtn o-mt-5" v-model="checkedAll" @click="checkAll">全选</van-checkbox> -->
  270. <span></span>
  271. <div class="o-mt-5">
  272. <span class="">{{ $t('orderCenter.totalRefund') }}:</span>
  273. <span class="totalRefund o-pr-15">{{ currencySymbol }} {{ totalRefund.toFixed(2) }}</span>
  274. </div>
  275. </div>
  276. </template>
  277. </kDialog>
  278. </div>
  279. </template>
  280. <script>
  281. // import { Api_getOnlineExport } from "../../service/order";
  282. // 导入接口
  283. import { getAdminMch } from "../../service/merchantManage";
  284. // 导入弹窗
  285. import kDialog from "../../components/commom/kDialog/index.vue";
  286. // 导入无数据组件
  287. import { showDialog, showConfirmDialog, showSuccessToast } from 'vant';
  288. import kNoData from "../../components/commom/kNoData/index.vue";
  289. import { onMounted, reactive, ref } from "vue";
  290. import sHeader from "../../components/SimpleHeader";
  291. import orderSearch from "./orderSearch.vue";
  292. import { getOrderList, refundOrder, refundWechatOrder, updateIsInvoice, sentMessage, exportOrder, refundSqbOrder } from "../../service/order/index";
  293. import { showFailToast, showToast, showLoadingToast } from "vant";
  294. import { getLoginUser, $M_IsDate, Format_time, $M_ExportFile, styleUrl } from "../../common/js/utils";
  295. import { getHuifuId } from "../../service/huifuMch/index";
  296. import dateUtil from "../../utils/dateUtil";
  297. import dateSelectList from "../../components/dateSelectList";
  298. import typeDownMenu from "../../components/typeDownMenu";
  299. import { getStatistics } from "../../service/home";
  300. import { useI18n } from "vue-i18n";
  301. export default {
  302. name: "order",
  303. components: { sHeader, orderSearch, dateSelectList, typeDownMenu, kNoData, kDialog },
  304. setup() {
  305. // 批量修改弹窗
  306. const kDialogRef = ref(null);
  307. // 订单明细
  308. const orderDetails = ref([]);
  309. // 订单总数
  310. const total = ref(0);
  311. // 退款商品选择状态
  312. const isChecked = ref([]);
  313. // 全选状态
  314. const checkedAll = ref(false);
  315. // 退款总额
  316. const totalRefund = ref(0);
  317. // 退款商户数量
  318. const refundNum = ref([]);
  319. // 订单类型
  320. const orderType = ref('');
  321. // 是否开发票
  322. const isInvoice = ref(0);
  323. // 更新是否开发票
  324. const updateInvoice = (id) => {
  325. const params = {
  326. id,
  327. isInvoice: isInvoice.value,
  328. }
  329. showConfirmDialog({
  330. message: '是否确认更新',
  331. }).then(() => {
  332. const { data } = updateIsInvoice(params);
  333. console.log(data);
  334. }).catch(() => {
  335. return;
  336. });
  337. }
  338. // 加载状态
  339. // const isLoading = ref(false);
  340. // 监控退款选择框状态
  341. const checkGood = (index) => {
  342. if (isChecked.value[index]) {
  343. totalRefund.value = parseFloat((totalRefund.value + (refundNum.value[index] * orderDetails.value[index].price)).toFixed(2));
  344. } else {
  345. if (totalRefund.value > 0) {
  346. totalRefund.value = parseFloat((totalRefund.value - (refundNum.value[index] * orderDetails.value[index].price)).toFixed(2));
  347. }
  348. }
  349. // 如果都为true,都为全选
  350. if (isChecked.value.every((value) => value === true)) {
  351. checkedAll.value = true;
  352. } else {
  353. checkedAll.value = false;
  354. }
  355. }
  356. // 点击增加按钮
  357. const plusRefundGood = (index) => {
  358. if (isChecked.value[index]) {
  359. totalRefund.value = parseFloat((totalRefund.value + orderDetails.value[index].price).toFixed(2));
  360. }
  361. }
  362. // 点击减少按钮
  363. const minusRefundGood = (index) => {
  364. if (isChecked.value[index]) {
  365. totalRefund.value = parseFloat((totalRefund.value - orderDetails.value[index].price).toFixed(2));
  366. }
  367. }
  368. // 点击弹出退款弹窗
  369. const noticeClk = (row) => {
  370. if (row.orderDetails.length > 0) {
  371. isChecked.value = [];
  372. orderDetails.value = [];
  373. refundNum.value = [];
  374. checkedAll.value = false;
  375. totalRefund.value = 0;
  376. // cofficentForm.price = row.price;
  377. // cofficentForm.maxPrice = row.price;
  378. cofficentForm.id = row.id;
  379. // cofficentForm.maxNumber = row.productNumber;
  380. // cofficentForm.productNumber = row.productNumber;
  381. row.orderDetails.forEach(item => {
  382. if (item.refundStatus == '1' || item.refundStatus == '2') {
  383. orderDetails.value.push(item);
  384. if (item.refundQuantity != null) {
  385. refundNum.value.push(item.productNumber - item.refundQuantity);
  386. } else {
  387. refundNum.value.push(item.productNumber);
  388. }
  389. }
  390. });
  391. // 根据orderDetails的长度,向isChecked添加相应数量的false
  392. isChecked.value = Array.from({ length: orderDetails.value.length }, () => false);
  393. kDialogRef.value.openDialog();
  394. } else {
  395. showToast("请联系管理员");
  396. return;
  397. }
  398. };
  399. // 点击全选按钮
  400. const checkAll = () => {
  401. isChecked.value.forEach((item, index) => {
  402. if (checkedAll.value) {
  403. isChecked.value[index] = true;
  404. } else {
  405. isChecked.value[index] = false;
  406. }
  407. })
  408. }
  409. // 点击确定按钮
  410. const confirmClk = () => {
  411. cofficentForm.note = "";
  412. cofficentForm.productNumber = 0;
  413. cofficentForm.price = 0;
  414. isChecked.value.forEach((isCheckedValue, index) => {
  415. if (isCheckedValue) {
  416. cofficentForm.note = cofficentForm.note + orderDetails.value[index].id + "-" + refundNum.value[index] + ","
  417. cofficentForm.productNumber = cofficentForm.productNumber + refundNum.value[index];
  418. }
  419. })
  420. cofficentForm.price = totalRefund.value;
  421. if (cofficentForm.note === "" || cofficentForm.price === 0 || cofficentForm.price === "") {
  422. showToast(t('orderCenter.refundPlace'));
  423. return;
  424. }
  425. if (orderType.value === '3' && (cofficentForm.refundReason === "" || cofficentForm.refundReason === null)) {
  426. showToast('请填写退款原因');
  427. return;
  428. }
  429. showConfirmDialog({
  430. // title: "提示",
  431. message: t('orderCenter.refundCheck'),
  432. }).then(() => {
  433. // isLoading.value = true; // 开始加载
  434. refundAjax();
  435. // isLoading.value = false; // 加载完成
  436. kDialogRef.value.closeDialog();
  437. }).catch(() => {
  438. return;
  439. });
  440. }
  441. const customerPhone = ref(''); // 消费者号码
  442. // 发送退款提醒短信
  443. const sentRefundMessage = async (row) => {
  444. const params = {
  445. id: row.id,
  446. customerPhone: customerPhone.value,
  447. }
  448. showConfirmDialog({
  449. message: '是否确认发送短信?',
  450. }).then(async () => {
  451. const { data } = await sentMessage(params);
  452. if (data.code) {
  453. showSuccessToast(data.data);
  454. } else {
  455. showFailToast(data.data);
  456. }
  457. }).catch(() => {
  458. return;
  459. });
  460. }
  461. // 退款操作
  462. const refundAjax = async () => {
  463. try {
  464. // 如果为微信退款
  465. let data = null;
  466. if (orderType.value === '3') {
  467. data = await refundWechatOrder(cofficentForm);
  468. } else if (orderType.value === '4') {
  469. data = await refundSqbOrder(cofficentForm);
  470. } else {
  471. data = await refundOrder(cofficentForm);
  472. }
  473. console.log(data);
  474. if (data.data.code && data.data.code !== 'B0001') {
  475. showDialog({
  476. message: t('orderCenter.refundSucceeded'),
  477. }).then(() => {
  478. refundType.value = false;
  479. // on close
  480. orderList.value = [];
  481. search({});
  482. });
  483. } else {
  484. showFailToast(data.data.message);
  485. }
  486. } catch (error) {
  487. showFailToast(t('orderCenter.requestFailed'));
  488. }
  489. };
  490. // 修改的价格
  491. const cofficentForm = reactive({
  492. price: 0,
  493. id: "",
  494. productNumber: 0,
  495. note: 0,
  496. refundReason: "",
  497. });
  498. // 引入语言
  499. const { t } = useI18n();
  500. // 订单商品图片路径处理
  501. const showSugerPhoto = (row) => {
  502. if (row.orderDetails != null) {
  503. if (row.orderDetails.length > 0) {
  504. return require(`../../assets/order/spunSugar/goods/${row.orderDetails[0].productNo}.png`);
  505. } else {
  506. if (row.productNo != null) {
  507. return require(`../../assets/order/spunSugar/goods/${row.productNo}.png`);
  508. }
  509. if (row.machineType == null || row.machineType == '0') {
  510. return require(`../../assets/order/spunSugar/goods/A01.png`);
  511. } else {
  512. return require(`../../assets/order/spunSugar/goods/B01.png`);
  513. }
  514. }
  515. } else {
  516. if (row.machineType == null || row.machineType == '0') {
  517. return require(`../../assets/order/spunSugar/goods/A01.png`);
  518. } else {
  519. return require(`../../assets/order/spunSugar/goods/B01.png`);
  520. }
  521. }
  522. };
  523. // 订单明细商品图片路径处理
  524. const showSugarPic = (row) => {
  525. return require(`../../assets/order/spunSugar/goods/${row}.png`);
  526. };
  527. // 如果是空数据
  528. const noData = (volumes, nums) => {
  529. if (!volumes && !nums) {
  530. return true;
  531. }
  532. return false;
  533. };
  534. const user = getLoginUser();
  535. const searchRef = ref(null);
  536. const huifuId = ref(null);
  537. const orderList = ref([]);
  538. const orderTotal = ref(0);
  539. const loading = ref(true);
  540. const error = ref(false);
  541. const finished = ref(false);
  542. // 滚动加载
  543. const onLoad = () => {
  544. if (!finished.value) {
  545. loading.value = true;
  546. searchParams.current = searchParams.current + 1;
  547. getList();
  548. }
  549. };
  550. // 自定义货币符号
  551. const currencySymbol = ref("¥");
  552. if (user.currencySymbol) {
  553. currencySymbol.value = user.currencySymbol;
  554. } else {
  555. currencySymbol.value = "¥";
  556. }
  557. // 页面列表查询参数
  558. let searchParams = reactive({
  559. adminId: "", // 用户账户id
  560. userName: "", // 用户名 String 没有值时传null
  561. adminType: "", // 判断是否查全部商户 当用户为商家时,“本商户”这个选项为“所有下级用户”传入一个“all”的值,其他情况传null
  562. type: user.ifForeign, // 订单类型 用来区分是国内、海外订单,0:国内,1:海外。默认值一般要根据当前登录用户的类型去选择。区分的参数是admin里ifForeign的值。ifForeign=0则type=0.
  563. // ifForeign现在用于区分国内0,海外1
  564. // isAir海外又分为两种情况,0/null为线下,1是线上
  565. payType: "", // 支付方式 全部时传null 0:无需支付 1:硬币 2:纸币 3:硬币+纸币 4:信用卡 5:电子支付 ALIPAY_NATIVE:支付宝主扫 WEIXIN_NATIVE:微信主扫 ALIPAY_CARD:支付宝反扫 WEIXIN_CARD:微信反扫
  566. productNo: "", // 商品的标识 全部时传null。 Tproductd对象的属性no的值。
  567. clientId: "", // 设备编号 String
  568. dateType: "0", // 所选时间类型 String 0:创建时间 1:退款时间
  569. startDate: "", // 开始时间 Date
  570. endDate: "", // 结束时间 Date
  571. current: 0, // 页数
  572. size: 15, // 页大小
  573. status: 1,//支付状态
  574. companyType: "", // 公司平台
  575. machineType: "", // 设备类型
  576. ifForeign: "",
  577. username: "",
  578. });
  579. let chartType = "day";
  580. // 获取订单列表数据
  581. const getList = async () => {
  582. finished.value = false;
  583. getStatisticsFun();
  584. // 因为订单的时间格式不一样
  585. const params = Object.assign({}, searchParams);
  586. if ($M_IsDate(params.startDate)) {
  587. params.startDate = dateUtil.formateDate(
  588. new Date(params.startDate),
  589. "yyyy-MM-dd hh:mm:ss"
  590. );
  591. } else {
  592. params.startDate = "";
  593. }
  594. if ($M_IsDate(params.endDate)) {
  595. params.endDate = dateUtil.formateDate(
  596. new Date(params.endDate),
  597. "yyyy-MM-dd hh:mm:ss"
  598. );
  599. } else {
  600. params.endDate = "";
  601. }
  602. // 获取订单列表
  603. const { data } = await getOrderList(Object.assign({}, params));
  604. total.value = 0;
  605. if (data.code === "00000") {
  606. if (data.data.total === 0) {
  607. finished.value = true;
  608. } else {
  609. // orderTotal.value = data.data.total;
  610. total.value = data.data.total;
  611. if (params.current === 1) {
  612. orderList.value = [];
  613. orderTotal.value = 0;
  614. }
  615. // 列表值叠加
  616. if (data.data.records.length > 0) {
  617. orderList.value = orderList.value.concat(
  618. data.data.records.map((item) => {
  619. return {
  620. ...item,
  621. statusText:
  622. item.altInfo != null
  623. ? t('orderCenter.onlinePayment')
  624. : t('orderCenter.offlinePayment'),
  625. };
  626. })
  627. );
  628. orderTotal.value = data.data.records.length + orderTotal.value;
  629. if (orderTotal.value === data.data.total) {
  630. finished.value = true;
  631. }
  632. } else {
  633. finished.value = true;
  634. }
  635. }
  636. loading.value = false;
  637. } else {
  638. // error.value = true;
  639. showToast(t('orderCenter.noOrderData'));
  640. finished.value = true;
  641. loading.value = false;
  642. }
  643. };
  644. // 搜索表单点击
  645. const searchClick = () => {
  646. searchRef.value.showSearch();
  647. };
  648. // 搜索表单初始化页面及状态查询列表
  649. const search = (data) => {
  650. searchParams = Object.assign(searchParams, data);
  651. // 这个会导致请求两次接口
  652. // finished.value = false;
  653. orderList.value = [];
  654. loading.value = true;
  655. searchParams.current = 1;
  656. getList();
  657. };
  658. // 今日、明日、本周、本月、其他时间选择回调
  659. const update = (uDate) => {
  660. chartType = uDate.chartType;
  661. searchParams = Object.assign(searchParams, uDate);
  662. searchParams.type = searchParams.ifForeign;
  663. search();
  664. };
  665. // 商户、支付方式、设备、商品选择回调
  666. const upselectdata = (uSData) => {
  667. // console.log('uSData', uSData)
  668. searchParams = Object.assign(searchParams, uSData);
  669. // console.log('searchParams', searchParams)
  670. searchParams.type = searchParams.ifForeign;
  671. search();
  672. };
  673. // 初始化页面获取列表
  674. onMounted(async () => {
  675. // 加载样式
  676. styleUrl('orderCenter');
  677. // orderList.value = [];
  678. // searchParams.current = 1;
  679. if (user) {
  680. searchParams.adminId = user.id;
  681. searchParams.userName = user.username;
  682. const { data } = await getHuifuId({
  683. adminId: user.id,
  684. });
  685. if (data.code === '00000') {
  686. if (data.data != null) {
  687. huifuId.value = data.data.huifuId;
  688. }
  689. }
  690. // 获取当天
  691. let now = new Date();
  692. let startDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0);
  693. searchParams.startDate = dateUtil.formateDate(startDate, "yyyy-MM-dd hh:mm:ss");
  694. let endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59);
  695. searchParams.endDate = dateUtil.formateDate(endDate, "yyyy-MM-dd hh:mm:ss");
  696. // finished.value = false;
  697. // loading.value = true;
  698. // getList();
  699. onLoad();
  700. addEventListener('load', onLoad);
  701. // 获取账户详情
  702. if (user.ifForeign === '0') {
  703. getAccountDetail(user.id);
  704. }
  705. }
  706. });
  707. // 查询是否有退款权限
  708. const isRefund = user.menuCodeList.some((item) => {
  709. return item === "M16";
  710. });
  711. // 跳转订单导出
  712. const gotoOrderExcel = async () => {
  713. if (total.value > 30000) {
  714. showToast(t('orderCenter.exportTips'));
  715. return;
  716. }
  717. if (searchParams.type == null || searchParams.type == '') {
  718. searchParams.type = user.ifForeign;
  719. }
  720. // 显示加载框
  721. const downloadOrder = showLoadingToast({
  722. forbidClick: true,
  723. duration: 0,
  724. });
  725. try {
  726. // const { headers, data } = await Api_getOnlineExport(searchParams);
  727. const { headers, data, status } = await exportOrder(searchParams);
  728. // 请求完成后隐藏加载框
  729. // downloadOrder.close();
  730. $M_ExportFile(data, headers);
  731. if (status == 200) {
  732. downloadOrder.close();
  733. showSuccessToast({
  734. message: t('orderCenter.exportSuccess'),
  735. forbidClick: true,
  736. duration: 2000,
  737. });
  738. } else {
  739. downloadOrder.close();
  740. }
  741. // 处理返回的数据
  742. } catch (error) {
  743. // 请求发生错误时隐藏加载框
  744. downloadOrder.close();
  745. // 处理错误情况
  746. console.error(error);
  747. } finally {
  748. downloadOrder.close();
  749. }
  750. };
  751. // 订单详情-退款弹窗
  752. const refundType = ref(false);
  753. const refundObject = ref({});
  754. const orderClick = (item) => {
  755. //查询商户余额,要用admin的type去区分 TODO
  756. refundObject.value = item;
  757. orderType.value = item.payPlatform;
  758. isInvoice.value = item.isInvoice;
  759. refundType.value = true;
  760. };
  761. const accountDetail = ref({});
  762. // 获取账户详情
  763. const getAccountDetail = (id) => {
  764. getAdminMch({ id }).then(res => {
  765. accountDetail.value = res.data.data;
  766. })
  767. };
  768. // 订单时间格式转换
  769. const showOrderTime = (item, idx) => {
  770. if (idx === 1) {
  771. switch (item.status) {
  772. case 1:
  773. return dateUtil.timeZoneDate(new Date(dateUtil.formateDate(new Date(item.payDate), "yyyy/MM/dd hh:mm:ss")));
  774. case 3:
  775. return dateUtil.timeZoneDate(new Date(dateUtil.formateDate(new Date(item.refundDate), "yyyy/MM/dd hh:mm:ss")));
  776. default:
  777. return dateUtil.timeZoneDate(new Date(dateUtil.formateDate(new Date(item.createDate), "yyyy/MM/dd hh:mm:ss")));
  778. }
  779. } else {
  780. return item && item.createDate
  781. ? dateUtil.timeZoneDate(new Date(dateUtil.formateDate(new Date(item.createDate), "yyyy/MM/dd hh:mm:ss")))
  782. : "";
  783. }
  784. };
  785. // 设备编号格式转换
  786. const showClientId = (item) => {
  787. return item && item.clientId
  788. ? item.clientId.substring(item.clientId.length - 6)
  789. : "";
  790. };
  791. // 计算分佣
  792. const showSubcom = (item) => {
  793. let subcom = "0";
  794. if (item.altInfo) {
  795. const altInfo = JSON.parse(item.altInfo);
  796. if (altInfo && altInfo.length > 0) {
  797. // altInfo这个属性里,最后一个实体的altAmount的值就是他的分佣。
  798. subcom = altInfo[altInfo.length - 1]['altAmount'];
  799. }
  800. }
  801. if (item.acctSplitBunch) {
  802. const data = JSON.parse(item.acctSplitBunch);
  803. const targetObj = data.acct_infos.find(obj => obj.huifu_id === huifuId.value);
  804. if (targetObj) {
  805. subcom = targetObj.div_amt;
  806. }
  807. }
  808. return subcom;
  809. };
  810. // 弹窗订单状态
  811. const showStatus = (item) => {
  812. if (typeof item.status === "undefined") {
  813. return t('orderCenter.paymentSucceeded');
  814. } else {
  815. if (item.status === 0) {
  816. return t('orderCenter.unpaid');
  817. }
  818. if (item.status === 1) {
  819. return t('orderCenter.paid');
  820. }
  821. if (item.status === 2) {
  822. return t('orderCenter.refundInProgress');
  823. }
  824. if (item.status === 3) {
  825. return t('orderCenter.refunded');
  826. }
  827. }
  828. return item;
  829. };
  830. const paySouerList = [
  831. { text: t('orderCenter.whole'), values: null },
  832. { text: t('orderCenter.noPaymentRequired'), values: 0 },
  833. { text: t('orderCenter.coin'), values: 1 },
  834. { text: t('orderCenter.notes'), values: 2 },
  835. { text: t('orderCenter.coinsNotes'), values: 3 },
  836. { text: t('orderCenter.creditCard'), values: 4 },
  837. { text: t('orderCenter.electronicPayment'), values: 5 },
  838. { text: t('orderCenter.mainSweepOfAlipay'), values: "ALIPAY_NATIVE" },
  839. { text: t('orderCenter.weChatScanning'), values: "WEIXIN_NATIVE" },
  840. { text: t('orderCenter.antiScanningOfAlipay'), values: "ALIPAY_CARD" },
  841. { text: t('orderCenter.weChatBackScanning'), values: "WEIXIN_CARD" },
  842. { text: t('orderCenter.weChatBackScanning'), values: "WEIXIN_PAYCODE" },
  843. { text: t('orderCenter.eCNYBackeScanning'), values: 'ECNY_CARD' },
  844. ];
  845. // 弹窗支付上述
  846. const showPayType = (item) => {
  847. const payType = user.ifForeign === "0" ? item.frpCode : item.payType;
  848. const paySoure = paySouerList.filter((i) => i.values === payType);
  849. if (paySoure.length > 0) {
  850. return paySoure[0].text;
  851. } else {
  852. return "";
  853. }
  854. };
  855. const salesVolume = ref(0);
  856. const salesNumber = ref(0);
  857. const orderNumber = ref(0);
  858. // 查询图表
  859. const getStatisticsFun = async () => {
  860. // console.log('searchParams', searchParams)
  861. const params = {
  862. adminId: user.id,
  863. chartType: chartType,
  864. endDate: searchParams.endDate,
  865. ifForeign: searchParams.ifForeign == '' ? user.ifForeign : searchParams.ifForeign,
  866. startDate: searchParams.startDate,
  867. userName: searchParams.userName,
  868. username: searchParams.username,
  869. clientId:
  870. searchParams.clientId === "" ? null : searchParams.clientId,
  871. equipmentId:
  872. searchParams.equipmentId === "" ? null : searchParams.equipmentId,
  873. payType:
  874. searchParams.payType === "" ? null : searchParams.payType,
  875. companyType: searchParams.companyType,
  876. machineType: searchParams.machineType,
  877. isAir: searchParams.isAir === "" ? null : searchParams.isAir,
  878. };
  879. const { data } = await getStatistics(params);
  880. if (data.code && data.data) {
  881. salesVolume.value = 0;
  882. salesNumber.value = 0;
  883. orderNumber.value = 0;
  884. data.data.series[0].data.forEach((item) => {
  885. salesNumber.value = parseInt(salesNumber.value + item);
  886. });
  887. data.data.series[1].data.forEach((item) => {
  888. salesVolume.value = parseFloat(salesVolume.value) + parseFloat(item);
  889. });
  890. data.data.series[2].data.forEach((item) => {
  891. orderNumber.value = parseInt(orderNumber.value + item);
  892. });
  893. }
  894. };
  895. return {
  896. user,
  897. loading,
  898. error,
  899. finished,
  900. onLoad,
  901. orderList,
  902. orderTotal,
  903. searchRef,
  904. searchClick,
  905. search,
  906. update,
  907. upselectdata,
  908. gotoOrderExcel,
  909. refundType,
  910. refundObject,
  911. orderClick,
  912. showSugerPhoto,
  913. showOrderTime,
  914. showClientId,
  915. showSubcom,
  916. showStatus,
  917. showPayType,
  918. salesVolume,
  919. salesNumber,
  920. orderNumber,
  921. noData,
  922. kDialogRef,
  923. noticeClk,
  924. confirmClk,
  925. sentRefundMessage,
  926. customerPhone,
  927. cofficentForm,
  928. accountDetail,
  929. Format_time,
  930. searchParams,
  931. orderDetails,
  932. huifuId,
  933. showSugarPic,
  934. isChecked,
  935. refundNum,
  936. checkAll,
  937. checkedAll,
  938. totalRefund,
  939. checkGood,
  940. plusRefundGood,
  941. minusRefundGood,
  942. // isLoading,
  943. isRefund,
  944. currencySymbol,
  945. orderType,
  946. isInvoice,
  947. updateInvoice,
  948. total,
  949. };
  950. },
  951. };
  952. </script>
  953. <style lang="less" scoped>
  954. @import "../../common/style/common.less";
  955. @import "../../styles/orderCenter/index.less";
  956. </style>