重构产品价和红线价功能

This commit is contained in:
wuweihua
2026-10-18 14:16:27 +08:00
parent db6f5e882a
commit 60d4614695
84 changed files with 6753 additions and 2843 deletions
+121 -28
View File
@@ -18,14 +18,6 @@ export function listProductOptions(query) {
})
}
/** 查询产品详情 */
export function getProduct(productId) {
return request({
url: '/price/product/' + productId,
method: 'get'
})
}
/** 查询产品国家明细(优先 productId,绑定到具体产品版本行) */
export function listProductCountries(productCode, effectiveDate, productId) {
const params = {}
@@ -47,21 +39,79 @@ export function updateProductCountry(data) {
})
}
/** 新增产品 */
export function addProduct(data) {
export function listProductVersions(query) {
return request({
url: '/price/product',
method: 'post',
data: data
url: '/price/product/versions',
method: 'get',
params: query
})
}
/** 修改产品 */
export function updateProduct(data) {
export function activateProductVersion(psvId, data) {
return request({
url: '/price/product',
url: '/price/product/version/activate/' + psvId,
method: 'put',
data: data
data: data || {}
})
}
export function deleteProductVersion(psvId) {
return request({
url: '/price/product/version/' + psvId,
method: 'delete'
})
}
export function getProductDraftVersion() {
return request({
url: '/price/product/version/draft',
method: 'get'
})
}
export function prepareProductVersion(copyFromLatest) {
return request({
url: '/price/product/version/prepare',
method: 'post',
params: { copyFromLatest: !!copyFromLatest }
})
}
/** Persist create-page preview into draft (no effectiveDate required). Polls until saved. */
export async function applyProductCatalogPreview(data, onProgress) {
const submitRes = await request({
url: '/price/product/version/applyPreviewAsync',
method: 'post',
data,
headers: { repeatSubmit: false },
timeout: 10 * 60 * 1000
})
const taskId = pickImportTaskId(submitRes)
if (!taskId) {
throw new Error('missing import taskId')
}
const { task } = await pollProductImportTask(taskId, onProgress)
return { data: task }
}
/** Excel attachments of a product version. */
export function listProductVersionExcelFiles(psvId) {
return request({
url: '/price/product/version/' + psvId + '/excelFiles',
method: 'get'
})
}
/** Save import Excel onto draft/pending version (prc_price_excel_file). */
export function attachProductVersionExcel(psvId, file) {
const formData = new FormData()
formData.append('file', file)
return request({
url: '/price/product/version/' + psvId + '/excel',
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false },
timeout: 10 * 60 * 1000
})
}
@@ -76,7 +126,8 @@ export function delProduct(productIds) {
export function getProductImportTask(taskId) {
return request({
url: '/price/product/import/task/' + taskId,
method: 'get'
method: 'get',
timeout: 10 * 60 * 1000
})
}
@@ -123,6 +174,54 @@ async function pollProductImportTask(taskId, onProgress) {
* @param {string} effectiveDate yyyy-MM-dd (required)
* @param {(task: object) => void} [onProgress]
*/
/** Async parse multi-country Excel only (no DB write); poll until done. */
function appendUploadFiles(formData, file) {
const list = Array.isArray(file) ? file : [file]
for (const item of list) {
const raw = item && (item.raw || item)
if (raw) formData.append('files', raw)
}
}
export async function previewProductImport(file, onProgress) {
const formData = new FormData()
appendUploadFiles(formData, file)
const submitRes = await request({
url: '/price/product/previewImport',
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false },
timeout: 10 * 60 * 1000
})
const taskId = pickImportTaskId(submitRes)
if (!taskId) {
throw new Error('missing import taskId')
}
const { task } = await pollProductImportTask(taskId, onProgress)
return { data: (task && task.result) || {} }
}
/** Async parse single-country Excel only (no DB write); poll until done. */
export async function previewProductCountryImport(file, countryCode, onProgress) {
const formData = new FormData()
appendUploadFiles(formData, file)
const params = new URLSearchParams()
params.set('countryCode', countryCode)
const submitRes = await request({
url: '/price/product/previewImportCountry?' + params.toString(),
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false },
timeout: 10 * 60 * 1000
})
const taskId = pickImportTaskId(submitRes)
if (!taskId) {
throw new Error('missing import taskId')
}
const { task } = await pollProductImportTask(taskId, onProgress)
return { data: (task && task.result) || {} }
}
export async function importProductExcelAsync(file, effectiveDate, onProgress) {
const formData = new FormData()
formData.append('file', file)
@@ -133,7 +232,8 @@ export async function importProductExcelAsync(file, effectiveDate, onProgress) {
url: '/price/product/importData?' + params.toString(),
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data' }
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false },
timeout: 10 * 60 * 1000
})
const taskId = pickImportTaskId(submitRes)
if (!taskId) {
@@ -159,7 +259,8 @@ export async function importProductCountryExcelAsync(file, countryCode, effectiv
url: '/price/product/importCountryData?' + params.toString(),
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data' }
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false },
timeout: 10 * 60 * 1000
})
const taskId = pickImportTaskId(submitRes)
if (!taskId) {
@@ -167,11 +268,3 @@ export async function importProductCountryExcelAsync(file, countryCode, effectiv
}
return pollProductImportTask(taskId, onProgress)
}
/** List imported Excel attachments for product_code */
export function listProductExcelFiles(productCode) {
return request({
url: '/price/product/' + encodeURIComponent(productCode) + '/excelFiles',
method: 'get'
})
}
+121 -28
View File
@@ -18,14 +18,6 @@ export function listRedlineOptions(query) {
})
}
/** 查询产品详情 */
export function getRedline(productId) {
return request({
url: '/price/redline/' + productId,
method: 'get'
})
}
/** 查询产品国家明细(优先 productId,绑定到具体产品版本行) */
export function listRedlineCountries(productCode, effectiveDate, productId) {
const params = {}
@@ -47,21 +39,79 @@ export function updateRedlineCountry(data) {
})
}
/** 新增红线价 */
export function addRedline(data) {
export function listRedlineVersions(query) {
return request({
url: '/price/redline',
method: 'post',
data: data
url: '/price/redline/versions',
method: 'get',
params: query
})
}
/** 修改产品 */
export function updateRedline(data) {
export function activateRedlineVersion(psvId, data) {
return request({
url: '/price/redline',
url: '/price/redline/version/activate/' + psvId,
method: 'put',
data: data
data: data || {}
})
}
export function deleteRedlineVersion(psvId) {
return request({
url: '/price/redline/version/' + psvId,
method: 'delete'
})
}
export function getRedlineDraftVersion() {
return request({
url: '/price/redline/version/draft',
method: 'get'
})
}
export function prepareRedlineVersion(copyFromLatest) {
return request({
url: '/price/redline/version/prepare',
method: 'post',
params: { copyFromLatest: !!copyFromLatest }
})
}
/** Persist create-page preview into draft (no effectiveDate required). Polls until saved. */
export async function applyRedlineCatalogPreview(data, onProgress) {
const submitRes = await request({
url: '/price/redline/version/applyPreviewAsync',
method: 'post',
data,
headers: { repeatSubmit: false },
timeout: 10 * 60 * 1000
})
const taskId = pickImportTaskId(submitRes)
if (!taskId) {
throw new Error('missing import taskId')
}
const { task } = await pollProductImportTask(taskId, onProgress)
return { data: task }
}
/** Excel attachments of a redline version. */
export function listRedlineVersionExcelFiles(psvId) {
return request({
url: '/price/redline/version/' + psvId + '/excelFiles',
method: 'get'
})
}
/** Save import Excel onto draft/pending version (prc_price_excel_file). */
export function attachRedlineVersionExcel(psvId, file) {
const formData = new FormData()
formData.append('file', file)
return request({
url: '/price/redline/version/' + psvId + '/excel',
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false },
timeout: 10 * 60 * 1000
})
}
@@ -76,7 +126,8 @@ export function delRedline(productIds) {
export function getRedlineImportTask(taskId) {
return request({
url: '/price/redline/import/task/' + taskId,
method: 'get'
method: 'get',
timeout: 10 * 60 * 1000
})
}
@@ -123,6 +174,54 @@ async function pollProductImportTask(taskId, onProgress) {
* @param {string} effectiveDate yyyy-MM-dd (required)
* @param {(task: object) => void} [onProgress]
*/
/** Async parse multi-country Excel only (no DB write); poll until done. */
function appendUploadFiles(formData, file) {
const list = Array.isArray(file) ? file : [file]
for (const item of list) {
const raw = item && (item.raw || item)
if (raw) formData.append('files', raw)
}
}
export async function previewRedlineImport(file, onProgress) {
const formData = new FormData()
appendUploadFiles(formData, file)
const submitRes = await request({
url: '/price/redline/previewImport',
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false },
timeout: 10 * 60 * 1000
})
const taskId = pickImportTaskId(submitRes)
if (!taskId) {
throw new Error('missing import taskId')
}
const { task } = await pollProductImportTask(taskId, onProgress)
return { data: (task && task.result) || {} }
}
/** Async parse single-country Excel only (no DB write); poll until done. */
export async function previewRedlineCountryImport(file, countryCode, onProgress) {
const formData = new FormData()
appendUploadFiles(formData, file)
const params = new URLSearchParams()
params.set('countryCode', countryCode)
const submitRes = await request({
url: '/price/redline/previewImportCountry?' + params.toString(),
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false },
timeout: 10 * 60 * 1000
})
const taskId = pickImportTaskId(submitRes)
if (!taskId) {
throw new Error('missing import taskId')
}
const { task } = await pollProductImportTask(taskId, onProgress)
return { data: (task && task.result) || {} }
}
export async function importRedlineExcelAsync(file, effectiveDate, onProgress) {
const formData = new FormData()
formData.append('file', file)
@@ -133,7 +232,8 @@ export async function importRedlineExcelAsync(file, effectiveDate, onProgress) {
url: '/price/redline/importData?' + params.toString(),
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data' }
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false },
timeout: 10 * 60 * 1000
})
const taskId = pickImportTaskId(submitRes)
if (!taskId) {
@@ -159,7 +259,8 @@ export async function importRedlineCountryExcelAsync(file, countryCode, effectiv
url: '/price/redline/importCountryData?' + params.toString(),
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data' }
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false },
timeout: 10 * 60 * 1000
})
const taskId = pickImportTaskId(submitRes)
if (!taskId) {
@@ -167,11 +268,3 @@ export async function importRedlineCountryExcelAsync(file, countryCode, effectiv
}
return pollProductImportTask(taskId, onProgress)
}
/** List imported Excel attachments for product_code */
export function listProductExcelFiles(productCode) {
return request({
url: '/price/redline/' + encodeURIComponent(productCode) + '/excelFiles',
method: 'get'
})
}
+13 -4
View File
@@ -26,7 +26,8 @@ export function savePriceSet(data) {
export function getPriceSetSaveTask(taskId) {
return request({
url: '/price/set/save/task/' + taskId,
method: 'get'
method: 'get',
timeout: 10 * 60 * 1000
})
}
@@ -222,9 +223,17 @@ export function addSetDetail(data) {
* @param {(task: object) => void} [onProgress]
* @returns {Promise<{ task: object }>}
*/
function appendUploadFiles(formData, file) {
const list = Array.isArray(file) ? file : [file]
for (const item of list) {
const raw = item && (item.raw || item)
if (raw) formData.append('files', raw)
}
}
export async function importSetDetailPricesAsync(file, query, onProgress) {
const formData = new FormData()
formData.append('file', file)
appendUploadFiles(formData, file)
const params = new URLSearchParams()
if (query && query.priceSetId != null) params.set('priceSetId', query.priceSetId)
if (query && query.psvId != null && query.psvId !== '') params.set('psvId', query.psvId)
@@ -236,7 +245,7 @@ export async function importSetDetailPricesAsync(file, query, onProgress) {
url: '/price/set/detail/importPrices?' + params.toString(),
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data' }
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false }
})
const taskId = pickSaveTaskId(submitRes)
if (!taskId) {
@@ -262,7 +271,7 @@ export function previewPullFromLibrary() {
*/
export function previewImportDetailPrices(file, opts = {}) {
const formData = new FormData()
formData.append('file', file)
appendUploadFiles(formData, file)
if (opts.updateOnly) formData.append('updateOnly', 'true')
if (opts.replaceByProductCountry) formData.append('replaceByProductCountry', 'true')
if (opts.countryCode) formData.append('countryCode', opts.countryCode)