自媒体来源改推广渠道字典;非白名单隐藏账户消耗/ROI;部门展示完整路径;业绩与消耗按日期+渠道全局去重。 Co-authored-by: Cursor <cursoragent@cursor.com>
64 lines
2.0 KiB
TypeScript
64 lines
2.0 KiB
TypeScript
import { getSelfInputMediaSourceOptions } from '@/api/self_input_stats'
|
|
|
|
/**
|
|
* 自录转化统计:自媒体来源选项(来自字典「推广渠道」channels)。
|
|
* 业绩页与账户消耗页共用同一接口,下拉打开时刷新,保证两侧字典变更同步。
|
|
*/
|
|
export interface MediaSourceOption {
|
|
name: string
|
|
value: string
|
|
}
|
|
|
|
export function useMediaSourceOptions() {
|
|
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
|
|
}
|
|
mediaSourceLoading.value = true
|
|
try {
|
|
const res = await getSelfInputMediaSourceOptions()
|
|
mediaSourceOptions.value = normalize(res)
|
|
} catch {
|
|
mediaSourceOptions.value = []
|
|
} finally {
|
|
mediaSourceLoading.value = false
|
|
}
|
|
}
|
|
|
|
const refreshMediaSourceOptions = () => loadMediaSourceOptions(true)
|
|
|
|
return {
|
|
mediaSourceOptions,
|
|
mediaSourceLoading,
|
|
loadMediaSourceOptions,
|
|
refreshMediaSourceOptions,
|
|
}
|
|
}
|