Files
shanxia2.0/web-admin/src/api/crm/clue/index.ts
T
2026-08-22 09:08:05 +08:00

296 lines
8.2 KiB
TypeScript

/**
* 线索管理 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<string, any> {
const body: Record<string, any> = {
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<string, any> = { 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<string, any> = {}) {
const { ids, columns, ...rest } = data
const body: Record<string, any> = {
...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<string, any> = {}) {
const body: Record<string, any> = {}
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<string, any>) {
const res = await request.post({
url: `${BASE}/statistics/overview`,
data: mapStatisticsParams(params)
})
return { data: unwrapData(res) }
}
export async function getStatisticsBySource(params?: Record<string, any>) {
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<string, any>) {
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<string, any>) {
const res = await request.post({
url: `${BASE}/statistics/owner`,
data: mapStatisticsParams(params)
})
const data = unwrapData(res)
return { data: Array.isArray(data) ? data : data?.list || [] }
}