xw 14 hodín pred
rodič
commit
2779c59df1

+ 16 - 0
src/api/course/courseRandomRedPacket.js

@@ -0,0 +1,16 @@
+import request from '@/utils/request'
+
+export function getCourseRandomRedPacket(project) {
+  return request({
+    url: '/course/courseRandomRedPacket/' + project,
+    method: 'get'
+  })
+}
+
+export function saveCourseRandomRedPacket(data) {
+  return request({
+    url: '/course/courseRandomRedPacket',
+    method: 'post',
+    data: data
+  })
+}

+ 316 - 0
src/views/course/courseRandomRedPacket/index.vue

@@ -0,0 +1,316 @@
+<template>
+  <div class="app-container course-random-red-packet">
+    <el-card shadow="never">
+      <div slot="header" class="card-header">
+        <div>
+          <div class="title">配置中心 - 课程随机红包</div>
+          <div class="desc">
+            绑定课程项目fs_user_course.project,仅白名单企业可参与;权重总和需为100%,多个企业ID逗号分隔,填写ALL代表全部企业随机红包
+          </div>
+        </div>
+        <el-tag type="info" size="small">红包模块 v2.0</el-tag>
+      </div>
+
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px" v-loading="loading">
+        <el-form-item label="课程项目" prop="project">
+          <el-select
+            v-model="form.project"
+            placeholder="请选择课程项目"
+            filterable
+            clearable
+            style="width: 420px"
+            @change="handleProjectChange"
+          >
+            <el-option
+              v-for="item in projectOptions"
+              :key="item.dictValue"
+              :label="item.dictLabel"
+              :value="Number(item.dictValue)"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-divider content-position="left">红包开关配置</el-divider>
+
+        <el-form-item label="开启随机红包">
+          <el-switch
+            v-model="form.enableRandom"
+            active-color="#13ce66"
+            inactive-color="#ff4949"
+          />
+        </el-form-item>
+
+        <template v-if="form.enableRandom">
+          <div v-for="(tier, index) in form.tiers" :key="index" class="tier-row">
+            <el-form-item
+              label="红包金额"
+              :prop="'tiers.' + index + '.amount'"
+              :rules="[{ required: true, message: '请填写金额', trigger: 'blur' }]"
+            >
+              <el-input-number
+                v-model="tier.amount"
+                :min="0.01"
+                :max="200"
+                :step="0.01"
+                :precision="2"
+                controls-position="right"
+              />
+              <span class="unit">元</span>
+            </el-form-item>
+            <el-form-item
+              label="权重占比"
+              :prop="'tiers.' + index + '.weight'"
+              :rules="[
+                { required: true, message: '请填写权重', trigger: 'blur' },
+                { type: 'number', min: 1, message: '权重不能小于0', trigger: 'blur' }
+              ]"
+            >
+              <el-input-number
+                v-model="tier.weight"
+                :min="1"
+                :max="100"
+                controls-position="right"
+              />
+              <span class="unit">%</span>
+            </el-form-item>
+            <el-button
+              type="text"
+              icon="el-icon-delete"
+              class="delete-btn"
+              :disabled="form.tiers.length <= 1"
+              @click="removeTier(index)"
+            />
+          </div>
+
+          <el-form-item>
+            <el-button type="primary" plain icon="el-icon-plus" @click="addTier">新增档位</el-button>
+            <span class="weight-total" :class="{ error: totalWeight !== 100 }">
+              权重总和:{{ totalWeight }}%
+            </span>
+          </el-form-item>
+        </template>
+
+        <el-divider content-position="left">企业白名单</el-divider>
+
+        <el-form-item label="允许企业">
+          <el-select
+            v-model="whitelistCompanyIds"
+            multiple
+            filterable
+            clearable
+            collapse-tags
+            placeholder="不选择代表全部企业走随机红包"
+            style="width: 100%"
+          >
+            <el-option
+              v-for="item in companyOptions"
+              :key="item.dictValue"
+              :label="item.dictLabel"
+              :value="String(item.dictValue)"
+            />
+          </el-select>
+          <div class="tip">多个企业ID逗号分隔,内部存储ALL代表全部企业可参与红包</div>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button type="primary" :loading="submitting" @click="submitForm">保存配置</el-button>
+          <el-button @click="resetForm">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import { getCourseRandomRedPacket, saveCourseRandomRedPacket } from '@/api/course/courseRandomRedPacket'
+import { allList } from '@/api/company/company'
+
+const defaultTier = () => ({ amount: 1.88, weight: 50 })
+
+export default {
+  name: 'CourseRandomRedPacket',
+  data() {
+    return {
+      loading: false,
+      submitting: false,
+      projectOptions: [],
+      companyOptions: [],
+      whitelistCompanyIds: [],
+      form: {
+        project: null,
+        enableRandom: false,
+        companyWhitelist: '',
+        tiers: [defaultTier()]
+      },
+      rules: {
+        project: [{ required: true, message: '请选择课程项目', trigger: 'change' }]
+      }
+    }
+  },
+  computed: {
+    totalWeight() {
+      return (this.form.tiers || []).reduce((sum, item) => sum + (Number(item.weight) || 0), 0)
+    }
+  },
+  created() {
+    this.getDicts('sys_course_project').then(response => {
+      this.projectOptions = response.data || []
+    })
+    allList().then(res => {
+      this.companyOptions = res.rows || []
+    })
+    if (this.$route.query.project) {
+      this.form.project = Number(this.$route.query.project)
+      this.loadConfig()
+    }
+  },
+  methods: {
+    handleProjectChange() {
+      if (this.form.project) {
+        this.loadConfig()
+      } else {
+        this.resetForm(false)
+      }
+    },
+    loadConfig() {
+      if (!this.form.project) {
+        return
+      }
+      this.loading = true
+      getCourseRandomRedPacket(this.form.project).then(res => {
+        const data = res.data
+        if (data) {
+          this.form.enableRandom = !!data.enableRandom
+          this.form.companyWhitelist = data.companyWhitelist || ''
+          this.form.tiers = (data.tiers && data.tiers.length)
+            ? data.tiers.map(item => ({
+              amount: Number(item.amount),
+              weight: Number(item.weight)
+            }))
+            : [defaultTier()]
+          this.parseWhitelist()
+        } else {
+          this.form.enableRandom = false
+          this.form.companyWhitelist = ''
+          this.form.tiers = [defaultTier()]
+          this.whitelistCompanyIds = []
+        }
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    parseWhitelist() {
+      const whitelist = (this.form.companyWhitelist || '').trim()
+      if (!whitelist || whitelist.toUpperCase() === 'ALL') {
+        this.whitelistCompanyIds = []
+        return
+      }
+      this.whitelistCompanyIds = whitelist.split(',').map(item => item.trim()).filter(Boolean)
+    },
+    buildWhitelist() {
+      if (!this.whitelistCompanyIds || this.whitelistCompanyIds.length === 0) {
+        return ''
+      }
+      return this.whitelistCompanyIds.join(',')
+    },
+    addTier() {
+      this.form.tiers.push({ amount: 1.88, weight: 10 })
+    },
+    removeTier(index) {
+      this.form.tiers.splice(index, 1)
+    },
+    resetForm(clearProject = true) {
+      if (clearProject) {
+        this.form.project = null
+      }
+      this.form.enableRandom = false
+      this.form.companyWhitelist = ''
+      this.form.tiers = [defaultTier()]
+      this.whitelistCompanyIds = []
+      this.$nextTick(() => {
+        if (this.$refs.form) {
+          this.$refs.form.clearValidate()
+        }
+      })
+    },
+    submitForm() {
+      this.$refs.form.validate(valid => {
+        if (!valid) {
+          return
+        }
+        if (this.form.enableRandom) {
+          if (this.totalWeight !== 100) {
+            this.$message.warning('权重总和必须为 100%')
+            return
+          }
+          if (!this.form.tiers.length) {
+            this.$message.warning('至少保留一个红包档位')
+            return
+          }
+        }
+        this.submitting = true
+        const payload = {
+          project: this.form.project,
+          enableRandom: this.form.enableRandom,
+          companyWhitelist: this.buildWhitelist(),
+          tiers: this.form.enableRandom ? this.form.tiers : []
+        }
+        saveCourseRandomRedPacket(payload).then(() => {
+          this.$message.success('保存成功')
+        }).finally(() => {
+          this.submitting = false
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.course-random-red-packet .card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+}
+
+.course-random-red-packet .title {
+  font-size: 18px;
+  font-weight: 600;
+  margin-bottom: 8px;
+}
+
+.course-random-red-packet .desc,
+.course-random-red-packet .tip {
+  color: #909399;
+  font-size: 13px;
+  line-height: 1.6;
+}
+
+.course-random-red-packet .tier-row {
+  display: flex;
+  align-items: flex-start;
+  flex-wrap: wrap;
+  gap: 8px;
+  margin-bottom: 8px;
+}
+
+.course-random-red-packet .unit {
+  margin-left: 8px;
+  color: #606266;
+}
+
+.course-random-red-packet .delete-btn {
+  margin-top: 6px;
+  color: #f56c6c;
+}
+
+.course-random-red-packet .weight-total {
+  margin-left: 16px;
+  color: #67c23a;
+  font-weight: 600;
+}
+
+.course-random-red-packet .weight-total.error {
+  color: #f56c6c;
+}
+</style>