证书,项目,积分管理
This commit is contained in:
parent
1cb0ac2978
commit
20b04d9124
@ -70,9 +70,9 @@
|
||||
|
||||
<!-- 选择有效期 -->
|
||||
<el-form-item label="选择有效期" prop="startTime">
|
||||
<el-date-picker type="daterange" v-model="formData.time" start-placeholder="开始日期"
|
||||
end-placeholder="结束日期" style="width: 100%;" value-format="YYYY-MM-DD" @change="(val) => {
|
||||
console.log('选择的日期范围:', val);
|
||||
<el-date-picker type="datetimerange" v-model="formData.time" start-placeholder="开始日期时间"
|
||||
end-placeholder="结束日期时间" style="width: 100%;" value-format="YYYY-MM-DD HH:mm" @change="(val) => {
|
||||
console.log('选择的日期时间范围:', val);
|
||||
formData.startTime = val[0];
|
||||
formData.endTime = val[1];
|
||||
}"></el-date-picker>
|
||||
@ -120,14 +120,39 @@ import { auths } from '/@/utils/authFunction';
|
||||
import ProTable from '/@/components/ProTable/index.vue';
|
||||
import { couponPage, couponAdd, couponEdit, couponDelete, couponEventlistGet, couponGeneratecodePost } from '/@/api/match/coupon';
|
||||
|
||||
// 格式化日期,只显示年月日
|
||||
// 格式化日期,显示完整时间(YYYY-MM-DD HH:MM)
|
||||
const formatDate = (dateStr) => {
|
||||
if (!dateStr) return '';
|
||||
if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) {
|
||||
// 如果已经是日期时间格式,直接返回(或调整格式)
|
||||
try {
|
||||
const date = new Date(dateStr);
|
||||
if (isNaN(date.getTime())) return dateStr;
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
} catch (e) {
|
||||
return dateStr;
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化日期为选择器用的格式
|
||||
const formatDateTimePicker = (dateStr) => {
|
||||
if (!dateStr) return '';
|
||||
try {
|
||||
const date = new Date(dateStr);
|
||||
if (isNaN(date.getTime())) return dateStr;
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
} catch (e) {
|
||||
return dateStr;
|
||||
}
|
||||
// 截取前10个字符(YYYY-MM-DD)
|
||||
return dateStr.slice(0, 10);
|
||||
};
|
||||
|
||||
// 定义表单引用类型
|
||||
@ -209,9 +234,9 @@ const onOpenMenu = async (row) => {
|
||||
if (row) {
|
||||
formData.value = {
|
||||
...row,
|
||||
startTime: formatDate(row.startTime),
|
||||
endTime: formatDate(row.endTime),
|
||||
time: [formatDate(row.startTime), formatDate(row.endTime)],
|
||||
startTime: formatDateTimePicker(row.startTime),
|
||||
endTime: formatDateTimePicker(row.endTime),
|
||||
time: [formatDateTimePicker(row.startTime), formatDateTimePicker(row.endTime)],
|
||||
};
|
||||
} else {
|
||||
formData.value = {
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
<el-button size="small" v-auth="'integral:config:delete'" text type="danger" icon="ele-Delete"> 删除 </el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<el-button size="small" v-auth="'integral:config:detail'" text type="primary" icon="ele-View" @click="onOpenDialog(scope.row, true)"> 查看详情 </el-button>
|
||||
</template>
|
||||
</ProTable>
|
||||
|
||||
@ -29,37 +30,34 @@
|
||||
<el-dialog :title="dialogTitle" v-model="isShowDialog" width="900px">
|
||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px" v-if="isShowDialog">
|
||||
<el-form-item label="规则名称" prop="ruleName">
|
||||
<el-input v-model="formData.ruleName" placeholder="请输入规则名称" />
|
||||
<el-input v-model="formData.ruleName" placeholder="请输入规则名称" :disabled="isDetailMode" />
|
||||
</el-form-item>
|
||||
<el-form-item label="参与积分" prop="participationPoints">
|
||||
<el-input-number v-model="formData.participationPoints" :min="0" :step="1" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="formData.remark" type="textarea" :rows="2" placeholder="可不填" />
|
||||
<el-input-number v-model="formData.participationPoints" :min="0" :step="1" style="width: 100%" :disabled="isDetailMode" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="名次积分">
|
||||
<div style="width: 100%">
|
||||
<div style="display: flex; justify-content: flex-end; margin-bottom: 10px">
|
||||
<div style="display: flex; justify-content: flex-end; margin-bottom: 10px" v-if="!isDetailMode">
|
||||
<el-button type="primary" plain icon="ele-Plus" @click="onAddDetailRow">新增区间</el-button>
|
||||
</div>
|
||||
<el-table :data="formData.details" border style="width: 100%" >
|
||||
<el-table-column label="起始排名" width="180">
|
||||
<template #default="scope">
|
||||
<el-input-number v-model="scope.row.startRank" :min="1" :step="1" />
|
||||
<el-input-number v-model="scope.row.startRank" :min="1" :step="1" :disabled="isDetailMode" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="结束排名" width="180">
|
||||
<template #default="scope">
|
||||
<el-input-number v-model="scope.row.endRank" :min="1" :step="1" />
|
||||
<el-input-number v-model="scope.row.endRank" :min="1" :step="1" :disabled="isDetailMode" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="对应积分" width="180">
|
||||
<template #default="scope">
|
||||
<el-input-number v-model="scope.row.points" :min="0" :step="1" />
|
||||
<el-input-number v-model="scope.row.points" :min="0" :step="1" :disabled="isDetailMode" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="140" align="center">
|
||||
<el-table-column label="操作" width="140" align="center" v-if="!isDetailMode">
|
||||
<template #default="scope">
|
||||
<el-button text type="danger" icon="ele-Delete" @click="onRemoveDetailRow(scope.$index)">
|
||||
删除
|
||||
@ -69,11 +67,15 @@
|
||||
</el-table>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="formData.remark" type="textarea" :rows="2" placeholder="可不填" :disabled="isDetailMode" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="onCancel">取消</el-button>
|
||||
<el-button type="primary" @click="onSubmit">确定</el-button>
|
||||
<el-button type="primary" @click="onSubmit" v-if="!isDetailMode">确定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@ -105,6 +107,7 @@ const buildEmptyForm = () => ({
|
||||
});
|
||||
|
||||
const formData = ref(buildEmptyForm());
|
||||
const isDetailMode = ref(false);
|
||||
|
||||
const formRules = ref({
|
||||
ruleName: [{ required: true, message: '请输入规则名称', trigger: 'blur' }],
|
||||
@ -125,14 +128,15 @@ const columns = ref([
|
||||
// search: { el: 'select' },
|
||||
// },
|
||||
{ prop: 'createdTime', label: '创建时间', align: 'center' },
|
||||
{ prop: 'action', label: '操作', align: 'center', fixed: 'right', width: 220 },
|
||||
{ prop: 'action', label: '操作', align: 'center', fixed: 'right', width: 320 },
|
||||
]);
|
||||
|
||||
const isShowDialog = ref(false);
|
||||
const dialogTitle = ref('新增');
|
||||
|
||||
const onOpenDialog = async (row?: any) => {
|
||||
dialogTitle.value = row ? '编辑' : '新增';
|
||||
const onOpenDialog = async (row?: any, isDetail = false) => {
|
||||
isDetailMode.value = isDetail;
|
||||
dialogTitle.value = isDetail ? '查看详情' : row ? '编辑' : '新增';
|
||||
if (row?.id) {
|
||||
const res: any = await pointsruleDetailGet({ id: row.id });
|
||||
formData.value = {
|
||||
@ -150,7 +154,7 @@ const onOpenDialog = async (row?: any) => {
|
||||
} else {
|
||||
formData.value = buildEmptyForm();
|
||||
}
|
||||
if (!formData.value.details?.length) onAddDetailRow();
|
||||
if (!formData.value.details?.length && !isDetail) onAddDetailRow();
|
||||
isShowDialog.value = true;
|
||||
};
|
||||
|
||||
@ -162,6 +166,30 @@ const onRemoveDetailRow = (index: number) => {
|
||||
formData.value.details.splice(index, 1);
|
||||
};
|
||||
|
||||
// 验证名次范围是否重叠
|
||||
const validateRankOverlap = () => {
|
||||
const details = formData.value.details;
|
||||
if (details.length <= 1) return true;
|
||||
|
||||
for (let i = 0; i < details.length; i++) {
|
||||
const item1 = details[i];
|
||||
if (!item1.startRank || !item1.endRank) continue;
|
||||
|
||||
for (let j = i + 1; j < details.length; j++) {
|
||||
const item2 = details[j];
|
||||
if (!item2.startRank || !item2.endRank) continue;
|
||||
|
||||
// 检查是否重叠
|
||||
const isOverlap = !(item1.endRank < item2.startRank || item2.endRank < item1.startRank);
|
||||
if (isOverlap) {
|
||||
ElMessage.error(`名次范围 ${item1.startRank}-${item1.endRank} 与 ${item2.startRank}-${item2.endRank} 存在重叠,请调整!`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const onDelete = async (id: number) => {
|
||||
await pointsruleDeleteDelete({ id });
|
||||
ElMessage.success('删除成功');
|
||||
@ -185,6 +213,10 @@ const onSubmit = () => {
|
||||
ElMessage.warning('请至少配置一个排名区间');
|
||||
return;
|
||||
}
|
||||
// 验证名次范围是否重叠
|
||||
if (!validateRankOverlap()) {
|
||||
return;
|
||||
}
|
||||
const payload = {
|
||||
id: formData.value.id,
|
||||
ruleName: formData.value.ruleName,
|
||||
@ -211,6 +243,7 @@ const onSubmit = () => {
|
||||
// 取消
|
||||
const onCancel = () => {
|
||||
isShowDialog.value = false;
|
||||
isDetailMode.value = false;
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
||||
@ -30,9 +30,8 @@
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
|
||||
<el-button v-auth="'project:detail'" size="small" text type="primary" @click="onOpenMenu(scope.row)">
|
||||
查看详情 </el-button>
|
||||
<el-button v-auth="'project:detail'" size="small" text type="primary"
|
||||
@click="onViewDetail(scope.row)"> 查看详情 </el-button>
|
||||
</template>
|
||||
</ProTable>
|
||||
|
||||
@ -74,6 +73,8 @@
|
||||
callback(new Error('请选择出生日期开始'));
|
||||
} else if (!value.birthDateEnd) {
|
||||
callback(new Error('请选择出生日期结束'));
|
||||
} else if (new Date(value.birthDateStart) > new Date(value.birthDateEnd)) {
|
||||
callback(new Error('出生日期结束必须大于或等于出生日期开始'));
|
||||
} else if (!value.gender) {
|
||||
callback(new Error('请选择性别'));
|
||||
} else {
|
||||
@ -85,9 +86,9 @@
|
||||
<el-input v-model="group.groupName" placeholder="输入组别名"
|
||||
style="width: 100px; margin-right: 18px"></el-input>
|
||||
<el-date-picker v-model="group.birthDateStart" type="date" placeholder="出生日期开始"
|
||||
style="margin-right: 18px"></el-date-picker>
|
||||
style="margin-right: 18px" value-format="YYYY-MM-DD"></el-date-picker>
|
||||
<el-date-picker v-model="group.birthDateEnd" type="date" placeholder="出生日期结束"
|
||||
style="margin-right: 18px"></el-date-picker>
|
||||
style="margin-right: 18px" value-format="YYYY-MM-DD"></el-date-picker>
|
||||
<el-select v-model="group.gender" placeholder="性别" style="width: 100px">
|
||||
<el-option label="男" value="0"></el-option>
|
||||
<el-option label="女" value="1"></el-option>
|
||||
@ -125,6 +126,76 @@
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 详情弹窗 - 复用编辑页面布局 -->
|
||||
<el-dialog title="项目详情" v-model="isShowDetailDialog" width="1100px">
|
||||
<el-form :model="detailData" label-width="150px"
|
||||
style="width: 90%; margin-bottom: 30px" v-if="isShowDetailDialog">
|
||||
<!-- 项目名称 -->
|
||||
<el-form-item label="项目名称:">
|
||||
<el-input v-model="detailData.name" disabled></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 项目类型 -->
|
||||
<el-form-item label="项目类型:">
|
||||
<el-select v-model="detailData.projectTypeId" disabled style="width: 100%">
|
||||
<el-option label="个人速度" :value="1003"></el-option>
|
||||
<el-option label="个人花样" :value="1004"></el-option>
|
||||
<el-option label="团队速度" :value="1005"></el-option>
|
||||
<el-option label="团队花样" :value="1006"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 完成人数 -->
|
||||
<el-form-item label="完成人数:">
|
||||
<el-input-number v-model="detailData.completionCount" disabled :min="0" :step="1" style="width: 100%"></el-input-number>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 组别 -->
|
||||
<div class="detail-groups-section">
|
||||
<el-form-item :label="'组别' + (index + 1) + ':'"
|
||||
v-for="(group, index) in (detailData.groups || [])" :key="index">
|
||||
<el-input v-model="group.groupName" disabled
|
||||
style="width: 100px; margin-right: 18px"></el-input>
|
||||
<el-date-picker v-model="group.birthDateStart" type="date" disabled
|
||||
style="margin-right: 18px" value-format="YYYY-MM-DD"></el-date-picker>
|
||||
<el-date-picker v-model="group.birthDateEnd" type="date" disabled
|
||||
style="margin-right: 18px" value-format="YYYY-MM-DD"></el-date-picker>
|
||||
<el-select v-model="group.gender" disabled style="width: 100px">
|
||||
<el-option label="男" value="0"></el-option>
|
||||
<el-option label="女" value="1"></el-option>
|
||||
<el-option label="不限" value="3"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 视觉分隔线 -->
|
||||
<div class="detail-section-divider"></div>
|
||||
|
||||
<!-- 费用 -->
|
||||
<el-form-item label="费用:">
|
||||
<el-input v-model="detailData.fee" disabled class="fee-input">
|
||||
<template slot="append">元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 时长 -->
|
||||
<el-form-item label="时长:">
|
||||
<div class="duration-row">
|
||||
<el-input v-model="detailData.durationMinutes" disabled type="number"></el-input>
|
||||
<span class="duration-label">分</span>
|
||||
<span class="duration-separator">--</span>
|
||||
<el-input v-model="detailData.durationSeconds" disabled type="number"></el-input>
|
||||
<span class="duration-label">秒</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="isShowDetailDialog = false">关闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -142,6 +213,20 @@ const initParam = ref({
|
||||
refresh: true,
|
||||
});
|
||||
|
||||
// 详情弹窗相关
|
||||
const isShowDetailDialog = ref(false);
|
||||
const detailData = ref(null);
|
||||
|
||||
// 日期格式化函数
|
||||
const formatDate = (date) => {
|
||||
if (!date) return '';
|
||||
const d = new Date(date);
|
||||
const year = d.getFullYear();
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(d.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
};
|
||||
|
||||
const addGroup = () => {
|
||||
formData.value.groups.push({
|
||||
groupName: '',
|
||||
@ -262,7 +347,7 @@ const columns = ref([
|
||||
|
||||
{ prop: 'time', label: '时长' },
|
||||
|
||||
{ prop: 'action', label: '操作', align: 'center', fixed: 'right', isShow: auths(['project:delete', 'project:edit', 'project:add']) },
|
||||
{ prop: 'action', label: '操作', align: 'center', fixed: 'right' },
|
||||
]);
|
||||
|
||||
const isShowDialog = ref(false);
|
||||
@ -300,13 +385,13 @@ const onOpenMenu = async (row) => {
|
||||
},
|
||||
];
|
||||
} else {
|
||||
// 过滤无效的 group 并补充缺失的属性
|
||||
// 过滤无效的 group 并补充缺失的属性,同时格式化日期
|
||||
formData.value.groups = formData.value.groups
|
||||
.filter(group => group)
|
||||
.map(group => ({
|
||||
groupName: group.groupName || '',
|
||||
birthDateStart: group.birthDateStart || '',
|
||||
birthDateEnd: group.birthDateEnd || '',
|
||||
birthDateStart: formatDate(group.birthDateStart),
|
||||
birthDateEnd: formatDate(group.birthDateEnd),
|
||||
gender: group.gender !== undefined && group.gender !== null ? group.gender.toString() : '',
|
||||
}));
|
||||
// 如果过滤后没有组,添加一个空组
|
||||
@ -325,6 +410,31 @@ const onOpenMenu = async (row) => {
|
||||
isShowDialog.value = true;
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const onViewDetail = async (row) => {
|
||||
const { succeeded, data } = await projectDetailGet({ id: row.id });
|
||||
if (succeeded) {
|
||||
// 确保 groups 数组存在且有效,并格式化日期
|
||||
let groupsData = [];
|
||||
if (data.groups && Array.isArray(data.groups)) {
|
||||
groupsData = data.groups
|
||||
.filter(group => group)
|
||||
.map(group => ({
|
||||
groupName: group.groupName || '',
|
||||
birthDateStart: formatDate(group.birthDateStart),
|
||||
birthDateEnd: formatDate(group.birthDateEnd),
|
||||
gender: group.gender !== undefined && group.gender !== null ? group.gender.toString() : '',
|
||||
}));
|
||||
}
|
||||
|
||||
detailData.value = {
|
||||
...data,
|
||||
groups: groupsData
|
||||
};
|
||||
isShowDetailDialog.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
//删除菜单
|
||||
const onDeleteMenu = async (id) => {
|
||||
const { succeeded, errors } = await projectDeleteDelete({ id });
|
||||
@ -429,4 +539,9 @@ const onCancel = () => {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 详情页面组别区域样式 */
|
||||
.detail-groups-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -169,7 +169,12 @@ const formRules = ref({
|
||||
{ required: true, message: '请上传营业执照', trigger: 'blur' }
|
||||
],
|
||||
contactPhone: [
|
||||
{ required: true, message: '请输入联系电话', trigger: 'blur' }
|
||||
{ required: true, message: '请输入联系电话', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^1[3-9]\d{9}$/,
|
||||
message: '请输入正确的手机号格式',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user