|
|
@@ -670,7 +670,7 @@ function nextAuditId() {
|
|
|
return 'AR' + ymd + String(auditIdCounter).padStart(4, '0')
|
|
|
}
|
|
|
|
|
|
-function snapshotOf(equity) {
|
|
|
+function snapshotOf(equity, couponBatchId) {
|
|
|
return {
|
|
|
equityName: equity.equityName,
|
|
|
source: equity.source,
|
|
|
@@ -680,7 +680,8 @@ function snapshotOf(equity) {
|
|
|
jumpLink: equity.jumpLink,
|
|
|
skuNo: equity.skuNo,
|
|
|
merchantName: equity.merchantName,
|
|
|
- subTitle: equity.subTitle || ''
|
|
|
+ subTitle: equity.subTitle || '',
|
|
|
+ couponBatchId: couponBatchId !== undefined ? (couponBatchId || '') : (equity.couponBatchId || '')
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -748,7 +749,8 @@ Mock.mock(/\/api\/equity\/save-draft/, 'post', (options) => {
|
|
|
showOnHome: body.showOnHome || '不显示',
|
|
|
showOnAssembly: body.showOnAssembly || '不显示',
|
|
|
assemblyPages: body.assemblyPages || [],
|
|
|
- subTitle: body.subTitle || ''
|
|
|
+ subTitle: body.subTitle || '',
|
|
|
+ couponBatchId: body.couponBatchId || ''
|
|
|
}
|
|
|
equityList.unshift(newRow)
|
|
|
return { code: 200, data: { productId: newId }, msg: '草稿已保存' }
|
|
|
@@ -794,7 +796,8 @@ Mock.mock(/\/api\/equity\/submit/, 'post', (options) => {
|
|
|
showOnHome: body.showOnHome || '不显示',
|
|
|
showOnAssembly: body.showOnAssembly || '不显示',
|
|
|
assemblyPages: body.assemblyPages || [],
|
|
|
- subTitle: body.subTitle || ''
|
|
|
+ subTitle: body.subTitle || '',
|
|
|
+ couponBatchId: body.couponBatchId || ''
|
|
|
}
|
|
|
equityList.unshift(newRow)
|
|
|
auditList.unshift({
|
|
|
@@ -954,6 +957,10 @@ Mock.mock(/\/api\/audit\/approve/, 'post', (options) => {
|
|
|
|
|
|
if (audit.auditType === 'new') {
|
|
|
equityList[eqIdx] = { ...eq, shelfStatus: '已上架', auditStatus: '审核通过', reviewer: auditor, reviewTime: now }
|
|
|
+ // 券码商品且关联了待导入批次:首次上架通过时模拟 SIP 导入、移入已导入列表
|
|
|
+ if (audit.snapshot && audit.snapshot.couponBatchId) {
|
|
|
+ importPendingBatch(audit.snapshot.couponBatchId, eq.productId, eq.equityName)
|
|
|
+ }
|
|
|
} else if (audit.auditType === 'offshelf') {
|
|
|
equityList[eqIdx] = { ...eq, shelfStatus: '未上架', auditStatus: '审核通过', reviewer: auditor, reviewTime: now }
|
|
|
}
|
|
|
@@ -1734,6 +1741,14 @@ Mock.mock(/\/api\/coupon-audit\/approve/, 'post', (options) => {
|
|
|
const audit = couponAuditList[idx]
|
|
|
if (audit.auditStatus !== 'pending') return { code: 400, data: null, msg: '该审核单已完成' }
|
|
|
couponAuditList[idx] = { ...audit, auditStatus: 'approved', auditorName: body.auditorName || '王五', auditTime: nowStr() }
|
|
|
+ // 联动待导入记录:已关联权益商品 → 模拟 SIP 导入、移入已导入列表;未关联 → 仅置为审核通过,留在待导入列表
|
|
|
+ if (audit.batchId) {
|
|
|
+ const pending = pendingCouponList.find(p => p.batchId === audit.batchId)
|
|
|
+ if (pending) {
|
|
|
+ pending.auditStatus = 'approved'
|
|
|
+ if (pending.productId) importPendingBatch(pending.batchId)
|
|
|
+ }
|
|
|
+ }
|
|
|
return { code: 200, data: null, msg: '审核通过' }
|
|
|
})
|
|
|
|
|
|
@@ -1744,7 +1759,273 @@ Mock.mock(/\/api\/coupon-audit\/reject/, 'post', (options) => {
|
|
|
const audit = couponAuditList[idx]
|
|
|
if (audit.auditStatus !== 'pending') return { code: 400, data: null, msg: '该审核单已完成' }
|
|
|
couponAuditList[idx] = { ...audit, auditStatus: 'rejected', auditorName: body.auditorName || '王五', auditTime: nowStr() }
|
|
|
+ if (audit.batchId) {
|
|
|
+ const pending = pendingCouponList.find(p => p.batchId === audit.batchId)
|
|
|
+ if (pending) pending.auditStatus = 'rejected'
|
|
|
+ }
|
|
|
return { code: 200, data: null, msg: '已驳回' }
|
|
|
})
|
|
|
|
|
|
+// ==================== 已导入券码批次(全部借记卡权益商品) ====================
|
|
|
+const couponBatchList = [
|
|
|
+ {
|
|
|
+ batchId: 'B100001', productId: 'Q100001', equityName: '权益A',
|
|
|
+ importCount: 1000, actualImportCount: 998, failCount: 2, remainingCount: 720,
|
|
|
+ effectiveTime: '2026-04-16 00:00:00', expireTime: '2026-12-31 23:59:59',
|
|
|
+ fileStatus: '处理成功', importTime: '2026-04-15 10:32:18', creator: '张三',
|
|
|
+ recycleRecords: [
|
|
|
+ { recycleTime: '2026-05-10 14:22:08', type: '未发放券码回收', operator: '张三', amount: 120 },
|
|
|
+ { recycleTime: '2026-04-28 09:15:33', type: '已过期券码回收', operator: '李四', amount: 80 }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ batchId: 'B100002', productId: 'Q100001', equityName: '权益A',
|
|
|
+ importCount: 500, actualImportCount: 500, failCount: 0, remainingCount: 320,
|
|
|
+ effectiveTime: '2026-04-21 00:00:00', expireTime: '2026-09-30 23:59:59',
|
|
|
+ fileStatus: '处理成功', importTime: '2026-04-20 14:15:42', creator: '李四',
|
|
|
+ recycleRecords: [
|
|
|
+ { recycleTime: '2026-04-12 16:40:51', type: '未发放券码回收', operator: '王五', amount: 200 }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ batchId: 'B100003', productId: 'Q100002', equityName: '权益B',
|
|
|
+ importCount: 800, actualImportCount: 0, failCount: 0, remainingCount: 0,
|
|
|
+ effectiveTime: '2026-05-08 00:00:00', expireTime: '2026-12-31 23:59:59',
|
|
|
+ fileStatus: '处理中', importTime: '2026-05-07 09:08:11', creator: '王五',
|
|
|
+ recycleRecords: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ batchId: 'B100004', productId: 'Q100002', equityName: '权益B',
|
|
|
+ importCount: 200, actualImportCount: 0, failCount: 200, remainingCount: 0,
|
|
|
+ effectiveTime: '2026-05-02 00:00:00', expireTime: '2026-10-31 23:59:59',
|
|
|
+ fileStatus: '处理失败', importTime: '2026-05-01 16:45:30', creator: '赵六',
|
|
|
+ recycleRecords: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ batchId: 'B100005', productId: 'Q100003', equityName: '权益C',
|
|
|
+ importCount: 1500, actualImportCount: 1500, failCount: 0, remainingCount: 1280,
|
|
|
+ effectiveTime: '2026-04-10 00:00:00', expireTime: '2026-12-31 23:59:59',
|
|
|
+ fileStatus: '处理成功', importTime: '2026-04-09 09:21:05', creator: '张三',
|
|
|
+ recycleRecords: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ batchId: 'B100006', productId: 'Q100003', equityName: '权益C',
|
|
|
+ importCount: 600, actualImportCount: 598, failCount: 2, remainingCount: 420,
|
|
|
+ effectiveTime: '2026-04-05 00:00:00', expireTime: '2026-11-30 23:59:59',
|
|
|
+ fileStatus: '处理成功', importTime: '2026-04-04 14:02:33', creator: '李四',
|
|
|
+ recycleRecords: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ batchId: 'B100007', productId: 'Q100004', equityName: '权益D',
|
|
|
+ importCount: 300, actualImportCount: 300, failCount: 0, remainingCount: 0,
|
|
|
+ effectiveTime: '2026-03-20 00:00:00', expireTime: '2026-09-30 23:59:59',
|
|
|
+ fileStatus: '处理成功', importTime: '2026-03-19 10:45:12', creator: '王五',
|
|
|
+ recycleRecords: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ batchId: 'B100008', productId: 'Q100004', equityName: '权益D',
|
|
|
+ importCount: 2000, actualImportCount: 1995, failCount: 5, remainingCount: 1620,
|
|
|
+ effectiveTime: '2026-03-15 00:00:00', expireTime: '2026-12-31 23:59:59',
|
|
|
+ fileStatus: '处理成功', importTime: '2026-03-14 16:30:48', creator: '张三',
|
|
|
+ recycleRecords: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ batchId: 'B100009', productId: 'Q100005', equityName: '权益E',
|
|
|
+ importCount: 450, actualImportCount: 450, failCount: 0, remainingCount: 130,
|
|
|
+ effectiveTime: '2026-03-01 00:00:00', expireTime: '2026-08-31 23:59:59',
|
|
|
+ fileStatus: '处理成功', importTime: '2026-02-28 11:18:27', creator: '李四',
|
|
|
+ recycleRecords: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ batchId: 'B100010', productId: 'Q100005', equityName: '权益E',
|
|
|
+ importCount: 800, actualImportCount: 796, failCount: 4, remainingCount: 510,
|
|
|
+ effectiveTime: '2026-02-20 00:00:00', expireTime: '2026-10-31 23:59:59',
|
|
|
+ fileStatus: '处理成功', importTime: '2026-02-19 15:55:09', creator: '王五',
|
|
|
+ recycleRecords: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ batchId: 'B100011', productId: 'Q100007', equityName: '微信立减金 5元(满10减5)',
|
|
|
+ importCount: 1200, actualImportCount: 1200, failCount: 0, remainingCount: 60,
|
|
|
+ effectiveTime: '2026-02-10 00:00:00', expireTime: '2026-07-31 23:59:59',
|
|
|
+ fileStatus: '处理成功', importTime: '2026-02-09 09:40:51', creator: '赵六',
|
|
|
+ recycleRecords: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ batchId: 'B100012', productId: 'Q100001', equityName: '权益A',
|
|
|
+ importCount: 350, actualImportCount: 348, failCount: 2, remainingCount: 0,
|
|
|
+ effectiveTime: '2026-01-15 00:00:00', expireTime: '2026-06-30 23:59:59',
|
|
|
+ fileStatus: '处理成功', importTime: '2026-01-14 13:27:36', creator: '张三',
|
|
|
+ recycleRecords: []
|
|
|
+ }
|
|
|
+]
|
|
|
+
|
|
|
+// 已导入券码列表:权益编号、批次ID 均为精准匹配
|
|
|
+Mock.mock(/\/api\/coupon\/batch-list/, 'get', (options) => {
|
|
|
+ const url = new URL(options.url, 'http://localhost')
|
|
|
+ const productId = url.searchParams.get('productId') || ''
|
|
|
+ const batchId = url.searchParams.get('batchId') || ''
|
|
|
+ let filtered = couponBatchList
|
|
|
+ if (productId) filtered = filtered.filter(b => b.productId === productId)
|
|
|
+ if (batchId) filtered = filtered.filter(b => b.batchId === batchId)
|
|
|
+ return { code: 200, data: filtered, msg: 'ok' }
|
|
|
+})
|
|
|
+
|
|
|
+// 导入券码:生成「待导入券码记录」+「券码审核单」,券码审核通过后才真正导入
|
|
|
+Mock.mock(/\/api\/coupon\/import/, 'post', (options) => {
|
|
|
+ const body = JSON.parse(options.body)
|
|
|
+ let productId = ''
|
|
|
+ let equityName = ''
|
|
|
+ if (body.productId) {
|
|
|
+ const equity = equityList.find(e => e.productId === body.productId)
|
|
|
+ if (!equity) return { code: 404, data: null, msg: '权益商品不存在' }
|
|
|
+ productId = equity.productId
|
|
|
+ equityName = equity.equityName
|
|
|
+ }
|
|
|
+ const batchId = nextPendingBatchId()
|
|
|
+ // 原型读不了上传文件,导入数量用 mock 随机数模拟
|
|
|
+ const importCount = 100 + Math.floor(Math.random() * 4900)
|
|
|
+ const createTime = nowStr()
|
|
|
+ const pending = { batchId, productId, equityName, importCount, creator: '当前用户', createTime, auditStatus: 'pending' }
|
|
|
+ pendingCouponList.unshift(pending)
|
|
|
+ couponAuditList.unshift(makeImportAudit(pending))
|
|
|
+ return { code: 200, data: { batchId }, msg: '已提交,等待券码审核' }
|
|
|
+})
|
|
|
+
|
|
|
+Mock.mock(/\/api\/coupon\/recycle/, 'post', (options) => {
|
|
|
+ const body = JSON.parse(options.body)
|
|
|
+ const batch = couponBatchList.find(b => b.batchId === body.batchId)
|
|
|
+ if (!batch) return { code: 404, data: null, msg: '批次不存在' }
|
|
|
+ const amount = Number(body.amount) || 0
|
|
|
+ if (amount < 1) return { code: 400, data: null, msg: '回收数量无效' }
|
|
|
+ // 未发放券码回收会扣减剩余数量;已过期券码回收仅记录,不扣减剩余库存
|
|
|
+ if (body.type === 'unissued') {
|
|
|
+ batch.remainingCount = Math.max(0, Number(batch.remainingCount) - amount)
|
|
|
+ }
|
|
|
+ const typeLabel = body.type === 'expired' ? '已过期券码回收' : '未发放券码回收'
|
|
|
+ if (!batch.recycleRecords) batch.recycleRecords = []
|
|
|
+ batch.recycleRecords.unshift({ recycleTime: nowStr(), type: typeLabel, operator: '当前用户', amount })
|
|
|
+ return { code: 200, data: null, msg: '回收成功' }
|
|
|
+})
|
|
|
+
|
|
|
+// ==================== 待导入券码记录(券码先导入、后关联权益) ====================
|
|
|
+function nextPendingBatchId() {
|
|
|
+ const d = new Date()
|
|
|
+ const p = n => String(n).padStart(2, '0')
|
|
|
+ return 'I' + d.getFullYear() + p(d.getMonth() + 1) + p(d.getDate()) + p(d.getHours()) + p(d.getMinutes()) + p(d.getSeconds())
|
|
|
+}
|
|
|
+
|
|
|
+const pendingCouponList = [
|
|
|
+ { batchId: 'I20260620090301', productId: '', equityName: '', importCount: 1000, creator: '张三', createTime: '2026-06-20 09:03:01', auditStatus: 'pending' },
|
|
|
+ { batchId: 'I20260620143512', productId: 'Q100001', equityName: '权益A', importCount: 500, creator: '李四', createTime: '2026-06-20 14:35:12', auditStatus: 'pending' },
|
|
|
+ { batchId: 'I20260618101055', productId: '', equityName: '', importCount: 1200, creator: '张三', createTime: '2026-06-18 10:10:55', auditStatus: 'approved' },
|
|
|
+ { batchId: 'I20260617161820', productId: '', equityName: '', importCount: 800, creator: '王五', createTime: '2026-06-17 16:18:20', auditStatus: 'approved' },
|
|
|
+ { batchId: 'I20260616113045', productId: 'Q100003', equityName: '权益C', importCount: 300, creator: '赵六', createTime: '2026-06-16 11:30:45', auditStatus: 'rejected' },
|
|
|
+ { batchId: 'I20260615153000', productId: '', equityName: '', importCount: 600, creator: '李四', createTime: '2026-06-15 15:30:00', auditStatus: 'rejected' }
|
|
|
+]
|
|
|
+
|
|
|
+// 待导入记录 → 已导入批次(模拟 SIP 导入成功)
|
|
|
+function importPendingBatch(batchId, productId, equityName) {
|
|
|
+ const idx = pendingCouponList.findIndex(p => p.batchId === batchId)
|
|
|
+ if (idx < 0) return false
|
|
|
+ const p = pendingCouponList[idx]
|
|
|
+ pendingCouponList.splice(idx, 1)
|
|
|
+ couponBatchList.unshift({
|
|
|
+ batchId: p.batchId,
|
|
|
+ productId: productId || p.productId,
|
|
|
+ equityName: equityName || p.equityName,
|
|
|
+ importCount: p.importCount,
|
|
|
+ actualImportCount: p.importCount,
|
|
|
+ failCount: 0,
|
|
|
+ remainingCount: p.importCount,
|
|
|
+ effectiveTime: '',
|
|
|
+ expireTime: '',
|
|
|
+ fileStatus: '处理成功',
|
|
|
+ importTime: nowStr(),
|
|
|
+ creator: p.creator,
|
|
|
+ recycleRecords: []
|
|
|
+ })
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+// 由待导入记录派生对应的券码审核单
|
|
|
+let couponAuditSeq = 0
|
|
|
+function makeImportAudit(p) {
|
|
|
+ couponAuditSeq += 1
|
|
|
+ const reviewed = p.auditStatus !== 'pending'
|
|
|
+ return {
|
|
|
+ id: 'CPA' + p.batchId.slice(1) + String(couponAuditSeq).padStart(2, '0'),
|
|
|
+ type: 'import',
|
|
|
+ batchId: p.batchId,
|
|
|
+ productName: p.equityName || '',
|
|
|
+ productId: p.productId || '',
|
|
|
+ importCount: p.importCount,
|
|
|
+ effectiveTime: '',
|
|
|
+ expireTime: '',
|
|
|
+ creator: p.creator,
|
|
|
+ createTime: p.createTime,
|
|
|
+ auditorName: reviewed ? '王五' : '',
|
|
|
+ auditTime: reviewed ? p.createTime : '',
|
|
|
+ auditStatus: p.auditStatus
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 用待导入记录派生的审核单替换旧的占位 import 审核单(recycle 记录保留)
|
|
|
+for (let i = couponAuditList.length - 1; i >= 0; i--) {
|
|
|
+ if (couponAuditList[i].type === 'import') couponAuditList.splice(i, 1)
|
|
|
+}
|
|
|
+pendingCouponList.forEach(p => couponAuditList.push(makeImportAudit(p)))
|
|
|
+
|
|
|
+// 待导入券码列表(券码管理-待导入 Tab;选择批次弹窗传 status=approved&unlinked=1)
|
|
|
+Mock.mock(/\/api\/coupon\/pending-list/, 'get', (options) => {
|
|
|
+ const url = new URL(options.url, 'http://localhost')
|
|
|
+ const batchId = url.searchParams.get('batchId') || ''
|
|
|
+ const status = url.searchParams.get('status') || ''
|
|
|
+ const unlinked = url.searchParams.get('unlinked') || ''
|
|
|
+ let filtered = pendingCouponList
|
|
|
+ if (batchId) filtered = filtered.filter(p => p.batchId === batchId)
|
|
|
+ if (status) filtered = filtered.filter(p => p.auditStatus === status)
|
|
|
+ if (unlinked === '1') filtered = filtered.filter(p => !p.productId)
|
|
|
+ return { code: 200, data: filtered, msg: 'ok' }
|
|
|
+})
|
|
|
+
|
|
|
+// 编辑待导入记录(仅审核拒绝可编辑:可改关联权益商品,提交后重新进入待审核)
|
|
|
+Mock.mock(/\/api\/coupon\/pending-edit/, 'post', (options) => {
|
|
|
+ const body = JSON.parse(options.body)
|
|
|
+ const p = pendingCouponList.find(x => x.batchId === body.batchId)
|
|
|
+ if (!p) return { code: 404, data: null, msg: '记录不存在' }
|
|
|
+ if (p.auditStatus !== 'rejected') return { code: 400, data: null, msg: '仅审核拒绝的记录可编辑' }
|
|
|
+ let productId = ''
|
|
|
+ let equityName = ''
|
|
|
+ if (body.productId) {
|
|
|
+ const equity = equityList.find(e => e.productId === body.productId)
|
|
|
+ if (!equity) return { code: 404, data: null, msg: '权益商品不存在' }
|
|
|
+ productId = equity.productId
|
|
|
+ equityName = equity.equityName
|
|
|
+ }
|
|
|
+ p.productId = productId
|
|
|
+ p.equityName = equityName
|
|
|
+ p.auditStatus = 'pending'
|
|
|
+ const audit = couponAuditList.find(a => a.type === 'import' && a.batchId === p.batchId)
|
|
|
+ if (audit) {
|
|
|
+ audit.productId = productId
|
|
|
+ audit.productName = equityName
|
|
|
+ audit.auditStatus = 'pending'
|
|
|
+ audit.auditorName = ''
|
|
|
+ audit.auditTime = ''
|
|
|
+ }
|
|
|
+ return { code: 200, data: null, msg: '已重新提交审核' }
|
|
|
+})
|
|
|
+
|
|
|
+// 删除待导入记录(仅审核拒绝可删除)
|
|
|
+Mock.mock(/\/api\/coupon\/pending-delete/, 'post', (options) => {
|
|
|
+ const body = JSON.parse(options.body)
|
|
|
+ const idx = pendingCouponList.findIndex(p => p.batchId === body.batchId)
|
|
|
+ if (idx < 0) return { code: 404, data: null, msg: '记录不存在' }
|
|
|
+ if (pendingCouponList[idx].auditStatus !== 'rejected') return { code: 400, data: null, msg: '仅审核拒绝的记录可删除' }
|
|
|
+ pendingCouponList.splice(idx, 1)
|
|
|
+ const aIdx = couponAuditList.findIndex(a => a.type === 'import' && a.batchId === body.batchId)
|
|
|
+ if (aIdx >= 0) couponAuditList.splice(aIdx, 1)
|
|
|
+ return { code: 200, data: null, msg: '已删除' }
|
|
|
+})
|
|
|
+
|
|
|
export default Mock
|