增加专属报价功能
This commit is contained in:
@@ -0,0 +1,484 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/** Build price-set style API against a controller base path (e.g. /price/set, /price/exclusive). */
|
||||
export function createPriceSetApi(basePath) {
|
||||
const base = String(basePath || '/price/set').replace(/\/$/, '')
|
||||
function listPriceSet(query) {
|
||||
return request({
|
||||
url: base + '/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
function getPriceSet(priceSetId) {
|
||||
return request({
|
||||
url: base + '/' + priceSetId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
function savePriceSet(data) {
|
||||
return request({
|
||||
url: base + '',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
function getPriceSetSaveTask(taskId) {
|
||||
return request({
|
||||
url: base + '/save/task/' + taskId,
|
||||
method: 'get',
|
||||
timeout: 10 * 60 * 1000
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit save async and poll Redis progress until SUCCESS/FAIL.
|
||||
* @returns {Promise<{ priceSetId: number|string, task: object }>}
|
||||
*/
|
||||
async function savePriceSetAsync(data, onProgress) {
|
||||
const submitRes = await savePriceSet(data)
|
||||
const taskId = pickSaveTaskId(submitRes)
|
||||
if (!taskId) {
|
||||
throw new Error('missing save taskId')
|
||||
}
|
||||
const started = Date.now()
|
||||
const maxMs = 30 * 60 * 1000
|
||||
while (Date.now() - started < maxMs) {
|
||||
const res = await getPriceSetSaveTask(taskId)
|
||||
const task = res.data || {}
|
||||
if (typeof onProgress === 'function') {
|
||||
onProgress(task)
|
||||
}
|
||||
if (task.status === 'SUCCESS') {
|
||||
return { priceSetId: task.priceSetId, task }
|
||||
}
|
||||
if (task.status === 'FAIL') {
|
||||
const err = new Error(task.error || task.message || 'save failed')
|
||||
err.task = task
|
||||
throw err
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 400))
|
||||
}
|
||||
throw new Error('save timeout')
|
||||
}
|
||||
|
||||
/** Accept data.taskId / data string / legacy msg UUID (Bms String overload). */
|
||||
function pickSaveTaskId(res) {
|
||||
if (!res) return null
|
||||
const d = res.data
|
||||
if (d && typeof d === 'object' && d.taskId) return String(d.taskId)
|
||||
if (typeof d === 'string' && d.trim()) return d.trim()
|
||||
if (typeof res.msg === 'string') {
|
||||
const m = res.msg.trim()
|
||||
if (/^[a-f0-9]{32}$/i.test(m)) return m
|
||||
if (/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(m)) {
|
||||
return m.replace(/-/g, '')
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function updatePriceSet(data) {
|
||||
return request({
|
||||
url: base + '',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
/** Update package name and note only. */
|
||||
function updatePriceSetBasic(data) {
|
||||
return request({
|
||||
url: base + '/basic',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
function delPriceSet(priceSetIds) {
|
||||
return request({
|
||||
url: base + '/' + priceSetIds,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
function submitPriceSet(priceSetId) {
|
||||
return request({
|
||||
url: base + '/submit/' + priceSetId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
function approvePriceSet(priceSetId) {
|
||||
return request({
|
||||
url: base + '/approve/' + priceSetId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
function rejectPriceSet(priceSetId) {
|
||||
return request({
|
||||
url: base + '/reject/' + priceSetId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
function activatePriceSetVersion(psvId, data) {
|
||||
return request({
|
||||
url: base + '/version/activate/' + psvId,
|
||||
method: 'put',
|
||||
data: data || {}
|
||||
})
|
||||
}
|
||||
|
||||
function copyPriceSetVersion(psvId) {
|
||||
return request({
|
||||
url: base + '/version/copy/' + psvId,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
/** Create empty draft version under package */
|
||||
function createPriceSetVersion(priceSetId) {
|
||||
return request({
|
||||
url: base + '/version/create/' + priceSetId,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
/** Import excel attachments for a price-set version (via prc_price_set_product.psv_id). */
|
||||
function listPriceSetVersionExcelFiles(psvId) {
|
||||
return request({
|
||||
url: base + '/version/' + psvId + '/excelFiles',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
function deletePriceSetVersion(psvId) {
|
||||
return request({
|
||||
url: base + '/version/' + psvId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
function disablePriceSet(priceSetId) {
|
||||
return request({
|
||||
url: base + '/disable/' + priceSetId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
function enablePriceSet(priceSetId) {
|
||||
return request({
|
||||
url: base + '/enable/' + priceSetId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
function copyPriceSet(priceSetId) {
|
||||
return request({
|
||||
url: base + '/copy/' + priceSetId,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
function validatePriceSet(data) {
|
||||
return request({
|
||||
url: base + '/validate',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
function listSetDetail(query) {
|
||||
return request({
|
||||
url: base + '/detail/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
/** All detail rows for one product under a version (no pagination). */
|
||||
function listSetDetailByProduct(psvId, productCode) {
|
||||
return request({
|
||||
url: base + '/detail/byProduct',
|
||||
method: 'get',
|
||||
params: { psvId, productCode }
|
||||
})
|
||||
}
|
||||
|
||||
/** All detail rows for a version (no pagination); one call instead of N byProduct. */
|
||||
function listSetDetailByVersion(psvId) {
|
||||
return request({
|
||||
url: base + '/detail/byVersion',
|
||||
method: 'get',
|
||||
params: { psvId }
|
||||
})
|
||||
}
|
||||
|
||||
/** 版本明细搜索下拉选项:按版本去重后的 产品/国家/分区 */
|
||||
function listSetDetailOptions(psvId) {
|
||||
return request({
|
||||
url: base + '/detail/options',
|
||||
method: 'get',
|
||||
params: { psvId }
|
||||
})
|
||||
}
|
||||
|
||||
function addSetDetail(data) {
|
||||
return request({
|
||||
url: base + '/detail',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Async import quote Excel into FIXED package detail prices; poll until done.
|
||||
* @param {File|Blob} file
|
||||
* @param {{ priceSetId: string|number, psvId?: string|number, updateOnly?: boolean, replaceByProductCountry?: boolean, countryCode?: string }} query
|
||||
* @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)
|
||||
}
|
||||
}
|
||||
|
||||
async function importSetDetailPricesAsync(file, query, onProgress) {
|
||||
const formData = new FormData()
|
||||
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)
|
||||
if (query && query.updateOnly) params.set('updateOnly', 'true')
|
||||
// Package Excel build-price only (product+country replace scope)
|
||||
if (query && query.replaceByProductCountry) params.set('replaceByProductCountry', 'true')
|
||||
if (query && query.countryCode) params.set('countryCode', query.countryCode)
|
||||
const submitRes = await request({
|
||||
url: base + '/detail/importPrices?' + params.toString(),
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false }
|
||||
})
|
||||
const taskId = pickSaveTaskId(submitRes)
|
||||
if (!taskId) {
|
||||
throw new Error('missing import taskId')
|
||||
}
|
||||
return pollPriceSetSaveTask(taskId, onProgress)
|
||||
}
|
||||
|
||||
/**
|
||||
* Preview pull product library (no DB write). Returns { products, details, message }.
|
||||
*/
|
||||
function previewPullFromLibrary() {
|
||||
return request({
|
||||
url: base + '/detail/previewPullFromLibrary',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Preview Excel import (no DB write).
|
||||
* @param {File|Blob} file
|
||||
* @param {{ updateOnly?: boolean, replaceByProductCountry?: boolean, countryCode?: string, details?: Array }} [opts]
|
||||
*/
|
||||
function previewImportDetailPrices(file, opts = {}) {
|
||||
const formData = new FormData()
|
||||
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)
|
||||
// updateOnly / Excel build-price merge need current draft details
|
||||
if ((opts.updateOnly || opts.replaceByProductCountry || opts.countryCode) && Array.isArray(opts.details)) {
|
||||
formData.append('detailsJson', JSON.stringify(opts.details))
|
||||
}
|
||||
return request({
|
||||
url: base + '/detail/previewImportPrices',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
// FormData must not go through repeat-submit JSON.stringify (collapses to "{}")
|
||||
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false },
|
||||
timeout: 10 * 60 * 1000
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Async pull product library into package version details; poll until done.
|
||||
* @param {{ priceSetId: string|number, psvId?: string|number, force?: boolean }} query
|
||||
* @param {(task: object) => void} [onProgress]
|
||||
*/
|
||||
async function pullSetDetailsFromLibraryAsync(query, onProgress) {
|
||||
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)
|
||||
params.set('force', query && query.force ? 'true' : 'false')
|
||||
const submitRes = await request({
|
||||
url: base + '/detail/pullFromLibrary?' + params.toString(),
|
||||
method: 'post'
|
||||
})
|
||||
const taskId = pickSaveTaskId(submitRes)
|
||||
if (!taskId) {
|
||||
throw new Error('missing pull taskId')
|
||||
}
|
||||
return pollPriceSetSaveTask(taskId, onProgress)
|
||||
}
|
||||
|
||||
async function pollPriceSetSaveTask(taskId, onProgress) {
|
||||
const started = Date.now()
|
||||
const maxMs = 30 * 60 * 1000
|
||||
while (Date.now() - started < maxMs) {
|
||||
const res = await getPriceSetSaveTask(taskId)
|
||||
const task = res.data || {}
|
||||
if (typeof onProgress === 'function') {
|
||||
onProgress(task)
|
||||
}
|
||||
if (task.status === 'SUCCESS') {
|
||||
return { task }
|
||||
}
|
||||
if (task.status === 'FAIL') {
|
||||
const err = new Error(task.error || task.message || 'task failed')
|
||||
err.task = task
|
||||
throw err
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 400))
|
||||
}
|
||||
throw new Error('task timeout')
|
||||
}
|
||||
|
||||
function updateSetDetail(data) {
|
||||
return request({
|
||||
url: base + '/detail',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit async batch write of detail surcharge snapshots and poll until done.
|
||||
* @returns {Promise<{ task: object }>}
|
||||
*/
|
||||
async function updateSetDetailSurchargeAsync(details, onProgress) {
|
||||
const submitRes = await request({
|
||||
url: base + '/detail/surcharge/async',
|
||||
method: 'post',
|
||||
data: details || []
|
||||
})
|
||||
const taskId = pickSaveTaskId(submitRes)
|
||||
if (!taskId) {
|
||||
throw new Error('missing surcharge taskId')
|
||||
}
|
||||
const started = Date.now()
|
||||
const maxMs = 30 * 60 * 1000
|
||||
while (Date.now() - started < maxMs) {
|
||||
const res = await getPriceSetSaveTask(taskId)
|
||||
const task = res.data || {}
|
||||
if (typeof onProgress === 'function') {
|
||||
onProgress(task)
|
||||
}
|
||||
if (task.status === 'SUCCESS') {
|
||||
return { task }
|
||||
}
|
||||
if (task.status === 'FAIL') {
|
||||
const err = new Error(task.error || task.message || 'surcharge save failed')
|
||||
err.task = task
|
||||
throw err
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 400))
|
||||
}
|
||||
throw new Error('surcharge save timeout')
|
||||
}
|
||||
|
||||
function delSetDetail(psdIds) {
|
||||
return request({
|
||||
url: base + '/detail/' + psdIds,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
function listSetCustomer(query) {
|
||||
return request({
|
||||
url: base + '/customer/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
function addSetCustomer(data) {
|
||||
return request({
|
||||
url: base + '/customer',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
function batchAddSetCustomer(data) {
|
||||
return request({
|
||||
url: base + '/customer/batch',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
function updateSetCustomer(data) {
|
||||
return request({
|
||||
url: base + '/customer',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
function delSetCustomer(ids) {
|
||||
return request({
|
||||
url: base + '/customer/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
listPriceSet,
|
||||
getPriceSet,
|
||||
savePriceSet,
|
||||
getPriceSetSaveTask,
|
||||
savePriceSetAsync,
|
||||
updatePriceSet,
|
||||
updatePriceSetBasic,
|
||||
delPriceSet,
|
||||
submitPriceSet,
|
||||
approvePriceSet,
|
||||
rejectPriceSet,
|
||||
activatePriceSetVersion,
|
||||
copyPriceSetVersion,
|
||||
createPriceSetVersion,
|
||||
listPriceSetVersionExcelFiles,
|
||||
deletePriceSetVersion,
|
||||
disablePriceSet,
|
||||
enablePriceSet,
|
||||
copyPriceSet,
|
||||
validatePriceSet,
|
||||
listSetDetail,
|
||||
listSetDetailByProduct,
|
||||
listSetDetailByVersion,
|
||||
listSetDetailOptions,
|
||||
addSetDetail,
|
||||
importSetDetailPricesAsync,
|
||||
previewPullFromLibrary,
|
||||
previewImportDetailPrices,
|
||||
pullSetDetailsFromLibraryAsync,
|
||||
updateSetDetail,
|
||||
updateSetDetailSurchargeAsync,
|
||||
delSetDetail,
|
||||
listSetCustomer,
|
||||
addSetCustomer,
|
||||
batchAddSetCustomer,
|
||||
updateSetCustomer,
|
||||
delSetCustomer
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { createPriceSetApi } from './createPriceSetApi'
|
||||
|
||||
export const exclusiveQuoteApi = createPriceSetApi('/price/exclusive')
|
||||
|
||||
export const {
|
||||
listPriceSet,
|
||||
getPriceSet,
|
||||
savePriceSet,
|
||||
getPriceSetSaveTask,
|
||||
savePriceSetAsync,
|
||||
updatePriceSet,
|
||||
updatePriceSetBasic,
|
||||
delPriceSet,
|
||||
submitPriceSet,
|
||||
approvePriceSet,
|
||||
rejectPriceSet,
|
||||
activatePriceSetVersion,
|
||||
copyPriceSetVersion,
|
||||
createPriceSetVersion,
|
||||
listPriceSetVersionExcelFiles,
|
||||
deletePriceSetVersion,
|
||||
disablePriceSet,
|
||||
enablePriceSet,
|
||||
copyPriceSet,
|
||||
validatePriceSet,
|
||||
listSetDetail,
|
||||
listSetDetailByProduct,
|
||||
listSetDetailByVersion,
|
||||
listSetDetailOptions,
|
||||
addSetDetail,
|
||||
importSetDetailPricesAsync,
|
||||
previewPullFromLibrary,
|
||||
previewImportDetailPrices,
|
||||
pullSetDetailsFromLibraryAsync,
|
||||
updateSetDetail,
|
||||
updateSetDetailSurchargeAsync,
|
||||
delSetDetail,
|
||||
listSetCustomer,
|
||||
addSetCustomer,
|
||||
batchAddSetCustomer,
|
||||
updateSetCustomer,
|
||||
delSetCustomer
|
||||
} = exclusiveQuoteApi
|
||||
+41
-438
@@ -1,440 +1,43 @@
|
||||
import request from '@/utils/request'
|
||||
import { createPriceSetApi } from './createPriceSetApi'
|
||||
|
||||
export function listPriceSet(query) {
|
||||
return request({
|
||||
url: '/price/set/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
export const priceSetApi = createPriceSetApi('/price/set')
|
||||
|
||||
export function getPriceSet(priceSetId) {
|
||||
return request({
|
||||
url: '/price/set/' + priceSetId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function savePriceSet(data) {
|
||||
return request({
|
||||
url: '/price/set',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function getPriceSetSaveTask(taskId) {
|
||||
return request({
|
||||
url: '/price/set/save/task/' + taskId,
|
||||
method: 'get',
|
||||
timeout: 10 * 60 * 1000
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit save async and poll Redis progress until SUCCESS/FAIL.
|
||||
* @returns {Promise<{ priceSetId: number|string, task: object }>}
|
||||
*/
|
||||
export async function savePriceSetAsync(data, onProgress) {
|
||||
const submitRes = await savePriceSet(data)
|
||||
const taskId = pickSaveTaskId(submitRes)
|
||||
if (!taskId) {
|
||||
throw new Error('missing save taskId')
|
||||
}
|
||||
const started = Date.now()
|
||||
const maxMs = 30 * 60 * 1000
|
||||
while (Date.now() - started < maxMs) {
|
||||
const res = await getPriceSetSaveTask(taskId)
|
||||
const task = res.data || {}
|
||||
if (typeof onProgress === 'function') {
|
||||
onProgress(task)
|
||||
}
|
||||
if (task.status === 'SUCCESS') {
|
||||
return { priceSetId: task.priceSetId, task }
|
||||
}
|
||||
if (task.status === 'FAIL') {
|
||||
const err = new Error(task.error || task.message || 'save failed')
|
||||
err.task = task
|
||||
throw err
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 400))
|
||||
}
|
||||
throw new Error('save timeout')
|
||||
}
|
||||
|
||||
/** Accept data.taskId / data string / legacy msg UUID (Bms String overload). */
|
||||
function pickSaveTaskId(res) {
|
||||
if (!res) return null
|
||||
const d = res.data
|
||||
if (d && typeof d === 'object' && d.taskId) return String(d.taskId)
|
||||
if (typeof d === 'string' && d.trim()) return d.trim()
|
||||
if (typeof res.msg === 'string') {
|
||||
const m = res.msg.trim()
|
||||
if (/^[a-f0-9]{32}$/i.test(m)) return m
|
||||
if (/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(m)) {
|
||||
return m.replace(/-/g, '')
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function updatePriceSet(data) {
|
||||
return request({
|
||||
url: '/price/set',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
/** Update package name and note only. */
|
||||
export function updatePriceSetBasic(data) {
|
||||
return request({
|
||||
url: '/price/set/basic',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function delPriceSet(priceSetIds) {
|
||||
return request({
|
||||
url: '/price/set/' + priceSetIds,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function submitPriceSet(priceSetId) {
|
||||
return request({
|
||||
url: '/price/set/submit/' + priceSetId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function approvePriceSet(priceSetId) {
|
||||
return request({
|
||||
url: '/price/set/approve/' + priceSetId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function rejectPriceSet(priceSetId) {
|
||||
return request({
|
||||
url: '/price/set/reject/' + priceSetId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function activatePriceSetVersion(psvId, data) {
|
||||
return request({
|
||||
url: '/price/set/version/activate/' + psvId,
|
||||
method: 'put',
|
||||
data: data || {}
|
||||
})
|
||||
}
|
||||
|
||||
export function copyPriceSetVersion(psvId) {
|
||||
return request({
|
||||
url: '/price/set/version/copy/' + psvId,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
/** Create empty draft version under package */
|
||||
export function createPriceSetVersion(priceSetId) {
|
||||
return request({
|
||||
url: '/price/set/version/create/' + priceSetId,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
/** Import excel attachments for a price-set version (via prc_price_set_product.psv_id). */
|
||||
export function listPriceSetVersionExcelFiles(psvId) {
|
||||
return request({
|
||||
url: '/price/set/version/' + psvId + '/excelFiles',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function deletePriceSetVersion(psvId) {
|
||||
return request({
|
||||
url: '/price/set/version/' + psvId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function disablePriceSet(priceSetId) {
|
||||
return request({
|
||||
url: '/price/set/disable/' + priceSetId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function enablePriceSet(priceSetId) {
|
||||
return request({
|
||||
url: '/price/set/enable/' + priceSetId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function copyPriceSet(priceSetId) {
|
||||
return request({
|
||||
url: '/price/set/copy/' + priceSetId,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
export function validatePriceSet(data) {
|
||||
return request({
|
||||
url: '/price/set/validate',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function listSetDetail(query) {
|
||||
return request({
|
||||
url: '/price/set/detail/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
/** All detail rows for one product under a version (no pagination). */
|
||||
export function listSetDetailByProduct(psvId, productCode) {
|
||||
return request({
|
||||
url: '/price/set/detail/byProduct',
|
||||
method: 'get',
|
||||
params: { psvId, productCode }
|
||||
})
|
||||
}
|
||||
|
||||
/** All detail rows for a version (no pagination); one call instead of N byProduct. */
|
||||
export function listSetDetailByVersion(psvId) {
|
||||
return request({
|
||||
url: '/price/set/detail/byVersion',
|
||||
method: 'get',
|
||||
params: { psvId }
|
||||
})
|
||||
}
|
||||
|
||||
/** 版本明细搜索下拉选项:按版本去重后的 产品/国家/分区 */
|
||||
export function listSetDetailOptions(psvId) {
|
||||
return request({
|
||||
url: '/price/set/detail/options',
|
||||
method: 'get',
|
||||
params: { psvId }
|
||||
})
|
||||
}
|
||||
|
||||
export function addSetDetail(data) {
|
||||
return request({
|
||||
url: '/price/set/detail',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Async import quote Excel into FIXED package detail prices; poll until done.
|
||||
* @param {File|Blob} file
|
||||
* @param {{ priceSetId: string|number, psvId?: string|number, updateOnly?: boolean, replaceByProductCountry?: boolean, countryCode?: string }} query
|
||||
* @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()
|
||||
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)
|
||||
if (query && query.updateOnly) params.set('updateOnly', 'true')
|
||||
// Package Excel build-price only (product+country replace scope)
|
||||
if (query && query.replaceByProductCountry) params.set('replaceByProductCountry', 'true')
|
||||
if (query && query.countryCode) params.set('countryCode', query.countryCode)
|
||||
const submitRes = await request({
|
||||
url: '/price/set/detail/importPrices?' + params.toString(),
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false }
|
||||
})
|
||||
const taskId = pickSaveTaskId(submitRes)
|
||||
if (!taskId) {
|
||||
throw new Error('missing import taskId')
|
||||
}
|
||||
return pollPriceSetSaveTask(taskId, onProgress)
|
||||
}
|
||||
|
||||
/**
|
||||
* Preview pull product library (no DB write). Returns { products, details, message }.
|
||||
*/
|
||||
export function previewPullFromLibrary() {
|
||||
return request({
|
||||
url: '/price/set/detail/previewPullFromLibrary',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Preview Excel import (no DB write).
|
||||
* @param {File|Blob} file
|
||||
* @param {{ updateOnly?: boolean, replaceByProductCountry?: boolean, countryCode?: string, details?: Array }} [opts]
|
||||
*/
|
||||
export function previewImportDetailPrices(file, opts = {}) {
|
||||
const formData = new FormData()
|
||||
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)
|
||||
// updateOnly / Excel build-price merge need current draft details
|
||||
if ((opts.updateOnly || opts.replaceByProductCountry || opts.countryCode) && Array.isArray(opts.details)) {
|
||||
formData.append('detailsJson', JSON.stringify(opts.details))
|
||||
}
|
||||
return request({
|
||||
url: '/price/set/detail/previewImportPrices',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
// FormData must not go through repeat-submit JSON.stringify (collapses to "{}")
|
||||
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false },
|
||||
timeout: 10 * 60 * 1000
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Async pull product library into package version details; poll until done.
|
||||
* @param {{ priceSetId: string|number, psvId?: string|number, force?: boolean }} query
|
||||
* @param {(task: object) => void} [onProgress]
|
||||
*/
|
||||
export async function pullSetDetailsFromLibraryAsync(query, onProgress) {
|
||||
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)
|
||||
params.set('force', query && query.force ? 'true' : 'false')
|
||||
const submitRes = await request({
|
||||
url: '/price/set/detail/pullFromLibrary?' + params.toString(),
|
||||
method: 'post'
|
||||
})
|
||||
const taskId = pickSaveTaskId(submitRes)
|
||||
if (!taskId) {
|
||||
throw new Error('missing pull taskId')
|
||||
}
|
||||
return pollPriceSetSaveTask(taskId, onProgress)
|
||||
}
|
||||
|
||||
async function pollPriceSetSaveTask(taskId, onProgress) {
|
||||
const started = Date.now()
|
||||
const maxMs = 30 * 60 * 1000
|
||||
while (Date.now() - started < maxMs) {
|
||||
const res = await getPriceSetSaveTask(taskId)
|
||||
const task = res.data || {}
|
||||
if (typeof onProgress === 'function') {
|
||||
onProgress(task)
|
||||
}
|
||||
if (task.status === 'SUCCESS') {
|
||||
return { task }
|
||||
}
|
||||
if (task.status === 'FAIL') {
|
||||
const err = new Error(task.error || task.message || 'task failed')
|
||||
err.task = task
|
||||
throw err
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 400))
|
||||
}
|
||||
throw new Error('task timeout')
|
||||
}
|
||||
|
||||
export function updateSetDetail(data) {
|
||||
return request({
|
||||
url: '/price/set/detail',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit async batch write of detail surcharge snapshots and poll until done.
|
||||
* @returns {Promise<{ task: object }>}
|
||||
*/
|
||||
export async function updateSetDetailSurchargeAsync(details, onProgress) {
|
||||
const submitRes = await request({
|
||||
url: '/price/set/detail/surcharge/async',
|
||||
method: 'post',
|
||||
data: details || []
|
||||
})
|
||||
const taskId = pickSaveTaskId(submitRes)
|
||||
if (!taskId) {
|
||||
throw new Error('missing surcharge taskId')
|
||||
}
|
||||
const started = Date.now()
|
||||
const maxMs = 30 * 60 * 1000
|
||||
while (Date.now() - started < maxMs) {
|
||||
const res = await getPriceSetSaveTask(taskId)
|
||||
const task = res.data || {}
|
||||
if (typeof onProgress === 'function') {
|
||||
onProgress(task)
|
||||
}
|
||||
if (task.status === 'SUCCESS') {
|
||||
return { task }
|
||||
}
|
||||
if (task.status === 'FAIL') {
|
||||
const err = new Error(task.error || task.message || 'surcharge save failed')
|
||||
err.task = task
|
||||
throw err
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 400))
|
||||
}
|
||||
throw new Error('surcharge save timeout')
|
||||
}
|
||||
|
||||
export function delSetDetail(psdIds) {
|
||||
return request({
|
||||
url: '/price/set/detail/' + psdIds,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function listSetCustomer(query) {
|
||||
return request({
|
||||
url: '/price/set/customer/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function addSetCustomer(data) {
|
||||
return request({
|
||||
url: '/price/set/customer',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function batchAddSetCustomer(data) {
|
||||
return request({
|
||||
url: '/price/set/customer/batch',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateSetCustomer(data) {
|
||||
return request({
|
||||
url: '/price/set/customer',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function delSetCustomer(ids) {
|
||||
return request({
|
||||
url: '/price/set/customer/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
export const {
|
||||
listPriceSet,
|
||||
getPriceSet,
|
||||
savePriceSet,
|
||||
getPriceSetSaveTask,
|
||||
savePriceSetAsync,
|
||||
updatePriceSet,
|
||||
updatePriceSetBasic,
|
||||
delPriceSet,
|
||||
submitPriceSet,
|
||||
approvePriceSet,
|
||||
rejectPriceSet,
|
||||
activatePriceSetVersion,
|
||||
copyPriceSetVersion,
|
||||
createPriceSetVersion,
|
||||
listPriceSetVersionExcelFiles,
|
||||
deletePriceSetVersion,
|
||||
disablePriceSet,
|
||||
enablePriceSet,
|
||||
copyPriceSet,
|
||||
validatePriceSet,
|
||||
listSetDetail,
|
||||
listSetDetailByProduct,
|
||||
listSetDetailByVersion,
|
||||
listSetDetailOptions,
|
||||
addSetDetail,
|
||||
importSetDetailPricesAsync,
|
||||
previewPullFromLibrary,
|
||||
previewImportDetailPrices,
|
||||
pullSetDetailsFromLibraryAsync,
|
||||
updateSetDetail,
|
||||
updateSetDetailSurchargeAsync,
|
||||
delSetDetail,
|
||||
listSetCustomer,
|
||||
addSetCustomer,
|
||||
batchAddSetCustomer,
|
||||
updateSetCustomer,
|
||||
delSetCustomer
|
||||
} = priceSetApi
|
||||
|
||||
Reference in New Issue
Block a user