赛事详情
This commit is contained in:
parent
c3f8796c88
commit
ecec637f05
@ -44,24 +44,33 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="赛事类型" prop="eventType">
|
||||
<el-select v-model="localFormData.eventType" placeholder="请选择赛事类型" style="width: 100%" :disabled="readonly">
|
||||
<el-select v-if="!readonly" v-model="localFormData.eventType" placeholder="请选择赛事类型" style="width: 100%">
|
||||
<el-option label="线上" :value="0" />
|
||||
<el-option label="线下" :value="1" />
|
||||
</el-select>
|
||||
<span v-else>
|
||||
{{ localFormData.eventType === 0 ? '线上' : localFormData.eventType === 1 ? '线下' : '-' }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="报名方式" prop="registrationType">
|
||||
<el-radio-group v-model="localFormData.registrationType" :disabled="readonly">
|
||||
<el-radio-group v-if="!readonly" v-model="localFormData.registrationType" :disabled="readonly">
|
||||
<el-radio :label="0">个人报名</el-radio>
|
||||
<el-radio :label="1">团队报名</el-radio>
|
||||
<el-radio :label="2">个人/团队报名</el-radio>
|
||||
</el-radio-group>
|
||||
<span v-else>
|
||||
{{ localFormData.registrationType === 0 ? '个人报名' : localFormData.registrationType === 1 ? '团队报名' : localFormData.registrationType === 2 ? '个人/团队报名' : '-' }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="积分发放规则" prop="pointsRuleId">
|
||||
<el-select v-model="localFormData.pointsRuleId" placeholder="请选择积分发放规则" filterable style="width: 100%" :disabled="readonly">
|
||||
<el-select v-if="!readonly" v-model="localFormData.pointsRuleId" placeholder="请选择积分发放规则" filterable style="width: 100%">
|
||||
<el-option v-for="r in pointsRuleOptions" :key="r.value" :label="r.label" :value="r.value" />
|
||||
</el-select>
|
||||
<span v-else>
|
||||
{{ localFormData.pointsRuleName || '-' }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 报名起止时间 -->
|
||||
@ -89,19 +98,22 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="赛事地址(省/市/区)" prop="regionIds">
|
||||
<div style="display: flex; gap: 8px ;width: 90%;">
|
||||
<div v-if="!readonly" style="display: flex; gap: 8px ;width: 90%;">
|
||||
<el-select v-model="localFormData.regionIds[0]" placeholder="请选择省份" style="flex: 1"
|
||||
@change="handleProvinceChange" clearable :disabled="readonly">
|
||||
@change="handleProvinceChange" clearable>
|
||||
<el-option v-for="p in provinces" :key="p.id" :label="p.name" :value="p.code" />
|
||||
</el-select>
|
||||
<el-select v-model="localFormData.regionIds[1]" placeholder="请选择城市" style="flex: 1"
|
||||
@change="handleCityChange" clearable :disabled="readonly">
|
||||
@change="handleCityChange" clearable>
|
||||
<el-option v-for="c in cities" :key="c.id" :label="c.name" :value="c.code" />
|
||||
</el-select>
|
||||
<el-select v-model="localFormData.regionIds[2]" placeholder="请选择区县" style="flex: 1" clearable :disabled="readonly">
|
||||
<el-select v-model="localFormData.regionIds[2]" placeholder="请选择区县" style="flex: 1" clearable>
|
||||
<el-option v-for="d in districts" :key="d.id" :label="d.name" :value="d.code" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div v-else>
|
||||
{{ [localFormData.provinceName, localFormData.cityName, localFormData.districtName].filter(x => x).join(' / ') || '-' }}
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="详细地址" prop="detailAddress">
|
||||
@ -138,8 +150,12 @@ const localFormData = ref({
|
||||
coverImage: '',
|
||||
eventVideo: '',
|
||||
eventType: undefined, // 0/1
|
||||
registrationType: '', // OnlyIndividual/OnlyTeam/Both
|
||||
registrationType: undefined, // 0/1/2
|
||||
pointsRuleId: undefined,
|
||||
pointsRuleName: '',
|
||||
provinceName: '',
|
||||
cityName: '',
|
||||
districtName: '',
|
||||
registrationTime: [],
|
||||
isNeedMaterial: false,
|
||||
materialRemark: '',
|
||||
@ -162,10 +178,15 @@ watch(
|
||||
if(k === 'regionIds' && Array.isArray(v[k])) {
|
||||
// 确保 regionIds 是长度为 3 的数组
|
||||
for(let i = 0; i < 3; i++) {
|
||||
if (v[k][i] !== undefined) localFormData.value.regionIds[i] = v[k][i].toString();
|
||||
if (v[k][i] !== undefined) localFormData.value.regionIds[i] = v[k][i] !== null ? v[k][i].toString() : undefined;
|
||||
}
|
||||
}
|
||||
});
|
||||
// 确保新字段也被赋值
|
||||
if (v.pointsRuleName !== undefined) localFormData.value.pointsRuleName = v.pointsRuleName;
|
||||
if (v.provinceName !== undefined) localFormData.value.provinceName = v.provinceName;
|
||||
if (v.cityName !== undefined) localFormData.value.cityName = v.cityName;
|
||||
if (v.districtName !== undefined) localFormData.value.districtName = v.districtName;
|
||||
console.log('after init', localFormData.value);
|
||||
|
||||
// 如果有省份数据,重新加载对应的城市和区县数据
|
||||
|
||||
192
src/views/user/registration/UserStep4FeeConfig.vue
Normal file
192
src/views/user/registration/UserStep4FeeConfig.vue
Normal file
@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="localFormData" :rules="rules" label-position="right" label-width="120px" class="step-fee">
|
||||
<el-form-item label="收费模式" prop="chargeMode">
|
||||
<el-radio-group v-if="!readonly" v-model="localFormData.chargeMode" :disabled="readonly">
|
||||
<el-radio border :label="0">免费</el-radio>
|
||||
<el-radio border :label="1">定价(赛事)</el-radio>
|
||||
<el-radio border :label="2">单价(赛事)</el-radio>
|
||||
<el-radio border :label="3">单价(项目)</el-radio>
|
||||
</el-radio-group>
|
||||
<span v-else>
|
||||
{{ getChargeModeText(localFormData.chargeMode) }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="价格" prop="price" v-if="localFormData.chargeMode === 1 || localFormData.chargeMode === 2">
|
||||
<el-input-number v-if="!readonly" v-model="localFormData.price" :min="0" :step="1" style="width: 100%" :disabled="readonly" />
|
||||
<span v-else>{{ localFormData.price ?? '-' }}</span>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 单价(项目)模式:逐项目设置价格 -->
|
||||
<el-form-item label="项目单价" v-if="localFormData.chargeMode === 3">
|
||||
<div class="project-fee-list">
|
||||
<div v-if="!localFormData.projects || !localFormData.projects.length" class="project-fee-empty">
|
||||
暂无项目
|
||||
</div>
|
||||
<el-table v-else :data="localFormData.projects" border style="width: 100%">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="name" label="项目名称" min-width="160" />
|
||||
<el-table-column label="价格(元)" width="200" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input-number
|
||||
v-if="!readonly"
|
||||
v-model="row.fee"
|
||||
:min="0"
|
||||
:step="1"
|
||||
:precision="2"
|
||||
style="width: 160px"
|
||||
placeholder="请输入价格"
|
||||
/>
|
||||
<span v-else>{{ row.fee !== undefined && row.fee !== null ? row.fee : '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: Object, required: true },
|
||||
readonly: { type: Boolean, default: false }
|
||||
});
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
const formRef = ref(null);
|
||||
const localFormData = ref({
|
||||
chargeMode: 0,
|
||||
price: 0,
|
||||
merchantId: undefined,
|
||||
merchantName: '',
|
||||
creditCode: '',
|
||||
bankName: '',
|
||||
accountNumber: '',
|
||||
businessLicenseUrl: '',
|
||||
projects: [],
|
||||
});
|
||||
|
||||
const getChargeModeText = (mode) => {
|
||||
if (mode === 0 || mode === '0' || mode === 'Free' || mode === 'free') return '免费';
|
||||
if (mode === 1 || mode === '1' || mode === 'FixedPrice') return '定价(赛事)';
|
||||
if (mode === 2 || mode === '2' || mode === 'UnitPriceEvent') return '单价(赛事)';
|
||||
if (mode === 3 || mode === '3' || mode === 'UnitPriceProject') return '单价(项目)';
|
||||
return '-';
|
||||
};
|
||||
|
||||
// 标准化收费模式为数字
|
||||
const normalizeChargeMode = (mode) => {
|
||||
if (mode === 0 || mode === '0' || mode === 'Free' || mode === 'free') return 0;
|
||||
if (mode === 1 || mode === '1' || mode === 'FixedPrice') return 1;
|
||||
if (mode === 2 || mode === '2' || mode === 'UnitPriceEvent') return 2;
|
||||
if (mode === 3 || mode === '3' || mode === 'UnitPriceProject') return 3;
|
||||
return 0;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(v) => {
|
||||
if (!v) return;
|
||||
|
||||
// 直接复制所有属性,强制覆盖
|
||||
localFormData.value.chargeMode = normalizeChargeMode(v.chargeMode);
|
||||
localFormData.value.price = v.price ?? 0;
|
||||
localFormData.value.merchantId = v.merchantId;
|
||||
localFormData.value.merchantName = v.merchantName ?? '';
|
||||
localFormData.value.creditCode = v.creditCode ?? '';
|
||||
localFormData.value.bankName = v.bankName ?? '';
|
||||
localFormData.value.accountNumber = v.accountNumber ?? '';
|
||||
localFormData.value.businessLicenseUrl = v.businessLicenseUrl ?? '';
|
||||
localFormData.value.projects = v.projects ?? [];
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
localFormData,
|
||||
(v) => emit('update:modelValue', { ...props.modelValue, ...v }),
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const validatePrice = (rule, value, callback) => {
|
||||
// 当收费模式为定价(赛事)或单价(赛事)时,价格必填
|
||||
if (localFormData.value.chargeMode === 1 || localFormData.value.chargeMode === 2) {
|
||||
if (value === '' || value === null || value === undefined || value <= 0) {
|
||||
callback(new Error('请输入价格,且价格必须大于0'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 单价(项目)模式:每个项目都必须有价格
|
||||
if (localFormData.value.chargeMode === 3) {
|
||||
const projects = localFormData.value.projects ?? [];
|
||||
const invalid = projects.some((p) => p.fee === undefined || p.fee === null || p.fee === '' || p.fee < 0);
|
||||
if (invalid) {
|
||||
callback(new Error('请为所有项目设置价格(不能为空且不能小于0)'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
const rules = {
|
||||
chargeMode: [{ required: true, message: '请选择收费模式', trigger: 'change' }],
|
||||
price: [
|
||||
{ validator: validatePrice, trigger: ['change', 'blur'] }
|
||||
],
|
||||
};
|
||||
|
||||
const validate = async () => {
|
||||
if (!formRef.value) return false;
|
||||
// 单价(项目)模式:额外验证每个项目的 fee
|
||||
if (localFormData.value.chargeMode === 3) {
|
||||
const projects = localFormData.value.projects ?? [];
|
||||
const invalid = projects.some((p) => p.fee === undefined || p.fee === null || p.fee === '' || p.fee < 0);
|
||||
if (invalid) {
|
||||
return Promise.reject('请为所有项目设置价格(不能为空且不能小于0)');
|
||||
}
|
||||
}
|
||||
return await formRef.value.validate();
|
||||
};
|
||||
|
||||
defineExpose({ validate });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.step-fee {
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.step-fee .el-form-item {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.fee-type-group {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fee-type-group .el-radio-button {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.fee-type-group .el-radio-button__inner {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fee-description {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
/* 项目单价列表 */
|
||||
.project-fee-list {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.project-fee-empty {
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 14px;
|
||||
padding: 12px 0;
|
||||
}
|
||||
</style>
|
||||
@ -65,7 +65,7 @@
|
||||
<div style="height:50px;"></div>
|
||||
<Step3ProjectConfig v-model:modelValue="formData.projectConfig" :readonly="true" />
|
||||
<div style="height:50px;"></div>
|
||||
<Step4FeeConfig v-model:modelValue="formData.feeConfig" :readonly="true" />
|
||||
<UserStep4FeeConfig v-model:modelValue="formData.feeConfig" :readonly="true" />
|
||||
<div style="height:100px;"></div>
|
||||
</div>
|
||||
<el-empty v-else description="暂无详情数据" />
|
||||
@ -467,7 +467,7 @@ import QRCode from 'qrcodejs2-fixes';
|
||||
import Step1BasicInfo from '/@/views/match/manage/Steps/Step1BasicInfo.vue';
|
||||
import Step2Units from '/@/views/match/manage/Steps/Step2Units.vue';
|
||||
import Step3ProjectConfig from '/@/views/match/manage/Steps/Step3ProjectConfig.vue';
|
||||
import Step4FeeConfig from '/@/views/match/manage/Steps/Step4FeeConfig.vue';
|
||||
import UserStep4FeeConfig from './UserStep4FeeConfig.vue';
|
||||
import PreviewImage from '/@/components/PreviewImage/index.vue';
|
||||
|
||||
const tableRef = ref();
|
||||
@ -638,9 +638,13 @@ const formData = ref({
|
||||
eventName: '',
|
||||
coverImage: '',
|
||||
eventVideo: '',
|
||||
eventType: '',
|
||||
registrationType: '',
|
||||
eventType: undefined,
|
||||
registrationType: undefined,
|
||||
pointsRuleId: undefined,
|
||||
pointsRuleName: '',
|
||||
provinceName: '',
|
||||
cityName: '',
|
||||
districtName: '',
|
||||
registrationTime: [],
|
||||
isNeedMaterial: false,
|
||||
materialRemark: '',
|
||||
@ -665,13 +669,14 @@ const formData = ref({
|
||||
},
|
||||
// 步骤4:费用与账户配置
|
||||
feeConfig: {
|
||||
chargeMode: 'Free',
|
||||
chargeMode: 0,
|
||||
price: 0,
|
||||
merchantId: undefined,
|
||||
merchantName: '',
|
||||
creditCode: '',
|
||||
bankName: '',
|
||||
accountNumber: '',
|
||||
projects: [],
|
||||
},
|
||||
});
|
||||
|
||||
@ -684,9 +689,13 @@ const clearDetailState = () => {
|
||||
eventName: '',
|
||||
coverImage: '',
|
||||
eventVideo: '',
|
||||
eventType: '',
|
||||
registrationType: '',
|
||||
eventType: undefined,
|
||||
registrationType: undefined,
|
||||
pointsRuleId: undefined,
|
||||
pointsRuleName: '',
|
||||
provinceName: '',
|
||||
cityName: '',
|
||||
districtName: '',
|
||||
registrationTime: [],
|
||||
isNeedMaterial: false,
|
||||
materialRemark: '',
|
||||
@ -703,13 +712,14 @@ const clearDetailState = () => {
|
||||
registrationLimit: { individualProjectLimit: 1, teamProjectLimit: 1 },
|
||||
},
|
||||
feeConfig: {
|
||||
chargeMode: 'Free',
|
||||
chargeMode: 0,
|
||||
price: 0,
|
||||
merchantId: undefined,
|
||||
merchantName: '',
|
||||
creditCode: '',
|
||||
bankName: '',
|
||||
accountNumber: '',
|
||||
projects: [],
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -735,25 +745,35 @@ const openDetailDialog = async (row) => {
|
||||
eventName: data.name || data.eventName || '',
|
||||
coverImage: data.coverImage || '',
|
||||
eventVideo: data.eventVideo || '',
|
||||
eventType: data.type || data.eventType || '',
|
||||
registrationType: data.registrationType || data.registrationMode || '',
|
||||
eventType: data.type,
|
||||
registrationType: data.registrationType,
|
||||
pointsRuleId: data.pointsRuleId,
|
||||
pointsRuleName: data.pointsRuleName || '',
|
||||
provinceName: data.provinceName || '',
|
||||
cityName: data.cityName || '',
|
||||
districtName: data.districtName || '',
|
||||
registrationTime: [data.registrationStartTime, data.registrationEndTime],
|
||||
isNeedMaterial: !!data.isNeedMaterial,
|
||||
materialRemark: data.materialRemark || '',
|
||||
materialUploadTime: [data.materialUploadStartTime, data.materialUploadEndTime],
|
||||
matchTime: [data.matchStartTime, data.matchEndTime],
|
||||
regionIds: [data.provinceId, data.cityId, data.districtId].filter((x) => x !== undefined && x !== null),
|
||||
detailAddress: data.detailAddress || '',
|
||||
eventIntroduction: data.eventIntroduction || '',
|
||||
detailAddress: data.address || data.detailAddress || '',
|
||||
eventIntroduction: data.description || data.eventIntroduction || '',
|
||||
customConfigJson: data.customConfigJson || '',
|
||||
};
|
||||
formData.value.units = { units: data.units || [] };
|
||||
formData.value.projectConfig = {
|
||||
projects: data.projects || [],
|
||||
registrationLimit: data.registrationLimit || { individualProjectLimit: 1, teamProjectLimit: 1 },
|
||||
registrationLimit: data.limitConfig || data.registrationLimit || { individualProjectLimit: 1, teamProjectLimit: 1 },
|
||||
};
|
||||
// 处理 feeConfig 数据,确保包含项目信息
|
||||
formData.value.feeConfig = {
|
||||
...formData.value.feeConfig,
|
||||
...(data.feeConfig || {}),
|
||||
chargeMode: data.feeConfig?.chargeMode,
|
||||
projects: data.projects || []
|
||||
};
|
||||
formData.value.feeConfig = { ...formData.value.feeConfig, ...(data.feeConfig || {}) };
|
||||
}
|
||||
} catch {
|
||||
ElMessage.error('赛事详情加载失败');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user