crm.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /**
  2. * CRM 管理端接口(复用 /web/crm/*,需 admin JWT)
  3. */
  4. import { request, parseResponseJson } from '@/utils/request'
  5. function unwrap(res) {
  6. const body = parseResponseJson(res)
  7. if (!body || typeof body !== 'object') {
  8. throw new Error('接口响应异常')
  9. }
  10. if (body.code != null && body.code !== 200) {
  11. throw new Error(body.message || '请求失败')
  12. }
  13. return body.data != null ? body.data : body
  14. }
  15. async function post(url, data = {}) {
  16. const res = await request({ url, method: 'POST', data })
  17. return unwrap(res)
  18. }
  19. async function get(url, params = {}) {
  20. const res = await request({ url, method: 'GET', data: params, params })
  21. return unwrap(res)
  22. }
  23. function pageBody(query = {}) {
  24. const { pageNum, page, pageSize, ...rest } = query
  25. return {
  26. page: pageNum ?? page ?? 1,
  27. pageSize: pageSize ?? 20,
  28. ...rest
  29. }
  30. }
  31. function normalizeList(data) {
  32. if (Array.isArray(data)) {
  33. return { rows: data, total: data.length }
  34. }
  35. const d = data || {}
  36. return {
  37. rows: d.list || d.rows || [],
  38. total: d.total ?? (d.list || d.rows || []).length
  39. }
  40. }
  41. // ── 线索 ──
  42. export async function listClue(query = {}) {
  43. const { pageNum, pageSize, ...rest } = query
  44. return normalizeList(await post('/web/crm/clue/list', pageBody({ pageNum, pageSize, ...rest })))
  45. }
  46. export async function listMyClue(query = {}) {
  47. const { pageNum, pageSize, ...rest } = query
  48. return normalizeList(await post('/web/crm/clue/mine', pageBody({ pageNum, pageSize, ...rest })))
  49. }
  50. export async function getClue(id) {
  51. return post('/web/crm/clue/detail', { id: String(id) })
  52. }
  53. export function addClue(data) {
  54. return post('/web/crm/clue/add', data)
  55. }
  56. export function updateClue(data) {
  57. return post('/web/crm/clue/update', data)
  58. }
  59. export function convertClue(data) {
  60. return post('/web/crm/clue/convert', {
  61. id: String(data.clueId ?? data.id),
  62. customerName: data.customerName,
  63. customerType: data.customerType,
  64. contactName: data.contactName,
  65. contactMobile: data.contactMobile,
  66. remark: data.remark
  67. })
  68. }
  69. export function markClueInvalid(data) {
  70. return post('/web/crm/clue/invalid', {
  71. id: data.id != null ? String(data.id) : undefined,
  72. remark: data.remark
  73. })
  74. }
  75. export async function listClueFollow(clueId, pageNum = 1, pageSize = 20) {
  76. return normalizeList(
  77. await post('/web/crm/clue/follow/list', {
  78. clueId: String(clueId),
  79. page: pageNum,
  80. pageSize
  81. })
  82. )
  83. }
  84. export function addClueFollow(data) {
  85. return post('/web/crm/clue/follow/add', {
  86. ...data,
  87. clueId: String(data.clueId)
  88. })
  89. }
  90. // ── 商机 ──
  91. export async function listOpportunity(query = {}) {
  92. const { pageNum, pageSize, ...rest } = query
  93. return normalizeList(
  94. await post('/web/crm/opportunity/list', pageBody({ pageNum, pageSize, ...rest }))
  95. )
  96. }
  97. export async function getOpportunity(id) {
  98. return post('/web/crm/opportunity/detail', { id: String(id) })
  99. }
  100. export async function listOpportunityFollow(opportunityId, pageNum = 1, pageSize = 20) {
  101. return normalizeList(
  102. await post('/web/crm/opportunity/follow/list', {
  103. opportunityId: String(opportunityId),
  104. page: pageNum,
  105. pageSize
  106. })
  107. )
  108. }
  109. export function addOpportunityFollow(data) {
  110. return post('/web/crm/opportunity/follow/add', {
  111. ...data,
  112. opportunityId: String(data.opportunityId)
  113. })
  114. }
  115. // ── 客户 ──
  116. export async function listCustomer(query = {}) {
  117. const { pageNum, pageSize, ...rest } = query
  118. return normalizeList(
  119. await post('/web/crm/customer/list', pageBody({ pageNum, pageSize, ...rest }))
  120. )
  121. }
  122. export async function listMyCustomer(query = {}) {
  123. const { pageNum, pageSize, ...rest } = query
  124. return normalizeList(
  125. await post('/web/crm/customer/mine', pageBody({ pageNum, pageSize, ...rest }))
  126. )
  127. }
  128. export async function getCustomer(id) {
  129. return post('/web/crm/customer/detail', { id: String(id) })
  130. }
  131. export async function listCustomerFollow(customerId, pageNum = 1, pageSize = 20) {
  132. return normalizeList(
  133. await post('/web/crm/customer/follow/byCustomer', {
  134. customerId: String(customerId),
  135. page: pageNum,
  136. pageSize
  137. })
  138. )
  139. }
  140. export function addCustomerFollow(data) {
  141. return post('/web/crm/customer/follow/add', {
  142. ...data,
  143. customerId: String(data.customerId)
  144. })
  145. }
  146. // ── 公海 ──
  147. export async function listPoolCustomer(query = {}) {
  148. const { pageNum, pageSize, ...rest } = query
  149. return normalizeList(
  150. await post('/web/crm/customer/pool/list', pageBody({ pageNum, pageSize, ...rest }))
  151. )
  152. }
  153. export function claimCustomer(ids) {
  154. const idList = Array.isArray(ids) ? ids.map(String) : [String(ids)]
  155. return post('/web/crm/customer/claim', { ids: idList })
  156. }
  157. // ── 报价 ──
  158. export async function listQuote(query = {}) {
  159. const { pageNum, pageSize, ...rest } = query
  160. return normalizeList(await post('/web/crm/quote/list', pageBody({ pageNum, pageSize, ...rest })))
  161. }
  162. export async function getQuote(id) {
  163. return post('/web/crm/quote/detail', { id: String(id) })
  164. }
  165. // ── 合同(GET) ──
  166. export async function listContract(query = {}) {
  167. const params = {
  168. pageNum: query.pageNum ?? 1,
  169. pageSize: query.pageSize ?? 20
  170. }
  171. ;['keyword', 'contractNo', 'contractName', 'customerName', 'status', 'approvalStatus'].forEach(
  172. (k) => {
  173. if (query[k] != null && query[k] !== '') params[k] = query[k]
  174. }
  175. )
  176. return normalizeList(await get('/web/crm/contract/list', params))
  177. }
  178. export async function getContract(id) {
  179. return get(`/web/crm/contract/${String(id)}`)
  180. }
  181. // ── 产品分类 ──
  182. /** 产品分类树(不分页,嵌套 children) */
  183. export async function listProductCategoryTree(query = {}) {
  184. const body = {}
  185. if (query.categoryName) body.categoryName = String(query.categoryName).trim()
  186. if (query.status != null && query.status !== '') body.status = String(query.status)
  187. const data = await post('/web/crm/product-categories/tree', body)
  188. return Array.isArray(data) ? data : []
  189. }
  190. export function addProductCategory(data) {
  191. return post('/web/crm/product-categories/add', data)
  192. }
  193. export function updateProductCategory(data) {
  194. return post('/web/crm/product-categories/update', data)
  195. }
  196. export function deleteProductCategory(id) {
  197. return post('/web/crm/product-categories/delete', { id: String(id) })
  198. }