You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

637 lines
22 KiB

2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
2 months ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
  1. <!-- 客服 -->
  2. <template>
  3. <el-card style="margin-bottom: 0.5vh;">
  4. <div class="condition">
  5. <div class="item1">
  6. <el-text size="large" style="width:4vw;">精网号</el-text>
  7. <el-input v-model="searchForm.jwcode" placeholder="请输入精网号" style="width:9vw;" clearable />
  8. </div>
  9. <div class="item1">
  10. <el-text size="large" style="width:4vw;">客户姓名</el-text>
  11. <el-input v-model="searchForm.name" placeholder="请输入客户姓名" style="width:9vw;" clearable />
  12. </div>
  13. <div class="item1">
  14. <el-text size="large" style="width:4vw;">所属地区</el-text>
  15. <el-input v-model="searchForm.market" placeholder="请输入所属地区" style="width:9vw;" clearable />
  16. </div>
  17. <div class="item1">
  18. <el-text size="large" style="width:4vw;">产品名称</el-text>
  19. <el-input v-model="searchForm.goodsName" placeholder="请输入产品名称" style="width:9vw;" clearable />
  20. </div>
  21. <div class="item1">
  22. <el-text size="large" style="width:4vw;" multiple>订单状态</el-text>
  23. <el-select v-model="searchForm.statuses" style="width:9vw;">
  24. <el-option v-for="item in statusList" :key="item.value" :label="item.label" :value="item.value" />
  25. </el-select>
  26. </div>
  27. </div>
  28. <div class="condition">
  29. <div class="item2">
  30. <el-text size="large" style="width:4vw;">付款币种</el-text>
  31. <el-select v-model="searchForm.paymentCurrency" style="width:9vw;">
  32. <el-option v-for="item in currencies" :key="item.value" :label="item.label" :value="item.value" />
  33. </el-select>
  34. </div>
  35. <div class="item2">
  36. <el-text size="large" style="width:4vw;">支付方式</el-text>
  37. <el-select v-model="searchForm.payType" style="width:9vw;">
  38. <el-option v-for="item in channelOptions" :key="item.value" :label="item.label" :value="item.value" />
  39. </el-select>
  40. </div>
  41. <div class="item2" style="width: 28.5vw;">
  42. <el-text size="large" style="width:4vw;">付款时间</el-text>
  43. <el-date-picker v-model="dateRange" type="datetimerange" range-separator="" start-placeholder="起始时间"
  44. end-placeholder="结束时间" style="width:22vw;" :disabled-date="disabledDate" />
  45. </div>
  46. <div>
  47. <el-button type="primary" @click="getRefund">查询</el-button>
  48. <el-button type="success" @click="reset">重置</el-button>
  49. <el-button type="warning">导出excel</el-button>
  50. <el-button type="primary">查看导出列表</el-button>
  51. </div>
  52. </div>
  53. </el-card>
  54. <el-card style="margin-top: 0.5vh;">
  55. <el-table :data="tableData" style="height:64vh;width:82vw">
  56. <el-table-column type="index" label="序号" width="60" fixed="left" />
  57. <el-table-column prop="jwcode" label="Homily ID" width="120" fixed="left" />
  58. <el-table-column prop="name" label="姓名" width="120" fixed="left" show-overflow-tooltip />
  59. <el-table-column prop="marketName" label="所属地区" width="120" />
  60. <el-table-column prop="activity" label="活动名称" width="120px" show-overflow-tooltip />
  61. <el-table-column prop="goodsName" label="产品名称" width="120" />
  62. <el-table-column prop="goodNum" label="产品数量" width="120" />
  63. <el-table-column prop="paymentCurrency" label="付款币种" width="120" />
  64. <el-table-column prop="paymentAmount" label="付款金额" width="120" />
  65. <el-table-column prop="payType" label="支付方式" width="120" />
  66. <el-table-column prop="payTime" label="付款时间" width="180" />
  67. <el-table-column prop="voucher" label="转账凭证" width="120" show-overflow-tooltip>
  68. <template #default="scope">
  69. <img v-if="scope.row.voucher" :src="scope.row.voucher" style="width: 40px; height: 40px;" />
  70. <span v-else>无转账凭证</span>
  71. </template>
  72. </el-table-column>
  73. <el-table-column prop="remark" label="备注" width="150" show-overflow-tooltip />
  74. <el-table-column prop="status" label="订单状态" width="120">
  75. <template #default="scope">
  76. {{
  77. [10, 20, 30, 40].includes(scope.row.status) ? '审核中' :
  78. [12, 22, 32].includes(scope.row.status) ? '审核驳回' :
  79. scope.row.status === 41 ? '退款完成' : scope.row.status
  80. }}
  81. </template>
  82. </el-table-column>
  83. <el-table-column prop="operation" label="操作" fixed="right" width="100px">
  84. <template #default="scope">
  85. <div class="operation">
  86. <el-button v-if="scope.row.status === 10" type="primary" text
  87. @click="showBackDialog(scope.row)">
  88. 撤回
  89. </el-button>
  90. <el-button v-if="scope.row.status === 11" type="primary" text
  91. @click="showEditDialog(scope.row)">
  92. 编辑
  93. </el-button>
  94. <el-button v-if="scope.row.status !== 11 && scope.row.status !== 10" type="primary" text
  95. @click="showSteps = true">
  96. 查看进度
  97. </el-button>
  98. </div>
  99. </template>
  100. </el-table-column>
  101. </el-table>
  102. <el-pagination v-model:current-page="pagination.pageNum" v-model:page-size="pagination.pageSize"
  103. layout="total, sizes, prev, pager, next, jumper" :total="pagination.total"
  104. @size-change="handlePageSizeChange" @current-change="handleCurrentChange"
  105. style="margin-top: 1vh;"></el-pagination>
  106. </el-card>
  107. <el-dialog v-model="showEdit" title="退款" class="editDialog" overflow draggable style="width: 40vw;">
  108. <div style="display: flex;">
  109. <div class="left">
  110. <div class="add-item">
  111. <el-text style="width:4vw;">精网号</el-text>
  112. <el-input v-model="editRow.jwcode" style="width:10vw;" disabled />
  113. </div>
  114. <div class="add-item">
  115. <el-text style="width:4vw;">客户姓名</el-text>
  116. <el-input v-model="editRow.name" style="width:10vw;" disabled />
  117. </div>
  118. <div class="add-item">
  119. <el-text style="width:4vw;">所属地区</el-text>
  120. <el-input v-model="editRow.marketName" style="width:10vw;" disabled />
  121. </div>
  122. <div class="add-item">
  123. <el-text style="width:4vw;">活动名称</el-text>
  124. <el-input v-model="editRow.activity" style="width:10vw;" disabled />
  125. </div>
  126. <div class="add-item">
  127. <el-text style="width:4vw;">产品名称</el-text>
  128. <el-input v-model="editRow.goodsName" style="width:10vw;" disabled />
  129. </div>
  130. <div class="add-item">
  131. <el-text style="width:4vw;">产品数量</el-text>
  132. <el-input v-model="editRow.goodNum" style="width:10vw;" disabled />
  133. &nbsp;
  134. </div>
  135. <div class="add-item">
  136. <el-text style="width:4vw;">付款币种</el-text>
  137. <el-input v-model="editRow.paymentCurrency" style="width:10vw;" disabled />
  138. </div>
  139. <div class="add-item">
  140. <el-text style="width:4vw;">付款金额</el-text>
  141. <el-input v-model="editRow.paymentAmount" style="width:10vw;" disabled />
  142. </div>
  143. <div class="add-item">
  144. <el-text style="width:4vw;">支付方式</el-text>
  145. <el-input v-model="editRow.payType" style="width:10vw;" disabled />
  146. </div>
  147. <div class="add-item">
  148. <el-text style="width:4vw;">付款时间</el-text>
  149. <el-date-picker v-model="editRow.payTime" type="datetime" style="width:10vw;" disabled />
  150. </div>
  151. <div class="add-item">
  152. <el-text style="width:4vw;">转账凭证</el-text>
  153. <img v-if="editRow.voucher" :src="editRow.voucher"
  154. style="width: 100%; height: 100%; object-fit: cover;">
  155. <div v-else>
  156. 无转账凭证
  157. </div>
  158. </div>
  159. <div class="add-item">
  160. <el-text style="width:4vw;">备注</el-text>
  161. <el-input v-model="editRow.remark" style="width:10vw;" :rows="3" type="textarea" maxLength="100"
  162. disabled show-word-limit />
  163. </div>
  164. </div>
  165. <div class="right">
  166. <div class="add-item">
  167. <el-text style="width:4vw;">退款模式</el-text>
  168. <el-radio-group v-model="editForm.refundModel">
  169. <el-radio value="0">全部退款</el-radio>
  170. <el-radio value="1">部分退款</el-radio>
  171. </el-radio-group>
  172. </div>
  173. <div class="add-item">
  174. <el-text style="width:4vw;">退款理由</el-text>
  175. <el-input v-model="editForm.refundReason" style="width:10vw;" :rows="5" maxlength="150"
  176. show-word-limit type="textarea" />
  177. </div>
  178. <div>ps:请在退款理由表明用户的退款需求</div>
  179. <div style="display:flex;justify-content: center;margin-top: 5vh;">
  180. <el-button type="default" @click="resetEdit">重置</el-button>
  181. <el-button type="primary" @click="submitEdit">提交</el-button>
  182. </div>
  183. </div>
  184. </div>
  185. </el-dialog>
  186. <el-dialog v-model="showSteps" overflow draggable width="1206px" :style="{
  187. backgroundImage: 'url(/src/assets/images/背景图.png)',
  188. backgroundSize: 'cover',
  189. backgroundPosition: 'center'
  190. }">
  191. <div class="steps">
  192. <div class="steps-content">
  193. <el-steps style="min-width: 60vw" :active="1" align-center>
  194. <el-step> <template #title>
  195. <div>提交人<br>你是死的</div>
  196. </template>
  197. <template #icon>
  198. <img src="@/assets/images/已审核.png" alt="已审核图标">
  199. </template>
  200. </el-step>
  201. <el-step title="地区财务">
  202. <template #icon>
  203. <img src="@/assets/images/待审核.png" alt="待审核图标">
  204. </template>
  205. </el-step>
  206. <el-step title="地区负责人">
  207. <template #icon>
  208. <img src="@/assets/images/还没传到.png" alt="还没传到图标">
  209. </template>
  210. </el-step>
  211. <el-step title="总部财务">
  212. <template #icon>
  213. <img src="@/assets/images/还没传到.png" alt="还没传到图标">
  214. </template>
  215. </el-step>
  216. <el-step title="指定执行人">
  217. <template #icon>
  218. <img src="@/assets/images/还没传到.png" alt="还没传到图标">
  219. </template>
  220. </el-step>
  221. </el-steps>
  222. </div>
  223. <div class="steps-btn">
  224. <el-button type="primary" @click="showSteps = false">确定</el-button>
  225. </div>
  226. </div>
  227. </el-dialog>
  228. <el-dialog v-model="showBack" title="撤回退款" overflow draggable class="back-dialog" :style="{
  229. backgroundImage: 'url(/src/assets/images/撤回.png)',
  230. backgroundSize: 'cover',
  231. backgroundPosition: 'center'
  232. }">
  233. <div class="back-text"> </div>
  234. <div class="back-btn">
  235. <el-button type="default" @click="showBack = false">取消</el-button>
  236. <el-button type="primary" @click="recall" style="margin-left: 2vw;">确定</el-button>
  237. </div>
  238. </el-dialog>
  239. <el-dialog v-model="showError" overflow draggable class="back-dialog" :style="{
  240. backgroundImage: 'url(/src/assets/images/撤回.png)',
  241. backgroundSize: 'cover',
  242. backgroundPosition: 'center'
  243. }">
  244. <div class="back-text">退 </div>
  245. <div class="back-btn">
  246. <el-button type="default" @click="showError = false">取消</el-button>
  247. <el-button type="primary" @click="" style="margin-left: 2vw;">确定</el-button>
  248. </div>
  249. </el-dialog>
  250. </template>
  251. <script setup>
  252. import { ref, onMounted } from 'vue'
  253. import { ElMessage } from 'element-plus'
  254. import API from '@/util/http.js'
  255. const uploadUrl = 'https://api.homilychart.com/hljw/api/aws/upload'
  256. import { useAdminStore } from "@/store/index.js"
  257. import { storeToRefs } from "pinia"
  258. import dayjs from 'dayjs'
  259. const adminStore = useAdminStore()
  260. const { adminData, menuTree } = storeToRefs(adminStore)
  261. import { permissionMapping, findMenuById } from "@/utils/menuTreePermission.js"
  262. const dateRange = ref([])
  263. const searchForm = ref({
  264. jwcode: '',
  265. market: [],
  266. statuses: []
  267. })
  268. const backRow = ref({})// 撤回存数据
  269. const editRow = ref({})// 编辑存数据
  270. const editForm = ref({
  271. refundModel: '',
  272. refundReason: ''
  273. })
  274. const auditForm = ref({
  275. refundType: ''
  276. })
  277. const pagination = ref({
  278. pageNum: 1,
  279. pageSize: 50,
  280. total: 0
  281. })
  282. const tableData = ref([])
  283. const showEdit = ref(false)
  284. const currentRow = ref({})// 审核进度行信息
  285. const showSteps = ref(false)
  286. const uploadRef = ref(null)
  287. const showBack = ref(false)
  288. const showError = ref(false)
  289. const isKF = adminData.value.adminName.includes('客服')
  290. const statusList = ref([
  291. {
  292. value: 'waiting',
  293. label: '待审核',
  294. },
  295. {
  296. value: 'pending',
  297. label: '审核中'
  298. },
  299. {
  300. value: 'completed',
  301. label: '退款完成'
  302. }
  303. ])
  304. // 查全部
  305. const getRefund = async function () {
  306. if (!hasMenuPermission(menuTree.value, permissionMapping.refundServiceShow)) {
  307. ElMessage.error('无此权限')
  308. return
  309. }
  310. try {
  311. if (searchForm.value.statuses === 'completed') {
  312. searchForm.value.statuses = [41]
  313. } else if (searchForm.value.statuses === 'pending') {
  314. searchForm.value.statuses = [20, 30, 40]
  315. } else if (searchForm.value.statuses === 'waiting') {
  316. searchForm.value.statuses = [10]
  317. }
  318. const params = {
  319. pageNum: pagination.value.pageNum,
  320. pageSize: pagination.value.pageSize,
  321. cashRecordDone: {
  322. jwcode: searchForm.value.jwcode,//精网号
  323. name: searchForm.value.name,//姓名
  324. markets: searchForm.value.market,//地区
  325. goodsName: searchForm.value.goodsName,//商品名
  326. statuses: searchForm.value.statuses,//10:地区财务待审核;12:地区财务驳回;
  327. // 20:地区负责人待审核;22:地区负责人驳回;
  328. // 30:总部财务待审核;32:总部财务驳回;
  329. // 40:执行人待处理;41:执行人已处理,退款完成;
  330. paymentCurrency: searchForm.value.paymentCurrency,//付款币种
  331. payType: searchForm.value.payType,//支付方式
  332. startTime: dateRange.value && dateRange.value[0] ? moment(dateRange.value[0]).format('YYYY-MM-DD HH:mm:ss') : "",
  333. endtime: dateRange.value && dateRange.value[1] ? moment(dateRange.value[1]).format('YYYY-MM-DD HH:mm:ss') : "",
  334. submitterId: isKF ? adminData.value.id : null
  335. }
  336. }
  337. const result = await API({
  338. url: '/Money/select',
  339. method: 'POST',
  340. data: params
  341. })
  342. tableData.value = result.data.list || []
  343. } catch (error) {
  344. ElMessage.error(error.message || '查询失败')
  345. }
  346. }
  347. // 撤回
  348. const recall = async function () {
  349. if (!hasMenuPermission(menuTree.value, permissionMapping.refundServiceBack)) {
  350. ElMessage.error('无此权限')
  351. return
  352. }
  353. try {
  354. console.log(backRow.value)
  355. const params = {
  356. id: backRow.value.id,
  357. status: backRow.value.status,
  358. orderType: backRow.value.orderType
  359. }
  360. const result = await API({
  361. url: '/Money/update',
  362. data: params
  363. })
  364. if (result.code === 200) {
  365. ElMessage.success(result.msg || '退款成功')
  366. showBack.value = false
  367. getRefund()
  368. } else {
  369. ElMessage.error(result.msg || '退款失败')
  370. }
  371. } catch (error) {
  372. ElMessage.error(error.message || '退款失败')
  373. }
  374. }
  375. // 编辑
  376. const submitEdit = async function () {
  377. if (!hasMenuPermission(menuTree.value, permissionMapping.refundServiceEdit)) {
  378. ElMessage.error('无此权限')
  379. return
  380. }
  381. try {
  382. console.log(editRow.value)
  383. const params = {
  384. id: editRow.value.id,
  385. status: editRow.value.status,
  386. refundModel: editForm.value.refundModel,
  387. refundReason: editForm.value.refundReason,
  388. jwcode: editRow.value.jwcode,
  389. paymentAmount: editRow.value.paymentAmount,
  390. paymentCurrency: editRow.value.paymentCurrency
  391. }
  392. const result = await API({
  393. url: '/Money/update',
  394. data: params
  395. })
  396. if (result.code === 200) {
  397. ElMessage.success(result.msg || '编辑成功')
  398. showEdit.value = false
  399. getRefund()
  400. } else {
  401. ElMessage.error(result.msg || '编辑失败')
  402. }
  403. } catch (error) {
  404. ElMessage.error(error.message || '编辑失败')
  405. }
  406. }
  407. const currencies = ref([
  408. {
  409. value: '新币',
  410. label: '新币'
  411. },
  412. {
  413. value: '港币',
  414. label: '港币'
  415. },
  416. {
  417. value: '马币',
  418. label: '马币'
  419. },
  420. {
  421. value: '加币',
  422. label: '加币'
  423. },
  424. {
  425. value: '泰铢',
  426. label: '泰铢'
  427. },
  428. {
  429. value: '越南盾',
  430. label: '越南盾'
  431. }
  432. ])
  433. const channelOptions = ref([{
  434. value: '银行转账',
  435. label: '银行转账'
  436. },
  437. {
  438. value: '现金',
  439. label: '现金'
  440. },
  441. {
  442. value: '支票',
  443. label: '支票'
  444. },
  445. {
  446. value: '刷卡',
  447. label: '刷卡'
  448. },
  449. {
  450. value: 'Grabpay',
  451. label: 'Grabpay'
  452. },
  453. {
  454. value: 'Nets',
  455. label: 'Nets'
  456. },
  457. {
  458. value: 'PayPal',
  459. label: 'PayPal'
  460. },
  461. {
  462. value: 'Stripe-链接收款',
  463. label: 'Stripe-链接收款'
  464. },
  465. {
  466. value: 'Ipay88-链接收款',
  467. label: 'Ipay88-链接收款'
  468. },
  469. {
  470. value: 'PaymentAsia-链接收款',
  471. label: 'PaymentAsia-链接收款'
  472. },
  473. {
  474. value: 'Stripe-Link平台',
  475. label: 'Stripe-Link平台'
  476. },
  477. {
  478. value: 'PaymentAsia-Link平台',
  479. label: 'PaymentAsia-Link平台'
  480. },
  481. {
  482. value: 'FirstData-Link平台-Link平台',
  483. label: 'FirstData-Link平台-Link平台'
  484. },
  485. {
  486. value: 'IOS-Link平台',
  487. label: 'IOS-Link平台'
  488. },
  489. {
  490. value: 'Ipay88-Link平台',
  491. label: 'Ipay88-Link平台'
  492. }
  493. ])
  494. const reset = function () {
  495. searchForm.value = {
  496. jwcode: ''
  497. }
  498. dateRange.value = []
  499. getRefund()
  500. }
  501. const resetEdit = function () {
  502. editForm.value = {
  503. refundModel: '',
  504. refundReason: ''
  505. }
  506. }
  507. const showBackDialog = function (row) {
  508. backRow.value = row
  509. showBack.value = true
  510. }
  511. const showEditDialog = function (row) {
  512. editRow.value = row
  513. showEdit.value = true
  514. }
  515. const handlePageSizeChange = function (val) {
  516. pagination.value.pageSize = val
  517. getRefund()
  518. }
  519. const handleCurrentChange = function (val) {
  520. pagination.value.pageNum = val
  521. getRefund()
  522. }
  523. const disabledDate = (time) => {
  524. const limitDate = new Date(2025, 0, 1);
  525. return time.getTime() < limitDate.getTime();
  526. }
  527. onMounted(() => {
  528. getRefund()
  529. console.log('???????????????????', adminData.value)
  530. })
  531. </script>
  532. <style scoped lang="scss">
  533. .condition {
  534. width: 82vw;
  535. display: flex;
  536. align-items: center;
  537. height: 4vh;
  538. .item1 {
  539. width: 18%;
  540. display: flex;
  541. align-items: center;
  542. margin-bottom: 1vh;
  543. margin-right: 0.5vw;
  544. }
  545. .item2 {
  546. width: 18%;
  547. display: flex;
  548. align-items: center;
  549. margin-right: 0.5vw;
  550. }
  551. }
  552. .editDialog {
  553. .left {
  554. width: 50%;
  555. height: 70vh;
  556. padding: 0 2vw;
  557. .add-item {
  558. display: flex;
  559. align-items: center;
  560. margin-bottom: 1vh;
  561. }
  562. .image {
  563. width: 4vw !important;
  564. height: 4vw !important;
  565. }
  566. }
  567. .right {
  568. width: 50%;
  569. height: 50vh;
  570. .add-item {
  571. display: flex;
  572. align-items: center;
  573. margin-bottom: 1vh;
  574. }
  575. }
  576. }
  577. .steps {
  578. .steps-content {
  579. width: 45vw;
  580. height: 15vh;
  581. display: flex;
  582. justify-content: center;
  583. padding-top: 15vw;
  584. padding-left: 8vw;
  585. }
  586. .steps-status {
  587. display: flex;
  588. align-items: center;
  589. justify-content: center;
  590. }
  591. .steps-btn {
  592. height: 15vh;
  593. display: flex;
  594. justify-content: center;
  595. align-items: center;
  596. }
  597. }
  598. .back-dialog {
  599. width: 700px;
  600. height: auto;
  601. .back-text {
  602. font-size: 60px;
  603. font-weight: bold;
  604. color: #000000;
  605. text-align: center;
  606. justify-content: center;
  607. margin-top: 22vh;
  608. }
  609. .back-btn {
  610. height: 20vh;
  611. display: flex;
  612. justify-content: center;
  613. align-items: center;
  614. }
  615. }
  616. </style>