赛事管理bug

This commit is contained in:
马梓彭 2026-04-07 09:05:06 +08:00
parent 1c15442978
commit 762483d07d
5 changed files with 161 additions and 54 deletions

View File

@ -124,7 +124,7 @@ const localFormData = ref({
// init from parent
watch(
() => props.modelValue,
(v) => {
async (v) => {
console.log('init from parent', v);
if (!v) return;
Object.keys(localFormData.value).forEach((k) => {
@ -137,6 +137,21 @@ watch(
}
});
console.log('after init', localFormData.value);
// 如果有省份数据,重新加载对应的城市和区县数据
if(localFormData.value.regionIds[0]) {
try {
const cityRes = await regionCitiesbyprovinceGet({ provincecode: localFormData.value.regionIds[0] });
cities.value = cityRes?.data ?? [];
if(localFormData.value.regionIds[1]) {
const districtRes = await regionDistrictsbycityGet({ citycode: localFormData.value.regionIds[1] });
districts.value = districtRes?.data ?? [];
}
} catch {
cities.value = [];
districts.value = [];
}
}
},
{ deep: true, immediate: true }
);

View File

@ -47,7 +47,7 @@
</div>
<div class="account-item">
<div class="account-item__label">营业执照</div>
<img :src="businessLicenseUrl" style="width: 100px; height: 100px;" />
<el-image :src="localFormData.businessLicenseUrl" style="width: 100px; height: 100px;" fit="cover" />
</div>
</div>
</div>
@ -149,15 +149,67 @@ const localFormData = ref({
creditCode: '',
bankName: '',
accountNumber: '',
businessLicenseUrl: '',
});
const merchantOptions = ref([]);
const isInitialized = ref(false);
const syncMerchantInfo = () => {
const id = localFormData.value.merchantId;
// 如果已经有商户信息(merchantName 不为空),即使没有 merchantId 也正常显示
if (localFormData.value.merchantName) {
return;
}
// 如果没有 id,不强制清空,保留已有数据
if (!id) {
return;
}
// 尝试从 merchantOptions 中查找商户
const m = (merchantOptions.value ?? []).find((x) => x?.value == id);
if (m) {
// 只在 localFormData 中的值为空时才从 merchantOptions 中获取
if (!localFormData.value.merchantName) {
localFormData.value.merchantName = m.merchantName ?? '';
}
if (!localFormData.value.creditCode) {
localFormData.value.creditCode = m.creditCode ?? '';
}
if (!localFormData.value.bankName) {
localFormData.value.bankName = m.bankName ?? '';
}
if (!localFormData.value.accountNumber) {
localFormData.value.accountNumber = m.accountNumber ?? '';
}
// 只在营业执照 URL 为空时才从 merchantOptions 中获取
if (!localFormData.value.businessLicenseUrl) {
localFormData.value.businessLicenseUrl = m.businessLicenseUrl ?? '';
}
}
};
watch(
() => props.modelValue,
(v) => {
if (!v) return;
Object.keys(localFormData.value).forEach((k) => {
if (v[k] !== undefined) localFormData.value[k] = v[k];
});
// 直接复制所有属性,强制覆盖
localFormData.value.chargeMode = v.chargeMode ?? 0;
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 ?? '';
// 如果已经初始化完成,调用 syncMerchantInfo
if (isInitialized.value) {
syncMerchantInfo();
}
},
{ deep: true, immediate: true }
);
@ -167,8 +219,7 @@ watch(
(v) => emit('update:modelValue', { ...props.modelValue, ...v }),
{ deep: true }
);
const businessLicenseUrl = ref('');
const merchantOptions = ref([]);
onMounted(async () => {
try {
const res = await merchantPageGet({ PageNo: 1, PageSize: 200 });
@ -185,27 +236,11 @@ onMounted(async () => {
} catch {
merchantOptions.value = [];
}
isInitialized.value = true;
syncMerchantInfo();
});
const syncMerchantInfo = () => {
const id = localFormData.value.merchantId;
if (!id) {
localFormData.value.merchantName = '';
localFormData.value.creditCode = '';
localFormData.value.bankName = '';
localFormData.value.accountNumber = '';
businessLicenseUrl.value = '';
return;
}
const m = (merchantOptions.value ?? []).find((x) => x?.value == id);
localFormData.value.merchantName = m?.merchantName ?? '';
localFormData.value.creditCode = m?.creditCode ?? '';
localFormData.value.bankName = m?.bankName ?? '';
localFormData.value.accountNumber = m?.accountNumber ?? '';
businessLicenseUrl.value = m?.businessLicenseUrl ?? '';
};
// 商户选择弹窗相关
const merchantDialogVisible = ref(false);
const merchantList = ref([]);
@ -256,16 +291,47 @@ const selectMerchant = (row) => {
localFormData.value.creditCode = row.creditCode ?? '';
localFormData.value.bankName = row.bankName ?? '';
localFormData.value.accountNumber = row.accountNumber ?? '';
businessLicenseUrl.value = row.businessLicenseUrl ?? '';
localFormData.value.businessLicenseUrl = row.businessLicenseUrl ?? '';
merchantDialogVisible.value = false;
};
watch(merchantOptions, syncMerchantInfo, { deep: true });
watch(merchantOptions, () => {
if (isInitialized.value) {
syncMerchantInfo();
}
}, { 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;
}
}
callback();
};
const validateMerchantId = (rule, value, callback) => {
// 当收费模式为非免费时,收款商户必填
if (localFormData.value.chargeMode !== 0) {
// 如果有 merchantName,说明数据已经从后端回填了,即使没有 merchantId 也通过
if (!value && !localFormData.value.merchantName) {
callback(new Error('请选择收款商户'));
return;
}
}
callback();
};
const rules = {
chargeMode: [{ required: true, message: '请选择收费模式', trigger: 'change' }],
price: [{ required: false, message: '请输入价格', trigger: 'change' }],
merchantId: [{ required: true, message: '请选择收款商户', trigger: 'change' }],
price: [
{ validator: validatePrice, trigger: 'change' }
],
merchantId: [
{ validator: validateMerchantId, trigger: 'change' }
],
bankName: [{ required: false, message: '请输入开户银行', trigger: 'blur' }],
accountNumber: [{ required: false, message: '请输入银行账号', trigger: 'blur' }],
};

View File

@ -12,9 +12,7 @@
<!-- 步骤内容区域 -->
<div class="step-content">
<keep-alive>
<component :is="currentStepComponent" ref="stepRef" :model-value="currentStepData" @update:model-value="handleStepDataUpdate" />
</keep-alive>
<component :is="currentStepComponent" :key="activeStep" ref="stepRef" :model-value="currentStepData" @update:model-value="handleStepDataUpdate" />
</div>
<!-- 底部操作按钮 -->
@ -160,13 +158,14 @@ const formData = ref({
},
// 步骤4:费用与账户配置
feeConfig: {
chargeMode: 'Free',
chargeMode: 0, // 0=免费,1=定价(赛事),2=单价(赛事),3=单价(项目)
price: 0,
merchantId: undefined,
merchantName: '',
creditCode: '',
bankName: '',
accountNumber: '',
businessLicenseUrl: '',
},
});
@ -191,6 +190,10 @@ const openDialog = async (id) => {
console.log('openDialog called with id:', id);
dialog.isShowDialog = true;
dialog.loading = true;
// 先重置表单,清除前一个赛事的数据残留
handleReset();
if (id) {
dialog.title = '编辑赛事';
dialog.submitTxt = '保 存';
@ -223,14 +226,24 @@ const openDialog = async (id) => {
projects: d.projects ?? [],
registrationLimit: d.registrationLimit ?? { individualProjectLimit: 1, teamProjectLimit: 1 },
};
formData.value.feeConfig = { ...formData.value.feeConfig, ...(d.feeConfig ?? {}) };
console.log('formData.value', formData.value);
// 完全覆盖 feeConfig,不要保留旧数据
if (d.feeConfig) {
formData.value.feeConfig = {
chargeMode: d.feeConfig.chargeMode ?? 0,
price: d.feeConfig.price ?? 0,
merchantId: d.feeConfig.merchantId,
merchantName: d.feeConfig.merchantName ?? '',
creditCode: d.feeConfig.creditCode ?? '',
bankName: d.feeConfig.bankName ?? '',
accountNumber: d.feeConfig.accountNumber ?? '',
businessLicenseUrl: d.feeConfig.businessLicenseUrl ?? '',
};
}
}
} catch (e) {
ElMessage.error('加载赛事详情失败');
}
} else {
handleReset();
dialog.title = '新增赛事';
dialog.submitTxt = '新 增';
}
@ -360,6 +373,7 @@ const handleReset = () => {
creditCode: '',
bankName: '',
accountNumber: '',
businessLicenseUrl: '',
};
// 重置步骤

View File

@ -80,13 +80,13 @@ const refreshTable = () =>{
}
const columns = reactive([
{
width: '120px',
width: '80px',
prop: 'index',
label: '序号',
align: 'center',
},
{
width: '120px',
width: '200px',
prop: 'eventName',
label: '赛事名称',
align: 'center',
@ -99,10 +99,9 @@ const columns = reactive([
prop: 'coverImage',
label: '封面',
align: 'center',
width: '120px',
},
{
width: '120px',
width: '100px',
prop: 'eventType',
label: '赛事类型',
search: {
@ -115,7 +114,7 @@ const columns = reactive([
],
},
{
width: '120px',
width: '130px',
prop: 'registrationType',
label: '报名方式',
enum: [
@ -125,7 +124,7 @@ const columns = reactive([
],
},
{
width: '120px',
width: '130px',
prop: 'chargeMode',
label: '收费模式',
search: {
@ -139,10 +138,9 @@ const columns = reactive([
{ label: '单价(项目)', value: 3 },
],
},
{ prop: 'merchantName', label: '收款账户',width: '120px', },
{ prop: 'merchantName', label: '收款账户', width: '150px', },
{
width: '120px',
width: '100px',
prop: 'eventStatus',
label: '赛事状态',
search: {
@ -157,7 +155,7 @@ const columns = reactive([
],
},
{
width: '120px',
width: '160px',
prop: 'registrationStartTime',
label: '报名开始时间',
search: {
@ -168,7 +166,7 @@ const columns = reactive([
},
},
{
width: '120px',
width: '160px',
prop: 'registrationEndTime',
label: '报名结束时间',
search: {
@ -179,7 +177,7 @@ const columns = reactive([
},
},
{
width: '120px',
width: '160px',
prop: 'matchStartTime',
label: '比赛开始时间',
search: {
@ -190,7 +188,7 @@ const columns = reactive([
},
},
{
width: '120px',
width: '160px',
prop: 'matchEndTime',
label: '比赛结束时间',
search: {
@ -200,7 +198,7 @@ const columns = reactive([
},
},
},
{ prop: 'action', label: '操作', align: 'center', width: 160, fixed: 'right', isShow: auths(['event:edit', 'event:delete']) },
{ prop: 'action', label: '操作', align: 'center', width: 200, fixed: 'right', isShow: auths(['event:edit', 'event:delete']) },
]);
const exportableColumns = computed(() =>

View File

@ -420,7 +420,7 @@
<script setup>
import { ref, computed, nextTick, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { ElMessage, ElMessageBox } from 'element-plus';
import { Close, Picture, Loading, CircleCheck, ArrowRight } from '@element-plus/icons-vue';
import ProTable from '/@/components/ProTable/index.vue';
import { formatDate } from '/@/utils/formatTime';
@ -954,9 +954,6 @@ const openRegistrationDialog = async (row) => {
clearRegisterState();
currentEventId.value = eventId;
isShowRegisterDialog.value = true;
activeStep.value = 0;
registerLoading.value = true;
try {
@ -965,9 +962,26 @@ const openRegistrationDialog = async (row) => {
ElMessage.error(data ?? '项目加载失败');
return;
}
// 检查报名类型,如果是只允许个人报名,则显示提示并阻止继续
const registrationType = data?.registrationType;
if (registrationType === 'OnlyIndividual') {
ElMessageBox.alert(
'当前赛事只允许个人报名,请到移动端进行个人报名',
'提示',
{
confirmButtonText: '确定',
type: 'warning'
}
);
return;
}
// 保存完整的详情数据,用于项目类型显示等
detailData.value = data;
projects.value = Array.isArray(data?.projects) ? data.projects : [];
isShowRegisterDialog.value = true;
activeStep.value = 0;
} catch {
ElMessage.error('项目加载失败');
} finally {