Files
one-pipe-system/src/views/asset-management/record-management/asset-assign/index.vue
sexygoat a5e76313cb
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m9s
fix: bug
2026-04-23 14:59:05 +08:00

435 lines
11 KiB
Vue

<template>
<ArtTableFullScreen>
<div class="asset-allocation-records-page" id="table-full-screen">
<!-- 搜索栏 -->
<ArtSearchBar
v-model:filter="formFilters"
:items="formItems"
label-width="90"
@reset="handleReset"
@search="handleSearch"
></ArtSearchBar>
<ElCard shadow="never" class="art-table-card">
<!-- 表格头部 -->
<ArtTableHeader
:columnList="columnOptions"
v-model:columns="columnChecks"
@refresh="handleRefresh"
/>
<!-- 表格 -->
<ArtTable
ref="tableRef"
row-key="id"
:loading="loading"
:data="recordList"
:currentPage="pagination.page"
:pageSize="pagination.pageSize"
:total="pagination.total"
:marginTop="10"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
>
<template #default>
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
</template>
</ArtTable>
</ElCard>
</div>
</ArtTableFullScreen>
</template>
<script setup lang="ts">
import { h } from 'vue'
import { useRouter } from 'vue-router'
import { CardService, ShopService } from '@/api/modules'
import { ElMessage, ElTag } from 'element-plus'
import type { SearchFormItem } from '@/types'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import { useAuth } from '@/composables/useAuth'
import { useTableContextMenu } from '@/composables/useTableContextMenu'
import { formatDateTime } from '@/utils/business/format'
import type { AssetAllocationRecord, AllocationTypeEnum, AssetTypeEnum } from '@/types/api/card'
import { RoutesAlias } from '@/router/routesAlias'
defineOptions({ name: 'AssetAllocationRecords' })
const { hasAuth } = useAuth()
const router = useRouter()
const loading = ref(false)
const tableRef = ref()
// 搜索表单初始值
const initialSearchState = {
allocation_type: undefined as AllocationTypeEnum | undefined,
asset_type: undefined as AssetTypeEnum | undefined,
asset_identifier: '',
allocation_no: '',
from_shop_id: undefined as number | undefined,
to_shop_id: undefined as number | undefined,
operator_id: undefined as number | undefined,
dateRange: [] as string[],
created_at_start: '',
created_at_end: ''
}
// 搜索表单
const formFilters = reactive({ ...initialSearchState })
// 分页
const pagination = reactive({
page: 1,
pageSize: 20,
total: 0
})
// 搜索表单配置
const formItems: SearchFormItem[] = [
{
label: '分配类型',
prop: 'allocation_type',
type: 'select',
config: {
clearable: true,
placeholder: '全部'
},
options: () => [
{ label: '分配', value: 'allocate' },
{ label: '回收', value: 'recall' }
]
},
{
label: '资产类型',
prop: 'asset_type',
type: 'select',
config: {
clearable: true,
placeholder: '全部'
},
options: () => [
{ label: '物联网卡', value: 'iot_card' },
{ label: '设备', value: 'device' }
]
},
{
label: '分配单号',
prop: 'allocation_no',
type: 'input',
config: {
clearable: true,
placeholder: '请输入分配单号'
}
},
{
label: '资产标识符',
prop: 'asset_identifier',
type: 'input',
config: {
clearable: true,
placeholder: 'ICCID或设备号'
}
},
{
label: '来源店铺',
prop: 'from_shop_id',
type: 'select',
config: {
clearable: true,
filterable: true,
remote: true,
remoteMethod: (query: string) => searchShops(query, 'from'),
placeholder: '请选择或搜索来源店铺'
},
options: () =>
fromShopOptions.value.map((shop) => ({
label: shop.shop_name,
value: shop.id
}))
},
{
label: '目标店铺',
prop: 'to_shop_id',
type: 'select',
config: {
clearable: true,
filterable: true,
remote: true,
remoteMethod: (query: string) => searchShops(query, 'to'),
placeholder: '请选择或搜索目标店铺'
},
options: () =>
toShopOptions.value.map((shop) => ({
label: shop.shop_name,
value: shop.id
}))
},
{
label: '创建时间',
prop: 'dateRange',
type: 'date',
config: {
type: 'daterange',
clearable: true,
rangeSeparator: '至',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
valueFormat: 'YYYY-MM-DD'
}
}
]
// 列配置
const columnOptions = [
{ label: '分配单号', prop: 'allocation_no' },
{ label: '分配类型', prop: 'allocation_name' },
{ label: '资产类型', prop: 'asset_type_name' },
{ label: '资产标识符', prop: 'asset_identifier' },
{ label: '来源所有者', prop: 'from_owner_name' },
{ label: '目标所有者', prop: 'to_owner_name' },
{ label: '操作人', prop: 'operator_name' },
{ label: '关联卡数量', prop: 'related_card_count' },
{ label: '创建时间', prop: 'created_at' }
]
// 店铺搜索选项
const fromShopOptions = ref<any[]>([])
const toShopOptions = ref<any[]>([])
// 搜索店铺
const searchShops = async (query: string, type: 'from' | 'to') => {
try {
const params: any = {
page: 1,
page_size: 20
}
if (query) {
params.shop_name = query
}
const res = await ShopService.getShops(params)
if (res.code === 0) {
if (type === 'from') {
fromShopOptions.value = res.data.items || []
} else {
toShopOptions.value = res.data.items || []
}
}
} catch (error) {
console.error('搜索店铺失败:', error)
}
}
const recordList = ref<AssetAllocationRecord[]>([])
// 获取分配类型标签类型
const getAllocationTypeType = (type: AllocationTypeEnum) => {
return type === 'allocate' ? 'success' : 'warning'
}
// 获取资产类型标签类型
const getAssetTypeType = (type: AssetTypeEnum) => {
return type === 'iot_card' ? 'primary' : 'info'
}
// 动态列配置
const { columnChecks, columns } = useCheckedColumns(() => [
{
prop: 'allocation_no',
label: '分配单号',
minWidth: 200,
formatter: (row: AssetAllocationRecord) => {
return h(
'span',
{
style: 'color: var(--el-color-primary); cursor: pointer; text-decoration: underline;',
onClick: (e: MouseEvent) => {
e.stopPropagation()
handleNameClick(row)
}
},
row.allocation_no
)
}
},
{
prop: 'allocation_name',
label: '分配类型',
width: 100,
formatter: (row: AssetAllocationRecord) => {
return h(
ElTag,
{ type: getAllocationTypeType(row.allocation_type) },
() => row.allocation_name
)
}
},
{
prop: 'asset_type_name',
label: '资产类型',
width: 100,
formatter: (row: AssetAllocationRecord) => {
return h(ElTag, { type: getAssetTypeType(row.asset_type) }, () => row.asset_type_name)
}
},
{
prop: 'asset_identifier',
label: '资产标识符',
minWidth: 200
},
{
prop: 'from_owner_name',
label: '来源所有者',
width: 150,
formatter: (row: AssetAllocationRecord) => row.from_owner_name || '-'
},
{
prop: 'from_owner_type',
label: '来源类型',
width: 100,
formatter: (row: AssetAllocationRecord) => {
const typeMap: Record<string, string> = {
platform: '平台',
shop: '店铺'
}
return typeMap[row.from_owner_type] || row.from_owner_type || '-'
}
},
{
prop: 'to_owner_name',
label: '目标所有者',
width: 150,
formatter: (row: AssetAllocationRecord) => row.to_owner_name || '-'
},
{
prop: 'to_owner_type',
label: '目标类型',
width: 100,
formatter: (row: AssetAllocationRecord) => {
const typeMap: Record<string, string> = {
platform: '平台',
shop: '店铺'
}
return typeMap[row.to_owner_type] || row.to_owner_type || '-'
}
},
{
prop: 'operator_name',
label: '操作人',
width: 120
},
{
prop: 'related_card_count',
label: '关联卡数量',
width: 120
},
{
prop: 'remark',
label: '备注',
minWidth: 150,
showOverflowTooltip: true
},
{
prop: 'created_at',
label: '创建时间',
width: 180,
formatter: (row: AssetAllocationRecord) => formatDateTime(row.created_at)
}
])
onMounted(() => {
getTableData()
searchShops('', 'from')
searchShops('', 'to')
})
// 获取分配记录列表
const getTableData = async () => {
loading.value = true
try {
const params = {
page: pagination.page,
page_size: pagination.pageSize,
...formFilters
}
// 清理空值
Object.keys(params).forEach((key) => {
if (params[key] === '' || params[key] === undefined) {
delete params[key]
}
})
const res = await CardService.getAssetAllocationRecords(params)
if (res.code === 0) {
recordList.value = res.data.items || []
pagination.total = res.data.total || 0
}
} catch (error) {
console.error(error)
console.log('获取分配记录列表失败')
} finally {
loading.value = false
}
}
// 重置搜索
const handleReset = () => {
Object.assign(formFilters, { ...initialSearchState })
pagination.page = 1
getTableData()
}
// 搜索
const handleSearch = () => {
// 处理日期范围
if (formFilters.dateRange && Array.isArray(formFilters.dateRange)) {
formFilters.created_at_start = formFilters.dateRange[0] || ''
formFilters.created_at_end = formFilters.dateRange[1] || ''
} else {
formFilters.created_at_start = ''
formFilters.created_at_end = ''
}
pagination.page = 1
getTableData()
}
// 刷新表格
const handleRefresh = () => {
getTableData()
}
// 处理表格分页变化
const handleSizeChange = (newPageSize: number) => {
pagination.pageSize = newPageSize
getTableData()
}
const handleCurrentChange = (newCurrentPage: number) => {
pagination.page = newCurrentPage
getTableData()
}
// 查看详情
const viewDetail = (row: AssetAllocationRecord) => {
router.push({
path: `${RoutesAlias.AssetAssign}/detail/${row.id}`
})
}
// 处理名称点击
const handleNameClick = (row: AssetAllocationRecord) => {
if (hasAuth('asset_assign:view_detail')) {
viewDetail(row)
} else {
ElMessage.warning('您没有查看详情的权限')
}
}
</script>
<style lang="scss" scoped>
.asset-allocation-records-page {
// Allocation records page styles
}
</style>