watchReward.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. <template >
  2. <div v-loading="loading">
  3. <!-- 提示信息 -->
  4. <div class="tip-message" >
  5. 设置观看奖励,用户达到直播观看时长后可领取奖励
  6. </div>
  7. <!-- 开启观看奖励开关 -->
  8. <div class="reward-switch">
  9. <span class="switch-label">开启观看奖励</span>
  10. <el-switch v-model="watchRewardForm.enabled"></el-switch>
  11. </div>
  12. <!-- 观看奖励设置 -->
  13. <div v-if="watchRewardForm.enabled" class="section-block">
  14. <div class="section-title">观看奖励设置</div>
  15. <!-- 表单内容 -->
  16. <el-form
  17. :model="watchRewardForm"
  18. :rules="rules"
  19. ref="watchRewardForm"
  20. label-width="130px"
  21. >
  22. <!-- 参与条件 -->
  23. <el-form-item label="参与条件" prop="participateCondition">
  24. <el-radio-group v-model="watchRewardForm.participateCondition">
  25. <el-radio label="1">达到指定观看时长发积分</el-radio>
  26. <el-radio label="2" v-if="this.projectFrom!=='颐安心'">启用完课积分</el-radio>
  27. <el-radio label="3">启动直播完课奖励</el-radio>
  28. </el-radio-group>
  29. </el-form-item>
  30. <!-- 观看时长 -->
  31. <el-form-item label="观看时长" prop="watchDuration" v-if="watchRewardForm.participateCondition === '1'">
  32. <el-input v-model="watchRewardForm.watchDuration" placeholder="请输入观看时长" class="duration-input">
  33. <template #append>分钟</template>
  34. </el-input>
  35. </el-form-item>
  36. <!-- 完课率要求 -->
  37. <el-form-item label="完课率要求" prop="completionRate" v-if="watchRewardForm.participateCondition === '2' || watchRewardForm.participateCondition === '3'">
  38. <el-input-number
  39. v-model="watchRewardForm.completionRate"
  40. :min="1"
  41. :max="100"
  42. :precision="0"
  43. placeholder="请输入完课率"
  44. style="width: 200px;"
  45. ></el-input-number>
  46. <span style="margin-left: 10px; color: #909399;">%(观看时长占直播总时长的比例)</span>
  47. </el-form-item>
  48. <!-- 连续完课积分配置 -->
  49. <el-form-item label="连续完课积分" prop="pointsConfig" v-if="watchRewardForm.participateCondition === '2'">
  50. <div style="display: flex; flex-direction: column; gap: 10px;">
  51. <div v-for="(point, index) in watchRewardForm.pointsConfig" :key="index" style="display: flex; align-items: center;">
  52. <span style="width: 80px;">第{{ index + 1 }}天:</span>
  53. <el-input-number
  54. v-model="watchRewardForm.pointsConfig[index]"
  55. :min="0"
  56. :precision="0"
  57. placeholder="请输入积分值"
  58. style="width: 200px;"
  59. ></el-input-number>
  60. <span style="margin-left: 10px; color: #909399;">积分</span>
  61. </div>
  62. </div>
  63. </el-form-item>
  64. <!-- 实施动作(仅在达到指定观看时长时显示) -->
  65. <el-form-item label="实施动作" prop="action" v-if="watchRewardForm.participateCondition === '1'">
  66. <el-select v-model="watchRewardForm.action" placeholder="请选择实施动作" style="width: 300px;">
  67. <el-option
  68. v-for="item in actionOptions"
  69. :key="item.value"
  70. :label="item.label"
  71. :value="item.value"
  72. ></el-option>
  73. </el-select>
  74. </el-form-item>
  75. <!-- 领取提示语 -->
  76. <!-- <el-form-item label="领取提示语" prop="receivePrompt">-->
  77. <!-- <el-input v-model="watchRewardForm.receivePrompt" placeholder="请输入领取提示语"></el-input>-->
  78. <!-- </el-form-item>-->
  79. <div v-if="watchRewardForm.participateCondition === '3'">
  80. <div class="section-title">直播红包设置</div>
  81. <!-- 红包金额 -->
  82. <el-form-item label="红包金额" prop="redPacketAmount" v-if="watchRewardForm.participateCondition === '3'">
  83. <el-input-number v-model="watchRewardForm.redPacketAmount" :min="0.1" :max="10" :step="0.1"></el-input-number>
  84. </el-form-item>
  85. <!-- 红包余额是否扣减开关 -->
  86. <el-form-item label="红包余额是否扣减开关">
  87. <el-radio-group v-model="watchRewardForm.isRedPackageBalanceDeduction">
  88. <el-radio label="1">开</el-radio>
  89. <el-radio label="2">关</el-radio>
  90. </el-radio-group>
  91. </el-form-item>
  92. </div>
  93. <div v-if="watchRewardForm.participateCondition === '3'">
  94. <div class="section-title">录播奖励设置</div>
  95. <!-- 是否录播可领取奖励 -->
  96. <el-form-item label="录播可领取奖励">
  97. <el-switch v-model="watchRewardForm.recordRedPacketEnabled"></el-switch>
  98. </el-form-item>
  99. <!-- 录播奖励配置列表 -->
  100. <div v-if="watchRewardForm.recordRedPacketEnabled">
  101. <div v-for="(item, index) in watchRewardForm.recordTimeRanges" :key="index" class="record-reward-item">
  102. <el-time-picker
  103. is-range
  104. v-model="item.range"
  105. range-separator="至"
  106. start-placeholder="开始时间"
  107. end-placeholder="结束时间"
  108. format="HH:mm"
  109. value-format="HH:mm"
  110. style="width: 280px;"
  111. @change="onTimeRangeChange(index)"
  112. ></el-time-picker>
  113. <el-checkbox-group v-model="item.rewardTypes" style="margin-left: 15px; flex-shrink: 0; width: 200px;">
  114. <el-checkbox label="1">红包</el-checkbox>
  115. <el-checkbox label="2">积分</el-checkbox>
  116. <el-checkbox label="3">核销卷</el-checkbox>
  117. </el-checkbox-group>
  118. <el-input-number v-if="item.rewardTypes.includes('1')" v-model="item.redPacketAmount" :min="0.1" :max="10" :step="0.1" style="width: 140px; margin-left: 15px;"></el-input-number>
  119. <el-input v-if="item.rewardTypes.includes('2')" v-model="item.scoreAmount" placeholder="积分值" style="width: 140px; margin-left: 15px;"></el-input>
  120. <el-select v-if="item.rewardTypes.includes('3')" v-model="item.couponId" placeholder="请选择核销卷" clearable style="width: 200px; margin-left: 15px;">
  121. <el-option
  122. v-for="c in couponList"
  123. :key="c.id"
  124. :label="c.couponName + ' (' + c.id + ')'"
  125. :value="c.id"
  126. ></el-option>
  127. </el-select>
  128. <el-button type="danger" icon="el-icon-delete" circle style="margin-left: 10px;" @click="removeRecordTimeRange(index)" v-if="watchRewardForm.recordTimeRanges.length > 1"></el-button>
  129. </div>
  130. <div v-if="timeRangeOverlap" style="color: #F56C6C; font-size: 12px; margin-top: -5px; margin-bottom: 10px;">时间段之间存在重叠,请重新选择</div>
  131. <el-button type="primary" icon="el-icon-plus" size="small" @click="addRecordTimeRange">添加时间段</el-button>
  132. </div>
  133. </div>
  134. <!-- 红包设置(仅在达到指定观看时长时显示) -->
  135. <div v-if="watchRewardForm.participateCondition === '1'">
  136. <div class="section-title">红包设置</div>
  137. <!-- 根据实施动作类型显示不同的表单内容 -->
  138. <template v-if="watchRewardForm.action === '1'">
  139. <!-- 现金红包设置 -->
  140. <!-- 红包发放方式 1固定金额 2随机金额 -->
  141. <el-form-item label="红包发放方式" prop="redPacketType">
  142. <el-radio-group v-model="watchRewardForm.redPacketType">
  143. <el-radio label="1">固定金额</el-radio>
  144. <el-radio label="2">随机金额</el-radio>
  145. </el-radio-group>
  146. </el-form-item>
  147. <!-- 红包金额 -->
  148. <el-form-item label="红包金额" prop="redPacketAmount">
  149. <el-input v-model="watchRewardForm.redPacketAmount" placeholder="请输入红包金额"></el-input>
  150. </el-form-item>
  151. <!-- 红包发放数量 -->
  152. <el-form-item label="红包发放数量" prop="redPacketCount">
  153. <el-input v-model="watchRewardForm.redPacketCount" placeholder="红包数量+28888人数"></el-input>
  154. </el-form-item>
  155. <!-- 红包领取方式 1二维码核销 2微信提现 -->
  156. <el-form-item label="红包领取方式" prop="receiveMethod">
  157. <el-radio-group v-model="watchRewardForm.receiveMethod">
  158. <el-radio label="1">二维码领取</el-radio>
  159. <el-radio label="2">微信发放</el-radio>
  160. </el-radio-group>
  161. </el-form-item>
  162. </template>
  163. <template v-else>
  164. <!-- 积分红包设置 -->
  165. <!-- 积分值 -->
  166. <el-form-item label="积分值" prop="scoreAmount">
  167. <el-input
  168. v-model="watchRewardForm.scoreAmount"
  169. placeholder="请输入积分值" style="width: 300px;"
  170. ></el-input>
  171. </el-form-item>
  172. <!-- 最大领取人数 -->
  173. <!-- <el-form-item label="最大领取人数" prop="maxReceivers">-->
  174. <!-- <el-input-->
  175. <!-- v-model="watchRewardForm.maxReceivers"-->
  176. <!-- placeholder="请输入最大领取人数" style="width: 300px;"-->
  177. <!-- ></el-input>-->
  178. <!-- </el-form-item>-->
  179. </template>
  180. </div>
  181. <!-- 其他设置(仅在达到指定观看时长时显示) -->
  182. <div v-if="watchRewardForm.participateCondition === '1'">
  183. <div class="section-title">其他设置</div>
  184. <template v-if="watchRewardForm.action === '1'">
  185. <!-- 客服引导 1跟进企业微信 2不设置 -->
  186. <el-form-item label="客服引导" prop="showGuide">
  187. <el-radio-group v-model="watchRewardForm.showGuide">
  188. <el-radio label="1">跟进企业微信</el-radio>
  189. <el-radio label="2">不设置</el-radio>
  190. </el-radio-group>
  191. </el-form-item>
  192. <!-- 客服引导语 -->
  193. <el-form-item label="客服引导语" prop="guideText">
  194. <el-input
  195. v-model="watchRewardForm.guideText"
  196. placeholder="请输入客服引导语" style="width: 300px;"
  197. ></el-input>
  198. </el-form-item>
  199. </template>
  200. <template v-else>
  201. <!-- 积分使用引导语 -->
  202. <el-form-item label="积分使用引导语" prop="scoreGuideText">
  203. <el-input
  204. v-model="watchRewardForm.scoreGuideText"
  205. placeholder="请输入积分使用引导语" style="width: 300px;"
  206. ></el-input>
  207. </el-form-item>
  208. <!-- 积分使用引导链接 -->
  209. <el-form-item label="积分使用引导链接" prop="scoreGuideLink">
  210. <el-input
  211. v-model="watchRewardForm.scoreGuideLink"
  212. placeholder="请输入积分使用引导链接" style="width: 300px;"
  213. ></el-input>
  214. </el-form-item>
  215. <!-- 引导语 -->
  216. <!-- <el-form-item label="引导语" prop="guideText">-->
  217. <!-- <el-input-->
  218. <!-- v-model="watchRewardForm.guideText"-->
  219. <!-- placeholder="请输入引导语" style="width: 300px;"-->
  220. <!-- ></el-input>-->
  221. <!-- </el-form-item>-->
  222. </template>
  223. </div>
  224. <!-- 保存按钮 -->
  225. <div class="form-actions">
  226. <el-button type="primary" @click="saveWatchReward">保存</el-button>
  227. </div>
  228. </el-form>
  229. </div>
  230. </div>
  231. </template>
  232. <script>
  233. import {addConfig, getConfig, updateConfig} from "@/api/live/liveQuestionLive";
  234. import { listStoreCouponIssue } from "@/api/live/liveCouponIssue";
  235. export default {
  236. data() {
  237. return {
  238. projectFrom:process.env.VUE_APP_TITLE_INDEX,
  239. loading: true,
  240. liveId: null,
  241. watchRewardForm: {
  242. id: null,
  243. liveId: null,
  244. // 是否启用观看奖励
  245. enabled: false,
  246. // 参与条件 1:达到指定观看时长 2:启用完课积分
  247. participateCondition: '1',
  248. // 观看时长
  249. watchDuration: '',
  250. // 实施动作
  251. action: '2',
  252. // 领取提示语
  253. receivePrompt: '',
  254. // 红包发放方式(固定金额/随机金额)
  255. redPacketType: '1',
  256. // 红包金额
  257. redPacketAmount: '',
  258. //是否开启红包扣减
  259. isRedPackageBalanceDeduction: '2',
  260. // 红包发放数量
  261. redPacketCount: '',
  262. // 红包领取方式
  263. receiveMethod: '1',
  264. // 是否显示客服引导
  265. showGuide: '1',
  266. // 客服引导语
  267. guideText: '',
  268. // 积分值
  269. scoreAmount: '',
  270. // 是否录播可领取奖励
  271. recordRedPacketEnabled: false,
  272. // 录播奖励配置列表(前端展示用)
  273. recordTimeRanges: [{ range: null, rewardTypes: ['1'], redPacketAmount: '', scoreAmount: '', couponId: '' }],
  274. // 录播奖励配置字符串(提交后端用)
  275. recordTimeRangeStr: '',
  276. // // 最大领取人数
  277. // maxReceivers: '',
  278. // 积分使用引导语
  279. scoreGuideText: '',
  280. // 积分使用引导链接
  281. scoreGuideLink: '',
  282. // 完课积分相关配置(participateCondition为2时使用)
  283. // 完课率要求(1-100)
  284. completionRate: 90,
  285. // 连续完课积分配置(第1-10天)
  286. pointsConfig: [100, 110, 120, 130, 140, 150, 160, 170, 180, 200]
  287. },
  288. rules:{
  289. participateCondition:[
  290. { required: true, message: '请选择参与条件', trigger: 'change'}
  291. ],
  292. watchDuration:[
  293. {
  294. validator: (rule, value, callback) => {
  295. if (this.watchRewardForm.participateCondition === '1') {
  296. if (!value) {
  297. callback(new Error('请输入观看时长'));
  298. } else {
  299. callback();
  300. }
  301. } else {
  302. callback();
  303. }
  304. },
  305. trigger: 'blur'
  306. }
  307. ],
  308. completionRate:[
  309. {
  310. validator: (rule, value, callback) => {
  311. if (this.watchRewardForm.participateCondition === '2') {
  312. if (!value && value !== 0) {
  313. callback(new Error('请输入完课率要求'));
  314. } else if (value < 1 || value > 100) {
  315. callback(new Error('完课率要求范围为1-100'));
  316. } else {
  317. callback();
  318. }
  319. } else {
  320. callback();
  321. }
  322. },
  323. trigger: 'blur'
  324. }
  325. ],
  326. action:[
  327. {
  328. validator: (rule, value, callback) => {
  329. if (this.watchRewardForm.participateCondition === '1') {
  330. if (!value) {
  331. callback(new Error('请选择实施动作'));
  332. } else {
  333. callback();
  334. }
  335. } else {
  336. callback();
  337. }
  338. },
  339. trigger: 'change'
  340. }
  341. ],
  342. // receivePrompt:[
  343. // { required: true, message: '请输入领取提示语', trigger: 'blur'}
  344. // ],
  345. redPacketType:[
  346. { required: true, message: '请选择红包发放方式', trigger: 'blur'}
  347. ],
  348. redPacketAmount:[
  349. { required: true, message: '请输入红包金额', trigger: 'blur'}
  350. ],
  351. scoreAmount:[
  352. { required: true, message: '请输入积分数量', trigger: 'blur'}
  353. ],
  354. receiveMethod:[
  355. { required: true, message: '请选择红包领取方式', trigger: 'blur'}
  356. ],
  357. // guideText:[
  358. // { required: true, message: '请输入客服引导语', trigger: 'blur'}
  359. // ],
  360. showGuide:[
  361. { required: true, message: '请选择是否显示客服引导', trigger: 'blur'}
  362. ]
  363. },
  364. // 添加实施动作选项
  365. actionOptions: [
  366. // {
  367. // label: '现金红包',
  368. // value: '1'
  369. // },
  370. {
  371. label: '积分红包',
  372. value: '2'
  373. }
  374. ],
  375. timeRangeOverlap: false,
  376. // 核销卷列表(couponType=3)
  377. couponList: [],
  378. };
  379. },
  380. watch: {
  381. // 监听路由的 query 参数变化
  382. '$route.query': {
  383. handler(newQuery) {
  384. this.liveId = this.$route.params.liveId
  385. this.watchRewardForm.liveId = this.liveId
  386. if(this.liveId == null) {
  387. return;
  388. }
  389. this.getLiveConfig();
  390. },
  391. // 初始化时立即执行一次
  392. immediate: true
  393. },
  394. // 监听开启观看奖励开关变化
  395. 'watchRewardForm.enabled': {
  396. handler(newValue, oldValue) {
  397. // 只有当关闭开关时才自动保存(从 true 变为 false)
  398. if (oldValue === true && newValue === false && this.liveId) {
  399. this.autoSaveEnabled();
  400. }
  401. }
  402. }
  403. },
  404. created() {
  405. this.getCouponList();
  406. },
  407. methods: {
  408. // 获取核销卷列表(couponType=3)
  409. getCouponList() {
  410. listStoreCouponIssue({ pageNum: 1, pageSize: 999, couponType: '3' }).then(response => {
  411. this.couponList = response.rows || [];
  412. });
  413. },
  414. addRecordTimeRange() {
  415. this.watchRewardForm.recordTimeRanges.push({ range: null, rewardTypes: ['1'], redPacketAmount: '', scoreAmount: '', couponId: '' })
  416. },
  417. removeRecordTimeRange(index) {
  418. this.watchRewardForm.recordTimeRanges.splice(index, 1)
  419. this.checkOverlap()
  420. },
  421. onTimeRangeChange(currentIndex) {
  422. const current = this.watchRewardForm.recordTimeRanges[currentIndex]
  423. if (!current || !current.range || current.range.length !== 2) {
  424. this.checkOverlap()
  425. return
  426. }
  427. const currentStart = this.timeToMinutes(current.range[0])
  428. const currentEnd = this.timeToMinutes(current.range[1])
  429. const others = this.watchRewardForm.recordTimeRanges
  430. .filter((item, i) => i !== currentIndex && item.range && item.range.length === 2)
  431. .map(item => ({
  432. start: this.timeToMinutes(item.range[0]),
  433. end: this.timeToMinutes(item.range[1])
  434. }))
  435. let overlap = false
  436. for (const other of others) {
  437. if (currentStart < other.end && other.start < currentEnd) {
  438. overlap = true
  439. break
  440. }
  441. }
  442. if (overlap) {
  443. this.$set(current, 'range', null)
  444. this.$message.error('时间重叠,请重新选择')
  445. }
  446. this.checkOverlap()
  447. },
  448. checkOverlap() {
  449. const ranges = this.watchRewardForm.recordTimeRanges
  450. .filter(item => item.range && item.range.length === 2)
  451. .map(item => ({
  452. start: this.timeToMinutes(item.range[0]),
  453. end: this.timeToMinutes(item.range[1])
  454. }))
  455. for (let i = 0; i < ranges.length; i++) {
  456. for (let j = i + 1; j < ranges.length; j++) {
  457. if (ranges[i].start < ranges[j].end && ranges[j].start < ranges[i].end) {
  458. this.timeRangeOverlap = true
  459. return
  460. }
  461. }
  462. }
  463. this.timeRangeOverlap = false
  464. },
  465. timeToMinutes(timeStr) {
  466. if (!timeStr) return 0
  467. const parts = timeStr.split(':')
  468. return parseInt(parts[0]) * 60 + parseInt(parts[1])
  469. },
  470. minutesToTime(minutes) {
  471. const h = Math.floor(minutes / 60).toString().padStart(2, '0')
  472. const m = (minutes % 60).toString().padStart(2, '0')
  473. return h + ':' + m
  474. },
  475. getLiveConfig(){
  476. getConfig(this.liveId).then(response => {
  477. if(response.code === 200 && response.data != null && response.data.length > 0){
  478. const serverData = JSON.parse(response.data)
  479. this.watchRewardForm = Object.assign({}, this.watchRewardForm, serverData)
  480. if (this.watchRewardForm.recordTimeRangeStr) {
  481. this.watchRewardForm.recordTimeRanges = this.watchRewardForm.recordTimeRangeStr.split(',').map(item => {
  482. const parts = item.split('-')
  483. return { range: [parts[0], parts[1]], rewardTypes: parts[2] ? parts[2].split('|') : ['1'], redPacketAmount: parts[3] || '', scoreAmount: parts[4] || '', couponId: parts[5] ? Number(parts[5]) : '' }
  484. })
  485. } else {
  486. this.watchRewardForm.recordTimeRanges = [{ range: null, rewardTypes: ['1'], redPacketAmount: '', scoreAmount: '', couponId: '' }]
  487. }
  488. if(this.watchRewardForm.isRedPackageBalanceDeduction == null){
  489. this.watchRewardForm.isRedPackageBalanceDeduction = '1'
  490. } else {
  491. this.watchRewardForm.isRedPackageBalanceDeduction = String(this.watchRewardForm.isRedPackageBalanceDeduction)
  492. }
  493. }
  494. this.loading = false
  495. })
  496. },
  497. // 自动保存开关状态
  498. autoSaveEnabled() {
  499. const submitData = Object.assign({}, this.watchRewardForm)
  500. if (submitData.recordTimeRanges && submitData.recordTimeRanges.length > 0) {
  501. submitData.recordTimeRangeStr = submitData.recordTimeRanges
  502. .filter(item => item.range && item.range.length === 2)
  503. .map(item => item.range[0] + '-' + item.range[1] + '-' + (item.rewardTypes || []).join('|') + '-' + (item.redPacketAmount || '') + '-' + (item.scoreAmount || '') + '-' + (item.couponId || ''))
  504. .join(',')
  505. } else {
  506. submitData.recordTimeRangeStr = ''
  507. }
  508. delete submitData.recordTimeRanges
  509. if (this.watchRewardForm.id == null) {
  510. addConfig(submitData, this.liveId).then(res => {
  511. if (res.code == 200) {
  512. this.msgSuccess("已关闭观看奖励");
  513. // 更新 id,下次修改时使用 update
  514. if (res.data && res.data.id) {
  515. this.watchRewardForm.id = res.data.id;
  516. }
  517. }
  518. }).catch(() => {
  519. // 如果保存失败,恢复开关状态
  520. this.watchRewardForm.enabled = true;
  521. });
  522. } else {
  523. updateConfig(submitData, this.liveId).then(response => {
  524. if (response.code == 200) {
  525. this.msgSuccess("已关闭观看奖励");
  526. }
  527. }).catch(() => {
  528. // 如果保存失败,恢复开关状态
  529. this.watchRewardForm.enabled = true;
  530. });
  531. }
  532. },
  533. saveWatchReward() {
  534. this.$refs["watchRewardForm"].validate(valid => {
  535. console.log(valid)
  536. if (valid) {
  537. if (this.timeRangeOverlap) {
  538. this.$message.error('时间段之间存在重叠,请重新选择')
  539. return
  540. }
  541. // 录播奖励必填校验
  542. if (this.watchRewardForm.recordRedPacketEnabled) {
  543. for (let i = 0; i < this.watchRewardForm.recordTimeRanges.length; i++) {
  544. const item = this.watchRewardForm.recordTimeRanges[i]
  545. if (!item.range || item.range.length !== 2) {
  546. this.$message.error('请选择第' + (i + 1) + '个时间段')
  547. return
  548. }
  549. if (!item.rewardTypes || item.rewardTypes.length === 0) {
  550. this.$message.error('第' + (i + 1) + '个时间段请至少选择一个奖励类型')
  551. return
  552. }
  553. if (item.rewardTypes.includes('1') && !item.redPacketAmount) {
  554. this.$message.error('第' + (i + 1) + '个时间段选择了红包,请填写红包金额')
  555. return
  556. }
  557. if (item.rewardTypes.includes('2') && !item.scoreAmount) {
  558. this.$message.error('第' + (i + 1) + '个时间段选择了积分,请填写积分值')
  559. return
  560. }
  561. if (item.rewardTypes.includes('3') && !item.couponId) {
  562. this.$message.error('第' + (i + 1) + '个时间段选择了核销卷,请选择核销卷')
  563. return
  564. }
  565. }
  566. }
  567. const submitData = Object.assign({}, this.watchRewardForm)
  568. if (submitData.recordTimeRanges && submitData.recordTimeRanges.length > 0) {
  569. submitData.recordTimeRangeStr = submitData.recordTimeRanges
  570. .filter(item => item.range && item.range.length === 2)
  571. .map(item => item.range[0] + '-' + item.range[1] + '-' + (item.rewardTypes || []).join('|') + '-' + (item.redPacketAmount || '') + '-' + (item.scoreAmount || '') + '-' + (item.couponId || ''))
  572. .join(',')
  573. } else {
  574. submitData.recordTimeRangeStr = ''
  575. }
  576. delete submitData.recordTimeRanges
  577. if (this.watchRewardForm.id == null) {
  578. addConfig(submitData,this.liveId).then(res => {
  579. if (res.code == 200) {
  580. this.msgSuccess("修改成功");
  581. }
  582. })
  583. } else {
  584. updateConfig(submitData,this.liveId).then(response => {
  585. this.msgSuccess("修改成功");
  586. });
  587. }
  588. }
  589. })
  590. },
  591. }
  592. };
  593. </script>
  594. <style scoped>
  595. /* 录播奖励配置项样式 */
  596. .record-reward-item {
  597. display: flex;
  598. align-items: center;
  599. width: 100%;
  600. margin-bottom: 10px;
  601. padding: 10px 0;
  602. border-top: 1px dashed #dcdfe6;
  603. }
  604. .record-reward-item:first-child {
  605. border-top: none;
  606. padding-top: 0;
  607. }
  608. /* 提示信息样式 */
  609. .tip-message {
  610. padding: 12px 16px;
  611. background-color: #FFF6F2;
  612. border-radius: 4px;
  613. color: #666;
  614. font-size: 14px;
  615. margin-bottom: 20px;
  616. }
  617. /* 开关容器样式 */
  618. .reward-switch {
  619. margin-left: 200px;
  620. margin-bottom: 20px;
  621. padding: 20px;
  622. background-color: #fff;
  623. border-radius: 4px;
  624. display: flex;
  625. align-items: center;
  626. }
  627. /* 开关标签样式 */
  628. .reward-switch .switch-label {
  629. margin-right: 10px;
  630. font-size: 14px;
  631. color: #333;
  632. margin-left: 50px;
  633. }
  634. /* 表单区块样式 */
  635. .section-block {
  636. width: 100%;
  637. background-color: #fff;
  638. padding: 20px;
  639. border-radius: 4px;
  640. margin-left: 50px;
  641. margin-bottom: 20px;
  642. }
  643. /* 标题样式 */
  644. .section-block .section-title {
  645. font-size: 14px;
  646. color: #333;
  647. margin-bottom: 20px;
  648. border-left: 4px solid #409EFF;
  649. padding-left: 10px;
  650. line-height: 1;
  651. }
  652. /* 表单样式 */
  653. .reward-form {
  654. margin-top: 20px;
  655. }
  656. /* 表单项样式 */
  657. .reward-form .el-form-item {
  658. margin-bottom: 22px;
  659. padding-left: 50px;
  660. }
  661. .reward-form .el-form-item:last-child {
  662. margin-bottom: 0;
  663. }
  664. /* 表单标签样式 */
  665. .reward-form .el-form-item .el-form-item__label {
  666. color: #606266;
  667. }
  668. /* 输入框统一宽度 */
  669. .reward-form .el-form-item .el-input {
  670. width: 300px;
  671. }
  672. /* 必填项星号样式 */
  673. .reward-form .el-form-item.is-required .el-form-item__label:before {
  674. color: #F56C6C;
  675. }
  676. /* 观看时长输入框样式 */
  677. .reward-form .el-form-item .duration-input {
  678. width: 300px;
  679. }
  680. .reward-form .el-form-item .duration-input .el-input__inner {
  681. text-align: left;
  682. }
  683. /* 保存按钮样式 */
  684. .form-actions {
  685. width: 600px;
  686. text-align: center;
  687. margin-top: 30px;
  688. }
  689. .form-actions .el-button {
  690. padding: 8px 20px;
  691. font-size: 13px;
  692. }
  693. </style>