This commit is contained in:
aaron 2025-03-16 00:10:38 +08:00
parent 3731b0efff
commit bb4d562346
2 changed files with 286 additions and 168 deletions

View File

@ -48,7 +48,8 @@
@ok="handleSubmit"
@cancel="handleCancel"
:confirmLoading="submitting"
width="720px"
width="800px"
class="coupon-activity-modal"
>
<a-form
ref="formRef"
@ -57,6 +58,7 @@
layout="vertical"
class="coupon-activity-form"
>
<a-card :bordered="false" class="form-card">
<a-form-item
label="活动名称"
name="name"
@ -69,20 +71,7 @@
/>
</a-form-item>
<a-form-item
label="活动说明"
name="description"
>
<a-textarea
v-model:value="formState.description"
placeholder="请输入活动说明"
:rows="2"
:maxLength="200"
:auto-size="{ minRows: 2, maxRows: 3 }"
/>
</a-form-item>
<a-row :gutter="16">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item
label="活动开始时间"
@ -115,7 +104,7 @@
</a-col>
</a-row>
<a-row :gutter="16">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item
label="每日开始时间"
@ -146,7 +135,7 @@
</a-col>
</a-row>
<a-row :gutter="16">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item
label="总限领数量"
@ -163,15 +152,15 @@
</a-col>
<a-col :span="12">
<a-form-item
label="每日限领数量"
name="daily_limit"
:rules="[{ required: true, message: '请输入每日限领数量' }]"
label="用户可领次数限制"
name="user_limit"
:rules="[{ required: true, message: '请输入用户可领次数限制' }]"
>
<a-input-number
v-model:value="formState.daily_limit"
v-model:value="formState.user_limit"
:min="1"
style="width: 100%"
placeholder="请输入每日限领数量"
placeholder="请输入用户可领次数限制"
/>
</a-form-item>
</a-col>
@ -182,26 +171,42 @@
name="coupon_config"
:rules="[{ required: true, message: '请至少选择一个优惠券' }]"
>
<div class="coupon-table-container">
<a-table
:columns="couponColumns"
:data-source="couponTemplates"
:pagination="false"
size="small"
:scroll="{ y: 180 }"
:scroll="{ y: 240 }"
:rowClassName="(record) => isSelectedCoupon(record.id) ? 'selected-coupon-row' : ''"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'selected'">
<a-checkbox
:checked="isSelectedCoupon(record.id)"
@change="(e) => handleCouponSelect(record.id, e.target.checked)"
/>
</template>
<template v-if="column.key === 'type'">
<a-tag :color="record.coupon_type === 'CASH' ? 'green' : 'blue'">
{{ record.coupon_type === 'CASH' ? '现金券' : '商品券' }}
</a-tag>
</template>
<template v-if="column.key === 'amount'">
{{ record.amount }}
<span v-if="record.coupon_type === 'CASH'">{{ record.amount }}</span>
<span v-else>-</span>
</template>
<template v-if="column.key === 'quantity'">
<a-input-number
v-model:value="formState.coupon_config[record.id]"
:min="0"
size="small"
:disabled="!isSelectedCoupon(record.id)"
/>
</template>
</template>
</a-table>
</div>
</a-form-item>
<a-form-item
@ -209,7 +214,9 @@
name="is_active"
>
<a-switch v-model:checked="formState.is_active" />
<span class="status-label">{{ formState.is_active ? '启用' : '禁用' }}</span>
</a-form-item>
</a-card>
</a-form>
</a-modal>
</div>
@ -227,7 +234,10 @@ import {
Input,
InputNumber,
Switch,
Table
Table,
Checkbox,
Card,
Divider
} from 'ant-design-vue'
import PageContainer from '@/components/PageContainer.vue'
import dayjs from 'dayjs'
@ -244,7 +254,10 @@ export default defineComponent({
ATextarea: Input.TextArea,
AInputNumber: InputNumber,
ASwitch: Switch,
ATable: Table
ATable: Table,
ACheckbox: Checkbox,
ACard: Card,
ADivider: Divider
},
setup() {
@ -291,9 +304,9 @@ export default defineComponent({
width: 120
},
{
title: '每日限领',
dataIndex: 'daily_limit',
key: 'daily_limit',
title: '用户可领次数',
dataIndex: 'user_limit',
key: 'user_limit',
width: 100,
align: 'center'
},
@ -383,17 +396,30 @@ export default defineComponent({
daily_start_time: null,
daily_end_time: null,
total_limit: undefined,
daily_limit: 1,
user_limit: 1,
coupon_config: {},
selected_coupons: [],
is_active: true
})
const couponColumns = [
{
title: '选择',
key: 'selected',
width: 60,
align: 'center'
},
{
title: '模板名称',
dataIndex: 'name',
key: 'name'
},
{
title: '券类型',
key: 'type',
width: 100,
align: 'center'
},
{
title: '优惠金额',
key: 'amount',
@ -420,6 +446,28 @@ export default defineComponent({
}
}
//
const isSelectedCoupon = (couponId) => {
return formState.value.selected_coupons.includes(couponId);
}
//
const handleCouponSelect = (couponId, checked) => {
if (checked) {
//
if (!isSelectedCoupon(couponId)) {
formState.value.selected_coupons.push(couponId);
// 1
if (!formState.value.coupon_config[couponId]) {
formState.value.coupon_config[couponId] = 1;
}
}
} else {
//
formState.value.selected_coupons = formState.value.selected_coupons.filter(id => id !== couponId);
}
}
//
const showAddModal = async () => {
isEdit.value = false
@ -432,8 +480,9 @@ export default defineComponent({
daily_start_time: null,
daily_end_time: null,
total_limit: undefined,
daily_limit: 1,
user_limit: 1,
coupon_config: {},
selected_coupons: [],
is_active: true
}
await fetchCouponTemplates()
@ -451,9 +500,12 @@ export default defineComponent({
// 0
const couponConfig = {}
const selectedCoupons = []
Object.entries(record.coupon_config || {}).forEach(([key, value]) => {
if (value && value > 0) {
couponConfig[key] = value
selectedCoupons.push(parseInt(key))
}
})
@ -466,8 +518,9 @@ export default defineComponent({
daily_start_time: dayjs(record.daily_start_time, 'HH:mm:ss'),
daily_end_time: dayjs(record.daily_end_time, 'HH:mm:ss'),
total_limit: record.total_limit,
daily_limit: record.daily_limit,
user_limit: record.user_limit,
coupon_config: couponConfig,
selected_coupons: selectedCoupons,
is_active: record.is_active
}
@ -483,11 +536,12 @@ export default defineComponent({
formRef.value.validate().then(async () => {
try {
submitting.value = true
//
//
const couponConfig = {}
Object.entries(formState.value.coupon_config).forEach(([key, value]) => {
if (value && value > 0) {
couponConfig[key] = value
formState.value.selected_coupons.forEach(couponId => {
const quantity = formState.value.coupon_config[couponId]
if (quantity && quantity > 0) {
couponConfig[couponId] = quantity
}
})
@ -500,6 +554,9 @@ export default defineComponent({
daily_end_time: dayjs(formState.value.daily_end_time).format('HH:mm:ss')
}
//
delete params.selected_coupons
let res
if (isEdit.value) {
res = await request.put(`/api/coupon-activities/${currentId.value}`, params)
@ -617,7 +674,9 @@ export default defineComponent({
disabledEndDate,
disabledDailyStartTime,
disabledDailyEndTime,
handleEdit
handleEdit,
isSelectedCoupon,
handleCouponSelect
}
}
})
@ -645,7 +704,7 @@ export default defineComponent({
}
.coupon-activity-form :deep(.ant-form-item) {
margin-bottom: 16px !important;
margin-bottom: 24px !important;
}
.coupon-activity-form :deep(.ant-form-item:last-child) {
@ -692,11 +751,66 @@ export default defineComponent({
}
.coupon-activity-form :deep(.ant-row) {
margin-bottom: 0 !important;
margin-bottom: 8px !important;
}
/* 调整表格高度 */
.coupon-activity-form :deep(.ant-table-body) {
max-height: 200px !important;
}
/* 选中的优惠券行样式 */
:deep(.selected-coupon-row) {
background-color: #e6f7ff;
}
:deep(.selected-coupon-row:hover) {
background-color: #cceeff !important;
}
/* 新增样式 - 优化模态框 */
.coupon-activity-modal {
:deep(.ant-modal-body) {
padding: 16px;
}
:deep(.ant-modal-footer) {
border-top: 1px solid #f0f0f0;
padding: 10px 24px;
}
}
.form-card {
box-shadow: none !important;
:deep(.ant-card-body) {
padding: 0;
}
}
.coupon-activity-form :deep(.ant-divider) {
margin: 16px 0;
color: #1890ff;
font-weight: 500;
}
.coupon-activity-form :deep(.ant-divider-inner-text) {
font-size: 14px;
}
.coupon-table-container {
border: 1px solid #f0f0f0;
border-radius: 4px;
padding: 0;
margin-top: 8px;
}
.status-label {
margin-left: 8px;
color: rgba(0, 0, 0, 0.65);
}
.coupon-activity-form :deep(.ant-card) {
background: transparent;
}
</style>

View File

@ -109,7 +109,11 @@ export default defineComponent({
const handleSubmit = async (values) => {
try {
loading.value = true
const res = await request.post('/api/user/password-login', values)
const params = {
...values,
role: formState.role
}
const res = await request.post('/api/user/password-login', params)
if (res.code === 200) {
localStorage.setItem('token', res.data.access_token)