修改订单管理
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m28s

This commit is contained in:
sexygoat
2026-02-28 16:49:28 +08:00
parent ce1032c7f9
commit 7b459b5c8d
6 changed files with 219 additions and 21 deletions

View File

@@ -4,7 +4,13 @@
<Transition name="context-menu" @before-enter="onBeforeEnter" @after-leave="onAfterLeave"> <Transition name="context-menu" @before-enter="onBeforeEnter" @after-leave="onAfterLeave">
<div v-show="visible" :style="menuStyle" class="context-menu"> <div v-show="visible" :style="menuStyle" class="context-menu">
<ul class="menu-list" :style="menuListStyle"> <ul class="menu-list" :style="menuListStyle">
<template v-for="item in menuItems" :key="item.key"> <!-- 无权限提示 -->
<li v-if="menuItems.length === 0" class="menu-item no-permission" :style="menuItemStyle">
<span class="menu-label">您暂无更多权限</span>
</li>
<!-- 菜单项 -->
<template v-else v-for="item in menuItems" :key="item.key">
<!-- 普通菜单项 --> <!-- 普通菜单项 -->
<li <li
v-if="!item.children" v-if="!item.children"
@@ -249,10 +255,23 @@
user-select: none; user-select: none;
transition: background-color 0.15s ease; transition: background-color 0.15s ease;
&:hover:not(.is-disabled) { &:hover:not(.is-disabled):not(.no-permission) {
background-color: rgba(var(--art-gray-200-rgb), 0.7); background-color: rgba(var(--art-gray-200-rgb), 0.7);
} }
&.no-permission {
justify-content: center;
color: var(--el-text-color-secondary);
cursor: default;
.menu-label {
color: var(--el-text-color-secondary);
text-align: center;
white-space: normal;
word-break: break-all;
}
}
&.has-line { &.has-line {
margin-bottom: 10px; margin-bottom: 10px;

View File

@@ -36,11 +36,18 @@
@refresh="handleRefresh" @refresh="handleRefresh"
> >
<template #left> <template #left>
<ElButton type="primary" @click="showAllocateDialog">授权卡</ElButton> <ElButton
type="primary"
@click="showAllocateDialog"
v-permission="'enterprise_cards:allocate'"
>
授权卡
</ElButton>
<ElButton <ElButton
type="warning" type="warning"
:disabled="selectedCards.length === 0" :disabled="selectedCards.length === 0"
@click="showRecallDialog" @click="showRecallDialog"
v-permission="'enterprise_cards:batch_recall'"
> >
批量回收 批量回收
</ElButton> </ElButton>
@@ -215,6 +222,7 @@
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
import type { SearchFormItem } from '@/types' import type { SearchFormItem } from '@/types'
import { useCheckedColumns } from '@/composables/useCheckedColumns' import { useCheckedColumns } from '@/composables/useCheckedColumns'
import { useAuth } from '@/composables/useAuth'
import { formatDateTime } from '@/utils/business/format' import { formatDateTime } from '@/utils/business/format'
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue' import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
import { BgColorEnum } from '@/enums/appEnum' import { BgColorEnum } from '@/enums/appEnum'
@@ -228,6 +236,8 @@
defineOptions({ name: 'EnterpriseCards' }) defineOptions({ name: 'EnterpriseCards' })
const { hasAuth } = useAuth()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const loading = ref(false) const loading = ref(false)
@@ -537,19 +547,33 @@
width: 100, width: 100,
fixed: 'right', fixed: 'right',
formatter: (row: EnterpriseCardItem) => { formatter: (row: EnterpriseCardItem) => {
return h('div', { style: 'display: flex; gap: 8px;' }, [ const buttons = []
row.network_status === 0
? h(ArtButtonTable, { if (row.network_status === 0) {
// 停机状态,显示复机按钮
if (hasAuth('enterprise_cards:resume')) {
buttons.push(
h(ArtButtonTable, {
text: '复机', text: '复机',
iconClass: BgColorEnum.SUCCESS, iconClass: BgColorEnum.SUCCESS,
onClick: () => handleResume(row) onClick: () => handleResume(row)
}) })
: h(ArtButtonTable, { )
}
} else {
// 开机状态,显示停机按钮
if (hasAuth('enterprise_cards:suspend')) {
buttons.push(
h(ArtButtonTable, {
text: '停机', text: '停机',
iconClass: BgColorEnum.ERROR, iconClass: BgColorEnum.ERROR,
onClick: () => handleSuspend(row) onClick: () => handleSuspend(row)
}) })
]) )
}
}
return h('div', { style: 'display: flex; gap: 8px;' }, buttons)
} }
} }
]) ])

