This commit is contained in:
@@ -34,15 +34,21 @@
|
||||
:pageSize="pagination.page_size"
|
||||
:total="pagination.total"
|
||||
:marginTop="10"
|
||||
:row-class-name="getRowClassName"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@row-contextmenu="handleRowContextMenu"
|
||||
@cell-mouse-enter="handleCellMouseEnter"
|
||||
@cell-mouse-leave="handleCellMouseLeave"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 鼠标悬浮提示 -->
|
||||
<TableContextMenuHint :visible="showContextMenuHint" :position="hintPosition" />
|
||||
|
||||
<!-- 右键菜单 -->
|
||||
<ArtMenuRight
|
||||
ref="contextMenuRef"
|
||||
@@ -251,8 +257,10 @@
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
import { useTableContextMenu } from '@/composables/useTableContextMenu'
|
||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||||
import TableContextMenuHint from '@/components/core/others/TableContextMenuHint.vue'
|
||||
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import { RoutesAlias } from '@/router/routesAlias'
|
||||
@@ -283,6 +291,15 @@
|
||||
const seriesOptions = ref<SeriesSelectOption[]>([])
|
||||
const searchSeriesOptions = ref<SeriesSelectOption[]>([])
|
||||
|
||||
// 使用表格右键菜单功能
|
||||
const {
|
||||
showContextMenuHint,
|
||||
hintPosition,
|
||||
getRowClassName,
|
||||
handleCellMouseEnter,
|
||||
handleCellMouseLeave
|
||||
} = useTableContextMenu()
|
||||
|
||||
// 搜索表单初始值
|
||||
const initialSearchState = {
|
||||
package_name: '',
|
||||
@@ -952,6 +969,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-table__row.table-row-with-context-menu) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.package-list-page {
|
||||
// 可以添加特定样式
|
||||
}
|
||||
|
||||
@@ -35,15 +35,21 @@
|
||||
:pageSize="pagination.page_size"
|
||||
:total="pagination.total"
|
||||
:marginTop="10"
|
||||
:row-class-name="getRowClassName"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@row-contextmenu="handleRowContextMenu"
|
||||
@cell-mouse-enter="handleCellMouseEnter"
|
||||
@cell-mouse-leave="handleCellMouseLeave"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 鼠标悬浮提示 -->
|
||||
<TableContextMenuHint :visible="showContextMenuHint" :position="hintPosition" />
|
||||
|
||||
<!-- 套餐系列操作右键菜单 -->
|
||||
<ArtMenuRight
|
||||
ref="seriesOperationMenuRef"
|
||||
@@ -245,7 +251,7 @@
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption label="仅自己" value="self" />
|
||||
<ElOption label="自己+下级" value="self_and_sub" />
|
||||
<!--<ElOption label="自己+下级" value="self_and_sub" />-->
|
||||
</ElSelect>
|
||||
</div>
|
||||
</div>
|
||||
@@ -396,8 +402,10 @@
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
import { useTableContextMenu } from '@/composables/useTableContextMenu'
|
||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||||
import TableContextMenuHint from '@/components/core/others/TableContextMenuHint.vue'
|
||||
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import {
|
||||
@@ -1112,6 +1120,15 @@
|
||||
ElMessage.warning('您没有查看详情的权限')
|
||||
}
|
||||
}
|
||||
|
||||
// 使用表格右键菜单功能
|
||||
const {
|
||||
showContextMenuHint,
|
||||
hintPosition,
|
||||
getRowClassName,
|
||||
handleCellMouseEnter,
|
||||
handleCellMouseLeave
|
||||
} = useTableContextMenu()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -1122,4 +1139,8 @@
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
:deep(.el-table__row.table-row-with-context-menu) {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -91,13 +91,14 @@
|
||||
<ElTableColumn label="统计范围" width="120">
|
||||
<template #default="{ row }">
|
||||
<ElTag size="small" type="warning">
|
||||
{{
|
||||
row.stat_scope === 'self'
|
||||
? '仅自己'
|
||||
: row.stat_scope === 'self_and_sub'
|
||||
? '自己+下级'
|
||||
: '-'
|
||||
}}
|
||||
仅自己
|
||||
<!--{{-->
|
||||
<!-- row.stat_scope === 'self'-->
|
||||
<!-- ? '仅自己'-->
|
||||
<!-- : row.stat_scope === 'self_and_sub'-->
|
||||
<!-- ? '自己+下级'-->
|
||||
<!-- : '-'-->
|
||||
<!--}}-->
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
|
||||
@@ -35,15 +35,21 @@
|
||||
:pageSize="pagination.page_size"
|
||||
:total="pagination.total"
|
||||
:marginTop="10"
|
||||
:row-class-name="getRowClassName"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@row-contextmenu="handleRowContextMenu"
|
||||
@cell-mouse-enter="handleCellMouseEnter"
|
||||
@cell-mouse-leave="handleCellMouseLeave"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 鼠标悬浮提示 -->
|
||||
<TableContextMenuHint :visible="showContextMenuHint" :position="hintPosition" />
|
||||
|
||||
<!-- 右键菜单 -->
|
||||
<ArtMenuRight
|
||||
ref="contextMenuRef"
|
||||
@@ -52,60 +58,443 @@
|
||||
@select="handleContextMenuSelect"
|
||||
/>
|
||||
|
||||
<!-- 套餐列表对话框 -->
|
||||
<ElDialog
|
||||
v-model="packageListDialogVisible"
|
||||
title="套餐列表"
|
||||
width="65%"
|
||||
:close-on-click-modal="false"
|
||||
@closed="handlePackageListDialogClosed"
|
||||
>
|
||||
<div class="package-list-dialog-content">
|
||||
<!-- 添加授权套餐按钮 -->
|
||||
<div class="package-list-header">
|
||||
<ElButton
|
||||
type="primary"
|
||||
@click="showAddPackageDialog"
|
||||
v-permission="'series_grants:manage_packages'"
|
||||
>
|
||||
添加授权套餐
|
||||
</ElButton>
|
||||
</div>
|
||||
|
||||
<!-- 套餐列表 -->
|
||||
<ElTable
|
||||
v-if="currentGrantPackages.length > 0"
|
||||
:data="currentGrantPackages"
|
||||
border
|
||||
stripe
|
||||
style="margin-top: 12px"
|
||||
>
|
||||
<ElTableColumn prop="package_name" label="套餐名称" />
|
||||
<ElTableColumn prop="package_code" label="套餐编码" />
|
||||
<ElTableColumn label="成本价">
|
||||
<template #default="{ row }">
|
||||
<span class="amount-value">¥{{ (row.cost_price / 100).toFixed(2) }}</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="上架状态" align="center">
|
||||
<template #default="{ row }">
|
||||
<ElTag v-if="row.shelf_status === 1" type="success" size="small">上架</ElTag>
|
||||
<ElTag v-else-if="row.shelf_status === 2" type="info" size="small">下架</ElTag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<ElTag v-if="row.status === 1" type="success" size="small">启用</ElTag>
|
||||
<ElTag v-else-if="row.status === 2" type="danger" size="small">禁用</ElTag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="操作" width="150" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<ElButton
|
||||
type="primary"
|
||||
size="small"
|
||||
link
|
||||
@click="showEditPackageDialog(row)"
|
||||
v-permission="'series_grants:edit_packages'"
|
||||
>
|
||||
编辑
|
||||
</ElButton>
|
||||
<ElButton
|
||||
type="danger"
|
||||
size="small"
|
||||
link
|
||||
@click="handleDeletePackage(row)"
|
||||
v-permission="'series_grants:delete_packages'"
|
||||
>
|
||||
删除
|
||||
</ElButton>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</ElTable>
|
||||
<ElEmpty v-else description="暂无套餐" :image-size="80" />
|
||||
</div>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 添加/编辑套餐对话框 -->
|
||||
<ElDialog
|
||||
v-model="packageDialogVisible"
|
||||
:title="packageDialogType === 'add' ? '添加套餐' : '编辑套餐'"
|
||||
width="500px"
|
||||
:close-on-click-modal="false"
|
||||
@closed="handlePackageDialogClosed"
|
||||
>
|
||||
<ElForm
|
||||
ref="packageFormRef"
|
||||
:model="packageForm"
|
||||
:rules="packageFormRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<!-- 添加模式:选择套餐 -->
|
||||
<ElFormItem label="选择套餐" prop="package_id" v-if="packageDialogType === 'add'">
|
||||
<ElSelect
|
||||
v-model="packageForm.package_id"
|
||||
placeholder="请选择套餐"
|
||||
style="width: 100%"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="searchAvailablePackages"
|
||||
:loading="packageLoading"
|
||||
clearable
|
||||
>
|
||||
<template
|
||||
v-if="availablePackages.length === 0 && !packageLoading && currentGrantSeriesId"
|
||||
>
|
||||
<ElOption disabled value="" label="该系列没有可选套餐" />
|
||||
</template>
|
||||
<ElOption
|
||||
v-for="pkg in availablePackages"
|
||||
:key="pkg.id"
|
||||
:label="`${pkg.package_name} (${pkg.package_code})`"
|
||||
:value="pkg.id"
|
||||
:disabled="isPackageAlreadyAdded(pkg.id)"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
|
||||
<!-- 编辑模式:显示套餐信息 -->
|
||||
<ElFormItem label="套餐名称" v-if="packageDialogType === 'edit'">
|
||||
<span>{{ packageForm.package_name }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="套餐编码" v-if="packageDialogType === 'edit'">
|
||||
<span>{{ packageForm.package_code }}</span>
|
||||
</ElFormItem>
|
||||
|
||||
<!-- 成本价 -->
|
||||
<ElFormItem label="成本价(元)" prop="cost_price_yuan">
|
||||
<ElInputNumber
|
||||
v-model="packageForm.cost_price_yuan"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
placeholder="请输入成本价"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="packageDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSavePackage" :loading="packageSubmitLoading">
|
||||
保存
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 新增/编辑对话框 -->
|
||||
<ElDialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogType === 'add' ? '新增代理系列授权' : '编辑代理系列授权'"
|
||||
width="50%"
|
||||
width="60%"
|
||||
:close-on-click-modal="false"
|
||||
@closed="handleDialogClosed"
|
||||
>
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="130px">
|
||||
<!-- 新增模式:基本信息 - 2列布局 -->
|
||||
<div v-if="dialogType === 'add'">
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="选择套餐系列" prop="series_id">
|
||||
<!-- 新增模式:分步骤表单 -->
|
||||
<template v-if="dialogType === 'add'">
|
||||
<!-- 步骤条 -->
|
||||
<ElSteps
|
||||
:active="currentStep"
|
||||
finish-status="success"
|
||||
align-center
|
||||
style="margin-bottom: 30px"
|
||||
>
|
||||
<ElStep title="基本信息" description="选择系列和店铺" />
|
||||
<ElStep title="佣金和充值配置" description="设置佣金和强制充值" />
|
||||
</ElSteps>
|
||||
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="130px">
|
||||
<!-- 第一步:基本信息 -->
|
||||
<div v-show="currentStep === 0">
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="24">
|
||||
<ElFormItem label="选择套餐系列" prop="series_id">
|
||||
<ElSelect
|
||||
v-model="form.series_id"
|
||||
placeholder="请选择套餐系列"
|
||||
style="width: 100%"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="searchSeries"
|
||||
:loading="seriesLoading"
|
||||
clearable
|
||||
>
|
||||
<ElOption
|
||||
v-for="series in seriesOptions"
|
||||
:key="series.id"
|
||||
:label="`${series.series_name} (${series.series_code})`"
|
||||
:value="series.id"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="20" v-if="form.series_id">
|
||||
<ElCol :span="24">
|
||||
<ElFormItem label="选择店铺" prop="shop_id">
|
||||
<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>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<!-- 套餐配置 -->
|
||||
<div v-if="form.shop_id" class="form-section-title">
|
||||
<span class="title-text">套餐配置(可选)</span>
|
||||
</div>
|
||||
|
||||
<template v-if="form.shop_id">
|
||||
<!-- 选择套餐 -->
|
||||
<ElFormItem label="选择套餐">
|
||||
<ElSelect
|
||||
v-model="form.series_id"
|
||||
placeholder="请选择套餐系列"
|
||||
v-model="selectedPackageIds"
|
||||
placeholder="请选择套餐"
|
||||
style="width: 100%"
|
||||
multiple
|
||||
filterable
|
||||
remote
|
||||
:remote-method="searchSeries"
|
||||
:loading="seriesLoading"
|
||||
:remote-method="searchPackages"
|
||||
:loading="packageLoading"
|
||||
clearable
|
||||
>
|
||||
<template
|
||||
v-if="packageOptions.length === 0 && !packageLoading && form.series_id"
|
||||
>
|
||||
<ElOption disabled value="" label="该系列没有可选套餐" />
|
||||
</template>
|
||||
<ElOption
|
||||
v-for="series in seriesOptions"
|
||||
:key="series.id"
|
||||
:label="`${series.series_name} (${series.series_code})`"
|
||||
:value="series.id"
|
||||
v-for="pkg in packageOptions"
|
||||
:key="pkg.id"
|
||||
:label="pkg.package_name"
|
||||
:value="pkg.id"
|
||||
/>
|
||||
</ElSelect>
|
||||
<div class="form-tip">选择该授权下包含的套餐</div>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="选择店铺" prop="shop_id">
|
||||
<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>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
|
||||
<!-- 套餐成本价 -->
|
||||
<ElFormItem label="套餐成本价" v-if="form.packages.length > 0">
|
||||
<div class="package-list">
|
||||
<div
|
||||
v-for="(pkg, index) in form.packages"
|
||||
:key="pkg.package_id"
|
||||
class="package-item"
|
||||
>
|
||||
<span class="package-name">{{ getPackageName(pkg.package_id) }}</span>
|
||||
<div class="cost-price-input-wrapper">
|
||||
<ElInputNumber
|
||||
v-model="pkg.cost_price"
|
||||
:min="pkg.original_cost_price || 0"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
:controls="false"
|
||||
placeholder="成本价(元)"
|
||||
style="width: 150px"
|
||||
/>
|
||||
<span v-if="pkg.original_cost_price" class="min-cost-hint">
|
||||
(成本价: ¥{{ pkg.original_cost_price.toFixed(2) }})
|
||||
</span>
|
||||
</div>
|
||||
<ElButton type="danger" size="small" @click="removePackage(index)"
|
||||
>删除</ElButton
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-tip"
|
||||
>设置每个套餐的成本价(单位:元),不能低于套餐原始成本价</div
|
||||
>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 第二步:佣金和强制充值配置 -->
|
||||
<div v-show="currentStep === 1">
|
||||
<!-- 一次性佣金配置 -->
|
||||
<div class="form-section-title">
|
||||
<span class="title-text">一次性佣金配置</span>
|
||||
</div>
|
||||
|
||||
<!-- 佣金类型和金额 - 2列布局 -->
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="佣金类型">
|
||||
<div class="commission-type-display">
|
||||
<ElTag
|
||||
:type="form.commission_type === 'fixed' ? 'success' : 'warning'"
|
||||
size="large"
|
||||
>
|
||||
{{ form.commission_type === 'fixed' ? '固定佣金' : '梯度佣金' }}
|
||||
</ElTag>
|
||||
<span class="type-hint">(从套餐系列配置继承)</span>
|
||||
</div>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12" v-if="form.commission_type === 'fixed'">
|
||||
<ElFormItem label="佣金金额(元)" prop="one_time_commission_amount">
|
||||
<ElInputNumber
|
||||
v-model="form.one_time_commission_amount"
|
||||
:min="0"
|
||||
:max="form.series_max_commission_amount"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
placeholder="请输入固定佣金金额(元)"
|
||||
/>
|
||||
<div class="form-tip">
|
||||
该代理能获得的固定佣金金额(单位:元)
|
||||
<span v-if="form.series_max_commission_amount > 0" class="max-amount-hint">
|
||||
<br />
|
||||
该系列最大佣金金额:
|
||||
<span class="amount-value"
|
||||
>¥{{ form.series_max_commission_amount.toFixed(2) }}</span
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<!-- 梯度佣金配置 -->
|
||||
<template v-if="form.commission_type === 'tiered'">
|
||||
<ElFormItem label="梯度配置" prop="commission_tiers">
|
||||
<ElTable :data="form.commission_tiers" border style="width: 100%">
|
||||
<ElTableColumn label="比较运算符" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<ElTag size="small" type="success">{{ row.operator || '>=' }}</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="达标阈值" width="120">
|
||||
<template #default="{ row }">
|
||||
<span class="readonly-value">{{ row.threshold }}</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="统计维度" width="120">
|
||||
<template #default="{ row }">
|
||||
<ElTag size="small" type="info">
|
||||
{{ row.dimension === 'sales_count' ? '销量' : '销售额' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="统计范围" width="140">
|
||||
<template #default="{ row }">
|
||||
<ElTag size="small" type="warning"> 仅自己 </ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="佣金金额(元)" min-width="180">
|
||||
<template #default="{ row }">
|
||||
<div style="display: flex; flex-direction: column; gap: 4px">
|
||||
<ElInputNumber
|
||||
v-model="row.amount"
|
||||
:min="0"
|
||||
:max="row.max_amount"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
:controls="false"
|
||||
placeholder="请输入佣金金额"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<span
|
||||
v-if="row.max_amount"
|
||||
style="font-size: 12px; color: var(--el-text-color-secondary)"
|
||||
>
|
||||
最大: ¥{{ row.max_amount.toFixed(2) }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</ElTable>
|
||||
<div class="form-tip" style="margin-top: 8px">
|
||||
梯度配置从套餐系列继承,达标阈值、统计维度、统计范围为只读,只能修改佣金金额
|
||||
</div>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
|
||||
<!-- 强制充值配置 -->
|
||||
<div class="form-section-title">
|
||||
<span class="title-text">强制充值配置(可选)</span>
|
||||
</div>
|
||||
|
||||
<!-- 启用强制充值和强充金额 - 2列布局 -->
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="启用强制充值">
|
||||
<ElSwitch v-model="form.enable_force_recharge" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12" v-if="form.enable_force_recharge">
|
||||
<ElFormItem label="强充金额(元)" prop="force_recharge_amount">
|
||||
<ElInputNumber
|
||||
v-model="form.force_recharge_amount"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="0.01"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
placeholder="请输入强制充值金额(元)"
|
||||
/>
|
||||
<div class="form-tip">
|
||||
用户需要达到的强制充值金额
|
||||
<span
|
||||
v-if="form.series_name && form.series_force_recharge_amount > 0"
|
||||
class="series-force-hint"
|
||||
>
|
||||
<br />
|
||||
可参考
|
||||
<span class="amount-value">{{ form.series_name }}</span
|
||||
>系列强充金额:
|
||||
<span class="amount-value"
|
||||
>¥{{ form.series_force_recharge_amount.toFixed(2) }}</span
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
</ElForm>
|
||||
</template>
|
||||
|
||||
<!-- 编辑模式:原有的表单布局 -->
|
||||
<ElForm v-else ref="formRef" :model="form" :rules="rules" label-width="130px">
|
||||
<!-- 编辑模式:显示只读信息 -->
|
||||
<div v-if="dialogType === 'edit'" class="info-row">
|
||||
<div class="info-row">
|
||||
<div class="info-item">
|
||||
<span class="info-label">系列名称:</span>
|
||||
<span class="info-value">{{ form.series_name || '-' }}</span>
|
||||
@@ -189,15 +578,7 @@
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="统计范围" width="140">
|
||||
<template #default="{ row }">
|
||||
<ElTag size="small" type="warning">
|
||||
{{
|
||||
row.stat_scope === 'self'
|
||||
? '仅自己'
|
||||
: row.stat_scope === 'self_and_sub'
|
||||
? '自己+下级'
|
||||
: '-'
|
||||
}}
|
||||
</ElTag>
|
||||
<ElTag size="small" type="warning"> 仅自己 </ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="佣金金额(元)" min-width="180">
|
||||
@@ -271,13 +652,13 @@
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<!-- 套餐配置 -->
|
||||
<div class="form-section-title">
|
||||
<!-- 套餐配置(编辑模式下禁用) -->
|
||||
<!-- <div class="form-section-title">
|
||||
<span class="title-text">套餐配置(可选)</span>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- 选择套餐 -->
|
||||
<ElFormItem label="选择套餐">
|
||||
<!-- 编辑模式下不显示套餐配置区域,请使用右键菜单中的"添加授权套餐"功能 -->
|
||||
<!-- <ElFormItem label="选择套餐">
|
||||
<ElSelect
|
||||
v-model="selectedPackageIds"
|
||||
placeholder="请选择套餐"
|
||||
@@ -300,10 +681,10 @@
|
||||
/>
|
||||
</ElSelect>
|
||||
<div class="form-tip">选择该授权下包含的套餐</div>
|
||||
</ElFormItem>
|
||||
</ElFormItem> -->
|
||||
|
||||
<!-- 套餐成本价 -->
|
||||
<ElFormItem label="套餐成本价" v-if="form.packages.length > 0">
|
||||
<!-- <ElFormItem label="套餐成本价" v-if="form.packages.length > 0">
|
||||
<div class="package-list">
|
||||
<div
|
||||
v-for="(pkg, index) in form.packages"
|
||||
@@ -329,14 +710,32 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-tip">设置每个套餐的成本价(单位:元),不能低于套餐原始成本价</div>
|
||||
</ElFormItem>
|
||||
</ElFormItem> -->
|
||||
</ElForm>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmit(formRef)" :loading="submitLoading">
|
||||
提交
|
||||
</ElButton>
|
||||
<template v-if="dialogType === 'add'">
|
||||
<ElButton v-if="currentStep > 0" @click="handlePrevStep">上一步</ElButton>
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton v-if="currentStep < 1" type="primary" @click="handleNextStep"
|
||||
>下一步</ElButton
|
||||
>
|
||||
<ElButton
|
||||
v-else
|
||||
type="primary"
|
||||
@click="handleSubmit(formRef)"
|
||||
:loading="submitLoading"
|
||||
>
|
||||
提交
|
||||
</ElButton>
|
||||
</template>
|
||||
<template v-else>
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmit(formRef)" :loading="submitLoading">
|
||||
提交
|
||||
</ElButton>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
@@ -346,7 +745,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { h, ref, reactive, computed, watch, onMounted, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import {
|
||||
ShopSeriesGrantService,
|
||||
@@ -354,20 +753,34 @@
|
||||
ShopService,
|
||||
PackageManageService
|
||||
} from '@/api/modules'
|
||||
import { ElMessage, ElMessageBox, ElSwitch, ElTag, ElRow, ElCol } from 'element-plus'
|
||||
import {
|
||||
ElMessage,
|
||||
ElMessageBox,
|
||||
ElSwitch,
|
||||
ElTag,
|
||||
ElRow,
|
||||
ElCol,
|
||||
ElSteps,
|
||||
ElStep,
|
||||
ElEmpty
|
||||
} from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type {
|
||||
ShopSeriesGrantResponse,
|
||||
PackageSeriesResponse,
|
||||
ShopResponse,
|
||||
PackageResponse,
|
||||
CommissionTier
|
||||
CommissionTier,
|
||||
GrantPackageItem,
|
||||
GrantPackageInfo
|
||||
} from '@/types/api'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
import { useTableContextMenu } from '@/composables/useTableContextMenu'
|
||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||||
import TableContextMenuHint from '@/components/core/others/TableContextMenuHint.vue'
|
||||
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import {
|
||||
@@ -392,6 +805,42 @@
|
||||
const formRef = ref<FormInstance>()
|
||||
const contextMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||
const currentRow = ref<ShopSeriesGrantResponse | null>(null)
|
||||
const currentStep = ref(0) // 当前步骤,0 为第一步,1 为第二步
|
||||
|
||||
// 套餐列表对话框相关
|
||||
const packageListDialogVisible = ref(false)
|
||||
const currentGrantId = ref<number>(0)
|
||||
const currentGrantSeriesId = ref<number>(0)
|
||||
const currentGrantPackages = ref<GrantPackageInfo[]>([])
|
||||
|
||||
// 套餐管理相关
|
||||
const packageDialogVisible = ref(false)
|
||||
const packageDialogType = ref<'add' | 'edit'>('add')
|
||||
const packageSubmitLoading = ref(false)
|
||||
const availablePackages = ref<PackageResponse[]>([])
|
||||
const packageFormRef = ref<FormInstance>()
|
||||
|
||||
// 套餐表单
|
||||
const packageForm = ref<{
|
||||
package_id?: number
|
||||
package_name?: string
|
||||
package_code?: string
|
||||
cost_price_yuan: number
|
||||
}>({
|
||||
cost_price_yuan: 0
|
||||
})
|
||||
|
||||
// 套餐表单验证规则
|
||||
const packageFormRules = computed<FormRules>(() => ({
|
||||
package_id: [
|
||||
{ required: packageDialogType.value === 'add', message: '请选择套餐', trigger: 'change' }
|
||||
],
|
||||
cost_price_yuan: [
|
||||
{ required: true, message: '请输入成本价', trigger: 'blur' },
|
||||
{ type: 'number', min: 0, message: '成本价不能小于0', trigger: 'blur' }
|
||||
]
|
||||
}))
|
||||
|
||||
const seriesOptions = ref<PackageSeriesResponse[]>([])
|
||||
const shopOptions = ref<ShopResponse[]>([])
|
||||
const shopTreeData = ref<ShopResponse[]>([])
|
||||
@@ -1277,6 +1726,8 @@
|
||||
const handleDialogClosed = () => {
|
||||
// 清除表单验证状态
|
||||
formRef.value?.clearValidate()
|
||||
// 重置步骤
|
||||
currentStep.value = 0
|
||||
// 重置表单数据
|
||||
form.id = 0
|
||||
form.series_id = undefined
|
||||
@@ -1414,6 +1865,10 @@
|
||||
const contextMenuItems = computed((): MenuItemType[] => {
|
||||
const items: MenuItemType[] = []
|
||||
|
||||
if (hasAuth('series_grants:detail')) {
|
||||
items.push({ key: 'view_packages', label: '查看套餐列表' })
|
||||
}
|
||||
|
||||
if (hasAuth('series_grants:edit')) {
|
||||
items.push({ key: 'edit', label: '编辑' })
|
||||
}
|
||||
@@ -1438,6 +1893,9 @@
|
||||
if (!currentRow.value) return
|
||||
|
||||
switch (item.key) {
|
||||
case 'view_packages':
|
||||
showPackageListDialog(currentRow.value)
|
||||
break
|
||||
case 'edit':
|
||||
showDialog('edit', currentRow.value)
|
||||
break
|
||||
@@ -1446,6 +1904,242 @@
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 显示套餐列表对话框
|
||||
const showPackageListDialog = async (row: ShopSeriesGrantResponse) => {
|
||||
currentGrantId.value = row.id
|
||||
currentGrantSeriesId.value = row.series_id
|
||||
|
||||
// 获取该授权的详细信息,包括套餐列表
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await ShopSeriesGrantService.getShopSeriesGrantDetail(row.id)
|
||||
if (res.code === 0) {
|
||||
currentGrantPackages.value = res.data.packages || []
|
||||
packageListDialogVisible.value = true
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取套餐列表失败:', error)
|
||||
ElMessage.error('获取套餐列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 显示添加套餐对话框
|
||||
const showAddPackageDialog = () => {
|
||||
packageDialogType.value = 'add'
|
||||
packageForm.value = {
|
||||
package_id: undefined,
|
||||
cost_price_yuan: 0
|
||||
}
|
||||
|
||||
// 加载可用套餐
|
||||
if (currentGrantSeriesId.value) {
|
||||
loadAvailablePackages()
|
||||
}
|
||||
|
||||
packageDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 显示编辑套餐对话框
|
||||
const showEditPackageDialog = (row: GrantPackageInfo) => {
|
||||
packageDialogType.value = 'edit'
|
||||
packageForm.value = {
|
||||
package_id: row.package_id,
|
||||
package_name: row.package_name,
|
||||
package_code: row.package_code,
|
||||
cost_price_yuan: row.cost_price / 100
|
||||
}
|
||||
|
||||
packageDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 加载可用套餐
|
||||
const loadAvailablePackages = async (packageName?: string) => {
|
||||
if (!currentGrantSeriesId.value) return
|
||||
|
||||
packageLoading.value = true
|
||||
try {
|
||||
const params: any = {
|
||||
page: 1,
|
||||
page_size: 50,
|
||||
series_id: currentGrantSeriesId.value
|
||||
}
|
||||
|
||||
if (packageName) {
|
||||
params.package_name = packageName
|
||||
}
|
||||
|
||||
const res = await PackageManageService.getPackages(params)
|
||||
if (res.code === 0) {
|
||||
availablePackages.value = res.data.items
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载套餐选项失败:', error)
|
||||
} finally {
|
||||
packageLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索可用套餐
|
||||
const searchAvailablePackages = (query: string) => {
|
||||
if (query) {
|
||||
loadAvailablePackages(query)
|
||||
} else {
|
||||
loadAvailablePackages()
|
||||
}
|
||||
}
|
||||
|
||||
// 检查套餐是否已添加
|
||||
const isPackageAlreadyAdded = (packageId: number) => {
|
||||
return currentGrantPackages.value.some((p) => p.package_id === packageId)
|
||||
}
|
||||
|
||||
// 保存套餐
|
||||
const handleSavePackage = async () => {
|
||||
if (!packageFormRef.value || !currentGrantId.value) return
|
||||
|
||||
await packageFormRef.value.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
|
||||
packageSubmitLoading.value = true
|
||||
try {
|
||||
const packages: GrantPackageItem[] = []
|
||||
|
||||
if (packageDialogType.value === 'add') {
|
||||
// 添加模式:添加新套餐
|
||||
packages.push({
|
||||
package_id: packageForm.value.package_id,
|
||||
cost_price: Math.round(packageForm.value.cost_price_yuan * 100)
|
||||
})
|
||||
} else {
|
||||
// 编辑模式:更新套餐成本价
|
||||
packages.push({
|
||||
package_id: packageForm.value.package_id,
|
||||
cost_price: Math.round(packageForm.value.cost_price_yuan * 100)
|
||||
})
|
||||
}
|
||||
|
||||
await ShopSeriesGrantService.manageGrantPackages(currentGrantId.value, { packages })
|
||||
ElMessage.success(packageDialogType.value === 'add' ? '添加成功' : '更新成功')
|
||||
packageDialogVisible.value = false
|
||||
|
||||
// 刷新套餐列表
|
||||
await refreshPackageList()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
ElMessage.error(packageDialogType.value === 'add' ? '添加失败' : '更新失败')
|
||||
} finally {
|
||||
packageSubmitLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 删除套餐
|
||||
const handleDeletePackage = (row: GrantPackageInfo) => {
|
||||
ElMessageBox.confirm(`确定删除套餐 ${row.package_name} 的授权吗?`, '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(async () => {
|
||||
if (!currentGrantId.value) return
|
||||
|
||||
packageSubmitLoading.value = true
|
||||
try {
|
||||
const packages: GrantPackageItem[] = [
|
||||
{
|
||||
package_id: row.package_id,
|
||||
remove: true
|
||||
}
|
||||
]
|
||||
|
||||
await ShopSeriesGrantService.manageGrantPackages(currentGrantId.value, { packages })
|
||||
ElMessage.success('删除成功')
|
||||
|
||||
// 刷新套餐列表
|
||||
await refreshPackageList()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
ElMessage.error('删除失败')
|
||||
} finally {
|
||||
packageSubmitLoading.value = false
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// 用户取消
|
||||
})
|
||||
}
|
||||
|
||||
// 刷新套餐列表
|
||||
const refreshPackageList = async () => {
|
||||
if (!currentGrantId.value) return
|
||||
|
||||
try {
|
||||
const res = await ShopSeriesGrantService.getShopSeriesGrantDetail(currentGrantId.value)
|
||||
if (res.code === 0) {
|
||||
currentGrantPackages.value = res.data.packages || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('刷新套餐列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭套餐对话框
|
||||
const handlePackageDialogClosed = () => {
|
||||
packageFormRef.value?.resetFields()
|
||||
packageForm.value = {
|
||||
cost_price_yuan: 0
|
||||
}
|
||||
availablePackages.value = []
|
||||
}
|
||||
|
||||
// 关闭套餐列表对话框
|
||||
const handlePackageListDialogClosed = () => {
|
||||
currentGrantId.value = 0
|
||||
currentGrantSeriesId.value = 0
|
||||
currentGrantPackages.value = []
|
||||
availablePackages.value = []
|
||||
}
|
||||
|
||||
// 使用表格右键菜单功能
|
||||
const {
|
||||
showContextMenuHint,
|
||||
hintPosition,
|
||||
getRowClassName,
|
||||
handleCellMouseEnter,
|
||||
handleCellMouseLeave
|
||||
} = useTableContextMenu()
|
||||
|
||||
// 下一步
|
||||
const handleNextStep = async () => {
|
||||
if (!formRef.value) return
|
||||
|
||||
// 根据当前步骤验证不同的字段
|
||||
let fieldsToValidate: string[] = []
|
||||
|
||||
if (currentStep.value === 0) {
|
||||
// 第一步:验证系列和店铺选择
|
||||
fieldsToValidate = ['series_id', 'shop_id']
|
||||
}
|
||||
|
||||
try {
|
||||
// 验证当前步骤的字段
|
||||
await formRef.value.validateField(fieldsToValidate)
|
||||
// 验证通过,进入下一步
|
||||
currentStep.value++
|
||||
} catch (error) {
|
||||
console.error('表单验证失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 上一步
|
||||
const handlePrevStep = () => {
|
||||
if (currentStep.value > 0) {
|
||||
currentStep.value--
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -1453,6 +2147,10 @@
|
||||
// 可以添加特定样式
|
||||
}
|
||||
|
||||
:deep(.el-table__row.table-row-with-context-menu) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
@@ -1595,4 +2293,17 @@
|
||||
color: var(--el-text-color-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.package-list-dialog-content {
|
||||
.package-list-header {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.amount-value {
|
||||
font-weight: 600;
|
||||
color: var(--el-color-warning);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user