/** * 线索管理 API(门户 POST 风格,兼容原 CRM 函数名) */ import request from '@/utils/http' import type { ClueQuery, ClueForm, ClueAssignParams, ClueStatusParams, ClueLevelParams, ClueConvertParams, ClueFollowQuery, ClueFollowForm } from './types' const BASE = '/web/crm/clue' function unwrapData(res: any) { return res?.data ?? res ?? {} } function mapListQuery(query: ClueQuery = {}): Record { const body: Record = { page: query.pageNum ?? 1, pageSize: query.pageSize ?? 20 } if (query.clueName) body.clueName = query.clueName if (query.company) body.company = query.company if (query.mobile) body.mobile = query.mobile if (query.source) body.source = query.source if (query.level) body.level = query.level if (query.status) body.status = query.status if (query.industry) body.industry = query.industry if (query.parkArea) body.parkArea = query.parkArea if (query.ownerUserId != null) body.ownerUserId = String(query.ownerUserId) if (query.beginTime) body.beginTime = query.beginTime if (query.endTime) body.endTime = query.endTime if (query.keyword) body.keyword = query.keyword if (query.isConverted === 1) body.viewType = 'converted' return body } async function postList(url: string, query?: ClueQuery) { const res = await request.post({ url, data: mapListQuery(query) }) const data = unwrapData(res) return { rows: data.list || data.rows || [], total: data.total ?? 0 } } // ── 线索 CRUD ── export function listClue(query?: ClueQuery) { return postList(`${BASE}/list`, query) } export function listMyClue(query?: ClueQuery) { return postList(`${BASE}/mine`, query) } export function listToFollowClue(query?: ClueQuery) { return postList(`${BASE}/toFollow`, query) } export async function listTodayNewClue(query?: ClueQuery) { return postList(`${BASE}/todayNew`, query) } export async function getClue(id: number | string) { const res = await request.post({ url: `${BASE}/detail`, data: { id: String(id) } }) return { data: unwrapData(res) } } export function addClue(data: ClueForm) { return request.post({ url: `${BASE}/add`, data }) } export function updateClue(data: ClueForm) { return request.post({ url: `${BASE}/update`, data }) } export function delClue(ids: number | number[] | string | string[]) { const idList = Array.isArray(ids) ? ids.map(String) : [String(ids)] return request.post({ url: `${BASE}/delete`, data: { ids: idList } }) } export function assignClue(data: ClueAssignParams) { return request.post({ url: `${BASE}/assign`, data: { ids: (data.ids || []).map(String), ownerUserId: data.ownerUserId != null ? String(data.ownerUserId) : undefined, remark: data.remark } }) } export function updateClueStatus(data: ClueStatusParams) { const id = data.id ?? (Array.isArray(data.ids) ? data.ids[0] : undefined) return request.post({ url: `${BASE}/updateStatus`, data: { id: String(id), status: data.status } }) } export function markInvalid(data: { id?: string | number ids?: (string | number)[] remark?: string }) { const body: Record = { remark: data.remark } if (data.ids?.length) { body.ids = data.ids.map(String) } else if (data.id != null) { body.id = String(data.id) } return request.post({ url: `${BASE}/invalid`, data: body }) } export function updateClueLevel(data: ClueLevelParams) { return request.post({ url: `${BASE}/updateLevel`, data: { ids: (data.ids || []).map(String), level: data.level } }) } export function convertClue(data: ClueConvertParams) { const clueId = data.clueId ?? (data as any).id return request.post({ url: `${BASE}/convert`, data: { id: String(clueId), customerName: data.customerName, customerType: data.customerType, contactName: data.contactName, contactMobile: data.contactMobile, remark: data.remark } }) } export async function checkConvert(id: number | string) { const res = await request.post({ url: `${BASE}/checkConvert`, data: { id: String(id) } }) return { data: unwrapData(res) } } export function exportClue(data: Record = {}) { const { ids, columns, ...rest } = data const body: Record = { ...mapListQuery(rest as ClueQuery), ...(ids ? { ids } : {}), ...(columns ? { columns } : {}) } return request.post({ url: `${BASE}/export`, data: body, responseType: 'blob', showErrorMessage: false }) } export function importTemplate() { return request.post({ url: `${BASE}/importTemplate`, responseType: 'blob' }) } export function importClue(file: File, updateSupport = false) { const formData = new FormData() formData.append('file', file) formData.append('updateSupport', String(updateSupport)) return request.post({ url: `${BASE}/import`, data: formData, headers: { 'Content-Type': 'multipart/form-data' } }) } export async function checkDuplicateClue(data: { mobile?: string company?: string excludeId?: string | number }) { const res = await request.post({ url: `${BASE}/checkDuplicate`, data }) return unwrapData(res) } export async function getParkAreaList() { const res = await request.post({ url: `${BASE}/parkAreaList`, data: {} }) return { data: unwrapData(res) } } // ── 跟进记录 ── export async function listClueFollow(query: ClueFollowQuery) { const res = await request.post({ url: `${BASE}/follow/list`, data: { clueId: String(query.clueId), page: query.pageNum ?? 1, pageSize: query.pageSize ?? 20 } }) const data = unwrapData(res) return { rows: data.list || [], total: data.total ?? 0 } } export async function getClueFollow(id: number | string) { const res = await request.post({ url: `${BASE}/follow/detail`, data: { id: String(id) } }) return { data: unwrapData(res) } } export function addClueFollow(data: ClueFollowForm) { return request.post({ url: `${BASE}/follow/add`, data: { ...data, clueId: String(data.clueId) } }) } export function updateClueFollow(data: ClueFollowForm) { return request.post({ url: `${BASE}/follow/update`, data: { ...data, id: data.id != null ? String(data.id) : undefined, clueId: String(data.clueId) } }) } export function delClueFollow(ids: number | number[] | string | string[]) { const idList = Array.isArray(ids) ? ids.map(String) : [String(ids)] return request.post({ url: `${BASE}/follow/delete`, data: { ids: idList } }) } // ── 统计 ── function mapStatisticsParams(params: Record = {}) { const body: Record = {} if (params.beginTime) body.beginTime = params.beginTime if (params.endTime) body.endTime = params.endTime if (params.ownerUserId != null) body.ownerUserId = String(params.ownerUserId) if (params.type) body.timeUnit = params.type if (params.timeUnit) body.timeUnit = params.timeUnit return body } export async function getStatisticsOverview(params?: Record) { const res = await request.post({ url: `${BASE}/statistics/overview`, data: mapStatisticsParams(params) }) return { data: unwrapData(res) } } export async function getStatisticsBySource(params?: Record) { const res = await request.post({ url: `${BASE}/statistics/source`, data: mapStatisticsParams(params) }) const data = unwrapData(res) return { data: Array.isArray(data) ? data : data?.list || [] } } export async function getStatisticsByLevel() { const res = await request.post({ url: `${BASE}/statistics/level`, data: {} }) const data = unwrapData(res) return { data: Array.isArray(data) ? data : data?.list || [] } } export async function getStatisticsTrend(params?: Record) { const res = await request.post({ url: `${BASE}/statistics/trend`, data: mapStatisticsParams(params) }) const data = unwrapData(res) return { data: Array.isArray(data) ? data : data?.list || [] } } export async function getStatisticsByOwner(params?: Record) { const res = await request.post({ url: `${BASE}/statistics/owner`, data: mapStatisticsParams(params) }) const data = unwrapData(res) return { data: Array.isArray(data) ? data : data?.list || [] } }