forecast-summary.js 21 KB

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