refund.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. <?php
  2. use common\helpers\ComponentHelper;
  3. ComponentHelper::loadComponentView('com-export-dialog');
  4. ?>
  5. <style>
  6. @media screen and (max-width: 1500px) {
  7. #app {
  8. min-width: 1270px;
  9. }
  10. }
  11. .demo-form-inline .el-select .el-input {
  12. width: 100px;
  13. }
  14. /* 订单表格 start */
  15. .width-pre10 {
  16. width: 10%;
  17. }
  18. .width-50 {
  19. width: 80px;
  20. }
  21. .width-400 {
  22. width: 350px;
  23. }
  24. .order-table {
  25. overflow-x: scroll;
  26. }
  27. .tab-title,
  28. .tab-cont {
  29. width: 100%;
  30. min-width: 1290px;
  31. font-size: 13px;
  32. }
  33. .tab-title {
  34. padding: 20px 0;
  35. }
  36. .tab-title>li {
  37. padding: 0 10px;
  38. }
  39. .tab-cont {
  40. border: 1px solid #F2F2F2;
  41. margin-bottom: 20px;
  42. }
  43. .tab-cont-row {
  44. padding: 10px 0;
  45. background-color: #F7F7F7;
  46. }
  47. .tab-cont-info {
  48. height: 100px;
  49. }
  50. .tab-cont-info>li {
  51. /* display: flex;
  52. flex-direction: column;
  53. justify-content: center; */
  54. height: 100%;
  55. padding: 16px 10px;
  56. }
  57. .tab-btns {
  58. width: 320px;
  59. margin-right: 20px;
  60. }
  61. .tab-goods-name {
  62. margin: 0 10px;
  63. }
  64. .border-right {
  65. border-right: 1px solid #f2f2f2;
  66. }
  67. .border-bottom {
  68. border-bottom: 1px solid #f2f2f2;
  69. }
  70. .no-border-bottom {
  71. border-bottom: none !important;
  72. }
  73. .cursor {
  74. cursor: pointer;
  75. }
  76. .edit-icon {
  77. color: #03c5ff;
  78. cursor: pointer;
  79. }
  80. .popover-btn {
  81. font-size: 12px;
  82. padding: 0 10px;
  83. border-right: 1px solid var(--primary, #03c5ff);
  84. cursor: pointer;
  85. display: inline-block;
  86. line-height: 1;
  87. color: #03c5ff;
  88. }
  89. .popover-btn:last-child {
  90. border-right: none;
  91. }
  92. .width-s {
  93. width: 250px;
  94. }
  95. .el-button--text {
  96. padding: 0 !important;
  97. }
  98. /* 订单表格 end */
  99. </style>
  100. <div id="app" v-cloak>
  101. <el-card shadow="never" body-style="background-color: #f3f3f3;padding: 10px 0 0;">
  102. <div slot="header">
  103. <span>订单列表</span>
  104. <div style="float: right; margin: -5px 0">
  105. <!-- <el-button type="primary" size="small" @click="handle('edit')">添加商品</el-button>-->
  106. <!-- <el-button type="primary" size="small">订单导出</el-button>-->
  107. <com-export-dialog style="float: right;margin-top: -5px" :field_list='export_list' :action_url="export_url" :params="search_data">
  108. </com-export-dialog>
  109. </div>
  110. <div style="float: right; margin: -5px 0">
  111. <!-- <el-button type="primary" size="small" @click="handle('edit')">添加商品</el-button>
  112. <el-button type="primary" size="small">商品导出</el-button> -->
  113. </div>
  114. </div>
  115. <div class="table-body">
  116. <el-tabs v-model="activeName" @tab-click="handleClick">
  117. <el-tab-pane v-for="item in tabs" :key="item.value" :label="item.name" :name="item.value">
  118. <el-form :inline="true" :model="search_data" size="small" class="demo-form-inline">
  119. <el-form-item label="订单号">
  120. <el-input placeholder="请输入订单号或售后编号" v-model="search_data.order_no"></el-input>
  121. </el-form-item>
  122. <el-form-item label="">
  123. <el-input placeholder="请输入内容" v-model="search_data.keyword" class="input-with-select">
  124. <el-select v-model="search_data.type" slot="prepend" placeholder="请选择">
  125. <el-option label="用户电话" value="mobile"></el-option>
  126. <el-option label="商品名称" value="goods_name"></el-option>
  127. <el-option label="交易单号" value="trade_no"></el-option>
  128. </el-select>
  129. </el-input>
  130. </el-form-item>
  131. <el-form-item label="售后类型">
  132. <el-select v-model="search_data.refund_type" clearable placeholder="请选择售后类型">
  133. <el-option :label="item" :value="index" v-for="(item, index) in refund_type_list" :key="index"></el-option>
  134. </el-select>
  135. </el-form-item>
  136. <el-form-item label="商品类型">
  137. <el-select v-model="search_data.goods_type" clearable placeholder="请选择商品类型">
  138. <el-option v-for="(name, value) in goods_type" :key="value" :label="name" :value="value"></el-option>
  139. </el-select>
  140. </el-form-item>
  141. <el-form-item>
  142. <el-button type="primary" @click="search">搜索</el-button>
  143. <el-button type="danger" @click="clearSearch" v-if="show_clear_search_btn">清除条件</el-button>
  144. <el-button type="primary" @click="batchRefundSubmit" :disabled="batchRefund.is_refund_button_disabled">批量退款</el-button>
  145. </el-form-item>
  146. </el-form>
  147. <!-- 订单表格 start -->
  148. <div class="order-table">
  149. <ul class="tab-title" flex="dir:left cross:center">
  150. <li class="width-50" flex="main:center">
  151. <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="allSelOrder"></el-checkbox>
  152. </li>
  153. <li class="width-50" flex="main:center">
  154. ID
  155. </li>
  156. <li class="width-400">商品信息</li>
  157. <li class="width-pre10">价格/数量</li>
  158. <li class="width-pre10">售后状态</li>
  159. <li class="width-pre10">申请退款金额</li>
  160. <li class="width-pre10">售后方式</li>
  161. <li class="width-s">售后原因</li>
  162. <li class="width-s">收货人信息</li>
  163. <li class="">操作</li>
  164. </ul>
  165. <div class="tab-cont" v-for="(item, index) in list" :key="index">
  166. <div class="tab-cont-row" flex="main:justify cross:center">
  167. <div flex="dir:left cross:center">
  168. <div class="width-50" flex="main:center">
  169. <el-checkbox-group v-model="checkedOrder" @change="orderChange">
  170. <el-checkbox :label="item.id">{{''}}</el-checkbox>
  171. </el-checkbox-group>
  172. </div>
  173. <div style="padding-right: 20px;">售后编号:{{ item.order_no || '-' }}</div>
  174. <div style="padding-right: 20px;" v-if="item.base_user">
  175. <el-button type="text" @click="navUserDetail(item.base_user.id)" class="all_text">
  176. 用户({{item.base_user.id}}):{{ item.base_user.nickname || item.base_user.username }}
  177. </el-button>
  178. </div>
  179. <div style="padding-right: 20px;">申请时间:{{ item.created_at|dateTimeFormat('Y-m-d H:i:s')}}</div>
  180. <div style="padding-right: 20px;">订单编号:{{ item.order['order_no'] || '-' }}</div>
  181. <el-tag size="small" effect="plain" :type="item.orderDetail.order_status >= 1 ? 'success' : 'danger'">{{ order_status_map[item.orderDetail.order_status] }}</el-tag>
  182. <div style="padding-left: 20px;" v-if="item.refund_status == 1 && item.lastStep">完成时间:{{ item.lastStep.created_at|dateTimeFormat('Y-m-d H:i:s')}}</div>
  183. </div>
  184. </div>
  185. <ul class="tab-cont-info" flex="dir:left cross:center" v-if="true">
  186. <li class="width-50 border-bottom"></li>
  187. <li class="width-50 border-right border-bottom" flex="cross:center">{{ item.id }}</li>
  188. <li class="tab-shop-info width-400 border-bottom" flex="dir:left">
  189. <div style="position: relative;">
  190. <el-image style="width: 50px; height: 50px; border-radius: 5px;" :src="item.orderDetail['pic_url']"></el-image>
  191. </div>
  192. <div class="tab-goods-name">
  193. <com-ellipsis :line="1" :text="item.orderDetail['goods_name'].toString()"></com-ellipsis>
  194. <template v-if="item.orderDetail['attr_list'] && item.orderDetail['attr_list.length'] > 0">
  195. <el-tag style="margin-right: 2px;margin-top: 5px;" v-for="(attrItem, attrIndex) in item.orderDetail['attr_list']" :key="attrIndex" size="small">
  196. {{ attrItem }}
  197. </el-tag>
  198. </template>
  199. <el-tag v-else size="small">
  200. 无规格
  201. </el-tag>
  202. </div>
  203. </li>
  204. <li class="width-pre10 border-bottom">
  205. <div class="cursor" flex="cross:center">
  206. <p style="padding-right: 10px;">
  207. {{getOrderPrice(item.orderDetail)}}
  208. <span v-if="item.orderDetail['adjust_money'] != 0">(调价:¥{{ item.orderDetail['adjust_money'] }})</span>
  209. </p>
  210. </div>
  211. <p>{{ item.orderDetail['num'] }}{{item.goods_unit||'件'}}</p>
  212. </li>
  213. <li class="width-pre10 border-right border-bottom" flex="cross:center">
  214. <div>
  215. <el-tag size="small" effect="plain" :type="item.refund_status == 1 ? 'success' : 'danger'">{{ refund_status_list[item.refund_status] }}</el-tag>
  216. </div>
  217. </li>
  218. <li class="width-pre10 border-right">
  219. <div>
  220. <!-- <p>{{getOrderPrices(item,item.orderDetail, 'goods_price')}}</p>-->
  221. <p>¥{{item.refund_price}}</p>
  222. </div>
  223. </li>
  224. <li class="width-pre10 border-right">
  225. <div>
  226. <p>{{ refund_type_list[item.type] }}</p>
  227. <p v-if="item.type != 3">退款金额:{{getOrderPrices(item,item.orderDetail, 'reality_refund_price')}}</p>
  228. </div>
  229. </li>
  230. <li class="width-s border-right">
  231. <p>{{ item.reason }}</p>
  232. <com-ellipsis :line="1" :text="item.remark.toString()"></com-ellipsis>
  233. </li>
  234. <li class="width-s border-right">
  235. <div v-if="item.order && item.order.province == 0 && item.order.community_addons_data">
  236. <p>{{ item.order.community_addons_data.name | emptyFilled }}</p>
  237. <p>{{ item.order.community_addons_data.contact_name | emptyFilled }}</p>
  238. <p>{{ item.order.community_addons_data.contact_phone | emptyFilled}} </p>
  239. <p style="display: flex;align-items: center;">
  240. <com-ellipsis :line="1" :text="item.order.community_addons_data.address"></com-ellipsis>
  241. </p>
  242. </div>
  243. <div v-else>
  244. <p>{{ item.order.receiver_name | emptyFilled }}</p>
  245. <p>{{ item.order.mobile |emptyFilled}} </p>
  246. <p style="display: flex;align-items: center;">
  247. <com-ellipsis v-if="(item.order.region_name ).trim() != 'null'" :line="1" :text="item.order.region_name + '' + item.order.address"></com-ellipsis>
  248. <span v-else>--</span>
  249. </p>
  250. </div>
  251. </li>
  252. <li>
  253. <el-button size="small" type="text" @click="handle('detail',item)">售后详情</el-button>
  254. <el-button size="small" type="text" @click="handle('fen_run',item)" v-if="item.refund_status == 1">分润明细</el-button>
  255. </li>
  256. </ul>
  257. </div>
  258. </div>
  259. <div style="text-align: right;margin: 20px 0;">
  260. <el-pagination @current-change="pagination" background layout="prev, pager, next" :page-count="pageCount"></el-pagination>
  261. </div>
  262. <!-- 订单表格 end -->
  263. </el-tab-pane>
  264. </el-tabs>
  265. </div>
  266. </el-card>
  267. <el-dialog :close-on-click-modal="false" class="fenRunData" title="分润明细" :visible.sync="dialogTableVisible_fenRun">
  268. <el-tabs v-model="activeNames" @tab-click="commissionHandleClick">
  269. <el-tab-pane v-for="(v, k) in commission_type" :label="v.label" :key="v.name" :name="v.name">
  270. <el-table :data="fenRunData">
  271. <el-table-column label="用户">
  272. <template slot-scope="scope">
  273. <div class="table-info-img-text">
  274. <el-image class="table-info-img circle" :src="scope.row.avatar_url">
  275. <div slot="error" class="image-slot">
  276. <el-image class="table-info-img" src="/resources/img/common/default-avatar.png"></el-image>
  277. </div>
  278. </el-image>
  279. <div class="table-info-text">
  280. <div>{{scope.row.nickname}}<span style="color:blue">({{scope.row.user_id}})</span></div>
  281. <div>{{scope.row.mobile}}</div>
  282. </div>
  283. </div>
  284. </template>
  285. </el-table-column>
  286. <el-table-column property="change_num" :label="v.label">
  287. <template slot-scope="scope">
  288. <span v-if="scope.row.change_type=='add'" style="color:green;">+{{scope.row.change_num}}</span>
  289. <span v-else style="color:red;">-{{scope.row.change_num}}</span>
  290. </template>
  291. </el-table-column>
  292. <el-table-column property="is_frozen" label="状态"></el-table-column>
  293. <el-table-column property="capital_type_text" label="类型">
  294. <template slot-scope="scope">
  295. {{scope.row.capital_type_text}} : {{scope.row.desc}}
  296. </template>
  297. </el-table-column>
  298. <el-table-column property="from_type_text" label="所属插件"></el-table-column>
  299. </el-table>
  300. </el-tab-pane>
  301. </el-dialog>
  302. </div>
  303. <script>
  304. const app = new Vue({
  305. el: '#app',
  306. data() {
  307. return {
  308. export_list: {},
  309. export_url: 'mall/order/refund',
  310. price: 0,
  311. visibles: false,
  312. hidden: false,
  313. current: -1,
  314. detailIndex: -1,
  315. checkAll: false,
  316. isIndeterminate: false,
  317. checked: false,
  318. select: '',
  319. goods_name: '',
  320. goods_id: '',
  321. batchRefund: {// 批量退款数据
  322. refund_ids: null,
  323. is_refund_button_disabled: false,
  324. },
  325. tabs: [
  326. {
  327. name: '全部',
  328. value: '999'
  329. },
  330. {
  331. name: '售后申请',
  332. value: '0'
  333. },
  334. {
  335. name: '售后中',
  336. value: '3,4,5'
  337. },
  338. {
  339. name: '售后完成',
  340. value: '1'
  341. }
  342. ],
  343. refund_type_list: {},
  344. refund_status_list: {},
  345. checkedOrder: [], //选中的订单
  346. activeName: '999',
  347. list: [],
  348. listLoading: false,
  349. page: 1,
  350. pageCount: 0,
  351. mch_id: 0, // 这个地方不知道要怎么获取
  352. search_data: { // 筛选条件
  353. type: "mobile",
  354. keyword: null,
  355. order_no: null,
  356. refund_type: null,
  357. goods_type: ''
  358. },
  359. order_status_map: {},
  360. goods_type: <?= $goods_type ?>,
  361. dialogTableVisible_fenRun: false,
  362. fenRunData: [],
  363. user_level: {},
  364. commission_type: [],
  365. activeNames: 'commission',
  366. order_detail_id: 0,
  367. order_id: 0,
  368. };
  369. },
  370. mounted: function() {
  371. this.getOrderStatus();
  372. this.getList();
  373. },
  374. computed: {
  375. show_clear_search_btn: function() {
  376. return !isEmpty(this.search_data.order_no) || !isEmpty(this.search_data.keyword);
  377. }
  378. },
  379. updated: function() {
  380. // console.log('ssssss')
  381. },
  382. methods: {
  383. handleClick(res) { //标签页切换
  384. this.page = 1;
  385. if (this.search_data.refund_status == this.activeName) return;
  386. if (this.activeName == '999') {
  387. this.search_data.refund_status = null;
  388. } else {
  389. this.search_data.refund_status = this.activeName;
  390. }
  391. this.getList(this.search_data);
  392. },
  393. search() {
  394. this.getList(this.search_data);
  395. },
  396. clearSearch() {
  397. this.search_data.order_no = null;
  398. this.search_data.type = 'mobile';
  399. this.search_data.keyword = null;
  400. this.getList();
  401. },
  402. navUserDetail(id) {
  403. this.$navigate({
  404. r: 'mall/user/user-detail',
  405. id: id
  406. })
  407. },
  408. handle(type, data = null) {
  409. let id = data ? parseInt(data.id) : '';
  410. switch (type) {
  411. // 订单详情
  412. case 'detail':
  413. let params = {
  414. r: 'mall/order/refund-detail'
  415. };
  416. if (id) params = Object.assign(params, {
  417. id: id
  418. });
  419. navigateTo(params);
  420. break;
  421. // 删除售后
  422. case 'destroy':
  423. param = {
  424. id: data.id,
  425. type
  426. };
  427. this.$confirm('删除该条数据后不可以恢复, 是否继续?', '警告', {
  428. type: 'warning'
  429. }).then(() => {
  430. this.send(param)
  431. }).catch((err) => {})
  432. break;
  433. case 'fen_run':
  434. this.dialogTableVisible_fenRun = true;
  435. this.order_id = data.order_id;
  436. this.order_detail_id = data.order_detail_id;
  437. this.getCapitalLog(data.order_id, data.order_detail_id, this.activeNames)
  438. break;
  439. }
  440. },
  441. send(url, params, callback) {
  442. let self = this;
  443. request({
  444. params: {
  445. r: url,
  446. },
  447. method: 'post',
  448. data: params
  449. }).then(e => {
  450. if (e.data.code == 0) {
  451. self.$message.success(e.data.msg);
  452. self.getList(this.search_data);
  453. } else {
  454. self.$message.error(e.data.msg);
  455. }
  456. if (callback) callback(e.data);
  457. }).catch(e => {
  458. console.log(e);
  459. });
  460. },
  461. pagination(currentPage) {
  462. let self = this;
  463. self.page = currentPage;
  464. self.getList(this.search_data);
  465. },
  466. getOrderStatus() {
  467. let self = this;
  468. request({
  469. params: {
  470. r: 'mall/order/get-order-status',
  471. },
  472. method: 'get',
  473. }).then(e => {
  474. if (e.data.code == 0) {
  475. self.order_status_map = e.data.data.order_status_map;
  476. } else {
  477. self.$message.error(e.data.msg);
  478. }
  479. }).catch(e => {
  480. self.$message.error(e);
  481. });
  482. },
  483. // 获取商品列表
  484. getList(params = {}) {
  485. let self = this;
  486. let basic_params = {
  487. r: 'mall/order/refund',
  488. page: self.page,
  489. };
  490. params = Object.assign(basic_params, params);
  491. console.log(params);
  492. if (self.listLoading == false) {
  493. self.listLoading = true;
  494. request({
  495. params: params,
  496. method: 'get',
  497. }).then(e => {
  498. self.listLoading = false;
  499. if (e.data.code == 0) {
  500. self.list = e.data.data.list;
  501. self.export_list = e.data.data.export_list;
  502. self.refund_type_list = e.data.data.refund_type_list;
  503. self.refund_status_list = e.data.data.refund_status_list;
  504. self.commission_type = e.data.data.commission_type;
  505. self.pageCount = e.data.data.page_count;
  506. } else {
  507. self.$message.error(e.data.msg);
  508. }
  509. }).catch(e => {
  510. self.$message.error(e.data.msg);
  511. self.listLoading = false;
  512. });
  513. }
  514. },
  515. getOrderPrice(data){
  516. let text = '';
  517. switch (data.marketing_type) {
  518. case 'ScoreMall' :
  519. text = data.extra_info;
  520. break;
  521. default :
  522. text = '¥'+data.goods_price;
  523. }
  524. return text;
  525. },
  526. getOrderPrices(order,orderDetail, field = null){
  527. let text = '';
  528. switch (orderDetail.marketing_type) {
  529. case 'ScoreMall' :
  530. text = orderDetail.extra_info;
  531. break;
  532. default :
  533. text = '¥'+order.refund_price;
  534. }
  535. return text;
  536. },
  537. orderChange(val) {
  538. let checkedCount = val.length;
  539. this.checkAll = checkedCount == this.list.length;
  540. this.isIndeterminate = checkedCount > 0 && checkedCount < this.list.length;
  541. this.batchRefund.refund_ids = val;
  542. },
  543. allSelOrder(boo) {
  544. let ids = [];
  545. this.list.forEach(v => {
  546. ids.push(v.id);
  547. })
  548. this.checkedOrder = boo ? ids : [];
  549. this.isIndeterminate = false;
  550. this.batchRefund.refund_ids = ids;
  551. },
  552. batchRefundSubmit() {// 批量退款
  553. if (this.batchRefund.refund_ids === '' || this.batchRefund.refund_ids == null){
  554. return this.$message.error("请选择需要操作操作的订单!");
  555. }
  556. let refund_ids = this.batchRefund.refund_ids.join(',');
  557. this.batchRefund.is_refund_button_disabled = true;
  558. request({
  559. params: {
  560. r: 'mall/order/batch-refund',
  561. },
  562. method: 'post',
  563. data: {
  564. refund_ids: refund_ids,
  565. }
  566. }).then(e => {
  567. if (e.data.code === 0) {
  568. this.$message({
  569. message: e.data.msg,
  570. type: 'success',
  571. duration: 2000,
  572. onClose: () => {
  573. window.location.reload();
  574. }
  575. });
  576. } else {
  577. this.batchRefund.is_refund_button_disabled = false;
  578. this.$message.error(e.data.msg);
  579. }
  580. }).catch(e => {
  581. console.log(e);
  582. });
  583. },
  584. getCapitalLog(order_id, order_detail_id, wallet_type) {
  585. request({
  586. params: {
  587. r: 'mall/order/commission-and-score-list-by-order-detail-id',
  588. order_detail_id: order_detail_id,
  589. order_id: order_id,
  590. wallet_type: wallet_type,
  591. },
  592. method: 'get',
  593. }).then(e => {
  594. if (e.data.code == 0) {
  595. this.fenRunData = e.data.data.list;
  596. this.user_level = e.data.data.user_level;
  597. } else {
  598. self.$message.error(e.data.msg);
  599. }
  600. }).catch(e => {
  601. console.log(e);
  602. });
  603. },
  604. commissionHandleClick(tab, event) {
  605. this.getCapitalLog(this.order_id, this.order_detail_id, this.activeNames)
  606. },
  607. }
  608. });
  609. </script>