View File

@@ -67,8 +67,14 @@
<p>1. 请先下载 Excel 模板文件按照模板格式填写设备信息</p> <p>1. 请先下载 Excel 模板文件按照模板格式填写设备信息</p>
<p>2. 仅支持 Excel 格式.xlsx单次最多导入 1000 </p> <p>2. 仅支持 Excel 格式.xlsx单次最多导入 1000 </p>
<p>3. 列格式请设置为文本格式避免长数字被转为科学计数法</p> <p>3. 列格式请设置为文本格式避免长数字被转为科学计数法</p>
<p>4. 必填列device_no设备号device_name设备名称device_model设备型号device_type设备类型</p> <p
<p>5. 可选列manufacturer制造商max_sim_slots最大插槽数默认4iccid_1 ~ iccid_4绑定的卡ICCID</p> >4.
必填列device_no设备号device_name设备名称device_model设备型号device_type设备类型</p
>
<p
>5. 可选列manufacturer制造商max_sim_slots最大插槽数默认4iccid_1 ~
iccid_4绑定的卡ICCID</p
>
</div> </div>
</template> </template>
</ElAlert> </ElAlert>
@@ -106,7 +112,6 @@
</ElButton> </ElButton>
</template> </template>
</ElDialog> </ElDialog>
</ArtTableFullScreen> </ArtTableFullScreen>
</template> </template>
@@ -353,7 +358,6 @@
} }
} catch (error) { } catch (error) {
console.error(error) console.error(error)
ElMessage.error('获取设备任务列表失败')
} finally { } finally {
loading.value = false loading.value = false
} }
@@ -437,7 +441,7 @@
{ wch: 22 }, // iccid_1 { wch: 22 }, // iccid_1
{ wch: 22 }, // iccid_2 { wch: 22 }, // iccid_2
{ wch: 22 }, // iccid_3 { wch: 22 }, // iccid_3
{ wch: 22 } // iccid_4 { wch: 22 } // iccid_4
] ]
// 将所有单元格设置为文本格式 // 将所有单元格设置为文本格式
@@ -520,7 +524,11 @@
const { upload_url, file_key } = uploadUrlRes.data const { upload_url, file_key } = uploadUrlRes.data
ElMessage.info('正在上传文件...') ElMessage.info('正在上传文件...')
await StorageService.uploadFile(upload_url, file, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') await StorageService.uploadFile(
upload_url,
file,
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
ElMessage.info('正在创建导入任务...') ElMessage.info('正在创建导入任务...')
const importRes = await DeviceService.importDevices({ const importRes = await DeviceService.importDevices({

View File

@@ -399,7 +399,6 @@
} }
} catch (error) { } catch (error) {
console.error(error) console.error(error)
ElMessage.error('获取IoT卡任务列表失败')
} finally { } finally {
loading.value = false loading.value = false
} }

View File

@@ -106,6 +106,17 @@
return statusMap[status] || '-' return statusMap[status] || '-'
} }
// 获取订单角色文本
const getPurchaseRoleText = (role: string): string => {
const roleMap: Record<string, string> = {
self_purchase: '自己购买',
purchased_by_parent: '上级代理购买',
purchased_by_platform: '平台代购',
purchase_for_subordinate: '给下级购买'
}
return roleMap[role] || role
}
// 详情页配置 // 详情页配置
const detailSections: DetailSection[] = [ const detailSections: DetailSection[] = [
{ {
@@ -125,6 +136,11 @@
prop: 'total_amount', prop: 'total_amount',
formatter: (value) => formatCurrency(value) formatter: (value) => formatCurrency(value)
}, },
{
label: '实付金额',
prop: 'actual_paid_amount',
formatter: (value) => (value !== undefined && value !== null ? formatCurrency(value) : '-')
},
{ {
label: 'IoT卡ID', label: 'IoT卡ID',
prop: 'iot_card_id', prop: 'iot_card_id',
@@ -132,7 +148,7 @@
}, },
{ {
label: t('orderManagement.table.buyerType'), label: t('orderManagement.table.buyerType'),
formatter: (_, data) => data.buyer_type ? getBuyerTypeText(data.buyer_type) : '-' formatter: (_, data) => (data.buyer_type ? getBuyerTypeText(data.buyer_type) : '-')
}, },
{ {
label: '买家ID', label: '买家ID',
@@ -140,8 +156,32 @@
formatter: (value) => value || '-' formatter: (value) => value || '-'
}, },
{ {
label: '代付订单', label: '订单角色',
formatter: (_, data) => data.is_purchase_on_behalf ? '是' : '否' formatter: (_, data) => (data.purchase_role ? getPurchaseRoleText(data.purchase_role) : '-')
},
{
label: '购买备注',
prop: 'purchase_remark',
formatter: (value) => value || '-'
},
{
label: '是否上级代购',
formatter: (_, data) => (data.is_purchased_by_parent ? '是' : '否')
},
{
label: '操作者ID',
prop: 'operator_id',
formatter: (value) => value || '-'
},
{
label: '操作者类型',
prop: 'operator_type',
formatter: (value) => value || '-'
},
{
label: '操作者名称',
prop: 'operator_name',
formatter: (value) => value || '-'
}, },
{ {
label: t('orderManagement.table.commissionStatus'), label: t('orderManagement.table.commissionStatus'),

View File

@@ -164,6 +164,24 @@
</ElOption> </ElOption>
</ElSelect> </ElSelect>
</ElFormItem> </ElFormItem>
<ElFormItem label="支付方式" prop="payment_method">
<ElSelect
v-model="createForm.payment_method"
placeholder="请选择支付方式"
style="width: 100%"
>
<ElOption label="钱包支付" value="wallet" />
<ElOption label="线下支付" value="offline" />
</ElSelect>
<div style="margin-top: 8px; font-size: 12px; color: var(--el-text-color-secondary)">
<template v-if="createForm.payment_method === 'wallet'">
提示: 使用钱包支付时,订单将直接完成
</template>
<template v-else-if="createForm.payment_method === 'offline'">
提示: 线下支付订单需要手动确认支付
</template>
</div>
</ElFormItem>
</ElForm> </ElForm>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
@@ -319,6 +337,7 @@
order_no: '', order_no: '',
payment_status: undefined, payment_status: undefined,
order_type: undefined, order_type: undefined,
purchase_role: undefined,
start_time: '', start_time: '',
end_time: '' end_time: ''
} }
@@ -326,6 +345,17 @@
// 搜索表单 // 搜索表单
const searchForm = reactive<OrderQueryParams>({ ...initialSearchState }) const searchForm = reactive<OrderQueryParams>({ ...initialSearchState })
// 获取订单角色文本
const getPurchaseRoleText = (role: string): string => {
const roleMap: Record<string, string> = {
self_purchase: '自己购买',
purchased_by_parent: '上级代理购买',
purchased_by_platform: '平台代购',
purchase_for_subordinate: '给下级购买'
}
return roleMap[role] || role
}
// 搜索表单配置 // 搜索表单配置
const searchFormItems: SearchFormItem[] = [ const searchFormItems: SearchFormItem[] = [
{ {
@@ -365,6 +395,21 @@
clearable: true clearable: true
} }
}, },
{
label: '订单角色',
prop: 'purchase_role',
type: 'select',
placeholder: '请选择订单角色',
options: [
{ label: '自己购买', value: 'self_purchase' },
{ label: '上级代理购买', value: 'purchased_by_parent' },
{ label: '平台代购', value: 'purchased_by_platform' },
{ label: '给下级购买', value: 'purchase_for_subordinate' }
],
config: {
clearable: true
}
},
{ {
label: t('orderManagement.searchForm.dateRange'), label: t('orderManagement.searchForm.dateRange'),
prop: 'dateRange', prop: 'dateRange',
@@ -391,8 +436,12 @@
{ label: t('orderManagement.table.orderNo'), prop: 'order_no' }, { label: t('orderManagement.table.orderNo'), prop: 'order_no' },
{ label: t('orderManagement.table.orderType'), prop: 'order_type' }, { label: t('orderManagement.table.orderType'), prop: 'order_type' },
{ label: t('orderManagement.table.buyerType'), prop: 'buyer_type' }, { label: t('orderManagement.table.buyerType'), prop: 'buyer_type' },
{ label: '订单角色', prop: 'purchase_role' },
{ label: '购买备注', prop: 'purchase_remark' },
{ label: '操作者', prop: 'operator_name' },
{ label: t('orderManagement.table.paymentStatus'), prop: 'payment_status' }, { label: t('orderManagement.table.paymentStatus'), prop: 'payment_status' },
{ label: t('orderManagement.table.totalAmount'), prop: 'total_amount' }, { label: t('orderManagement.table.totalAmount'), prop: 'total_amount' },
{ label: '实付金额', prop: 'actual_paid_amount' },
{ label: t('orderManagement.table.paymentMethod'), prop: 'payment_method' }, { label: t('orderManagement.table.paymentMethod'), prop: 'payment_method' },
{ label: t('orderManagement.table.paidAt'), prop: 'paid_at' }, { label: t('orderManagement.table.paidAt'), prop: 'paid_at' },
{ label: t('orderManagement.table.createdAt'), prop: 'created_at' } { label: t('orderManagement.table.createdAt'), prop: 'created_at' }
@@ -414,6 +463,13 @@
message: t('orderManagement.validation.packageIdsRequired'), message: t('orderManagement.validation.packageIdsRequired'),
trigger: 'change' trigger: 'change'
} }
],
payment_method: [
{
required: true,
message: '请选择支付方式',
trigger: 'change'
}
] ]
}) })
@@ -421,7 +477,8 @@
order_type: 'single_card', order_type: 'single_card',
package_ids: [], package_ids: [],
iot_card_id: null, iot_card_id: null,
device_id: null device_id: null,
payment_method: 'wallet' // 默认使用钱包支付
}) })
const orderList = ref<Order[]>([]) const orderList = ref<Order[]>([])
@@ -604,6 +661,38 @@
) )
} }
}, },
{
prop: 'purchase_role',
label: '订单角色',
width: 140,
formatter: (row: Order) => {
if (!row.purchase_role) return '-'
const roleTypeMap: Record<string, 'success' | 'info' | 'warning' | 'danger'> = {
self_purchase: 'success',
purchased_by_parent: 'warning',
purchased_by_platform: 'danger',
purchase_for_subordinate: 'info'
}
return h(
ElTag,
{ type: roleTypeMap[row.purchase_role] || 'info', size: 'small' },
() => getPurchaseRoleText(row.purchase_role)
)
}
},
{
prop: 'purchase_remark',
label: '购买备注',
minWidth: 180,
showOverflowTooltip: true,
formatter: (row: Order) => row.purchase_remark || '-'
},
{
prop: 'operator_name',
label: '操作者',
width: 120,
formatter: (row: Order) => row.operator_name || '-'
},
{ {
prop: 'payment_status', prop: 'payment_status',
label: t('orderManagement.table.paymentStatus'), label: t('orderManagement.table.paymentStatus'),
@@ -622,6 +711,15 @@
width: 120, width: 120,
formatter: (row: Order) => formatCurrency(row.total_amount) formatter: (row: Order) => formatCurrency(row.total_amount)
}, },
{
prop: 'actual_paid_amount',
label: '实付金额',
width: 120,
formatter: (row: Order) => {
if (row.actual_paid_amount === undefined || row.actual_paid_amount === null) return '-'
return formatCurrency(row.actual_paid_amount)
}
},
{ {
prop: 'payment_method', prop: 'payment_method',
label: t('orderManagement.table.paymentMethod'), label: t('orderManagement.table.paymentMethod'),
@@ -692,6 +790,7 @@
order_no: searchForm.order_no || undefined, order_no: searchForm.order_no || undefined,
payment_status: searchForm.payment_status, payment_status: searchForm.payment_status,
order_type: searchForm.order_type, order_type: searchForm.order_type,
purchase_role: searchForm.purchase_role,
start_time: searchForm.start_time || undefined, start_time: searchForm.start_time || undefined,
end_time: searchForm.end_time || undefined end_time: searchForm.end_time || undefined
} }
@@ -821,6 +920,7 @@
createForm.package_ids = [] createForm.package_ids = []
createForm.iot_card_id = null createForm.iot_card_id = null
createForm.device_id = null createForm.device_id = null
createForm.payment_method = 'wallet'
// 清空套餐、IoT卡和设备搜索结果 // 清空套餐、IoT卡和设备搜索结果
packageOptions.value = [] packageOptions.value = []
@@ -840,11 +940,19 @@
order_type: createForm.order_type, order_type: createForm.order_type,
package_ids: createForm.package_ids, package_ids: createForm.package_ids,
iot_card_id: createForm.order_type === 'single_card' ? createForm.iot_card_id : null, iot_card_id: createForm.order_type === 'single_card' ? createForm.iot_card_id : null,
device_id: createForm.order_type === 'device' ? createForm.device_id : null device_id: createForm.order_type === 'device' ? createForm.device_id : null,
payment_method: createForm.payment_method // 必填字段
} }
await OrderService.createOrder(data) await OrderService.createOrder(data)
ElMessage.success(t('orderManagement.messages.createSuccess'))
// 根据支付方式显示不同的成功消息
if (createForm.payment_method === 'wallet') {
ElMessage.success('订单创建成功,已自动完成支付')
} else {
ElMessage.success(t('orderManagement.messages.createSuccess'))
}
createDialogVisible.value = false createDialogVisible.value = false
formEl.resetFields() formEl.resetFields()
await getTableData() await getTableData()