886 lines
25 KiB
Vue
886 lines
25 KiB
Vue
<template>
|
||
<ArtTableFullScreen>
|
||
<div class="package-assign-page" id="table-full-screen">
|
||
<!-- 搜索栏 -->
|
||
<ArtSearchBar
|
||
v-model:filter="searchForm"
|
||
:items="searchFormItems"
|
||
:show-expand="true"
|
||
label-width="85"
|
||
@reset="handleReset"
|
||
@search="handleSearch"
|
||
></ArtSearchBar>
|
||
|
||
<ElCard shadow="never" class="art-table-card">
|
||
<!-- 表格头部 -->
|
||
<ArtTableHeader
|
||
:columnList="columnOptions"
|
||
v-model:columns="columnChecks"
|
||
@refresh="handleRefresh"
|
||
>
|
||
<template #left>
|
||
<ElButton type="primary" @click="showDialog('add')" v-permission="'package_assign:add'"
|
||
>新增分配</ElButton
|
||
>
|
||
</template>
|
||
</ArtTableHeader>
|
||
|
||
<!-- 表格 -->
|
||
<ArtTable
|
||
ref="tableRef"
|
||
row-key="id"
|
||
:loading="loading"
|
||
:data="allocationList"
|
||
:currentPage="pagination.page"
|
||
:pageSize="pagination.page_size"
|
||
:total="pagination.total"
|
||
:marginTop="10"
|
||
@size-change="handleSizeChange"
|
||
@current-change="handleCurrentChange"
|
||
@row-contextmenu="handleRowContextMenu"
|
||
>
|
||
<template #default>
|
||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||
</template>
|
||
</ArtTable>
|
||
|
||
<!-- 右键菜单 -->
|
||
<ArtMenuRight
|
||
ref="contextMenuRef"
|
||
:menu-items="contextMenuItems"
|
||
:menu-width="120"
|
||
@select="handleContextMenuSelect"
|
||
/>
|
||
|
||
<!-- 新增/编辑对话框 -->
|
||
<ElDialog
|
||
v-model="dialogVisible"
|
||
:title="dialogType === 'add' ? '新增分配' : '编辑分配'"
|
||
width="30%"
|
||
:close-on-click-modal="false"
|
||
@closed="handleDialogClosed"
|
||
>
|
||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="90px">
|
||
<ElFormItem label="选择套餐" prop="package_id" v-if="dialogType === 'add'">
|
||
<ElSelect
|
||
v-model="form.package_id"
|
||
placeholder="请选择套餐"
|
||
style="width: 100%"
|
||
filterable
|
||
remote
|
||
:remote-method="searchPackage"
|
||
:loading="packageLoading"
|
||
clearable
|
||
@change="handlePackageChange"
|
||
>
|
||
<ElOption
|
||
v-for="pkg in packageOptions"
|
||
:key="pkg.id"
|
||
:label="`${pkg.package_name} (${pkg.series_name})`"
|
||
:value="pkg.id"
|
||
/>
|
||
</ElSelect>
|
||
</ElFormItem>
|
||
<ElFormItem label="选择店铺" prop="shop_id" v-if="dialogType === 'add'">
|
||
<ElTreeSelect
|
||
v-model="form.shop_id"
|
||
:data="shopTreeData"
|
||
:props="{ label: 'shop_name', value: 'id', children: 'children' }"
|
||
placeholder="请选择店铺"
|
||
style="width: 100%"
|
||
filterable
|
||
clearable
|
||
:loading="shopLoading"
|
||
check-strictly
|
||
:render-after-expand="false"
|
||
/>
|
||
</ElFormItem>
|
||
<ElFormItem label="成本价(元)" prop="cost_price">
|
||
<ElInputNumber
|
||
v-model="form.cost_price"
|
||
:min="0"
|
||
:precision="2"
|
||
:step="0.01"
|
||
:controls="false"
|
||
style="width: 100%"
|
||
placeholder="请输入成本价"
|
||
/>
|
||
</ElFormItem>
|
||
</ElForm>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||
<ElButton type="primary" @click="handleSubmit(formRef)" :loading="submitLoading">
|
||
提交
|
||
</ElButton>
|
||
</div>
|
||
</template>
|
||
</ElDialog>
|
||
</ElCard>
|
||
</div>
|
||
</ArtTableFullScreen>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { h } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import {
|
||
ShopPackageAllocationService,
|
||
PackageManageService,
|
||
ShopService,
|
||
ShopSeriesAllocationService
|
||
} from '@/api/modules'
|
||
import { ElMessage, ElMessageBox, ElSwitch } from 'element-plus'
|
||
import type { FormInstance, FormRules } from 'element-plus'
|
||
import type { ShopPackageAllocationResponse, PackageResponse, ShopResponse } from '@/types/api'
|
||
import type { SearchFormItem } from '@/types'
|
||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||
import { useAuth } from '@/composables/useAuth'
|
||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
||
import { formatDateTime } from '@/utils/business/format'
|
||
import { RoutesAlias } from '@/router/routesAlias'
|
||
import {
|
||
CommonStatus,
|
||
getStatusText,
|
||
frontendStatusToApi,
|
||
apiStatusToFrontend
|
||
} from '@/config/constants'
|
||
|
||
defineOptions({ name: 'PackageAssign' })
|
||
|
||
const { hasAuth } = useAuth()
|
||
const router = useRouter()
|
||
|
||
const dialogVisible = ref(false)
|
||
const loading = ref(false)
|
||
const submitLoading = ref(false)
|
||
const packageLoading = ref(false)
|
||
const shopLoading = ref(false)
|
||
const tableRef = ref()
|
||
const formRef = ref<FormInstance>()
|
||
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||
const currentRow = ref<ShopPackageAllocationResponse | null>(null)
|
||
const packageOptions = ref<PackageResponse[]>([])
|
||
const shopOptions = ref<ShopResponse[]>([])
|
||
const shopTreeData = ref<ShopResponse[]>([])
|
||
const searchPackageOptions = ref<PackageResponse[]>([])
|
||
const searchShopOptions = ref<ShopResponse[]>([])
|
||
const searchAllocatorShopOptions = ref<ShopResponse[]>([])
|
||
const searchSeriesAllocationOptions = ref<any[]>([])
|
||
|
||
// 搜索表单初始值
|
||
const initialSearchState = {
|
||
shop_id: undefined as number | undefined,
|
||
package_id: undefined as number | undefined,
|
||
series_allocation_id: undefined as number | undefined,
|
||
allocator_shop_id: undefined as number | undefined,
|
||
status: undefined as number | undefined
|
||
}
|
||
|
||
// 搜索表单
|
||
const searchForm = reactive({ ...initialSearchState })
|
||
|
||
// 搜索表单配置
|
||
const searchFormItems = computed<SearchFormItem[]>(() => [
|
||
{
|
||
label: '被分配店铺',
|
||
prop: 'shop_id',
|
||
type: 'select',
|
||
config: {
|
||
clearable: true,
|
||
filterable: true,
|
||
remote: true,
|
||
remoteMethod: handleSearchShop,
|
||
loading: shopLoading.value,
|
||
placeholder: '请选择或搜索店铺'
|
||
},
|
||
options: () =>
|
||
searchShopOptions.value.map((s) => ({
|
||
label: s.shop_name,
|
||
value: s.id
|
||
}))
|
||
},
|
||
{
|
||
label: '套餐',
|
||
prop: 'package_id',
|
||
type: 'select',
|
||
config: {
|
||
clearable: true,
|
||
filterable: true,
|
||
remote: true,
|
||
remoteMethod: handleSearchPackage,
|
||
loading: packageLoading.value,
|
||
placeholder: '请选择或搜索套餐'
|
||
},
|
||
options: () =>
|
||
searchPackageOptions.value.map((p) => ({
|
||
label: p.package_name,
|
||
value: p.id
|
||
}))
|
||
},
|
||
{
|
||
label: '系列分配',
|
||
prop: 'series_allocation_id',
|
||
type: 'select',
|
||
config: {
|
||
clearable: true,
|
||
filterable: true,
|
||
remote: true,
|
||
remoteMethod: handleSearchSeriesAllocation,
|
||
loading: loading.value,
|
||
placeholder: '请选择或搜索系列分配'
|
||
},
|
||
options: () =>
|
||
searchSeriesAllocationOptions.value.map((s) => ({
|
||
label: `${s.series_name} - ${s.shop_name}`,
|
||
value: s.id
|
||
}))
|
||
},
|
||
{
|
||
label: '分配者店铺',
|
||
prop: 'allocator_shop_id',
|
||
type: 'select',
|
||
config: {
|
||
clearable: true,
|
||
filterable: true,
|
||
remote: true,
|
||
remoteMethod: handleSearchAllocatorShop,
|
||
loading: shopLoading.value,
|
||
placeholder: '请选择或搜索分配者店铺'
|
||
},
|
||
options: () => [
|
||
{ label: '平台', value: 0 },
|
||
...searchAllocatorShopOptions.value.map((s) => ({
|
||
label: s.shop_name,
|
||
value: s.id
|
||
}))
|
||
]
|
||
},
|
||
{
|
||
label: '状态',
|
||
prop: 'status',
|
||
type: 'select',
|
||
config: {
|
||
clearable: true,
|
||
placeholder: '请选择状态'
|
||
},
|
||
options: () => [
|
||
{ label: '启用', value: 1 },
|
||
{ label: '禁用', value: 2 }
|
||
]
|
||
}
|
||
])
|
||
|
||
// 分页
|
||
const pagination = reactive({
|
||
page: 1,
|
||
page_size: 20,
|
||
total: 0
|
||
})
|
||
|
||
// 列配置
|
||
const columnOptions = [
|
||
{ label: '套餐编码', prop: 'package_code' },
|
||
{ label: '套餐名称', prop: 'package_name' },
|
||
{ label: '系列名称', prop: 'series_name' },
|
||
{ label: '被分配店铺', prop: 'shop_name' },
|
||
{ label: '分配者', prop: 'allocator_shop_name' },
|
||
{ label: '成本价', prop: 'cost_price' },
|
||
{ label: '状态', prop: 'status' },
|
||
{ label: '创建时间', prop: 'created_at' }
|
||
]
|
||
|
||
// 表单验证规则
|
||
const rules = reactive<FormRules>({
|
||
package_id: [{ required: true, message: '请选择套餐', trigger: 'change' }],
|
||
shop_id: [{ required: true, message: '请选择店铺', trigger: 'change' }],
|
||
cost_price: [
|
||
{ required: true, message: '请输入成本价', trigger: 'blur' },
|
||
{
|
||
validator: (rule: any, value: any, callback: any) => {
|
||
if (value === undefined || value === null || value === '') {
|
||
callback(new Error('请输入成本价'))
|
||
} else if (form.package_base_price && value < form.package_base_price / 100) {
|
||
callback(
|
||
new Error(`成本价不能低于套餐价格 ¥${(form.package_base_price / 100).toFixed(2)}`)
|
||
)
|
||
} else {
|
||
callback()
|
||
}
|
||
},
|
||
trigger: 'blur'
|
||
}
|
||
]
|
||
})
|
||
|
||
// 表单数据
|
||
const form = reactive<any>({
|
||
id: 0,
|
||
package_id: undefined,
|
||
shop_id: undefined,
|
||
cost_price: 0,
|
||
package_base_price: 0 // 存储选中套餐的成本价,用于验证
|
||
})
|
||
|
||
const allocationList = ref<ShopPackageAllocationResponse[]>([])
|
||
const dialogType = ref('add')
|
||
|
||
// 动态列配置
|
||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||
{
|
||
prop: 'package_code',
|
||
label: '套餐编码',
|
||
minWidth: 200,
|
||
showOverflowTooltip: true
|
||
},
|
||
{
|
||
prop: 'package_name',
|
||
label: '套餐名称',
|
||
minWidth: 180
|
||
},
|
||
{
|
||
prop: 'series_name',
|
||
label: '系列名称',
|
||
minWidth: 150
|
||
},
|
||
{
|
||
prop: 'shop_name',
|
||
label: '被分配店铺',
|
||
minWidth: 180
|
||
},
|
||
{
|
||
prop: 'allocator_shop_name',
|
||
label: '分配者',
|
||
formatter: (row: ShopPackageAllocationResponse) => {
|
||
// 如果是平台分配(allocator_shop_id为0),显示"平台"标签
|
||
if (row.allocator_shop_id === 0) {
|
||
return h(
|
||
'span',
|
||
{ style: 'color: #409eff; font-weight: bold' },
|
||
row.allocator_shop_name || '平台'
|
||
)
|
||
}
|
||
return row.allocator_shop_name
|
||
}
|
||
},
|
||
{
|
||
prop: 'cost_price',
|
||
label: '成本价',
|
||
width: 100,
|
||
formatter: (row: ShopPackageAllocationResponse) => {
|
||
return h(
|
||
'span',
|
||
{ style: 'color: #f56c6c; font-weight: bold' },
|
||
`¥${(row.cost_price / 100).toFixed(2)}`
|
||
)
|
||
}
|
||
},
|
||
{
|
||
prop: 'status',
|
||
label: '状态',
|
||
width: 100,
|
||
formatter: (row: ShopPackageAllocationResponse) => {
|
||
const frontendStatus = apiStatusToFrontend(row.status)
|
||
return h(ElSwitch, {
|
||
modelValue: frontendStatus,
|
||
activeValue: CommonStatus.ENABLED,
|
||
inactiveValue: CommonStatus.DISABLED,
|
||
activeText: getStatusText(CommonStatus.ENABLED),
|
||
inactiveText: getStatusText(CommonStatus.DISABLED),
|
||
inlinePrompt: true,
|
||
disabled: !hasAuth('package_assign:update_status'),
|
||
'onUpdate:modelValue': (val: string | number | boolean) =>
|
||
handleStatusChange(row, val as number)
|
||
})
|
||
}
|
||
},
|
||
{
|
||
prop: 'created_at',
|
||
label: '创建时间',
|
||
width: 180,
|
||
formatter: (row: ShopPackageAllocationResponse) => formatDateTime(row.created_at)
|
||
}
|
||
])
|
||
|
||
// 右键菜单项配置
|
||
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 map = new Map<number, ShopResponse & { children?: ShopResponse[] }>()
|
||
const tree: ShopResponse[] = []
|
||
|
||
// 先将所有项放入 map
|
||
items.forEach((item) => {
|
||
map.set(item.id, { ...item, children: [] })
|
||
})
|
||
|
||
// 构建树形结构
|
||
items.forEach((item) => {
|
||
const node = map.get(item.id)!
|
||
if (item.parent_id && map.has(item.parent_id)) {
|
||
// 有父节点,添加到父节点的 children 中
|
||
const parent = map.get(item.parent_id)!
|
||
if (!parent.children) parent.children = []
|
||
parent.children.push(node)
|
||
} else {
|
||
// 没有父节点或父节点不存在,作为根节点
|
||
tree.push(node)
|
||
}
|
||
})
|
||
|
||
return tree
|
||
}
|
||
|
||
onMounted(() => {
|
||
loadPackageOptions()
|
||
loadShopOptions()
|
||
loadSearchPackageOptions()
|
||
loadSearchShopOptions()
|
||
loadSearchAllocatorShopOptions()
|
||
loadSearchSeriesAllocationOptions()
|
||
getTableData()
|
||
})
|
||
|
||
// 加载套餐选项(用于新增对话框,默认加载10条)
|
||
const loadPackageOptions = async (packageName?: string) => {
|
||
packageLoading.value = true
|
||
try {
|
||
const params: any = {
|
||
page: 1,
|
||
page_size: 10
|
||
}
|
||
if (packageName) {
|
||
params.package_name = packageName
|
||
}
|
||
const res = await PackageManageService.getPackages(params)
|
||
if (res.code === 0) {
|
||
packageOptions.value = res.data.items
|
||
}
|
||
} catch (error) {
|
||
console.error('加载套餐选项失败:', error)
|
||
} finally {
|
||
packageLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 加载店铺选项(用于新增对话框,加载所有店铺并构建树形结构)
|
||
const loadShopOptions = async () => {
|
||
shopLoading.value = true
|
||
try {
|
||
// 加载所有店铺,不分页
|
||
const res = await ShopService.getShops({
|
||
page: 1,
|
||
page_size: 10000 // 使用较大的值获取所有店铺
|
||
})
|
||
if (res.code === 0) {
|
||
shopOptions.value = res.data.items
|
||
// 构建树形结构数据
|
||
shopTreeData.value = buildTreeData(shopOptions.value)
|
||
}
|
||
} catch (error) {
|
||
console.error('加载店铺选项失败:', error)
|
||
} finally {
|
||
shopLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 加载搜索栏套餐选项(默认加载10条)
|
||
const loadSearchPackageOptions = async () => {
|
||
try {
|
||
const res = await PackageManageService.getPackages({
|
||
page: 1,
|
||
page_size: 10
|
||
})
|
||
if (res.code === 0) {
|
||
searchPackageOptions.value = res.data.items
|
||
}
|
||
} catch (error) {
|
||
console.error('加载搜索栏套餐选项失败:', error)
|
||
}
|
||
}
|
||
|
||
// 加载搜索栏店铺选项(默认加载10条)
|
||
const loadSearchShopOptions = async () => {
|
||
try {
|
||
const res = await ShopService.getShops({ page: 1, page_size: 10 })
|
||
if (res.code === 0) {
|
||
searchShopOptions.value = res.data.items
|
||
}
|
||
} catch (error) {
|
||
console.error('加载搜索栏店铺选项失败:', error)
|
||
}
|
||
}
|
||
|
||
// 搜索套餐(用于新增对话框)
|
||
const searchPackage = (query: string) => {
|
||
if (query) {
|
||
loadPackageOptions(query)
|
||
} else {
|
||
loadPackageOptions()
|
||
}
|
||
}
|
||
|
||
// 搜索套餐(用于搜索栏)
|
||
const handleSearchPackage = async (query: string) => {
|
||
if (!query) {
|
||
loadSearchPackageOptions()
|
||
return
|
||
}
|
||
try {
|
||
const res = await PackageManageService.getPackages({
|
||
page: 1,
|
||
page_size: 10,
|
||
package_name: query
|
||
})
|
||
if (res.code === 0) {
|
||
searchPackageOptions.value = res.data.items
|
||
}
|
||
} catch (error) {
|
||
console.error('搜索套餐失败:', error)
|
||
}
|
||
}
|
||
|
||
// 搜索店铺(用于搜索栏)
|
||
const handleSearchShop = async (query: string) => {
|
||
if (!query) {
|
||
loadSearchShopOptions()
|
||
return
|
||
}
|
||
try {
|
||
const res = await ShopService.getShops({
|
||
page: 1,
|
||
page_size: 10,
|
||
shop_name: query
|
||
})
|
||
if (res.code === 0) {
|
||
searchShopOptions.value = res.data.items
|
||
}
|
||
} catch (error) {
|
||
console.error('搜索店铺失败:', error)
|
||
}
|
||
}
|
||
|
||
// 加载搜索栏分配者店铺选项(默认加载10条)
|
||
const loadSearchAllocatorShopOptions = async () => {
|
||
try {
|
||
const res = await ShopService.getShops({ page: 1, page_size: 10 })
|
||
if (res.code === 0) {
|
||
searchAllocatorShopOptions.value = res.data.items
|
||
}
|
||
} catch (error) {
|
||
console.error('加载搜索栏分配者店铺选项失败:', error)
|
||
}
|
||
}
|
||
|
||
// 搜索分配者店铺(用于搜索栏)
|
||
const handleSearchAllocatorShop = async (query: string) => {
|
||
if (!query) {
|
||
loadSearchAllocatorShopOptions()
|
||
return
|
||
}
|
||
try {
|
||
const res = await ShopService.getShops({
|
||
page: 1,
|
||
page_size: 10,
|
||
shop_name: query
|
||
})
|
||
if (res.code === 0) {
|
||
searchAllocatorShopOptions.value = res.data.items
|
||
}
|
||
} catch (error) {
|
||
console.error('搜索分配者店铺失败:', error)
|
||
}
|
||
}
|
||
|
||
// 加载搜索栏系列分配选项(默认加载10条)
|
||
const loadSearchSeriesAllocationOptions = async () => {
|
||
try {
|
||
const res = await ShopSeriesAllocationService.getShopSeriesAllocations({
|
||
page: 1,
|
||
page_size: 10
|
||
})
|
||
if (res.code === 0) {
|
||
searchSeriesAllocationOptions.value = res.data.items
|
||
}
|
||
} catch (error) {
|
||
console.error('加载搜索栏系列分配选项失败:', error)
|
||
}
|
||
}
|
||
|
||
// 搜索系列分配(用于搜索栏)
|
||
const handleSearchSeriesAllocation = async (query: string) => {
|
||
if (!query) {
|
||
loadSearchSeriesAllocationOptions()
|
||
return
|
||
}
|
||
try {
|
||
const res = await ShopSeriesAllocationService.getShopSeriesAllocations({
|
||
page: 1,
|
||
page_size: 10,
|
||
series_name: query
|
||
})
|
||
if (res.code === 0) {
|
||
searchSeriesAllocationOptions.value = res.data.items
|
||
}
|
||
} catch (error) {
|
||
console.error('搜索系列分配失败:', error)
|
||
}
|
||
}
|
||
|
||
// 获取分配列表
|
||
const getTableData = async () => {
|
||
loading.value = true
|
||
try {
|
||
const params = {
|
||
page: pagination.page,
|
||
page_size: pagination.page_size,
|
||
shop_id: searchForm.shop_id || undefined,
|
||
package_id: searchForm.package_id || undefined,
|
||
series_allocation_id: searchForm.series_allocation_id || undefined,
|
||
allocator_shop_id: searchForm.allocator_shop_id || undefined,
|
||
status: searchForm.status || undefined
|
||
}
|
||
const res = await ShopPackageAllocationService.getShopPackageAllocations(params)
|
||
if (res.code === 0) {
|
||
allocationList.value = res.data.items
|
||
pagination.total = res.data.total || 0
|
||
}
|
||
} catch (error) {
|
||
console.error(error)
|
||
ElMessage.error('获取分配列表失败')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 重置搜索
|
||
const handleReset = () => {
|
||
Object.assign(searchForm, { ...initialSearchState })
|
||
pagination.page = 1
|
||
getTableData()
|
||
}
|
||
|
||
// 搜索
|
||
const handleSearch = () => {
|
||
pagination.page = 1
|
||
getTableData()
|
||
}
|
||
|
||
// 刷新表格
|
||
const handleRefresh = () => {
|
||
getTableData()
|
||
}
|
||
|
||
// 处理表格分页变化
|
||
const handleSizeChange = (newPageSize: number) => {
|
||
pagination.page_size = newPageSize
|
||
getTableData()
|
||
}
|
||
|
||
const handleCurrentChange = (newCurrentPage: number) => {
|
||
pagination.page = newCurrentPage
|
||
getTableData()
|
||
}
|
||
|
||
// 显示新增/编辑对话框
|
||
const showDialog = (type: string, row?: ShopPackageAllocationResponse) => {
|
||
dialogVisible.value = true
|
||
dialogType.value = type
|
||
|
||
if (type === 'edit' && row) {
|
||
form.id = row.id
|
||
form.package_id = row.package_id
|
||
form.shop_id = row.shop_id
|
||
form.cost_price = row.cost_price / 100 // 转换为元显示
|
||
form.package_base_price = 0
|
||
} else {
|
||
form.id = 0
|
||
form.package_id = undefined
|
||
form.shop_id = undefined
|
||
form.cost_price = 0
|
||
form.package_base_price = 0
|
||
}
|
||
|
||
// 重置表单验证状态
|
||
nextTick(() => {
|
||
formRef.value?.clearValidate()
|
||
})
|
||
}
|
||
|
||
// 处理套餐选择变化
|
||
const handlePackageChange = (packageId: number | undefined) => {
|
||
if (packageId) {
|
||
// 从套餐选项中找到选中的套餐
|
||
const selectedPackage = packageOptions.value.find((pkg) => pkg.id === packageId)
|
||
if (selectedPackage) {
|
||
// 将套餐的成本价(分)转换为元显示
|
||
form.cost_price = selectedPackage.cost_price / 100
|
||
form.package_base_price = selectedPackage.cost_price // 保持原始值(分)用于验证
|
||
}
|
||
} else {
|
||
// 清空时重置成本价
|
||
form.cost_price = 0
|
||
form.package_base_price = 0
|
||
}
|
||
}
|
||
|
||
// 处理弹窗关闭事件
|
||
const handleDialogClosed = () => {
|
||
// 清除表单验证状态
|
||
formRef.value?.clearValidate()
|
||
// 重置表单数据
|
||
form.id = 0
|
||
form.package_id = undefined
|
||
form.shop_id = undefined
|
||
form.cost_price = 0
|
||
form.package_base_price = 0
|
||
}
|
||
|
||
// 删除分配
|
||
const deleteAllocation = (row: ShopPackageAllocationResponse) => {
|
||
ElMessageBox.confirm(
|
||
`确定删除套餐 ${row.package_name} 对店铺 ${row.shop_name} 的分配吗?`,
|
||
'删除确认',
|
||
{
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'error'
|
||
}
|
||
)
|
||
.then(async () => {
|
||
try {
|
||
await ShopPackageAllocationService.deleteShopPackageAllocation(row.id)
|
||
ElMessage.success('删除成功')
|
||
await getTableData()
|
||
} catch (error) {
|
||
console.error(error)
|
||
}
|
||
})
|
||
.catch(() => {
|
||
// 用户取消删除
|
||
})
|
||
}
|
||
|
||
// 提交表单
|
||
const handleSubmit = async (formEl: FormInstance | undefined) => {
|
||
if (!formEl) return
|
||
|
||
await formEl.validate(async (valid) => {
|
||
if (valid) {
|
||
submitLoading.value = true
|
||
try {
|
||
// 将元转换为分提交给后端
|
||
const costPriceInCents = Math.round(form.cost_price * 100)
|
||
|
||
const data = {
|
||
package_id: form.package_id,
|
||
shop_id: form.shop_id,
|
||
cost_price: costPriceInCents
|
||
}
|
||
|
||
if (dialogType.value === 'add') {
|
||
await ShopPackageAllocationService.createShopPackageAllocation(data)
|
||
ElMessage.success('新增成功')
|
||
} else {
|
||
await ShopPackageAllocationService.updateShopPackageAllocation(form.id, {
|
||
cost_price: costPriceInCents
|
||
})
|
||
ElMessage.success('修改成功')
|
||
}
|
||
|
||
dialogVisible.value = false
|
||
formEl.resetFields()
|
||
await getTableData()
|
||
} catch (error) {
|
||
console.error(error)
|
||
} finally {
|
||
submitLoading.value = false
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 状态切换
|
||
const handleStatusChange = async (
|
||
row: ShopPackageAllocationResponse,
|
||
newFrontendStatus: number
|
||
) => {
|
||
const oldStatus = row.status
|
||
const newApiStatus = frontendStatusToApi(newFrontendStatus)
|
||
row.status = newApiStatus
|
||
try {
|
||
await ShopPackageAllocationService.updateShopPackageAllocationStatus(row.id, newApiStatus)
|
||
ElMessage.success('状态切换成功')
|
||
} catch (error) {
|
||
row.status = oldStatus
|
||
console.error(error)
|
||
}
|
||
}
|
||
|
||
// 查看详情
|
||
const handleViewDetail = (row: ShopPackageAllocationResponse) => {
|
||
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>
|
||
|
||
<style lang="scss" scoped>
|
||
.package-assign-page {
|
||
// 可以添加特定样式
|
||
}
|
||
|
||
.dialog-footer {
|
||
text-align: right;
|
||
}
|
||
</style>
|