forecast-summary.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. // @ts-check
  2. import request from '@/router/axios'
  3. /**
  4. * @typedef {import('./types').ForecastSummaryQueryParams} ForecastSummaryQueryParams
  5. * @typedef {import('./types').ForecastSummaryForm} ForecastSummaryForm
  6. * @typedef {import('./types').ForecastSummaryRecord} ForecastSummaryRecord
  7. * @typedef {import('./types').ForecastSummaryListResponse} ForecastSummaryListResponse
  8. * @typedef {import('./types').ForecastSummaryOperationResponse} ForecastSummaryOperationResponse
  9. * @typedef {import('./types').ForecastSummaryBatchOperationResponse} ForecastSummaryBatchOperationResponse
  10. * @typedef {import('./types').ForecastSummaryItem} ForecastSummaryItem
  11. * @typedef {import('./types').ForecastSummaryPageResponse} ForecastSummaryPageResponse
  12. * @typedef {import('./types').ApprovalData} ApprovalData
  13. * @typedef {import('./types').SalesForecastSummaryBatchSaveRequest} SalesForecastSummaryBatchSaveRequest
  14. * @typedef {import('./types').SalesForecastSummaryBatchSaveResponse} SalesForecastSummaryBatchSaveResponse
  15. * @typedef {import('./types').SalesForecastSummaryPageQueryParams} SalesForecastSummaryPageQueryParams
  16. * @typedef {import('./types').SalesForecastSummaryPageResponse} SalesForecastSummaryPageResponse
  17. * @typedef {import('./types').SalesForecastMainListQueryParams} SalesForecastMainListQueryParams
  18. * @typedef {import('./types').SalesForecastMainListResponse} SalesForecastMainListResponse
  19. * @typedef {import('./types').SalesForecastTemplateResponse} SalesForecastTemplateResponse
  20. * @typedef {import('./types').SalesForecastMainDetailResponse} SalesForecastMainDetailResponse
  21. * @typedef {import('./types').SalesForecastMainUpdateRequest} SalesForecastMainUpdateRequest
  22. * @typedef {import('./types').SalesForecastMainUpdateResponse} SalesForecastMainUpdateResponse
  23. */
  24. /**
  25. * 获取预测汇总列表
  26. * @param {number} [current=1] - 当前页码
  27. * @param {number} [size=10] - 每页数量
  28. * @param {ForecastSummaryQueryParams} [params={}] - 查询参数
  29. * @returns {Promise<ForecastSummaryListResponse>} 预测汇总列表响应
  30. * @description 获取经销商销售预测汇总列表,支持多条件查询和分页
  31. * @example
  32. * // 获取第一页10条数据
  33. * const result = await getForecastSummaryList(1, 10)
  34. *
  35. * // 按年月查询
  36. * const result = await getForecastSummaryList(1, 10, { year: 2023, month: 8 })
  37. *
  38. * // 按客户查询
  39. * const result = await getForecastSummaryList(1, 10, { customerId: 1002 })
  40. *
  41. * // 按审批状态查询
  42. * const result = await getForecastSummaryList(1, 10, { approvalStatus: 2 })
  43. */
  44. export const getForecastSummaryList = async (current = 1, size = 10, params = {}) => {
  45. return request({
  46. url: '/api/blade-factory/api/factory/forecast-summary',
  47. method: 'get',
  48. params: {
  49. current,
  50. size,
  51. ...params
  52. }
  53. })
  54. }
  55. /**
  56. * 销售预测汇总分页查询
  57. * 对应后端:GET /api/blade-factory/api/factory/salesForecastSummary/page
  58. * @param {number} [current=1] - 当前页码
  59. * @param {number} [size=10] - 每页数量
  60. * @param {SalesForecastSummaryPageQueryParams} [params={}] - 查询参数(startMonth、endMonth、brandName、startDate、endDate)
  61. * @returns {Promise<SalesForecastSummaryPageResponse>} 分页响应
  62. * @example
  63. * // 基础分页
  64. * const res = await getSalesForecastSummaryPage(1, 10)
  65. * // 条件筛选
  66. * const res2 = await getSalesForecastSummaryPage(1, 20, { startMonth: '2025-08', endMonth: '2025-12', brandName: '朝阳', startDate: '2025-09-01', endDate: '2025-09-30' })
  67. */
  68. export const getSalesForecastSummaryPage = async (current = 1, size = 10, params = {}) => {
  69. return request({
  70. url: '/api/blade-factory/api/factory/salesForecastSummary/page',
  71. method: 'get',
  72. params: {
  73. current,
  74. size,
  75. ...params
  76. }
  77. })
  78. }
  79. /**
  80. * 销售预测主表分页列表
  81. * 对应后端:GET /api/blade-factory/api/factory/salesForecastSummary/main-list
  82. * @param {number} [current=1] - 当前页码
  83. * @param {number} [size=10] - 每页数量
  84. * @param {SalesForecastMainListQueryParams} [params={}] - 查询参数(year、month、customerName)
  85. * @returns {Promise<SalesForecastMainListResponse>} 分页响应
  86. * @example
  87. * // 基础分页
  88. * const res = await getSalesForecastMainList(1, 10)
  89. * // 条件筛选
  90. * const res2 = await getSalesForecastMainList(1, 10, { year: 2025, month: 9, customerName: '库比森' })
  91. */
  92. export const getSalesForecastMainList = async (current = 1, size = 10, params = {}) => {
  93. return request({
  94. url: '/api/blade-factory/api/factory/salesForecastSummary/main-list',
  95. method: 'get',
  96. params: { current, size, ...params }
  97. })
  98. }
  99. /**
  100. * 销售预测主表分页(新接口)
  101. * 对应后端:GET /api/blade-factory/api/factory/sales-forecast-main
  102. * @param {number} [current=1] - 当前页码
  103. * @param {number} [size=10] - 每页数量
  104. * @param {SalesForecastMainListQueryParams} [params={}] - 查询参数(可选)
  105. * @returns {Promise<SalesForecastMainListResponse>} 分页响应(records 为 SalesForecastMainRecord[])
  106. * @example
  107. * const res = await getSalesForecastMainPage(1, 10)
  108. */
  109. export const getSalesForecastMainPage = async (current = 1, size = 10, params = {}) => {
  110. return request({
  111. url: '/api/blade-factory/api/factory/sales-forecast-main',
  112. method: 'get',
  113. params: { current, size, ...params }
  114. })
  115. }
  116. /**
  117. * 销售预测主表分页列表(含明细)
  118. * 对应后端:GET /api/blade-factory/api/factory/salesForecastSummary/forecast/list
  119. * 说明:返回结构与 main-list 相同,顶层记录为 SalesForecastMainRecord,
  120. * 明细列表字段为 pcBladeSalesForecastSummaryList,因此直接复用现有类型
  121. * @param {number} [current=1] - 当前页码
  122. * @param {number} [size=10] - 每页数量
  123. * @param {SalesForecastMainListQueryParams} [params={}] - 查询参数(year、month、customerName)
  124. * @returns {Promise<SalesForecastMainListResponse>} 分页响应
  125. * @example
  126. * // 基础分页
  127. * const res = await getSalesForecastForecastList(1, 10)
  128. * // 条件筛选
  129. * const res2 = await getSalesForecastForecastList(1, 10, { year: 2025, month: 10, customerName: '库比森' })
  130. */
  131. export const getSalesForecastForecastList = async (current = 1, size = 10, params = {}) => {
  132. return request({
  133. url: '/api/blade-factory/api/factory/salesForecastSummary/forecast/list',
  134. method: 'get',
  135. params: { current, size, ...params }
  136. })
  137. }
  138. /**
  139. * 新增销售预测主表(main-add)
  140. * @param {import('./types').SalesForecastMainAddRequest} data - 主表新增请求体(包含年份、月份、审批状态以及子项列表)
  141. * @returns {Promise<import('./types').SalesForecastMainAddResponse>} 新增主表响应(data 通常为 null,msg 为提示信息)
  142. * @description 新增销售预测主表记录,提交 pcBladeSalesForecastSummaryList 子项明细;遵循后端通用响应结构 { code, success, data, msg }
  143. * @example
  144. * const payload = {
  145. * year: 2025,
  146. * month: 10,
  147. * approvalStatus: 0,
  148. * pcBladeSalesForecastSummaryList: [
  149. * {
  150. * brandId: 101,
  151. * brandCode: 'BD-001',
  152. * brandName: '品牌A',
  153. * itemId: 2001,
  154. * itemCode: 'IT-2001',
  155. * itemName: '刀片型号A1',
  156. * specs: '100x200mm',
  157. * pattern: '标准花纹',
  158. * forecastQuantity: 500.00,
  159. * approvalStatus: 0
  160. * }
  161. * ]
  162. * }
  163. * const res = await addSalesForecastMain(payload)
  164. */
  165. export const addSalesForecastMain = async (data) => {
  166. return request({
  167. url: '/api/blade-factory/api/factory/salesForecastSummary/main-add',
  168. method: 'post',
  169. data
  170. })
  171. }
  172. /**
  173. * 更新销售预测主表(main-update)
  174. * 对应后端:PUT /api/blade-factory/api/factory/salesForecastSummary/main-update
  175. * @param {SalesForecastMainUpdateRequest} data - 更新请求体(包含主表 id、年月、审批状态及明细列表)
  176. * @returns {Promise<SalesForecastMainUpdateResponse>} 更新响应(data 通常为 null,msg 为提示文本)
  177. * @example
  178. * const payload = {
  179. * id: 1965692513192693762,
  180. * year: 2025,
  181. * month: 9,
  182. * approvalStatus: 1,
  183. * pcBladeSalesForecastSummaryList: [
  184. * { id: 1965692513603735554, brandId: 101, brandCode: 'BD-001', brandName: '品牌A1111111111', itemId: 2001, itemCode: 'IT-2001', itemName: '刀片型号A1', specs: '100x200mm', pattern: '标准花纹', forecastQuantity: 500.00, approvalStatus: 0 },
  185. * { id: 1965692513633095681, brandId: 101, brandCode: 'BD-001', brandName: '品牌A11111111111', itemId: 2002, itemCode: 'IT-2002', itemName: '刀片型号A2', specs: '150x250mm', pattern: '加强花纹', forecastQuantity: 300.00, approvalStatus: 0 },
  186. * { id: 1965692513641484290, brandId: 102, brandCode: 'BD-002', brandName: '品牌B11111111111', itemId: 3001, itemCode: 'IT-3001', itemName: '刀片型号B1', specs: '200x300mm', pattern: '特殊花纹', forecastQuantity: 200.00, approvalStatus: 0 }
  187. * ]
  188. * }
  189. * const res = await updateSalesForecastMain(payload)
  190. * // 可能返回:{ code: 400, success: false, data: null, msg: '修改失败,请稍后重试' }
  191. */
  192. export const updateSalesForecastMain = async (data) => {
  193. return request({
  194. url: '/api/blade-factory/api/factory/salesForecastSummary/main-update',
  195. method: 'put',
  196. data
  197. })
  198. }
  199. /**
  200. * 获取预测汇总详情
  201. * @param {string|number} forecastSummaryId - 预测汇总ID
  202. * @returns {Promise<ForecastSummaryOperationResponse>} 预测汇总详情响应
  203. * @description 根据ID获取预测汇总的详细信息
  204. * @example
  205. * const result = await getForecastSummaryDetail('1954819531796865026')
  206. *
  207. * // 处理响应数据
  208. * if (result.success && result.code === 200) {
  209. * const summaryData = result.data
  210. * console.log('预测汇总详情:', summaryData)
  211. * }
  212. */
  213. export const getForecastSummaryDetail = async (forecastSummaryId) => {
  214. return request({
  215. url: `/api/blade-factory/api/factory/forecast-summary/${forecastSummaryId}`,
  216. method: 'get'
  217. })
  218. }
  219. /**
  220. * 添加预测汇总
  221. * @param {ForecastSummaryForm} data - 预测汇总表单数据
  222. * @returns {Promise<ForecastSummaryOperationResponse>} 添加预测汇总响应
  223. * @description 创建新的销售预测汇总记录
  224. * @example
  225. * const formData = {
  226. * year: 2023,
  227. * month: 8,
  228. * customerId: 1001,
  229. * customerCode: 'DLR001',
  230. * customerName: '上海轮胎经销商',
  231. * brandId: 2001,
  232. * brandCode: 'BRD001',
  233. * brandName: '米其林',
  234. * itemId: 3001,
  235. * itemCode: 'ITEM001',
  236. * itemName: '轮胎A型号',
  237. * specs: '225/65R17',
  238. * pattern: 'Primacy SUV',
  239. * forecastQuantity: 150,
  240. * approvalStatus: 0
  241. * }
  242. * const result = await addForecastSummary(formData)
  243. */
  244. export const addForecastSummary = async (data) => {
  245. return request({
  246. url: '/api/blade-factory/api/factory/forecast-summary',
  247. method: 'post',
  248. data
  249. })
  250. }
  251. /**
  252. * 更新预测汇总
  253. * @param {ForecastSummaryForm} data - 预测汇总表单数据(必须包含id)
  254. * @returns {Promise<ForecastSummaryOperationResponse>} 更新预测汇总响应
  255. * @description 更新现有的销售预测汇总记录
  256. * @example
  257. * const formData = {
  258. * id: '1954819531796865026',
  259. * year: 2023,
  260. * month: 8,
  261. * customerId: 1001,
  262. * customerCode: 'DLR001',
  263. * customerName: '上海轮胎经销商',
  264. * brandId: 2001,
  265. * brandCode: 'BRD001',
  266. * brandName: '米其林',
  267. * itemId: 3001,
  268. * itemCode: 'ITEM001',
  269. * itemName: '轮胎A型号',
  270. * specs: '225/65R17',
  271. * pattern: 'Primacy SUV',
  272. * forecastQuantity: 180,
  273. * approvalStatus: 0
  274. * }
  275. * const result = await updateForecastSummary(formData)
  276. */
  277. export const updateForecastSummary = async (data) => {
  278. return request({
  279. url: '/api/blade-factory/api/factory/forecast-summary',
  280. method: 'put',
  281. data
  282. })
  283. }
  284. /**
  285. * 删除预测汇总
  286. * @param {string|number} id - 预测汇总ID
  287. * @returns {Promise<ForecastSummaryOperationResponse>} 删除预测汇总响应
  288. * @description 根据ID删除销售预测汇总记录
  289. * @example
  290. * const result = await removeForecastSummary('1954819531796865026')
  291. */
  292. export const removeForecastSummary = async (id) => {
  293. return request({
  294. url: `/api/blade-factory/api/factory/forecast-summary/${id}`,
  295. method: 'delete'
  296. })
  297. }
  298. /**
  299. * 批量删除预测汇总
  300. * @param {Array<string|number>} ids - 预测汇总ID数组
  301. * @returns {Promise<ForecastSummaryBatchOperationResponse>} 批量删除预测汇总响应
  302. * @description 批量删除多个销售预测汇总记录
  303. * @example
  304. * const result = await batchRemoveForecastSummary(['1954819531796865026', '1954819531796865027'])
  305. */
  306. export const batchRemoveForecastSummary = async (ids) => {
  307. return request({
  308. url: '/api/blade-factory/api/factory/forecast-summary/batch',
  309. method: 'delete',
  310. data: ids
  311. })
  312. }
  313. /**
  314. * 审批预测汇总
  315. * @param {ApprovalData} data - 审批数据
  316. * @returns {Promise<ForecastSummaryOperationResponse>} 审批预测汇总响应
  317. * @description 审批销售预测汇总记录
  318. * @example
  319. * // 通过审批
  320. * await approveForecastSummary({ id: '123', approvalStatus: 1, approvalComment: '同意' })
  321. * // 拒绝审批
  322. * await approveForecastSummary({ id: '123', approvalStatus: 2, approvalComment: '不符合要求' })
  323. */
  324. export const approveForecastSummary = async (data) => {
  325. return request({
  326. url: '/api/blade-factory/api/factory/forecast-summary/approve',
  327. method: 'post',
  328. data
  329. })
  330. }
  331. /**
  332. * 销售预测汇总批量保存
  333. * 对应后端:POST /api/blade-factory/api/factory/salesForecastSummary/batchSave
  334. * @param {SalesForecastSummaryBatchSaveRequest} data - 批量保存请求体
  335. * @returns {Promise<SalesForecastSummaryBatchSaveResponse>} 响应,data 通常为 null,msg 提示文本
  336. */
  337. export const batchSaveSalesForecastSummary = async (data) => {
  338. return request({
  339. url: '/api/blade-factory/api/factory/salesForecastSummary/batchSave',
  340. method: 'post',
  341. data
  342. })
  343. }
  344. /**
  345. * 销售预测模板下载
  346. * 对应后端:GET /api/blade-factory/api/factory/salesForecastSummary/exportTemplate
  347. * @param {number} [current=1] - 当前页码
  348. * @param {number} [size=10] - 每页数量
  349. * @param {SalesForecastSummaryPageQueryParams} [params={}] - 查询参数(用于与分页检索保持一致,便于后端构造模板)
  350. * @returns {Promise<SalesForecastTemplateResponse>} 模板下载响应(Blob 数据 + 响应头)
  351. */
  352. export const exportSalesForecastTemplate = async (current = 1, size = 10, params = {}) => {
  353. return request({
  354. url: '/api/blade-factory/api/factory/salesForecastSummary/exportTemplate',
  355. method: 'get',
  356. responseType: 'blob',
  357. params: { current, size, ...params }
  358. })
  359. }
  360. /**
  361. * 销售预测数据导出(按年月)
  362. * 对应后端:GET /api/blade-factory/api/factory/salesForecastSummary/export/{year}/{month}
  363. * @param {number|string} year - 年份,如 2025
  364. * @param {number|string} month - 月份,1-12 或 '01'-'12'
  365. * @returns {Promise<SalesForecastTemplateResponse>} 导出响应(Blob 数据 + 响应头)
  366. * @example
  367. * const res = await exportSalesForecastByMonth(2025, 10)
  368. * // 文件名可从 res.headers['content-disposition'] 中解析
  369. */
  370. export const exportSalesForecastByMonth = async (year, month) => {
  371. return request({
  372. url: `/api/blade-factory/api/factory/salesForecastSummary/export/${year}/${month}`,
  373. method: 'get',
  374. responseType: 'blob'
  375. })
  376. }
  377. /**
  378. * 销售预测数据导出(用户维度,按年月)
  379. * 对应后端:GET /api/blade-factory/api/factory/salesForecastSummary/user/export/{year}/{month}
  380. * @param {number|string} year - 年份,如 2025
  381. * @param {number|string} month - 月份,1-12 或 '01'-'12'
  382. * @returns {Promise<SalesForecastTemplateResponse>} 导出响应(Blob 数据 + 响应头)
  383. * @example
  384. * const res = await exportUserSalesForecastByMonth(2025, 10)
  385. * // 文件名可从 res.headers['content-disposition'] 中解析
  386. */
  387. export const exportUserSalesForecastByMonth = async (year, month) => {
  388. return request({
  389. url: `/api/blade-factory/api/factory/salesForecastSummary/user/export/${year}/${month}`,
  390. method: 'get',
  391. responseType: 'blob'
  392. })
  393. }
  394. /**
  395. * 销售预测数据导出(按主表ID)
  396. * 对应后端:GET /api/blade-factory/api/factory/salesForecastSummary/exportByMainId/{mainId}
  397. * @param {number|string} mainId - 主表ID
  398. * @returns {Promise<SalesForecastTemplateResponse>} 导出响应(Blob 数据 + 响应头)
  399. * @example
  400. * const res = await exportSalesForecastByMainId('1966517943156121601')
  401. * // 文件名可从 res.headers['content-disposition'] 中解析
  402. */
  403. export const exportSalesForecastByMainId = async (mainId) => {
  404. return request({
  405. url: `/api/blade-factory/api/factory/salesForecastSummary/exportByMainId/${mainId}`,
  406. method: 'get',
  407. responseType: 'blob'
  408. })
  409. }
  410. /**
  411. * 获取销售预测主表详情
  412. * 对应后端:GET /api/blade-factory/api/factory/salesForecastSummary/forecast/detail
  413. * @param {string|number} id - 主表ID
  414. * @returns {Promise<SalesForecastMainDetailResponse>} 详情响应(data: SalesForecastMainRecord)
  415. * @description 根据 ID 查询销售预测主表详情,包含 pcBladeSalesForecastSummaryList 子项
  416. * @example
  417. * const { data } = await getSalesForecastForecastDetail('1966138542639833089')
  418. * if (data.success && data.code === 200) {
  419. * const detail = data.data
  420. * console.log('主表详情', detail)
  421. * }
  422. */
  423. export const getSalesForecastForecastDetail = async (id) => {
  424. return request({
  425. url: '/api/blade-factory/api/factory/salesForecastSummary/forecast/detail',
  426. method: 'get',
  427. params: { id }
  428. })
  429. }
  430. /**
  431. * 销售预测汇总审批
  432. * 对应后端:POST /api/blade-factory/api/factory/salesForecastSummary/approve
  433. * @param {{ id: string|number, approvalStatus: number, remark?: string, approvalComment?: string }} data - 审批参数
  434. * @returns {Promise<SalesForecastSummaryBatchSaveResponse>} 操作响应(data: null,msg 提示信息)
  435. * @description 入参支持 remark 或 approvalComment,内部统一映射为 remark
  436. * @example
  437. * await approveSalesForecastSummary({ id: 1965692513192693762, approvalStatus: 1, remark: '' })
  438. */
  439. export const approveSalesForecastSummary = async (data) => {
  440. const { id, approvalStatus, remark, approvalComment } = data || {}
  441. return request({
  442. url: '/api/blade-factory/api/factory/salesForecastSummary/approve',
  443. method: 'post',
  444. data: { id, approvalStatus, remark: remark ?? approvalComment ?? '' }
  445. })
  446. }
  447. /**
  448. * 销售预测明细审批
  449. * 对应后端:POST /api/blade-factory/api/factory/salesForecastSummary/particulars
  450. * @param {{ id: string|number, forecastMainId: string|number, approvalStatus: number, remark?: string, approvalComment?: string }} data - 审批参数
  451. * @returns {Promise<SalesForecastSummaryBatchSaveResponse>} 操作响应(data: null,msg 提示信息)
  452. * @description 入参支持 remark 或 approvalComment,内部统一映射为 remark
  453. * @example
  454. * await approveSalesForecastSummaryParticulars({ id: 1966138542895685633, forecastMainId: 1966138542639833089, approvalStatus: 1, remark: '' })
  455. */
  456. export const approveSalesForecastSummaryParticulars = async (data) => {
  457. const { id, forecastMainId, approvalStatus, remark, approvalComment } = data || {}
  458. return request({
  459. url: '/api/blade-factory/api/factory/salesForecastSummary/particulars',
  460. method: 'post',
  461. data: { id, forecastMainId, approvalStatus, remark: remark ?? approvalComment ?? '' }
  462. })
  463. }