删除多余代码
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<div class="asset-assign-detail">
|
||||
<ElCard shadow="never">
|
||||
<!-- 页面头部 -->
|
||||
<div class="detail-header">
|
||||
<ElButton @click="handleBack">
|
||||
<template #icon>
|
||||
<ElIcon><ArrowLeft /></ElIcon>
|
||||
</template>
|
||||
返回
|
||||
</ElButton>
|
||||
<h2 class="detail-title">资产分配详情</h2>
|
||||
</div>
|
||||
|
||||
<!-- 详情内容 -->
|
||||
<DetailPage v-if="detailData" :sections="detailSections" :data="detailData" />
|
||||
|
||||
<!-- 加载中 -->
|
||||
<div v-if="loading" class="loading-container">
|
||||
<ElIcon class="is-loading"><Loading /></ElIcon>
|
||||
<span>加载中...</span>
|
||||
</div>
|
||||
</ElCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElCard, ElButton, ElIcon, ElMessage } from 'element-plus'
|
||||
import { ArrowLeft, Loading } from '@element-plus/icons-vue'
|
||||
import DetailPage from '@/components/common/DetailPage.vue'
|
||||
import type { DetailSection } from '@/components/common/DetailPage.vue'
|
||||
import { CardService } from '@/api/modules'
|
||||
import type { AssetAllocationRecord } from '@/types/api/card'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
|
||||
defineOptions({ name: 'AssetAssignDetail' })
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const loading = ref(false)
|
||||
const detailData = ref<AssetAllocationRecord | null>(null)
|
||||
|
||||
// 详情页配置
|
||||
const detailSections: DetailSection[] = [
|
||||
{
|
||||
title: '基本信息',
|
||||
fields: [
|
||||
{ label: '分配单号', prop: 'allocation_no' },
|
||||
{
|
||||
label: '分配类型',
|
||||
formatter: (_, data) => data.allocation_name || '-'
|
||||
},
|
||||
{
|
||||
label: '资产类型',
|
||||
formatter: (_, data) => data.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', formatter: (value) => formatDateTime(value) },
|
||||
{ label: '备注', prop: 'remark', formatter: (value) => value || '-' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// 返回上一页
|
||||
const handleBack = () => {
|
||||
router.back()
|
||||
}
|
||||
|
||||
// 获取详情数据
|
||||
const fetchDetail = async () => {
|
||||
const id = Number(route.params.id)
|
||||
if (!id) {
|
||||
ElMessage.error('缺少ID参数')
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await CardService.getAssetAllocationRecordDetail(id)
|
||||
if (res.code === 0) {
|
||||
detailData.value = res.data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchDetail()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.asset-assign-detail {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
padding-bottom: 16px;
|
||||
|
||||
.detail-title {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 60px 20px;
|
||||
color: var(--el-text-color-secondary);
|
||||
|
||||
.el-icon {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,401 @@
|
||||
<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"
|
||||
:row-class-name="getRowClassName"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@row-contextmenu="handleRowContextMenu"
|
||||
@cell-mouse-enter="handleCellMouseEnter"
|
||||
@cell-mouse-leave="handleCellMouseLeave"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 鼠标悬浮提示 -->
|
||||
<TableContextMenuHint :visible="showContextMenuHint" :position="hintPosition" />
|
||||
|
||||
<!-- 右键菜单 -->
|
||||
<ArtMenuRight
|
||||
ref="contextMenuRef"
|
||||
:menu-items="contextMenuItems"
|
||||
:menu-width="120"
|
||||
@select="handleContextMenuSelect"
|
||||
/>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { CardService } 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'
|
||||
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||||
import TableContextMenuHint from '@/components/core/others/TableContextMenuHint.vue'
|
||||
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
||||
|
||||
defineOptions({ name: 'AssetAllocationRecords' })
|
||||
|
||||
const { hasAuth } = useAuth()
|
||||
const router = useRouter()
|
||||
|
||||
// 使用表格右键菜单功能
|
||||
const {
|
||||
showContextMenuHint,
|
||||
hintPosition,
|
||||
getRowClassName,
|
||||
handleCellMouseEnter,
|
||||
handleCellMouseLeave
|
||||
} = useTableContextMenu()
|
||||
|
||||
const loading = ref(false)
|
||||
const tableRef = ref()
|
||||
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||
const currentRow = ref<AssetAllocationRecord | null>(null)
|
||||
|
||||
// 搜索表单初始值
|
||||
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,
|
||||
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: 'created_at_range',
|
||||
type: 'date',
|
||||
config: {
|
||||
type: 'datetimerange',
|
||||
clearable: true,
|
||||
startPlaceholder: '开始时间',
|
||||
endPlaceholder: '结束时间',
|
||||
valueFormat: 'YYYY-MM-DDTHH:mm:ssZ'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
// 列配置
|
||||
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 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
|
||||
},
|
||||
{
|
||||
prop: 'to_owner_name',
|
||||
label: '目标所有者',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
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()
|
||||
})
|
||||
|
||||
// 获取分配记录列表
|
||||
const getTableData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
page: pagination.page,
|
||||
page_size: pagination.pageSize,
|
||||
...formFilters
|
||||
}
|
||||
|
||||
// 处理日期范围
|
||||
if ((params as any).created_at_range && (params as any).created_at_range.length === 2) {
|
||||
params.created_at_start = (params as any).created_at_range[0]
|
||||
params.created_at_end = (params as any).created_at_range[1]
|
||||
delete (params as any).created_at_range
|
||||
}
|
||||
|
||||
// 清理空值
|
||||
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 = () => {
|
||||
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('您没有查看详情的权限')
|
||||
}
|
||||
}
|
||||
|
||||
// 右键菜单项配置
|
||||
const contextMenuItems = computed((): MenuItemType[] => {
|
||||
const items: MenuItemType[] = []
|
||||
|
||||
return items
|
||||
})
|
||||
|
||||
// 处理表格行右键菜单
|
||||
const handleRowContextMenu = (row: AssetAllocationRecord, 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
|
||||
// No cases available
|
||||
) {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.asset-allocation-records-page {
|
||||
// Allocation records page styles
|
||||
}
|
||||
|
||||
:deep(.el-table__row.table-row-with-context-menu) {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div class="authorization-record-detail">
|
||||
<ElCard shadow="never">
|
||||
<!-- 页面头部 -->
|
||||
<div class="detail-header">
|
||||
<ElButton @click="handleBack">
|
||||
<template #icon>
|
||||
<ElIcon><ArrowLeft /></ElIcon>
|
||||
</template>
|
||||
返回
|
||||
</ElButton>
|
||||
<h2 class="detail-title">授权记录详情</h2>
|
||||
</div>
|
||||
|
||||
<!-- 详情内容 -->
|
||||
<DetailPage v-if="detailData" :sections="detailSections" :data="detailData" />
|
||||
|
||||
<!-- 加载中 -->
|
||||
<div v-if="loading" class="loading-container">
|
||||
<ElIcon class="is-loading"><Loading /></ElIcon>
|
||||
<span>加载中...</span>
|
||||
</div>
|
||||
</ElCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElCard, ElButton, ElIcon, ElMessage } from 'element-plus'
|
||||
import { ArrowLeft, Loading } from '@element-plus/icons-vue'
|
||||
import DetailPage from '@/components/common/DetailPage.vue'
|
||||
import type { DetailSection } from '@/components/common/DetailPage.vue'
|
||||
import { AuthorizationService } from '@/api/modules'
|
||||
import type { AuthorizationItem } from '@/types/api/authorization'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
|
||||
defineOptions({ name: 'AuthorizationRecordDetail' })
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const loading = ref(false)
|
||||
const detailData = ref<AuthorizationItem | null>(null)
|
||||
|
||||
// 详情页配置
|
||||
const detailSections: DetailSection[] = [
|
||||
{
|
||||
title: '基本信息',
|
||||
fields: [
|
||||
{ label: '企业ID', prop: 'enterprise_id' },
|
||||
{ label: '企业名称', prop: 'enterprise_name' },
|
||||
{ label: '卡ID', prop: 'card_id' },
|
||||
{ label: 'ICCID', prop: 'iccid' },
|
||||
{ label: '手机号', prop: 'msisdn', formatter: (value) => value || '-' },
|
||||
{ label: '授权人ID', prop: 'authorized_by' },
|
||||
{ label: '授权人', prop: 'authorizer_name' },
|
||||
{
|
||||
label: '授权人类型',
|
||||
formatter: (_, data) => {
|
||||
return data.authorizer_type === 2 ? '平台' : '代理'
|
||||
}
|
||||
},
|
||||
{ label: '授权时间', prop: 'authorized_at', formatter: (value) => formatDateTime(value) },
|
||||
{
|
||||
label: '状态',
|
||||
formatter: (_, data) => {
|
||||
return data.status === 1 ? '有效' : '已回收'
|
||||
}
|
||||
},
|
||||
{ label: '备注', prop: 'remark', formatter: (value) => value || '-' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// 返回上一页
|
||||
const handleBack = () => {
|
||||
router.back()
|
||||
}
|
||||
|
||||
// 获取详情数据
|
||||
const fetchDetail = async () => {
|
||||
const id = Number(route.params.id)
|
||||
if (!id) {
|
||||
ElMessage.error('缺少ID参数')
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await AuthorizationService.getAuthorizationDetail(id)
|
||||
if (res.code === 0) {
|
||||
detailData.value = res.data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
console.log('获取授权记录详情失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchDetail()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.authorization-record-detail {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
padding-bottom: 16px;
|
||||
|
||||
.detail-title {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 60px 20px;
|
||||
color: var(--el-text-color-secondary);
|
||||
|
||||
.el-icon {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,465 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="authorization-records-page" id="table-full-screen">
|
||||
<!-- 搜索栏 -->
|
||||
<ArtSearchBar
|
||||
v-model:filter="searchForm"
|
||||
:items="searchFormItems"
|
||||
label-width="85"
|
||||
@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="authorizationList"
|
||||
:currentPage="pagination.page"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:marginTop="10"
|
||||
:row-class-name="getRowClassName"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@row-contextmenu="handleRowContextMenu"
|
||||
@cell-mouse-enter="handleCellMouseEnter"
|
||||
@cell-mouse-leave="handleCellMouseLeave"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 鼠标悬浮提示 -->
|
||||
<TableContextMenuHint :visible="showContextMenuHint" :position="hintPosition" />
|
||||
|
||||
<!-- 右键菜单 -->
|
||||
<ArtMenuRight
|
||||
ref="contextMenuRef"
|
||||
:menu-items="contextMenuItems"
|
||||
:menu-width="120"
|
||||
@select="handleContextMenuSelect"
|
||||
/>
|
||||
|
||||
<!-- 修改备注对话框 -->
|
||||
<ElDialog v-model="remarkDialogVisible" title="修改备注" width="500px">
|
||||
<ElForm ref="remarkFormRef" :model="remarkForm" :rules="remarkRules" label-width="80px">
|
||||
<ElFormItem label="备注" prop="remark">
|
||||
<ElInput
|
||||
v-model="remarkForm.remark"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入备注(最多500字)"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="remarkDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmitRemark" :loading="remarkLoading">
|
||||
提交
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { AuthorizationService } from '@/api/modules'
|
||||
import { ElMessage, ElTag } from 'element-plus'
|
||||
import type { FormInstance, FormRules } 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 ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||||
import TableContextMenuHint from '@/components/core/others/TableContextMenuHint.vue'
|
||||
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
||||
import type {
|
||||
AuthorizationItem,
|
||||
AuthorizationStatus,
|
||||
AuthorizerType
|
||||
} from '@/types/api/authorization'
|
||||
import { CommonStatus } from '@/config/constants'
|
||||
import { RoutesAlias } from '@/router/routesAlias'
|
||||
|
||||
defineOptions({ name: 'AuthorizationRecords' })
|
||||
|
||||
const { hasAuth } = useAuth()
|
||||
const router = useRouter()
|
||||
|
||||
// 使用表格右键菜单功能
|
||||
const {
|
||||
showContextMenuHint,
|
||||
hintPosition,
|
||||
getRowClassName,
|
||||
handleCellMouseEnter,
|
||||
handleCellMouseLeave
|
||||
} = useTableContextMenu()
|
||||
|
||||
const loading = ref(false)
|
||||
const remarkDialogVisible = ref(false)
|
||||
const remarkLoading = ref(false)
|
||||
const tableRef = ref()
|
||||
const remarkFormRef = ref<FormInstance>()
|
||||
const currentRecordId = ref<number>(0)
|
||||
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||
const currentRow = ref<AuthorizationItem | null>(null)
|
||||
|
||||
// 搜索表单初始值
|
||||
const initialSearchState = {
|
||||
enterprise_id: undefined as number | undefined,
|
||||
iccid: '',
|
||||
authorizer_type: undefined as AuthorizerType | undefined,
|
||||
status: undefined as AuthorizationStatus | undefined,
|
||||
dateRange: [] as string[]
|
||||
}
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({ ...initialSearchState })
|
||||
|
||||
// 备注表单
|
||||
const remarkForm = reactive({
|
||||
remark: ''
|
||||
})
|
||||
|
||||
// 备注表单验证规则
|
||||
const remarkRules = reactive<FormRules>({
|
||||
remark: [{ max: 500, message: '备注不能超过500个字符', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 搜索表单配置
|
||||
const searchFormItems: SearchFormItem[] = [
|
||||
{
|
||||
label: 'ICCID',
|
||||
prop: 'iccid',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入ICCID'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '授权人类型',
|
||||
prop: 'authorizer_type',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '平台', value: 2 },
|
||||
{ label: '代理', value: 3 }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '有效', value: 1 },
|
||||
{ label: '已回收', value: 0 }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '授权时间',
|
||||
prop: 'dateRange',
|
||||
type: 'daterange',
|
||||
config: {
|
||||
type: 'daterange',
|
||||
startPlaceholder: '开始日期',
|
||||
endPlaceholder: '结束日期',
|
||||
valueFormat: 'YYYY-MM-DD'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: 'ICCID', prop: 'iccid' },
|
||||
{ label: '手机号', prop: 'msisdn' },
|
||||
{ label: '企业名称', prop: 'enterprise_name' },
|
||||
{ label: '授权人', prop: 'authorizer_name' },
|
||||
{ label: '授权人类型', prop: 'authorizer_type' },
|
||||
{ label: '授权时间', prop: 'authorized_at' },
|
||||
{ label: '状态', prop: 'status' },
|
||||
{ label: '备注', prop: 'remark' }
|
||||
]
|
||||
|
||||
const authorizationList = ref<AuthorizationItem[]>([])
|
||||
|
||||
// 获取授权人类型标签类型
|
||||
const getAuthorizerTypeTag = (type: AuthorizerType) => {
|
||||
return type === 2 ? 'primary' : 'success'
|
||||
}
|
||||
|
||||
// 获取授权人类型文本
|
||||
const getAuthorizerTypeText = (type: AuthorizerType) => {
|
||||
return type === 2 ? '平台' : '代理'
|
||||
}
|
||||
|
||||
// 获取状态标签类型
|
||||
const getStatusTag = (status: AuthorizationStatus) => {
|
||||
return status === 1 ? 'success' : 'info'
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status: AuthorizationStatus) => {
|
||||
return status === 1 ? '有效' : '已回收'
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{
|
||||
prop: 'iccid',
|
||||
label: 'ICCID',
|
||||
minWidth: 200,
|
||||
formatter: (row: AuthorizationItem) => {
|
||||
return h(
|
||||
'span',
|
||||
{
|
||||
style: 'color: var(--el-color-primary); cursor: pointer; text-decoration: underline;',
|
||||
onClick: (e: MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
handleNameClick(row)
|
||||
}
|
||||
},
|
||||
row.iccid
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'msisdn',
|
||||
label: '手机号',
|
||||
width: 130,
|
||||
formatter: (row: AuthorizationItem) => row.msisdn || '-'
|
||||
},
|
||||
{
|
||||
prop: 'enterprise_name',
|
||||
label: '企业名称',
|
||||
minWidth: 150
|
||||
},
|
||||
{
|
||||
prop: 'authorizer_name',
|
||||
label: '授权人',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'authorizer_type',
|
||||
label: '授权人类型',
|
||||
width: 110,
|
||||
formatter: (row: AuthorizationItem) => {
|
||||
return h(ElTag, { type: getAuthorizerTypeTag(row.authorizer_type) }, () =>
|
||||
getAuthorizerTypeText(row.authorizer_type)
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'authorized_at',
|
||||
label: '授权时间',
|
||||
width: 180,
|
||||
formatter: (row: AuthorizationItem) => formatDateTime(row.authorized_at)
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
label: '状态',
|
||||
width: 100,
|
||||
formatter: (row: AuthorizationItem) => {
|
||||
return h(ElTag, { type: getStatusTag(row.status) }, () => getStatusText(row.status))
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'remark',
|
||||
label: '备注',
|
||||
minWidth: 150,
|
||||
showOverflowTooltip: true,
|
||||
formatter: (row: AuthorizationItem) => row.remark || '-'
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
getTableData()
|
||||
})
|
||||
|
||||
// 获取授权记录列表
|
||||
const getTableData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params: any = {
|
||||
page: pagination.page,
|
||||
page_size: pagination.pageSize,
|
||||
iccid: searchForm.iccid || undefined,
|
||||
authorizer_type: searchForm.authorizer_type,
|
||||
status: searchForm.status
|
||||
}
|
||||
|
||||
// 处理日期范围
|
||||
if (searchForm.dateRange && searchForm.dateRange.length === 2) {
|
||||
params.start_time = searchForm.dateRange[0]
|
||||
params.end_time = searchForm.dateRange[1]
|
||||
}
|
||||
|
||||
// 清理空值
|
||||
Object.keys(params).forEach((key) => {
|
||||
if (params[key] === '' || params[key] === undefined) {
|
||||
delete params[key]
|
||||
}
|
||||
})
|
||||
|
||||
const res = await AuthorizationService.getAuthorizations(params)
|
||||
if (res.code === 0) {
|
||||
authorizationList.value = res.data.items || []
|
||||
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 = () => {
|
||||
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: AuthorizationItem) => {
|
||||
router.push({
|
||||
path: `${RoutesAlias.AuthorizationRecords}/detail/${row.id}`
|
||||
})
|
||||
}
|
||||
|
||||
// 处理名称点击
|
||||
const handleNameClick = (row: AuthorizationItem) => {
|
||||
if (hasAuth('authorization_records:view_detail')) {
|
||||
viewDetail(row)
|
||||
} else {
|
||||
ElMessage.warning('您没有查看详情的权限')
|
||||
}
|
||||
}
|
||||
|
||||
// 显示修改备注对话框
|
||||
const showRemarkDialog = (row: AuthorizationItem) => {
|
||||
currentRecordId.value = row.id
|
||||
remarkForm.remark = row.remark || ''
|
||||
remarkDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 提交备注修改
|
||||
const handleSubmitRemark = async () => {
|
||||
if (!remarkFormRef.value) return
|
||||
|
||||
await remarkFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
remarkLoading.value = true
|
||||
try {
|
||||
await AuthorizationService.updateAuthorizationRemark(currentRecordId.value, {
|
||||
remark: remarkForm.remark
|
||||
})
|
||||
ElMessage.success('备注修改成功')
|
||||
remarkDialogVisible.value = false
|
||||
getTableData()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
remarkLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 右键菜单项配置
|
||||
const contextMenuItems = computed((): MenuItemType[] => {
|
||||
const items: MenuItemType[] = []
|
||||
|
||||
if (hasAuth('authorization_records:update_remark')) {
|
||||
items.push({ key: 'edit', label: '编辑' })
|
||||
}
|
||||
|
||||
return items
|
||||
})
|
||||
|
||||
// 处理表格行右键菜单
|
||||
const handleRowContextMenu = (row: AuthorizationItem, 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 'edit':
|
||||
showRemarkDialog(currentRow.value)
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.authorization-records-page {
|
||||
// Authorization records page styles
|
||||
}
|
||||
|
||||
:deep(.el-table__row.table-row-with-context-menu) {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user