Files
one-pipe-system/src/views/order-management/order-list/index.vue
sexygoat ce1032c7f9
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m29s
完善按钮和详情权限
2026-02-28 11:04:32 +08:00

953 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<ArtTableFullScreen>
<div class="order-list-page" id="table-full-screen">
<!-- 搜索栏 -->
<ArtSearchBar
v-model:filter="searchForm"
:items="searchFormItems"
:show-expand="false"
@reset="handleReset"
@search="handleSearch"
></ArtSearchBar>
<ElCard shadow="never" class="art-table-card">
<!-- 表格头部 -->
<ArtTableHeader
:columnList="columnOptions"
v-model:columns="columnChecks"
@refresh="handleRefresh"
>
<template #left>
<ElButton @click="showCreateDialog" v-permission="'orders:add'">{{
t('orderManagement.createOrder')
}}</ElButton>
</template>
</ArtTableHeader>
<!-- 表格 -->
<ArtTable
ref="tableRef"
row-key="id"
:loading="loading"
:data="orderList"
:currentPage="pagination.page"
:pageSize="pagination.page_size"
:total="pagination.total"
:marginTop="10"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
@row-contextmenu="handleRowContextMenu"
>
<template #default>
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
</template>
</ArtTable>
<!-- 右键菜单 -->
<ArtMenuRight
ref="contextMenuRef"
:menu-items="contextMenuItems"
:menu-width="120"
@select="handleContextMenuSelect"
/>
<!-- 创建订单对话框 -->
<ElDialog
v-model="createDialogVisible"
:title="t('orderManagement.createOrder')"
width="600px"
@closed="handleCreateDialogClosed"
>
<ElForm ref="createFormRef" :model="createForm" :rules="createRules" label-width="120px">
<ElFormItem :label="t('orderManagement.table.orderType')" prop="order_type">
<ElSelect
v-model="createForm.order_type"
:placeholder="t('orderManagement.searchForm.orderTypePlaceholder')"
style="width: 100%"
>
<ElOption :label="t('orderManagement.orderType.singleCard')" value="single_card" />
<ElOption :label="t('orderManagement.orderType.device')" value="device" />
</ElSelect>
</ElFormItem>
<ElFormItem
v-if="createForm.order_type === 'single_card'"
:label="t('orderManagement.createForm.iotCardId')"
prop="iot_card_id"
>
<ElSelect
v-model="createForm.iot_card_id"
filterable
remote
reserve-keyword
:placeholder="t('orderManagement.createForm.iotCardIdPlaceholder')"
:remote-method="searchIotCards"
:loading="cardSearchLoading"
style="width: 100%"
clearable
>
<ElOption
v-for="card in iotCardOptions"
:key="card.id"
:label="`${card.iccid} (${card.msisdn || '无接入号'})`"
:value="card.id"
>
<div style="display: flex; justify-content: space-between">
<span>{{ card.iccid }}</span>
<span style="color: var(--el-text-color-secondary); font-size: 12px">
{{ card.msisdn || '无接入号' }}
</span>
</div>
</ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem
v-if="createForm.order_type === 'device'"
:label="t('orderManagement.createForm.deviceId')"
prop="device_id"
>
<ElSelect
v-model="createForm.device_id"
filterable
remote
reserve-keyword
:placeholder="t('orderManagement.createForm.deviceIdPlaceholder')"
:remote-method="searchDevices"
:loading="deviceSearchLoading"
style="width: 100%"
clearable
>
<ElOption
v-for="device in deviceOptions"
:key="device.id"
:label="`${device.device_no} (${device.device_name})`"
:value="device.id"
>
<div style="display: flex; justify-content: space-between">
<span>{{ device.device_no }}</span>
<span style="color: var(--el-text-color-secondary); font-size: 12px">
{{ device.device_name }}
</span>
</div>
</ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem :label="t('orderManagement.createForm.packageIds')" prop="package_ids">
<ElSelect
v-model="createForm.package_ids"
:placeholder="t('orderManagement.createForm.packageIdsPlaceholder')"
multiple
filterable
remote
reserve-keyword
:remote-method="handlePackageSearch"
:loading="packageSearchLoading"
:disabled="
(!createForm.iot_card_id && !createForm.device_id) ||
(createForm.order_type === 'single_card' && !createForm.iot_card_id) ||
(createForm.order_type === 'device' && !createForm.device_id)
"
clearable
style="width: 100%"
>
<ElOption
v-for="pkg in packageOptions"
:key="pkg.id"
:label="`${pkg.package_name} (¥${(pkg.cost_price / 100).toFixed(2)})`"
:value="pkg.id"
>
<div style="display: flex; justify-content: space-between">
<span>{{ pkg.package_name }}</span>
<span style="color: var(--el-text-color-secondary); font-size: 12px">
¥{{ (pkg.cost_price / 100).toFixed(2) }}
</span>
</div>
</ElOption>
</ElSelect>
</ElFormItem>
</ElForm>
<template #footer>
<div class="dialog-footer">
<ElButton @click="createDialogVisible = false">{{
t('orderManagement.actions.cancel')
}}</ElButton>
<ElButton
type="primary"
@click="handleCreateOrder(createFormRef)"
:loading="createLoading"
>
{{ t('orderManagement.actions.submit') }}
</ElButton>
</div>
</template>
</ElDialog>
<!-- 订单详情对话框 -->
<ElDialog
v-model="detailDialogVisible"
:title="t('orderManagement.orderDetail')"
width="800px"
>
<div v-if="currentOrder" class="order-detail">
<ElDescriptions :column="2" border>
<ElDescriptionsItem :label="t('orderManagement.table.orderNo')">
{{ currentOrder.order_no }}
</ElDescriptionsItem>
<ElDescriptionsItem :label="t('orderManagement.table.orderType')">
{{ getOrderTypeText(currentOrder.order_type) }}
</ElDescriptionsItem>
<ElDescriptionsItem :label="t('orderManagement.table.paymentStatus')">
<ElTag :type="getPaymentStatusType(currentOrder.payment_status)">
{{ currentOrder.payment_status_text }}
</ElTag>
</ElDescriptionsItem>
<ElDescriptionsItem :label="t('orderManagement.table.totalAmount')">
{{ formatCurrency(currentOrder.total_amount) }}
</ElDescriptionsItem>
<ElDescriptionsItem :label="t('orderManagement.table.paymentMethod')">
{{ getPaymentMethodText(currentOrder.payment_method) }}
</ElDescriptionsItem>
<ElDescriptionsItem :label="t('orderManagement.table.buyerType')">
{{ getBuyerTypeText(currentOrder.buyer_type) }}
</ElDescriptionsItem>
<ElDescriptionsItem :label="t('orderManagement.table.commissionStatus')">
{{ getCommissionStatusText(currentOrder.commission_status) }}
</ElDescriptionsItem>
<ElDescriptionsItem :label="t('orderManagement.table.paidAt')">
{{ currentOrder.paid_at ? formatDateTime(currentOrder.paid_at) : '-' }}
</ElDescriptionsItem>
<ElDescriptionsItem :label="t('orderManagement.table.createdAt')">
{{ formatDateTime(currentOrder.created_at) }}
</ElDescriptionsItem>
<ElDescriptionsItem :label="t('orderManagement.table.updatedAt')">
{{ formatDateTime(currentOrder.updated_at) }}
</ElDescriptionsItem>
</ElDescriptions>
<!-- 订单项列表 -->
<div
v-if="currentOrder.items && currentOrder.items.length > 0"
style="margin-top: 20px"
>
<h4>{{ t('orderManagement.orderItems') }}</h4>
<ElTable :data="currentOrder.items" border style="margin-top: 10px">
<ElTableColumn
prop="package_name"
:label="t('orderManagement.items.packageName')"
min-width="150"
/>
<ElTableColumn
prop="quantity"
:label="t('orderManagement.items.quantity')"
width="100"
/>
<ElTableColumn
prop="unit_price"
:label="t('orderManagement.items.unitPrice')"
width="120"
>
<template #default="{ row }">
{{ formatCurrency(row.unit_price) }}
</template>
</ElTableColumn>
<ElTableColumn prop="amount" :label="t('orderManagement.items.amount')" width="120">
<template #default="{ row }">
{{ formatCurrency(row.amount) }}
</template>
</ElTableColumn>
</ElTable>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<ElButton @click="detailDialogVisible = false">{{
t('orderManagement.actions.close')
}}</ElButton>
</div>
</template>
</ElDialog>
</ElCard>
</div>
</ArtTableFullScreen>
</template>
<script setup lang="ts">
import { h } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import { OrderService, CardService, DeviceService, PackageManageService } from '@/api/modules'
import { ElMessage, ElMessageBox, ElTag } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import type {
Order,
OrderQueryParams,
CreateOrderRequest,
PaymentStatus,
OrderType,
BuyerType,
OrderPaymentMethod,
OrderCommissionStatus,
StandaloneIotCard,
Device,
PackageResponse
} from '@/types/api'
import type { SearchFormItem } from '@/types'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import { useAuth } from '@/composables/useAuth'
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
import { formatDateTime } from '@/utils/business/format'
import { RoutesAlias } from '@/router/routesAlias'
defineOptions({ name: 'OrderList' })
const { t } = useI18n()
const router = useRouter()
const { hasAuth } = useAuth()
const loading = ref(false)
const createLoading = ref(false)
const tableRef = ref()
const createDialogVisible = ref(false)
const detailDialogVisible = ref(false)
const currentOrder = ref<Order | null>(null)
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
const currentRow = ref<Order | null>(null)
// 搜索表单初始值
const initialSearchState: OrderQueryParams = {
order_no: '',
payment_status: undefined,
order_type: undefined,
start_time: '',
end_time: ''
}
// 搜索表单
const searchForm = reactive<OrderQueryParams>({ ...initialSearchState })
// 搜索表单配置
const searchFormItems: SearchFormItem[] = [
{
label: t('orderManagement.searchForm.orderNo'),
prop: 'order_no',
type: 'input',
placeholder: t('orderManagement.searchForm.orderNoPlaceholder'),
config: {
clearable: true
}
},
{
label: t('orderManagement.searchForm.paymentStatus'),
prop: 'payment_status',
type: 'select',
placeholder: t('orderManagement.searchForm.paymentStatusPlaceholder'),
options: [
{ label: t('orderManagement.paymentStatus.pending'), value: 1 },
{ label: t('orderManagement.paymentStatus.paid'), value: 2 },
{ label: t('orderManagement.paymentStatus.cancelled'), value: 3 },
{ label: t('orderManagement.paymentStatus.refunded'), value: 4 }
],
config: {
clearable: true
}
},
{
label: t('orderManagement.searchForm.orderType'),
prop: 'order_type',
type: 'select',
placeholder: t('orderManagement.searchForm.orderTypePlaceholder'),
options: [
{ label: t('orderManagement.orderType.singleCard'), value: 'single_card' },
{ label: t('orderManagement.orderType.device'), value: 'device' }
],
config: {
clearable: true
}
},
{
label: t('orderManagement.searchForm.dateRange'),
prop: 'dateRange',
type: 'daterange',
config: {
clearable: true,
startPlaceholder: t('orderManagement.searchForm.startDate'),
endPlaceholder: t('orderManagement.searchForm.endDate'),
valueFormat: 'YYYY-MM-DD HH:mm:ss'
}
}
]
// 分页
const pagination = reactive({
page: 1,
page_size: 20,
total: 0
})
// 列配置
const columnOptions = [
{ label: t('orderManagement.table.id'), prop: 'id' },
{ label: t('orderManagement.table.orderNo'), prop: 'order_no' },
{ label: t('orderManagement.table.orderType'), prop: 'order_type' },
{ label: t('orderManagement.table.buyerType'), prop: 'buyer_type' },
{ label: t('orderManagement.table.paymentStatus'), prop: 'payment_status' },
{ label: t('orderManagement.table.totalAmount'), prop: 'total_amount' },
{ label: t('orderManagement.table.paymentMethod'), prop: 'payment_method' },
{ label: t('orderManagement.table.paidAt'), prop: 'paid_at' },
{ label: t('orderManagement.table.createdAt'), prop: 'created_at' }
]
const createFormRef = ref<FormInstance>()
const createRules = reactive<FormRules>({
order_type: [
{
required: true,
message: t('orderManagement.validation.orderTypeRequired'),
trigger: 'change'
}
],
package_ids: [
{
required: true,
message: t('orderManagement.validation.packageIdsRequired'),
trigger: 'change'
}
]
})
const createForm = reactive<CreateOrderRequest>({
order_type: 'single_card',
package_ids: [],
iot_card_id: null,
device_id: null
})
const orderList = ref<Order[]>([])
// 套餐搜索相关
const packageOptions = ref<PackageResponse[]>([])
const packageSearchLoading = ref(false)
// IoT卡搜索相关
const iotCardOptions = ref<StandaloneIotCard[]>([])
const cardSearchLoading = ref(false)
// 设备搜索相关
const deviceOptions = ref<Device[]>([])
const deviceSearchLoading = ref(false)
// 搜索套餐根据套餐名称可选按series_id筛选
const searchPackages = async (query: string, seriesId?: number) => {
packageSearchLoading.value = true
try {
const res = await PackageManageService.getPackages({
package_name: query || undefined,
series_id: seriesId,
page: 1,
page_size: 20,
status: 1, // 只获取启用的套餐
shelf_status: 1 // 只获取已上架的套餐
})
if (res.code === 0) {
packageOptions.value = res.data.items || []
}
} catch (error) {
console.error('Search packages failed:', error)
packageOptions.value = []
} finally {
packageSearchLoading.value = false
}
}
// 套餐远程搜索方法自动使用当前选中的IOT卡/设备的series_id
const handlePackageSearch = (query: string) => {
let seriesId: number | undefined
// 如果是单卡订单并且已选择IOT卡使用该卡的series_id筛选
if (createForm.order_type === 'single_card' && createForm.iot_card_id) {
const selectedCard = iotCardOptions.value.find((card) => card.id === createForm.iot_card_id)
if (selectedCard && selectedCard.series_id) {
seriesId = selectedCard.series_id
}
} else if (createForm.order_type === 'device' && createForm.device_id) {
// 如果是设备订单并且已选择设备使用设备的series_id筛选
const selectedDevice = deviceOptions.value.find((dev) => dev.id === createForm.device_id)
if (selectedDevice && selectedDevice.series_id) {
seriesId = selectedDevice.series_id
}
}
searchPackages(query, seriesId)
}
// 搜索IoT卡根据ICCID
const searchIotCards = async (query: string) => {
cardSearchLoading.value = true
try {
const res = await CardService.getStandaloneIotCards({
iccid: query || undefined,
page: 1,
page_size: 20
})
if (res.code === 0) {
iotCardOptions.value = res.data.items || []
}
} catch (error) {
console.error('Search IoT cards failed:', error)
iotCardOptions.value = []
} finally {
cardSearchLoading.value = false
}
}
// 搜索设备根据设备号device_no
const searchDevices = async (query: string) => {
deviceSearchLoading.value = true
try {
const res = await DeviceService.getDevices({
device_no: query || undefined,
page: 1,
page_size: 20
})
if (res.code === 0) {
deviceOptions.value = res.data.items || []
}
} catch (error) {
console.error('Search devices failed:', error)
deviceOptions.value = []
} finally {
deviceSearchLoading.value = false
}
}
// 格式化货币 - 将分转换为元
const formatCurrency = (amount: number): string => {
return `¥${(amount / 100).toFixed(2)}`
}
// 获取支付状态标签类型
const getPaymentStatusType = (
status: PaymentStatus
): 'success' | 'info' | 'warning' | 'danger' => {
const statusMap: Record<PaymentStatus, 'success' | 'info' | 'warning' | 'danger'> = {
1: 'warning', // 待支付
2: 'success', // 已支付
3: 'info', // 已取消
4: 'danger' // 已退款
}
return statusMap[status] || 'info'
}
// 获取订单类型文本
const getOrderTypeText = (type: OrderType): string => {
return type === 'single_card'
? t('orderManagement.orderType.singleCard')
: t('orderManagement.orderType.device')
}
// 获取买家类型文本
const getBuyerTypeText = (type: BuyerType): string => {
return type === 'personal'
? t('orderManagement.buyerType.personal')
: t('orderManagement.buyerType.agent')
}
// 获取支付方式文本
const getPaymentMethodText = (method: OrderPaymentMethod): string => {
const methodMap: Record<OrderPaymentMethod, string> = {
wallet: t('orderManagement.paymentMethod.wallet'),
wechat: t('orderManagement.paymentMethod.wechat'),
alipay: t('orderManagement.paymentMethod.alipay')
}
return methodMap[method] || method
}
// 获取佣金状态文本
const getCommissionStatusText = (status: OrderCommissionStatus): string => {
const statusMap: Record<OrderCommissionStatus, string> = {
0: t('orderManagement.commissionStatus.notApplicable'),
1: t('orderManagement.commissionStatus.pending'),
2: t('orderManagement.commissionStatus.settled')
}
return statusMap[status] || '-'
}
// 动态列配置
const { columnChecks, columns } = useCheckedColumns(() => [
{
prop: 'id',
label: t('orderManagement.table.id'),
width: 80
},
{
prop: 'order_no',
label: t('orderManagement.table.orderNo'),
minWidth: 220
},
{
prop: 'order_type',
label: t('orderManagement.table.orderType'),
width: 120,
formatter: (row: Order) => {
return h(ElTag, { type: row.order_type === 'single_card' ? 'primary' : 'success' }, () =>
getOrderTypeText(row.order_type)
)
}
},
{
prop: 'buyer_type',
label: t('orderManagement.table.buyerType'),
width: 120,
formatter: (row: Order) => {
return h(ElTag, { type: row.buyer_type === 'personal' ? 'info' : 'warning' }, () =>
getBuyerTypeText(row.buyer_type)
)
}
},
{
prop: 'payment_status',
label: t('orderManagement.table.paymentStatus'),
width: 120,
formatter: (row: Order) => {
return h(
ElTag,
{ type: getPaymentStatusType(row.payment_status) },
() => row.payment_status_text
)
}
},
{
prop: 'total_amount',
label: t('orderManagement.table.totalAmount'),
width: 120,
formatter: (row: Order) => formatCurrency(row.total_amount)
},
{
prop: 'payment_method',
label: t('orderManagement.table.paymentMethod'),
width: 120,
formatter: (row: Order) => getPaymentMethodText(row.payment_method)
},
{
prop: 'paid_at',
label: t('orderManagement.table.paidAt'),
width: 180,
formatter: (row: Order) => (row.paid_at ? formatDateTime(row.paid_at) : '-')
},
{
prop: 'created_at',
label: t('orderManagement.table.createdAt'),
width: 180,
formatter: (row: Order) => formatDateTime(row.created_at)
}
])
// 当选择IOT卡时根据series_id筛选套餐
watch(
() => createForm.iot_card_id,
(newCardId) => {
if (newCardId && createForm.order_type === 'single_card') {
// 找到选中的IOT卡
const selectedCard = iotCardOptions.value.find((card) => card.id === newCardId)
if (selectedCard && selectedCard.series_id) {
// 根据series_id重新加载套餐列表
loadDefaultPackages(selectedCard.series_id)
} else {
// 如果没有series_id加载所有套餐
loadDefaultPackages()
}
}
}
)
// 当选择设备时根据series_id筛选套餐
watch(
() => createForm.device_id,
(newDeviceId) => {
if (newDeviceId && createForm.order_type === 'device') {
// 找到选中的设备
const selectedDevice = deviceOptions.value.find((dev) => dev.id === newDeviceId)
if (selectedDevice && selectedDevice.series_id) {
// 根据series_id重新加载套餐列表
loadDefaultPackages(selectedDevice.series_id)
} else {
// 如果没有series_id加载所有套餐
loadDefaultPackages()
}
}
}
)
onMounted(() => {
getTableData()
})
// 获取订单列表
const getTableData = async () => {
loading.value = true
try {
const params: OrderQueryParams = {
page: pagination.page,
page_size: pagination.page_size,
order_no: searchForm.order_no || undefined,
payment_status: searchForm.payment_status,
order_type: searchForm.order_type,
start_time: searchForm.start_time || undefined,
end_time: searchForm.end_time || undefined
}
const res = await OrderService.getOrders(params)
if (res.code === 0) {
orderList.value = res.data.list || []
pagination.total = res.data.total || 0
}
} catch (error) {
console.error(error)
} finally {
loading.value = false
}
}
// 重置搜索
const handleReset = () => {
Object.assign(searchForm, { ...initialSearchState })
pagination.page = 1
getTableData()
}
// 搜索
const handleSearch = () => {
// 处理日期范围
if (searchForm.dateRange && Array.isArray(searchForm.dateRange)) {
searchForm.start_time = searchForm.dateRange[0]
searchForm.end_time = searchForm.dateRange[1]
} else {
searchForm.start_time = ''
searchForm.end_time = ''
}
pagination.page = 1
getTableData()
}
// 刷新表格
const handleRefresh = () => {
getTableData()
}
// 处理表格分页变化
const handleSizeChange = (newPageSize: number) => {
pagination.page_size = newPageSize
getTableData()
}
const handleCurrentChange = (newCurrentPage: number) => {
pagination.page = newCurrentPage
getTableData()
}
// 显示创建订单对话框
const showCreateDialog = async () => {
createDialogVisible.value = true
// 加载IoT卡和设备列表套餐列表在选择IoT卡/设备后才加载
await Promise.all([loadDefaultIotCards(), loadDefaultDevices()])
}
// 加载默认套餐列表可选按series_id筛选
const loadDefaultPackages = async (seriesId?: number) => {
packageSearchLoading.value = true
try {
const res = await PackageManageService.getPackages({
series_id: seriesId,
page: 1,
page_size: 20,
status: 1, // 只获取启用的套餐
shelf_status: 1 // 只获取已上架的套餐
})
if (res.code === 0) {
packageOptions.value = res.data.items || []
}
} catch (error) {
console.error('Load default packages failed:', error)
packageOptions.value = []
} finally {
packageSearchLoading.value = false
}
}
// 加载默认IoT卡列表
const loadDefaultIotCards = async () => {
cardSearchLoading.value = true
try {
const res = await CardService.getStandaloneIotCards({
page: 1,
page_size: 20
})
if (res.code === 0) {
iotCardOptions.value = res.data.items || []
}
} catch (error) {
console.error('Load default IoT cards failed:', error)
iotCardOptions.value = []
} finally {
cardSearchLoading.value = false
}
}
// 加载默认设备列表
const loadDefaultDevices = async () => {
deviceSearchLoading.value = true
try {
const res = await DeviceService.getDevices({
page: 1,
page_size: 20
})
if (res.code === 0) {
deviceOptions.value = res.data.items || []
}
} catch (error) {
console.error('Load default devices failed:', error)
deviceOptions.value = []
} finally {
deviceSearchLoading.value = false
}
}
// 对话框关闭后的清理
const handleCreateDialogClosed = () => {
// 重置表单(会同时清除验证状态)
createFormRef.value?.resetFields()
// 重置表单数据到初始值
createForm.order_type = 'single_card'
createForm.package_ids = []
createForm.iot_card_id = null
createForm.device_id = null
// 清空套餐、IoT卡和设备搜索结果
packageOptions.value = []
iotCardOptions.value = []
deviceOptions.value = []
}
// 创建订单
const handleCreateOrder = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate(async (valid) => {
if (valid) {
createLoading.value = true
try {
const data: CreateOrderRequest = {
order_type: createForm.order_type,
package_ids: createForm.package_ids,
iot_card_id: createForm.order_type === 'single_card' ? createForm.iot_card_id : null,
device_id: createForm.order_type === 'device' ? createForm.device_id : null
}
await OrderService.createOrder(data)
ElMessage.success(t('orderManagement.messages.createSuccess'))
createDialogVisible.value = false
formEl.resetFields()
await getTableData()
} catch (error) {
console.error(error)
} finally {
createLoading.value = false
}
}
})
}
// 查看订单详情
const showOrderDetail = (row: Order) => {
router.push({
path: `${RoutesAlias.OrderList}/detail/${row.id}`
})
}
// 取消订单
const handleCancelOrder = (row: Order) => {
// 已支付的订单不能取消
if (row.payment_status === 2) {
ElMessage.warning(t('orderManagement.messages.cannotCancelPaid'))
return
}
ElMessageBox.confirm(
t('orderManagement.messages.cancelConfirmText'),
t('orderManagement.messages.cancelConfirm'),
{
confirmButtonText: t('orderManagement.actions.confirm'),
cancelButtonText: t('orderManagement.actions.cancel'),
type: 'warning'
}
)
.then(async () => {
try {
await OrderService.cancelOrder(row.id)
ElMessage.success(t('orderManagement.messages.cancelSuccess'))
await getTableData()
} catch (error) {
console.error(error)
}
})
.catch(() => {
// 用户取消操作
})
}
// 右键菜单项配置
const contextMenuItems = computed((): MenuItemType[] => {
if (!currentRow.value) return []
const items: MenuItemType[] = []
if (hasAuth('orders:view_detail')) {
items.push({ key: 'detail', label: '详情' })
}
// 只有待支付和已支付的订单可以删除
if (
(currentRow.value.payment_status === 1 || currentRow.value.payment_status === 2) &&
hasAuth('orders:delete')
) {
items.push({ key: 'cancel', label: '删除' })
}
return items
})
// 处理表格行右键菜单
const handleRowContextMenu = (row: Order, column: any, event: MouseEvent) => {
event.preventDefault()
event.stopPropagation()
currentRow.value = row
contextMenuRef.value?.show(event)
}
// 处理右键菜单选择
const handleContextMenuSelect = (item: MenuItemType) => {
if (!currentRow.value) return
switch (item.key) {
case 'detail':
showOrderDetail(currentRow.value)
break
case 'cancel':
handleCancelOrder(currentRow.value)
break
}
}
</script>
<style scoped lang="scss">
.order-list-page {
height: 100%;
}
.order-detail {
:deep(.el-descriptions__label) {
width: 140px;
}
}
</style>