提交 34000873 作者: 毛细亚

合并分支 '7.8.2' 到 'release'

新增退款退回道具功能

查看合并请求 !67
<template>
<el-drawer :lock-scroll="true" :title="title" :visible="show" size="300px" :append-to-body="true" @close="close">
<el-drawer :lock-scroll="true" :title="title" :visible="show" size="360px" :append-to-body="true" @close="close">
<div class="errorHandleContent">
<el-form
ref="ruleForm"
......@@ -27,6 +27,65 @@
</el-option>
</el-select>
</el-form-item>
<!-- 退回道具 -->
<el-form-item label="退回道具名称">
<div class="return-prop-container">
<!-- 道具行 -->
<div
v-for="(item, index) in ruleForm.return_prop"
:key="index"
class="prop-item"
>
<!-- 道具名称选择器 -->
<div>
<el-select
v-model="item.code"
filterable
remote
reserve-keyword
:remote-method="remoteMethod"
placeholder="请输入道具名称"
style="width: 120px;"
@change="returnPropChange(item, index)"
>
<el-option
v-for="prop in codeList"
:key="prop.value"
:label="prop.label"
:value="prop.value"
></el-option>
</el-select>
<!-- 数量输入框 -->
<el-input
v-model="item.num"
type="number"
min="1"
step="1"
placeholder="数量"
class="prop-num-input"
style="width: 80px; margin-left: 8px;"
@blur="normalizeReturnPropNum(item)"
/>
</div>
<!-- 删除按钮 -->
<i
class="el-icon-remove-outline icon"
@click="removeReturnProp(item, index)"
></i>
</div>
<!-- 添加按钮 -->
<el-button
size="small"
style="width: 80px;"
icon="el-icon-plus"
@click="addReturnProp"
>
添加
</el-button>
</div>
</el-form-item>
<el-form-item label="玩家反馈时间" prop="feedback_time">
<el-date-picker
v-model="ruleForm.feedback_time"
......@@ -58,8 +117,9 @@
</el-drawer>
</template>
<script type="text/javascript">
import { refundRequest } from '@/api/game'
import { refundRequest,selectSearch } from '@/api/game'
import textEditor from '@/components/textEditor.vue'
import { debounce } from '@/utils'
export default {
name: 'orderRefund',
components: { textEditor },
......@@ -67,9 +127,11 @@
data() {
return {
searchLoading: false,
number: 1,
reasonList: [
{ label: '充值未到账', value: 1 } // 掌微只有一个原因
],
codeList: [],
ruleForm: {
reason: 1,
feedback_time: '',
......@@ -80,7 +142,8 @@
remark: '',
extra_attribution: [],
user_name: '',
user_id: ''
user_id: '',
return_prop: []
},
rules: {
'orders.order_id': [
......@@ -112,7 +175,8 @@
remark: '',
extra_attribution: [],
user_name: '',
user_id: ''
user_id: '',
return_prop: []
}
this.ruleForm.remark = ''
this.ruleForm.orders.order_id = this.info.order_id
......@@ -121,8 +185,9 @@
}
}
},
mounted() {
created() {
// 创建防抖搜索函数
this.debouncedSearch = debounce(this.searchProps, 500)
},
methods: {
resultReamrk(html) {
......@@ -132,12 +197,90 @@
resultUpload(value) {
this.ruleForm.extra_attribution = value
},
// 添加退回道具
addReturnProp() {
if (this.ruleForm.return_prop.length >= 10) {
this.$message.warning('最多添加 10 个道具')
return
}
this.ruleForm.return_prop.push({
code: '',
num: 1
})
},
// 删除退回道具
removeReturnProp(item, index) {
this.ruleForm.return_prop.splice(index, 1)
},
// 道具选择变化
returnPropChange(item, index) {
const selectedProp = this.codeList.find(prop => prop.value === item.code)
// 使用 $set 确保 Vue 能检测到变化
this.$set(this.ruleForm.return_prop, index, {
...item,
name: selectedProp ? selectedProp.label : ''
})
},
// 搜索道具(实际执行的方法)
async searchProps(query) {
if (!this.info.main_game_id) {
this.$message.warning('缺少游戏信息,无法搜索道具')
return
}
const trimmedQuery = query.trim()
if (!trimmedQuery) {
this.codeList = []
return
}
try {
const data = {
type: 'misoperation_code',
value: trimmedQuery,
main_game_id: this.info.main_game_id
}
const res = await selectSearch(data)
if (res.status_code === 1) {
this.codeList = res.data.data || []
}
} catch (error) {
console.error('搜索道具失败:', error)
this.$message.error('搜索道具失败')
}
},
// 远程搜索方法(防抖后的方法)
remoteMethod(query) {
this.debouncedSearch(query)
},
// 数量输入框失焦后规范为整数且不小于 1(type=number 时 v-model 可能为字符串)
normalizeReturnPropNum(item) {
const raw = item.num
const n = parseInt(String(raw).trim(), 10)
if (raw === '' || raw === null || Number.isNaN(n) || n < 1) {
this.$set(item, 'num', 1)
} else {
this.$set(item, 'num', n)
}
},
close() {
this.$emit('update:show', false)
},
async submit() {
this.$refs.ruleForm.validate(async (valid) => {
if (valid) {
// 过滤掉未选择道具的项
const validReturnProp = this.ruleForm.return_prop.filter(
item => item.code && item.num > 0
)
// 验证退回道具数据
const invalidProp = this.ruleForm.return_prop.find(item =>
(item.code && !item.num) || (!item.code && item.num)
)
if (invalidProp) {
this.$message.warning('请完善退回道具信息')
return
}
this.ruleForm.orders.refund_amount = this.info.amount
this.searchLoading = true
const { reason, feedback_time, orders, remark, extra_attribution } = this.ruleForm
......@@ -149,18 +292,22 @@
remark,
extra_attribution,
user_name: username,
user_id: id
user_id: id,
return_prop: validReturnProp
}
try {
const res = await refundRequest(data)
if (res.status_code === 1) {
this.$message.success(res.msg)
this.close()
}
this.searchLoading = false
this.close()
} catch (error) {
}catch (error) {
console.error('提交退款申请失败:', error)
this.$message.error('提交失败,请重试')
} finally {
this.searchLoading = false
}
} else {
return false
}
......@@ -220,5 +367,80 @@
margin-bottom: 20px;
}
}
.return-prop-container {
display: flex;
flex-direction: column;
gap: 8px;
width: 100%;
}
.prop-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 16px;
background: #f7f8fa;
border-radius: 4px;
height: 48px;
.el-select {
::v-deep .el-input__inner {
height: 32px;
line-height: 32px;
font-size: 13px;
font-family: 'PingFang SC', sans-serif;
color: #323335;
background: white;
border: 1px solid #d9d9d9;
border-radius: 4px;
padding: 4px 12px;
&::placeholder {
color: #c9cdd4;
font-size: 13px;
}
}
}
.prop-num-input {
::v-deep .el-input__inner {
height: 32px;
line-height: 32px;
font-size: 13px;
font-family: 'PingFang SC', sans-serif;
color: #323335;
text-align: center;
background: #fff;
border: 1px solid #d9d9d9;
border-radius: 4px;
padding: 4px 12px;
box-sizing: border-box;
appearance: textfield;
-moz-appearance: textfield;
}
}
.icon {
font-size: 18px;
color: #00BF8A;
cursor: pointer;
transition: color 0.2s;
&:hover {
color: #409eff;
}
}
}
.icon {
font-size: 18px;
color: #409eff;
cursor: pointer;
transition: color 0.2s;
&:hover {
color: #66b1ff;
}
}
</style>
\ No newline at end of file
......@@ -65,7 +65,9 @@
<div v-for="(item, index) in orderList" :key="index" class="orderDetails">
<div class="bridgeMain">
<p class="text">{{ item.pay_type_text || item.pay_type }}</p>
<img :src="sanjiaoxing" class="bridge" />
<span class="bridge">
<svg-icon icon-class="sanjiaoxing" />
</span>
</div>
<div class="orderDetailsTitle">
<!-- || item.pay_type=='抖音支付'去掉抖音支付补单操作 -->
......@@ -174,7 +176,6 @@ import searchSelect from './components/order/searchUser.vue'
import orderRefund from './components/order/orderRefund.vue'
import refundLog from './components/order/refundLog.vue'
import { throttle } from '@/utils'
import sanjiaoxing from '@/assets/icon/svg/sanjiaoxing.svg'
import noContent from '@/components/noContent.vue'
export default {
name: 'orderList',
......@@ -188,7 +189,6 @@ export default {
},
data() {
return {
sanjiaoxing,
loading: false,
activeType: 2,
activeTypeStr: '2',
......@@ -687,6 +687,7 @@ export default {
position: absolute;
top: 0;
right: 0;
color: #ffe59a;
}
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论