fix(stats/self_input): 渠道字典、财务脱敏与同日同渠道全局唯一

自媒体来源改推广渠道字典;非白名单隐藏账户消耗/ROI;部门展示完整路径;业绩与消耗按日期+渠道全局去重。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-22 12:02:12 +08:00
co-authored by Cursor
parent bba989c0af
commit e4f181e4fe
13 changed files with 277 additions and 65 deletions
@@ -1,12 +1,42 @@
import { getSelfInputMediaSourceOptions } from '@/api/self_input_stats'
/**
* 自录转化统计:自媒体来源下拉(从已录入业绩/消耗去重,两页共用同一接口)
* 自录转化统计:自媒体来源选项(来自字典「推广渠道」channels)。
* 业绩页与账户消耗页共用同一接口,下拉打开时刷新,保证两侧字典变更同步。
*/
export interface MediaSourceOption {
name: string
value: string
}
export function useMediaSourceOptions() {
const mediaSourceOptions = ref<string[]>([])
const mediaSourceOptions = ref<MediaSourceOption[]>([])
const mediaSourceLoading = ref(false)
const normalize = (raw: any): MediaSourceOption[] => {
if (!Array.isArray(raw)) return []
const list: MediaSourceOption[] = []
const seen = new Set<string>()
for (const item of raw) {
if (typeof item === 'string') {
const name = item.trim()
if (name && !seen.has(name)) {
seen.add(name)
list.push({ name, value: '' })
}
continue
}
if (item && typeof item === 'object') {
const name = String(item.name ?? '').trim()
if (name && !seen.has(name)) {
seen.add(name)
list.push({ name, value: String(item.value ?? '') })
}
}
}
return list
}
const loadMediaSourceOptions = async (force = false) => {
if (!force && mediaSourceOptions.value.length > 0) {
return
@@ -14,7 +44,7 @@ export function useMediaSourceOptions() {
mediaSourceLoading.value = true
try {
const res = await getSelfInputMediaSourceOptions()
mediaSourceOptions.value = Array.isArray(res) ? res : []
mediaSourceOptions.value = normalize(res)
} catch {
mediaSourceOptions.value = []
} finally {