Ver Fonte

新增权益审核模块,借记卡权益接入双状态字段和审核工作流

- 借记卡权益用商品状态(未上架/已上架)+ 审核状态(草稿/上架待审核/编辑待审核/下架待审核/审核通过)双字段表达业务状态
- 新增/编辑页拆分为"保存草稿"和"提交审核",已上架编辑生成变更审核单(pending_data 暂存,主表运行字段不动)
- 详情页和列表行加"下架"操作,提交下架审核单
- 权益管理菜单下新增"权益审核",含待审核/审核通过/审核驳回三 Tab,支持按权益编号筛选;审核通过/驳回级联回写权益主表
- mock 端补全权益和审核单两套接口,含状态机校验

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fade há 1 mês atrás
pai
commit
f11b5b3713

+ 3 - 0
pc/src/components/Layout.vue

@@ -41,6 +41,9 @@
               <el-menu-item index="/customization/hsbc/credit-card-equity">
                 信用卡权益
               </el-menu-item>
+              <el-menu-item index="/customization/hsbc/audit">
+                权益审核
+              </el-menu-item>
             </el-submenu>
             <el-submenu index="customization-hsbc-crowd">
               <template slot="title">人群管理</template>

+ 610 - 0
pc/src/mock/index.js

@@ -327,4 +327,614 @@ Mock.mock(/\/api\/campaign\/delete/, 'post', (options) => {
   return { code: 200, data: null, msg: '删除成功' }
 })
 
