|
|
@@ -4,136 +4,88 @@
|
|
|
<div class="text-lg font-bold mb-6">降价营销规则</div>
|
|
|
<div class="flex">
|
|
|
<div class="flex-1 max-w-3xl">
|
|
|
- <el-form
|
|
|
- :model="form"
|
|
|
- label-width="200px"
|
|
|
- class="rules-form"
|
|
|
- v-loading="loading"
|
|
|
- >
|
|
|
+ <el-form :model="form" label-width="200px" class="rules-form" v-loading="loading">
|
|
|
<el-form-item label="分享一人降价比例:">
|
|
|
<div class="flex items-center">
|
|
|
- <el-input-number
|
|
|
- v-model="form.shareRatio"
|
|
|
- :min="0"
|
|
|
- :max="100"
|
|
|
- />
|
|
|
+ <el-input-number v-model="form.reduceRate" :min="0" :max="100" />
|
|
|
<span class="ml-2">(%)</span>
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="降价限制时间:">
|
|
|
<div class="flex items-center">
|
|
|
- <el-input-number
|
|
|
- v-model="form.limitTime"
|
|
|
- :min="0"
|
|
|
- />
|
|
|
+ <el-input-number v-model="form.inviteExpireHour" :min="0" />
|
|
|
<span class="ml-2">(小时)</span>
|
|
|
- <span class="ml-4 text-gray-400"
|
|
|
- >以助力成功计算</span
|
|
|
- >
|
|
|
+ <span class="ml-4 text-gray-400">以助力成功计算</span>
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="每单每本书可降价次数:">
|
|
|
<div class="flex items-center">
|
|
|
- <el-input-number
|
|
|
- v-model="form.discountTimesPerBook"
|
|
|
- :min="0"
|
|
|
- />
|
|
|
+ <el-input-number v-model="form.reduceTimesPerIsbn" :min="0" />
|
|
|
<span class="ml-2">(次)</span>
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="每个ID每天助力限制:">
|
|
|
<div class="flex items-center">
|
|
|
- <el-input-number
|
|
|
- v-model="form.assistLimitPerDay"
|
|
|
- :min="0"
|
|
|
- />
|
|
|
+ <el-input-number v-model="form.assistTimesEveryDay" :min="0" />
|
|
|
<span class="ml-2">(次)</span>
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="分享一人最高降价:">
|
|
|
<div class="flex items-center">
|
|
|
- <el-input-number
|
|
|
- v-model="form.maxDiscountPerShare"
|
|
|
- :min="0"
|
|
|
- :precision="2"
|
|
|
- />
|
|
|
+ <el-input-number v-model="form.maxPerHelp" :min="0" :precision="2" />
|
|
|
<span class="ml-2">(元)</span>
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="分享一人最低降价:">
|
|
|
<div class="flex items-center">
|
|
|
- <el-input-number
|
|
|
- v-model="form.minDiscountPerShare"
|
|
|
- :min="0"
|
|
|
- :precision="2"
|
|
|
- />
|
|
|
+ <el-input-number v-model="form.minPerHelp" :min="0" :precision="2" />
|
|
|
<span class="ml-2">(元)</span>
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="降价取消场景:">
|
|
|
<div class="flex items-center w-full">
|
|
|
- <el-select
|
|
|
- v-model="form.cancelScenarios"
|
|
|
- multiple
|
|
|
- placeholder="请选择"
|
|
|
- style="width: 300px"
|
|
|
- >
|
|
|
- <el-option
|
|
|
- label="订单退款"
|
|
|
- value="refund"
|
|
|
- />
|
|
|
- <el-option
|
|
|
- label="订单取消"
|
|
|
- value="cancel"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
+ <dict-data v-model="form.upsellValidScenario" code="upsell_valid_scenario"
|
|
|
+ type="multipleSelect" style="width:300px" />
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="预留手机号:">
|
|
|
<div class="flex items-center">
|
|
|
- <el-input
|
|
|
- v-model="form.mobile"
|
|
|
- placeholder="请输入手机号"
|
|
|
- style="width: 200px"
|
|
|
- />
|
|
|
+ <el-input v-model="form.mobile" placeholder="请输入手机号" style="width: 300px" />
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="验证码:" v-if="needVerification">
|
|
|
+ <div class="flex items-center">
|
|
|
+ <el-input v-model="form.code" placeholder="请输入验证码" style="width: 200px" />
|
|
|
+ <el-button type="primary" link class="ml-4" @click="handleResendCode"
|
|
|
+ :disabled="cooldown > 0">
|
|
|
+ {{ cooldown > 0 ? `${cooldown}秒后重发` : '获取验证码' }}
|
|
|
+ </el-button>
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="营销降价书单:">
|
|
|
<div class="flex items-center">
|
|
|
- <el-select
|
|
|
- v-model="form.booklistId"
|
|
|
- placeholder="请选择书单"
|
|
|
- style="width: 300px"
|
|
|
- >
|
|
|
- <el-option
|
|
|
- label="营销书单降价"
|
|
|
- value="1"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
+ <dict-data v-model="form.reduceScope" code="reduce_scope" style="width:300px" />
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item>
|
|
|
- <el-button type="primary" :loading="saving" @click="handleSave"
|
|
|
- >保存</el-button
|
|
|
- >
|
|
|
+ <el-button type="primary" :loading="saving" @click="handleSave">保存</el-button>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
</div>
|
|
|
|
|
|
<!-- Right Side Note -->
|
|
|
<div class="w-64 ml-8">
|
|
|
- <div
|
|
|
- class="bg-yellow-50 border border-yellow-200 p-4 rounded text-sm text-gray-600"
|
|
|
- >
|
|
|
+ <div class="bg-yellow-50 border border-yellow-200 p-4 rounded text-sm text-gray-600">
|
|
|
<p class="mb-2 font-bold">注意事项:</p>
|
|
|
<p class="mb-2">单本金额不能为负,最低为0</p>
|
|
|
<p>
|
|
|
@@ -147,7 +99,7 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
- import { reactive, ref, onMounted } from 'vue';
|
|
|
+ import { reactive, ref, onMounted, onUnmounted } from 'vue';
|
|
|
import { EleMessage } from 'ele-admin-plus/es';
|
|
|
import request from '@/utils/request';
|
|
|
|
|
|
@@ -155,40 +107,114 @@
|
|
|
|
|
|
const loading = ref(false);
|
|
|
const saving = ref(false);
|
|
|
+ const needVerification = ref(false);
|
|
|
+ const cooldown = ref(0);
|
|
|
+ let timer = null;
|
|
|
|
|
|
const form = reactive({
|
|
|
- shareRatio: 10,
|
|
|
- limitTime: 24,
|
|
|
- discountTimesPerBook: 3,
|
|
|
- assistLimitPerDay: 1,
|
|
|
- maxDiscountPerShare: 3,
|
|
|
- minDiscountPerShare: 0.5,
|
|
|
- cancelScenarios: ['refund', 'cancel'],
|
|
|
- mobile: '18888888888',
|
|
|
- booklistId: '1'
|
|
|
+ reduceRate: void 0,
|
|
|
+ inviteExpireHour: void 0,
|
|
|
+ reduceTimesPerIsbn: void 0,
|
|
|
+ assistTimesEveryDay: void 0,
|
|
|
+ maxPerHelp: void 0,
|
|
|
+ minPerHelp: void 0,
|
|
|
+ upsellValidScenario: [],
|
|
|
+ mobile: '',
|
|
|
+ reduceScope: void 0,
|
|
|
+ code: ''
|
|
|
});
|
|
|
|
|
|
+ const startCooldown = () => {
|
|
|
+ cooldown.value = 60;
|
|
|
+ if (timer) clearInterval(timer);
|
|
|
+ timer = setInterval(() => {
|
|
|
+ if (cooldown.value > 0) {
|
|
|
+ cooldown.value--;
|
|
|
+ } else {
|
|
|
+ clearInterval(timer);
|
|
|
+ timer = null;
|
|
|
+ }
|
|
|
+ }, 1000);
|
|
|
+ };
|
|
|
+
|
|
|
const fetchRules = async () => {
|
|
|
loading.value = true;
|
|
|
try {
|
|
|
- const res = await request.get('/marketing/shareDiscount/rules/detail');
|
|
|
- Object.assign(form, res.data);
|
|
|
+ const res = await request.get('/activity/reduce/manage/rule/get');
|
|
|
+ if (res.data.code === 0 || res.data.code === 200) {
|
|
|
+ const data = res.data.data;
|
|
|
+ Object.assign(form, data);
|
|
|
+ form.upsellValidScenario = data.upsellValidScenario.map(v => v.toString());
|
|
|
+ form.reduceScope = data.reduceScope?.toString();
|
|
|
+ if(form.mobile){
|
|
|
+ needVerification.value = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
} catch (error) {
|
|
|
- // Mock data if API fails
|
|
|
- console.log('Using mock data for rules');
|
|
|
+ console.error(error);
|
|
|
} finally {
|
|
|
loading.value = false;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ const updateRule = async () => {
|
|
|
+ try {
|
|
|
+ const res = await request.post('/activity/reduce/manage/rule/update', form);
|
|
|
+ if (res.data.code === 0 || res.data.code === 200) {
|
|
|
+ EleMessage.success('保存成功');
|
|
|
+ form.code = '';
|
|
|
+ } else {
|
|
|
+ EleMessage.error(res.data.msg || '保存失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error);
|
|
|
+ EleMessage.error('保存失败');
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleResendCode = async () => {
|
|
|
+ try {
|
|
|
+ const res = await request.post('/activity/reduce/manage/rule/getCode');
|
|
|
+ if (res.data.code === 0 || res.data.code === 200) {
|
|
|
+ if (res.data.data === 1) {
|
|
|
+ EleMessage.success('验证码已发送');
|
|
|
+ startCooldown();
|
|
|
+ } else {
|
|
|
+ EleMessage.info('无需验证码');
|
|
|
+ needVerification.value = false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ EleMessage.error(res.data.msg || '获取验证码失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error);
|
|
|
+ EleMessage.error('获取验证码失败');
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
const handleSave = async () => {
|
|
|
saving.value = true;
|
|
|
try {
|
|
|
- await request.post('/marketing/shareDiscount/rules/update', form);
|
|
|
- EleMessage.success('保存成功');
|
|
|
+ if (form.code) {
|
|
|
+ await updateRule();
|
|
|
+ } else {
|
|
|
+ // Check if verification is needed
|
|
|
+ const res = await request.post('/activity/reduce/manage/rule/getCode');
|
|
|
+ if (res.data.code === 0 || res.data.code === 200) {
|
|
|
+ if (res.data.data === 1) {
|
|
|
+ needVerification.value = true;
|
|
|
+ EleMessage.success('验证码已发送,请输入验证码');
|
|
|
+ startCooldown();
|
|
|
+ } else {
|
|
|
+ await updateRule();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ EleMessage.error(res.data.msg || '获取验证码失败');
|
|
|
+ }
|
|
|
+ }
|
|
|
} catch (error) {
|
|
|
- // Mock success
|
|
|
- EleMessage.success('保存成功 (Mock)');
|
|
|
+ console.error(error);
|
|
|
+ EleMessage.error('操作失败');
|
|
|
} finally {
|
|
|
saving.value = false;
|
|
|
}
|
|
|
@@ -197,6 +223,13 @@
|
|
|
onMounted(() => {
|
|
|
fetchRules();
|
|
|
});
|
|
|
+
|
|
|
+ onUnmounted(() => {
|
|
|
+ if (timer) {
|
|
|
+ clearInterval(timer);
|
|
|
+ timer = null;
|
|
|
+ }
|
|
|
+ });
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|