fix: 修改工单bug
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m15s

This commit is contained in:
sexygoat
2026-04-22 17:42:36 +08:00
parent 8378d2228e
commit fd22dc7ad4
14 changed files with 199 additions and 280 deletions

View File

@@ -280,6 +280,11 @@
transform: scale(0.6) !important;
}
}
.el-checkbox__input.is-disabled .el-checkbox__inner {
background-color: var(--el-color-primary) !important;
border-color: var(--el-color-primary) !important;
}
}
.el-notification .el-notification__icon {

Binary file not shown.

Binary file not shown.

View File

@@ -402,7 +402,7 @@
]
// 显示对话框
const showDialog = (type: string, row?: any) => {
const showDialog = async (type: string, row?: any) => {
dialogVisible.value = true
dialogType.value = type
@@ -411,6 +411,10 @@
formRef.value.resetFields()
}
if (type === 'add') {
await loadAllRoles()
}
if (type === 'edit' && row) {
formData.id = row.id
formData.username = row.username
@@ -590,7 +594,8 @@
try {
const params: any = {
page: 1,
page_size: keyword ? 100 : 20 // 搜索时加载更多默认20条
page_size: keyword ? 100 : 20, // 搜索时加载更多默认20条
role_type: 1
}
if (keyword) {
params.role_name = keyword
@@ -604,48 +609,14 @@
}
}
// 计算属性:新建账号时可选的角色(根据账号类型过滤)
// 计算属性:新建账号时可选的角色
const availableRolesForCreate = computed(() => {
let roles = allRoles.value
// 根据账号类型过滤角色
if (formData.user_type === 1) {
// 超级管理员:不能分配角色
return []
} else if (formData.user_type === 2) {
// 平台用户:只显示平台角色
roles = roles.filter((role) => role.role_type === 1)
} else if (formData.user_type === 3) {
// 代理账号:只显示客户角色
roles = roles.filter((role) => role.role_type === 2)
} else if (formData.user_type === 4) {
// 企业账号:只显示客户角色
roles = roles.filter((role) => role.role_type === 2)
}
return roles
return allRoles.value
})
// 计算属性:过滤后的可分配角色(根据账号类型过滤)
// 计算属性:过滤后的可分配角色
const filteredAvailableRoles = computed(() => {
let roles = allRoles.value
// 根据账号类型过滤角色
if (currentAccountType.value === 1) {
// 超级管理员:不能分配任何角色
return []
} else if (currentAccountType.value === 3) {
// 代理账号:只显示客户角色
roles = roles.filter((role) => role.role_type === 2)
} else if (currentAccountType.value === 4) {
// 企业账号:只显示客户角色
roles = roles.filter((role) => role.role_type === 2)
} else if (currentAccountType.value === 2) {
// 平台用户:只显示平台角色
roles = roles.filter((role) => role.role_type === 1)
}
return roles
return allRoles.value
})
// 搜索防抖定时器

View File

@@ -6,9 +6,6 @@
<ElDescriptionsItem label="套餐名称">
{{ data.package_name }}
</ElDescriptionsItem>
<ElDescriptionsItem label="套餐使用记录ID">
{{ data.package_usage_id }}
</ElDescriptionsItem>
<ElDescriptionsItem label="总使用流量" :span="2">
{{ formatDataSize(data.total_usage_mb) }}
</ElDescriptionsItem>

View File

@@ -171,20 +171,25 @@ export function useAssetInfo() {
const loadCurrentPackage = async (identifier: string) => {
try {
currentPackageLoading.value = true
// 清空之前的错误信息
currentPackageErrorMsg.value = ''
const response = await AssetService.getCurrentPackage(identifier)
if (response.code === 0) {
if (response.data) {
const pkg = response.data
const [currentPkgResponse, packageListResponse] = await Promise.all([
AssetService.getCurrentPackage(identifier),
AssetService.getAssetPackages(identifier, { page: 1, page_size: 50 })
])
const activePackage = packageListResponse.data?.items?.find((p: any) => p.status === 1)
const activePaidAmount = activePackage?.paid_amount || 0
if (currentPkgResponse.code === 0) {
if (currentPkgResponse.data) {
const pkg = currentPkgResponse.data
// 转换为组件期望的格式
currentPackage.value = {
id: pkg.package_usage_id || 0,
package_id: pkg.package_id || 0,
package_name: pkg.package_name || '',
package_price: 0, // API 没有返回价格
package_price: activePaidAmount,
package_total_data: pkg.data_limit_mb || 0,
real_data_used: pkg.data_usage_mb || 0,
real_data_remaining: (pkg.data_limit_mb || 0) - (pkg.data_usage_mb || 0),
@@ -196,10 +201,10 @@ export function useAssetInfo() {
expire_time: pkg.expires_at || '',
status: pkg.status || 0,
status_name: pkg.status_name,
duration_days: undefined, // API 没有返回时长
virtual_ratio: pkg.virtual_ratio, // 虚流量比例
package_type: pkg.package_type, // 套餐类型
enable_virtual_data: pkg.enable_virtual_data, // 是否启用虚流量
duration_days: undefined,
virtual_ratio: pkg.virtual_ratio,
package_type: pkg.package_type,
enable_virtual_data: pkg.enable_virtual_data,
data_limit_mb: pkg.data_limit_mb,
virtual_limit_mb: pkg.virtual_limit_mb,
virtual_remain_mb: pkg.virtual_remain_mb,

View File

@@ -338,34 +338,47 @@
label-width="80"
>
<ElRow :gutter="20">
<ElCol :span="10">
<ElFormItem label="IoT卡" prop="iot_card_id">
<ElCol :span="6">
<ElFormItem label="搜索类型" prop="search_type">
<ElSelect v-model="bindCardForm.search_type" placeholder="请选择搜索类型" style="width: 100%">
<ElOption label="ICCID" value="iccid" />
<ElOption label="运营商名称" value="carrier_name" />
</ElSelect>
</ElFormItem>
</ElCol>
<ElCol :span="8">
<ElFormItem label="ICCID" prop="iot_card_id">
<ElSelect
v-model="bindCardForm.iot_card_id"
:placeholder="
iotCardList.length === 0 && !iotCardSearchLoading
? '当前没有未绑定设备的卡'
: '请选择或搜索IoT卡支持ICCID搜索)'
bindCardForm.search_type === 'carrier_name'
? '请选择或搜索运营商名称'
: '请选择或搜索ICCID'
"
filterable
remote
reserve-keyword
:remote-method="searchIotCards"
:loading="iotCardSearchLoading"
:disabled="iotCardList.length === 0 && !iotCardSearchLoading"
clearable
style="width: 100%"
>
<ElOption
v-for="card in iotCardList"
:key="card.id"
:label="`${card.iccid} ${card.msisdn ? '(' + card.msisdn + ')' : ''}`"
:label="`${card.iccid} ${card.carrier_name ? '(' + card.carrier_name + ')' : ''}`"
:value="card.id"
/>
<ElOption
v-if="iotCardList.length === 0 && !iotCardSearchLoading"
label="未找到相关数据"
:value="undefined"
disabled
/>
</ElSelect>
</ElFormItem>
</ElCol>
<ElCol :span="10">
<ElCol :span="6">
<ElFormItem label="插槽位置" prop="slot_position">
<ElSelect
v-model="bindCardForm.slot_position"
@@ -561,7 +574,8 @@
ShopService,
CardService,
PackageSeriesService,
AssetService
AssetService,
CarrierService
} from '@/api/modules'
import { ElMessage, ElMessageBox, ElTag, ElIcon, ElRadioGroup, ElRadio } from 'element-plus'
import { Loading } from '@element-plus/icons-vue'
@@ -656,11 +670,13 @@
const iotCardSearchLoading = ref(false)
const iotCardHasSearched = ref(false) // 标记是否已执行过搜索
const bindCardForm = reactive({
search_type: 'iccid' as 'iccid' | 'carrier_name',
iot_card_id: undefined as number | undefined,
slot_position: 1
})
const bindCardRules = reactive<FormRules>({
iot_card_id: [{ required: true, message: '请选择IoT卡', trigger: 'change' }],
search_type: [{ required: true, message: '请选择搜索类型', trigger: 'change' }],
iot_card_id: [{ required: true, message: '请选择ICCID', trigger: 'change' }],
slot_position: [{ required: true, message: '请选择插槽位置', trigger: 'change' }]
})
@@ -855,10 +871,14 @@
deviceCards.value = []
deviceCardsDialogVisible.value = true
// 重置绑定卡表单
bindCardForm.search_type = 'iccid'
bindCardForm.iot_card_id = undefined
bindCardForm.slot_position = 1
// 加载设备卡列表
await loadDeviceCards(device.virtual_no)
// 加载未绑定设备卡列表
await Promise.all([
loadDeviceCards(device.virtual_no),
loadDefaultIotCards()
])
}
// 加载设备绑定的卡列表
@@ -897,7 +917,7 @@
}
}
// 搜索IoT卡根据ICCID
// 搜索IoT卡根据ICCID或运营商名称
const searchIotCards = async (query: string) => {
if (!query) {
await loadDefaultIotCards()
@@ -906,12 +926,17 @@
iotCardSearchLoading.value = true
iotCardHasSearched.value = true
try {
const res = await CardService.getStandaloneIotCards({
const params: any = {
page: 1,
page_size: 20,
iccid: query,
is_standalone: true
})
}
if (bindCardForm.search_type === 'iccid') {
params.iccid = query
} else if (bindCardForm.search_type === 'carrier_name') {
params.carrier_name = query
}
const res = await CardService.getStandaloneIotCards(params)
if (res.code === 0 && res.data?.items) {
iotCardList.value = res.data.items
}

View File

@@ -562,7 +562,7 @@
import { h } from 'vue'
import { useRouter } from 'vue-router'
import { RoutesAlias } from '@/router/routesAlias'
import { CardService, ShopService, PackageSeriesService, AssetService } from '@/api/modules'
import { CardService, ShopService, PackageSeriesService, AssetService, CarrierService } from '@/api/modules'
import { ElMessage, ElTag, ElIcon, ElMessageBox } from 'element-plus'
import { Loading } from '@element-plus/icons-vue'
import RealnamePolicyDialog from '@/components/device/RealnamePolicyDialog.vue'
@@ -627,6 +627,38 @@
failed_items: null
})
// 运营商搜索相关
const carrierLoading = ref(false)
const searchCarrierOptions = ref<any[]>([])
// 加载搜索栏运营商选项默认加载10条
const loadSearchCarrierOptions = async (carrierName?: string) => {
try {
const params: any = {
page: 1,
page_size: 10
}
if (carrierName) {
params.carrier_name = carrierName
}
const res = await CarrierService.getCarriers(params)
if (res.code === 0) {
searchCarrierOptions.value = res.data.items
}
} catch (error) {
console.error('加载运营商选项失败:', error)
}
}
// 搜索运营商(用于搜索栏)
const handleSearchCarrier = (query: string) => {
if (query) {
loadSearchCarrierOptions(query)
} else {
loadSearchCarrierOptions()
}
}
// 卡详情弹窗相关
const cardDetailDialogVisible = ref(false)
const cardDetailLoading = ref(false)
@@ -730,8 +762,8 @@
// 搜索表单初始值
const initialSearchState: {
status: undefined | number
carrier_id: undefined | number
iccid: string
carrier_name: string
msisdn: string
virtual_no: string
device_virtual_no: string
@@ -740,8 +772,8 @@
[key: string]: any
} = {
status: undefined,
carrier_id: undefined,
iccid: '',
carrier_name: '',
msisdn: '',
virtual_no: '',
device_virtual_no: '',
@@ -863,20 +895,6 @@
{ label: '已停用', value: 4 }
]
},
{
label: '运营商',
prop: 'carrier_id',
type: 'select',
config: {
clearable: true,
placeholder: '全部'
},
options: () => [
{ label: '中国移动', value: 1 },
{ label: '中国联通', value: 2 },
{ label: '中国电信', value: 3 }
]
},
{
label: 'ICCID',
prop: 'iccid',
@@ -886,6 +904,24 @@
placeholder: '请输入ICCID'
}
},
{
label: '运营商名称',
prop: 'carrier_name',
type: 'select',
config: {
clearable: true,
filterable: true,
remote: true,
remoteMethod: handleSearchCarrier,
loading: carrierLoading.value,
placeholder: '请选择或搜索运营商名称'
},
options: () =>
searchCarrierOptions.value.map((c) => ({
label: c.carrier_name,
value: c.carrier_name
}))
},
{
label: '卡接入号',
prop: 'msisdn',
@@ -1180,20 +1216,22 @@
const getActions = (row: StandaloneIotCard) => {
const actions: any[] = []
if (hasAuth('iot_card:start_card')) {
actions.push({
label: '启用此卡',
handler: () => handleCardOperation('start-card', row.iccid),
type: 'primary'
})
}
if (hasAuth('iot_card:stop_card')) {
actions.push({
label: '停用此卡',
handler: () => handleCardOperation('stop-card', row.iccid),
type: 'primary'
})
if (row.network_status === 1) {
if (hasAuth('iot_card:stop_card')) {
actions.push({
label: '停用此卡',
handler: () => handleCardOperation('stop-card', row.iccid),
type: 'primary'
})
}
} else {
if (hasAuth('iot_card:start_card')) {
actions.push({
label: '启用此卡',
handler: () => handleCardOperation('start-card', row.iccid),
type: 'primary'
})
}
}
if (hasAuth('iot_card:realname_policy')) {
@@ -1216,6 +1254,7 @@
}
onMounted(() => {
loadSearchCarrierOptions()
getTableData()
})
@@ -1228,7 +1267,6 @@
page_size: pagination.pageSize,
...formFilters
}
// 清理空值
Object.keys(params).forEach((key) => {
if (params[key] === '' || params[key] === undefined) {
delete params[key]

View File

@@ -61,7 +61,7 @@
<p>2. 仅支持 Excel 格式.xlsx单次最多导入 1000 </p>
<p>3. 列格式请设置为文本格式避免长数字被转为科学计数法</p>
<p>4. <strong>重要列顺序固定不可调整</strong>系统按位置读取不识别列名</p>
<p>5. 必填列虚拟号第1列</p>
<p style="color: var(--el-color-primary)">5. 必填列虚拟号第1列</p>
<p
>6.
可选列设备名称设备型号设备类型IMEI制造商最大SIM槽数默认4有效范围1-4卡1~卡4
@@ -443,77 +443,16 @@
// 下载模板
const downloadTemplate = async () => {
try {
// 动态导入 xlsx 库
const XLSX = await import('xlsx')
// 创建示例数据(按固定列顺序)
const templateData = [
{
虚拟号: '862639070731999',
设备名称: '智能水表01',
设备型号: 'WM-2000',
设备类型: '智能水表',
IMEI: '860123456789012',
制造商: '华为',
最大SIM槽数: 4,
'卡1 ICCID': '89860123456789012345',
'卡2 ICCID': '',
'卡3 ICCID': '',
'卡4 ICCID': ''
},
{
虚拟号: '862639070750932',
设备名称: 'GPS定位器01',
设备型号: 'GPS-3000',
设备类型: '定位设备',
IMEI: '860123456789013',
制造商: '小米',
最大SIM槽数: 2,
'卡1 ICCID': '89860123456789012346',
'卡2 ICCID': '89860123456789012347',
'卡3 ICCID': '',
'卡4 ICCID': ''
}
]
// 创建工作簿
const wb = XLSX.utils.book_new()
const ws = XLSX.utils.json_to_sheet(templateData)
// 设置列宽
ws['!cols'] = [
{ wch: 20 }, // 虚拟号
{ wch: 15 }, // 设备名称
{ wch: 15 }, // 设备型号
{ wch: 15 }, // 设备类型
{ wch: 18 }, // IMEI
{ wch: 12 }, // 制造商
{ wch: 15 }, // 最大SIM槽数
{ wch: 25 }, // 卡1 ICCID
{ wch: 25 }, // 卡2 ICCID
{ wch: 25 }, // 卡3 ICCID
{ wch: 25 } // 卡4 ICCID
]
// 将所有单元格设置为文本格式
const range = XLSX.utils.decode_range(ws['!ref'] || 'A1')
for (let R = range.s.r; R <= range.e.r; ++R) {
for (let C = range.s.c; C <= range.e.c; ++C) {
const cellAddress = XLSX.utils.encode_cell({ r: R, c: C })
if (!ws[cellAddress]) continue
ws[cellAddress].t = 's' // 设置为字符串类型
}
}
// 添加工作表到工作簿
XLSX.utils.book_append_sheet(wb, ws, '设备导入模板')
// 导出文件
XLSX.writeFile(wb, '设备导入模板.xlsx')
const link = document.createElement('a')
link.href = new URL('@/template/设备导入模板.xlsx', import.meta.url).href
link.download = '设备导入模板.xlsx'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
ElMessage.success('设备导入模板下载成功')
} catch (error) {
console.error('下载模板失败:', error)
ElMessage.error('下载模板失败')
}
}

View File

@@ -105,10 +105,8 @@
<p>1. 请先下载 Excel 模板文件按照模板格式填写IoT卡信息</p>
<p>2. 仅支持 Excel 格式.xlsx单次最多导入 1000 </p>
<p>3. 列格式请设置为文本格式避免长数字被转为科学计数法</p>
<p>4. <strong>必填字段ICCIDMSISDN手机号virtual_no虚拟号</strong></p>
<p>5. <strong>Excel 文件必须包含 virtual_no 否则整批导入将失败</strong></p>
<p>6. virtual_no 为空将导入失败</p>
<p>7. 必须选择运营商</p>
<p>4. <span style="color: var(--el-color-primary)">必填字段ICCIDMSISDN</span></p>
<p>5. 必须选择运营商</p>
</div>
</template>
</ElAlert>
@@ -642,58 +640,16 @@
// 下载模板
const downloadTemplate = async () => {
try {
// 动态导入 xlsx 库
const XLSX = await import('xlsx')
// 创建示例数据按固定列顺序ICCID、MSISDN、虚拟号
const templateData = [
{
ICCID: '89860123456789012345',
'MSISDN接入号': '13800138000',
虚拟号: 'V001'
},
{
ICCID: '89860123456789012346',
'MSISDN接入号': '13800138001',
虚拟号: 'V002'
},
{
ICCID: '89860123456789012347',
'MSISDN接入号': '13800138002',
虚拟号: 'V003'
}
]
// 创建工作簿
const wb = XLSX.utils.book_new()
const ws = XLSX.utils.json_to_sheet(templateData)
// 设置列宽
ws['!cols'] = [
{ wch: 25 }, // ICCID
{ wch: 20 }, // MSISDN接入号
{ wch: 15 } // 虚拟号
]
// 将所有单元格设置为文本格式,防止科学计数法
const range = XLSX.utils.decode_range(ws['!ref'] || 'A1')
for (let R = range.s.r; R <= range.e.r; ++R) {
for (let C = range.s.c; C <= range.e.c; ++C) {
const cellAddress = XLSX.utils.encode_cell({ r: R, c: C })
if (!ws[cellAddress]) continue
ws[cellAddress].t = 's' // 设置为字符串类型
}
}
// 添加工作表到工作簿
XLSX.utils.book_append_sheet(wb, ws, 'IoT卡导入模板')
// 导出文件
XLSX.writeFile(wb, 'IoT卡导入模板.xlsx')
const link = document.createElement('a')
link.href = new URL('@/template/IoT卡导入模板.xlsx', import.meta.url).href
link.download = 'IoT卡导入模板.xlsx'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
ElMessage.success('IoT卡导入模板下载成功')
} catch (error) {
console.error('下载模板失败:', error)
ElMessage.error('下载模板失败')
}
}

View File

@@ -582,7 +582,8 @@
try {
const params: any = {
page: 1,
page_size: 20
page_size: 20,
role_type: 1
}
if (keyword) {
params.role_name = keyword
@@ -607,23 +608,9 @@
}, 300)
}
// 计算属性:过滤后的可分配角色(根据账号类型过滤)
// 计算属性:过滤后的可分配角色
const filteredAvailableRoles = computed(() => {
let roles = allRoles.value
// 根据账号类型过滤角色
if (currentAccountType.value === 3) {
// 代理账号:只显示客户角色
roles = roles.filter((role) => role.role_type === 2)
} else if (currentAccountType.value === 2) {
// 平台用户:只显示平台角色
roles = roles.filter((role) => role.role_type === 1)
} else if (currentAccountType.value === 4) {
// 企业账号:只显示客户角色
roles = roles.filter((role) => role.role_type === 2)
}
return roles
return allRoles.value
})
// 计算属性:过滤后的已分配角色

View File

@@ -94,9 +94,7 @@
title: '订单信息',
fields: [
{ label: '充值单号', prop: 'recharge_no' },
{ label: '充值记录ID', prop: 'id' },
{ label: '店铺名称', prop: 'shop_name' },
{ label: '店铺ID', prop: 'shop_id' },
{
label: '充值金额',
formatter: (_, data) => formatCurrency(data.amount)
@@ -122,15 +120,6 @@
prop: 'payment_channel',
formatter: (value) => value || '-'
},
{
label: '支付配置ID',
prop: 'payment_config_id',
formatter: (value) => value || '-'
},
{
label: '代理钱包ID',
prop: 'agent_wallet_id'
},
{
label: '第三方支付流水号',
prop: 'payment_transaction_id',

View File

@@ -14,12 +14,6 @@
<ElTag :type="getStatusType(refund.status)">{{ getStatusText(refund.status) }}</ElTag>
</ElDescriptionsItem>
<ElDescriptionsItem label="订单ID">{{ refund.order_id }}</ElDescriptionsItem>
<ElDescriptionsItem label="店铺ID">{{ refund.shop_id }}</ElDescriptionsItem>
<ElDescriptionsItem label="套餐使用记录ID">
{{ refund.package_usage_id || '-' }}
</ElDescriptionsItem>
<ElDescriptionsItem label="申请退款金额">
{{ formatCurrency(refund.requested_refund_amount) }}
</ElDescriptionsItem>
@@ -42,34 +36,29 @@
</ElTag>
</ElDescriptionsItem>
<ElDescriptionsItem label="退款原因" :span="2">
<ElDescriptionsItem label="退款原因">
{{ refund.refund_reason || '-' }}
</ElDescriptionsItem>
<ElDescriptionsItem label="拒绝原因" :span="2">
<ElDescriptionsItem label="拒绝原因">
{{ refund.reject_reason || '-' }}
</ElDescriptionsItem>
<ElDescriptionsItem label="审批备注" :span="2">
{{ refund.remark || '-' }}
<ElDescriptionsItem label="审批时间">
{{ refund.processed_at ? formatDateTime(refund.processed_at) : '-' }}
</ElDescriptionsItem>
<ElDescriptionsItem label="创建人ID">{{ refund.creator }}</ElDescriptionsItem>
<ElDescriptionsItem label="审批人ID">
{{ refund.processor_id || '-' }}
<ElDescriptionsItem label="审批备注">
{{ refund.remark || '-' }}
</ElDescriptionsItem>
<ElDescriptionsItem label="创建时间">
{{ formatDateTime(refund.created_at) }}
</ElDescriptionsItem>
<ElDescriptionsItem label="审批时间">
{{ refund.processed_at ? formatDateTime(refund.processed_at) : '-' }}
</ElDescriptionsItem>
<ElDescriptionsItem label="更新时间">
{{ formatDateTime(refund.updated_at) }}
</ElDescriptionsItem>
<ElDescriptionsItem label="更新人ID">{{ refund.updater }}</ElDescriptionsItem>
</ElDescriptions>
<div class="action-buttons" v-if="refund">

View File

@@ -63,11 +63,12 @@
placeholder="请输入订单号搜索"
style="width: 100%"
@focus="handleOrderSelectFocus"
@change="handleOrderSelectChange"
>
<ElOption
v-for="order in orderSearchOptions"
:key="order.id"
:label="`订单号: ${order.order_no} (ID: ${order.id})`"
:label="order.order_no"
:value="order.id"
/>
</ElSelect>
@@ -75,21 +76,18 @@
<ElFormItem label="申请退款金额" prop="requested_refund_amount">
<ElInputNumber
v-model="createForm.requested_refund_amount"
:min="1"
:min="0"
:precision="2"
:step="1"
style="width: 100%"
placeholder="请输入申请退款金额(元)"
/>
</ElFormItem>
<ElFormItem label="实收金额" prop="actual_received_amount">
<ElInputNumber
v-model="createForm.actual_received_amount"
:min="1"
:precision="2"
:step="1"
<ElFormItem label="实收金额">
<ElInput
:model-value="selectedOrderActualPaid"
disabled
style="width: 100%"
placeholder="请输入实收金额(元)"
/>
</ElFormItem>
<ElFormItem label="退款原因">
@@ -434,8 +432,7 @@
const createRules = reactive<FormRules>({
order_id: [{ required: true, message: '请输入订单ID', trigger: 'blur' }],
requested_refund_amount: [{ required: true, message: '请输入申请退款金额', trigger: 'blur' }],
actual_received_amount: [{ required: true, message: '请输入实收金额', trigger: 'blur' }]
requested_refund_amount: [{ required: true, message: '请输入申请退款金额', trigger: 'blur' }]
})
const approveRules = reactive<FormRules>({})
@@ -485,6 +482,15 @@
const refundList = ref<Refund[]>([])
// 选中的订单实收金额
const selectedOrderActualPaid = computed(() => {
if (!createForm.order_id) return 0
const selectedOrder = orderSearchOptions.value.find((o) => o.id === createForm.order_id)
if (!selectedOrder?.actual_paid_amount) return 0
const amount = selectedOrder.actual_paid_amount / 100
return isNaN(amount) ? 0 : amount
})
// 格式化货币 - 将分转换为元
const formatCurrency = (amount: number): string => {
return `¥${(amount / 100).toFixed(2)}`
@@ -684,6 +690,18 @@
}
}
// 订单选择变化 - 自动填充实收金额
const handleOrderSelectChange = (orderId: number | null) => {
if (!orderId) {
createForm.actual_received_amount = 0
return
}
const selectedOrder = orderSearchOptions.value.find((o) => o.id === orderId)
if (selectedOrder) {
createForm.actual_received_amount = selectedOrder.actual_paid_amount / 100
}
}
// 获取退款申请列表
const getTableData = async () => {
loading.value = true