feat:代理现金余额不足100元展示、店铺业务员选择展示与筛选
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 5m34s

This commit is contained in:
luo
2026-07-20 12:17:02 +08:00
parent ca338dd345
commit e95dc8e4f5
12 changed files with 334 additions and 49 deletions

View File

@@ -6,6 +6,8 @@ import { BaseService } from '../BaseService'
import type {
PlatformAccount,
AccountQueryParams,
PlatformSalesperson,
PlatformSalespersonQueryParams,
CreatePlatformAccountParams,
BaseResponse,
PaginationResponse
@@ -23,6 +25,16 @@ export class AccountService extends BaseService {
return this.getPage<PlatformAccount>('/api/admin/accounts', params)
}
/**
* 获取启用的平台业务员候选
* GET /api/admin/accounts?account_type=platform&status=1
*/
static getPlatformSalespeople(
params: PlatformSalespersonQueryParams
): Promise<PaginationResponse<PlatformSalesperson>> {
return this.getPage<PlatformSalesperson>('/api/admin/accounts', params)
}
/**
* 创建账号
* POST /api/admin/accounts

View File

@@ -107,6 +107,20 @@ export interface AccountQueryParams extends PaginationParams {
enterprise_id?: number // 按企业ID筛选
}
// 平台业务员候选账号
export interface PlatformSalesperson {
account_id: number
account_name: string
phone_masked: string
}
// 平台业务员候选查询参数
export interface PlatformSalespersonQueryParams extends PaginationParams {
account_type: 'platform'
status: AccountStatus
account_name?: string
}
// 代理商查询参数
export interface AgentQueryParams extends PaginationParams {
keyword?: string

View File

@@ -211,6 +211,10 @@ export interface ShopFundSummaryItem {
phone?: string // 主账号手机号
main_balance: number // 预充值余额(分)
main_frozen_balance: number // 预充值冻结余额(分)
balance: number // 现金余额(分)
frozen_balance: number // 现金冻结金额(分)
cash_available: number // 现金可用余额(分)
low_balance_warning: boolean // 现金可用余额不足100元预警
total_commission: number // 总佣金(分)
available_commission: number // 可提现佣金(分)
frozen_commission: number // 冻结中佣金(分)

View File

@@ -21,6 +21,9 @@ export interface ShopResponse {
contact_name: string // 联系人姓名
contact_phone: string // 联系人电话
status: number // 状态 (0:禁用, 1:启用)
business_owner_account_id?: number | null // 平台业务员账号ID
business_owner_name?: string // 平台业务员名称
business_owner_phone_masked?: string // 平台业务员脱敏手机号
}
// 店铺列表查询参数
@@ -32,6 +35,7 @@ export interface ShopQueryParams extends PaginationParams {
parent_id?: number | null // 上级店铺ID
level?: number | null // 店铺层级 (1-7级)
status?: number | null // 状态 (0:禁用, 1:启用)
business_owner_account_id?: number | null // 平台业务员账号ID
page?: number // 页码
page_size?: number // 每页数量
}
@@ -50,6 +54,7 @@ export interface CreateShopParams {
address?: string // 详细地址
contact_name?: string // 联系人姓名
contact_phone?: string // 联系人电话
business_owner_account_id?: number | null // 平台业务员账号ID
}
// 更新店铺参数
@@ -62,6 +67,7 @@ export interface UpdateShopParams {
address?: string // 详细地址
contact_name?: string // 联系人姓名
contact_phone?: string // 联系人电话
business_owner_account_id?: number | null // 平台业务员账号ID
}
// 店铺列表分页响应

View File

@@ -550,7 +550,9 @@
{ label: '店铺名称', prop: 'shop_name' },
{ label: '用户名', prop: 'username' },
{ label: '手机号', prop: 'phone' },
{ label: '预充值余额', prop: 'main_balance' },
{ label: '现金余额', prop: 'balance' },
{ label: '冻结金额', prop: 'frozen_balance' },
{ label: '余额预警', prop: 'low_balance_warning' },
{ label: '总佣金', prop: 'total_commission' },
{ label: '可提现', prop: 'available_commission' },
{ label: '冻结中', prop: 'frozen_commission' },
@@ -637,17 +639,33 @@
width: 120
},
{
prop: 'main_balance',
label: '预充值余额',
prop: 'balance',
label: '现金余额',
minWidth: 130,
formatter: (row: ShopFundSummaryItem) => {
return h(
'span',
{ style: 'color: var(--el-color-primary); font-weight: 500' },
formatMoney(row.main_balance)
formatMoney(row.balance)
)
}
},
{
prop: 'frozen_balance',
label: '冻结金额',
minWidth: 120,
formatter: (row: ShopFundSummaryItem) => formatMoney(row.frozen_balance)
},
{
prop: 'low_balance_warning',
label: '余额预警',
minWidth: 170,
formatter: (row: ShopFundSummaryItem) => {
if (!row.low_balance_warning) return '-'
return h(ElTag, { type: 'danger' }, () => '现金余额不足100元')
}
},
{
prop: 'total_commission',
label: '总佣金',

View File

@@ -126,6 +126,37 @@
</ElCol>
</ElRow>
<ElRow :gutter="20">
<ElCol :span="12">
<ElFormItem label="平台业务员">
<ElSelect
v-model="formData.business_owner_account_id"
filterable
remote
clearable
placeholder="请选择或搜索平台业务员"
:remote-method="searchPlatformSalespeople"
:loading="salespersonLoading"
style="width: 100%"
>
<ElOption
v-for="salesperson in salespersonOptions"
:key="salesperson.account_id"
:label="salesperson.account_name"
:value="salesperson.account_id"
>
<div style="display: flex; justify-content: space-between">
<span>{{ salesperson.account_name }}</span>
<span style="font-size: 12px; color: var(--el-text-color-secondary)">
{{ salesperson.phone_masked }}
</span>
</div>
</ElOption>
</ElSelect>
</ElFormItem>
</ElCol>
</ElRow>
<!-- 新增店铺时的初始账号信息 -->
<template v-if="dialogType === 'add'">
<div class="form-section-title">
@@ -207,6 +238,16 @@
</template>
</ElDialog>
<ElDialog v-model="detailDialogVisible" title="店铺详情" width="500px">
<ElDescriptions v-if="detailShop" :column="1" border>
<ElDescriptionsItem label="店铺名称">{{ detailShop.shop_name }}</ElDescriptionsItem>
<ElDescriptionsItem label="店铺编号">{{ detailShop.shop_code }}</ElDescriptionsItem>
<ElDescriptionsItem label="平台业务员">
{{ formatBusinessOwner(detailShop) }}
</ElDescriptionsItem>
</ElDescriptions>
</ElDialog>
<!-- 店铺默认角色管理对话框 -->
<ElDialog
v-model="defaultRolesDialogVisible"
@@ -287,10 +328,10 @@
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import { useAuth } from '@/composables/useAuth'
import { generateShopCode } from '@/utils/codeGenerator'
import { ShopService, RoleService } from '@/api/modules'
import { ShopService, RoleService, AccountService } from '@/api/modules'
import type { SearchFormItem } from '@/types'
import type { ShopResponse, ShopRoleResponse } from '@/types/api'
import { RoleType, RoleStatus } from '@/types/api'
import type { PlatformSalesperson, ShopResponse, ShopRoleResponse } from '@/types/api'
import { AccountStatus, RoleType, RoleStatus } from '@/types/api'
import { formatDateTime } from '@/utils/business/format'
import { CommonStatus, getStatusText, STATUS_SELECT_OPTIONS } from '@/config/constants'
import { regionData } from '@/utils/constants/regionData'
@@ -307,6 +348,10 @@
const submitLoading = ref(false)
const defaultRoleLoading = ref(false)
const defaultRoleList = ref<any[]>([])
const salespersonLoading = ref(false)
const salespersonOptions = ref<PlatformSalesperson[]>([])
const detailDialogVisible = ref(false)
const detailShop = ref<ShopResponse | null>(null)
// 级联选择相关
const parentShopCascadeOptions = ref<any[]>([])
@@ -370,6 +415,39 @@
}
}
const searchPlatformSalespeople = async (query: string) => {
salespersonLoading.value = true
try {
const res = await AccountService.getPlatformSalespeople({
page: 1,
page_size: 20,
account_type: 'platform',
status: AccountStatus.ENABLED,
account_name: query || undefined
})
if (res.code === 0) {
salespersonOptions.value = res.data.items || []
}
} catch (error) {
console.error('获取平台业务员列表失败:', error)
salespersonOptions.value = []
} finally {
salespersonLoading.value = false
}
}
const formatBusinessOwner = (shop: ShopResponse) => {
if (!shop.business_owner_name) return '-'
return shop.business_owner_phone_masked
? `${shop.business_owner_name} (${shop.business_owner_phone_masked})`
: shop.business_owner_name
}
const showDetail = (row: ShopResponse) => {
detailShop.value = row
detailDialogVisible.value = true
}
// 定义表单搜索初始值
const initialSearchState = {
shop_name: '',
@@ -377,7 +455,8 @@
parent_shop_name: '',
parent_id: undefined as number | undefined,
level: undefined as number | undefined,
status: undefined as number | undefined
status: undefined as number | undefined,
business_owner_account_id: undefined as number | undefined
}
// 响应式表单数据
@@ -457,6 +536,23 @@
clearable: true,
placeholder: '请选择状态'
}
},
{
label: '平台业务员',
prop: 'business_owner_account_id',
type: 'select',
config: {
clearable: true,
filterable: true,
remote: true,
remoteMethod: (query: string) => searchPlatformSalespeople(query),
placeholder: '请选择或搜索平台业务员'
},
options: () =>
salespersonOptions.value.map((salesperson) => ({
label: `${salesperson.account_name} (${salesperson.phone_masked})`,
value: salesperson.account_id
}))
}
])
@@ -468,6 +564,7 @@
{ label: '所在地区', prop: 'region' },
{ label: '联系人', prop: 'contact_name' },
{ label: '联系电话', prop: 'contact_phone' },
{ label: '平台业务员', prop: 'business_owner_name' },
...(canModifyShopStatus ? [{ label: '状态', prop: 'status' }] : []),
{ label: '创建时间', prop: 'created_at' },
{ label: '操作', prop: 'operation' }
@@ -497,6 +594,7 @@
formData.address = row.address || ''
formData.contact_name = row.contact_name || ''
formData.contact_phone = row.contact_phone || ''
formData.business_owner_account_id = row.business_owner_account_id ?? null
formData.status = row.status
formData.init_username = ''
formData.init_password = ''
@@ -514,6 +612,7 @@
formData.address = ''
formData.contact_name = ''
formData.contact_phone = ''
formData.business_owner_account_id = null
formData.status = CommonStatus.ENABLED
formData.init_username = ''
formData.init_password = ''
@@ -597,6 +696,13 @@
label: '联系电话',
width: 130
},
{
prop: 'business_owner_name',
label: '平台业务员',
minWidth: 180,
showOverflowTooltip: true,
formatter: (row: ShopResponse) => formatBusinessOwner(row)
},
...(canModifyShopStatus
? [
{
@@ -630,6 +736,12 @@
const getActions = (row: ShopResponse) => {
const actions: any[] = []
actions.push({
label: '详情',
handler: () => showDetail(row),
type: 'primary'
})
if (hasAuth('shop:look_customer')) {
actions.push({
label: '账号列表',
@@ -685,7 +797,8 @@
init_username: '',
init_password: '',
init_phone: '',
default_role_id: undefined as number | undefined
default_role_id: undefined as number | undefined,
business_owner_account_id: null as number | null
})
// 处理编码生成
@@ -766,6 +879,7 @@
loadTopLevelShops() // 加载顶级店铺用于级联选择
searchDefaultRoles('') // 加载初始默认角色列表
searchParentShops('') // 加载上级店铺选项
searchPlatformSalespeople('') // 加载启用的平台业务员选项
})
// 获取店铺列表
@@ -780,7 +894,8 @@
parent_shop_name: searchForm.parent_shop_name || undefined,
parent_id: searchForm.parent_id,
level: searchForm.level,
status: searchForm.status
status: searchForm.status,
business_owner_account_id: searchForm.business_owner_account_id
}
const res = await ShopService.getShops(params)
if (res.code === 0) {
@@ -850,7 +965,8 @@
init_username: formData.init_username,
init_password: formData.init_password,
init_phone: formData.init_phone,
default_role_id: formData.default_role_id
default_role_id: formData.default_role_id,
business_owner_account_id: formData.business_owner_account_id
}
// 可选字段 - parent_id 可能是数组(级联选择器)或数字
@@ -871,7 +987,8 @@
} else {
const data: any = {
shop_name: formData.shop_name,
status: formData.status
status: formData.status,
business_owner_account_id: formData.business_owner_account_id
}
// 可选字段