index.vue 38 KB

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