+// =============================================
+// 借记卡权益 + 审核中心
+// =============================================
+
+// 商品状态:未上架 / 已上架
+// 审核状态:草稿 / 上架待审核 / 编辑待审核 / 下架待审核 / 审核通过
+// 合法组合(6 种):
+//   未上架+草稿        = 草稿
+//   未上架+上架待审核   = 新增待审核
+//   未上架+审核通过     = 已下架
+//   已上架+审核通过     = 已上架
+//   已上架+编辑待审核   = 已上架·变更待审核
+//   已上架+下架待审核   = 已上架·下架待审核
+const equityList = [
+  {
+    productId: '100001',
+    equityName: '权益A',
+    source: '银行自有',
+    jumpMethod: '-',
+    jumpLink: '-',
+    exchangeMethod: '权益平台',
+    productType: '券码',
+    skuNo: 'SKU001',
+    merchantName: '商户A',
+    creator: '李运营',
+    createTime: '2026-04-10 09:32:15',
+    reviewer: '王五',
+    reviewTime: '2026-04-15 10:30:00',
+    shelfStatus: '已上架',
+    auditStatus: '审核通过',
+    pendingData: null,
+    showOnHome: '显示',
+    showOnAssembly: '不显示',
+    assemblyPages: []
+  },
+  {
+    productId: '100002',
+    equityName: '权益B',
+    source: '第三方',
+    jumpMethod: '没有',
+    jumpLink: '太古地产',
+    exchangeMethod: '第三方(列表跳转)',
+    productType: '',
+    skuNo: 'SKU002',
+    merchantName: '商户B',
+    creator: '王运营',
+    createTime: '2026-04-12 14:08:42',
+    reviewer: '',
+    reviewTime: '',
+    shelfStatus: '未上架',
+    auditStatus: '上架待审核',
+    pendingData: null,
+    showOnHome: '显示',
+    showOnAssembly: '不显示',
+    assemblyPages: []
+  },
+  {
+    productId: '100003',
+    equityName: '权益C',
+    source: '第三方',
+    jumpMethod: '有',
+    jumpLink: '龙腾',
+    exchangeMethod: '第三方(详情页跳转)',
+    productType: '',
+    skuNo: 'SKU003',
+    merchantName: '商户C',
+    creator: '李运营',
+    createTime: '2026-04-08 11:20:05',
+    reviewer: '王五',
+    reviewTime: '2026-04-14 16:45:00',
+    shelfStatus: '已上架',
+    auditStatus: '编辑待审核',
+    pendingData: { equityName: '权益C(变更)', subTitle: '调整后的副标题' },
+    showOnHome: '显示',
+    showOnAssembly: '不显示',
+    assemblyPages: []
+  },
+  {
+    productId: '100004',
+    equityName: '权益D',
+    source: '第三方',
+    jumpMethod: '有',
+    jumpLink: 'h5链接',
+    exchangeMethod: '第三方(详情页跳转)',
+    productType: '',
+    skuNo: 'SKU004',
+    merchantName: '商户D',
+    creator: '陈运营',
+    createTime: '2026-04-05 15:50:18',
+    reviewer: '赵六',
+    reviewTime: '2026-04-13 09:15:00',
+    shelfStatus: '已上架',
+    auditStatus: '下架待审核',
+    pendingData: null,
+    showOnHome: '显示',
+    showOnAssembly: '不显示',
+    assemblyPages: []
+  },
+  {
+    productId: '100005',
+    equityName: '权益E',
+    source: '银行自有',
+    jumpMethod: '-',
+    jumpLink: '-',
+    exchangeMethod: '权益平台',
+    productType: '券码',
+    skuNo: 'SKU005',
+    merchantName: '商户E',
+    creator: '王运营',
+    createTime: '2026-03-28 09:00:11',
+    reviewer: '钱七',
+    reviewTime: '2026-04-12 11:20:00',
+    shelfStatus: '未上架',
+    auditStatus: '审核通过',
+    pendingData: null,
+    showOnHome: '显示',
+    showOnAssembly: '不显示',
+    assemblyPages: []
+  },
+  {
+    productId: '100006',
+    equityName: '权益F(草稿)',
+    source: '银行自有',
+    jumpMethod: '-',
+    jumpLink: '-',
+    exchangeMethod: '权益平台',
+    productType: '券码',
+    skuNo: 'SKU006',
+    merchantName: '商户F',
+    creator: '李运营',
+    createTime: '2026-05-16 10:00:00',
+    reviewer: '',
+    reviewTime: '',
+    shelfStatus: '未上架',
+    auditStatus: '草稿',
+    pendingData: null,
+    showOnHome: '不显示',
+    showOnAssembly: '不显示',
+    assemblyPages: []
+  }
+]
+
+let equityIdCounter = 100006
+
+const auditList = [
+  {
+    id: 'AR202605150001',
+    auditType: 'new',
+    bizModule: 'equity_product',
+    bizModuleName: '借记卡权益',
+    bizId: '100002',
+    bizName: '权益B',
+    snapshot: {
+      equityName: '权益B',
+      source: '第三方',
+      jumpMethod: '没有',
+      jumpLink: '太古地产',
+      productType: '',
+      skuNo: 'SKU002',
+      merchantName: '商户B',
+      subTitle: '外部列表页副标题'
+    },
+    submitReason: '新建第三方权益,链接已对齐',
+    submitterId: 'u001',
+    submitterName: '王运营',
+    submitTime: '2026-05-15 10:00:00',
+    auditorId: null,
+    auditorName: '',
+    auditTime: '',
+    auditStatus: 'pending',
+    auditComment: ''
+  },
+  {
+    id: 'AR202605160001',
+    auditType: 'change',
+    bizModule: 'equity_product',
+    bizModuleName: '借记卡权益',
+    bizId: '100003',
+    bizName: '权益C',
+    snapshot: {
+      equityName: '权益C(变更)',
+      source: '第三方',
+      jumpMethod: '有',
+      jumpLink: '龙腾',
+      productType: '',
+      skuNo: 'SKU003',
+      merchantName: '商户C',
+      subTitle: '调整后的副标题'
+    },
+    submitReason: '调整副标题与名称',
+    submitterId: 'u002',
+    submitterName: '李运营',
+    submitTime: '2026-05-16 14:30:00',
+    auditorId: null,
+    auditorName: '',
+    auditTime: '',
+    auditStatus: 'pending',
+    auditComment: ''
+  },
+  {
+    id: 'AR202605170001',
+    auditType: 'offshelf',
+    bizModule: 'equity_product',
+    bizModuleName: '借记卡权益',
+    bizId: '100004',
+    bizName: '权益D',
+    snapshot: {
+      equityName: '权益D',
+      source: '第三方',
+      jumpMethod: '有',
+      jumpLink: 'h5链接',
+      productType: '',
+      skuNo: 'SKU004',
+      merchantName: '商户D',
+      subTitle: '外部自定义链接副标题'
+    },
+    submitReason: '业务合作到期,申请下架',
+    submitterId: 'u003',
+    submitterName: '陈运营',
+    submitTime: '2026-05-17 09:00:00',
+    auditorId: null,
+    auditorName: '',
+    auditTime: '',
+    auditStatus: 'pending',
+    auditComment: ''
+  },
+  {
+    id: 'AR202605120001',
+    auditType: 'new',
+    bizModule: 'equity_product',
+    bizModuleName: '借记卡权益',
+    bizId: '100001',
+    bizName: '权益A',
+    snapshot: {
+      equityName: '权益A',
+      source: '银行自有',
+      jumpMethod: '-',
+      jumpLink: '-',
+      productType: '券码',
+      skuNo: 'SKU001',
+      merchantName: '商户A',
+      subTitle: '副标题示例'
+    },
+    submitReason: '',
+    submitterId: 'u001',
+    submitterName: '李运营',
+    submitTime: '2026-04-10 09:32:15',
+    auditorId: 'u099',
+    auditorName: '王五',
+    auditTime: '2026-04-15 10:30:00',
+    auditStatus: 'approved',
+    auditComment: '内容合规,准予上架'
+  }
+]
+
+let auditIdCounter = 4
+
+function nowStr() {
+  return new Date().toLocaleString('zh-CN', { hour12: false }).replace(/\//g, '-')
+}
+
+function nextAuditId() {
+  auditIdCounter += 1
+  const d = new Date()
+  const ymd = d.getFullYear().toString() + String(d.getMonth() + 1).padStart(2, '0') + String(d.getDate()).padStart(2, '0')
+  return 'AR' + ymd + String(auditIdCounter).padStart(4, '0')
+}
+
+function snapshotOf(equity) {
+  return {
+    equityName: equity.equityName,
+    source: equity.source,
+    jumpMethod: equity.jumpMethod,
+    jumpLink: equity.jumpLink,
+    productType: equity.productType,
+    skuNo: equity.skuNo,
+    merchantName: equity.merchantName,
+    subTitle: equity.subTitle || ''
+  }
+}
+
+// 借记卡权益 - 列表
+Mock.mock(/\/api\/equity\/list/, 'get', (options) => {
+  const url = new URL(options.url, 'http://localhost')
+  const equityName = url.searchParams.get('equityName') || ''
+  const productId = url.searchParams.get('productId') || ''
+  const shelfStatus = url.searchParams.get('shelfStatus') || ''
+  const auditStatus = url.searchParams.get('auditStatus') || ''
+  let filtered = equityList
+  if (equityName) filtered = filtered.filter(e => e.equityName.includes(equityName))
+  if (productId) filtered = filtered.filter(e => e.productId.includes(productId))
+  if (shelfStatus) filtered = filtered.filter(e => e.shelfStatus === shelfStatus)
+  if (auditStatus) filtered = filtered.filter(e => e.auditStatus === auditStatus)
+  return { code: 200, data: filtered, msg: 'ok' }
+})
+
+// 借记卡权益 - 详情
+Mock.mock(/\/api\/equity\/detail/, 'get', (options) => {
+  const url = new URL(options.url, 'http://localhost')
+  const id = url.searchParams.get('id')
+  const item = equityList.find(e => e.productId === id)
+  return item
+    ? { code: 200, data: item, msg: 'ok' }
+    : { code: 404, data: null, msg: '权益不存在' }
+})
+
+// 保存草稿(新建或修改草稿)
+Mock.mock(/\/api\/equity\/save-draft/, 'post', (options) => {
+  const body = JSON.parse(options.body)
+  if (body.productId) {
+    // 修改草稿
+    const idx = equityList.findIndex(e => e.productId === body.productId)
+    if (idx < 0) return { code: 404, data: null, msg: '权益不存在' }
+    const cur = equityList[idx]
+    if (cur.auditStatus !== '草稿') {
+      return { code: 400, data: null, msg: '仅草稿状态可保存为草稿' }
+    }
+    equityList[idx] = { ...cur, ...body, shelfStatus: '未上架', auditStatus: '草稿' }
+    return { code: 200, data: { productId: cur.productId }, msg: '草稿已保存' }
+  }
+  // 新建草稿
+  equityIdCounter += 1
+  const newId = String(equityIdCounter)
+  const newRow = {
+    productId: newId,
+    equityName: body.equityName || '未命名权益',
+    source: body.source || '银行自有',
+    jumpMethod: body.jumpMethod || '-',
+    jumpLink: body.jumpLink || '-',
+    exchangeMethod: body.exchangeMethod || '权益平台',
+    productType: body.productType || '',
+    skuNo: body.skuNo || '',
+    merchantName: body.merchantName || '',
+    creator: body.creator || '李运营',
+    createTime: nowStr(),
+    reviewer: '',
+    reviewTime: '',
+    shelfStatus: '未上架',
+    auditStatus: '草稿',
+    pendingData: null,
+    showOnHome: body.showOnHome || '不显示',
+    showOnAssembly: body.showOnAssembly || '不显示',
+    assemblyPages: body.assemblyPages || [],
+    subTitle: body.subTitle || ''
+  }
+  equityList.unshift(newRow)
+  return { code: 200, data: { productId: newId }, msg: '草稿已保存' }
+})
+
+// 提交审核(新增上架审核 / 已上架编辑提审 / 已下架重新提审)
+Mock.mock(/\/api\/equity\/submit/, 'post', (options) => {
+  const body = JSON.parse(options.body)
+  let cur
+  let idx = -1
+  if (body.productId) {
+    idx = equityList.findIndex(e => e.productId === body.productId)
+    if (idx < 0) return { code: 404, data: null, msg: '权益不存在' }
+    cur = equityList[idx]
+  }
+
+  const submitReason = body.submitReason || ''
+  const submitter = body.submitterName || '李运营'
+
+  // 新建 + 直接提审
+  if (!cur) {
+    equityIdCounter += 1
+    const newId = String(equityIdCounter)
+    const newRow = {
+      productId: newId,
+      equityName: body.equityName || '未命名权益',
+      source: body.source || '银行自有',
+      jumpMethod: body.jumpMethod || '-',
+      jumpLink: body.jumpLink || '-',
+      exchangeMethod: body.exchangeMethod || '权益平台',
+      productType: body.productType || '',
+      skuNo: body.skuNo || '',
+      merchantName: body.merchantName || '',
+      creator: submitter,
+      createTime: nowStr(),
+      reviewer: '',
+      reviewTime: '',
+      shelfStatus: '未上架',
+      auditStatus: '上架待审核',
+      pendingData: null,
+      showOnHome: body.showOnHome || '不显示',
+      showOnAssembly: body.showOnAssembly || '不显示',
+      assemblyPages: body.assemblyPages || [],
+      subTitle: body.subTitle || ''
+    }
+    equityList.unshift(newRow)
+    auditList.unshift({
+      id: nextAuditId(),
+      auditType: 'new',
+      bizModule: 'equity_product',
+      bizModuleName: '借记卡权益',
+      bizId: newId,
+      bizName: newRow.equityName,
+      snapshot: snapshotOf(newRow),
+      submitReason,
+      submitterId: 'u001',
+      submitterName: submitter,
+      submitTime: nowStr(),
+      auditorId: null,
+      auditorName: '',
+      auditTime: '',
+      auditStatus: 'pending',
+      auditComment: ''
+    })
+    return { code: 200, data: { productId: newId }, msg: '已提交审核' }
+  }
+
+  // 草稿 → 上架待审核(new)
+  if (cur.shelfStatus === '未上架' && cur.auditStatus === '草稿') {
+    const merged = { ...cur, ...body }
+    equityList[idx] = { ...merged, shelfStatus: '未上架', auditStatus: '上架待审核' }
+    auditList.unshift({
+      id: nextAuditId(),
+      auditType: 'new',
+      bizModule: 'equity_product',
+      bizModuleName: '借记卡权益',
+      bizId: cur.productId,
+      bizName: equityList[idx].equityName,
+      snapshot: snapshotOf(equityList[idx]),
+      submitReason,
+      submitterId: 'u001',
+      submitterName: submitter,
+      submitTime: nowStr(),
+      auditorId: null,
+      auditorName: '',
+      auditTime: '',
+      auditStatus: 'pending',
+      auditComment: ''
+    })
+    return { code: 200, data: { productId: cur.productId }, msg: '已提交审核' }
+  }
+
+  // 已下架 → 重新上架(也是 new)
+  if (cur.shelfStatus === '未上架' && cur.auditStatus === '审核通过') {
+    equityList[idx] = { ...cur, ...body, shelfStatus: '未上架', auditStatus: '上架待审核' }
+    auditList.unshift({
+      id: nextAuditId(),
+      auditType: 'new',
+      bizModule: 'equity_product',
+      bizModuleName: '借记卡权益',
+      bizId: cur.productId,
+      bizName: equityList[idx].equityName,
+      snapshot: snapshotOf(equityList[idx]),
+      submitReason,
+      submitterId: 'u001',
+      submitterName: submitter,
+      submitTime: nowStr(),
+      auditorId: null,
+      auditorName: '',
+      auditTime: '',
+      auditStatus: 'pending',
+      auditComment: ''
+    })
+    return { code: 200, data: { productId: cur.productId }, msg: '已提交审核' }
+  }
+
+  // 已上架 → 编辑待审核(change),写入 pendingData,不动主表运行字段
+  if (cur.shelfStatus === '已上架' && cur.auditStatus === '审核通过') {
+    const pending = { ...body }
+    delete pending.submitReason
+    delete pending.submitterName
+    delete pending.productId
+    equityList[idx] = { ...cur, auditStatus: '编辑待审核', pendingData: pending }
+    auditList.unshift({
+      id: nextAuditId(),
+      auditType: 'change',
+      bizModule: 'equity_product',
+      bizModuleName: '借记卡权益',
+      bizId: cur.productId,
+      bizName: cur.equityName,
+      snapshot: { ...snapshotOf(cur), ...pending },
+      submitReason,
+      submitterId: 'u001',
+      submitterName: submitter,
+      submitTime: nowStr(),
+      auditorId: null,
+      auditorName: '',
+      auditTime: '',
+      auditStatus: 'pending',
+      auditComment: ''
+    })
+    return { code: 200, data: { productId: cur.productId }, msg: '已提交审核' }
+  }
+
+  return { code: 400, data: null, msg: '当前状态不可提交审核' }
+})
+
+// 申请下架
+Mock.mock(/\/api\/equity\/request-offshelf/, 'post', (options) => {
+  const body = JSON.parse(options.body)
+  const idx = equityList.findIndex(e => e.productId === body.productId)
+  if (idx < 0) return { code: 404, data: null, msg: '权益不存在' }
+  const cur = equityList[idx]
+  if (cur.shelfStatus !== '已上架' || cur.auditStatus !== '审核通过') {
+    return { code: 400, data: null, msg: '仅已上架且无审核中的权益可申请下架' }
+  }
+  equityList[idx] = { ...cur, auditStatus: '下架待审核' }
+  auditList.unshift({
+    id: nextAuditId(),
+    auditType: 'offshelf',
+    bizModule: 'equity_product',
+    bizModuleName: '借记卡权益',
+    bizId: cur.productId,
+    bizName: cur.equityName,
+    snapshot: snapshotOf(cur),
+    submitReason: '',
+    submitterId: 'u001',
+    submitterName: body.submitterName || '李运营',
+    submitTime: nowStr(),
+    auditorId: null,
+    auditorName: '',
+    auditTime: '',
+    auditStatus: 'pending',
+    auditComment: ''
+  })
+  return { code: 200, data: null, msg: '已提交下架审核' }
+})
+
+// 删除权益(仅草稿/已下架)
+Mock.mock(/\/api\/equity\/delete/, 'post', (options) => {
+  const body = JSON.parse(options.body)
+  const idx = equityList.findIndex(e => e.productId === body.productId)
+  if (idx < 0) return { code: 404, data: null, msg: '权益不存在' }
+  const cur = equityList[idx]
+  const canDelete = (cur.shelfStatus === '未上架' && (cur.auditStatus === '草稿' || cur.auditStatus === '审核通过'))
+  if (!canDelete) return { code: 400, data: null, msg: '当前状态不可删除' }
+  equityList.splice(idx, 1)
+  return { code: 200, data: null, msg: '删除成功' }
+})
+
+// 审核中心 - 列表
+Mock.mock(/\/api\/audit\/list/, 'get', (options) => {
+  const url = new URL(options.url, 'http://localhost')
+  const auditStatus = url.searchParams.get('auditStatus') || ''
+  const bizId = url.searchParams.get('bizId') || ''
+  let filtered = auditList
+  if (auditStatus) filtered = filtered.filter(a => a.auditStatus === auditStatus)
+  if (bizId) filtered = filtered.filter(a => String(a.bizId).includes(bizId))
+  return { code: 200, data: filtered, msg: 'ok' }
+})
+
+// 审核中心 - 详情
+Mock.mock(/\/api\/audit\/detail/, 'get', (options) => {
+  const url = new URL(options.url, 'http://localhost')
+  const id = url.searchParams.get('id')
+  const item = auditList.find(a => a.id === id)
+  return item
+    ? { code: 200, data: item, msg: 'ok' }
+    : { code: 404, data: null, msg: '审核单不存在' }
+})
+
+// 审核中心 - 通过
+Mock.mock(/\/api\/audit\/approve/, 'post', (options) => {
+  const body = JSON.parse(options.body)
+  const idx = auditList.findIndex(a => a.id === body.id)
+  if (idx < 0) return { code: 404, data: null, msg: '审核单不存在' }
+  const audit = auditList[idx]
+  if (audit.auditStatus !== 'pending') return { code: 400, data: null, msg: '该审核单已完成' }
+
+  const eqIdx = equityList.findIndex(e => e.productId === audit.bizId)
+  if (eqIdx < 0) return { code: 404, data: null, msg: '关联权益不存在' }
+  const eq = equityList[eqIdx]
+  const now = nowStr()
+  const auditor = body.auditorName || '王五'
+
+  if (audit.auditType === 'new') {
+    equityList[eqIdx] = { ...eq, shelfStatus: '已上架', auditStatus: '审核通过', reviewer: auditor, reviewTime: now }
+  } else if (audit.auditType === 'change') {
+    // 合并 pendingData 到主表
+    const merged = { ...eq, ...(eq.pendingData || {}) }
+    equityList[eqIdx] = { ...merged, shelfStatus: '已上架', auditStatus: '审核通过', pendingData: null, reviewer: auditor, reviewTime: now }
+  } else if (audit.auditType === 'offshelf') {
+    equityList[eqIdx] = { ...eq, shelfStatus: '未上架', auditStatus: '审核通过', reviewer: auditor, reviewTime: now }
+  }
+
+  auditList[idx] = { ...audit, auditStatus: 'approved', auditorId: 'u099', auditorName: auditor, auditTime: now, auditComment: body.comment || '' }
+  return { code: 200, data: null, msg: '审核通过' }
+})
+
+// 审核中心 - 驳回
+Mock.mock(/\/api\/audit\/reject/, 'post', (options) => {
+  const body = JSON.parse(options.body)
+  const idx = auditList.findIndex(a => a.id === body.id)
+  if (idx < 0) return { code: 404, data: null, msg: '审核单不存在' }
+  const audit = auditList[idx]
+  if (audit.auditStatus !== 'pending') return { code: 400, data: null, msg: '该审核单已完成' }
+
+  const eqIdx = equityList.findIndex(e => e.productId === audit.bizId)
+  if (eqIdx < 0) return { code: 404, data: null, msg: '关联权益不存在' }
+  const eq = equityList[eqIdx]
+  const now = nowStr()
+  const auditor = body.auditorName || '王五'
+
+  // 驳回后权益主表回退到提审前的状态
+  if (audit.auditType === 'new') {
+    equityList[eqIdx] = { ...eq, shelfStatus: '未上架', auditStatus: '草稿' }
+  } else if (audit.auditType === 'change') {
+    equityList[eqIdx] = { ...eq, shelfStatus: '已上架', auditStatus: '审核通过', pendingData: null }
+  } else if (audit.auditType === 'offshelf') {
+    equityList[eqIdx] = { ...eq, shelfStatus: '已上架', auditStatus: '审核通过' }
+  }
+
+  auditList[idx] = { ...audit, auditStatus: 'rejected', auditorId: 'u099', auditorName: auditor, auditTime: now, auditComment: body.comment || '' }
+  return { code: 200, data: null, msg: '已驳回' }
+})
+
 export default Mock

+ 12 - 0
pc/src/router/index.js

@@ -218,6 +218,18 @@ const routes = [
         name: 'CampaignManagement',
         component: () => import('@/views/CampaignManagement.vue'),
         meta: { title: 'Campaign管理' }
+      },
+      {
+        path: 'customization/hsbc/audit',
+        name: 'AuditList',
+        component: () => import('@/views/AuditList.vue'),
+        meta: { title: '权益审核', icon: 'el-icon-finished' }
+      },
+      {
+        path: 'customization/hsbc/audit/:id',
+        name: 'AuditDetail',
+        component: () => import('@/views/AuditDetail.vue'),
+        meta: { title: '审核详情' }
       }
     ]
   },

