f
This commit is contained in:
@@ -47,11 +47,13 @@ export const subPortalApi = {
|
|||||||
export const subordinateApi = {
|
export const subordinateApi = {
|
||||||
createInvitation: (data) => request.post('/subordinate/invitations', data || {}),
|
createInvitation: (data) => request.post('/subordinate/invitations', data || {}),
|
||||||
listSubordinates: (params) => request.get('/subordinate/subordinates', { params }),
|
listSubordinates: (params) => request.get('/subordinate/subordinates', { params }),
|
||||||
|
updateRemark: (data) => request.patch('/subordinate/subordinates/remark', data),
|
||||||
allocate: (data) => request.post('/subordinate/allocate', data),
|
allocate: (data) => request.post('/subordinate/allocate', data),
|
||||||
listAllocations: (params) => request.get('/subordinate/allocations', { params }),
|
listAllocations: (params) => request.get('/subordinate/allocations', { params }),
|
||||||
purchaseQuota: (data) => request.post('/subordinate/purchase-quota', data),
|
purchaseQuota: (data) => request.post('/subordinate/purchase-quota', data),
|
||||||
listQuotaPurchases: (params) => request.get('/subordinate/quota-purchases', { params }),
|
listQuotaPurchases: (params) => request.get('/subordinate/quota-purchases', { params }),
|
||||||
listChildQuotas: (params) => request.get('/subordinate/child-quotas', { params }),
|
listChildQuotas: (params) => request.get('/subordinate/child-quotas', { params }),
|
||||||
|
listChildApiCalls: (params) => request.get('/subordinate/child-api-calls', { params }),
|
||||||
listMyQuotas: () => request.get('/subordinate/my-quotas'),
|
listMyQuotas: () => request.get('/subordinate/my-quotas'),
|
||||||
assignSubscription: (data) => request.post('/subordinate/assign-subscription', data),
|
assignSubscription: (data) => request.post('/subordinate/assign-subscription', data),
|
||||||
listChildSubscriptions: (params) => request.get('/subordinate/child-subscriptions', { params }),
|
listChildSubscriptions: (params) => request.get('/subordinate/child-subscriptions', { params }),
|
||||||
|
|||||||
@@ -5,13 +5,46 @@
|
|||||||
>
|
>
|
||||||
<template #filters>
|
<template #filters>
|
||||||
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4 mb-4">
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4 mb-4">
|
||||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
<FilterSection>
|
||||||
<div class="text-sm text-gray-600">共找到 {{ total }} 个下属账号</div>
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
<div class="flex items-center gap-2">
|
<FilterItem label="备注">
|
||||||
<el-button class="toolbar-btn toolbar-btn-secondary" :loading="listLoading" @click="loadList">刷新列表</el-button>
|
<el-input
|
||||||
<el-button class="toolbar-btn toolbar-btn-primary" type="primary" :loading="invLoading" @click="createInvite">生成新邀请</el-button>
|
v-model="filters.remark"
|
||||||
|
placeholder="模糊搜索备注"
|
||||||
|
clearable
|
||||||
|
@input="handleFilterChange"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
</FilterItem>
|
||||||
|
<FilterItem label="手机号">
|
||||||
|
<el-input
|
||||||
|
v-model="filters.phone"
|
||||||
|
placeholder="模糊搜索手机号"
|
||||||
|
clearable
|
||||||
|
maxlength="11"
|
||||||
|
@input="handleFilterChange"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
</FilterItem>
|
||||||
|
<FilterItem label="下属公司">
|
||||||
|
<el-input
|
||||||
|
v-model="filters.company_name"
|
||||||
|
placeholder="模糊搜索公司名称"
|
||||||
|
clearable
|
||||||
|
@input="handleFilterChange"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
</FilterItem>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<template #stats>
|
||||||
|
共找到 {{ total }} 个下属账号
|
||||||
|
</template>
|
||||||
|
<template #buttons>
|
||||||
|
<el-button class="toolbar-btn toolbar-btn-secondary" @click="resetFilters">重置</el-button>
|
||||||
|
<el-button class="toolbar-btn toolbar-btn-secondary" :loading="listLoading" @click="loadList">刷新列表</el-button>
|
||||||
|
<el-button class="toolbar-btn toolbar-btn-primary" type="primary" :loading="invLoading" @click="createInvite">复制邀请链接</el-button>
|
||||||
|
</template>
|
||||||
|
</FilterSection>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -46,12 +79,41 @@
|
|||||||
<span class="font-medium text-gray-700">{{ row.phone || '-' }}</span>
|
<span class="font-medium text-gray-700">{{ row.phone || '-' }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="company_name" label="下属公司" min-width="220" show-overflow-tooltip>
|
<el-table-column prop="company_name" label="下属公司" min-width="200" show-overflow-tooltip>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag v-if="row.is_certified" type="success" size="small">{{ row.company_name }}</el-tag>
|
<el-tag v-if="row.is_certified" type="success" size="small">{{ row.company_name }}</el-tag>
|
||||||
<el-tag v-else type="info" size="small">未认证</el-tag>
|
<el-tag v-else type="info" size="small">未认证</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column prop="remark" label="备注" min-width="180">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input
|
||||||
|
v-model="row.remark"
|
||||||
|
placeholder="添加备注"
|
||||||
|
size="small"
|
||||||
|
clearable
|
||||||
|
:disabled="row._remarkSaving"
|
||||||
|
@blur="saveRemark(row)"
|
||||||
|
@keyup.enter="($event.target)?.blur()"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="产品与剩余额度" min-width="280">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div v-if="!row.product_quotas?.length" class="text-xs text-gray-400">暂无额度</div>
|
||||||
|
<div v-else class="flex flex-wrap gap-1">
|
||||||
|
<el-tag
|
||||||
|
v-for="item in row.product_quotas"
|
||||||
|
:key="item.product_id"
|
||||||
|
size="small"
|
||||||
|
type="info"
|
||||||
|
class="quota-tag"
|
||||||
|
>
|
||||||
|
{{ item.product_name }}:{{ item.available_quota }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="registered_at" label="注册时间" width="220">
|
<el-table-column prop="registered_at" label="注册时间" width="220">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="text-sm text-gray-600">{{ formatDateTime(row.registered_at) }}</div>
|
<div class="text-sm text-gray-600">{{ formatDateTime(row.registered_at) }}</div>
|
||||||
@@ -62,9 +124,17 @@
|
|||||||
<span class="font-semibold text-emerald-600">¥{{ formatMoney(row.balance) }}</span>
|
<span class="font-semibold text-emerald-600">¥{{ formatMoney(row.balance) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="110" fixed="right">
|
<el-table-column label="操作" width="200" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex flex-wrap items-center gap-1">
|
||||||
|
<el-button
|
||||||
|
class="table-action-btn action-calls"
|
||||||
|
text
|
||||||
|
bg
|
||||||
|
@click="openApiCalls(row)"
|
||||||
|
>
|
||||||
|
调用记录
|
||||||
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
class="table-action-btn action-allocate"
|
class="table-action-btn action-allocate"
|
||||||
:class="{ 'action-disabled': !row.is_certified }"
|
:class="{ 'action-disabled': !row.is_certified }"
|
||||||
@@ -194,12 +264,116 @@
|
|||||||
<el-button class="dialog-btn dialog-btn-secondary" @click="allocRecordVisible = false">关闭</el-button>
|
<el-button class="dialog-btn dialog-btn-secondary" @click="allocRecordVisible = false">关闭</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
v-model="apiCallsVisible"
|
||||||
|
:title="`下属调用记录${apiCallsTarget.company ? ' - ' + apiCallsTarget.company : ''}`"
|
||||||
|
width="960px"
|
||||||
|
@close="resetApiCallsDialog"
|
||||||
|
>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-3">
|
||||||
|
<el-input
|
||||||
|
v-model="apiCallsFilters.transaction_id"
|
||||||
|
placeholder="交易ID"
|
||||||
|
clearable
|
||||||
|
@keyup.enter="searchApiCalls"
|
||||||
|
/>
|
||||||
|
<el-input
|
||||||
|
v-model="apiCallsFilters.product_name"
|
||||||
|
placeholder="产品名称"
|
||||||
|
clearable
|
||||||
|
@keyup.enter="searchApiCalls"
|
||||||
|
/>
|
||||||
|
<el-select v-model="apiCallsFilters.status" placeholder="调用状态" clearable class="w-full">
|
||||||
|
<el-option label="全部" value="" />
|
||||||
|
<el-option label="成功" value="success" />
|
||||||
|
<el-option label="失败" value="failed" />
|
||||||
|
<el-option label="处理中" value="pending" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between gap-2">
|
||||||
|
<span class="text-sm text-gray-500">共 {{ apiCallsTotal }} 条记录</span>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<el-button class="toolbar-btn toolbar-btn-secondary" @click="resetApiCallsFilters">重置</el-button>
|
||||||
|
<el-button class="toolbar-btn toolbar-btn-primary" type="primary" :loading="apiCallsLoading" @click="searchApiCalls">查询</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table v-loading="apiCallsLoading" :data="apiCalls" border stripe max-height="420" size="small">
|
||||||
|
<el-table-column prop="transaction_id" label="交易ID" min-width="170" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="product_name" label="接口名称" min-width="140" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="status" label="状态" width="90">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="getApiCallStatusType(row.status)" size="small">{{ getApiCallStatusText(row.status) }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="translated_error_msg" label="错误信息" min-width="160" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span>{{ row.translated_error_msg || row.error_msg || '-' }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="client_ip" label="客户端IP" width="130" />
|
||||||
|
<el-table-column prop="start_at" label="调用时间" width="170">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ formatDateTime(row.start_at) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="90" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button size="small" type="primary" link @click="viewApiCallDetail(row)">详情</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<div class="pagination-wrapper !py-0">
|
||||||
|
<el-pagination
|
||||||
|
v-if="apiCallsTotal > 0"
|
||||||
|
v-model:current-page="apiCallsPage"
|
||||||
|
v-model:page-size="apiCallsPageSize"
|
||||||
|
:page-sizes="[10, 20, 50]"
|
||||||
|
:total="apiCallsTotal"
|
||||||
|
layout="total, sizes, prev, pager, next"
|
||||||
|
@size-change="loadChildApiCalls"
|
||||||
|
@current-change="loadChildApiCalls"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button class="dialog-btn dialog-btn-secondary" @click="apiCallsVisible = false">关闭</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog v-model="apiCallDetailVisible" title="调用详情" width="760px">
|
||||||
|
<div v-if="selectedApiCall" class="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
|
||||||
|
<div><span class="text-gray-500">交易ID:</span>{{ selectedApiCall.transaction_id }}</div>
|
||||||
|
<div>
|
||||||
|
<span class="text-gray-500">状态:</span>
|
||||||
|
<el-tag :type="getApiCallStatusType(selectedApiCall.status)" size="small">
|
||||||
|
{{ getApiCallStatusText(selectedApiCall.status) }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
|
<div><span class="text-gray-500">接口名称:</span>{{ selectedApiCall.product_name || '-' }}</div>
|
||||||
|
<div><span class="text-gray-500">客户端IP:</span>{{ selectedApiCall.client_ip || '-' }}</div>
|
||||||
|
<div><span class="text-gray-500">调用时间:</span>{{ formatDateTime(selectedApiCall.start_at) }}</div>
|
||||||
|
<div><span class="text-gray-500">完成时间:</span>{{ selectedApiCall.end_at ? formatDateTime(selectedApiCall.end_at) : '-' }}</div>
|
||||||
|
<div class="md:col-span-2">
|
||||||
|
<span class="text-gray-500">错误信息:</span>
|
||||||
|
{{ selectedApiCall.translated_error_msg || selectedApiCall.error_msg || '-' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button class="dialog-btn dialog-btn-secondary" @click="apiCallDetailVisible = false">关闭</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
</ListPageLayout>
|
</ListPageLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { financeApi, subordinateApi, subscriptionApi } from '@/api'
|
import { financeApi, subordinateApi, subscriptionApi } from '@/api'
|
||||||
|
import FilterItem from '@/components/common/FilterItem.vue'
|
||||||
|
import FilterSection from '@/components/common/FilterSection.vue'
|
||||||
import ListPageLayout from '@/components/common/ListPageLayout.vue'
|
import ListPageLayout from '@/components/common/ListPageLayout.vue'
|
||||||
import { useAliyunCaptcha } from '@/composables/useAliyunCaptcha'
|
import { useAliyunCaptcha } from '@/composables/useAliyunCaptcha'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
@@ -214,6 +388,11 @@ const page = ref(1)
|
|||||||
const pageSize = ref(20)
|
const pageSize = ref(20)
|
||||||
const listLoading = ref(false)
|
const listLoading = ref(false)
|
||||||
const invLoading = ref(false)
|
const invLoading = ref(false)
|
||||||
|
const filters = reactive({
|
||||||
|
remark: '',
|
||||||
|
phone: '',
|
||||||
|
company_name: ''
|
||||||
|
})
|
||||||
|
|
||||||
const allocVisible = ref(false)
|
const allocVisible = ref(false)
|
||||||
const allocLoading = ref(false)
|
const allocLoading = ref(false)
|
||||||
@@ -240,6 +419,21 @@ const allocationPageSize = ref(10)
|
|||||||
|
|
||||||
const parentSubscriptions = ref([])
|
const parentSubscriptions = ref([])
|
||||||
|
|
||||||
|
const apiCallsVisible = ref(false)
|
||||||
|
const apiCallsLoading = ref(false)
|
||||||
|
const apiCalls = ref([])
|
||||||
|
const apiCallsTotal = ref(0)
|
||||||
|
const apiCallsPage = ref(1)
|
||||||
|
const apiCallsPageSize = ref(10)
|
||||||
|
const apiCallsTarget = ref({ childId: '', company: '', phone: '' })
|
||||||
|
const apiCallsFilters = reactive({
|
||||||
|
transaction_id: '',
|
||||||
|
product_name: '',
|
||||||
|
status: ''
|
||||||
|
})
|
||||||
|
const apiCallDetailVisible = ref(false)
|
||||||
|
const selectedApiCall = ref(null)
|
||||||
|
|
||||||
const lastInvite = ref('')
|
const lastInvite = ref('')
|
||||||
const allocTotalAmount = computed(() => {
|
const allocTotalAmount = computed(() => {
|
||||||
const selected = allocProducts.value.find((item) => item.product_id === allocForm.value.productId)
|
const selected = allocProducts.value.find((item) => item.product_id === allocForm.value.productId)
|
||||||
@@ -270,9 +464,22 @@ const formatMoney = (value) => {
|
|||||||
const loadList = async () => {
|
const loadList = async () => {
|
||||||
listLoading.value = true
|
listLoading.value = true
|
||||||
try {
|
try {
|
||||||
const res = await subordinateApi.listSubordinates({ page: page.value, page_size: pageSize.value })
|
const params = {
|
||||||
|
page: page.value,
|
||||||
|
page_size: pageSize.value
|
||||||
|
}
|
||||||
|
if (filters.remark.trim()) params.remark = filters.remark.trim()
|
||||||
|
if (filters.phone.trim()) params.phone = filters.phone.trim()
|
||||||
|
if (filters.company_name.trim()) params.company_name = filters.company_name.trim()
|
||||||
|
|
||||||
|
const res = await subordinateApi.listSubordinates(params)
|
||||||
if (res?.success && res.data) {
|
if (res?.success && res.data) {
|
||||||
list.value = res.data.items || []
|
list.value = (res.data.items || []).map((item) => ({
|
||||||
|
...item,
|
||||||
|
remark: item.remark || '',
|
||||||
|
_remarkOriginal: item.remark || '',
|
||||||
|
_remarkSaving: false
|
||||||
|
}))
|
||||||
total.value = res.data.total || 0
|
total.value = res.data.total || 0
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -282,13 +489,51 @@ const loadList = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleFilterChange = () => {
|
||||||
|
page.value = 1
|
||||||
|
loadList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetFilters = () => {
|
||||||
|
filters.remark = ''
|
||||||
|
filters.phone = ''
|
||||||
|
filters.company_name = ''
|
||||||
|
page.value = 1
|
||||||
|
loadList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveRemark = async (row) => {
|
||||||
|
if (row._remarkSaving) return
|
||||||
|
const current = (row.remark || '').trim()
|
||||||
|
const original = (row._remarkOriginal || '').trim()
|
||||||
|
if (current === original) return
|
||||||
|
|
||||||
|
row._remarkSaving = true
|
||||||
|
try {
|
||||||
|
const res = await subordinateApi.updateRemark({
|
||||||
|
child_user_id: row.child_user_id,
|
||||||
|
remark: current
|
||||||
|
})
|
||||||
|
if (res?.success) {
|
||||||
|
row.remark = current
|
||||||
|
row._remarkOriginal = current
|
||||||
|
ElMessage.success('备注已保存')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
row.remark = row._remarkOriginal
|
||||||
|
ElMessage.error(e?.response?.data?.message || e?.message || '备注保存失败')
|
||||||
|
} finally {
|
||||||
|
row._remarkSaving = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const createInvite = async () => {
|
const createInvite = async () => {
|
||||||
invLoading.value = true
|
invLoading.value = true
|
||||||
try {
|
try {
|
||||||
const res = await subordinateApi.createInvitation({})
|
const res = await subordinateApi.createInvitation({})
|
||||||
if (res?.success && res.data) {
|
if (res?.success && res.data) {
|
||||||
lastInvite.value = res.data.invite_url || res.data.invite_token
|
lastInvite.value = res.data.invite_url || res.data.invite_token
|
||||||
ElMessage.success('邀请已生成,请复制链接发送给下属')
|
ElMessage.success('邀请链接已复制,可邀请多名下属重复使用')
|
||||||
await navigator.clipboard.writeText(res.data.invite_url || res.data.invite_token).catch(() => {})
|
await navigator.clipboard.writeText(res.data.invite_url || res.data.invite_token).catch(() => {})
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -462,6 +707,99 @@ const loadAllocationRecords = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getApiCallStatusType = (status) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'success':
|
||||||
|
return 'success'
|
||||||
|
case 'failed':
|
||||||
|
return 'danger'
|
||||||
|
case 'pending':
|
||||||
|
return 'warning'
|
||||||
|
default:
|
||||||
|
return 'info'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getApiCallStatusText = (status) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'success':
|
||||||
|
return '成功'
|
||||||
|
case 'failed':
|
||||||
|
return '失败'
|
||||||
|
case 'pending':
|
||||||
|
return '处理中'
|
||||||
|
default:
|
||||||
|
return '未知'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetApiCallsDialog = () => {
|
||||||
|
apiCalls.value = []
|
||||||
|
apiCallsTotal.value = 0
|
||||||
|
apiCallsPage.value = 1
|
||||||
|
apiCallsPageSize.value = 10
|
||||||
|
apiCallsTarget.value = { childId: '', company: '', phone: '' }
|
||||||
|
apiCallsFilters.transaction_id = ''
|
||||||
|
apiCallsFilters.product_name = ''
|
||||||
|
apiCallsFilters.status = ''
|
||||||
|
selectedApiCall.value = null
|
||||||
|
apiCallDetailVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetApiCallsFilters = () => {
|
||||||
|
apiCallsFilters.transaction_id = ''
|
||||||
|
apiCallsFilters.product_name = ''
|
||||||
|
apiCallsFilters.status = ''
|
||||||
|
apiCallsPage.value = 1
|
||||||
|
loadChildApiCalls()
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchApiCalls = () => {
|
||||||
|
apiCallsPage.value = 1
|
||||||
|
loadChildApiCalls()
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadChildApiCalls = async () => {
|
||||||
|
if (!apiCallsTarget.value.childId) return
|
||||||
|
apiCallsLoading.value = true
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
child_user_id: apiCallsTarget.value.childId,
|
||||||
|
page: apiCallsPage.value,
|
||||||
|
page_size: apiCallsPageSize.value
|
||||||
|
}
|
||||||
|
if (apiCallsFilters.transaction_id.trim()) params.transaction_id = apiCallsFilters.transaction_id.trim()
|
||||||
|
if (apiCallsFilters.product_name.trim()) params.product_name = apiCallsFilters.product_name.trim()
|
||||||
|
if (apiCallsFilters.status) params.status = apiCallsFilters.status
|
||||||
|
|
||||||
|
const res = await subordinateApi.listChildApiCalls(params)
|
||||||
|
if (res?.success && res.data) {
|
||||||
|
apiCalls.value = res.data.items || []
|
||||||
|
apiCallsTotal.value = res.data.total || 0
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error(e?.response?.data?.message || e?.message || '加载调用记录失败')
|
||||||
|
} finally {
|
||||||
|
apiCallsLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const openApiCalls = async (row) => {
|
||||||
|
apiCallsTarget.value = {
|
||||||
|
childId: row.child_user_id,
|
||||||
|
company: row.is_certified ? row.company_name : '',
|
||||||
|
phone: row.phone || ''
|
||||||
|
}
|
||||||
|
apiCallsPage.value = 1
|
||||||
|
apiCallsVisible.value = true
|
||||||
|
await loadChildApiCalls()
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewApiCallDetail = (row) => {
|
||||||
|
selectedApiCall.value = row
|
||||||
|
apiCallDetailVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
const handleSizeChange = (size) => {
|
const handleSizeChange = (size) => {
|
||||||
pageSize.value = size
|
pageSize.value = size
|
||||||
page.value = 1
|
page.value = 1
|
||||||
@@ -541,6 +879,10 @@ onUnmounted(() => {
|
|||||||
color: #2563eb;
|
color: #2563eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-calls {
|
||||||
|
color: #7c3aed;
|
||||||
|
}
|
||||||
|
|
||||||
.action-subscribe {
|
.action-subscribe {
|
||||||
color: #059669;
|
color: #059669;
|
||||||
}
|
}
|
||||||
@@ -588,10 +930,19 @@ onUnmounted(() => {
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.quota-tag {
|
||||||
|
max-width: 100%;
|
||||||
|
white-space: normal;
|
||||||
|
height: auto;
|
||||||
|
line-height: 1.4;
|
||||||
|
padding-top: 2px;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
:deep(.el-table) {
|
:deep(.el-table) {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
min-width: 860px;
|
min-width: 980px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-table th),
|
:deep(.el-table th),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="w-full auth-fade-in">
|
<div class="w-full auth-fade-in">
|
||||||
<div class="text-center mb-6">
|
<div class="text-center mb-6">
|
||||||
<h2 class="auth-title">注册账号</h2>
|
<h2 class="auth-title">注册账号</h2>
|
||||||
<p class="auth-subtitle">填写邀请码与手机号,完成账号注册</p>
|
<p class="auth-subtitle">填写主账号邀请码与手机号,完成账号注册</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="space-y-4" @submit.prevent="onRegister">
|
<form class="space-y-4" @submit.prevent="onRegister">
|
||||||
|
|||||||
@@ -132,6 +132,16 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
v-if="isSubordinate"
|
||||||
|
label="官方价格"
|
||||||
|
:width="isMobile ? 100 : 120"
|
||||||
|
>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span class="font-semibold text-gray-700">¥{{ formatPrice(row.product?.price) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-if="isSubordinate"
|
v-if="isSubordinate"
|
||||||
label="剩余额度"
|
label="剩余额度"
|
||||||
|
|||||||
Reference in New Issue
Block a user