AddEquityProduct.vue 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
  1. <template>
  2. <div class="add-equity-product">
  3. <el-card>
  4. <template #header>
  5. <div class="header-title">
  6. <span>添加权益</span>
  7. </div>
  8. </template>
  9. <!-- 步骤条 -->
  10. <el-steps :active="activeStep" simple style="margin-bottom: 20px;">
  11. <el-step title="填写权益信息">
  12. <template #icon><el-icon><InfoFilled /></el-icon></template>
  13. </el-step>
  14. <el-step title="设置规则">
  15. <template #icon><el-icon><Setting /></el-icon></template>
  16. </el-step>
  17. <el-step title="更多设置">
  18. <template #icon><el-icon><Monitor /></el-icon></template>
  19. </el-step>
  20. </el-steps>
  21. <!-- 步骤内容 -->
  22. <div v-show="activeStep === 0">
  23. <!-- 填写权益信息 -->
  24. <el-card shadow="never" class="section-card">
  25. <template #header>
  26. <div class="section-title">基本信息</div>
  27. </template>
  28. <el-form :model="form" label-width="120px" label-position="left">
  29. <el-row :gutter="20">
  30. <el-col :span="8">
  31. <el-form-item label="是否权益平台兑换" required label-width="150px">
  32. <el-radio-group v-model="form.isPlatformExchange" @change="handlePlatformExchangeChange">
  33. <el-radio label="是"></el-radio>
  34. <el-radio label="否"></el-radio>
  35. </el-radio-group>
  36. </el-form-item>
  37. </el-col>
  38. <el-col :span="8" v-if="form.isPlatformExchange === '是'">
  39. <el-form-item label="商品类型" required>
  40. <el-radio-group v-model="form.productType" @change="handleProductTypeChange">
  41. <el-radio label="券码"></el-radio>
  42. <el-radio label="微信立减金"></el-radio>
  43. </el-radio-group>
  44. </el-form-item>
  45. </el-col>
  46. <el-col :span="8" v-if="form.isPlatformExchange === '是' && form.productType === '微信立减金'">
  47. <el-form-item label="选择权益" required>
  48. <el-input
  49. v-model="form.rongshuProduct"
  50. placeholder="请选择权益"
  51. readonly
  52. >
  53. <template #append>
  54. <el-button @click="rongshuDialogVisible = true">选择</el-button>
  55. </template>
  56. </el-input>
  57. </el-form-item>
  58. </el-col>
  59. <el-col :span="8" v-if="form.isPlatformExchange === '是' && form.productType === '微信立减金' && form.rongshuSkuNo">
  60. <el-form-item label="SKU编号">
  61. <el-input v-model="form.rongshuSkuNo" readonly></el-input>
  62. </el-form-item>
  63. </el-col>
  64. </el-row>
  65. <el-row :gutter="20">
  66. <el-col :span="8" v-if="form.isPlatformExchange === '否'">
  67. <el-form-item label="外部权益链接" required>
  68. <el-select v-model="form.externalLink" placeholder="请选择外部权益链接">
  69. <el-option label="太古地产" value="太古地产"></el-option>
  70. <el-option label="龙腾" value="龙腾"></el-option>
  71. <el-option label="h5链接" value="h5链接"></el-option>
  72. <el-option label="小程序链接" value="小程序链接"></el-option>
  73. </el-select>
  74. </el-form-item>
  75. </el-col>
  76. <el-col :span="8" v-if="form.isPlatformExchange === '否' && form.externalLink === 'h5链接'" :gutter="20">
  77. <el-form-item label="h5链接" required>
  78. <el-input v-model="form.customLink" placeholder="请输入h5链接"></el-input>
  79. </el-form-item>
  80. </el-col>
  81. <el-col :span="8" v-if="form.isPlatformExchange === '否'">
  82. <el-form-item required label-width="140px">
  83. <template #label>
  84. <span style="white-space: nowrap;">是否有详情页<el-tooltip content="没有详情页时直接从首页/列表页/组装页直接跳转" placement="top"><el-icon class="tip-icon"><QuestionFilled /></el-icon></el-tooltip></span>
  85. </template>
  86. <el-radio-group v-model="form.externalJumpMethod">
  87. <el-radio-button label="没有"></el-radio-button>
  88. <el-radio-button label="有"></el-radio-button>
  89. </el-radio-group>
  90. </el-form-item>
  91. </el-col>
  92. </el-row>
  93. <el-row :gutter="20" v-if="form.isPlatformExchange === '否' && form.externalLink === '小程序链接'">
  94. <el-col :span="8">
  95. <el-form-item label="小程序appid" required>
  96. <el-input v-model="form.miniAppId" placeholder="请输入小程序appid"></el-input>
  97. </el-form-item>
  98. </el-col>
  99. <el-col :span="8">
  100. <el-form-item label="小程序页面地址" required label-width="140px">
  101. <el-input v-model="form.miniAppPath" placeholder="请输入小程序页面地址"></el-input>
  102. </el-form-item>
  103. </el-col>
  104. </el-row>
  105. <template v-if="form.isPlatformExchange === '是'">
  106. <el-row :gutter="20">
  107. <el-col :span="8">
  108. <el-form-item label="权益名称" required>
  109. <el-input v-model="form.equityName" maxlength="40" placeholder="请输入权益名称"></el-input>
  110. </el-form-item>
  111. </el-col>
  112. </el-row>
  113. <el-row :gutter="20" v-if="form.productType === '微信立减金'">
  114. <el-col :span="8">
  115. <el-form-item label="库存数" required>
  116. <el-input-number
  117. v-model="form.stockCount"
  118. :min="0"
  119. :max="100000"
  120. style="width: 100%"
  121. ></el-input-number>
  122. </el-form-item>
  123. </el-col>
  124. </el-row>
  125. <el-row :gutter="20">
  126. <el-col :span="8">
  127. <el-form-item required>
  128. <template #label>
  129. <span>权益图标
  130. <el-tooltip content="展示在权益首页和权益列表页" placement="top">
  131. <el-icon class="tip-icon"><QuestionFilled /></el-icon>
  132. </el-tooltip>
  133. </span>
  134. </template>
  135. <el-upload
  136. action=""
  137. :auto-upload="false"
  138. :file-list="form.listIcon"
  139. :on-change="file => handleUpload(file, 'listIcon')"
  140. :on-preview="handlePreviewImage"
  141. :on-remove="() => form.listIcon = []"
  142. :class="{ 'upload-hide-trigger': form.listIcon.length >= 1 }"
  143. :limit="1"
  144. list-type="picture-card"
  145. >
  146. <el-icon><Plus /></el-icon>
  147. </el-upload>
  148. <div class="upload-size-tip">建议尺寸:80x80px</div>
  149. </el-form-item>
  150. </el-col>
  151. </el-row>
  152. </template>
  153. <template v-else-if="form.isPlatformExchange === '否'">
  154. <el-row :gutter="20">
  155. <el-col :span="8">
  156. <el-form-item label="权益名称" required>
  157. <el-input v-model="form.equityName" maxlength="40" placeholder="请输入权益名称"></el-input>
  158. </el-form-item>
  159. </el-col>
  160. </el-row>
  161. <el-row :gutter="20" v-if="form.externalJumpMethod === '没有'">
  162. <el-col :span="8">
  163. <el-form-item required>
  164. <template #label>
  165. <span>权益图标
  166. <el-tooltip content="展示在权益首页和权益列表页" placement="top">
  167. <el-icon class="tip-icon"><QuestionFilled /></el-icon>
  168. </el-tooltip>
  169. </span>
  170. </template>
  171. <el-upload
  172. action=""
  173. :auto-upload="false"
  174. :file-list="form.listIcon"
  175. :on-change="file => handleUpload(file, 'listIcon')"
  176. :on-preview="handlePreviewImage"
  177. :on-remove="() => form.listIcon = []"
  178. :class="{ 'upload-hide-trigger': form.listIcon.length >= 1 }"
  179. :limit="1"
  180. list-type="picture-card"
  181. >
  182. <el-icon><Plus /></el-icon>
  183. </el-upload>
  184. <div class="upload-size-tip">建议尺寸:80x80px</div>
  185. </el-form-item>
  186. </el-col>
  187. </el-row>
  188. <el-row v-if="form.externalJumpMethod === '有'" :gutter="20">
  189. <el-col :span="8">
  190. <el-form-item required>
  191. <template #label>
  192. <span>权益图标
  193. <el-tooltip content="展示在权益首页和权益列表页" placement="top">
  194. <el-icon class="tip-icon"><QuestionFilled /></el-icon>
  195. </el-tooltip>
  196. </span>
  197. </template>
  198. <el-upload
  199. action=""
  200. :auto-upload="false"
  201. :file-list="form.listIcon"
  202. :on-change="file => handleUpload(file, 'listIcon')"
  203. :on-preview="handlePreviewImage"
  204. :on-remove="() => form.listIcon = []"
  205. :class="{ 'upload-hide-trigger': form.listIcon.length >= 1 }"
  206. :limit="1"
  207. list-type="picture-card"
  208. >
  209. <el-icon><Plus /></el-icon>
  210. </el-upload>
  211. <div class="upload-size-tip">建议尺寸:80x80px</div>
  212. </el-form-item>
  213. </el-col>
  214. </el-row>
  215. </template>
  216. </el-form>
  217. </el-card>
  218. <!-- 详情信息 -->
  219. <el-card v-if="shouldShowDetailCard" shadow="never" class="section-card">
  220. <template #header>
  221. <div class="section-title">详情信息</div>
  222. </template>
  223. <el-form :model="form" label-width="120px" label-position="left">
  224. <el-row :gutter="20">
  225. <el-col :span="8">
  226. <el-form-item label="权益主图" required>
  227. <el-upload
  228. action=""
  229. :auto-upload="false"
  230. :file-list="form.mainImage"
  231. :on-change="file => handleUpload(file, 'mainImage')"
  232. :on-preview="handlePreviewImage"
  233. :on-remove="() => form.mainImage = []"
  234. :class="{ 'upload-hide-trigger': form.mainImage.length >= 1 }"
  235. :limit="1"
  236. list-type="picture-card"
  237. >
  238. <el-icon><Plus /></el-icon>
  239. </el-upload>
  240. <div class="upload-size-tip">建议尺寸:716x400px</div>
  241. </el-form-item>
  242. </el-col>
  243. </el-row>
  244. <el-row :gutter="20">
  245. <el-col :span="12">
  246. <el-form-item label="权益介绍">
  247. <el-input
  248. v-model="form.introduction"
  249. type="textarea"
  250. :rows="4"
  251. maxlength="500"
  252. show-word-limit
  253. placeholder="请输入权益介绍"
  254. ></el-input>
  255. </el-form-item>
  256. </el-col>
  257. </el-row>
  258. <el-row :gutter="20">
  259. <el-col :span="12">
  260. <el-form-item label="权益有效期" required>
  261. <template v-if="form.isPlatformExchange === '是'">
  262. <el-radio-group v-model="form.validityType">
  263. <el-radio label="fromGrantPlan">取自发放计划</el-radio>
  264. <el-radio label="custom">自定义输入</el-radio>
  265. </el-radio-group>
  266. <el-input
  267. v-if="form.validityType === 'custom'"
  268. v-model="form.validityText"
  269. maxlength="50"
  270. show-word-limit
  271. placeholder="请输入权益有效期"
  272. style="margin-top: 8px;"
  273. ></el-input>
  274. </template>
  275. <el-input
  276. v-else
  277. v-model="form.validityText"
  278. maxlength="50"
  279. show-word-limit
  280. placeholder="请输入权益有效期"
  281. ></el-input>
  282. </el-form-item>
  283. </el-col>
  284. </el-row>
  285. <el-row :gutter="20">
  286. <el-col :span="12">
  287. <el-form-item label="权益内容" required>
  288. <quill-editor v-model:content="form.overview" content-type="html" :options="quillOptions"></quill-editor>
  289. </el-form-item>
  290. </el-col>
  291. <el-col :span="12">
  292. <el-form-item label="权益说明" required>
  293. <quill-editor v-model:content="form.details" content-type="html" :options="quillOptions"></quill-editor>
  294. </el-form-item>
  295. </el-col>
  296. </el-row>
  297. <template v-if="form.isPlatformExchange === '是'">
  298. <el-row :gutter="20">
  299. <el-col :span="24">
  300. <el-form-item>
  301. <template #label>
  302. <span>下单成功短信
  303. <el-tooltip placement="top">
  304. <template #content>
  305. 此模板为权益支付成功,发送给持卡人的短信模板;<br/>
  306. 开启后需选择短信模板,关闭则不发送短信。<br/>
  307. 占位符如下:<br/>
  308. 权益名称:${productName}<br/>
  309. 结束日期:${expireDate}<br/>
  310. 卡号:${exchangeNum}<br/>
  311. 卡密:${exchangePwd}<br/>
  312. 券码使用路径:${qrCodeDownPaths}
  313. </template>
  314. <el-icon class="tip-icon"><QuestionFilled /></el-icon>
  315. </el-tooltip>
  316. </span>
  317. </template>
  318. <el-switch v-model="form.smsEnabled" @change="handleSmsEnabledChange"></el-switch>
  319. <template v-if="form.smsEnabled">
  320. <div style="max-width: 600px;background: #f1f2f5;padding: 20px;margin-top: 10px;flex-basis: 100%;">
  321. <el-select
  322. v-model="form.smsTemplateId"
  323. placeholder="请选择短信模板"
  324. style="width: 100%"
  325. @change="handleSmsTemplateChange"
  326. >
  327. <el-option
  328. v-for="item in smsTemplateOptions"
  329. :key="item.id"
  330. :label="item.name"
  331. :value="item.id"
  332. />
  333. </el-select>
  334. <div v-if="form.smsTemplate" class="sms-template-preview">{{ form.smsTemplate }}</div>
  335. </div>
  336. </template>
  337. </el-form-item>
  338. </el-col>
  339. </el-row>
  340. <el-row :gutter="20" v-if="form.productType === '券码'">
  341. <el-col :span="8">
  342. <el-form-item label="领取成功按钮" required>
  343. <el-input v-model="form.successButtonText" placeholder="请输入按钮文案"></el-input>
  344. </el-form-item>
  345. </el-col>
  346. </el-row>
  347. </template>
  348. </el-form>
  349. </el-card>
  350. </div>
  351. <div v-show="activeStep === 1">
  352. <!-- 展示规则 -->
  353. <el-card shadow="never" class="section-card">
  354. <template #header>
  355. <div class="section-title">展示规则</div>
  356. </template>
  357. <div class="rule-section">
  358. <el-form :model="form" label-width="120px" label-position="left">
  359. <el-form-item label="展示时间限制">
  360. <el-switch v-model="form.showTimeEnabled"></el-switch>
  361. <template v-if="form.showTimeEnabled">
  362. <div style="display: flex;max-width: 600px;background: #f1f2f5;padding: 20px;margin-top: 10px;flex-basis: 100%;">
  363. <el-date-picker
  364. v-model="form.showStartTime"
  365. type="datetime"
  366. placeholder="请选择开始时间"
  367. format="YYYY-MM-DD HH:mm:ss"
  368. value-format="YYYY-MM-DD HH:mm:ss"
  369. style="width: 100%"
  370. ></el-date-picker>
  371. <div style="width: 50px;text-align: center;">-</div>
  372. <el-date-picker
  373. v-model="form.showEndTime"
  374. type="datetime"
  375. placeholder="请选择结束时间"
  376. format="YYYY-MM-DD HH:mm:ss"
  377. value-format="YYYY-MM-DD HH:mm:ss"
  378. style="width: 100%"
  379. ></el-date-picker>
  380. </div>
  381. </template>
  382. </el-form-item>
  383. <el-form-item label="展示客群限制">
  384. <el-switch v-model="form.showGroupEnabled"></el-switch>
  385. <template v-if="form.showGroupEnabled">
  386. <div style="display: flex;max-width: 600px;background: #f1f2f5;padding: 20px;margin-top: 10px;flex-basis: 100%;">
  387. <el-select v-model="form.showGroupTagIds" multiple filterable placeholder="请选择客群" style="width: 100%">
  388. <el-option label="客群A" value="客群A"></el-option>
  389. <el-option label="客群B" value="客群B"></el-option>
  390. <el-option label="客群C" value="客群C"></el-option>
  391. </el-select>
  392. </div>
  393. </template>
  394. </el-form-item>
  395. </el-form>
  396. </div>
  397. </el-card>
  398. <!-- 领取规则 -->
  399. <el-card shadow="never" class="section-card">
  400. <template #header>
  401. <div class="section-title">领取规则</div>
  402. </template>
  403. <div class="rule-section">
  404. <el-form :model="form" label-width="120px" label-position="left">
  405. <el-form-item label="领取时间限制">
  406. <el-switch v-model="form.claimTimeEnabled"></el-switch>
  407. <template v-if="form.claimTimeEnabled">
  408. <div style="display: flex;max-width: 600px;background: #f1f2f5;padding: 20px;margin-top: 10px;flex-basis: 100%;">
  409. <el-date-picker
  410. v-model="form.claimStartTime"
  411. type="datetime"
  412. placeholder="请选择开始时间"
  413. format="YYYY-MM-DD HH:mm:ss"
  414. value-format="YYYY-MM-DD HH:mm:ss"
  415. style="width: 100%"
  416. ></el-date-picker>
  417. <div style="width: 50px;text-align: center;">-</div>
  418. <el-date-picker
  419. v-model="form.claimEndTime"
  420. type="datetime"
  421. placeholder="请选择结束时间"
  422. format="YYYY-MM-DD HH:mm:ss"
  423. value-format="YYYY-MM-DD HH:mm:ss"
  424. style="width: 100%"
  425. ></el-date-picker>
  426. </div>
  427. </template>
  428. </el-form-item>
  429. <el-form-item label="领取客群限制">
  430. <el-switch v-model="form.claimGroupEnabled"></el-switch>
  431. <template v-if="form.claimGroupEnabled">
  432. <div style="max-width: 600px;background: #f1f2f5;padding: 20px;margin-top: 10px;flex-basis: 100%;">
  433. <el-alert
  434. title="需在【发放计划】中选择权益发放,未发放的权益移动端不展示"
  435. type="info"
  436. :closable="false"
  437. show-icon
  438. style="margin-bottom: 12px;"
  439. ></el-alert>
  440. <div style="font-size: 14px;color: #606266;margin-bottom: 8px;font-weight: 500;">不满足提示</div>
  441. <el-form-item label="提示内容" label-width="100px" style="margin-bottom: 12px;">
  442. <el-input v-model="form.claimDenyMessage" maxlength="200" placeholder="请输入提示内容"></el-input>
  443. </el-form-item>
  444. <el-form-item label="跳转按钮文案" label-width="100px" style="margin-bottom: 12px;">
  445. <el-input v-model="form.claimDenyButtonText" maxlength="10" placeholder="请输入按钮文案"></el-input>
  446. </el-form-item>
  447. <el-form-item label="跳转按钮链接" label-width="100px" style="margin-bottom: 0;">
  448. <el-input v-model="form.claimDenyButtonLink" maxlength="200" placeholder="请输入按钮链接"></el-input>
  449. </el-form-item>
  450. </div>
  451. </template>
  452. </el-form-item>
  453. </el-form>
  454. </div>
  455. </el-card>
  456. </div>
  457. <div v-show="activeStep === 2">
  458. <!-- 显示页面 -->
  459. <el-card shadow="never" class="section-card">
  460. <template #header>
  461. <div class="section-title">显示页面</div>
  462. </template>
  463. <el-form :model="form" label-width="120px" label-position="left">
  464. <el-form-item label="权益首页">
  465. <el-radio-group v-model="form.showOnHome">
  466. <el-radio label="显示">显示</el-radio>
  467. <el-radio label="不显示">不显示</el-radio>
  468. </el-radio-group>
  469. </el-form-item>
  470. <el-form-item label="组装页">
  471. <el-radio-group v-model="form.showOnAssembly">
  472. <el-radio label="显示">显示</el-radio>
  473. <el-radio label="不显示">不显示</el-radio>
  474. </el-radio-group>
  475. <div
  476. v-if="form.showOnAssembly === '显示'"
  477. style="max-width: 600px;background: #f1f2f5;padding: 20px;margin-top: 10px;flex-basis: 100%;"
  478. >
  479. <el-select
  480. v-model="form.assemblyPages"
  481. multiple
  482. filterable
  483. placeholder="请选择组装页"
  484. style="width: 100%"
  485. >
  486. <el-option label="组装页A" value="组装页A"></el-option>
  487. <el-option label="组装页B" value="组装页B"></el-option>
  488. <el-option label="组装页C" value="组装页C"></el-option>
  489. <el-option label="组装页D" value="组装页D"></el-option>
  490. </el-select>
  491. </div>
  492. </el-form-item>
  493. </el-form>
  494. </el-card>
  495. <!-- 分享设置 -->
  496. <el-card shadow="never" class="section-card">
  497. <template #header>
  498. <div class="section-title">分享设置</div>
  499. </template>
  500. <el-form :model="form" label-width="120px" label-position="left">
  501. <el-form-item label="是否支持分享">
  502. <el-switch v-model="form.shareEnabled" @change="handleShareEnabledChange"></el-switch>
  503. <template v-if="form.shareEnabled">
  504. <div style="max-width: 600px;background: #f1f2f5;padding: 20px;margin-top: 10px;flex-basis: 100%;">
  505. <el-form-item label="分享名称" label-width="100px" required style="margin-bottom: 16px;">
  506. <el-input
  507. v-model="form.shareName"
  508. maxlength="40"
  509. placeholder="请输入分享名称"
  510. ></el-input>
  511. </el-form-item>
  512. <el-form-item label="分享图片" label-width="100px" required style="margin-bottom: 0;">
  513. <el-upload
  514. action=""
  515. :auto-upload="false"
  516. :file-list="form.shareImage"
  517. :on-change="file => handleUpload(file, 'shareImage')"
  518. :limit="1"
  519. list-type="picture-card"
  520. >
  521. <el-icon><Plus /></el-icon>
  522. </el-upload>
  523. </el-form-item>
  524. </div>
  525. </template>
  526. </el-form-item>
  527. </el-form>
  528. </el-card>
  529. </div>
  530. <!-- 操作栏 -->
  531. <div class="action-bar">
  532. <div class="action-left">
  533. <el-button
  534. v-if="activeStep > 0"
  535. @click="prevStep"
  536. ><el-icon><ArrowLeft /></el-icon>上一步</el-button>
  537. </div>
  538. <div class="action-center">
  539. <el-button @click="goBack">取消</el-button>
  540. <el-button type="primary" plain @click="handleSaveDraft">保存草稿</el-button>
  541. <el-button
  542. v-if="activeStep === 2"
  543. type="primary"
  544. @click="handleSubmitAudit"
  545. >提交审核</el-button>
  546. </div>
  547. <div class="action-right">
  548. <el-button
  549. v-if="activeStep < 2"
  550. type="primary"
  551. @click="nextStep"
  552. >下一步<el-icon class="el-icon--right"><ArrowRight /></el-icon></el-button>
  553. </div>
  554. </div>
  555. </el-card>
  556. <rongshu-product-dialog
  557. v-model="rongshuDialogVisible"
  558. @select="onRongshuSelect"
  559. />
  560. <el-dialog v-model="previewVisible" title="图片预览" width="640px" append-to-body>
  561. <img v-if="previewImageUrl" :src="previewImageUrl" style="display:block; max-width:100%; margin:0 auto;" />
  562. </el-dialog>
  563. </div>
  564. </template>
  565. <script>
  566. import RongshuProductDialog from '@/components/RongshuProductDialog.vue'
  567. import request from '@/utils/request'
  568. import { ElMessage, ElMessageBox } from 'element-plus'
  569. export default {
  570. name: 'AddEquityProduct',
  571. components: { RongshuProductDialog },
  572. data() {
  573. return {
  574. activeStep: 0,
  575. rongshuDialogVisible: false,
  576. previewVisible: false,
  577. previewImageUrl: '',
  578. quillOptions: {
  579. placeholder: '请输入内容...',
  580. modules: {
  581. toolbar: [
  582. ['bold', 'italic', 'underline'],
  583. [{ list: 'ordered' }, { list: 'bullet' }],
  584. [{ header: [1, 2, 3, false] }],
  585. ['link', 'image'],
  586. ['clean']
  587. ]
  588. }
  589. },
  590. smsTemplateOptions: [
  591. { id: 'SMS_TPL_001', name: '通用权益支付成功模板', content: '【银行】您购买的${productName}已支付成功,卡号:${exchangeNum},卡密:${exchangePwd},有效期至${expireDate},详情:${qrCodeDownPaths}' },
  592. { id: 'SMS_TPL_002', name: '券码类短信模板', content: '【银行】尊敬的客户,您的${productName}购买成功,券码为${exchangeNum},请于${expireDate}前使用。' },
  593. { id: 'SMS_TPL_003', name: '实物类短信模板', content: '【银行】您购买的${productName}已受理,我们将尽快安排发货,感谢您的支持。' }
  594. ],
  595. form: {
  596. isPlatformExchange: '是',
  597. source: '银行自有',
  598. rongshuProduct: '',
  599. rongshuSkuNo: '',
  600. productType: '券码',
  601. faceValueThreshold: '',
  602. faceValueDiscount: '',
  603. stockCount: null,
  604. shareEnabled: false,
  605. shareImage: [],
  606. shareName: '',
  607. externalJumpMethod: '没有',
  608. externalLink: '太古地产',
  609. customLink: '',
  610. miniAppId: '',
  611. miniAppPath: '',
  612. equityName: '',
  613. productId: '',
  614. merchantName: '',
  615. listIcon: [],
  616. mainImage: [],
  617. introduction: '',
  618. validityType: 'fromGrantPlan',
  619. validityText: '',
  620. overview: '',
  621. details: '',
  622. smsEnabled: false,
  623. smsTemplateId: '',
  624. smsTemplate: '',
  625. successButtonText: '马上去使用',
  626. showTimeEnabled: false,
  627. showStartTime: '',
  628. showEndTime: '',
  629. showGroupEnabled: false,
  630. showGroupTagIds: [],
  631. claimTimeEnabled: false,
  632. claimStartTime: '',
  633. claimEndTime: '',
  634. claimGroupEnabled: false,
  635. claimGroupIsPotential: false,
  636. claimGroupTagId: '',
  637. claimDenyMessage: '很抱歉,您暂不符合领取条件。',
  638. claimDenyButtonText: '返回',
  639. claimDenyButtonLink: '权益首页',
  640. showOnHome: '显示',
  641. showOnAssembly: '不显示',
  642. assemblyPages: []
  643. }
  644. }
  645. },
  646. computed: {
  647. mappedSource() {
  648. if (this.form.isPlatformExchange === '否') return '第三方'
  649. if (this.form.productType === '微信立减金') return '荣数商品'
  650. return '银行自有'
  651. },
  652. shouldShowDetailCard() {
  653. if (this.form.isPlatformExchange === '是') return true
  654. if (this.form.isPlatformExchange === '否' && this.form.externalJumpMethod === '有') return true
  655. return false
  656. }
  657. },
  658. created() {
  659. const copyFrom = this.$route.query.copyFrom
  660. if (copyFrom) {
  661. this.loadCopySource(copyFrom)
  662. }
  663. },
  664. methods: {
  665. handlePlatformExchangeChange(val) {
  666. if (val === '是') {
  667. this.form.productType = '券码'
  668. this.form.externalLink = '太古地产'
  669. this.form.externalJumpMethod = '没有'
  670. this.form.customLink = ''
  671. this.form.miniAppId = ''
  672. this.form.miniAppPath = ''
  673. } else {
  674. this.form.rongshuProduct = ''
  675. this.form.rongshuSkuNo = ''
  676. this.form.stockCount = null
  677. this.form.merchantName = ''
  678. }
  679. },
  680. handleProductTypeChange(val) {
  681. if (val === '券码') {
  682. this.form.rongshuProduct = ''
  683. this.form.rongshuSkuNo = ''
  684. this.form.stockCount = null
  685. this.form.merchantName = ''
  686. }
  687. },
  688. loadCopySource(id) {
  689. const mockMap = {
  690. 'Q100001': {
  691. source: '银行自有',
  692. isPlatformExchange: '是',
  693. productType: '券码',
  694. externalJumpMethod: '',
  695. externalLink: '',
  696. customLink: '',
  697. miniAppId: '',
  698. miniAppPath: '',
  699. skuNo: 'SKU001',
  700. equityName: '权益A',
  701. listIcon: [],
  702. mainImage: [],
  703. overview: '<p>权益内容内容</p>',
  704. details: '<p>权益说明内容</p>',
  705. smsEnabled: true,
  706. smsTemplateId: 'SMS_TPL_001',
  707. smsTemplate: '【银行】您购买的${productName}已支付成功,卡号:${exchangeNum},卡密:${exchangePwd},有效期至${expireDate},详情:${qrCodeDownPaths}',
  708. successButtonText: '马上去使用',
  709. showTimeEnabled: true,
  710. showStartTime: '2026-01-01 00:00:00',
  711. showEndTime: '2026-12-31 23:59:59',
  712. showGroupEnabled: false,
  713. showGroupTagIds: [],
  714. claimTimeEnabled: true,
  715. claimStartTime: '2026-01-01 00:00:00',
  716. claimEndTime: '2026-12-31 23:59:59',
  717. claimGroupEnabled: false,
  718. claimGroupTagId: '',
  719. claimDenyMessage: '很抱歉,您暂不符合领取条件。',
  720. claimDenyButtonText: '返回',
  721. claimDenyButtonLink: '权益首页'
  722. },
  723. 'Q100002': {
  724. source: '第三方',
  725. isPlatformExchange: '否',
  726. productType: '',
  727. externalJumpMethod: '没有',
  728. externalLink: '太古地产',
  729. customLink: '',
  730. miniAppId: '',
  731. miniAppPath: '',
  732. skuNo: 'SKU002',
  733. equityName: '权益B',
  734. listIcon: [],
  735. mainImage: [],
  736. overview: '',
  737. details: '',
  738. smsEnabled: false,
  739. smsTemplateId: '',
  740. smsTemplate: '',
  741. successButtonText: '',
  742. showTimeEnabled: false,
  743. showStartTime: '',
  744. showEndTime: '',
  745. showGroupEnabled: true,
  746. showGroupTagIds: ['客群A'],
  747. claimTimeEnabled: true,
  748. claimStartTime: '2026-02-01 00:00:00',
  749. claimEndTime: '2026-11-30 23:59:59',
  750. claimGroupEnabled: true,
  751. claimGroupIsPotential: false,
  752. claimGroupTagId: '客群奖励活动A',
  753. claimDenyMessage: '很抱歉,您暂不符合领取条件。',
  754. claimDenyButtonText: '返回',
  755. claimDenyButtonLink: '权益首页'
  756. },
  757. 'Q100003': {
  758. source: '第三方',
  759. isPlatformExchange: '否',
  760. productType: '',
  761. externalJumpMethod: '有',
  762. externalLink: '龙腾',
  763. customLink: '',
  764. miniAppId: '',
  765. miniAppPath: '',
  766. skuNo: 'SKU003',
  767. equityName: '权益C',
  768. listIcon: [],
  769. mainImage: [],
  770. overview: '<p>外部详情页权益内容</p>',
  771. details: '<p>外部详情页权益说明</p>',
  772. smsEnabled: false,
  773. smsTemplateId: '',
  774. smsTemplate: '',
  775. successButtonText: '',
  776. showTimeEnabled: false,
  777. showStartTime: '',
  778. showEndTime: '',
  779. showGroupEnabled: false,
  780. showGroupTagIds: [],
  781. claimTimeEnabled: false,
  782. claimStartTime: '',
  783. claimEndTime: '',
  784. claimGroupEnabled: false,
  785. claimGroupTagId: '',
  786. claimDenyMessage: '很抱歉,您暂不符合领取条件。',
  787. claimDenyButtonText: '返回',
  788. claimDenyButtonLink: '权益首页'
  789. },
  790. 'Q100004': {
  791. source: '第三方',
  792. isPlatformExchange: '否',
  793. productType: '',
  794. externalJumpMethod: '有',
  795. externalLink: 'h5链接',
  796. customLink: 'https://example.com/custom',
  797. skuNo: 'SKU004',
  798. equityName: '权益D',
  799. listIcon: [],
  800. mainImage: [],
  801. overview: '<p>自定义链接权益内容</p>',
  802. details: '<p>自定义链接权益说明</p>',
  803. smsEnabled: false,
  804. smsTemplateId: '',
  805. smsTemplate: '',
  806. successButtonText: '',
  807. showTimeEnabled: false,
  808. showStartTime: '',
  809. showEndTime: '',
  810. showGroupEnabled: false,
  811. showGroupTagIds: [],
  812. claimTimeEnabled: false,
  813. claimStartTime: '',
  814. claimEndTime: '',
  815. claimGroupEnabled: false,
  816. claimGroupTagId: '',
  817. claimDenyMessage: '很抱歉,您暂不符合领取条件。',
  818. claimDenyButtonText: '返回',
  819. claimDenyButtonLink: '权益首页'
  820. }
  821. }
  822. request.get(`/api/equity/detail?id=${id}`).then(res => {
  823. const core = res.data || {}
  824. const rich = mockMap[id] || {}
  825. const merged = { ...rich }
  826. const coreFields = ['equityName', 'source', 'isPlatformExchange', 'productType', 'skuNo', 'merchantName']
  827. coreFields.forEach(k => {
  828. if (core[k] !== undefined && core[k] !== null && core[k] !== '') {
  829. merged[k] = core[k]
  830. }
  831. })
  832. // 根据接口返回的 source 推算 isPlatformExchange 和 productType
  833. if (!merged.isPlatformExchange) {
  834. if (core.source === '第三方') merged.isPlatformExchange = '否'
  835. else merged.isPlatformExchange = '是'
  836. }
  837. if (merged.isPlatformExchange === '是' && !merged.productType) {
  838. merged.productType = core.source === '荣数商品' ? '微信立减金' : '券码'
  839. }
  840. if (merged.isPlatformExchange === '否') {
  841. merged.productType = ''
  842. }
  843. if (merged.isPlatformExchange === '否') {
  844. if (core.jumpMethod) merged.externalJumpMethod = core.jumpMethod
  845. if (core.jumpLink) merged.externalLink = core.jumpLink
  846. }
  847. if (core.showOnHome) merged.showOnHome = core.showOnHome
  848. if (core.showOnAssembly) merged.showOnAssembly = core.showOnAssembly
  849. if (Array.isArray(core.assemblyPages)) merged.assemblyPages = [...core.assemblyPages]
  850. // 复制后清空标识字段,让用户重新命名并由后端生成新编号
  851. delete merged.productId
  852. Object.keys(merged).forEach(k => {
  853. this.form[k] = merged[k]
  854. })
  855. ElMessage.success(`已复制「${core.equityName || id}」的内容,请确认后保存`)
  856. }).catch(() => {
  857. ElMessage.warning('未能加载源权益信息,将以空白表单创建')
  858. })
  859. },
  860. nextStep() {
  861. if (this.activeStep < 2) {
  862. this.activeStep++
  863. }
  864. },
  865. prevStep() {
  866. if (this.activeStep > 0) {
  867. this.activeStep--
  868. }
  869. },
  870. buildPayload() {
  871. const f = this.form
  872. const source = this.mappedSource
  873. const isNotPlatform = f.isPlatformExchange === '否'
  874. const isCustomValidity = isNotPlatform || f.validityType === 'custom'
  875. return {
  876. equityName: f.equityName,
  877. source: source,
  878. isPlatformExchange: f.isPlatformExchange,
  879. productType: f.isPlatformExchange === '是' ? f.productType : '',
  880. skuNo: (f.isPlatformExchange === '是' && f.productType === '微信立减金') ? (f.rongshuSkuNo || f.skuNo || '') : (f.skuNo || ''),
  881. merchantName: f.merchantName || '',
  882. jumpMethod: isNotPlatform ? f.externalJumpMethod : '-',
  883. jumpLink: isNotPlatform ? f.externalLink : '-',
  884. exchangeMethod: isNotPlatform
  885. ? (f.externalJumpMethod === '有' ? '第三方(详情页跳转)' : '第三方(列表跳转)')
  886. : '权益平台',
  887. validityType: isCustomValidity ? 'custom' : 'fromGrantPlan',
  888. validityText: isCustomValidity ? (f.validityText || '') : '',
  889. showOnHome: f.showOnHome,
  890. showOnAssembly: f.showOnAssembly,
  891. assemblyPages: [...(f.assemblyPages || [])]
  892. }
  893. },
  894. handleSaveDraft() {
  895. if (!this.form.equityName) {
  896. ElMessage.warning('请填写权益名称后再保存草稿')
  897. return
  898. }
  899. request.post('/api/equity/save-draft', this.buildPayload()).then(() => {
  900. ElMessage.success('草稿已保存')
  901. this.$router.push('/customization/hsbc/equity-products')
  902. }).catch(() => {})
  903. },
  904. handleSubmitAudit() {
  905. if (!this.form.equityName) {
  906. ElMessage.warning('请填写权益名称后再提交')
  907. return
  908. }
  909. ElMessageBox.prompt('请填写提交说明(可选)', '提交审核', {
  910. confirmButtonText: '提交',
  911. cancelButtonText: '取消',
  912. inputType: 'textarea',
  913. inputPlaceholder: '可填写本次提交的关键变更点',
  914. inputValidator: () => true
  915. }).then(({ value }) => {
  916. const payload = { ...this.buildPayload(), submitReason: value || '' }
  917. request.post('/api/equity/submit', payload).then(() => {
  918. ElMessage.success('已提交审核')
  919. this.$router.push('/customization/hsbc/equity-products')
  920. }).catch(() => {})
  921. }).catch(() => {})
  922. },
  923. goBack() {
  924. this.$router.push('/customization/hsbc/equity-products')
  925. },
  926. handleShareEnabledChange(val) {
  927. if (val) {
  928. if (!this.form.shareName) {
  929. this.form.shareName = this.form.equityName || ''
  930. }
  931. }
  932. },
  933. handleSmsEnabledChange(val) {
  934. if (!val) {
  935. this.form.smsTemplateId = ''
  936. this.form.smsTemplate = ''
  937. }
  938. },
  939. handleSmsTemplateChange(id) {
  940. const tpl = this.smsTemplateOptions.find(i => i.id === id)
  941. this.form.smsTemplate = tpl ? tpl.content : ''
  942. },
  943. handleUpload(file, field) {
  944. if (!file || !file.raw) return
  945. const reader = new FileReader()
  946. reader.onload = (e) => {
  947. this.form[field] = [{ name: file.name, url: e.target.result, uid: file.uid }]
  948. }
  949. reader.readAsDataURL(file.raw)
  950. },
  951. handlePreviewImage(file) {
  952. this.previewImageUrl = file.url || ''
  953. this.previewVisible = !!this.previewImageUrl
  954. },
  955. onRongshuSelect(product) {
  956. this.form.rongshuProduct = product.name
  957. this.form.rongshuSkuNo = product.skuNo
  958. this.form.equityName = product.name
  959. this.form.merchantName = product.merchant
  960. this.form.stockCount = product.stock
  961. this.form.mainImage = product.mainImage ? [...product.mainImage] : []
  962. }
  963. }
  964. }
  965. </script>
  966. <style scoped>
  967. .add-equity-product {
  968. padding: 20px;
  969. }
  970. .header-title {
  971. font-size: 18px;
  972. font-weight: 500;
  973. }
  974. .section-card {
  975. margin-bottom: 16px;
  976. border: none;
  977. }
  978. .upload-hide-trigger >>> .el-upload--picture-card { display: none; }
  979. .section-card >>> .el-card__header {
  980. padding: 12px 20px;
  981. background: #fafafa;
  982. border-bottom: 1px solid #ebeef5;
  983. }
  984. .section-card >>> .el-form-item__content {
  985. display: block;
  986. }
  987. .section-title {
  988. font-size: 16px;
  989. font-weight: 600;
  990. color: #303133;
  991. }
  992. .action-bar {
  993. display: flex;
  994. align-items: center;
  995. justify-content: space-between;
  996. margin-top: 20px;
  997. padding-top: 20px;
  998. border-top: 1px solid #ebeef5;
  999. }
  1000. .action-left, .action-right {
  1001. width: 120px;
  1002. }
  1003. .action-center {
  1004. display: flex;
  1005. justify-content: center;
  1006. gap: 12px;
  1007. }
  1008. .tip-icon {
  1009. color: #909399;
  1010. cursor: pointer;
  1011. font-size: 14px;
  1012. }
  1013. .upload-size-tip {
  1014. width: 100%;
  1015. margin-top: 4px;
  1016. font-size: 12px;
  1017. color: #909399;
  1018. line-height: 1.5;
  1019. }
  1020. .sms-template-preview {
  1021. margin-top: 12px;
  1022. padding: 12px;
  1023. background: #fff;
  1024. border: 1px dashed #dcdfe6;
  1025. border-radius: 4px;
  1026. font-size: 13px;
  1027. color: #606266;
  1028. line-height: 1.6;
  1029. white-space: pre-wrap;
  1030. word-break: break-all;
  1031. }
  1032. </style>