1 Chinld Component
<template>
<div>
<a-button type="link" @click="showModal">选择模板</a-button>
<a-modal
width="400px"
v-model:open="visible"
title="选择模板"
@ok="handleOk"
>
<a-select
v-model:value="value"
:options="options"
mode="tags"
:size="size"
placeholder="Please select"
style="width: 200px"
></a-select>
</a-modal>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { SelectProps } from 'ant-design-vue'
import request from '@/utils/request'
const emit = defineEmits(['selectionData'])
const queryByPageUrl = '/api/list'
const value = ref<string[]>([])
const size = ref<SelectProps['size']>()
const options = ref<{ label: string
[]
)
const reqParams: { [key: string]: any } = {
pageNum: 1,
pageSize: 999,
status: 1,
}
const selectionData = ref<any>([])
const selectionOption = () =>
request
.post(queryByPageUrl, reqParams)
.then((res: any) => {
if (res.code === 200) {
const { data } = res
options.value = data.list?.map((item: any) => ({
label: item.title,
value: item.id,
templateNumber: item.templateNumber,
}))
}
})
.catch((error: any) => {
console.error('Error fetching data:', error)
})
const visible = ref(false)
const showModal = () => {
console.log('open selection modal')
visible.value = true
selectionOption()
}
const handleOk = () => {
console.log('selection value', value.value)
console.log('options', options.value)
visible.value = false
selectionData.value = options.value.filter((item: any) =>
value.value.includes(item.value)
)
console.log('selectionData', selectionData.value)
// Paraments passing
emit('selectionData', selectionData.value)
}
</script>
Parent Component
import { defineComponent, reactive, ref, nextTick, onMounted } from 'vue';
import Sortable from 'sortablejs';
import { getDrawConfig, saveDrawConfig } from './service';
import { DrawConfigInter, TemplateInter } from './interface';
import TemplateList from './TemplateList.vue';
import { message } from 'ant-design-vue';
import dayjs, { Dayjs } from 'dayjs';
import LottorySelection from './components/LottorySelection.vue';
export default defineComponent({
components: {
TemplateList,
LottorySelection,
},
setup() {
const formState = reactive<Partial<DrawConfigInter>>({
ruleName: '',
longTerm: true,
startTime: '',
endTime: '',
templateConfig: [],
winnerLimit: 0,
rewardType: 1,
rewardProperties: {
starValidityTimeUnit: '',
starValidityDuration: 0,
starCount: 0,
},
});
const pageType = ref<string>('detail');
const templateListItems = ref<Array<TemplateInter>>([]);
const dateRange = ref<Dayjs[]>([]);
const questionnaireTemplateRef = ref(null);
let sortableInstance: any = null;
const initSortable = () => {
const el = questionnaireTemplateRef.value;
if (el) {
sortableInstance = Sortable.create(el, {
animation: 150,
onEnd: (evt: any) => {
const { oldIndex, newIndex } = evt;
if (oldIndex !== null && newIndex !== null) {
const item = formState.templateConfig?.splice(oldIndex, 1)[0];
if (item) {
formState.templateConfig?.splice(newIndex, 0, item);
}
}
},
});
}
};
onMounted(async () => {
try {
const res: any = await getDrawConfig();
if (res.code === 200) {
const data = res.data as DrawConfigInter;
formState.ruleName = data.ruleName;
formState.longTerm = data.longTerm;
if (!data.longTerm) {
dateRange.value = [dayjs(data.startTime), dayjs(data.endTime)];
}
formState.templateConfig = data.templateConfig || [];
templateListItems.value = data.templateConfig || [];
formState.winnerLimit = data.winnerLimit;
formState.rewardType = data.rewardType;
// 确保 rewardProperties 存在且字段完整
formState.rewardProperties = {
...(data.rewardProperties || {}),
starValidityTimeUnit:
data.rewardProperties?.starValidityTimeUnit || '',
starValidityDuration:
data.rewardProperties?.starValidityDuration || 0,
starCount: data.rewardProperties?.starCount || 0,
};
}
} catch (error) {
console.error('Failed to fetch draw config:', error);
}
// 在接口数据加载完成后初始化可拖动功能
nextTick(() => {
initSortable();
});
});
const handleSubmit = async () => {
try {
const payload: Partial<DrawConfigInter> = {
ruleName: formState.ruleName,
longTerm: formState.longTerm,
startTime: dayjs(dateRange.value?.[0]).format(),
endTime: dayjs(dateRange.value?.[1]).format(),
templateConfig: templateListItems.value,
winnerLimit: formState.winnerLimit,
rewardType: formState.rewardType,
rewardProperties: formState.rewardProperties,
};
console.log('payload', payload);
const res: any = await saveDrawConfig(payload);
if (res.code === 200) {
message.success('保存成功');
} else {
message.error('保存失败');
}
} catch (error) {
console.error('Failed to save draw config:', error);
message.error('保存失败');
}
};
return {
pageType,
dateRange,
formState,
templateListItems,
questionnaireTemplateRef,
handleSubmit,
};
},
});
</script>
<template>
<div class="draw-config">
<a-form :model="formState" layout="vertical">
<a-form-item label="活动名称:" required>
<a-input v-model:value="formState.ruleName" />
</a-form-item>
<a-form-item label="活动有效期:" required>
<a-radio-group v-model:value="formState.longTerm">
<a-radio :value="true">长期有效</a-radio>
<a-radio :value="false">固定有效期</a-radio>
</a-radio-group>
<a-range-picker
v-if="formState.longTerm === false"
v-model:value="dateRange"
:placeholder="['开始日期', '结束日期']"
:rangeSeparator="'-'"
style="margin-top: 8px"
/>
</a-form-item>
<a-row>
<LottorySelection
ref="templateSelection"
// accept paramter from the chile component
@selectionData="(data) => {
console.log('processFormData', data);
data.map((item: any) => {
templateListItems.push({
title: item.label,
templateNumber: item.templateNumber,
});
});
}"
/>
</a-row>
<a-form-item label="参与抽奖问卷模版:" required>
<TemplateList
ref="compInfoRef"
:pageType="pageType"
:tableData="templateListItems"
/>
</a-form-item>
<a-form-item label="中奖数量配置:" required>
<a-input-number v-model:value="formState.winnerLimit" />
</a-form-item>
<a-form-item label="奖励类型:" required>
<a-radio-group v-model:value="formState.rewardType">
<a-radio :value="1">好礼星星</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item
label="好礼星星有效期:"
required
v-if="formState.rewardType === 1"
>
<a-select
v-model:value="formState.rewardProperties!.starValidityTimeUnit"
>
<a-select-option value="day">天</a-select-option>
<a-select-option value="month">月</a-select-option>
<a-select-option value="year">年</a-select-option>
</a-select>
<a-input-number
v-model:value="formState.rewardProperties!.starValidityDuration"
style="margin-left: 8px"
/>
</a-form-item>
<a-form-item
label="好礼星星数量:"
required
v-if="formState.rewardType === 1"
>
<a-input-number v-model:value="formState.rewardProperties!.starCount" />
</a-form-item>
<a-form-item>
<a-button type="primary" @click="handleSubmit">保存</a-button>
</a-form-item>
</a-form>
</div>
</template>
<style scoped>
.questionnaire-template-list {
list-style: none;
padding: 0;
}
.questionnaire-template-item {
display: flex;
align-items: center;
margin-bottom: 8px;
background-color: #f5f5f5;
padding: 4px 8px;
border-radius: 4px;
}
.drag-btn {
cursor: move;
margin-right: 10px;
}
</style>