+ 55 - 7
pc/src/views/AddEquityProduct.vue

@@ -495,10 +495,13 @@
           >上一步</el-button>
         </div>
         <div class="action-center">
-          <template v-if="activeStep === 2">
-            <el-button type="primary" @click="handleSubmit">提交</el-button>
-            <el-button @click="goBack">取消</el-button>
-          </template>
+          <el-button @click="goBack">取消</el-button>
+          <el-button type="primary" plain @click="handleSaveDraft">保存草稿</el-button>
+          <el-button
+            v-if="activeStep === 2"
+            type="primary"
+            @click="handleSubmitAudit"
+          >提交审核</el-button>
         </div>
         <div class="action-right">
           <el-button
@@ -523,6 +526,7 @@
 
 <script>
 import RongshuProductDialog from '@/components/RongshuProductDialog.vue'
+import request from '@/utils/request'
 
 export default {
   name: 'AddEquityProduct',
@@ -617,9 +621,53 @@ export default {
         this.activeStep--
       }
     },
-    handleSubmit() {
-      this.$message.success('权益已创建')
-      this.$router.push('/customization/hsbc/equity-products')
+    buildPayload() {
+      const f = this.form
+      return {
+        equityName: f.equityName,
+        source: f.source,
+        productType: f.productType || '',
+        skuNo: f.skuNo || '',
+        merchantName: f.merchantName || '',
+        subTitle: f.subTitle || '',
+        jumpMethod: f.source === '第三方' ? f.externalJumpMethod : '-',
+        jumpLink: f.source === '第三方' ? f.externalLink : '-',
+        exchangeMethod: f.source === '第三方'
+          ? (f.externalJumpMethod === '有' ? '第三方(详情页跳转)' : '第三方(列表跳转)')
+          : '权益平台',
+        showOnHome: f.showOnHome,
+        showOnAssembly: f.showOnAssembly,
+        assemblyPages: [...(f.assemblyPages || [])]
+      }
+    },
+    handleSaveDraft() {
+      if (!this.form.equityName) {
+        this.$message.warning('请填写权益名称后再保存草稿')
+        return
+      }
+      request.post('/api/equity/save-draft', this.buildPayload()).then(() => {
+        this.$message.success('草稿已保存')
+        this.$router.push('/customization/hsbc/equity-products')
+      }).catch(() => {})
+    },
+    handleSubmitAudit() {
+      if (!this.form.equityName) {
+        this.$message.warning('请填写权益名称后再提交')
+        return
+      }
+      this.$prompt('请填写提交说明(可选)', '提交审核', {
+        confirmButtonText: '提交',
+        cancelButtonText: '取消',
+        inputType: 'textarea',
+        inputPlaceholder: '可填写本次提交的关键变更点',
+        inputValidator: () => true
+      }).then(({ value }) => {
+        const payload = { ...this.buildPayload(), submitReason: value || '' }
+        request.post('/api/equity/submit', payload).then(() => {
+          this.$message.success('已提交审核')
+          this.$router.push('/customization/hsbc/equity-products')
+        }).catch(() => {})
+      }).catch(() => {})
     },
     goBack() {
       this.$router.push('/customization/hsbc/equity-products')

+ 509 - 0
pc/src/views/AuditDetail.vue

@@ -0,0 +1,509 @@
+<template>
+  <div class="audit-detail" v-if="audit">
+    <el-card>
+      <!-- 步骤条 -->
+      <el-steps :active="activeStep" simple style="margin-bottom: 20px;">
+        <el-step title="权益信息" icon="el-icon-info"></el-step>
+        <el-step title="设置规则" icon="el-icon-setting"></el-step>
+        <el-step title="更多设置" icon="el-icon-monitor"></el-step>
+      </el-steps>
+
+      <!-- 步骤 0:权益信息 -->
+      <div v-show="activeStep === 0">
+        <el-card shadow="never" class="section-card">
+          <div slot="header" class="section-title">基本信息</div>
+          <el-form :model="form" label-width="120px" label-position="left">
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item label="权益来源">
+                  <el-radio-group v-model="form.source" disabled>
+                    <el-radio-button label="银行自有"></el-radio-button>
+                    <el-radio-button label="荣数商品"></el-radio-button>
+                    <el-radio-button label="第三方"></el-radio-button>
+                  </el-radio-group>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8" v-if="form.source === '银行自有'">
+                <el-form-item label="权益类型">
+                  <el-radio-group v-model="form.productType" disabled>
+                    <el-radio-button label="券码"></el-radio-button>
+                  </el-radio-group>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8" v-if="form.source === '银行自有'">
+                <el-form-item label="商户名称">
+                  <el-input :value="form.merchantName" readonly></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="8" v-if="form.source === '第三方'">
+                <el-form-item label="外部权益链接">
+                  <el-input :value="form.externalLink" readonly></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8" v-if="form.source === '第三方'">
+                <el-form-item label="是否有详情页">
+                  <el-radio-group v-model="form.externalJumpMethod" disabled>
+                    <el-radio-button label="没有"></el-radio-button>
+                    <el-radio-button label="有"></el-radio-button>
+                  </el-radio-group>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item label="权益名称">
+                  <el-input :value="form.equityName" readonly></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item label="权益副标题">
+                  <el-input :value="form.subTitle" readonly></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8" v-if="form.source === '银行自有'">
+                <el-form-item label="SIP商品编号">
+                  <el-input :value="form.skuNo" readonly></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item label="权益图标">
+                  <div v-if="form.listIcon && form.listIcon.length" class="image-preview">
+                    <img :src="form.listIcon[0]" class="preview-img" />
+                  </div>
+                  <span v-else class="no-data">暂无图片</span>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+
+        <el-card v-if="shouldShowDetailCard" shadow="never" class="section-card">
+          <div slot="header" class="section-title">详情信息</div>
+          <el-form :model="form" label-width="120px" label-position="left">
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item label="权益主图">
+                  <div v-if="form.mainImage && form.mainImage.length" class="image-preview">
+                    <img :src="form.mainImage[0]" class="preview-img" />
+                  </div>
+                  <span v-else class="no-data">暂无图片</span>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="权益介绍">
+                  <el-input :value="form.introduction" type="textarea" :rows="4" readonly></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="权益内容">
+                  <div class="rich-text-view" v-html="form.overview || '暂无内容'"></div>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="权益说明">
+                  <div class="rich-text-view" v-html="form.details || '暂无内容'"></div>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20" v-if="form.source === '银行自有' || form.source === '荣数商品'">
+              <el-col :span="8">
+                <el-form-item label="领取成功按钮">
+                  <el-input :value="form.successButtonText" readonly></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+      </div>
+
+      <!-- 步骤 1:规则 -->
+      <div v-show="activeStep === 1">
+        <el-card shadow="never" class="section-card">
+          <div slot="header" class="section-title">展示规则</div>
+          <el-form :model="form" label-width="120px" label-position="left">
+            <el-form-item label="展示时间限制">
+              <el-switch v-model="form.showTimeEnabled" disabled></el-switch>
+              <template v-if="form.showTimeEnabled">
+                <div class="rule-pane">
+                  <el-input :value="form.showStartTime" readonly style="width: 240px;"></el-input>
+                  <span style="margin: 0 8px;">-</span>
+                  <el-input :value="form.showEndTime" readonly style="width: 240px;"></el-input>
+                </div>
+              </template>
+            </el-form-item>
+            <el-form-item label="展示客群限制">
+              <el-switch v-model="form.showGroupEnabled" disabled></el-switch>
+              <template v-if="form.showGroupEnabled">
+                <div class="rule-pane">
+                  <el-input :value="(form.showGroupTagIds || []).join('、')" readonly></el-input>
+                </div>
+              </template>
+            </el-form-item>
+          </el-form>
+        </el-card>
+
+        <el-card shadow="never" class="section-card">
+          <div slot="header" class="section-title">领取规则</div>
+          <el-form :model="form" label-width="120px" label-position="left">
+            <el-form-item label="领取时间限制">
+              <el-switch v-model="form.claimTimeEnabled" disabled></el-switch>
+              <template v-if="form.claimTimeEnabled">
+                <div class="rule-pane">
+                  <el-input :value="form.claimStartTime" readonly style="width: 240px;"></el-input>
+                  <span style="margin: 0 8px;">-</span>
+                  <el-input :value="form.claimEndTime" readonly style="width: 240px;"></el-input>
+                </div>
+              </template>
+            </el-form-item>
+            <el-form-item label="领取客群限制">
+              <el-switch v-model="form.claimGroupEnabled" disabled></el-switch>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+
+      <!-- 步骤 2:更多设置 -->
+      <div v-show="activeStep === 2">
+        <el-card shadow="never" class="section-card">
+          <div slot="header" class="section-title">显示页面</div>
+          <el-form :model="form" label-width="120px" label-position="left">
+            <el-form-item label="权益首页/列表页">
+              <el-radio-group v-model="form.showOnHome" disabled>
+                <el-radio label="显示">显示</el-radio>
+                <el-radio label="不显示">不显示</el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item label="组装页">
+              <el-radio-group v-model="form.showOnAssembly" disabled>
+                <el-radio label="显示">显示</el-radio>
+                <el-radio label="不显示">不显示</el-radio>
+              </el-radio-group>
+              <div v-if="form.showOnAssembly === '显示'" class="rule-pane">
+                <el-input :value="(form.assemblyPages || []).join(',')" readonly></el-input>
+              </div>
+            </el-form-item>
+          </el-form>
+        </el-card>
+
+        <el-card shadow="never" class="section-card">
+          <div slot="header" class="section-title">分享设置</div>
+          <el-form :model="form" label-width="120px" label-position="left">
+            <el-form-item label="是否支持分享">
+              <el-switch v-model="form.shareEnabled" disabled></el-switch>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+
+      <!-- 步骤导航 -->
+      <div class="step-navigation">
+        <el-button v-if="activeStep > 0" @click="prevStep" icon="el-icon-arrow-left">上一步</el-button>
+        <el-button
+          v-if="activeStep < 2"
+          type="primary"
+          @click="nextStep"
+          style="margin-left: auto;"
+        >下一步<i class="el-icon-arrow-right el-icon--right"></i></el-button>
+      </div>
+
+      <!-- 已审记录 -->
+      <el-card v-if="audit.auditStatus !== 'pending'" shadow="never" class="section-card audit-action-card">
+        <div slot="header" class="section-title">审核记录</div>
+        <el-form label-width="120px" label-position="left">
+          <el-row :gutter="20">
+            <el-col :span="8">
+              <el-form-item label="审核人">
+                <span>{{ audit.auditorName || '-' }}</span>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="审核时间">
+                <span>{{ audit.auditTime || '-' }}</span>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="审核结果">
+                <el-tag :type="auditStatusTag(audit.auditStatus)" size="small">
+                  {{ auditStatusLabel(audit.auditStatus) }}
+                </el-tag>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </el-card>
+
+      <!-- 操作栏 -->
+      <div class="action-bar">
+        <el-button @click="goBack">返回</el-button>
+        <template v-if="audit.auditStatus === 'pending'">
+          <el-button type="danger" @click="handleReject">驳回</el-button>
+          <el-button type="primary" @click="handleApprove">通过</el-button>
+        </template>
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import request from '@/utils/request'
+
+const detailMockMap = {
+  100001: {
+    listIcon: [], mainImage: [],
+    introduction: '权益A 介绍内容示例',
+    overview: '<p>权益内容内容</p>',
+    details: '<p>权益说明内容</p>',
+    successButtonText: '马上去使用',
+    showTimeEnabled: true,
+    showStartTime: '2026-01-01 00:00:00',
+    showEndTime: '2026-12-31 23:59:59',
+    showGroupEnabled: false,
+    showGroupTagIds: [],
+    claimTimeEnabled: true,
+    claimStartTime: '2026-01-01 00:00:00',
+    claimEndTime: '2026-12-31 23:59:59',
+    claimGroupEnabled: false
+  },
+  100002: {
+    externalJumpMethod: '没有', externalLink: '太古地产',
+    listIcon: [], mainImage: [], introduction: '',
+    overview: '', details: '',
+    successButtonText: '',
+    showTimeEnabled: false, showStartTime: '', showEndTime: '',
+    showGroupEnabled: true, showGroupTagIds: ['客群A'],
+    claimTimeEnabled: true,
+    claimStartTime: '2026-02-01 00:00:00',
+    claimEndTime: '2026-11-30 23:59:59',
+    claimGroupEnabled: true
+  },
+  100003: {
+    externalJumpMethod: '有', externalLink: '龙腾',
+    listIcon: [], mainImage: [],
+    introduction: '权益C 介绍内容示例',
+    overview: '<p>外部详情页权益内容</p>',
+    details: '<p>外部详情页权益说明</p>',
+    showTimeEnabled: false,
+    claimTimeEnabled: false,
+    claimGroupEnabled: false
+  },
+  100004: {
+    externalJumpMethod: '有', externalLink: 'h5链接',
+    listIcon: [], mainImage: [],
+    introduction: '权益D 介绍内容示例',
+    overview: '<p>自定义链接权益内容</p>',
+    details: '<p>自定义链接权益说明</p>',
+    showTimeEnabled: false,
+    claimTimeEnabled: false,
+    claimGroupEnabled: false
+  }
+}
+
+export default {
+  name: 'AuditDetail',
+  data() {
+    return {
+      audit: null,
+      activeStep: 0,
+      form: {
+        source: '银行自有',
+        productType: '',
+        externalJumpMethod: '',
+        externalLink: '',
+        equityName: '',
+        subTitle: '',
+        skuNo: '',
+        merchantName: '',
+        listIcon: [],
+        mainImage: [],
+        introduction: '',
+        overview: '',
+        details: '',
+        successButtonText: '',
+        showTimeEnabled: false,
+        showStartTime: '',
+        showEndTime: '',
+        showGroupEnabled: false,
+        showGroupTagIds: [],
+        claimTimeEnabled: false,
+        claimStartTime: '',
+        claimEndTime: '',
+        claimGroupEnabled: false,
+        showOnHome: '不显示',
+        showOnAssembly: '不显示',
+        assemblyPages: [],
+        shareEnabled: false
+      }
+    }
+  },
+  computed: {
+    shouldShowDetailCard() {
+      const s = this.form.source
+      if (s === '银行自有' || s === '荣数商品') return true
+      if (s === '第三方' && this.form.externalJumpMethod === '有') return true
+      return false
+    }
+  },
+  created() {
+    this.loadAudit()
+  },
+  methods: {
+    loadAudit() {
+      const id = this.$route.params.id
+      request.get(`/api/audit/detail?id=${id}`).then(res => {
+        this.audit = res.data
+        if (this.audit) this.populateForm()
+      }).catch(() => {})
+    },
+    populateForm() {
+      const bizId = this.audit.bizId
+      // 1) 先用 mockMap 填充丰富的详情字段
+      if (detailMockMap[bizId]) {
+        Object.assign(this.form, detailMockMap[bizId])
+      }
+      // 2) 用 audit snapshot 覆盖(变更类型时会包含最新内容)
+      Object.assign(this.form, this.audit.snapshot || {})
+      // 3) 推导第三方相关字段
+      if (this.form.source === '第三方') {
+        if (this.form.jumpLink && !this.form.externalLink) this.form.externalLink = this.form.jumpLink
+        if (this.form.jumpMethod && !this.form.externalJumpMethod) {
+          this.form.externalJumpMethod = this.form.jumpMethod
+        }
+      }
+    },
+    auditTypeLabel(t) {
+      return { new: '新增', change: '变更', offshelf: '下架' }[t] || t
+    },
+    auditTypeTag(t) {
+      return { new: 'success', change: '', offshelf: 'danger' }[t] || ''
+    },
+    auditStatusLabel(s) {
+      return { pending: '待审核', approved: '已通过', rejected: '已驳回' }[s] || s
+    },
+    auditStatusTag(s) {
+      return { pending: 'warning', approved: 'success', rejected: 'danger' }[s] || ''
+    },
+    nextStep() { if (this.activeStep < 2) this.activeStep++ },
+    prevStep() { if (this.activeStep > 0) this.activeStep-- },
+    handleApprove() {
+      this.$confirm('确定通过该审核单吗?', '提示', {
+        confirmButtonText: '通过',
+        cancelButtonText: '取消',
+        type: 'success'
+      }).then(() => {
+        request.post('/api/audit/approve', { id: this.audit.id }).then(() => {
+          this.$message.success('审核通过')
+          this.$router.push('/customization/hsbc/audit')
+        }).catch(() => {})
+      }).catch(() => {})
+    },
+    handleReject() {
+      this.$confirm('确定驳回该审核单吗?', '提示', {
+        confirmButtonText: '驳回',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        request.post('/api/audit/reject', { id: this.audit.id }).then(() => {
+          this.$message.success('已驳回')
+          this.$router.push('/customization/hsbc/audit')
+        }).catch(() => {})
+      }).catch(() => {})
+    },
+    goBack() {
+      this.$router.push('/customization/hsbc/audit')
+    }
+  }
+}
+</script>
+
+<style scoped>
+.audit-detail {
+  padding: 0;
+}
+.header-bar {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.header-left .title {
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+}
+.section-card {
+  margin-bottom: 16px;
+  border: none;
+}
+.section-card >>> .el-card__header {
+  padding: 12px 20px;
+  background: #fafafa;
+  border-bottom: 1px solid #ebeef5;
+}
+.section-title {
+  font-size: 14px;
+  font-weight: 600;
+  color: #303133;
+}
+.offshelf-reason {
+  color: #f56c6c;
+  font-weight: 500;
+}
+.rule-pane {
+  display: flex;
+  align-items: center;
+  width: 600px;
+  background: #f1f2f5;
+  padding: 12px 20px;
+  margin-top: 10px;
+}
+.image-preview {
+  width: 80px;
+  height: 80px;
+  border: 1px solid #d9d9d9;
+  border-radius: 4px;
+  overflow: hidden;
+}
+.preview-img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+.no-data {
+  color: #c0c4cc;
+  font-size: 13px;
+}
+.rich-text-view {
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 8px 12px;
+  min-height: 80px;
+  font-size: 14px;
+  color: #606266;
+  line-height: 1.6;
+}
+.step-navigation {
+  display: flex;
+  justify-content: space-between;
+  margin-top: 20px;
+  padding-top: 20px;
+  border-top: 1px solid #ebeef5;
+}
+.audit-action-card {
+  margin-top: 8px;
+}
+.action-bar {
+  display: flex;
+  justify-content: center;
+  gap: 12px;
+  margin-top: 20px;
+  padding-top: 20px;
+  border-top: 1px solid #ebeef5;
+}
+</style>

+ 167 - 0
pc/src/views/AuditList.vue

@@ -0,0 +1,167 @@
+<template>
+  <div class="audit-list">
+    <el-card>
+      <el-tabs v-model="activeTab" @tab-click="loadData">
+        <el-tab-pane label="待审核" name="pending"></el-tab-pane>
+        <el-tab-pane label="审核通过" name="approved"></el-tab-pane>
+        <el-tab-pane label="审核驳回" name="rejected"></el-tab-pane>
+      </el-tabs>
+      <div class="search-section">
+        <div class="search-row">
+          <el-form :model="searchForm" label-width="80px" inline>
+            <el-form-item label="权益编号:">
+              <el-input v-model="searchForm.bizId" placeholder="请输入" style="width: 150px"></el-input>
+            </el-form-item>
+            <div class="button-group" style="margin-left: 20px;">
+              <el-button type="primary" @click="loadData">查询</el-button>
+              <el-button @click="handleReset">重置</el-button>
+            </div>
+          </el-form>
+        </div>
+      </div>
+
+      <el-table :data="tableData" stripe style="width: 100%">
+        <el-table-column label="操作" min-width="140" fixed="left">
+          <template slot-scope="scope">
+            <el-button
+              v-if="activeTab === 'pending'"
+              type="text"
+              size="small"
+              @click="goDetail(scope.row.id)"
+            >审批</el-button>
+            <el-button
+              v-else
+              type="text"
+              size="small"
+              @click="goDetail(scope.row.id)"
+            >查看</el-button>
+          </template>
+        </el-table-column>
+        <el-table-column prop="bizName" label="权益名称" min-width="140" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="bizId" label="权益编号" min-width="140"></el-table-column>
+        <el-table-column label="审核类型" min-width="140">
+          <template slot-scope="scope">
+            <el-tag :type="auditTypeTag(scope.row.auditType)" size="small">
+              {{ auditTypeLabel(scope.row.auditType) }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="bizModuleName" label="业务模块" min-width="140"></el-table-column>
+        <el-table-column prop="submitterName" label="提交人" min-width="140"></el-table-column>
+        <el-table-column prop="submitTime" label="提交时间" min-width="180"></el-table-column>
+        <el-table-column prop="auditorName" label="审核人" min-width="140">
+          <template slot-scope="scope">
+            <span>{{ scope.row.auditorName || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="auditTime" label="审核时间" min-width="180">
+          <template slot-scope="scope">
+            <span>{{ scope.row.auditTime || '-' }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="pagination-section">
+        <span>Total {{ tableData.length }}</span>
+        <el-pagination
+          layout="prev, pager, next, sizes, jumper"
+          :page-size="100"
+          :page-sizes="[100, 200, 500]"
+          :total="tableData.length"
+        ></el-pagination>
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import request from '@/utils/request'
+
+export default {
+  name: 'AuditList',
+  data() {
+    return {
+      activeTab: 'pending',
+      searchForm: {
+        bizId: ''
+      },
+      tableData: []
+    }
+  },
+  created() {
+    this.loadData()
+  },
+  activated() {
+    this.loadData()
+  },
+  watch: {
+    $route(to) {
+      if (to.path === '/customization/hsbc/audit') {
+        this.loadData()
+      }
+    }
+  },
+  methods: {
+    loadData() {
+      const params = new URLSearchParams()
+      params.append('auditStatus', this.activeTab)
+      if (this.searchForm.bizId) params.append('bizId', this.searchForm.bizId)
+      request.get('/api/audit/list?' + params.toString()).then(res => {
+        this.tableData = res.data || []
+      }).catch(() => {})
+    },
+    handleReset() {
+      this.searchForm = { bizId: '' }
+      this.loadData()
+    },
+    auditTypeLabel(t) {
+      return { new: '新增', change: '变更', offshelf: '下架' }[t] || t
+    },
+    auditTypeTag(t) {
+      return { new: 'success', change: '', offshelf: 'danger' }[t] || ''
+    },
+    auditStatusLabel(s) {
+      return { pending: '待审核', approved: '已通过', rejected: '已驳回' }[s] || s
+    },
+    auditStatusTag(s) {
+      return { pending: 'warning', approved: 'success', rejected: 'danger' }[s] || ''
+    },
+    goDetail(id) {
+      this.$router.push(`/customization/hsbc/audit/${id}`)
+    }
+  }
+}
+</script>
+
+<style scoped>
+.audit-list {
+  padding: 0;
+}
+.search-section {
+  display: flex;
+  flex-direction: column;
+}
+.search-row {
+  margin-bottom: 0;
+}
+.search-row .el-form {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 0;
+}
+.search-row .el-form-item {
+  margin-right: 0;
+  margin-bottom: 8px;
+}
+.button-group {
+  display: flex;
+  gap: 5px;
+}
+.pagination-section {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  gap: 20px;
+  margin-top: 20px;
+}
+</style>

+ 78 - 8
pc/src/views/EditEquityProduct.vue

@@ -492,10 +492,18 @@
           >上一步</el-button>
         </div>
         <div class="action-center">
-          <template v-if="activeStep === 2">
-            <el-button type="primary" @click="handleSubmit">保存</el-button>
-            <el-button @click="goBack">取消</el-button>
-          </template>
+          <el-button @click="goBack">取消</el-button>
+          <el-button
+            v-if="currentAuditStatus === '草稿'"
+            type="primary"
+            plain
+            @click="handleSaveDraft"
+          >保存草稿</el-button>
+          <el-button
+            v-if="activeStep === 2"
+            type="primary"
+            @click="handleSubmitAudit"
+          >提交审核</el-button>
         </div>
         <div class="action-right">
           <el-button
@@ -520,6 +528,7 @@
 
 <script>
 import RongshuProductDialog from '@/components/RongshuProductDialog.vue'
+import request from '@/utils/request'
 
 export default {
   name: 'EditEquityProduct',
@@ -530,6 +539,8 @@ export default {
       rongshuDialogVisible: false,
       previewVisible: false,
       previewImageUrl: '',
+      currentShelfStatus: '',
+      currentAuditStatus: '',
       quillOptions: {
         placeholder: '请输入内容...',
         modules: {
@@ -606,8 +617,71 @@ export default {
   },
   created() {
     this.loadData()
+    this.loadStatus()
   },
   methods: {
+    loadStatus() {
+      const id = this.$route.params.id
+      if (!id) return
+      request.get(`/api/equity/detail?id=${id}`).then(res => {
+        if (res.data) {
+          this.currentShelfStatus = res.data.shelfStatus || ''
+          this.currentAuditStatus = res.data.auditStatus || ''
+          // 用 API 返回的核心字段覆盖(保证编辑/已上架的内容是当前线上版本)
+          const fields = ['equityName', 'source', 'productType', 'skuNo', 'merchantName', 'subTitle']
+          fields.forEach(k => {
+            if (res.data[k] !== undefined && res.data[k] !== null && res.data[k] !== '') {
+              this.$set(this.form, k, res.data[k])
+            }
+          })
+          this.form.productId = id
+        }
+      }).catch(() => {})
+    },
+    buildPayload() {
+      const f = this.form
+      return {
+        productId: f.productId || this.$route.params.id,
+        equityName: f.equityName,
+        source: f.source,
+        productType: f.productType || '',
+        skuNo: f.skuNo || '',
+        merchantName: f.merchantName || '',
+        subTitle: f.subTitle || '',
+        jumpMethod: f.source === '第三方' ? f.externalJumpMethod : '-',
+        jumpLink: f.source === '第三方' ? f.externalLink : '-',
+        exchangeMethod: f.source === '第三方'
+          ? (f.externalJumpMethod === '有' ? '第三方(详情页跳转)' : '第三方(列表跳转)')
+          : '权益平台',
+        showOnHome: f.showOnHome,
+        showOnAssembly: f.showOnAssembly,
+        assemblyPages: [...(f.assemblyPages || [])]
+      }
+    },
+    handleSaveDraft() {
+      request.post('/api/equity/save-draft', this.buildPayload()).then(() => {
+        this.$message.success('草稿已保存')
+        this.$router.push('/customization/hsbc/equity-products')
+      }).catch(() => {})
+    },
+    handleSubmitAudit() {
+      const tip = this.currentShelfStatus === '已上架'
+        ? '提交变更审核后,移动端仍展示当前线上版本,待审核通过后变更生效。'
+        : '提交后将进入审核流程,期间不可再编辑。'
+      this.$prompt(tip + '\n请填写提交说明(可选)', '提交审核', {
+        confirmButtonText: '提交',
+        cancelButtonText: '取消',
+        inputType: 'textarea',
+        inputPlaceholder: '可填写本次提交的关键变更点',
+        inputValidator: () => true
+      }).then(({ value }) => {
+        const payload = { ...this.buildPayload(), submitReason: value || '' }
+        request.post('/api/equity/submit', payload).then(() => {
+          this.$message.success('已提交审核')
+          this.$router.push('/customization/hsbc/equity-products')
+        }).catch(() => {})
+      }).catch(() => {})
+    },
     loadData() {
       const id = this.$route.params.id
       const mockMap = {
@@ -753,10 +827,6 @@ export default {
         this.activeStep--
       }
     },
-    handleSubmit() {
-      this.$message.success('保存成功')
-      this.$router.push('/customization/hsbc/equity-products')
-    },
     goBack() {
       this.$router.push('/customization/hsbc/equity-products')
     },

+ 139 - 232
pc/src/views/EquityProducts.vue

@@ -11,18 +11,23 @@
             <el-form-item label="权益编号:">
               <el-input v-model="searchForm.productId" placeholder="请输入" style="width: 150px"></el-input>
             </el-form-item>
-            <el-form-item label="状态:">
-              <el-select v-model="searchForm.reviewStatus" placeholder="全部" clearable style="width: 150px">
-                <el-option
-                  v-for="opt in statusOptions"
-                  :key="opt"
-                  :label="opt"
-                  :value="opt"
-                />
+            <el-form-item label="商品状态:">
+              <el-select v-model="searchForm.shelfStatus" placeholder="全部" clearable style="width: 130px">
+                <el-option label="未上架" value="未上架"></el-option>
+                <el-option label="已上架" value="已上架"></el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item label="审核状态:">
+              <el-select v-model="searchForm.auditStatus" placeholder="全部" clearable style="width: 150px">
+                <el-option label="草稿" value="草稿"></el-option>
+                <el-option label="上架待审核" value="上架待审核"></el-option>
+                <el-option label="编辑待审核" value="编辑待审核"></el-option>
+                <el-option label="下架待审核" value="下架待审核"></el-option>
+                <el-option label="审核通过" value="审核通过"></el-option>
               </el-select>
             </el-form-item>
             <div class="button-group" style="margin-left: 20px;">
-              <el-button type="primary" @click="handleSearch">查询</el-button>
+              <el-button type="primary" @click="loadData">查询</el-button>
               <el-button @click="handleReset">重置</el-button>
             </div>
           </el-form>
@@ -33,22 +38,21 @@
       </div>
 
       <!-- 表格区域 -->
-      <el-table :data="filteredTableData" stripe style="width: 100%">
+      <el-table :data="tableData" stripe style="width: 100%">
         <el-table-column label="操作" width="240" fixed="left">
           <template slot-scope="scope">
             <el-button type="text" size="small" @click="handleView(scope.row)">查看</el-button>
-            <el-button type="text" size="small" @click="handleEdit(scope.row)">编辑</el-button>
-              <el-button
-                v-if="scope.row.reviewStatus === '待审核'"
-                type="text"
-                size="small"
-                @click="handleAudit(scope.row)"
-              >审核</el-button>
             <el-button
-              v-if="scope.row.reviewStatus === '审核通过' || scope.row.reviewStatus === '已上架'"
+              v-if="canEdit(scope.row)"
+              type="text"
+              size="small"
+              @click="handleEdit(scope.row)"
+            >编辑</el-button>
+            <el-button
+              v-if="canRequestOffshelf(scope.row)"
               type="text"
               size="small"
-              @click="handleOffline(scope.row)"
+              @click="handleOffshelf(scope.row)"
             >下架</el-button>
             <el-popover
               placement="bottom"
@@ -100,22 +104,24 @@
                   @click="handleManageCouponsFromMore(scope.row, scope.$index)"
                 >券码管理</div>
                 <div
-                  v-if="scope.row.reviewStatus === '已下架'"
+                  v-if="canDelete(scope.row)"
                   class="more-actions-item more-actions-item-danger"
-                  @click="handleDelete(scope.row, scope.$index)"
+                  @click="handleDeleteFromMore(scope.row, scope.$index)"
                 >删除</div>
               </div>
               <el-button slot="reference" type="text" size="small" icon="el-icon-more" style="margin-left: 8px;"></el-button>
             </el-popover>
           </template>
         </el-table-column>
-        <el-table-column prop="equityName" label="权益名称" width="120"></el-table-column>
-        <el-table-column label="状态" width="100">
+        <el-table-column prop="equityName" label="权益名称" width="140" show-overflow-tooltip></el-table-column>
+        <el-table-column label="商品状态" width="100">
           <template slot-scope="scope">
-            <el-tag
-              :type="getStatusType(scope.row.reviewStatus)"
-              size="small"
-            >{{ scope.row.reviewStatus }}</el-tag>
+            <el-tag :type="getShelfTagType(scope.row.shelfStatus)" size="small">{{ scope.row.shelfStatus }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="审核状态" width="120">
+          <template slot-scope="scope">
+            <el-tag :type="getAuditTagType(scope.row.auditStatus)" size="small">{{ scope.row.auditStatus }}</el-tag>
           </template>
         </el-table-column>
         <el-table-column prop="source" label="权益来源" width="100"></el-table-column>
@@ -136,17 +142,11 @@
           </template>
         </el-table-column>
         <el-table-column prop="creator" label="创建人" width="100"></el-table-column>
-        <el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
+        <el-table-column prop="createTime" label="创建时间" width="170"></el-table-column>
         <el-table-column prop="reviewer" label="审核人" width="100"></el-table-column>
-        <el-table-column prop="reviewTime" label="审核时间" width="180"></el-table-column>
+        <el-table-column prop="reviewTime" label="审核时间" width="170"></el-table-column>
       </el-table>
 
-      <show-pages-dialog
-        :visible.sync="showPagesDialogVisible"
-        :row="showPagesRow"
-        @confirm="onShowPagesConfirm"
-      ></show-pages-dialog>
-
       <equity-link-dialog
         :visible.sync="linkDialogVisible"
         :id="linkTargetId"
@@ -156,151 +156,127 @@
 
       <!-- 分页 -->
       <div class="pagination-section">
-        <span>Total 1000</span>
+        <span>Total {{ tableData.length }}</span>
         <el-pagination
           layout="prev, pager, next, sizes, jumper"
           :page-size="100"
           :page-sizes="[100, 200, 500]"
-          :total="1000"
+          :total="tableData.length"
         ></el-pagination>
       </div>
     </el-card>
+
   </div>
 </template>
 
 <script>
-import ShowPagesDialog from '@/components/ShowPagesDialog.vue'
+import request from '@/utils/request'
 import EquityLinkDialog from '@/components/EquityLinkDialog.vue'
 
 export default {
   name: 'EquityProducts',
-  components: { ShowPagesDialog, EquityLinkDialog },
+  components: { EquityLinkDialog },
   data() {
     return {
       searchForm: {
         equityName: '',
         productId: '',
-        reviewStatus: ''
+        shelfStatus: '',
+        auditStatus: ''
       },
-      statusOptions: ['待审核', '已上架', '审核拒绝', '已下架'],
+      tableData: [],
       adjustOrderPosition: 1,
-      showPagesDialogVisible: false,
-      showPagesRow: null,
       linkDialogVisible: false,
-      linkTargetId: '',
-      tableData: [
-        {
-          equityName: '权益A',
-          reviewStatus: '待审核',
-          source: '银行自有',
-          jumpMethod: '-',
-          jumpLink: '-',
-          exchangeMethod: '权益平台',
-          productId: '100001',
-          skuNo: 'SKU001',
-          merchantName: '商户A',
-          productType: '券码',
-          creator: '李运营',
-          createTime: '2026-04-10 09:32:15',
-          reviewer: '',
-          reviewTime: ''
-        },
-        {
-          equityName: '权益B',
-          reviewStatus: '待审核',
-          source: '第三方',
-          jumpMethod: '没有',
-          jumpLink: '太古地产',
-          exchangeMethod: '第三方(列表跳转)',
-          productId: '100002',
-          skuNo: 'SKU002',
-          merchantName: '商户B',
-          creator: '王运营',
-          createTime: '2026-04-12 14:08:42',
-          reviewer: '张三',
-          reviewTime: '2026-04-15 10:30:00'
-        },
-        {
-          equityName: '权益C',
-          reviewStatus: '已上架',
-          source: '第三方',
-          jumpMethod: '有',
-          jumpLink: '龙腾',
-          exchangeMethod: '第三方(详情页跳转)',
-          productId: '100003',
-          skuNo: 'SKU003',
-          merchantName: '商户C',
-          creator: '李运营',
-          createTime: '2026-04-08 11:20:05',
-          reviewer: '王五',
-          reviewTime: '2026-04-14 16:45:00'
-        },
-        {
-          equityName: '权益D',
-          reviewStatus: '审核拒绝',
-          source: '第三方',
-          jumpMethod: '有',
-          jumpLink: 'h5链接',
-          exchangeMethod: '第三方(详情页跳转)',
-          productId: '100004',
-          skuNo: 'SKU004',
-          merchantName: '商户D',
-          creator: '陈运营',
-          createTime: '2026-04-05 15:50:18',
-          reviewer: '赵六',
-          reviewTime: '2026-04-13 09:15:00'
-        },
-        {
-          equityName: '权益E',
-          reviewStatus: '已下架',
-          source: '银行自有',
-          jumpMethod: '-',
-          jumpLink: '-',
-          exchangeMethod: '权益平台',
-          productId: '100005',
-          skuNo: 'SKU005',
-          merchantName: '商户E',
-          productType: '券码',
-          creator: '王运营',
-          createTime: '2026-03-28 09:00:11',
-          reviewer: '钱七',
-          reviewTime: '2026-04-12 11:20:00'
-        }
-      ]
+      linkTargetId: ''
     }
   },
-  computed: {
-    visiblePages() {
-      return row => {
-        const pages = []
-        if (row.showOnHome === '显示') pages.push("权益首页/列表页")
-        if (row.showOnAssembly === '显示' && Array.isArray(row.assemblyPages)) {
-          pages.push(...row.assemblyPages)
-        }
-        return pages
+  created() {
+    this.loadData()
+  },
+  activated() {
+    this.loadData()
+  },
+  watch: {
+    $route(to) {
+      if (to.path === '/customization/hsbc/equity-products') {
+        this.loadData()
       }
-    },
-    filteredTableData() {
-      return this.tableData.filter(row => {
-        const f = this.searchForm
-        if (f.equityName && !row.equityName.includes(f.equityName)) return false
-        if (f.productId && !row.productId.includes(f.productId)) return false
-        if (f.reviewStatus && row.reviewStatus !== f.reviewStatus) return false
-        return true
-      })
     }
   },
   methods: {
-    handleSearch() {
-      this.$message.success('已搜索')
+    loadData() {
+      const params = new URLSearchParams()
+      if (this.searchForm.equityName) params.append('equityName', this.searchForm.equityName)
+      if (this.searchForm.productId) params.append('productId', this.searchForm.productId)
+      if (this.searchForm.shelfStatus) params.append('shelfStatus', this.searchForm.shelfStatus)
+      if (this.searchForm.auditStatus) params.append('auditStatus', this.searchForm.auditStatus)
+      const qs = params.toString()
+      request.get('/api/equity/list' + (qs ? `?${qs}` : '')).then(res => {
+        this.tableData = res.data || []
+      }).catch(() => {})
     },
     handleReset() {
-      this.searchForm = {
-        equityName: '',
-        productId: '',
-        reviewStatus: ''
+      this.searchForm = { equityName: '', productId: '', shelfStatus: '', auditStatus: '' }
+      this.loadData()
+    },
+    // 按钮可见性
+    canEdit(row) {
+      return (row.shelfStatus === '未上架' && row.auditStatus === '草稿') ||
+             (row.shelfStatus === '已上架' && row.auditStatus === '审核通过')
+    },
+    canRequestOffshelf(row) {
+      return row.shelfStatus === '已上架' && row.auditStatus === '审核通过'
+    },
+    canDelete(row) {
+      return row.shelfStatus === '未上架' && (row.auditStatus === '草稿' || row.auditStatus === '审核通过')
+    },
+    // Tag 样式
+    getShelfTagType(s) {
+      if (s === '已上架') return 'success'
+      return 'info'
+    },
+    getAuditTagType(s) {
+      if (s === '审核通过') return 'success'
+      if (s === '草稿') return 'info'
+      if (s === '上架待审核') return ''
+      if (s === '编辑待审核') return 'warning'
+      if (s === '下架待审核') return 'danger'
+      return ''
+    },
+    visiblePages(row) {
+      const pages = []
+      if (row.showOnHome === '显示') pages.push('权益首页/列表页')
+      if (row.showOnAssembly === '显示' && Array.isArray(row.assemblyPages)) {
+        pages.push(...row.assemblyPages)
       }
+      return pages
+    },
+    // 路由跳转
+    createProduct() {
+      this.$router.push('/customization/hsbc/equity-products/add')
+    },
+    handleView(row) {
+      this.$router.push(`/customization/hsbc/equity-products/view/${row.productId}`)
+    },
+    handleEdit(row) {
+      this.$router.push(`/customization/hsbc/equity-products/edit/${row.productId}`)
     },
+    // 下架(提交下架审核)
+    handleOffshelf(row) {
+      this.$confirm(`确定提交"${row.equityName}"的下架审核吗?审核通过后才会下架。`, '提示', {
+        confirmButtonText: '提交',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        request.post('/api/equity/request-offshelf', {
+          productId: row.productId
+        }).then(() => {
+          this.$message.success('已提交下架审核')
+          this.loadData()
+        }).catch(() => {})
+      }).catch(() => {})
+    },
+    // popover 工具方法
     getPopoverInstance(name) {
       const ref = this.$refs[name]
       if (!ref) return null
@@ -309,19 +285,13 @@ export default {
     onAdjustOrderShow(index) {
       this.adjustOrderPosition = index + 1
       const moreRef = this.getPopoverInstance(`morePopover-${index}`)
-      if (moreRef) {
-        moreRef.doClose()
-      }
+      if (moreRef) moreRef.doClose()
     },
     closeAdjustOrder(index) {
       const adjustRef = this.getPopoverInstance(`adjustPopover-${index}`)
-      if (adjustRef) {
-        adjustRef.doClose()
-      }
+      if (adjustRef) adjustRef.doClose()
       const moreRef = this.getPopoverInstance(`morePopover-${index}`)
-      if (moreRef) {
-        moreRef.doClose()
-      }
+      if (moreRef) moreRef.doClose()
     },
     confirmAdjustOrder(index) {
       const target = Number(this.adjustOrderPosition)
@@ -337,101 +307,38 @@ export default {
       this.$message.success('顺序已调整')
       this.closeAdjustOrder(index)
     },
-    createProduct() {
-      this.$router.push('/customization/hsbc/equity-products/add')
-    },
-    handleView(row) {
-      this.$router.push(`/customization/hsbc/equity-products/view/${row.productId}`)
-    },
-    handleEdit(row) {
-      this.$router.push(`/customization/hsbc/equity-products/edit/${row.productId}`)
-    },
-    handleAudit(row) {
-      this.$router.push(`/customization/hsbc/equity-products/audit/${row.productId}`)
-    },
     showLinkDialog(row) {
       this.linkTargetId = row.productId
       this.linkDialogVisible = true
     },
     openLinkDialogFromMore(row, index) {
       const moreRef = this.getPopoverInstance(`morePopover-${index}`)
-      if (moreRef) {
-        moreRef.doClose()
-      }
+      if (moreRef) moreRef.doClose()
       this.showLinkDialog(row)
     },
-    handleManageCoupons() {
-      window.open('https://uat.leagpoint.com/sipAdmin/coupon/inboundCouponList', '_blank')
-    },
     handleManageCouponsFromMore(row, index) {
       const moreRef = this.getPopoverInstance(`morePopover-${index}`)
-      if (moreRef) {
-        moreRef.doClose()
-      }
-      this.handleManageCoupons(row)
-    },
-    handleImportCoupons() {
-      window.open('https://uat.leagpoint.com/sipAdmin/coupon/importCoupon', '_blank')
+      if (moreRef) moreRef.doClose()
+      window.open('https://uat.leagpoint.com/sipAdmin/coupon/inboundCouponList', '_blank')
     },
     handleImportCouponsFromMore(row, index) {
       const moreRef = this.getPopoverInstance(`morePopover-${index}`)
-      if (moreRef) {
-        moreRef.doClose()
-      }
-      this.handleImportCoupons(row)
-    },
-    handleOffline(row) {
-      this.$confirm(`确定要下架权益"${row.equityName}"吗?`, '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(() => {
-        this.$message.success('下架成功')
-      }).catch(() => {})
-    },
-    openShowPagesDialog(row, index) {
-      const moreRef = this.getPopoverInstance(`morePopover-${index}`)
-      if (moreRef) {
-        moreRef.doClose()
-      }
-      this.showPagesRow = row
-      this.showPagesDialogVisible = true
-    },
-    onShowPagesConfirm(values) {
-      if (this.showPagesRow) {
-        this.$set(this.showPagesRow, 'showOnHome', values.showOnHome)
-        this.$set(this.showPagesRow, 'showOnAssembly', values.showOnAssembly)
-        this.$set(this.showPagesRow, 'assemblyPages', [...values.assemblyPages])
-        this.$message.success('显示页面已更新')
-      }
+      if (moreRef) moreRef.doClose()
+      window.open('https://uat.leagpoint.com/sipAdmin/coupon/importCoupon', '_blank')
     },
-    handleDelete(row, index) {
+    handleDeleteFromMore(row, index) {
       const moreRef = this.getPopoverInstance(`morePopover-${index}`)
-      if (moreRef) {
-        moreRef.doClose()
-      }
-      this.$confirm(`确定要删除权益"${row.equityName}"吗?`, '提示', {
-        confirmButtonText: '确定',
+      if (moreRef) moreRef.doClose()
+      this.$confirm(`确定删除权益"${row.equityName}"吗?`, '提示', {
+        confirmButtonText: '删除',
         cancelButtonText: '取消',
         type: 'warning'
       }).then(() => {
-        this.tableData.splice(index, 1)
-        this.$message.success('删除成功')
+        request.post('/api/equity/delete', { productId: row.productId }).then(() => {
+          this.$message.success('删除成功')
+          this.loadData()
+        }).catch(() => {})
       }).catch(() => {})
-    },
-    getStatusType(status) {
-      switch (status) {
-        case '待审核':
-          return 'warning'
-        case '已上架':
-          return 'success'
-        case '审核拒绝':
-          return 'danger'
-        case '已下架':
-          return 'info'
-        default:
-          return ''
-      }
     }
   }
 }

+ 40 - 0
pc/src/views/ViewEquityProduct.vue

@@ -403,6 +403,12 @@
         <div class="action-center">
           <template v-if="activeStep === 2">
             <el-button @click="goBack">返回</el-button>
+            <el-button
+              v-if="canRequestOffshelf"
+              type="danger"
+              plain
+              @click="handleOffshelf"
+            >下架</el-button>
           </template>
         </div>
         <div class="action-right">
@@ -414,15 +420,20 @@
         </div>
       </div>
     </el-card>
+
   </div>
 </template>
 
 <script>
+import request from '@/utils/request'
+
 export default {
   name: 'ViewEquityProduct',
   data() {
     return {
       activeStep: 0,
+      currentShelfStatus: '',
+      currentAuditStatus: '',
       smsTemplateOptions: [
         { id: 'SMS_TPL_001', name: '通用权益支付成功模板', content: '【银行】您购买的${productName}已支付成功,卡号:${exchangeNum},卡密:${exchangePwd},有效期至${expireDate},详情:${qrCodeDownPaths}' },
         { id: 'SMS_TPL_002', name: '券码类短信模板', content: '【银行】尊敬的客户,您的${productName}购买成功,券码为${exchangeNum},请于${expireDate}前使用。' },
@@ -484,10 +495,14 @@ export default {
       if (s === '银行自有' || s === '荣数商品') return true
       if (s === '第三方' && this.form.externalJumpMethod === '有') return true
       return false
+    },
+    canRequestOffshelf() {
+      return this.currentShelfStatus === '已上架' && this.currentAuditStatus === '审核通过'
     }
   },
   created() {
     this.loadData()
+    this.loadStatus()
   },
   methods: {
     loadData() {
@@ -658,6 +673,31 @@ export default {
       }
       return map[action] || 'info'
     },
+    loadStatus() {
+      const id = this.$route.params.id
+      if (!id) return
+      request.get(`/api/equity/detail?id=${id}`).then(res => {
+        if (res.data) {
+          this.currentShelfStatus = res.data.shelfStatus || ''
+          this.currentAuditStatus = res.data.auditStatus || ''
+          if (res.data.equityName) this.form.equityName = res.data.equityName
+        }
+      }).catch(() => {})
+    },
+    handleOffshelf() {
+      this.$confirm(`确定提交"${this.form.equityName}"的下架审核吗?审核通过后才会下架。`, '提示', {
+        confirmButtonText: '提交',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        request.post('/api/equity/request-offshelf', {
+          productId: this.$route.params.id
+        }).then(() => {
+          this.$message.success('已提交下架审核')
+          this.$router.push('/customization/hsbc/equity-products')
+        }).catch(() => {})
+      }).catch(() => {})
+    },
     nextStep() {
       if (this.activeStep < 2) {
         this.activeStep++