YD_Event.Web/src/views/match/manage/Steps/Step3ProjectConfig.vue

232 lines
6.7 KiB
Vue
Raw Normal View History

2026-02-12 21:38:29 +08:00
<template>
2026-03-18 18:03:12 +08:00
<div class="step-config">
<el-form ref="formRef" :model="localFormData" :rules="rules" label-position="top">
<el-card shadow="never" style="margin-bottom: 16px">
<template #header>限报配置</template>
<el-row :gutter="12">
<el-col :span="12">
<el-form-item label="个人项目限报数" prop="registrationLimit.individualProjectLimit">
<el-input-number v-model="localFormData.registrationLimit.individualProjectLimit" :min="0" :step="1" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="团队项目限报数" prop="registrationLimit.teamProjectLimit">
<el-input-number v-model="localFormData.registrationLimit.teamProjectLimit" :min="0" :step="1" />
</el-form-item>
</el-col>
</el-row>
</el-card>
<el-card shadow="never">
<template #header>
<div style="display: flex; justify-content: space-between; align-items: center">
<span>项目配置</span>
<el-button type="primary" plain icon="ele-Plus" @click="addProject">新增项目</el-button>
</div>
</template>
<el-table :data="localFormData.projects" border stripe>
<el-table-column label="项目名称" min-width="180">
<template #default="{ row, $index }">
<el-form-item :prop="`projects.${$index}.name`" :rules="[{ required: true, message: '请输入项目名称', trigger: 'blur' }]" style="margin: 0">
<el-input v-model="row.name" placeholder="请输入项目名称" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="项目类型ID" width="120">
<template #default="{ row }">
<el-input-number v-model="row.projectTypeId" :min="0" :step="1" />
</template>
</el-table-column>
<el-table-column label="项目类型名" width="140">
<template #default="{ row }">
<el-input v-model="row.projectTypeName" placeholder="可不填" />
</template>
</el-table-column>
<el-table-column label="完成次数" width="120">
<template #default="{ row }">
<el-input-number v-model="row.completionCount" :min="0" :step="1" />
</template>
</el-table-column>
<el-table-column label="时长(分)" width="110">
<template #default="{ row }">
<el-input-number v-model="row.durationMinutes" :min="0" :step="1" />
</template>
</el-table-column>
<el-table-column label="时长(秒)" width="110">
<template #default="{ row }">
<el-input-number v-model="row.durationSeconds" :min="0" :max="59" :step="1" />
</template>
</el-table-column>
<el-table-column label="费用" width="110">
<template #default="{ row }">
<el-input-number v-model="row.fee" :min="0" :step="1" />
</template>
</el-table-column>
<el-table-column label="限报人数" width="110">
<template #default="{ row }">
<el-input-number v-model="row.limitCount" :min="0" :step="1" />
</template>
</el-table-column>
<el-table-column label="组别(简)" min-width="220">
<template #default="{ row }">
<el-input v-model="row.groupsText" placeholder="格式:组名|起始生日|结束生日|性别;多条用换行" type="textarea" :rows="2" />
</template>
</el-table-column>
<el-table-column label="操作" width="120" align="center">
<template #default="{ $index }">
<el-button text type="danger" icon="ele-Delete" @click="removeProject($index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</el-form>
</div>
2026-02-12 21:38:29 +08:00
</template>
<script setup>
2026-03-18 18:03:12 +08:00
import { ref, watch } from 'vue';
const props = defineProps({ modelValue: { type: Object, required: true } });
const emit = defineEmits(['update:modelValue']);
const formRef = ref(null);
const localFormData = ref({
projects: [],
registrationLimit: { individualProjectLimit: 1, teamProjectLimit: 1 },
});
const normalizeFromParent = (v) => {
localFormData.value.registrationLimit = v?.registrationLimit ?? { individualProjectLimit: 1, teamProjectLimit: 1 };
localFormData.value.projects = (v?.projects ?? []).map((p) => ({
...p,
// 用文本编辑组别,提交时再解析成 groups[]
groupsText: Array.isArray(p.groups)
? p.groups.map((g) => `${g.groupName}|${g.birthDateStart ?? ''}|${g.birthDateEnd ?? ''}|${g.gender ?? ''}`).join('\n')
: '',
}));
if (!localFormData.value.projects.length) addProject();
};
watch(
() => props.modelValue,
(v) => normalizeFromParent(v),
{ deep: true, immediate: true }
);
watch(
localFormData,
(v) => {
const projects = v.projects.map((p) => ({
id: p.id,
name: p.name,
projectTypeId: p.projectTypeId,
projectTypeName: p.projectTypeName,
completionCount: p.completionCount,
durationMinutes: p.durationMinutes,
durationSeconds: p.durationSeconds,
fee: p.fee,
limitCount: p.limitCount,
groups: (p.groupsText || '')
.split('\n')
.map((line) => line.trim())
.filter(Boolean)
.map((line) => {
const [groupName, birthDateStart, birthDateEnd, gender] = line.split('|').map((x) => (x ?? '').trim());
return { groupName, birthDateStart, birthDateEnd, gender };
}),
}));
emit('update:modelValue', { ...props.modelValue, registrationLimit: v.registrationLimit, projects });
},
{ deep: true }
);
const addProject = () => {
localFormData.value.projects.push({
name: '',
projectTypeId: 0,
projectTypeName: '',
completionCount: 0,
durationMinutes: 0,
durationSeconds: 0,
fee: 0,
limitCount: 0,
groupsText: '',
});
};
const removeProject = (idx) => localFormData.value.projects.splice(idx, 1);
const rules = {
'registrationLimit.individualProjectLimit': [{ required: true, message: '请填写个人项目限报数', trigger: 'change' }],
'registrationLimit.teamProjectLimit': [{ required: true, message: '请填写团队项目限报数', trigger: 'change' }],
};
2026-02-12 21:38:29 +08:00
const validate = async () => {
2026-03-18 18:03:12 +08:00
if (!formRef.value) return false;
return await formRef.value.validate();
};
2026-02-12 21:38:29 +08:00
2026-03-18 18:03:12 +08:00
defineExpose({ validate });
2026-02-12 21:38:29 +08:00
</script>
<style scoped>
.step-config {
padding: 0 20px;
}
.step-config .el-form-item {
margin-bottom: 24px;
}
.input-hint {
font-size: 12px;
color: #909399;
margin-top: 5px;
}
.switch-hint {
font-size: 12px;
color: #909399;
margin-top: 5px;
}
.type-info-card {
margin-top: 20px;
background: #f5f7fa;
}
.card-header {
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
}
.type-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.type-item {
display: flex;
align-items: center;
gap: 15px;
padding: 10px 15px;
background: #fff;
border-radius: 6px;
border: 1px solid #e4e7ed;
}
.type-name {
font-weight: 600;
color: #409eff;
min-width: 120px;
}
.type-desc {
color: #606266;
font-size: 14px;
}
</style>