afterSalesDetail.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. <template>
  2. <view class="content">
  3. <u-form :model="form" ref="uForm">
  4. <view class="after-sales-goods-detail-view">
  5. <view class="header">
  6. <view>
  7. 本次售后服务将由
  8. <text class="seller-name">{{ sku.storeName }}</text>
  9. 为您提供
  10. </view>
  11. </view>
  12. <view>
  13. <view class="goods-item-view" v-for="(item,index) in sku.orderItems" v-if="item.sn == sn" @click="gotoGoodsDetail(sku.goods_id)">
  14. <view class="goods-img">
  15. <u-image border-radius="6" width="131rpx" height="131rpx" :src="item.image"></u-image>
  16. </view>
  17. <view class="goods-info">
  18. <view class="goods-title u-line-2">{{ item.name }}</view>
  19. <view class="goods-price">
  20. <span>¥{{ applyInfo.applyRefundPrice }}</span>
  21. <span class="num">购买数量:{{ item.num }}</span>
  22. </view>
  23. </view>
  24. </view>
  25. </view>
  26. <view class="after-num">
  27. <view>申请数量</view>
  28. <view>
  29. <u-number-box :value="parseInt(form.num)" disabled-input :min="1" :max="parseInt(sku.num)" bg-color="#fff" @change="valChange"></u-number-box>
  30. </view>
  31. </view>
  32. </view>
  33. <view class="body-view">
  34. <!-- 退款原因 -->
  35. <view class="opt-view">
  36. <u-form-item label="申请原因" :label-width="150">
  37. <u-input v-model="form.reason" type="select" input-align="right" :select-open="reasonSelectShow" @click="reasonSelectShow = true" placeholder="请选择申请原因" />
  38. </u-form-item>
  39. <u-form-item label="申请说明" :label-width="150">
  40. <u-input input-align="right" type="textarea" v-model="form.problemDesc" placeholder="请描述申请售后的说明" />
  41. </u-form-item>
  42. </view>
  43. <!-- 上传凭证 -->
  44. <view class="opt-view">
  45. <view class="img-title">上传凭证(最多5张)</view>
  46. <view class="images-view">
  47. <u-upload :header=" { accessToken: storage.getAccessToken() }" :action="action" width="150" @on-uploaded="onUploaded" :max-count="5" :show-progress="false"></u-upload>
  48. </view>
  49. </view>
  50. <view class="opt-view">
  51. <u-form-item label="退款方式" :label-width="150">
  52. <u-input :value="
  53. applyInfo.refundWay == 'ORIGINAL' ? '原路退回' : '账号退款'
  54. " type="text" input-align="right" :disabled="true" />
  55. </u-form-item>
  56. <view v-if="
  57. applyInfo.accountType === 'BANK_TRANSFER' &&
  58. applyInfo.applyRefundPrice != 0
  59. ">
  60. <u-form-item label="银行开户行" :label-width="150">
  61. <u-input v-model="form.bankDepositName" type="text" input-align="right" placeholder="请输入银行开户行" />
  62. </u-form-item>
  63. <u-form-item label="银行开户名" :label-width="150">
  64. <u-input v-model="form.bankAccountName" type="text" input-align="right" placeholder="请输入银行开户名" />
  65. </u-form-item>
  66. <u-form-item label="银行账号" :label-width="150">
  67. <u-input v-model="form.bankAccountNumber" type="text" input-align="right" placeholder="请输入银行账号" />
  68. </u-form-item>
  69. </view>
  70. <u-form-item label="返回方式" :label-width="150">
  71. <u-input type="text" input-align="right" value="快递至第三方卖家" :disabled="true" />
  72. </u-form-item>
  73. </view>
  74. <view class="opt-tip">提交服务单后,售后专员可能与您电话沟通,请保持手机畅通</view>
  75. </view>
  76. </u-form>
  77. <view class="submit-view">
  78. <u-button type="primary" ripple shape="circle" v-if="applyInfo.refundWay" :custom-style="customStyle" @click="onSubmit">提交申请</u-button>
  79. </view>
  80. <u-select mode="single-column" :list="reasonList" v-model="reasonSelectShow" @confirm="reasonSelectConfirm"></u-select>
  81. <u-select mode="single-column" :list="typeList" v-model="typeSelectShow" @confirm="typeSelectConfirm"></u-select>
  82. <u-select mode="single-column" :list="returnList" v-model="returnSelectShow" @confirm="returnSelectConfirm"></u-select>
  83. <u-toast ref="uToast" />
  84. </view>
  85. </template>
  86. <script>
  87. import {
  88. getAfterSaleReason,
  89. applyReturn,
  90. getAfterSaleInfo,
  91. } from "@/api/after-sale";
  92. import city from "@/components/m-city/m-city";
  93. import { upload } from "@/api/common.js";
  94. import storage from "@/utils/storage.js";
  95. export default {
  96. component: {
  97. city,
  98. },
  99. data() {
  100. return {
  101. storage,
  102. list: [{ id: "", localName: "请选择", children: [] }],
  103. action: upload, //图片上传数据
  104. fileList: [],
  105. sn: "",
  106. sku: {},
  107. typeValue: 0,
  108. value: "",
  109. type: "textarea",
  110. border: true,
  111. //退款原因 弹出框
  112. reasonSelectShow: false,
  113. reasonList: [],
  114. //退款方式为账号退款 账号类型弹出框
  115. typeSelectShow: false,
  116. typeList: [
  117. {
  118. value: "ALIPAY",
  119. label: "支付宝",
  120. },
  121. {
  122. value: "WEIXINPAY",
  123. label: "微信",
  124. },
  125. {
  126. value: "BANK_TRANSFER",
  127. label: "银行卡",
  128. },
  129. ],
  130. //返回方式
  131. returnSelectShow: false,
  132. returnList: [
  133. {
  134. value: 1,
  135. label: "快递至第三方卖家",
  136. },
  137. ],
  138. customStyle: {
  139. backgroundColor: this.$lightColor,
  140. },
  141. applyInfo: {},
  142. form: {
  143. orderItemSn: "", // 订单sn
  144. skuId: "",
  145. reason: "", //退款原因
  146. problemDesc: "", //退款说明
  147. images: [], //图片凭证
  148. num: 1, //退货数量
  149. goodsId: "", //商品id
  150. accountType: "",
  151. applyRefundPrice: "",
  152. refundWay: "",
  153. serviceType: "", //申请类型
  154. },
  155. };
  156. },
  157. /**
  158. * 判断当前内容并生成数据
  159. */
  160. onLoad(options) {
  161. let navTitle = "申请售后";
  162. this.form.serviceType = "RETURN_GOODS";
  163. if (options.value == 1) {
  164. navTitle = "申请退货";
  165. this.form.serviceType = "RETURN_GOODS";
  166. }
  167. if (options.value == 2) {
  168. navTitle = "申请换货";
  169. this.form.serviceType = "EXCHANGE_GOODS";
  170. }
  171. if (options.value == 3) {
  172. navTitle = "申请退款";
  173. this.form.serviceType = "RETURN_MONEY";
  174. }
  175. this.typeValue = options.value;
  176. uni.setNavigationBarTitle({
  177. title: navTitle, //此处写页面的title
  178. });
  179. this.sn = options.sn;
  180. let dsku = decodeURIComponent(options.sku);
  181. let newSku = JSON.parse(dsku);
  182. this.sku = newSku
  183. this.form.orderItemSn = options.sn;
  184. this.form.skuId = this.sku.skuId;
  185. this.form.num = this.sku.num;
  186. this.form.goodsId = this.sku.goodsId;
  187. this.getReasonActions(this.form.serviceType);
  188. this.init(options.sn);
  189. },
  190. methods: {
  191. /** 获取申请原因下拉框数据 */
  192. async getReasonActions(serviceType) {
  193. uni.showLoading({
  194. title: "加载中",
  195. });
  196. await getAfterSaleReason(serviceType).then((res) => {
  197. if (res.data.success) {
  198. let action = [];
  199. res.data.result.forEach((item) => {
  200. action.push({
  201. value: item.id,
  202. label: item.reason,
  203. });
  204. });
  205. this.reasonList = action;
  206. }
  207. });
  208. uni.hideLoading();
  209. },
  210. //打开地区选择器
  211. showCitySelect() {
  212. this.$refs.cityPicker.show();
  213. },
  214. // 初始化数据
  215. init(sn) {
  216. getAfterSaleInfo(sn).then((response) => {
  217. if (response.data.code == 400) {
  218. uni.showToast({
  219. title: response.data.message,
  220. duration: 2000,
  221. icon: "none",
  222. });
  223. } else {
  224. this.applyInfo = response.data.result;
  225. this.form.accountType = response.data.result.accountType;
  226. }
  227. });
  228. },
  229. //退款原因
  230. reasonSelectConfirm(e) {
  231. this.form.reason = e[0].label;
  232. },
  233. //退款方式
  234. typeSelectConfirm(e) {
  235. this.form.accountType = e[0].value;
  236. this.form.accountType_label = e[0].label;
  237. },
  238. //返回方式
  239. returnSelectConfirm(e) {
  240. },
  241. //修改申请数量
  242. valChange(e) {
  243. this.form.num = e.value;
  244. },
  245. //图片上传
  246. onUploaded(lists) {
  247. let images = [];
  248. lists.forEach((item) => {
  249. images.push(item.response.result);
  250. });
  251. this.form.images = images;
  252. },
  253. //提交申请
  254. onSubmit() {
  255. //提交申请前检测参数
  256. if (!this.handleCheckParams()) {
  257. return;
  258. }
  259. uni.showLoading({
  260. title: "加载中",
  261. });
  262. this.form.accountType = this.applyInfo.accountType;
  263. this.form.refundWay = this.applyInfo.refundWay;
  264. this.form.applyRefundPrice = this.applyInfo.applyRefundPrice;
  265. applyReturn(this.sn, this.form).then((resp) => {
  266. uni.hideLoading();
  267. if (resp.data.success) {
  268. this.$refs.uToast.show({ title: "提交成功", type: "success" });
  269. uni.redirectTo({
  270. url: "/pages/order/afterSales/applySuccess",
  271. });
  272. } else {
  273. this.$refs.uToast.show({ title: resp.data.message, type: "error" });
  274. }
  275. });
  276. },
  277. /**
  278. * 验证银行卡号
  279. */
  280. checkBankno(bankno) {
  281. var lastNum = bankno.substr(bankno.length - 1, 1); //取出最后一位(与luhm进行比较)
  282. var first15Num = bankno.substr(0, bankno.length - 1); //前15或18位
  283. var newArr = [];
  284. for (var i = first15Num.length - 1; i > -1; i--) {
  285. //前15或18位倒序存进数组
  286. newArr.push(first15Num.substr(i, 1));
  287. }
  288. var arrJiShu = []; //奇数位*2的积 <9
  289. var arrJiShu2 = []; //奇数位*2的积 >9
  290. var arrOuShu = []; //偶数位数组
  291. for (var j = 0; j < newArr.length; j++) {
  292. if ((j + 1) % 2 == 1) {
  293. //奇数位
  294. if (parseInt(newArr[j]) * 2 < 9)
  295. arrJiShu.push(parseInt(newArr[j]) * 2);
  296. else arrJiShu2.push(parseInt(newArr[j]) * 2);
  297. } //偶数位
  298. else arrOuShu.push(newArr[j]);
  299. }
  300. var jishu_child1 = []; //奇数位*2 >9 的分割之后的数组个位数
  301. var jishu_child2 = []; //奇数位*2 >9 的分割之后的数组十位数
  302. for (var h = 0; h < arrJiShu2.length; h++) {
  303. jishu_child1.push(parseInt(arrJiShu2[h]) % 10);
  304. jishu_child2.push(parseInt(arrJiShu2[h]) / 10);
  305. }
  306. var sumJiShu = 0; //奇数位*2 < 9 的数组之和
  307. var sumOuShu = 0; //偶数位数组之和
  308. var sumJiShuChild1 = 0; //奇数位*2 >9 的分割之后的数组个位数之和
  309. var sumJiShuChild2 = 0; //奇数位*2 >9 的分割之后的数组十位数之和
  310. var sumTotal = 0;
  311. for (var m = 0; m < arrJiShu.length; m++) {
  312. sumJiShu = sumJiShu + parseInt(arrJiShu[m]);
  313. }
  314. for (var n = 0; n < arrOuShu.length; n++) {
  315. sumOuShu = sumOuShu + parseInt(arrOuShu[n]);
  316. }
  317. for (var p = 0; p < jishu_child1.length; p++) {
  318. sumJiShuChild1 = sumJiShuChild1 + parseInt(jishu_child1[p]);
  319. sumJiShuChild2 = sumJiShuChild2 + parseInt(jishu_child2[p]);
  320. }
  321. //计算总和
  322. sumTotal =
  323. parseInt(sumJiShu) +
  324. parseInt(sumOuShu) +
  325. parseInt(sumJiShuChild1) +
  326. parseInt(sumJiShuChild2);
  327. //计算Luhm值
  328. var k = parseInt(sumTotal) % 10 == 0 ? 10 : parseInt(sumTotal) % 10;
  329. var luhm = 10 - k;
  330. if (lastNum == luhm) {
  331. return true;
  332. } else {
  333. return false;
  334. }
  335. },
  336. //检测提交参数
  337. handleCheckParams() {
  338. if (this.$u.test.isEmpty(this.form.reason)) {
  339. this.$refs.uToast.show({ title: "请选择 退款原因", type: "error" });
  340. return false;
  341. }
  342. if (this.$u.test.isEmpty(this.form.problemDesc)) {
  343. this.$refs.uToast.show({ title: "请输入 退款说明", type: "error" });
  344. return false;
  345. }
  346. if (this.form.accountType == "BANK_TRANSFER") {
  347. // 银行开户行校验
  348. if (this.$u.test.isEmpty(this.form.bankDepositName)) {
  349. this.$refs.uToast.show({
  350. title: "请输入 银行开户行",
  351. type: "error",
  352. });
  353. return false;
  354. }
  355. // 银行开户名校验
  356. if (this.$u.test.isEmpty(this.form.bankAccountName)) {
  357. this.$refs.uToast.show({
  358. title: "请输入 银行开户名",
  359. type: "error",
  360. });
  361. return false;
  362. }
  363. // 银行账号校验
  364. if (this.$u.test.isEmpty(this.form.bankAccountNumber)) {
  365. this.$refs.uToast.show({
  366. title: "请输入 银行账号",
  367. type: "error",
  368. });
  369. return false;
  370. } else if (this.checkBankno(this.form.bankAccountNumber) === false) {
  371. this.$refs.uToast.show({
  372. title: "银行卡卡号不正确",
  373. type: "error",
  374. });
  375. return false;
  376. } else if (this.$u.test.chinese(this.form.bankAccountName) === false) {
  377. this.$refs.uToast.show({
  378. title: "银行开户名输入错误",
  379. type: "error",
  380. });
  381. return false;
  382. } else if (this.$u.test.chinese(this.form.bankDepositName) === false) {
  383. this.$refs.uToast.show({
  384. title: "银行开户行输入错误",
  385. type: "error",
  386. });
  387. return false;
  388. }
  389. }
  390. return true;
  391. },
  392. },
  393. };
  394. </script>
  395. <style lang="scss" scoped>
  396. page,
  397. .content {
  398. background: $page-color-base;
  399. height: 100%;
  400. }
  401. .body-view {
  402. margin-bottom: 150rpx;
  403. }
  404. .after-sales-goods-detail-view {
  405. background-color: #fff;
  406. .header {
  407. background-color: #f7f7f7;
  408. color: #999999;
  409. font-size: 22rpx;
  410. display: flex;
  411. flex-direction: row;
  412. align-items: center;
  413. justify-content: center;
  414. line-height: 70rpx;
  415. .header-text {
  416. background-color: #999999;
  417. padding: 10rpx 30rpx;
  418. border-radius: 50rpx;
  419. }
  420. .seller-name {
  421. color: $main-color;
  422. }
  423. }
  424. .goods-item-view {
  425. display: flex;
  426. flex-direction: row;
  427. padding: 10rpx 30rpx;
  428. background-color: #eef1f2;
  429. .goods-info {
  430. padding-left: 30rpx;
  431. flex: 1;
  432. .goods-title {
  433. margin-bottom: 10rpx;
  434. color: $font-color-dark;
  435. }
  436. .goods-specs {
  437. font-size: 24rpx;
  438. margin-bottom: 10rpx;
  439. color: #cccccc;
  440. }
  441. .goods-price {
  442. display: flex;
  443. flex-direction: row;
  444. justify-content: space-between;
  445. font-size: 28rpx;
  446. margin-bottom: 10rpx;
  447. color: $light-color;
  448. .num {
  449. font-size: 24rpx;
  450. color: #999999;
  451. }
  452. }
  453. }
  454. .goods-num {
  455. width: 60rpx;
  456. color: $main-color;
  457. }
  458. }
  459. }
  460. .after-num {
  461. margin: 0rpx 30rpx;
  462. display: flex;
  463. flex-direction: row;
  464. align-items: center;
  465. justify-content: space-between;
  466. height: 80rpx;
  467. }
  468. .opt-tip {
  469. margin-top: 20rpx;
  470. padding: 10rpx 30rpx;
  471. font-size: 22rpx;
  472. }
  473. .opt-view {
  474. background-color: #fff;
  475. margin-top: 20rpx;
  476. padding: 10rpx 30rpx;
  477. .how-view {
  478. display: flex;
  479. flex-direction: row;
  480. align-items: center;
  481. justify-content: space-between;
  482. height: 80rpx;
  483. border-bottom: 1px solid $page-color-base;
  484. }
  485. .explain-view {
  486. display: flex;
  487. flex-direction: row;
  488. align-items: center;
  489. height: 150rpx;
  490. }
  491. .img-title {
  492. height: 80rpx;
  493. display: flex;
  494. flex-direction: row;
  495. align-items: center;
  496. }
  497. .images-view {
  498. padding: 20rpx;
  499. display: flex;
  500. flex-direction: row;
  501. align-items: center;
  502. flex-wrap: wrap;
  503. }
  504. }
  505. .item-apply-voucher {
  506. width: 100%;
  507. display: flex;
  508. justify-content: flex-end;
  509. }
  510. .submit-view {
  511. position: fixed;
  512. z-index: 999;
  513. bottom: 0px;
  514. left: 0px;
  515. margin-top: 100rpx;
  516. border: solid 2rpx #f2f2f2;
  517. background-color: #ffffff;
  518. height: 100rpx;
  519. width: 750rpx;
  520. align-items: center;
  521. padding: 0rpx 20rpx;
  522. }
  523. </style>