This commit is contained in:
@@ -22,19 +22,10 @@ export interface PaginationParams {
|
|||||||
|
|
||||||
// 分页响应数据
|
// 分页响应数据
|
||||||
export interface PaginationData<T> {
|
export interface PaginationData<T> {
|
||||||
items: T[] // 后端实际返回的是 items,不是 records
|
items: T[] // 数据列表
|
||||||
total: number
|
total: number // 总数
|
||||||
size: number
|
page_size: number // 每页数量
|
||||||
page: number // 后端返回的是 page,不是 current
|
page: number // 当前页
|
||||||
pages?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新版分页响应数据(使用 list 字段)
|
|
||||||
export interface PaginationDataV2<T> {
|
|
||||||
list: T[] // 新版API使用 list 字段
|
|
||||||
total: number
|
|
||||||
page_size: number
|
|
||||||
page: number
|
|
||||||
total_pages: number // 总页数
|
total_pages: number // 总页数
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,11 +34,6 @@ export interface PaginationResponse<T = any> extends BaseResponse {
|
|||||||
data: PaginationData<T>
|
data: PaginationData<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新版分页响应(使用 list 字段)
|
|
||||||
export interface PaginationResponseV2<T = any> extends BaseResponse {
|
|
||||||
data: PaginationDataV2<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
// 列表响应
|
// 列表响应
|
||||||
export interface ListResponse<T = any> extends BaseResponse {
|
export interface ListResponse<T = any> extends BaseResponse {
|
||||||
data: T[]
|
data: T[]
|
||||||
|
|||||||
@@ -86,6 +86,15 @@ export interface UpdatePackageSeriesStatusRequest {
|
|||||||
|
|
||||||
// ==================== 套餐管理 ====================
|
// ==================== 套餐管理 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返佣档位信息
|
||||||
|
*/
|
||||||
|
export interface CommissionTierInfo {
|
||||||
|
current_rate?: string // 当前返佣比例
|
||||||
|
next_rate?: string // 下一档位返佣比例
|
||||||
|
next_threshold?: number | null // 下一档位阈值
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 套餐响应
|
* 套餐响应
|
||||||
*/
|
*/
|
||||||
@@ -93,22 +102,28 @@ export interface PackageResponse {
|
|||||||
id: number
|
id: number
|
||||||
package_code: string
|
package_code: string
|
||||||
package_name: string
|
package_name: string
|
||||||
series_id: number
|
series_id: number | null
|
||||||
series_name?: string
|
series_name?: string | null
|
||||||
package_type: string // 'formal':正式套餐, 'addon':加油包
|
package_type: string // 'formal':正式套餐, 'addon':附加套餐
|
||||||
data_type: string // 'real':真实流量, 'virtual':虚拟流量
|
calendar_type?: string // 套餐周期类型 (natural_month:自然月, by_day:按天)
|
||||||
real_data_mb: number // 真流量额度(MB)
|
duration_days?: number | null // 套餐天数(calendar_type=by_day时有值)
|
||||||
virtual_data_mb: number // 虚流量额度(MB)
|
duration_months?: number // 套餐时长(月数)
|
||||||
duration_months: number // 有效期(月)
|
data_reset_cycle?: string // 流量重置周期 (daily:每日, monthly:每月, yearly:每年, none:不重置)
|
||||||
price: number // 价格(分)
|
real_data_mb?: number // 真流量额度(MB)
|
||||||
cost_price: number // 成本价(分)
|
virtual_data_mb?: number // 虚流量额度(MB)
|
||||||
suggested_retail_price: number // 建议零售价(分)
|
enable_virtual_data?: boolean // 是否启用虚流量
|
||||||
enable_virtual_data: boolean // 是否启用虚流量
|
enable_realname_activation?: boolean // 是否启用实名激活 (true:需实名后激活, false:立即激活)
|
||||||
shelf_status: number // 上架状态 (1:上架, 2:下架)
|
cost_price?: number // 成本价(分)
|
||||||
status: number // 状态 (1:启用, 2:禁用)
|
suggested_retail_price?: number // 建议零售价(分)
|
||||||
|
current_commission_rate?: string // 当前返佣比例(仅代理用户可见)
|
||||||
|
one_time_commission_amount?: number | null // 一次性佣金金额(分,代理视角)
|
||||||
|
profit_margin?: number | null // 利润空间(分,仅代理用户可见)
|
||||||
|
tier_info?: CommissionTierInfo // 返佣档位信息
|
||||||
|
shelf_status?: number // 上架状态 (1:上架, 2:下架)
|
||||||
|
status?: number // 状态 (1:启用, 2:禁用)
|
||||||
description?: string
|
description?: string
|
||||||
created_at: string
|
created_at?: string
|
||||||
updated_at: string
|
updated_at?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,30 +144,37 @@ export interface PackageQueryParams extends PaginationParams {
|
|||||||
export interface CreatePackageRequest {
|
export interface CreatePackageRequest {
|
||||||
package_code: string // 套餐编码,必填
|
package_code: string // 套餐编码,必填
|
||||||
package_name: string // 套餐名称,必填
|
package_name: string // 套餐名称,必填
|
||||||
series_id: number // 所属系列ID,必填
|
series_id?: number | null // 所属系列ID,可选
|
||||||
package_type: string // 套餐类型,必填
|
package_type: string // 套餐类型,必填 (formal:正式套餐, addon:附加套餐)
|
||||||
data_type: string // 流量类型,必填
|
calendar_type?: string | null // 套餐周期类型 (natural_month:自然月, by_day:按天),可选
|
||||||
real_data_mb: number // 真流量额度(MB),必填
|
duration_days?: number | null // 套餐天数(calendar_type=by_day时必填),可选
|
||||||
virtual_data_mb: number // 虚流量额度(MB),必填
|
duration_months: number // 套餐时长(月数),必填
|
||||||
duration_months: number // 有效期(月),必填
|
data_reset_cycle?: string | null // 流量重置周期 (daily:每日, monthly:每月, yearly:每年, none:不重置),可选
|
||||||
price: number // 价格(分),必填
|
real_data_mb?: number | null // 真流量额度(MB),可选
|
||||||
description?: string // 描述,可选
|
virtual_data_mb?: number | null // 虚流量额度(MB),可选
|
||||||
|
enable_virtual_data?: boolean // 是否启用虚流量,可选
|
||||||
|
enable_realname_activation?: boolean | null // 是否启用实名激活 (true:需实名后激活, false:立即激活),可选
|
||||||
|
cost_price: number // 成本价(分),必填
|
||||||
|
suggested_retail_price?: number | null // 建议零售价(分),可选
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新套餐请求
|
* 更新套餐请求
|
||||||
*/
|
*/
|
||||||
export interface UpdatePackageRequest {
|
export interface UpdatePackageRequest {
|
||||||
package_code?: string
|
package_name?: string | null // 套餐名称,可选
|
||||||
package_name?: string
|
series_id?: number | null // 所属系列ID,可选
|
||||||
series_id?: number
|
package_type?: string | null // 套餐类型,可选 (formal:正式套餐, addon:附加套餐)
|
||||||
package_type?: string
|
calendar_type?: string | null // 套餐周期类型 (natural_month:自然月, by_day:按天),可选
|
||||||
data_type?: string
|
duration_days?: number | null // 套餐天数(calendar_type=by_day时必填),可选
|
||||||
real_data_mb?: number
|
duration_months?: number | null // 套餐时长(月数),可选
|
||||||
virtual_data_mb?: number
|
data_reset_cycle?: string | null // 流量重置周期 (daily:每日, monthly:每月, yearly:每年, none:不重置),可选
|
||||||
duration_months?: number
|
real_data_mb?: number | null // 真流量额度(MB),可选
|
||||||
price?: number
|
virtual_data_mb?: number | null // 虚流量额度(MB),可选
|
||||||
description?: string
|
enable_virtual_data?: boolean | null // 是否启用虚流量,可选
|
||||||
|
enable_realname_activation?: boolean | null // 是否启用实名激活,可选
|
||||||
|
cost_price?: number | null // 成本价(分),可选
|
||||||
|
suggested_retail_price?: number | null // 建议零售价(分),可选
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -34,12 +34,21 @@
|
|||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
|
@row-contextmenu="handleRowContextMenu"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||||
</template>
|
</template>
|
||||||
</ArtTable>
|
</ArtTable>
|
||||||
|
|
||||||
|
<!-- 右键菜单 -->
|
||||||
|
<ArtMenuRight
|
||||||
|
ref="contextMenuRef"
|
||||||
|
:menu-items="contextMenuItems"
|
||||||
|
:menu-width="120"
|
||||||
|
@select="handleContextMenuSelect"
|
||||||
|
/>
|
||||||
|
|
||||||
<ElDialog
|
<ElDialog
|
||||||
v-model="dialogVisible"
|
v-model="dialogVisible"
|
||||||
:title="dialogType === 'add' ? '添加账号' : '编辑账号'"
|
:title="dialogType === 'add' ? '添加账号' : '编辑账号'"
|
||||||
@@ -195,6 +204,8 @@
|
|||||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||||
import { useAuth } from '@/composables/useAuth'
|
import { useAuth } from '@/composables/useAuth'
|
||||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
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 { AccountService } from '@/api/modules/account'
|
import { AccountService } from '@/api/modules/account'
|
||||||
import { RoleService } from '@/api/modules/role'
|
import { RoleService } from '@/api/modules/role'
|
||||||
import { ShopService, EnterpriseService } from '@/api/modules'
|
import { ShopService, EnterpriseService } from '@/api/modules'
|
||||||
@@ -216,6 +227,8 @@
|
|||||||
const currentAccountId = ref<number>(0)
|
const currentAccountId = ref<number>(0)
|
||||||
const currentAccountName = ref<string>('')
|
const currentAccountName = ref<string>('')
|
||||||
const currentAccountType = ref<number>(0)
|
const currentAccountType = ref<number>(0)
|
||||||
|
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||||
|
const currentRow = ref<any | null>(null)
|
||||||
const selectedRoles = ref<number[]>([])
|
const selectedRoles = ref<number[]>([])
|
||||||
const allRoles = ref<PlatformRole[]>([])
|
const allRoles = ref<PlatformRole[]>([])
|
||||||
const rolesToAdd = ref<number[]>([])
|
const rolesToAdd = ref<number[]>([])
|
||||||
@@ -355,8 +368,7 @@
|
|||||||
{ label: '店铺名称', prop: 'shop_name' },
|
{ label: '店铺名称', prop: 'shop_name' },
|
||||||
{ label: '企业名称', prop: 'enterprise_name' },
|
{ label: '企业名称', prop: 'enterprise_name' },
|
||||||
{ label: '状态', prop: 'status' },
|
{ label: '状态', prop: 'status' },
|
||||||
{ label: '创建时间', prop: 'created_at' },
|
{ label: '创建时间', prop: 'created_at' }
|
||||||
{ label: '操作', prop: 'operation' }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
// 显示对话框
|
// 显示对话框
|
||||||
@@ -473,44 +485,6 @@
|
|||||||
label: '创建时间',
|
label: '创建时间',
|
||||||
width: 180,
|
width: 180,
|
||||||
formatter: (row: any) => formatDateTime(row.created_at)
|
formatter: (row: any) => formatDateTime(row.created_at)
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: 'operation',
|
|
||||||
label: '操作',
|
|
||||||
width: 240,
|
|
||||||
fixed: 'right',
|
|
||||||
formatter: (row: any) => {
|
|
||||||
const buttons = []
|
|
||||||
|
|
||||||
if (hasAuth('account:patch_role')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '分配角色',
|
|
||||||
onClick: () => showRoleDialog(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasAuth('account:edit')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '编辑',
|
|
||||||
onClick: () => showDialog('edit', row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasAuth('account:delete')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '删除',
|
|
||||||
onClick: () => deleteAccount(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return h('div', { style: 'display: flex; gap: 8px;' }, buttons)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -851,6 +825,50 @@
|
|||||||
const handleEnterpriseSearch = (query: string) => {
|
const handleEnterpriseSearch = (query: string) => {
|
||||||
loadEnterpriseList(query)
|
loadEnterpriseList(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 右键菜单项配置
|
||||||
|
const contextMenuItems = computed((): MenuItemType[] => {
|
||||||
|
const items: MenuItemType[] = []
|
||||||
|
|
||||||
|
if (hasAuth('account:patch_role')) {
|
||||||
|
items.push({ key: 'assignRole', label: '分配角色' })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAuth('account:edit')) {
|
||||||
|
items.push({ key: 'edit', label: '编辑' })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAuth('account:delete')) {
|
||||||
|
items.push({ key: 'delete', label: '删除' })
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理表格行右键菜单
|
||||||
|
const handleRowContextMenu = (row: any, 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 'assignRole':
|
||||||
|
showRoleDialog(currentRow.value)
|
||||||
|
break
|
||||||
|
case 'edit':
|
||||||
|
showDialog('edit', currentRow.value)
|
||||||
|
break
|
||||||
|
case 'delete':
|
||||||
|
deleteAccount(currentRow.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -97,7 +97,8 @@
|
|||||||
<ElInput v-model="form.district" placeholder="请输入区县" />
|
<ElInput v-model="form.district" placeholder="请输入区县" />
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
</ElCol>
|
</ElCol>
|
||||||
<ElCol :span="12">
|
<!-- 只有非代理账号才显示归属店铺选择 -->
|
||||||
|
<ElCol :span="12" v-if="!isAgentAccount">
|
||||||
<ElFormItem label="归属店铺" prop="owner_shop_id">
|
<ElFormItem label="归属店铺" prop="owner_shop_id">
|
||||||
<ElSelect
|
<ElSelect
|
||||||
v-model="form.owner_shop_id"
|
v-model="form.owner_shop_id"
|
||||||
@@ -219,6 +220,7 @@
|
|||||||
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 { useAuth } from '@/composables/useAuth'
|
||||||
|
import { useUserStore } from '@/store/modules/user'
|
||||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||||
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||||||
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
||||||
@@ -227,9 +229,13 @@
|
|||||||
defineOptions({ name: 'EnterpriseCustomer' })
|
defineOptions({ name: 'EnterpriseCustomer' })
|
||||||
|
|
||||||
const { hasAuth } = useAuth()
|
const { hasAuth } = useAuth()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
// 判断是否是代理账号 (user_type === 3)
|
||||||
|
const isAgentAccount = computed(() => userStore.info.user_type === 3)
|
||||||
|
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const passwordDialogVisible = ref(false)
|
const passwordDialogVisible = ref(false)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@@ -488,7 +494,10 @@
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getTableData()
|
getTableData()
|
||||||
loadShopList()
|
// 只有非代理账号才需要加载店铺列表
|
||||||
|
if (!isAgentAccount.value) {
|
||||||
|
loadShopList()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 加载店铺列表(默认加载20条)
|
// 加载店铺列表(默认加载20条)
|
||||||
@@ -609,7 +618,8 @@
|
|||||||
form.contact_phone = ''
|
form.contact_phone = ''
|
||||||
form.login_phone = ''
|
form.login_phone = ''
|
||||||
form.password = ''
|
form.password = ''
|
||||||
form.owner_shop_id = null
|
// 如果是代理账号,自动设置归属店铺为当前登录用户的店铺
|
||||||
|
form.owner_shop_id = isAgentAccount.value ? userStore.info.shop_id : null
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置表单验证状态
|
// 重置表单验证状态
|
||||||
|
|||||||
@@ -30,12 +30,21 @@
|
|||||||
:marginTop="10"
|
:marginTop="10"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
|
@row-contextmenu="handleRowContextMenu"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||||
</template>
|
</template>
|
||||||
</ArtTable>
|
</ArtTable>
|
||||||
|
|
||||||
|
<!-- 右键菜单 -->
|
||||||
|
<ArtMenuRight
|
||||||
|
ref="contextMenuRef"
|
||||||
|
:menu-items="contextMenuItems"
|
||||||
|
:menu-width="120"
|
||||||
|
@select="handleContextMenuSelect"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 授权详情对话框 -->
|
<!-- 授权详情对话框 -->
|
||||||
<ElDialog v-model="detailDialogVisible" title="授权详情" width="700px">
|
<ElDialog v-model="detailDialogVisible" title="授权详情" width="700px">
|
||||||
<ElDescriptions v-if="currentRecord" :column="2" border>
|
<ElDescriptions v-if="currentRecord" :column="2" border>
|
||||||
@@ -119,6 +128,8 @@
|
|||||||
import { useAuth } from '@/composables/useAuth'
|
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 ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||||||
|
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
||||||
import type {
|
import type {
|
||||||
AuthorizationItem,
|
AuthorizationItem,
|
||||||
AuthorizationStatus,
|
AuthorizationStatus,
|
||||||
@@ -138,6 +149,8 @@
|
|||||||
const remarkFormRef = ref<FormInstance>()
|
const remarkFormRef = ref<FormInstance>()
|
||||||
const currentRecordId = ref<number>(0)
|
const currentRecordId = ref<number>(0)
|
||||||
const currentRecord = ref<AuthorizationItem | null>(null)
|
const currentRecord = ref<AuthorizationItem | null>(null)
|
||||||
|
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||||
|
const currentRow = ref<AuthorizationItem | null>(null)
|
||||||
|
|
||||||
// 搜索表单初始值
|
// 搜索表单初始值
|
||||||
const initialSearchState = {
|
const initialSearchState = {
|
||||||
@@ -227,8 +240,7 @@
|
|||||||
{ label: '授权人类型', prop: 'authorizer_type' },
|
{ label: '授权人类型', prop: 'authorizer_type' },
|
||||||
{ label: '授权时间', prop: 'authorized_at' },
|
{ label: '授权时间', prop: 'authorized_at' },
|
||||||
{ label: '状态', prop: 'status' },
|
{ label: '状态', prop: 'status' },
|
||||||
{ label: '备注', prop: 'remark' },
|
{ label: '备注', prop: 'remark' }
|
||||||
{ label: '操作', prop: 'operation' }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const authorizationList = ref<AuthorizationItem[]>([])
|
const authorizationList = ref<AuthorizationItem[]>([])
|
||||||
@@ -306,33 +318,6 @@
|
|||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
showOverflowTooltip: true,
|
showOverflowTooltip: true,
|
||||||
formatter: (row: AuthorizationItem) => row.remark || '-'
|
formatter: (row: AuthorizationItem) => row.remark || '-'
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: 'operation',
|
|
||||||
label: '操作',
|
|
||||||
width: 150,
|
|
||||||
fixed: 'right',
|
|
||||||
formatter: (row: AuthorizationItem) => {
|
|
||||||
const buttons = []
|
|
||||||
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '详情',
|
|
||||||
onClick: () => viewDetail(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
if (hasAuth('authorization_records:update_remark')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '编辑',
|
|
||||||
onClick: () => showRemarkDialog(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return h('div', { style: 'display: flex; gap: 8px;' }, buttons)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -443,6 +428,41 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 右键菜单项配置
|
||||||
|
const contextMenuItems = computed((): MenuItemType[] => {
|
||||||
|
const items: MenuItemType[] = []
|
||||||
|
|
||||||
|
items.push({ key: 'detail', label: '详情' })
|
||||||
|
|
||||||
|
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 'detail':
|
||||||
|
viewDetail(currentRow.value)
|
||||||
|
break
|
||||||
|
case 'edit':
|
||||||
|
showRemarkDialog(currentRow.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -41,11 +41,20 @@
|
|||||||
:marginTop="10"
|
:marginTop="10"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
|
@row-contextmenu="handleRowContextMenu"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||||
</template>
|
</template>
|
||||||
</ArtTable>
|
</ArtTable>
|
||||||
|
|
||||||
|
<!-- 右键菜单 -->
|
||||||
|
<ArtMenuRight
|
||||||
|
ref="contextMenuRef"
|
||||||
|
:menu-items="contextMenuItems"
|
||||||
|
:menu-width="120"
|
||||||
|
@select="handleContextMenuSelect"
|
||||||
|
/>
|
||||||
</ElCard>
|
</ElCard>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -223,6 +232,8 @@
|
|||||||
import { useAuth } from '@/composables/useAuth'
|
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 ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||||||
|
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
||||||
import { StorageService } from '@/api/modules/storage'
|
import { StorageService } from '@/api/modules/storage'
|
||||||
import type { DeviceImportTask, DeviceImportTaskStatus } from '@/types/api/device'
|
import type { DeviceImportTask, DeviceImportTaskStatus } from '@/types/api/device'
|
||||||
|
|
||||||
@@ -236,6 +247,8 @@
|
|||||||
const uploading = ref(false)
|
const uploading = ref(false)
|
||||||
const importDialogVisible = ref(false)
|
const importDialogVisible = ref(false)
|
||||||
const detailDialogVisible = ref(false)
|
const detailDialogVisible = ref(false)
|
||||||
|
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||||
|
const currentRow = ref<DeviceImportTask | null>(null)
|
||||||
|
|
||||||
// 搜索表单初始值
|
// 搜索表单初始值
|
||||||
const initialSearchState = {
|
const initialSearchState = {
|
||||||
@@ -306,8 +319,7 @@
|
|||||||
{ label: '开始时间', prop: 'started_at' },
|
{ label: '开始时间', prop: 'started_at' },
|
||||||
{ label: '完成时间', prop: 'completed_at' },
|
{ label: '完成时间', prop: 'completed_at' },
|
||||||
{ label: '错误信息', prop: 'error_message' },
|
{ label: '错误信息', prop: 'error_message' },
|
||||||
{ label: '创建时间', prop: 'created_at' },
|
{ label: '创建时间', prop: 'created_at' }
|
||||||
{ label: '操作', prop: 'operation' }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const taskList = ref<DeviceImportTask[]>([])
|
const taskList = ref<DeviceImportTask[]>([])
|
||||||
@@ -421,36 +433,6 @@
|
|||||||
label: '创建时间',
|
label: '创建时间',
|
||||||
width: 180,
|
width: 180,
|
||||||
formatter: (row: DeviceImportTask) => formatDateTime(row.created_at)
|
formatter: (row: DeviceImportTask) => formatDateTime(row.created_at)
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: 'operation',
|
|
||||||
label: '操作',
|
|
||||||
width: 180,
|
|
||||||
fixed: 'right',
|
|
||||||
formatter: (row: DeviceImportTask) => {
|
|
||||||
const buttons = []
|
|
||||||
|
|
||||||
// 显示"查看详情"按钮
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '详情',
|
|
||||||
onClick: () => viewDetail(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
// 如果有失败数据,显示"失败数据"按钮
|
|
||||||
if (row.fail_count > 0) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '失败数据',
|
|
||||||
type: 'danger',
|
|
||||||
onClick: () => downloadFailDataByRow(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return h('div', { style: 'display: flex; gap: 8px;' }, buttons)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -831,6 +813,43 @@
|
|||||||
|
|
||||||
ElMessage.success('失败数据下载成功')
|
ElMessage.success('失败数据下载成功')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 右键菜单项配置
|
||||||
|
const contextMenuItems = computed((): MenuItemType[] => {
|
||||||
|
if (!currentRow.value) return []
|
||||||
|
|
||||||
|
const items: MenuItemType[] = []
|
||||||
|
|
||||||
|
items.push({ key: 'detail', label: '详情' })
|
||||||
|
|
||||||
|
if (currentRow.value.fail_count > 0) {
|
||||||
|
items.push({ key: 'failData', label: '失败数据' })
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理表格行右键菜单
|
||||||
|
const handleRowContextMenu = (row: DeviceImportTask, 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':
|
||||||
|
viewDetail(currentRow.value)
|
||||||
|
break
|
||||||
|
case 'failData':
|
||||||
|
downloadFailDataByRow(currentRow.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -397,18 +397,14 @@
|
|||||||
<ElDescriptionsItem label="卡业务类型">{{
|
<ElDescriptionsItem label="卡业务类型">{{
|
||||||
getCardCategoryText(currentCardDetail.card_category)
|
getCardCategoryText(currentCardDetail.card_category)
|
||||||
}}</ElDescriptionsItem>
|
}}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="成本价">{{
|
|
||||||
formatCardPrice(currentCardDetail.cost_price)
|
|
||||||
}}</ElDescriptionsItem>
|
|
||||||
|
|
||||||
<ElDescriptionsItem label="分销价">{{
|
|
||||||
formatCardPrice(currentCardDetail.distribute_price)
|
|
||||||
}}</ElDescriptionsItem>
|
|
||||||
<ElDescriptionsItem label="状态">
|
<ElDescriptionsItem label="状态">
|
||||||
<ElTag :type="getCardDetailStatusTagType(currentCardDetail.status)">
|
<ElTag :type="getCardDetailStatusTagType(currentCardDetail.status)">
|
||||||
{{ getCardDetailStatusText(currentCardDetail.status) }}
|
{{ getCardDetailStatusText(currentCardDetail.status) }}
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</ElDescriptionsItem>
|
</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="套餐系列">{{
|
||||||
|
currentCardDetail.series_name || '--'
|
||||||
|
}}</ElDescriptionsItem>
|
||||||
<ElDescriptionsItem label="激活状态">
|
<ElDescriptionsItem label="激活状态">
|
||||||
<ElTag :type="currentCardDetail.activation_status === 1 ? 'success' : 'info'">
|
<ElTag :type="currentCardDetail.activation_status === 1 ? 'success' : 'info'">
|
||||||
{{ currentCardDetail.activation_status === 1 ? '已激活' : '未激活' }}
|
{{ currentCardDetail.activation_status === 1 ? '已激活' : '未激活' }}
|
||||||
@@ -863,8 +859,6 @@
|
|||||||
{ label: '运营商', prop: 'carrier_name' },
|
{ label: '运营商', prop: 'carrier_name' },
|
||||||
{ label: '店铺名称', prop: 'shop_name' },
|
{ label: '店铺名称', prop: 'shop_name' },
|
||||||
{ label: '套餐系列', prop: 'series_name' },
|
{ label: '套餐系列', prop: 'series_name' },
|
||||||
{ label: '成本价', prop: 'cost_price' },
|
|
||||||
{ label: '分销价', prop: 'distribute_price' },
|
|
||||||
{ label: '状态', prop: 'status' },
|
{ label: '状态', prop: 'status' },
|
||||||
{ label: '激活状态', prop: 'activation_status' },
|
{ label: '激活状态', prop: 'activation_status' },
|
||||||
{ label: '网络状态', prop: 'network_status' },
|
{ label: '网络状态', prop: 'network_status' },
|
||||||
@@ -1020,18 +1014,6 @@
|
|||||||
width: 150,
|
width: 150,
|
||||||
formatter: (row: StandaloneIotCard) => row.series_name || '-'
|
formatter: (row: StandaloneIotCard) => row.series_name || '-'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
prop: 'cost_price',
|
|
||||||
label: '成本价',
|
|
||||||
width: 100,
|
|
||||||
formatter: (row: StandaloneIotCard) => `¥${(row.cost_price / 100).toFixed(2)}`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: 'distribute_price',
|
|
||||||
label: '分销价',
|
|
||||||
width: 100,
|
|
||||||
formatter: (row: StandaloneIotCard) => `¥${(row.distribute_price / 100).toFixed(2)}`
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
prop: 'status',
|
prop: 'status',
|
||||||
label: '状态',
|
label: '状态',
|
||||||
|
|||||||
@@ -41,11 +41,20 @@
|
|||||||
:marginTop="10"
|
:marginTop="10"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
|
@row-contextmenu="handleRowContextMenu"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||||
</template>
|
</template>
|
||||||
</ArtTable>
|
</ArtTable>
|
||||||
|
|
||||||
|
<!-- 右键菜单 -->
|
||||||
|
<ArtMenuRight
|
||||||
|
ref="contextMenuRef"
|
||||||
|
:menu-items="contextMenuItems"
|
||||||
|
:menu-width="120"
|
||||||
|
@select="handleContextMenuSelect"
|
||||||
|
/>
|
||||||
</ElCard>
|
</ElCard>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -220,6 +229,8 @@
|
|||||||
import { useAuth } from '@/composables/useAuth'
|
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 ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||||||
|
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
||||||
import { StorageService } from '@/api/modules/storage'
|
import { StorageService } from '@/api/modules/storage'
|
||||||
import type { IotCardImportTask, IotCardImportTaskStatus } from '@/types/api/card'
|
import type { IotCardImportTask, IotCardImportTaskStatus } from '@/types/api/card'
|
||||||
import type { Carrier } from '@/types/api'
|
import type { Carrier } from '@/types/api'
|
||||||
@@ -237,6 +248,8 @@
|
|||||||
const selectedCarrierId = ref<number>()
|
const selectedCarrierId = ref<number>()
|
||||||
const carrierList = ref<Carrier[]>([])
|
const carrierList = ref<Carrier[]>([])
|
||||||
const carrierLoading = ref(false)
|
const carrierLoading = ref(false)
|
||||||
|
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||||
|
const currentRow = ref<IotCardImportTask | null>(null)
|
||||||
|
|
||||||
// 搜索表单初始值
|
// 搜索表单初始值
|
||||||
const initialSearchState = {
|
const initialSearchState = {
|
||||||
@@ -324,8 +337,7 @@
|
|||||||
{ label: '开始时间', prop: 'started_at' },
|
{ label: '开始时间', prop: 'started_at' },
|
||||||
{ label: '完成时间', prop: 'completed_at' },
|
{ label: '完成时间', prop: 'completed_at' },
|
||||||
{ label: '错误信息', prop: 'error_message' },
|
{ label: '错误信息', prop: 'error_message' },
|
||||||
{ label: '创建时间', prop: 'created_at' },
|
{ label: '创建时间', prop: 'created_at' }
|
||||||
{ label: '操作', prop: 'operation' }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const taskList = ref<IotCardImportTask[]>([])
|
const taskList = ref<IotCardImportTask[]>([])
|
||||||
@@ -445,36 +457,6 @@
|
|||||||
label: '创建时间',
|
label: '创建时间',
|
||||||
width: 180,
|
width: 180,
|
||||||
formatter: (row: IotCardImportTask) => formatDateTime(row.created_at)
|
formatter: (row: IotCardImportTask) => formatDateTime(row.created_at)
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: 'operation',
|
|
||||||
label: '操作',
|
|
||||||
width: 180,
|
|
||||||
fixed: 'right',
|
|
||||||
formatter: (row: IotCardImportTask) => {
|
|
||||||
const buttons = []
|
|
||||||
|
|
||||||
// 显示"查看详情"按钮
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '详情',
|
|
||||||
onClick: () => viewDetail(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
// 如果有失败数据,显示"失败数据"按钮
|
|
||||||
if (row.fail_count > 0) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '失败数据',
|
|
||||||
type: 'danger',
|
|
||||||
onClick: () => downloadFailDataByRow(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return h('div', { style: 'display: flex; gap: 8px;' }, buttons)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -827,6 +809,43 @@
|
|||||||
uploading.value = false
|
uploading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 右键菜单项配置
|
||||||
|
const contextMenuItems = computed((): MenuItemType[] => {
|
||||||
|
if (!currentRow.value) return []
|
||||||
|
|
||||||
|
const items: MenuItemType[] = []
|
||||||
|
|
||||||
|
items.push({ key: 'detail', label: '详情' })
|
||||||
|
|
||||||
|
if (currentRow.value.fail_count > 0) {
|
||||||
|
items.push({ key: 'failData', label: '失败数据' })
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理表格行右键菜单
|
||||||
|
const handleRowContextMenu = (row: IotCardImportTask, 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':
|
||||||
|
viewDetail(currentRow.value)
|
||||||
|
break
|
||||||
|
case 'failData':
|
||||||
|
downloadFailDataByRow(currentRow.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -48,11 +48,20 @@
|
|||||||
:marginTop="10"
|
:marginTop="10"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
|
@row-contextmenu="handleRowContextMenu"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||||
</template>
|
</template>
|
||||||
</ArtTable>
|
</ArtTable>
|
||||||
|
|
||||||
|
<!-- 右键菜单 -->
|
||||||
|
<ArtMenuRight
|
||||||
|
ref="contextMenuRef"
|
||||||
|
:menu-items="contextMenuItems"
|
||||||
|
:menu-width="120"
|
||||||
|
@select="handleContextMenuSelect"
|
||||||
|
/>
|
||||||
</ElCard>
|
</ElCard>
|
||||||
</div>
|
</div>
|
||||||
</ArtTableFullScreen>
|
</ArtTableFullScreen>
|
||||||
@@ -234,6 +243,8 @@
|
|||||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||||
import { useAuth } from '@/composables/useAuth'
|
import { useAuth } from '@/composables/useAuth'
|
||||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
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, formatMoney } from '@/utils/business/format'
|
import { formatDateTime, formatMoney } from '@/utils/business/format'
|
||||||
import {
|
import {
|
||||||
CommissionStatusMap,
|
CommissionStatusMap,
|
||||||
@@ -252,6 +263,8 @@
|
|||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
const summaryList = ref<ShopCommissionSummaryItem[]>([])
|
const summaryList = ref<ShopCommissionSummaryItem[]>([])
|
||||||
|
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||||
|
const currentRow = ref<ShopCommissionSummaryItem | null>(null)
|
||||||
|
|
||||||
// 搜索表单
|
// 搜索表单
|
||||||
const searchForm = reactive({
|
const searchForm = reactive({
|
||||||
@@ -302,8 +315,7 @@
|
|||||||
{ label: '冻结中', prop: 'frozen_commission' },
|
{ label: '冻结中', prop: 'frozen_commission' },
|
||||||
{ label: '提现中', prop: 'withdrawing_commission' },
|
{ label: '提现中', prop: 'withdrawing_commission' },
|
||||||
{ label: '已提现', prop: 'withdrawn_commission' },
|
{ label: '已提现', prop: 'withdrawn_commission' },
|
||||||
{ label: '未提现', prop: 'unwithdraw_commission' },
|
{ label: '未提现', prop: 'unwithdraw_commission' }
|
||||||
{ label: '操作', prop: 'operation' }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
// 动态列配置
|
// 动态列配置
|
||||||
@@ -376,24 +388,6 @@
|
|||||||
label: '未提现',
|
label: '未提现',
|
||||||
width: 120,
|
width: 120,
|
||||||
formatter: (row: ShopCommissionSummaryItem) => formatMoney(row.unwithdraw_commission)
|
formatter: (row: ShopCommissionSummaryItem) => formatMoney(row.unwithdraw_commission)
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: 'operation',
|
|
||||||
label: '操作',
|
|
||||||
width: 120,
|
|
||||||
fixed: 'right',
|
|
||||||
formatter: (row: ShopCommissionSummaryItem) => {
|
|
||||||
const buttons = []
|
|
||||||
if (hasAuth('agent_commission:detail')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '详情',
|
|
||||||
onClick: () => showDetail(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return h('div', { style: 'display: flex; gap: 8px;' }, buttons)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -567,6 +561,36 @@
|
|||||||
withdrawalPagination.page = newCurrentPage
|
withdrawalPagination.page = newCurrentPage
|
||||||
loadWithdrawalRecords()
|
loadWithdrawalRecords()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 右键菜单项配置
|
||||||
|
const contextMenuItems = computed((): MenuItemType[] => {
|
||||||
|
const items: MenuItemType[] = []
|
||||||
|
|
||||||
|
if (hasAuth('agent_commission:detail')) {
|
||||||
|
items.push({ key: 'detail', label: '详情' })
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理表格行右键菜单
|
||||||
|
const handleRowContextMenu = (row: ShopCommissionSummaryItem, 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':
|
||||||
|
showDetail(currentRow.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -36,12 +36,21 @@
|
|||||||
:marginTop="10"
|
:marginTop="10"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
|
@row-contextmenu="handleRowContextMenu"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||||
</template>
|
</template>
|
||||||
</ArtTable>
|
</ArtTable>
|
||||||
|
|
||||||
|
<!-- 右键菜单 -->
|
||||||
|
<ArtMenuRight
|
||||||
|
ref="contextMenuRef"
|
||||||
|
:menu-items="contextMenuItems"
|
||||||
|
:menu-width="120"
|
||||||
|
@select="handleContextMenuSelect"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 创建订单对话框 -->
|
<!-- 创建订单对话框 -->
|
||||||
<ElDialog
|
<ElDialog
|
||||||
v-model="createDialogVisible"
|
v-model="createDialogVisible"
|
||||||
@@ -284,6 +293,8 @@
|
|||||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||||
import { useAuth } from '@/composables/useAuth'
|
import { useAuth } from '@/composables/useAuth'
|
||||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
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 { formatDateTime } from '@/utils/business/format'
|
||||||
|
|
||||||
defineOptions({ name: 'OrderList' })
|
defineOptions({ name: 'OrderList' })
|
||||||
@@ -297,6 +308,8 @@
|
|||||||
const createDialogVisible = ref(false)
|
const createDialogVisible = ref(false)
|
||||||
const detailDialogVisible = ref(false)
|
const detailDialogVisible = ref(false)
|
||||||
const currentOrder = ref<Order | null>(null)
|
const currentOrder = ref<Order | null>(null)
|
||||||
|
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||||
|
const currentRow = ref<Order | null>(null)
|
||||||
|
|
||||||
// 搜索表单初始值
|
// 搜索表单初始值
|
||||||
const initialSearchState: OrderQueryParams = {
|
const initialSearchState: OrderQueryParams = {
|
||||||
@@ -379,8 +392,7 @@
|
|||||||
{ label: t('orderManagement.table.totalAmount'), prop: 'total_amount' },
|
{ label: t('orderManagement.table.totalAmount'), prop: 'total_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' }
|
||||||
{ label: t('orderManagement.table.operation'), prop: 'operation' }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const createFormRef = ref<FormInstance>()
|
const createFormRef = ref<FormInstance>()
|
||||||
@@ -624,29 +636,6 @@
|
|||||||
label: t('orderManagement.table.createdAt'),
|
label: t('orderManagement.table.createdAt'),
|
||||||
width: 180,
|
width: 180,
|
||||||
formatter: (row: Order) => formatDateTime(row.created_at)
|
formatter: (row: Order) => formatDateTime(row.created_at)
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: 'operation',
|
|
||||||
label: t('orderManagement.table.operation'),
|
|
||||||
width: 160,
|
|
||||||
fixed: 'right',
|
|
||||||
formatter: (row: Order) => {
|
|
||||||
return h('div', { style: 'display: flex; gap: 8px;' }, [
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '详情',
|
|
||||||
tooltip: t('orderManagement.actions.viewDetail'),
|
|
||||||
onClick: () => showOrderDetail(row)
|
|
||||||
}),
|
|
||||||
// 只有待支付和已支付的订单可以取消
|
|
||||||
row.payment_status === 1 || row.payment_status === 2
|
|
||||||
? h(ArtButtonTable, {
|
|
||||||
text: '删除',
|
|
||||||
tooltip: t('orderManagement.actions.cancel'),
|
|
||||||
onClick: () => handleCancelOrder(row)
|
|
||||||
})
|
|
||||||
: null
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -908,6 +897,44 @@
|
|||||||
// 用户取消操作
|
// 用户取消操作
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 右键菜单项配置
|
||||||
|
const contextMenuItems = computed((): MenuItemType[] => {
|
||||||
|
if (!currentRow.value) return []
|
||||||
|
|
||||||
|
const items: MenuItemType[] = []
|
||||||
|
|
||||||
|
items.push({ key: 'detail', label: '详情' })
|
||||||
|
|
||||||
|
// 只有待支付和已支付的订单可以取消
|
||||||
|
if (currentRow.value.payment_status === 1 || currentRow.value.payment_status === 2) {
|
||||||
|
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>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -37,12 +37,21 @@
|
|||||||
:marginTop="10"
|
:marginTop="10"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
|
@row-contextmenu="handleRowContextMenu"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||||
</template>
|
</template>
|
||||||
</ArtTable>
|
</ArtTable>
|
||||||
|
|
||||||
|
<!-- 右键菜单 -->
|
||||||
|
<ArtMenuRight
|
||||||
|
ref="contextMenuRef"
|
||||||
|
:menu-items="contextMenuItems"
|
||||||
|
:menu-width="120"
|
||||||
|
@select="handleContextMenuSelect"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 新增/编辑对话框 -->
|
<!-- 新增/编辑对话框 -->
|
||||||
<ElDialog
|
<ElDialog
|
||||||
v-model="dialogVisible"
|
v-model="dialogVisible"
|
||||||
@@ -128,6 +137,8 @@
|
|||||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||||
import { useAuth } from '@/composables/useAuth'
|
import { useAuth } from '@/composables/useAuth'
|
||||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
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 { formatDateTime } from '@/utils/business/format'
|
||||||
import { RoutesAlias } from '@/router/routesAlias'
|
import { RoutesAlias } from '@/router/routesAlias'
|
||||||
import {
|
import {
|
||||||
@@ -149,6 +160,8 @@
|
|||||||
const shopLoading = ref(false)
|
const shopLoading = ref(false)
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
|
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||||
|
const currentRow = ref<ShopPackageAllocationResponse | null>(null)
|
||||||
const packageOptions = ref<PackageResponse[]>([])
|
const packageOptions = ref<PackageResponse[]>([])
|
||||||
const shopOptions = ref<ShopResponse[]>([])
|
const shopOptions = ref<ShopResponse[]>([])
|
||||||
const shopTreeData = ref<ShopResponse[]>([])
|
const shopTreeData = ref<ShopResponse[]>([])
|
||||||
@@ -276,8 +289,7 @@
|
|||||||
{ label: '分配者', prop: 'allocator_shop_name' },
|
{ label: '分配者', prop: 'allocator_shop_name' },
|
||||||
{ label: '成本价', prop: 'cost_price' },
|
{ label: '成本价', prop: 'cost_price' },
|
||||||
{ label: '状态', prop: 'status' },
|
{ label: '状态', prop: 'status' },
|
||||||
{ label: '创建时间', prop: 'created_at' },
|
{ label: '创建时间', prop: 'created_at' }
|
||||||
{ label: '操作', prop: 'operation' }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
// 表单验证规则
|
// 表单验证规则
|
||||||
@@ -389,45 +401,35 @@
|
|||||||
label: '创建时间',
|
label: '创建时间',
|
||||||
width: 180,
|
width: 180,
|
||||||
formatter: (row: ShopPackageAllocationResponse) => formatDateTime(row.created_at)
|
formatter: (row: ShopPackageAllocationResponse) => formatDateTime(row.created_at)
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: 'operation',
|
|
||||||
label: '操作',
|
|
||||||
width: 220,
|
|
||||||
fixed: 'right',
|
|
||||||
formatter: (row: ShopPackageAllocationResponse) => {
|
|
||||||
const buttons = []
|
|
||||||
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '详情',
|
|
||||||
onClick: () => handleViewDetail(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
if (hasAuth('package_assign:edit')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '编辑',
|
|
||||||
onClick: () => showDialog('edit', row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasAuth('package_assign:delete')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '删除',
|
|
||||||
onClick: () => deleteAllocation(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return h('div', { style: 'display: flex; gap: 8px;' }, buttons)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
// 右键菜单项配置
|
||||||
|
const contextMenuItems = computed((): MenuItemType[] => {
|
||||||
|
const items: MenuItemType[] = []
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
key: 'detail',
|
||||||
|
label: '详情'
|
||||||
|
})
|
||||||
|
|
||||||
|
if (hasAuth('package_assign:edit')) {
|
||||||
|
items.push({
|
||||||
|
key: 'edit',
|
||||||
|
label: '编辑'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAuth('package_assign:delete')) {
|
||||||
|
items.push({
|
||||||
|
key: 'delete',
|
||||||
|
label: '删除'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
})
|
||||||
|
|
||||||
// 构建树形结构数据
|
// 构建树形结构数据
|
||||||
const buildTreeData = (items: ShopResponse[]) => {
|
const buildTreeData = (items: ShopResponse[]) => {
|
||||||
const map = new Map<number, ShopResponse & { children?: ShopResponse[] }>()
|
const map = new Map<number, ShopResponse & { children?: ShopResponse[] }>()
|
||||||
@@ -478,7 +480,7 @@
|
|||||||
}
|
}
|
||||||
const res = await PackageManageService.getPackages(params)
|
const res = await PackageManageService.getPackages(params)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
packageOptions.value = res.data.items || []
|
packageOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载套餐选项失败:', error)
|
console.error('加载套餐选项失败:', error)
|
||||||
@@ -497,7 +499,7 @@
|
|||||||
page_size: 10000 // 使用较大的值获取所有店铺
|
page_size: 10000 // 使用较大的值获取所有店铺
|
||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
shopOptions.value = res.data.items || []
|
shopOptions.value = res.data.items
|
||||||
// 构建树形结构数据
|
// 构建树形结构数据
|
||||||
shopTreeData.value = buildTreeData(shopOptions.value)
|
shopTreeData.value = buildTreeData(shopOptions.value)
|
||||||
}
|
}
|
||||||
@@ -516,7 +518,7 @@
|
|||||||
page_size: 10
|
page_size: 10
|
||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchPackageOptions.value = res.data.items || []
|
searchPackageOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载搜索栏套餐选项失败:', error)
|
console.error('加载搜索栏套餐选项失败:', error)
|
||||||
@@ -528,7 +530,7 @@
|
|||||||
try {
|
try {
|
||||||
const res = await ShopService.getShops({ page: 1, page_size: 10 })
|
const res = await ShopService.getShops({ page: 1, page_size: 10 })
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchShopOptions.value = res.data.items || []
|
searchShopOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载搜索栏店铺选项失败:', error)
|
console.error('加载搜索栏店铺选项失败:', error)
|
||||||
@@ -557,7 +559,7 @@
|
|||||||
package_name: query
|
package_name: query
|
||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchPackageOptions.value = res.data.items || []
|
searchPackageOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('搜索套餐失败:', error)
|
console.error('搜索套餐失败:', error)
|
||||||
@@ -577,7 +579,7 @@
|
|||||||
shop_name: query
|
shop_name: query
|
||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchShopOptions.value = res.data.items || []
|
searchShopOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('搜索店铺失败:', error)
|
console.error('搜索店铺失败:', error)
|
||||||
@@ -589,7 +591,7 @@
|
|||||||
try {
|
try {
|
||||||
const res = await ShopService.getShops({ page: 1, page_size: 10 })
|
const res = await ShopService.getShops({ page: 1, page_size: 10 })
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchAllocatorShopOptions.value = res.data.items || []
|
searchAllocatorShopOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载搜索栏分配者店铺选项失败:', error)
|
console.error('加载搜索栏分配者店铺选项失败:', error)
|
||||||
@@ -609,7 +611,7 @@
|
|||||||
shop_name: query
|
shop_name: query
|
||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchAllocatorShopOptions.value = res.data.items || []
|
searchAllocatorShopOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('搜索分配者店铺失败:', error)
|
console.error('搜索分配者店铺失败:', error)
|
||||||
@@ -624,7 +626,7 @@
|
|||||||
page_size: 10
|
page_size: 10
|
||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchSeriesAllocationOptions.value = res.data.items || []
|
searchSeriesAllocationOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载搜索栏系列分配选项失败:', error)
|
console.error('加载搜索栏系列分配选项失败:', error)
|
||||||
@@ -644,7 +646,7 @@
|
|||||||
series_name: query
|
series_name: query
|
||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchSeriesAllocationOptions.value = res.data.items || []
|
searchSeriesAllocationOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('搜索系列分配失败:', error)
|
console.error('搜索系列分配失败:', error)
|
||||||
@@ -666,7 +668,7 @@
|
|||||||
}
|
}
|
||||||
const res = await ShopPackageAllocationService.getShopPackageAllocations(params)
|
const res = await ShopPackageAllocationService.getShopPackageAllocations(params)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
allocationList.value = res.data.items || []
|
allocationList.value = res.data.items
|
||||||
pagination.total = res.data.total || 0
|
pagination.total = res.data.total || 0
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -845,6 +847,31 @@
|
|||||||
const handleViewDetail = (row: ShopPackageAllocationResponse) => {
|
const handleViewDetail = (row: ShopPackageAllocationResponse) => {
|
||||||
router.push(`${RoutesAlias.PackageAssignDetail}/${row.id}`)
|
router.push(`${RoutesAlias.PackageAssignDetail}/${row.id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理表格行右键菜单
|
||||||
|
const handleRowContextMenu = (row: ShopPackageAllocationResponse, 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':
|
||||||
|
handleViewDetail(currentRow.value)
|
||||||
|
break
|
||||||
|
case 'edit':
|
||||||
|
showDialog('edit', currentRow.value)
|
||||||
|
break
|
||||||
|
case 'delete':
|
||||||
|
deleteAllocation(currentRow.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -68,6 +68,43 @@
|
|||||||
return `${data.duration_months} 个月`
|
return `${data.duration_months} 个月`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '套餐周期类型',
|
||||||
|
formatter: (_, data) => {
|
||||||
|
if (!data.calendar_type) return '-'
|
||||||
|
const typeMap = {
|
||||||
|
natural_month: '自然月',
|
||||||
|
by_day: '按天'
|
||||||
|
}
|
||||||
|
return typeMap[data.calendar_type] || data.calendar_type
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '套餐天数',
|
||||||
|
formatter: (_, data) => {
|
||||||
|
if (data.calendar_type !== 'by_day' || !data.duration_days) return '-'
|
||||||
|
return `${data.duration_days} 天`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '流量重置周期',
|
||||||
|
formatter: (_, data) => {
|
||||||
|
if (!data.data_reset_cycle) return '-'
|
||||||
|
const cycleMap = {
|
||||||
|
daily: '每日',
|
||||||
|
monthly: '每月',
|
||||||
|
yearly: '每年',
|
||||||
|
none: '不重置'
|
||||||
|
}
|
||||||
|
return cycleMap[data.data_reset_cycle] || data.data_reset_cycle
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '启用实名激活',
|
||||||
|
formatter: (_, data) => {
|
||||||
|
return data.enable_realname_activation ? '是' : '否'
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '状态',
|
label: '状态',
|
||||||
formatter: (_, data) => {
|
formatter: (_, data) => {
|
||||||
@@ -141,12 +178,6 @@
|
|||||||
{
|
{
|
||||||
title: '佣金配置',
|
title: '佣金配置',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
|
||||||
label: '当前返佣比例',
|
|
||||||
formatter: (_, data) => {
|
|
||||||
return data.current_commission_rate || '-'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: '一次性佣金金额',
|
label: '一次性佣金金额',
|
||||||
formatter: (_, data) => {
|
formatter: (_, data) => {
|
||||||
@@ -159,7 +190,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '当前返佣档位',
|
label: '当前返佣比例',
|
||||||
formatter: (_, data) => {
|
formatter: (_, data) => {
|
||||||
if (!data.tier_info || !data.tier_info.current_rate) return '-'
|
if (!data.tier_info || !data.tier_info.current_rate) return '-'
|
||||||
return data.tier_info.current_rate
|
return data.tier_info.current_rate
|
||||||
|
|||||||
@@ -36,12 +36,21 @@
|
|||||||
:marginTop="10"
|
:marginTop="10"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
|
@row-contextmenu="handleRowContextMenu"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||||
</template>
|
</template>
|
||||||
</ArtTable>
|
</ArtTable>
|
||||||
|
|
||||||
|
<!-- 右键菜单 -->
|
||||||
|
<ArtMenuRight
|
||||||
|
ref="contextMenuRef"
|
||||||
|
:menu-items="contextMenuItems"
|
||||||
|
:menu-width="120"
|
||||||
|
@select="handleContextMenuSelect"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 新增/编辑对话框 -->
|
<!-- 新增/编辑对话框 -->
|
||||||
<ElDialog
|
<ElDialog
|
||||||
v-model="dialogVisible"
|
v-model="dialogVisible"
|
||||||
@@ -101,6 +110,54 @@
|
|||||||
/>
|
/>
|
||||||
</ElSelect>
|
</ElSelect>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
|
<ElFormItem label="套餐周期类型" prop="calendar_type">
|
||||||
|
<ElSelect
|
||||||
|
v-model="form.calendar_type"
|
||||||
|
placeholder="请选择套餐周期类型"
|
||||||
|
style="width: 100%"
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<ElOption label="自然月" value="natural_month" />
|
||||||
|
<ElOption label="按天" value="by_day" />
|
||||||
|
</ElSelect>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem label="有效期(月)" prop="duration_months">
|
||||||
|
<ElInputNumber
|
||||||
|
v-model="form.duration_months"
|
||||||
|
:min="1"
|
||||||
|
:max="120"
|
||||||
|
:controls="false"
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="请输入有效期(月)"
|
||||||
|
/>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem
|
||||||
|
v-if="form.calendar_type === 'by_day'"
|
||||||
|
label="套餐天数"
|
||||||
|
prop="duration_days"
|
||||||
|
>
|
||||||
|
<ElInputNumber
|
||||||
|
v-model="form.duration_days"
|
||||||
|
:min="1"
|
||||||
|
:max="3650"
|
||||||
|
:controls="false"
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="请输入套餐天数"
|
||||||
|
/>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem label="流量重置周期" prop="data_reset_cycle">
|
||||||
|
<ElSelect
|
||||||
|
v-model="form.data_reset_cycle"
|
||||||
|
placeholder="请选择流量重置周期"
|
||||||
|
style="width: 100%"
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<ElOption label="每日" value="daily" />
|
||||||
|
<ElOption label="每月" value="monthly" />
|
||||||
|
<ElOption label="每年" value="yearly" />
|
||||||
|
<ElOption label="不重置" value="none" />
|
||||||
|
</ElSelect>
|
||||||
|
</ElFormItem>
|
||||||
<ElFormItem label="真流量额度(MB)" prop="real_data_mb">
|
<ElFormItem label="真流量额度(MB)" prop="real_data_mb">
|
||||||
<ElInputNumber
|
<ElInputNumber
|
||||||
v-model="form.real_data_mb"
|
v-model="form.real_data_mb"
|
||||||
@@ -130,13 +187,11 @@
|
|||||||
placeholder="请输入虚流量额度"
|
placeholder="请输入虚流量额度"
|
||||||
/>
|
/>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem label="有效期(月)" prop="duration_months">
|
<ElFormItem label="启用实名激活">
|
||||||
<ElInputNumber
|
<ElSwitch
|
||||||
v-model="form.duration_months"
|
v-model="form.enable_realname_activation"
|
||||||
:min="1"
|
active-text="启用"
|
||||||
:max="120"
|
inactive-text="不启用"
|
||||||
:controls="false"
|
|
||||||
style="width: 100%"
|
|
||||||
/>
|
/>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem label="成本价(元)" prop="cost_price">
|
<ElFormItem label="成本价(元)" prop="cost_price">
|
||||||
@@ -197,6 +252,8 @@
|
|||||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||||
import { useAuth } from '@/composables/useAuth'
|
import { useAuth } from '@/composables/useAuth'
|
||||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
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 { formatDateTime } from '@/utils/business/format'
|
||||||
import { RoutesAlias } from '@/router/routesAlias'
|
import { RoutesAlias } from '@/router/routesAlias'
|
||||||
import {
|
import {
|
||||||
@@ -221,6 +278,8 @@
|
|||||||
const seriesLoading = ref(false)
|
const seriesLoading = ref(false)
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
|
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||||
|
const currentRow = ref<PackageResponse | null>(null)
|
||||||
const seriesOptions = ref<SeriesSelectOption[]>([])
|
const seriesOptions = ref<SeriesSelectOption[]>([])
|
||||||
const searchSeriesOptions = ref<SeriesSelectOption[]>([])
|
const searchSeriesOptions = ref<SeriesSelectOption[]>([])
|
||||||
|
|
||||||
@@ -327,8 +386,7 @@
|
|||||||
{ label: '建议售价', prop: 'suggested_retail_price' },
|
{ label: '建议售价', prop: 'suggested_retail_price' },
|
||||||
{ label: '上架状态', prop: 'shelf_status' },
|
{ label: '上架状态', prop: 'shelf_status' },
|
||||||
{ label: '状态', prop: 'status' },
|
{ label: '状态', prop: 'status' },
|
||||||
{ label: '创建时间', prop: 'created_at' },
|
{ label: '创建时间', prop: 'created_at' }
|
||||||
{ label: '操作', prop: 'operation' }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
// 表单验证规则
|
// 表单验证规则
|
||||||
@@ -355,6 +413,14 @@
|
|||||||
baseRules.virtual_data_mb = [{ required: true, message: '请输入虚流量额度', trigger: 'blur' }]
|
baseRules.virtual_data_mb = [{ required: true, message: '请输入虚流量额度', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果套餐周期类型是按天,则套餐天数为必填
|
||||||
|
if (form.calendar_type === 'by_day') {
|
||||||
|
baseRules.duration_days = [
|
||||||
|
{ required: true, message: '请输入套餐天数', trigger: 'blur' },
|
||||||
|
{ type: 'number', min: 1, max: 3650, message: '套餐天数范围 1-3650 天', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
return baseRules
|
return baseRules
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -365,10 +431,14 @@
|
|||||||
package_name: '',
|
package_name: '',
|
||||||
series_id: undefined,
|
series_id: undefined,
|
||||||
package_type: '',
|
package_type: '',
|
||||||
|
calendar_type: undefined,
|
||||||
|
duration_days: undefined,
|
||||||
|
duration_months: 1,
|
||||||
|
data_reset_cycle: undefined,
|
||||||
enable_virtual_data: false,
|
enable_virtual_data: false,
|
||||||
|
enable_realname_activation: false,
|
||||||
real_data_mb: 0,
|
real_data_mb: 0,
|
||||||
virtual_data_mb: 0,
|
virtual_data_mb: 0,
|
||||||
duration_months: 1,
|
|
||||||
cost_price: 0,
|
cost_price: 0,
|
||||||
suggested_retail_price: undefined,
|
suggested_retail_price: undefined,
|
||||||
description: ''
|
description: ''
|
||||||
@@ -388,12 +458,14 @@
|
|||||||
{
|
{
|
||||||
prop: 'package_name',
|
prop: 'package_name',
|
||||||
label: '套餐名称',
|
label: '套餐名称',
|
||||||
minWidth: 160
|
minWidth: 160,
|
||||||
|
showOverflowTooltip: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'series_name',
|
prop: 'series_name',
|
||||||
label: '所属系列',
|
label: '所属系列',
|
||||||
width: 120
|
width: 160,
|
||||||
|
showOverflowTooltip: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'package_type',
|
prop: 'package_type',
|
||||||
@@ -476,45 +548,35 @@
|
|||||||
label: '创建时间',
|
label: '创建时间',
|
||||||
width: 180,
|
width: 180,
|
||||||
formatter: (row: PackageResponse) => formatDateTime(row.created_at)
|
formatter: (row: PackageResponse) => formatDateTime(row.created_at)
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: 'operation',
|
|
||||||
label: '操作',
|
|
||||||
width: 220,
|
|
||||||
fixed: 'right',
|
|
||||||
formatter: (row: PackageResponse) => {
|
|
||||||
const buttons = []
|
|
||||||
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '详情',
|
|
||||||
onClick: () => handleViewDetail(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
if (hasAuth('package:edit')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '编辑',
|
|
||||||
onClick: () => showDialog('edit', row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasAuth('package:delete')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '删除',
|
|
||||||
onClick: () => deletePackage(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return h('div', { style: 'display: flex; gap: 8px;' }, buttons)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
// 右键菜单项配置
|
||||||
|
const contextMenuItems = computed((): MenuItemType[] => {
|
||||||
|
const items: MenuItemType[] = []
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
key: 'detail',
|
||||||
|
label: '详情'
|
||||||
|
})
|
||||||
|
|
||||||
|
if (hasAuth('package:edit')) {
|
||||||
|
items.push({
|
||||||
|
key: 'edit',
|
||||||
|
label: '编辑'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAuth('package:delete')) {
|
||||||
|
items.push({
|
||||||
|
key: 'delete',
|
||||||
|
label: '删除'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
})
|
||||||
|
|
||||||
// 监听虚流量开关变化,关闭时重置虚流量额度
|
// 监听虚流量开关变化,关闭时重置虚流量额度
|
||||||
watch(
|
watch(
|
||||||
() => form.enable_virtual_data,
|
() => form.enable_virtual_data,
|
||||||
@@ -545,7 +607,7 @@
|
|||||||
}
|
}
|
||||||
const res = await PackageSeriesService.getPackageSeries(params)
|
const res = await PackageSeriesService.getPackageSeries(params)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
seriesOptions.value = res.data.items || []
|
seriesOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载系列选项失败:', error)
|
console.error('加载系列选项失败:', error)
|
||||||
@@ -567,7 +629,7 @@
|
|||||||
}
|
}
|
||||||
const res = await PackageSeriesService.getPackageSeries(params)
|
const res = await PackageSeriesService.getPackageSeries(params)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchSeriesOptions.value = res.data.items || []
|
searchSeriesOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载搜索栏系列选项失败:', error)
|
console.error('加载搜索栏系列选项失败:', error)
|
||||||
@@ -607,8 +669,8 @@
|
|||||||
}
|
}
|
||||||
const res = await PackageManageService.getPackages(params)
|
const res = await PackageManageService.getPackages(params)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
packageList.value = res.data.items || []
|
packageList.value = res.data.items
|
||||||
pagination.total = res.data.total || 0
|
pagination.total = res.data.total
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
@@ -658,10 +720,14 @@
|
|||||||
form.package_name = row.package_name
|
form.package_name = row.package_name
|
||||||
form.series_id = row.series_id
|
form.series_id = row.series_id
|
||||||
form.package_type = row.package_type
|
form.package_type = row.package_type
|
||||||
|
form.calendar_type = row.calendar_type || undefined
|
||||||
|
form.duration_days = row.duration_days || undefined
|
||||||
|
form.duration_months = row.duration_months
|
||||||
|
form.data_reset_cycle = row.data_reset_cycle || undefined
|
||||||
form.enable_virtual_data = row.enable_virtual_data || false
|
form.enable_virtual_data = row.enable_virtual_data || false
|
||||||
|
form.enable_realname_activation = row.enable_realname_activation || false
|
||||||
form.real_data_mb = row.real_data_mb || 0
|
form.real_data_mb = row.real_data_mb || 0
|
||||||
form.virtual_data_mb = row.virtual_data_mb || 0
|
form.virtual_data_mb = row.virtual_data_mb || 0
|
||||||
form.duration_months = row.duration_months
|
|
||||||
form.cost_price = row.cost_price / 100 // 分转换为元显示
|
form.cost_price = row.cost_price / 100 // 分转换为元显示
|
||||||
form.suggested_retail_price = row.suggested_retail_price
|
form.suggested_retail_price = row.suggested_retail_price
|
||||||
? row.suggested_retail_price / 100
|
? row.suggested_retail_price / 100
|
||||||
@@ -673,10 +739,14 @@
|
|||||||
form.package_name = ''
|
form.package_name = ''
|
||||||
form.series_id = undefined
|
form.series_id = undefined
|
||||||
form.package_type = ''
|
form.package_type = ''
|
||||||
|
form.calendar_type = undefined
|
||||||
|
form.duration_days = undefined
|
||||||
|
form.duration_months = 1
|
||||||
|
form.data_reset_cycle = undefined
|
||||||
form.enable_virtual_data = false
|
form.enable_virtual_data = false
|
||||||
|
form.enable_realname_activation = false
|
||||||
form.real_data_mb = 0
|
form.real_data_mb = 0
|
||||||
form.virtual_data_mb = 0
|
form.virtual_data_mb = 0
|
||||||
form.duration_months = 1
|
|
||||||
form.cost_price = 0
|
form.cost_price = 0
|
||||||
form.suggested_retail_price = undefined
|
form.suggested_retail_price = undefined
|
||||||
form.description = ''
|
form.description = ''
|
||||||
@@ -708,10 +778,14 @@
|
|||||||
form.package_name = ''
|
form.package_name = ''
|
||||||
form.series_id = undefined
|
form.series_id = undefined
|
||||||
form.package_type = ''
|
form.package_type = ''
|
||||||
|
form.calendar_type = undefined
|
||||||
|
form.duration_days = undefined
|
||||||
|
form.duration_months = 1
|
||||||
|
form.data_reset_cycle = undefined
|
||||||
form.enable_virtual_data = false
|
form.enable_virtual_data = false
|
||||||
|
form.enable_realname_activation = false
|
||||||
form.real_data_mb = 0
|
form.real_data_mb = 0
|
||||||
form.virtual_data_mb = 0
|
form.virtual_data_mb = 0
|
||||||
form.duration_months = 1
|
|
||||||
form.cost_price = 0
|
form.cost_price = 0
|
||||||
form.suggested_retail_price = undefined
|
form.suggested_retail_price = undefined
|
||||||
form.description = ''
|
form.description = ''
|
||||||
@@ -758,13 +832,23 @@
|
|||||||
package_type: form.package_type,
|
package_type: form.package_type,
|
||||||
duration_months: form.duration_months,
|
duration_months: form.duration_months,
|
||||||
cost_price: costPriceInCents,
|
cost_price: costPriceInCents,
|
||||||
enable_virtual_data: form.enable_virtual_data
|
enable_virtual_data: form.enable_virtual_data || false,
|
||||||
|
enable_realname_activation: form.enable_realname_activation || false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 可选字段
|
// 可选字段
|
||||||
if (form.series_id) {
|
if (form.series_id) {
|
||||||
data.series_id = form.series_id
|
data.series_id = form.series_id
|
||||||
}
|
}
|
||||||
|
if (form.calendar_type) {
|
||||||
|
data.calendar_type = form.calendar_type
|
||||||
|
}
|
||||||
|
if (form.calendar_type === 'by_day' && form.duration_days) {
|
||||||
|
data.duration_days = form.duration_days
|
||||||
|
}
|
||||||
|
if (form.data_reset_cycle) {
|
||||||
|
data.data_reset_cycle = form.data_reset_cycle
|
||||||
|
}
|
||||||
if (suggestedRetailPriceInCents !== undefined) {
|
if (suggestedRetailPriceInCents !== undefined) {
|
||||||
data.suggested_retail_price = suggestedRetailPriceInCents
|
data.suggested_retail_price = suggestedRetailPriceInCents
|
||||||
}
|
}
|
||||||
@@ -826,6 +910,31 @@
|
|||||||
const handleViewDetail = (row: PackageResponse) => {
|
const handleViewDetail = (row: PackageResponse) => {
|
||||||
router.push(`${RoutesAlias.PackageDetail}/${row.id}`)
|
router.push(`${RoutesAlias.PackageDetail}/${row.id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理表格行右键菜单
|
||||||
|
const handleRowContextMenu = (row: PackageResponse, 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':
|
||||||
|
handleViewDetail(currentRow.value)
|
||||||
|
break
|
||||||
|
case 'edit':
|
||||||
|
showDialog('edit', currentRow.value)
|
||||||
|
break
|
||||||
|
case 'delete':
|
||||||
|
deletePackage(currentRow.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -44,28 +44,13 @@
|
|||||||
</template>
|
</template>
|
||||||
</ArtTable>
|
</ArtTable>
|
||||||
|
|
||||||
<!-- 右键菜单 -->
|
<!-- 套餐系列操作右键菜单 -->
|
||||||
<div
|
<ArtMenuRight
|
||||||
v-if="contextMenuVisible"
|
ref="seriesOperationMenuRef"
|
||||||
:style="{
|
:menu-items="seriesOperationMenuItems"
|
||||||
position: 'fixed',
|
:menu-width="140"
|
||||||
left: contextMenuPosition.x + 'px',
|
@select="handleSeriesOperationMenuSelect"
|
||||||
top: contextMenuPosition.y + 'px',
|
/>
|
||||||
zIndex: 9999
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<ElCard shadow="always" class="context-menu">
|
|
||||||
<div class="context-menu-item" @click="handleViewDetail(contextMenuRow)" v-if="hasAuth('package_series:detail')">
|
|
||||||
<span>详情</span>
|
|
||||||
</div>
|
|
||||||
<div class="context-menu-item" @click="showDialog('edit', contextMenuRow)" v-if="hasAuth('package_series:edit')">
|
|
||||||
<span>编辑</span>
|
|
||||||
</div>
|
|
||||||
<div class="context-menu-item danger" @click="deleteSeries(contextMenuRow)" v-if="hasAuth('package_series:delete')">
|
|
||||||
<span>删除</span>
|
|
||||||
</div>
|
|
||||||
</ElCard>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 新增/编辑对话框 -->
|
<!-- 新增/编辑对话框 -->
|
||||||
<ElDialog
|
<ElDialog
|
||||||
@@ -389,6 +374,8 @@
|
|||||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||||
import { useAuth } from '@/composables/useAuth'
|
import { useAuth } from '@/composables/useAuth'
|
||||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
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 { formatDateTime } from '@/utils/business/format'
|
||||||
import {
|
import {
|
||||||
CommonStatus,
|
CommonStatus,
|
||||||
@@ -410,10 +397,9 @@
|
|||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
|
|
||||||
// 右键菜单状态
|
// 右键菜单
|
||||||
const contextMenuVisible = ref(false)
|
const seriesOperationMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||||
const contextMenuPosition = reactive({ x: 0, y: 0 })
|
const currentOperatingSeries = ref<PackageSeriesResponse | null>(null)
|
||||||
const contextMenuRow = ref<PackageSeriesResponse | null>(null)
|
|
||||||
|
|
||||||
// 搜索表单初始值
|
// 搜索表单初始值
|
||||||
const initialSearchState = {
|
const initialSearchState = {
|
||||||
@@ -708,27 +694,74 @@
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getTableData()
|
getTableData()
|
||||||
// 添加全局点击事件监听,关闭右键菜单
|
|
||||||
document.addEventListener('click', closeContextMenu)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
// 套餐系列操作菜单项配置
|
||||||
// 移除全局点击事件监听
|
const seriesOperationMenuItems = computed((): MenuItemType[] => {
|
||||||
document.removeEventListener('click', closeContextMenu)
|
const items: MenuItemType[] = []
|
||||||
|
|
||||||
|
// 详情
|
||||||
|
if (hasAuth('package_series:detail')) {
|
||||||
|
items.push({
|
||||||
|
key: 'detail',
|
||||||
|
label: '详情'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑
|
||||||
|
if (hasAuth('package_series:edit')) {
|
||||||
|
items.push({
|
||||||
|
key: 'edit',
|
||||||
|
label: '编辑'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
if (hasAuth('package_series:delete')) {
|
||||||
|
items.push({
|
||||||
|
key: 'delete',
|
||||||
|
label: '删除'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
})
|
})
|
||||||
|
|
||||||
// 处理右键菜单
|
// 显示套餐系列操作右键菜单
|
||||||
const handleRowContextMenu = (row: PackageSeriesResponse, column: any, event: MouseEvent) => {
|
const showSeriesOperationMenu = (e: MouseEvent, row: PackageSeriesResponse) => {
|
||||||
event.preventDefault()
|
e.preventDefault()
|
||||||
contextMenuRow.value = row
|
e.stopPropagation()
|
||||||
contextMenuPosition.x = event.clientX
|
currentOperatingSeries.value = row
|
||||||
contextMenuPosition.y = event.clientY
|
seriesOperationMenuRef.value?.show(e)
|
||||||
contextMenuVisible.value = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭右键菜单
|
// 处理表格行右键菜单
|
||||||
const closeContextMenu = () => {
|
const handleRowContextMenu = (row: PackageSeriesResponse, column: any, event: MouseEvent) => {
|
||||||
contextMenuVisible.value = false
|
// 如果用户有编辑或删除权限,显示右键菜单
|
||||||
|
if (
|
||||||
|
hasAuth('package_series:edit') ||
|
||||||
|
hasAuth('package_series:delete') ||
|
||||||
|
hasAuth('package_series:detail')
|
||||||
|
) {
|
||||||
|
showSeriesOperationMenu(event, row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理套餐系列操作菜单选择
|
||||||
|
const handleSeriesOperationMenuSelect = (item: MenuItemType) => {
|
||||||
|
if (!currentOperatingSeries.value) return
|
||||||
|
|
||||||
|
switch (item.key) {
|
||||||
|
case 'detail':
|
||||||
|
handleViewDetail(currentOperatingSeries.value)
|
||||||
|
break
|
||||||
|
case 'edit':
|
||||||
|
showDialog('edit', currentOperatingSeries.value)
|
||||||
|
break
|
||||||
|
case 'delete':
|
||||||
|
deleteSeries(currentOperatingSeries.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取套餐系列列表
|
// 获取套餐系列列表
|
||||||
@@ -744,8 +777,8 @@
|
|||||||
}
|
}
|
||||||
const res = await PackageSeriesService.getPackageSeries(params)
|
const res = await PackageSeriesService.getPackageSeries(params)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
seriesList.value = res.data.items || []
|
seriesList.value = res.data.items
|
||||||
pagination.total = res.data.total || 0
|
pagination.total = res.data.total
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
@@ -1058,35 +1091,4 @@
|
|||||||
.dialog-footer {
|
.dialog-footer {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-menu {
|
|
||||||
min-width: 120px;
|
|
||||||
padding: 4px 0;
|
|
||||||
background: white;
|
|
||||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
:deep(.el-card__body) {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu-item {
|
|
||||||
padding: 10px 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
font-size: 14px;
|
|
||||||
color: var(--el-text-color-primary);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--el-fill-color-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.danger {
|
|
||||||
color: var(--el-color-danger);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--el-color-danger-light-9);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -37,12 +37,21 @@
|
|||||||
:marginTop="10"
|
:marginTop="10"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
|
@row-contextmenu="handleRowContextMenu"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||||
</template>
|
</template>
|
||||||
</ArtTable>
|
</ArtTable>
|
||||||
|
|
||||||
|
<!-- 右键菜单 -->
|
||||||
|
<ArtMenuRight
|
||||||
|
ref="contextMenuRef"
|
||||||
|
:menu-items="contextMenuItems"
|
||||||
|
:menu-width="120"
|
||||||
|
@select="handleContextMenuSelect"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 新增/编辑对话框 -->
|
<!-- 新增/编辑对话框 -->
|
||||||
<ElDialog
|
<ElDialog
|
||||||
v-model="dialogVisible"
|
v-model="dialogVisible"
|
||||||
@@ -205,6 +214,8 @@
|
|||||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||||
import { useAuth } from '@/composables/useAuth'
|
import { useAuth } from '@/composables/useAuth'
|
||||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
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 { formatDateTime } from '@/utils/business/format'
|
||||||
import {
|
import {
|
||||||
CommonStatus,
|
CommonStatus,
|
||||||
@@ -225,6 +236,8 @@
|
|||||||
const shopLoading = ref(false)
|
const shopLoading = ref(false)
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
|
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||||
|
const currentRow = ref<ShopSeriesAllocationResponse | null>(null)
|
||||||
const seriesOptions = ref<PackageSeriesResponse[]>([])
|
const seriesOptions = ref<PackageSeriesResponse[]>([])
|
||||||
const shopOptions = ref<ShopResponse[]>([])
|
const shopOptions = ref<ShopResponse[]>([])
|
||||||
const shopTreeData = ref<ShopResponse[]>([])
|
const shopTreeData = ref<ShopResponse[]>([])
|
||||||
@@ -340,8 +353,7 @@
|
|||||||
{ label: '强充金额', prop: 'force_recharge_amount' },
|
{ label: '强充金额', prop: 'force_recharge_amount' },
|
||||||
{ label: '强充触发类型', prop: 'force_recharge_trigger_type' },
|
{ label: '强充触发类型', prop: 'force_recharge_trigger_type' },
|
||||||
{ label: '状态', prop: 'status' },
|
{ label: '状态', prop: 'status' },
|
||||||
{ label: '创建时间', prop: 'created_at' },
|
{ label: '创建时间', prop: 'created_at' }
|
||||||
{ label: '操作', prop: 'operation' }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
// 表单数据
|
// 表单数据
|
||||||
@@ -563,43 +575,6 @@
|
|||||||
label: '创建时间',
|
label: '创建时间',
|
||||||
width: 180,
|
width: 180,
|
||||||
formatter: (row: ShopSeriesAllocationResponse) => formatDateTime(row.created_at)
|
formatter: (row: ShopSeriesAllocationResponse) => formatDateTime(row.created_at)
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: 'operation',
|
|
||||||
label: '操作',
|
|
||||||
width: 220,
|
|
||||||
fixed: 'right',
|
|
||||||
formatter: (row: ShopSeriesAllocationResponse) => {
|
|
||||||
const buttons = []
|
|
||||||
|
|
||||||
// 详情按钮
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '详情',
|
|
||||||
onClick: () => handleViewDetail(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
if (hasAuth('series_assign:edit')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '编辑',
|
|
||||||
onClick: () => showDialog('edit', row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasAuth('series_assign:delete')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '删除',
|
|
||||||
onClick: () => deleteAllocation(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return h('div', { style: 'display: flex; gap: 8px;' }, buttons)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -653,7 +628,7 @@
|
|||||||
}
|
}
|
||||||
const res = await PackageSeriesService.getPackageSeries(params)
|
const res = await PackageSeriesService.getPackageSeries(params)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
seriesOptions.value = res.data.items || []
|
seriesOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载系列选项失败:', error)
|
console.error('加载系列选项失败:', error)
|
||||||
@@ -672,7 +647,7 @@
|
|||||||
page_size: 10000 // 使用较大的值获取所有店铺
|
page_size: 10000 // 使用较大的值获取所有店铺
|
||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
shopOptions.value = res.data.items || []
|
shopOptions.value = res.data.items
|
||||||
// 构建树形结构数据
|
// 构建树形结构数据
|
||||||
shopTreeData.value = buildTreeData(shopOptions.value)
|
shopTreeData.value = buildTreeData(shopOptions.value)
|
||||||
}
|
}
|
||||||
@@ -692,7 +667,7 @@
|
|||||||
status: 1
|
status: 1
|
||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchSeriesOptions.value = res.data.items || []
|
searchSeriesOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载搜索栏系列选项失败:', error)
|
console.error('加载搜索栏系列选项失败:', error)
|
||||||
@@ -704,7 +679,7 @@
|
|||||||
try {
|
try {
|
||||||
const res = await ShopService.getShops({ page: 1, page_size: 10 })
|
const res = await ShopService.getShops({ page: 1, page_size: 10 })
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchShopOptions.value = res.data.items || []
|
searchShopOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载搜索栏店铺选项失败:', error)
|
console.error('加载搜索栏店铺选项失败:', error)
|
||||||
@@ -716,7 +691,7 @@
|
|||||||
try {
|
try {
|
||||||
const res = await ShopService.getShops({ page: 1, page_size: 10 })
|
const res = await ShopService.getShops({ page: 1, page_size: 10 })
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchAllocatorShopOptions.value = res.data.items || []
|
searchAllocatorShopOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载搜索栏分配者店铺选项失败:', error)
|
console.error('加载搜索栏分配者店铺选项失败:', error)
|
||||||
@@ -746,7 +721,7 @@
|
|||||||
status: 1
|
status: 1
|
||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchSeriesOptions.value = res.data.items || []
|
searchSeriesOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('搜索系列失败:', error)
|
console.error('搜索系列失败:', error)
|
||||||
@@ -766,7 +741,7 @@
|
|||||||
shop_name: query
|
shop_name: query
|
||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchShopOptions.value = res.data.items || []
|
searchShopOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('搜索店铺失败:', error)
|
console.error('搜索店铺失败:', error)
|
||||||
@@ -786,7 +761,7 @@
|
|||||||
shop_name: query
|
shop_name: query
|
||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
searchAllocatorShopOptions.value = res.data.items || []
|
searchAllocatorShopOptions.value = res.data.items
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('搜索分配者店铺失败:', error)
|
console.error('搜索分配者店铺失败:', error)
|
||||||
@@ -808,7 +783,7 @@
|
|||||||
}
|
}
|
||||||
const res = await ShopSeriesAllocationService.getShopSeriesAllocations(params)
|
const res = await ShopSeriesAllocationService.getShopSeriesAllocations(params)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
allocationList.value = res.data.items || []
|
allocationList.value = res.data.items
|
||||||
pagination.total = res.data.total || 0
|
pagination.total = res.data.total || 0
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1011,6 +986,48 @@
|
|||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 右键菜单项配置
|
||||||
|
const contextMenuItems = computed((): MenuItemType[] => {
|
||||||
|
const items: MenuItemType[] = []
|
||||||
|
|
||||||
|
items.push({ key: 'detail', label: '详情' })
|
||||||
|
|
||||||
|
if (hasAuth('series_assign:edit')) {
|
||||||
|
items.push({ key: 'edit', label: '编辑' })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAuth('series_assign:delete')) {
|
||||||
|
items.push({ key: 'delete', label: '删除' })
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理表格行右键菜单
|
||||||
|
const handleRowContextMenu = (row: ShopSeriesAllocationResponse, 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':
|
||||||
|
handleViewDetail(currentRow.value)
|
||||||
|
break
|
||||||
|
case 'edit':
|
||||||
|
showDialog('edit', currentRow.value)
|
||||||
|
break
|
||||||
|
case 'delete':
|
||||||
|
deleteAllocation(currentRow.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -190,6 +190,7 @@
|
|||||||
{ label: '权限类型', prop: 'perm_type' },
|
{ label: '权限类型', prop: 'perm_type' },
|
||||||
{ label: '菜单路径', prop: 'url' },
|
{ label: '菜单路径', prop: 'url' },
|
||||||
{ label: '适用端口', prop: 'platform' },
|
{ label: '适用端口', prop: 'platform' },
|
||||||
|
// { label: '可用角色类型', prop: 'available_for_role_types' },
|
||||||
{ label: '状态', prop: 'status' },
|
{ label: '状态', prop: 'status' },
|
||||||
{ label: '排序', prop: 'sort' },
|
{ label: '排序', prop: 'sort' },
|
||||||
{ label: '操作', prop: 'operation' }
|
{ label: '操作', prop: 'operation' }
|
||||||
@@ -242,7 +243,7 @@
|
|||||||
{
|
{
|
||||||
prop: 'perm_name',
|
prop: 'perm_name',
|
||||||
label: '权限名称',
|
label: '权限名称',
|
||||||
width: 200
|
width: 240
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'perm_code',
|
prop: 'perm_code',
|
||||||
@@ -276,6 +277,24 @@
|
|||||||
return platformMap[row.platform || 'all'] || row.platform
|
return platformMap[row.platform || 'all'] || row.platform
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// prop: 'available_for_role_types',
|
||||||
|
// label: '可用角色类型',
|
||||||
|
// width: 160,
|
||||||
|
// formatter: (row: PermissionTreeNode) => {
|
||||||
|
// if (!row.available_for_role_types) {
|
||||||
|
// return '-'
|
||||||
|
// }
|
||||||
|
// const roleTypeMap: Record<string, string> = {
|
||||||
|
// '1': '平台角色',
|
||||||
|
// '2': '客户角色'
|
||||||
|
// }
|
||||||
|
// const types = row.available_for_role_types
|
||||||
|
// .split(',')
|
||||||
|
// .map((type) => roleTypeMap[type.trim()] || type)
|
||||||
|
// return types.join(', ')
|
||||||
|
// }
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
prop: 'status',
|
prop: 'status',
|
||||||
label: '状态',
|
label: '状态',
|
||||||
@@ -417,7 +436,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 显示对话框
|
// 显示对话框
|
||||||
const showDialog = (type: string, row?: PermissionTreeNode) => {
|
const showDialog = async (type: string, row?: PermissionTreeNode) => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
dialogType.value = type
|
dialogType.value = type
|
||||||
|
|
||||||
@@ -428,18 +447,35 @@
|
|||||||
if (type === 'edit' && row) {
|
if (type === 'edit' && row) {
|
||||||
currentRow.value = row
|
currentRow.value = row
|
||||||
currentPermissionId.value = row.id
|
currentPermissionId.value = row.id
|
||||||
// 需要从API获取完整的权限数据,因为树节点可能不包含所有字段
|
// 从API获取完整的权限数据(包含parent_id)
|
||||||
// 暂时使用树节点的数据
|
try {
|
||||||
Object.assign(form, {
|
const response = await PermissionService.getPermission(row.id)
|
||||||
perm_name: row.perm_name,
|
if (response.code === 0 && response.data) {
|
||||||
perm_code: row.perm_code,
|
Object.assign(form, {
|
||||||
perm_type: row.perm_type,
|
perm_name: response.data.perm_name,
|
||||||
parent_id: undefined, // 树结构中没有parent_id,需要从API获取
|
perm_code: response.data.perm_code,
|
||||||
url: row.url || '',
|
perm_type: response.data.perm_type,
|
||||||
platform: row.platform || 'all',
|
parent_id: response.data.parent_id || undefined,
|
||||||
sort: row.sort || 0,
|
url: response.data.url || '',
|
||||||
status: row.status ?? CommonStatus.ENABLED
|
platform: response.data.platform || 'all',
|
||||||
})
|
sort: response.data.sort || 0,
|
||||||
|
status: response.data.status ?? CommonStatus.ENABLED
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取权限详情失败:', error)
|
||||||
|
// 如果API获取失败,使用树节点数据作为备选
|
||||||
|
Object.assign(form, {
|
||||||
|
perm_name: row.perm_name,
|
||||||
|
perm_code: row.perm_code,
|
||||||
|
perm_type: row.perm_type,
|
||||||
|
parent_id: undefined,
|
||||||
|
url: row.url || '',
|
||||||
|
platform: row.platform || 'all',
|
||||||
|
sort: row.sort || 0,
|
||||||
|
status: row.status ?? CommonStatus.ENABLED
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
currentPermissionId.value = 0
|
currentPermissionId.value = 0
|
||||||
resetForm()
|
resetForm()
|
||||||
|
|||||||
@@ -34,12 +34,21 @@
|
|||||||
:marginTop="10"
|
:marginTop="10"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
|
@row-contextmenu="handleRowContextMenu"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||||
</template>
|
</template>
|
||||||
</ArtTable>
|
</ArtTable>
|
||||||
|
|
||||||
|
<!-- 右键菜单 -->
|
||||||
|
<ArtMenuRight
|
||||||
|
ref="contextMenuRef"
|
||||||
|
:menu-items="contextMenuItems"
|
||||||
|
:menu-width="120"
|
||||||
|
@select="handleContextMenuSelect"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 新增/编辑对话框 -->
|
<!-- 新增/编辑对话框 -->
|
||||||
<ElDialog
|
<ElDialog
|
||||||
v-model="dialogVisible"
|
v-model="dialogVisible"
|
||||||
@@ -226,6 +235,8 @@
|
|||||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||||
import { useAuth } from '@/composables/useAuth'
|
import { useAuth } from '@/composables/useAuth'
|
||||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
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 { formatDateTime } from '@/utils/business/format'
|
||||||
import { CommonStatus, getStatusText } from '@/config/constants'
|
import { CommonStatus, getStatusText } from '@/config/constants'
|
||||||
|
|
||||||
@@ -253,6 +264,8 @@
|
|||||||
const leftTreeFilter = ref('') // 左侧树搜索关键字
|
const leftTreeFilter = ref('') // 左侧树搜索关键字
|
||||||
const rightTreeFilter = ref('') // 右侧树搜索关键字
|
const rightTreeFilter = ref('') // 右侧树搜索关键字
|
||||||
const isHandlingCheck = ref(false) // 标志位:是否正在处理勾选事件
|
const isHandlingCheck = ref(false) // 标志位:是否正在处理勾选事件
|
||||||
|
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||||
|
const currentRow = ref<PlatformRole | null>(null)
|
||||||
|
|
||||||
// 搜索表单初始值
|
// 搜索表单初始值
|
||||||
const initialSearchState = {
|
const initialSearchState = {
|
||||||
@@ -317,8 +330,7 @@
|
|||||||
{ label: '角色描述', prop: 'role_desc' },
|
{ label: '角色描述', prop: 'role_desc' },
|
||||||
{ label: '角色类型', prop: 'role_type' },
|
{ label: '角色类型', prop: 'role_type' },
|
||||||
{ label: '状态', prop: 'status' },
|
{ label: '状态', prop: 'status' },
|
||||||
{ label: '创建时间', prop: 'CreatedAt' },
|
{ label: '创建时间', prop: 'CreatedAt' }
|
||||||
{ label: '操作', prop: 'operation' }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
@@ -391,47 +403,6 @@
|
|||||||
label: '创建时间',
|
label: '创建时间',
|
||||||
width: 180,
|
width: 180,
|
||||||
formatter: (row: any) => formatDateTime(row.CreatedAt)
|
formatter: (row: any) => formatDateTime(row.CreatedAt)
|
||||||
},
|
|
||||||
{
|
|
||||||
prop: 'operation',
|
|
||||||
label: '操作',
|
|
||||||
width: 240,
|
|
||||||
fixed: 'right',
|
|
||||||
formatter: (row: any) => {
|
|
||||||
const buttons = []
|
|
||||||
|
|
||||||
// 分配权限按钮
|
|
||||||
if (hasAuth('role:permission')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '分配权限',
|
|
||||||
onClick: () => showPermissionDialog(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 编辑按钮
|
|
||||||
if (hasAuth('role:edit')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '编辑',
|
|
||||||
onClick: () => showDialog('edit', row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除按钮
|
|
||||||
if (hasAuth('role:delete')) {
|
|
||||||
buttons.push(
|
|
||||||
h(ArtButtonTable, {
|
|
||||||
text: '删除',
|
|
||||||
onClick: () => deleteRole(row)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return h('div', { style: 'display: flex; gap: 8px;' }, buttons)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -1038,6 +1009,50 @@
|
|||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 右键菜单项配置
|
||||||
|
const contextMenuItems = computed((): MenuItemType[] => {
|
||||||
|
const items: MenuItemType[] = []
|
||||||
|
|
||||||
|
if (hasAuth('role:permission')) {
|
||||||
|
items.push({ key: 'assignPermission', label: '分配权限' })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAuth('role:edit')) {
|
||||||
|
items.push({ key: 'edit', label: '编辑' })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAuth('role:delete')) {
|
||||||
|
items.push({ key: 'delete', label: '删除' })
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理表格行右键菜单
|
||||||
|
const handleRowContextMenu = (row: any, 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 'assignPermission':
|
||||||
|
showPermissionDialog(currentRow.value)
|
||||||
|
break
|
||||||
|
case 'edit':
|
||||||
|
showDialog('edit', currentRow.value)
|
||||||
|
break
|
||||||
|
case 'delete':
|
||||||
|
deleteRole(currentRow.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
Reference in New Issue
Block a user