| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567 |
- <template>
- <el-dialog
- title="积分活动"
- :visible.sync="pointsActivity"
- width="900px"
- :before-close="handleClose"
- custom-class="activity-edit-dialog">
- {{form}}
- <el-form :model="form" :rules="rules" ref="formRef" label-width="140px" class="activity-form">
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="活动名称" prop="name">
- <el-input v-model="form.name" placeholder="请输入活动名称" :disabled="type === 'view'"></el-input>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="活动简述" prop="description">
- <el-input v-model="form.description" placeholder="请输入活动简述" :disabled="type === 'view'"></el-input>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="活动城市" prop="cityCode">
- <DictSelect v-model="form.cityCode" :dictOptions="cityOptions" placeholder="请选择" :disabled="type === 'view'"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="活动类型" prop="activityType">
- <DictSelect v-model="form.activityType.toString()" :dictOptions="activityTypeOption" placeholder="请选择" :disabled="type === 'view'" @change="handleActivityTypeChange"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="活动时间" prop="isPermanent">
- <el-radio-group v-model="form.isPermanent" :disabled="type === 'view'">
- <el-radio :label="1">长期有效</el-radio>
- <el-radio :label="0">指定时间</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.isPermanent == '0'">
- <el-form-item label="指定时间" prop="dateRange">
- <el-date-picker
- v-model="form.dateRange"
- type="daterange"
- range-separator="→"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- style="width: 100%"
- :disabled="type === 'view'"
- :picker-options="pickerOptions"
- @change="handleDateChange"
- ></el-date-picker>
- </el-form-item>
- </el-col>
- </el-row>
- <!-- 签到活动特有的内容 -->
- <template v-if="form.activityType == '0'">
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="每日签到基础积分" prop="basePoints">
- <el-input v-model="form.basePoints" type="number" placeholder="请输入" :disabled="type === 'view'"></el-input>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="24">
- <el-form-item label="连续签到加成" prop="signRewardList">
- <el-table :data="form.signRewardList" style="width: 100%" :disabled="type === 'view'" size="mini">
- <el-table-column prop="continueDays" label="连续签到周期(天)">
- <template slot-scope="scope">
- <span v-if="type === 'view'">
- {{ scope.row.continueDays }}天
- </span>
- <el-input v-else v-model="scope.row.continueDays" type="number" placeholder="天数" @blur="updatePeriod(scope.$index, scope.row.continueDays)"></el-input>
- </template>
- </el-table-column>
- <el-table-column prop="rewardPoints" label="连续签到积分">
- <template slot-scope="scope">
- <span v-if="type === 'view'">
- {{ scope.row.rewardPoints }}
- </span>
- <el-input v-else v-model="scope.row.rewardPoints" type="number" placeholder="积分"></el-input>
- </template>
- </el-table-column>
- <el-table-column label="说明" width="280">
- <template slot-scope="scope">
- {{ getDescription(scope.$index) }}
- </template>
- </el-table-column>
- <el-table-column width="50">
- <template slot="header" slot-scope="scope">
- <span>
- <el-button v-if="type !== 'view' && form.signRewardList.length < 5" type="text" size="medium" @click="addPeriod" title="添加周期">
- <i class="el-icon-circle-plus-outline"></i>
- </el-button>
- </span>
- </template>
- <template slot-scope="scope">
- <el-button v-if="type !== 'view'" type="text" @click="deletePeriod(scope.$index)" title="删除周期">
- <i class="el-icon-remove-outline"></i>
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="断签规则">
- <el-radio-group v-model="form.breakRule.toString()" :disabled="type === 'view'">
- <el-radio label="0">
- 断签重置
- </el-radio>
- <el-radio label="1">
- 保留进度
- </el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- </el-row>
- </template>
- <!-- 其他活动类型的内容 -->
- <template v-else>
- <el-row :gutter="20">
- <el-col :span="24">
- <el-form-item label="任务列表" prop="activityTaskList">
- <el-table :data="form.activityTaskList" style="width: 100%" :disabled="type === 'view'" size="medium">
- <el-table-column prop="taskName" label="任务名称" width="150">
- <template slot-scope="scope">
- <span>{{ scope.row.taskName }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="triggerValue" label="触发条件" width="200">
- <template slot-scope="scope">
- <span v-if="type === 'view'">
- <span v-if="scope.row.taskName === '分享服务号' || scope.row.taskName === '浏览动态' || scope.row.taskName === '浏览商户'">
- 点击
- </span>
- <template v-else>
- <span style="margin-right: 5px;">>=</span> {{ scope.row.triggerValue }}
- </template>
- </span>
- <template v-else>
- <span v-if="scope.row.taskName === '分享服务号' || scope.row.taskName === '浏览动态' || scope.row.taskName === '浏览商户'">
- 点击
- </span>
- <span v-else style="display: flex; align-items: center;">
- <template v-if="scope.row.status == 0">
- <span style="margin-right: 5px;">>=</span>
- <el-input v-model="scope.row.triggerValue" type="number" placeholder="请输入" style="width: 80px"></el-input>
- </template>
- <span v-else>--</span>
- </span>
- </template>
- </template>
- </el-table-column>
- <el-table-column prop="rewardPoints" label="积分">
- <template slot-scope="scope">
- <span v-if="type === 'view'">{{ scope.row.rewardPoints }}</span>
- <template v-else>
- <el-input v-if="scope.row.status == 0" v-model="scope.row.rewardPoints" type="number" placeholder="请输入"></el-input>
- <span v-else>--</span>
- </template>
- </template>
- </el-table-column>
- <el-table-column prop="frequencyLimitValue" label="次数限制" width="120">
- <template slot-scope="scope">
- <span v-if="type === 'view'">{{ scope.row.frequencyLimitValue }}</span>
- <template v-else>
- <el-select v-if="scope.row.status == 0" v-model="scope.row.frequencyLimitValue" placeholder="请选择">
- <el-option label="无限制" value="无限制"></el-option>
- <el-option label="每日1次" value="每日1次"></el-option>
- <el-option label="每周1次" value="每周1次"></el-option>
- <el-option label="每月1次" value="每月1次"></el-option>
- </el-select>
- <span v-else>--</span>
- </template>
- </template>
- </el-table-column>
- <el-table-column label="是否开启" width="120">
- <template slot-scope="scope">
- <el-switch v-model="scope.row.status" active-value="0"
- inactive-value="1" :disabled="type === 'view'"></el-switch>
- </template>
- </el-table-column>
- </el-table>
- </el-form-item>
- </el-col>
- </el-row>
- </template>
- </el-form>
- <div class="button-container" v-if="type !== 'view'">
- <el-button @click="handleClose" class="cancel-btn">取消</el-button>
- <el-button @click="handleSaveDraft" class="cancel-btn">保存草稿</el-button>
- <el-button type="primary" @click="handlePublish" class="confirm-btn">发布</el-button>
- </div>
- <div class="button-container" v-else>
- <el-button type="primary" @click="handleClose" class="confirm-btn">关闭</el-button>
- </div>
- </el-dialog>
- </template>
- <script>
- import { getActivityById } from "@/api/points/rules_api";
- export default {
- name: "Activity_editBox",
- props: ['activityTypeOption', 'cityOptions'],
- data() {
- return {
- pointsActivity: false,
- type: '',
- minDate: null,
- form: {
- name: '',
- description: '',
- cityCode: '',
- activityType: '',
- isPermanent: '',
- startTime: '',
- endTime: '',
- dateRange: '',
- basePoints: '',
- signRewardList: [
- { continueDays: '3', rewardPoints: '' },
- ],
- breakRule: '0', // 0: 断签重置, 1: 保留进度
- activityTaskList: []
- },
- pickerOptions: {
- onPick: ({ maxDate, minDate }) => {
- if (minDate) {
- this.minDate = minDate;
- }
- if (maxDate) {
- this.minDate = null;
- }
- },
- disabledDate: (time) => {
- if (this.minDate) {
- const minTime = this.minDate.getTime();
- const sevenDaysLater = minTime + 6 * 24 * 60 * 60 * 1000; // 6天后(总共7天)
- return time.getTime() < minTime || (time.getTime() < sevenDaysLater && time.getTime() > minTime);
- }
- return false;
- }
- },
- rules: {
- name: [
- { required: true, message: '请输入活动名称', trigger: 'blur' },
- { min: 2, max: 18, message: '请输入2-18个字符', trigger: 'blur' }
- ],
- description: [
- { required: true, message: '请输入活动简述', trigger: 'blur' },
- { min: 2, max: 30, message: '请输入2-30个字符', trigger: 'blur' }
- ],
- cityCode: [
- { required: true, message: '请选择活动城市', trigger: 'change' }
- ],
- activityType: [
- { required: true, message: '请选择活动类型', trigger: 'change' }
- ],
- basePoints: [
- { required: true, message: '请输入基础积分', trigger: 'blur' },
- { validator: (rule, value, callback) => {
- if (Number(value) < 0) {
- callback(new Error('基础积分不能小于0'));
- } else {
- callback();
- }
- },
- trigger: 'blur'
- }
- ],
- signRewardList: [
- { validator: (rule, value, callback) => {
- if (!value || value.length === 0) {
- callback(new Error('请添加连续签到加成'));
- return;
- }
- for (let i = 0; i < value.length; i++) {
- const bonus = value[i];
- if (!bonus.period || Number(bonus.continueDays) <= 0) {
- callback(new Error('连续签到周期必须大于0'));
- return;
- }
- if (!bonus.rewardPoints || Number(bonus.rewardPoints) <= 0) {
- callback(new Error('连续签到积分必须大于0'));
- return;
- }
- }
- // 检查连续签到周期总和是否超过活动总天数
- const totalDays = this.getTotalDays();
- if (this.form.isPermanent == '0' && totalDays > 0) {
- const totalPeriod = value.reduce((sum, item) => sum + Number(item.continueDays), 0);
- if (totalPeriod > totalDays) {
- callback(new Error('连续签到周期总和不能超过活动总天数'));
- return;
- }
- }
- callback();
- },
- trigger: 'change'
- }
- ],
- dateRange: [
- { required: true, message: '请选择活动时间', trigger: 'change' }
- ],
- activityTaskList: [
- { validator: (rule, value, callback) => {
- for (let i = 0; i < value.length; i++) {
- const task = value[i];
- // 只在任务开启的情况下才校验
- if (task.status == '0') {
- // 验证完成订单和充值任务的触发条件
- if ((task.taskName === '完成订单' || task.taskName === '充值任务') && (!task.triggerValue || Number(task.triggerValue) <= 0)) {
- callback(new Error('触发条件必须大于0'));
- return;
- }
- // 验证所有任务的积分
- if (!task.rewardPoints || Number(task.rewardPoints) <= 0) {
- callback(new Error('积分必须大于0'));
- return;
- }
- }
- }
- callback();
- },
- trigger: 'change'
- }
- ]
- },
- }
- },
- methods: {
- async getActivityInfo(row) {
- const res = await getActivityById({id: row.id});
- return res.data.detail;
- },
- getDefaultTasks() {
- return [
- { taskName: '完成订单', triggerValue: '', rewardPoints: '', frequencyLimitValue: '无限制', status: '1' },
- { taskName: '充值任务', triggerValue: '', rewardPoints: '', frequencyLimitValue: '无限制', status: '1' },
- { taskName: '分享服务号', triggerValue: '点击', rewardPoints: '', frequencyLimitValue: '无限制', status: '1' },
- { taskName: '浏览动态', triggerValue: '点击', rewardPoints: '', frequencyLimitValue: '无限制', status: '1' },
- { taskName: '浏览商户', triggerValue: '点击', rewardPoints: '', frequencyLimitValue: '无限制', status: '1' }
- ];
- },
- getTotalDays() {
- if (this.form.isPermanent == '0' && this.form.startTime && this.form.endTime) {
- const start = new Date(this.form.startTime);
- const end = new Date(this.form.endTime);
- return Math.floor((end - start) / (1000 * 60 * 60 * 24)) + 1;
- }
- return 0;
- },
- async getRow(row, type) {
- /** type ==== 添加:add 复制:copy 编辑:edit 查看:view */
- this.type = type;
- this.resetForm();
- if (type !== 'add') {
- const data = await this.getActivityInfo(row);
- this.form = type === 'copy' ? {...data, id: ''} : {...data};
- this.form.dateRange = [this.form.startTime, this.form.endTime];
- }
- this.pointsActivity = true;
- },
- handleClose() {
- this.pointsActivity = false;
- },
- resetForm() {
- this.form = {
- name: '',
- description: '',
- cityCode: '',
- activityType: '0',
- isPermanent: '1',
- startTime: '',
- endTime: '',
- dateRange: '',
- basePoints: '',
- signRewardList: [
- { continueDays: '3', rewardPoints: '' },
- ],
- breakRule: '0',
- activityTaskList: this.getDefaultTasks()
- };
- },
- handleDateChange(val) {
- if (val) {
- this.form.startTime = val[0];
- this.form.endTime = val[1];
- } else {
- this.form.startTime = '';
- this.form.endTime = '';
- }
- this.handleActivityTypeChange();
- },
- deletePeriod(index) {
- if (this.form.signRewardList.length <= 1) {
- this.$message.warning('至少保留一个连续签到周期');
- return;
- }
- this.form.signRewardList.splice(index, 1);
- },
- handleActivityTypeChange() {
- // 重置相关内容
- if (this.form.activityType == '0') {
- // 签到活动
- this.form.basePoints = '';
- this.form.signRewardList = [
- { continueDays: '3', rewardPoints: ''},
- ];
- this.form.breakRule = '0';
- } else {
- // 其他活动
- this.form.activityTaskList = this.getDefaultTasks();
- }
- },
- addPeriod() {
- const totalDays = this.getTotalDays();
- const currentTotalPeriod = this.form.signRewardList.reduce((sum, item) => {
- return sum + (Number(item.continueDays) || 0);
- }, 0);
- if (this.form.isPermanent == '0' && totalDays > 0 && currentTotalPeriod >= totalDays) {
- this.$message.warning('连续签到周期总和不能超过活动总天数');
- return;
- }
- this.form.signRewardList.push({
- continueDays: '',
- rewardPoints: ''
- });
- },
- updatePeriod(index, value) {
- // 触发表单验证
- this.$refs.formRef.validateField('signRewardList');
- },
- getDescription(index) {
- let totalPeriodDays = 0;
- let totalPoints = 0;
- for (let i = 0; i <= index; i++) {
- totalPeriodDays += Number(this.form.signRewardList[i].continueDays) || 0;
- totalPoints += Number(this.form.signRewardList[i].rewardPoints) || 0;
- }
- const basePoints = Number(this.form.basePoints) || 0;
- const finalPoints = totalPoints + basePoints;
- if (!totalPeriodDays || !finalPoints) {
- return '--';
- }
- return `连续签到 ${totalPeriodDays} 天后,继续签到可获得 ${finalPoints} 积分`;
- },
- validateForm(callback) {
- this.$refs.formRef.validate((valid) => {
- if (valid) {
- callback();
- }
- });
- },
- handleSaveDraft() {
- this.validateForm(() => {
- console.log('Form内容:', this.form);
- this.$message.success('草稿已保存');
- this.pointsActivity = false;
- });
- },
- handlePublish() {
- this.validateForm(() => {
- this.$message.success('活动已发布');
- this.pointsActivity = false;
- });
- }
- }
- }
- </script>
- <style scoped lang="scss">
- .activity-edit-dialog {
- .el-dialog__header {
- padding: 20px;
- border-bottom: 1px solid #e8e8e8;
- .el-dialog__title {
- font-size: 16px;
- font-weight: 600;
- color: #303133;
- }
- }
- .el-dialog__body {
- padding: 25px;
- }
- .el-dialog__footer {
- padding: 15px 20px;
- border-top: 1px solid #e8e8e8;
- }
- }
- .activity-form {
- .form-tip {
- font-size: 12px;
- color: #f56c6c;
- margin-top: 5px;
- }
- .el-form-item {
- margin-bottom: 20px;
- }
- .el-table {
- margin-top: 10px;
- border: 1px solid #ebeef5;
- border-radius: 4px;
- }
- .el-table__header-wrapper {
- background-color: #f5f7fa;
- }
- .el-table th {
- font-weight: 600;
- }
- }
- .button-container {
- display: flex;
- justify-content: flex-end;
- margin-top: 30px;
- .cancel-btn {
- margin-right: 10px;
- }
- .confirm-btn {
- min-width: 100px;
- }
- }
- /* 隐藏number输入框的上下小按钮 */
- ::v-deep input[type="number"]::-webkit-inner-spin-button,
- ::v-deep input[type="number"]::-webkit-outer-spin-button {
- -webkit-appearance: none;
- margin: 0;
- }
- ::v-deep input[type="number"] {
- -moz-appearance: textfield;
- }
- </style>
|