更新
This commit is contained in:
@@ -51,28 +51,51 @@
|
||||
</nav>
|
||||
|
||||
<div v-if="activeTab === 'links'" class="tab-content links-tab">
|
||||
<div class="section-heading">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2>获客助手分流方案</h2>
|
||||
<p>选择几名医助就生成几条成员规则;官方链接只在方案顶部复制,成员行不重复展示链接。</p>
|
||||
</div>
|
||||
<el-button type="primary" :icon="Plus" @click="openPoolDialog()">新建分流方案</el-button>
|
||||
</div>
|
||||
|
||||
<div v-if="overview.pools.length" class="pool-layout">
|
||||
<aside class="pool-sidebar">
|
||||
<button
|
||||
v-for="pool in overview.pools"
|
||||
:key="pool.id"
|
||||
class="pool-item"
|
||||
:class="{ active: Number(pool.id) === selectedPoolId }"
|
||||
@click="selectedPoolId = Number(pool.id)"
|
||||
>
|
||||
<span class="pool-status" :class="Number(pool.status) === 1 ? 'online' : 'offline'" />
|
||||
<span><strong>{{ pool.name }}</strong><small>{{ memberSummary(pool) }} · {{ pool.main_url ? '官方链接已生成' : '待生成链接' }}</small></span>
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</button>
|
||||
</aside>
|
||||
</div>
|
||||
<div class="section-heading-actions">
|
||||
<span v-if="selectedPoolIds.length" class="selection-count">已选 {{ selectedPoolIds.length }} 个方案</span>
|
||||
<el-button
|
||||
:icon="User"
|
||||
:disabled="!selectedPoolIds.length"
|
||||
@click="openAccessDialog()"
|
||||
>批量设置访问操作</el-button>
|
||||
<el-button type="primary" :icon="Plus" @click="openPoolDialog()">新建分流方案</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="overview.pools.length" class="pool-layout">
|
||||
<aside class="pool-sidebar">
|
||||
<div
|
||||
v-for="pool in overview.pools"
|
||||
:key="pool.id"
|
||||
class="pool-select-row"
|
||||
:class="{ active: Number(pool.id) === selectedPoolId }"
|
||||
>
|
||||
<el-checkbox
|
||||
:model-value="selectedPoolIds.includes(Number(pool.id))"
|
||||
:disabled="!pool.can_manage_access"
|
||||
:aria-label="`选择方案 ${pool.name}`"
|
||||
@change="(checked) => togglePoolSelection(pool, checked)"
|
||||
@click.stop
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="pool-item"
|
||||
@click="selectedPoolId = Number(pool.id)"
|
||||
>
|
||||
<span class="pool-status" :class="Number(pool.status) === 1 ? 'online' : 'offline'" />
|
||||
<span>
|
||||
<strong>{{ pool.name }}</strong>
|
||||
<small>{{ memberSummary(pool) }} · {{ accessSummary(pool) }}</small>
|
||||
</span>
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="pool-main">
|
||||
<div v-if="selectedPool" class="pool-toolbar">
|
||||
@@ -90,8 +113,9 @@
|
||||
<el-button :icon="CircleCheck" :loading="checkingApi" @click="checkApiPermission">验证 API</el-button>
|
||||
<el-button :icon="DocumentCopy" :disabled="!selectedPool.main_url" @click="copyText(selectedPool.main_url, '官方获客链接')">复制链接</el-button>
|
||||
<el-button :icon="DocumentCopy" @click="copyText(selectedPool.install_code, 'JS 安装代码')">复制 JS</el-button>
|
||||
<el-button :icon="Edit" @click="openPoolDialog(selectedPool)">编辑方案</el-button>
|
||||
<el-button type="danger" plain :icon="Delete" :loading="deletingPoolId === Number(selectedPool.id)" :disabled="deletingPoolId > 0" @click="removePool(selectedPool)">删除</el-button>
|
||||
<el-button v-if="selectedPool.can_manage_access" :icon="User" @click="openAccessDialog([Number(selectedPool.id)])">设置访问操作</el-button>
|
||||
<el-button v-if="selectedPool.can_operate" :icon="Edit" @click="openPoolDialog(selectedPool)">编辑方案</el-button>
|
||||
<el-button v-if="selectedPool.can_delete" type="danger" plain :icon="Delete" :loading="deletingPoolId === Number(selectedPool.id)" :disabled="deletingPoolId > 0" @click="removePool(selectedPool)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -142,12 +166,12 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="上线" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-switch :model-value="Number(row.enabled) === 1" :loading="togglingMemberId === Number(row.id)" @change="(value) => handleMemberToggle(row, value)" />
|
||||
<el-switch :model-value="Number(row.enabled) === 1" :disabled="!selectedPool.can_operate" :loading="togglingMemberId === Number(row.id)" @change="(value) => handleMemberToggle(row, value)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" min-width="100" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="openMemberDialog(row)">编辑规则</el-button>
|
||||
<el-button v-if="selectedPool.can_operate" type="primary" link @click="openMemberDialog(row)">编辑规则</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty><el-empty :image-size="72" description="编辑方案并选择获客医助" /></template>
|
||||
@@ -393,6 +417,70 @@
|
||||
<template #footer><el-button :disabled="savingPool" @click="poolDialogVisible = false">取消</el-button><el-button type="primary" :loading="savingPool" @click="savePool">{{ poolForm.id ? '保存方案' : '保存并生成链接' }}</el-button></template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="accessDialogVisible"
|
||||
title="批量设置他人访问操作"
|
||||
width="620px"
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="!savingAccess"
|
||||
>
|
||||
<el-alert
|
||||
type="info"
|
||||
show-icon
|
||||
:closable="false"
|
||||
:title="`将设置 ${accessForm.pool_ids.length} 个分流方案`"
|
||||
description="被添加的账号可以查看并编辑方案、成员规则和浮窗配置;不能删除方案,也不能继续分配操作权限。"
|
||||
/>
|
||||
<el-form class="access-form" label-position="top">
|
||||
<el-form-item label="设置方式" required>
|
||||
<el-radio-group v-model="accessForm.action" :disabled="savingAccess">
|
||||
<el-radio-button value="grant">添加操作人</el-radio-button>
|
||||
<el-radio-button value="revoke">移除操作人</el-radio-button>
|
||||
</el-radio-group>
|
||||
<span class="form-tip">批量添加不会覆盖各方案已有操作人;批量移除只撤销本次选中的账号。</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择账号" required>
|
||||
<el-select
|
||||
v-model="accessForm.operator_admin_ids"
|
||||
multiple
|
||||
filterable
|
||||
clearable
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
:max-collapse-tags="3"
|
||||
:multiple-limit="100"
|
||||
:disabled="savingAccess"
|
||||
placeholder="搜索姓名或部门"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="operator in overview.operator_options"
|
||||
:key="operator.id"
|
||||
:label="operatorOptionLabel(operator)"
|
||||
:value="Number(operator.id)"
|
||||
:disabled="accessForm.action === 'grant' && !operator.can_grant"
|
||||
/>
|
||||
</el-select>
|
||||
<span class="form-tip">添加时仅可选择已启用且拥有本页面权限的账号;失效账号仍可用于移除历史授权。</span>
|
||||
</el-form-item>
|
||||
<div v-if="accessDialogPools.length" class="access-pool-preview">
|
||||
<strong>当前授权</strong>
|
||||
<div v-for="pool in accessDialogPools.slice(0, 5)" :key="pool.id">
|
||||
<span>{{ pool.name }}</span>
|
||||
<small>{{ operatorNames(pool) }}</small>
|
||||
</div>
|
||||
<p v-if="accessDialogPools.length > 5">另有 {{ accessDialogPools.length - 5 }} 个方案</p>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button :disabled="savingAccess" @click="accessDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="savingAccess" @click="savePoolOperators">
|
||||
{{ accessForm.action === 'grant' ? '批量添加' : '批量移除' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="memberDialogVisible" title="编辑医助分流规则" width="560px" destroy-on-close :close-on-click-modal="false">
|
||||
<el-form label-position="top">
|
||||
<el-form-item label="获客医助">
|
||||
@@ -424,6 +512,7 @@ import {
|
||||
Promotion, Refresh, Search, SetUp, User, Warning
|
||||
} from '@element-plus/icons-vue'
|
||||
import {
|
||||
wecomPromotionBatchSetOperators,
|
||||
wecomPromotionCheckApiPermission,
|
||||
wecomPromotionCustomerStats,
|
||||
wecomPromotionDeletePool,
|
||||
@@ -454,6 +543,16 @@ interface PromotionMemberOption {
|
||||
dept_names: string[]
|
||||
}
|
||||
|
||||
interface PromotionOperatorOption {
|
||||
id: number
|
||||
name: string
|
||||
disable: number
|
||||
can_grant: boolean
|
||||
display_dept_id?: number
|
||||
dept_ids: number[]
|
||||
dept_names: string[]
|
||||
}
|
||||
|
||||
interface PromotionMemberTreeNode {
|
||||
value: number | string
|
||||
label: string
|
||||
@@ -466,12 +565,13 @@ interface PromotionMemberTreeNode {
|
||||
}
|
||||
|
||||
const emptyOverview = () => ({
|
||||
meta: { scope_label: '', generated_at: '' },
|
||||
meta: { admin_id: 0, scope_label: '', generated_at: '' },
|
||||
config: { mode: 'internal', configured: false, ready: false, missing: [] as string[], corp_id_masked: '', agent_id: '', secret_configured: false, callback_ready: false, callback_url: '', official_doc: '' },
|
||||
summary: { configured_apps: 0, pool_count: 0, online_links: 0, today_clicks: 0 },
|
||||
pools: [] as any[],
|
||||
links: [] as any[],
|
||||
member_options: [] as PromotionMemberOption[],
|
||||
operator_options: [] as PromotionOperatorOption[],
|
||||
department_options: [] as PromotionDepartmentOption[],
|
||||
customer_acquisition_link_example: 'https://work.weixin.qq.com/ca/xxxxxxxx'
|
||||
})
|
||||
@@ -481,6 +581,7 @@ const loading = ref(false)
|
||||
const activeTab = ref<TabName>('links')
|
||||
const selectedPoolId = ref<number>()
|
||||
const selectedInstallPoolId = ref<number>()
|
||||
const selectedPoolIds = ref<number[]>([])
|
||||
const poolDialogVisible = ref(false)
|
||||
const savingPool = ref(false)
|
||||
const checkingApi = ref(false)
|
||||
@@ -488,7 +589,10 @@ const memberDialogVisible = ref(false)
|
||||
const savingMember = ref(false)
|
||||
const togglingMemberId = ref(0)
|
||||
const deletingPoolId = ref(0)
|
||||
const accessDialogVisible = ref(false)
|
||||
const savingAccess = ref(false)
|
||||
const poolForm = reactive({ id: 0, name: '', fallback_url: '', status: 1, member_admin_ids: [] as number[], skip_verify: 0, main_url: '' })
|
||||
const accessForm = reactive({ pool_ids: [] as number[], operator_admin_ids: [] as number[], action: 'grant' as 'grant' | 'revoke' })
|
||||
const memberForm = reactive({ id: 0, name: '', userid: '', daily_limit: 0, status: 1, active_range: [] as string[], remark: '' })
|
||||
const customerStatsLoading = ref(false)
|
||||
const customerStatsLoaded = ref(false)
|
||||
@@ -510,6 +614,7 @@ const customerStats = reactive({
|
||||
const selectedPool = computed(() => overview.pools.find((item: any) => Number(item.id) === selectedPoolId.value))
|
||||
const selectedMemberRules = computed(() => Array.isArray(selectedPool.value?.member_rules) ? selectedPool.value.member_rules : [])
|
||||
const selectedInstallPool = computed(() => overview.pools.find((item: any) => Number(item.id) === selectedInstallPoolId.value))
|
||||
const accessDialogPools = computed(() => overview.pools.filter((item: any) => accessForm.pool_ids.includes(Number(item.id))))
|
||||
const memberTreeProps = { value: 'value', label: 'label', children: 'children', disabled: 'disabled' }
|
||||
const memberDepartmentTree = computed(() => buildMemberDepartmentTree(overview.department_options, overview.member_options))
|
||||
const memberTreeDefaultExpandedKeys = computed(() => memberDepartmentTree.value.map((node) => node.value))
|
||||
@@ -527,17 +632,29 @@ const customerMemberOptions = computed(() => customerStats.member_options.length
|
||||
department_name: Array.isArray(item.dept_names) ? item.dept_names.join(' / ') : (item.department_name || item.dept_name || '')
|
||||
})))
|
||||
|
||||
watch(() => overview.pools.map((item: any) => Number(item.id)).join(','), () => {
|
||||
const ids = overview.pools.map((item: any) => Number(item.id))
|
||||
if (!selectedPoolId.value || !ids.includes(selectedPoolId.value)) selectedPoolId.value = ids[0]
|
||||
if (!selectedInstallPoolId.value || !ids.includes(selectedInstallPoolId.value)) selectedInstallPoolId.value = ids[0]
|
||||
}, { immediate: true })
|
||||
watch(() => overview.pools.map((item: any) => `${Number(item.id)}:${item.can_manage_access ? 1 : 0}`).join(','), () => {
|
||||
const ids = overview.pools.map((item: any) => Number(item.id))
|
||||
const manageableIds = new Set(overview.pools
|
||||
.filter((item: any) => item.can_manage_access)
|
||||
.map((item: any) => Number(item.id)))
|
||||
if (!selectedPoolId.value || !ids.includes(selectedPoolId.value)) selectedPoolId.value = ids[0]
|
||||
if (!selectedInstallPoolId.value || !ids.includes(selectedInstallPoolId.value)) selectedInstallPoolId.value = ids[0]
|
||||
selectedPoolIds.value = selectedPoolIds.value.filter((id) => manageableIds.has(id))
|
||||
}, { immediate: true })
|
||||
|
||||
watch(activeTab, (tab) => {
|
||||
if (tab === 'customer-stats' && !customerStatsLoaded.value) loadCustomerStats()
|
||||
})
|
||||
watch(activeTab, (tab) => {
|
||||
if (tab === 'customer-stats' && !customerStatsLoaded.value) loadCustomerStats()
|
||||
})
|
||||
|
||||
watch(() => accessForm.action, (action) => {
|
||||
if (action !== 'grant') return
|
||||
const grantableIds = new Set(overview.operator_options
|
||||
.filter((operator) => operator.can_grant)
|
||||
.map((operator) => Number(operator.id)))
|
||||
accessForm.operator_admin_ids = accessForm.operator_admin_ids.filter((id) => grantableIds.has(Number(id)))
|
||||
})
|
||||
|
||||
async function loadOverview() {
|
||||
async function loadOverview() {
|
||||
loading.value = true
|
||||
try {
|
||||
const result: any = await wecomPromotionOverview()
|
||||
@@ -546,9 +663,79 @@ async function loadOverview() {
|
||||
ElMessage.error(error?.message || '企业微信推广配置加载失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function togglePoolSelection(pool: any, checked: unknown) {
|
||||
if (!pool?.can_manage_access) return
|
||||
const id = Number(pool.id)
|
||||
const next = new Set(selectedPoolIds.value)
|
||||
checked ? next.add(id) : next.delete(id)
|
||||
selectedPoolIds.value = [...next]
|
||||
}
|
||||
|
||||
function openAccessDialog(poolIds: number[] = selectedPoolIds.value) {
|
||||
const manageableIds = new Set(overview.pools
|
||||
.filter((pool: any) => pool.can_manage_access)
|
||||
.map((pool: any) => Number(pool.id)))
|
||||
const ids = [...new Set(poolIds.map(Number).filter((id) => manageableIds.has(id)))]
|
||||
if (!ids.length) return ElMessage.warning('请先选择可管理的分流方案')
|
||||
Object.assign(accessForm, {
|
||||
pool_ids: ids,
|
||||
operator_admin_ids: [],
|
||||
action: 'grant'
|
||||
})
|
||||
accessDialogVisible.value = true
|
||||
}
|
||||
|
||||
async function savePoolOperators() {
|
||||
if (!accessForm.pool_ids.length) return ElMessage.warning('请至少选择一个分流方案')
|
||||
if (!accessForm.operator_admin_ids.length) return ElMessage.warning('请至少选择一名操作人')
|
||||
savingAccess.value = true
|
||||
try {
|
||||
const result = await wecomPromotionBatchSetOperators({
|
||||
pool_ids: [...accessForm.pool_ids],
|
||||
operator_admin_ids: [...accessForm.operator_admin_ids],
|
||||
action: accessForm.action
|
||||
})
|
||||
accessDialogVisible.value = false
|
||||
selectedPoolIds.value = []
|
||||
await loadOverview()
|
||||
const actionLabel = accessForm.action === 'grant' ? '添加' : '移除'
|
||||
ElMessage.success(result?.affected
|
||||
? `已批量${actionLabel} ${result.affected} 条方案操作权限`
|
||||
: '权限设置已检查,没有需要变更的记录')
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error?.message || '批量设置访问操作失败')
|
||||
} finally {
|
||||
savingAccess.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function operatorOptionLabel(operator: PromotionOperatorOption) {
|
||||
const departments = Array.isArray(operator.dept_names) && operator.dept_names.length
|
||||
? operator.dept_names.join(' / ')
|
||||
: '未分部门'
|
||||
const unavailable = Number(operator.disable) === 1
|
||||
? ' · 已禁用'
|
||||
: (!operator.can_grant ? ' · 无页面权限' : '')
|
||||
return `${operator.name} · ${departments}${unavailable}`
|
||||
}
|
||||
|
||||
function operatorNames(pool: any) {
|
||||
const operators = Array.isArray(pool?.operators) ? pool.operators : []
|
||||
if (!operators.length) return '仅原管理范围可操作'
|
||||
return operators
|
||||
.map((operator: any) => `${operator.name || `账号 ${operator.id}`}${Number(operator.disable) === 1 ? '(已禁用)' : ''}`)
|
||||
.join('、')
|
||||
}
|
||||
|
||||
function accessSummary(pool: any) {
|
||||
const linkState = pool?.main_url ? '官方链接已生成' : '待生成链接'
|
||||
const operatorCount = Array.isArray(pool?.operator_admin_ids) ? pool.operator_admin_ids.length : 0
|
||||
return operatorCount > 0 ? `${linkState} · ${operatorCount} 人可操作` : linkState
|
||||
}
|
||||
|
||||
function openPoolDialog(pool?: any) {
|
||||
const selectableMemberIds = new Set(overview.member_options.map((member) => Number(member.id)))
|
||||
Object.assign(poolForm, pool ? {
|
||||
@@ -1074,12 +1261,17 @@ h1, h2, h3, p { margin: 0; }
|
||||
.tab-nav button { display: flex; align-items: center; gap: 7px; min-width: 132px; height: 54px; justify-content: center; border: 0; border-bottom: 3px solid transparent; color: #5e6d80; background: transparent; cursor: pointer; font-size: 14px; }
|
||||
.tab-nav button.active { border-bottom-color: var(--teal); color: #0d8277; font-weight: 700; }
|
||||
.tab-content { min-height: 460px; padding: 20px; }
|
||||
.section-heading { display: flex; align-items: center; justify-content: space-between; gap: 20px; margin-bottom: 16px; }
|
||||
.section-heading h2 { font-size: 17px; }.section-heading p { margin-top: 5px; color: var(--muted); font-size: 12px; }
|
||||
.pool-layout { display: grid; grid-template-columns: 252px minmax(0, 1fr); min-height: 430px; border: 1px solid var(--line); border-radius: 11px; overflow: hidden; }
|
||||
.pool-sidebar { padding: 8px; border-right: 1px solid var(--line); background: #f7f9fa; }
|
||||
.pool-item { display: grid; grid-template-columns: 9px 1fr 16px; align-items: center; gap: 9px; width: 100%; min-height: 62px; margin-bottom: 5px; padding: 10px; border: 1px solid transparent; border-radius: 8px; text-align: left; background: transparent; cursor: pointer; }
|
||||
.pool-item:hover { background: #fff; }.pool-item.active { border-color: #bfe1dc; background: #fff; box-shadow: 0 5px 16px rgba(25,69,70,.05); }
|
||||
.section-heading { display: flex; align-items: center; justify-content: space-between; gap: 20px; margin-bottom: 16px; }
|
||||
.section-heading h2 { font-size: 17px; }.section-heading p { margin-top: 5px; color: var(--muted); font-size: 12px; }
|
||||
.section-heading-actions { display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
|
||||
.section-heading-actions .el-button + .el-button { margin-left: 0; }
|
||||
.selection-count { color: #117f75; font-size: 11px; font-weight: 600; }
|
||||
.pool-layout { display: grid; grid-template-columns: 252px minmax(0, 1fr); min-height: 430px; border: 1px solid var(--line); border-radius: 11px; overflow: hidden; }
|
||||
.pool-sidebar { padding: 8px; border-right: 1px solid var(--line); background: #f7f9fa; }
|
||||
.pool-select-row { display: grid; grid-template-columns: 22px minmax(0, 1fr); align-items: center; gap: 4px; margin-bottom: 5px; }
|
||||
.pool-select-row :deep(.el-checkbox) { justify-content: center; margin-right: 0; }
|
||||
.pool-item { display: grid; grid-template-columns: 9px minmax(0, 1fr) 16px; align-items: center; gap: 9px; width: 100%; min-height: 62px; padding: 10px; border: 1px solid transparent; border-radius: 8px; text-align: left; background: transparent; cursor: pointer; }
|
||||
.pool-item:hover { background: #fff; }.pool-select-row.active .pool-item { border-color: #bfe1dc; background: #fff; box-shadow: 0 5px 16px rgba(25,69,70,.05); }
|
||||
.pool-item strong, .pool-item small { display: block; }.pool-item strong { overflow: hidden; color: #253348; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }.pool-item small { margin-top: 4px; color: #8c98a7; font-size: 10px; }
|
||||
.pool-status { width: 8px; height: 8px; border-radius: 50%; }.pool-status.online { background: #18a277; }.pool-status.offline { background: #aab3bf; }.pool-item > .el-icon { color: #9ca7b4; }
|
||||
.pool-main { min-width: 0; }.pool-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 78px; padding: 12px 15px; border-bottom: 1px solid var(--line); }
|
||||
@@ -1113,6 +1305,14 @@ h1, h2, h3, p { margin: 0; }
|
||||
.member-tree-option__count { flex: 0 0 auto; color: #98a2b3; font-size: 11px; }
|
||||
.member-tree-option__detail { overflow: hidden; color: #8b97a6; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.form-grid, .rule-form-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 14px; }.form-tip { display: block; margin-top: 5px; color: #8b97a6; font-size: 10px; }.link-form .el-select, .link-form .el-input-number { width: 100%; }
|
||||
@media (max-width: 1100px) { .heading-actions { flex-wrap: wrap; justify-content: flex-end; }.metric-grid, .customer-metric-grid { grid-template-columns: repeat(2, minmax(0,1fr)); }.pool-layout { grid-template-columns: 210px minmax(0,1fr); }.pool-toolbar { align-items: flex-start; flex-direction: column; } }
|
||||
@media (max-width: 760px) { .promotion-page { padding: 10px; }.page-header, .section-heading { align-items: flex-start; flex-direction: column; }.update-time { display: none; }.metric-grid, .customer-metric-grid, .form-grid, .rule-form-grid { grid-template-columns: 1fr; }.tab-nav { overflow-x: auto; }.tab-nav button { min-width: 112px; }.tab-content { padding: 14px; }.pool-layout { grid-template-columns: 1fr; }.pool-sidebar { display: flex; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--line); }.pool-item { min-width: 190px; }.callback-list > div { grid-template-columns: 1fr 48px; padding: 8px 0; }.callback-list dt { grid-column: 1 / -1; }.install-pool-select { width: 100%; }.customer-heading-actions { width: 100%; justify-content: flex-end; }.customer-filter-bar :deep(.el-form-item) { width: 100%; margin-right: 0; }.customer-filter-bar :deep(.el-form-item__content), .customer-filter-bar .el-select { width: 100%; }.customer-filter-bar .filter-actions :deep(.el-form-item__content) { justify-content: flex-end; }.customer-pagination { align-items: flex-start; flex-direction: column; }.customer-pagination :deep(.el-pagination) { max-width: 100%; flex-wrap: wrap; justify-content: flex-start; } }
|
||||
.access-form { margin-top: 16px; }
|
||||
.access-pool-preview { padding: 12px 14px; border: 1px solid var(--line); border-radius: 8px; background: #f8fafb; }
|
||||
.access-pool-preview > strong { display: block; margin-bottom: 7px; font-size: 12px; }
|
||||
.access-pool-preview > div { display: grid; grid-template-columns: minmax(120px, .8fr) minmax(0, 1.6fr); gap: 12px; padding: 6px 0; border-top: 1px solid #edf0f2; font-size: 11px; }
|
||||
.access-pool-preview span { overflow: hidden; color: #344054; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.access-pool-preview small, .access-pool-preview p { color: #8491a2; font-size: 10px; }
|
||||
.access-pool-preview small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.access-pool-preview p { margin-top: 7px; }
|
||||
@media (max-width: 1100px) { .heading-actions { flex-wrap: wrap; justify-content: flex-end; }.metric-grid, .customer-metric-grid { grid-template-columns: repeat(2, minmax(0,1fr)); }.pool-layout { grid-template-columns: 210px minmax(0,1fr); }.pool-toolbar { align-items: flex-start; flex-direction: column; } }
|
||||
@media (max-width: 760px) { .promotion-page { padding: 10px; }.page-header, .section-heading { align-items: flex-start; flex-direction: column; }.section-heading-actions { width: 100%; justify-content: flex-start; }.update-time { display: none; }.metric-grid, .customer-metric-grid, .form-grid, .rule-form-grid { grid-template-columns: 1fr; }.tab-nav { overflow-x: auto; }.tab-nav button { min-width: 112px; }.tab-content { padding: 14px; }.pool-layout { grid-template-columns: 1fr; }.pool-sidebar { display: flex; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--line); }.pool-select-row { min-width: 220px; }.pool-item { min-width: 190px; }.callback-list > div { grid-template-columns: 1fr 48px; padding: 8px 0; }.callback-list dt { grid-column: 1 / -1; }.install-pool-select { width: 100%; }.customer-heading-actions { width: 100%; justify-content: flex-end; }.customer-filter-bar :deep(.el-form-item) { width: 100%; margin-right: 0; }.customer-filter-bar :deep(.el-form-item__content), .customer-filter-bar .el-select { width: 100%; }.customer-filter-bar .filter-actions :deep(.el-form-item__content) { justify-content: flex-end; }.customer-pagination { align-items: flex-start; flex-direction: column; }.customer-pagination :deep(.el-pagination) { max-width: 100%; flex-wrap: wrap; justify-content: flex-start; }.access-pool-preview > div { grid-template-columns: 1fr; gap: 3px; } }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user