Kaynağa Gözat

feat(eventGroupConfig): 新增赛事组别配置管理功能

- 创建赛事组别配置API接口模块,包含增删改查功能
- 添加赛事组别配置数据类型定义
- 实现赛事组别配置管理页面,支持名称、日期、组别等字段配置
- 集成组别模板选择功能,支持常规组和决赛组模板配置
- 实现组别时间安排和间隔天数设置功能
- 添加系列赛生成功能,支持批量创建赛事
- 在路由中添加下载页面路径配置
- 修复下载页面样式问题,优化用户体验
- 调整裁判职务管理页面对话框布局
- 添加赛事组别配置的详细信息展示和编辑功能
fugui001 2 ay önce
ebeveyn
işleme
c9e92ef26b

+ 71 - 0
src/api/system/business/eventGroupConfig/index.ts

@@ -0,0 +1,71 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { EventGroupConfigVO, EventGroupConfigForm, EventGroupConfigQuery } from '@/api/system/business/eventGroupConfig/types';
+import { ConfigVO } from '@/api/system/business/config/types';
+
+/**
+ * 查询赛事组别配置主列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listEventGroupConfig = (query?: EventGroupConfigQuery): AxiosPromise<EventGroupConfigVO[]> => {
+  return request({
+    url: '/business/eventGroupConfig/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询赛事组别配置主详细
+ * @param id
+ */
+export const getEventGroupConfig = (id: string | number): AxiosPromise<EventGroupConfigVO> => {
+  return request({
+    url: '/business/eventGroupConfig/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增赛事组别配置主
+ * @param data
+ */
+export const addEventGroupConfig = (data: EventGroupConfigForm) => {
+  return request({
+    url: '/business/eventGroupConfig',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改赛事组别配置主
+ * @param data
+ */
+export const updateEventGroupConfig = (data: EventGroupConfigForm) => {
+  return request({
+    url: '/business/eventGroupConfig',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除赛事组别配置主
+ * @param id
+ */
+export const delEventGroupConfig = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/business/eventGroupConfig/' + id,
+    method: 'delete'
+  });
+};
+export const generateXiLieTournament = (eventId: string | number): AxiosPromise<EventGroupConfigVO> => {
+  return request({
+    url: '/business/eventGroupConfig/generateXiLieTournament',
+    method: 'post',
+    params: { eventId } // 添加 configId 参数传递
+  });
+};

+ 113 - 0
src/api/system/business/eventGroupConfig/types.ts

@@ -0,0 +1,113 @@
+export interface EventGroupConfigVO {
+  /**
+   *
+   */
+  id: string | number;
+
+  /**
+   * 配置名称(如“篮球小组赛”)
+   */
+  name: string;
+
+  /**
+   * 常规组别模板ID(关联 event_template)
+   */
+  regularTemplateId: string | number;
+
+  /**
+   * 决赛组别模板ID
+   */
+  finalTemplateId: string | number;
+
+  /**
+   * 开始日期(所有组别的基准日)
+   */
+  startDate: string;
+  finalStartDate?: string;
+  /**
+   *
+   */
+  createdAt: string;
+
+  /**
+   * 组别列表
+   */
+  groups?: Array<{
+    groupName: string;
+    executionTime: string;
+    intervalDays: number;
+  }>;
+}
+
+export interface EventGroupConfigForm extends BaseEntity {
+  /**
+   *
+   */
+  id?: string | number;
+
+  /**
+   * 配置名称(如“篮球小组赛”)
+   */
+  name?: string;
+
+  /**
+   * 常规组别模板ID(关联 event_template)
+   */
+  regularTemplateId?: string | number;
+
+  /**
+   * 决赛组别模板ID
+   */
+  finalTemplateId?: string | number;
+
+  /**
+   * 开始日期(所有组别的基准日)
+   */
+  startDate?: string;
+  finalStartDate?: string;
+
+  /**
+   *
+   */
+  createdAt?: string;
+  /**
+   * 组别列表
+   */
+  groups?: Array<{
+    groupName: string;
+    executionTime: string;
+    intervalDays: number;
+  }>;
+}
+
+export interface EventGroupConfigQuery extends PageQuery {
+  /**
+   * 配置名称(如“篮球小组赛”)
+   */
+  name?: string;
+
+  /**
+   * 常规组别模板ID(关联 event_template)
+   */
+  regularTemplateId?: string | number;
+
+  /**
+   * 决赛组别模板ID
+   */
+  finalTemplateId?: string | number;
+
+  /**
+   * 开始日期(所有组别的基准日)
+   */
+  startDate?: string;
+  finalStartDate?: string;
+  /**
+   *
+   */
+  createdAt?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 6 - 0
src/api/system/business/tournamentsTemplate/index.ts

@@ -106,3 +106,9 @@ export const uploadTournament = async (file: File) => {
 
   return res;
 };
+export const selectTournamentsVoListTemplateList = (): AxiosPromise<TournamentsVO> => {
+  return request({
+    url: '/business/tournamentsTemplate/selectTournamentsVoListTemplateList',
+    method: 'get'
+  });
+};

+ 2 - 1
src/permission.ts

@@ -22,7 +22,8 @@ const whiteList = [
   '/policy/*',
   '/policy',
   '/terms',
-  '/agreement'
+  '/agreement',
+  '/download'
 ];
 
 const isWhiteList = (path: string) => {

+ 5 - 0
src/router/index.ts

@@ -108,6 +108,11 @@ export const constantRoutes: RouteRecordRaw[] = [
     path: '/agreement',
     component: () => import('@/views/system/business/agreement/indexAgreePreview.vue'),
     hidden: true
+  },
+  {
+    path: '/download',
+    component: () => import('@/views/system/business/downloads/indexDownloadPreview.vue'),
+    hidden: true
   }
 ];
 

+ 6 - 2
src/views/system/business/downloads/indexDownloadPreview.vue

@@ -21,7 +21,9 @@
             iOS下载
           </el-button>
         </div>
-        <div style=" margin-top: 15px;
+        <div
+          style="
+            margin-top: 15px;
             padding: 12px;
             background-color: #fffbe6;
             border: 1px solid #ffe58f;
@@ -32,7 +34,9 @@
             color: #8c8c8c;
             max-width: 500px;
             margin-left: auto;
-            margin-right: auto;">
+            margin-right: auto;
+          "
+        >
           <p>我已知晓内测应用的来源,并同意自行承担下载此APP所带来的一切风险</p>
           <p>应用仅供内部测试,请谨慎辨别下载</p>
         </div>

+ 506 - 0
src/views/system/business/eventGroupConfig/index.vue

@@ -0,0 +1,506 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="名称" prop="name">
+              <el-input v-model="queryParams.name" placeholder="请输入名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['business:eventGroupConfig:add']">新增</el-button>
+          </el-col>
+<!--          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['business:eventGroupConfig:edit']"
+              >修改</el-button
+            >
+          </el-col>-->
+<!--          <el-col :span="1.5">
+            <el-button
+              type="danger"
+              plain
+              icon="Delete"
+              :disabled="multiple"
+              @click="handleDelete()"
+              v-hasPermi="['business:eventGroupConfig:remove']"
+              >删除</el-button
+            >
+          </el-col>-->
+<!--          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['business:eventGroupConfig:export']">导出</el-button>
+          </el-col>-->
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="eventGroupConfigList">
+<!--        <el-table-column type="selection" width="55" align="center" />-->
+        <el-table-column label="编号" align="center" prop="id" v-if="true" width="70" />
+        <el-table-column label="名称" align="center" prop="name" />
+        <el-table-column label="决赛组模板" align="center" prop="finalTemplateName" />
+        <el-table-column label="决赛组日期" align="center" prop="finalStartDate" />
+        <el-table-column label="常规组模板" align="center" prop="regularTemplateName" />
+        <el-table-column label="常规组日期" align="center" prop="startDate" width="180">
+          <template #default="scope">
+            <span>{{ parseTime(scope.row.startDate, '{y}-{m}-{d}') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="组别" align="center" width="180">
+          <template #default="scope">
+            <div v-for="(group, index) in scope.row.groups" :key="index" style="margin-bottom: 5px">
+              {{ group.groupName }}组 - {{ group.executionTime.substring(0, 5) }}
+              <span style="color: #999; font-size: 12px">(间隔{{ group.intervalDays }}天)</span>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="决赛组盲注表" align="center" prop="blindStructuresName" />
+        <el-table-column label="决赛组报名要求" align="center">
+          <template #default="scope">
+            {{
+              scope.row.itemsName && scope.row.itemsNum
+                ? `${scope.row.itemsName} x ${scope.row.itemsNum}`
+                : scope.row.itemsName || scope.row.itemsNum || '—'
+            }}
+          </template>
+        </el-table-column>
+        <el-table-column label="奖励" align="center">
+          <template #default="scope">
+            <div v-if="scope.row.itemsPrizeList && scope.row.itemsPrizeList.length > 0">
+              <!-- 显示第一名奖励 -->
+              <div>
+                第{{ scope.row.itemsPrizeList[0].ranking }}名:{{ scope.row.itemsPrizeList[0].quantity }} {{ scope.row.itemsPrizeList[0].itemsName }}
+              </div>
+              <!-- 如果有更多奖励,用 tooltip 显示 -->
+              <el-tooltip v-if="scope.row.itemsPrizeList.length > 1" :content="getRewardTooltipContent(scope.row.itemsPrizeList)" placement="top">
+                <span class="more-rewards">更多</span>
+              </el-tooltip>
+            </div>
+            <span v-else>—</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="创建时间" align="center" prop="createdAt" width="180">
+          <template #default="scope">
+            <span>{{ parseTime(scope.row.createdAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" width="220">
+          <template #default="scope">
+            <!-- 查看按钮 -->
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" size="small" @click="handleUpdate(scope.row)">
+                <el-icon><View /></el-icon>
+                修改
+              </el-button>
+            </el-tooltip>
+            <!-- 删除按钮 -->
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="danger" size="small" @click="handleDelete(scope.row)">
+                <el-icon><Delete /></el-icon>
+                删除
+              </el-button>
+            </el-tooltip>
+            <el-tooltip content="生成" placement="top">
+              <el-button link type="success" size="small" @click="handleGenerateMatchesForNextSevenDays(scope.row)">
+                <el-icon><VideoPlay /></el-icon>
+                生成
+              </el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改赛事组别配置主对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="650px" append-to-body>
+      <el-form ref="groupFormRef" :model="groupForm" :rules="groupRules" label-width="130px">
+        <el-form-item label="名称" prop="name">
+          <el-input v-model="groupForm.name" placeholder="请输入名称" />
+        </el-form-item>
+
+        <el-form-item label="常规组模板" prop="regularTemplateId">
+          <el-select v-model="groupForm.regularTemplateId" placeholder="选项">
+            <el-option v-for="item in itemOptionsTournamentTemplateList" :key="item.id" :label="item.label" :value="item.id" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="决赛组模板" prop="finalTemplateId">
+          <el-select v-model="groupForm.finalTemplateId" placeholder="选项">
+            <el-option v-for="item in itemOptionsTournamentTemplateList" :key="item.id" :label="item.label" :value="item.id" />
+          </el-select>
+        </el-form-item>
+        <!-- 开始日期 -->
+        <el-form-item label="决赛组日期" prop="finalStartDate">
+          <el-date-picker
+            v-model="groupForm.finalStartDate"
+            type="datetime"
+            value-format="YYYY-MM-DD HH:mm"
+            format="YYYY-MM-DD HH:mm"
+            placeholder="选择开始日期和时间"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <!-- 开始日期 -->
+        <el-form-item label="常规组日期" prop="startDate">
+          <el-date-picker v-model="groupForm.startDate" type="date" placeholder="选择开始日期" style="width: 100%" />
+        </el-form-item>
+        <!-- 组别列表 -->
+        <el-form-item label="组别">
+          <div v-for="(item, index) in groupList" :key="index" style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px">
+            <span style="width: 60px">{{ item.name }}组</span>
+            间隔天数:<el-input-number
+              v-model="item.intervalDays"
+              :min="0"
+              :max="7"
+              controls-position="right"
+              placeholder="间隔天数"
+              style="width: 80px"
+            />
+            <el-time-picker v-model="item.time" value-format="HH:mm" format="HH:mm" placeholder="选择时间" style="flex: 1; min-width: 120px" />
+            <el-button type="primary" icon="Plus" @click="addGroup" v-if="index === groupList.length - 1" style="width: 40px; height: 40px" />
+            <el-button type="primary" icon="Minus" @click="removeGroup(index)" v-else style="width: 40px; height: 40px" />
+          </div>
+        </el-form-item>
+      </el-form>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" @click="submitGroupForm" type="primary">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="EventGroupConfig" lang="ts">
+import {
+  listEventGroupConfig,
+  getEventGroupConfig,
+  delEventGroupConfig,
+  addEventGroupConfig,
+  updateEventGroupConfig,
+  generateXiLieTournament
+} from '@/api/system/business/eventGroupConfig';
+import { selectTournamentsVoListTemplateList } from '@/api/system/business/tournamentsTemplate';
+import { EventGroupConfigVO, EventGroupConfigQuery, EventGroupConfigForm } from '@/api/system/business/eventGroupConfig/types';
+import { ElSelect } from 'element-plus';
+import { ref } from 'vue';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const eventGroupConfigList = ref<EventGroupConfigVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const eventGroupConfigFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: EventGroupConfigForm = {
+  id: undefined,
+  name: undefined,
+  regularTemplateId: undefined,
+  finalTemplateId: undefined,
+  startDate: undefined,
+  createdAt: undefined
+};
+const data = reactive<PageData<EventGroupConfigForm, EventGroupConfigQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    name: undefined,
+    regularTemplateId: undefined,
+    finalTemplateId: undefined,
+    startDate: undefined,
+    createdAt: undefined,
+    params: {}
+  },
+  rules: {
+    id: [{ required: true, message: '不能为空', trigger: 'blur' }],
+    name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
+    startDate: [{ required: true, message: '日期不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询赛事组别配置主列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listEventGroupConfig(queryParams.value);
+  eventGroupConfigList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  eventGroupConfigFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: EventGroupConfigVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加';
+};
+
+/** 修改按钮操作 */
+/** 修改按钮操作 */
+const handleUpdate = async (row?: EventGroupConfigVO) => {
+  reset();
+
+  if (row) {
+    // 获取要修改的记录
+    const _id = row.id;
+    const res = await getEventGroupConfig(_id);
+
+    // 将数据赋值到 form.value
+    Object.assign(form.value, res.data);
+
+    // 处理 groupList 数据
+    if (res.data.groups && Array.isArray(res.data.groups)) {
+      groupList.value = res.data.groups.map((group) => ({
+        name: group.groupName,
+        time: group.executionTime,
+        intervalDays: group.intervalDays
+      }));
+    } else {
+      // 如果没有 groups 数据,初始化默认值
+      groupList.value = [{ name: 'A', time: '', intervalDays: 0 }];
+    }
+
+    // 设置表单其他字段
+    groupForm.value.regularTemplateId = res.data.regularTemplateId;
+    groupForm.value.finalTemplateId = res.data.finalTemplateId;
+    groupForm.value.startDate = res.data.startDate;
+    groupForm.value.name = res.data.name;
+    groupForm.value.finalStartDate = res.data.finalStartDate;
+
+    dialog.title = '修改';
+  } else {
+    // 新增情况
+    dialog.title = '新增';
+  }
+
+  dialog.visible = true;
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: EventGroupConfigVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delEventGroupConfig(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download(
+    'business/eventGroupConfig/export',
+    {
+      ...queryParams.value
+    },
+    `eventGroupConfig_${new Date().getTime()}.xlsx`
+  );
+};
+
+onMounted(() => {
+  getList();
+  handleBlindStructureChange();
+});
+
+const itemOptionsTournamentTemplateList = ref<{ id: number; label: string }[]>([]);
+// 加载报名条件选项
+const handleBlindStructureChange = async () => {
+  try {
+    const res = await selectTournamentsVoListTemplateList();
+    if (res.code === 200) {
+      // 使用 unknown 中间类型进行类型转换
+      const data2 = res.data as unknown as { id: number; name: string }[];
+      const list = [];
+      for (let i = 0; i < data2.length; i++) {
+        const item = data2[i];
+        list.push({
+          id: item.id,
+          label: item.name
+        });
+      }
+      itemOptionsTournamentTemplateList.value = list;
+    } else {
+      alert('加载失败:' + res.msg);
+    }
+  } catch (error) {
+    console.error('请求出错:', error);
+  }
+};
+
+// 组别表单数据
+const groupForm = ref<{
+  regularTemplateId: string | number;
+  finalTemplateId: string | number;
+  startDate: string;
+  finalStartDate: string;
+  generateDays: number;
+  name: string;
+}>({
+  regularTemplateId: '',
+  finalTemplateId: '',
+  startDate: '',
+  finalStartDate: '',
+  generateDays: 1,
+  name: ''
+});
+
+// 组别列表(修改为包含时间和名称的对象数组)
+const groupList = ref<{ name: string; time: string; intervalDays: number }[]>([{ name: 'A', time: '', intervalDays: 0 }]);
+// 表单规则(修改)
+const groupRules = {
+  name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
+  startDate: [{ required: true, message: '常规组日期不能为空', trigger: 'blur' }],
+  finalStartDate: [{ required: true, message: '决赛组日期不能为空', trigger: 'blur' }],
+  regularTemplateId: [{ required: true, message: '请输入组别模板名称', trigger: 'blur' }],
+  finalTemplateId: [{ required: true, message: '请选择赛制类型', trigger: 'change' }]
+};
+
+// 添加组别方法(修改)
+const addGroup = () => {
+  const lastGroup = groupList.value[groupList.value.length - 1];
+  let nextLetter = 'A';
+
+  // 获取最后一个组别的字母
+  if (lastGroup && lastGroup.name) {
+    const lastChar = lastGroup.name.toUpperCase();
+    // 计算下一个字母的ASCII码
+    const nextCharCode = lastChar.charCodeAt(0) + 1;
+    nextLetter = String.fromCharCode(nextCharCode);
+
+    // 如果超过Z,从A开始循环
+    if (nextCharCode > 90) {
+      nextLetter = 'A';
+    }
+  }
+
+  groupList.value.push({ name: nextLetter, time: '', intervalDays: 0 });
+};
+// 删除组别方法(修正)
+const removeGroup = (index: number) => {
+  if (groupList.value.length > 1) {
+    // 删除该组别
+    groupList.value.splice(index, 1);
+
+    // 重新生成所有组别的字母顺序(从A开始连续分配)
+    const newGroupList = [];
+    for (let i = 0; i < groupList.value.length; i++) {
+      const letter = String.fromCharCode(65 + i); // 65是'A'的ASCII码
+      newGroupList.push({
+        name: letter,
+        time: groupList.value[i].time,
+        intervalDays: groupList.value[i].intervalDays
+      });
+    }
+
+    // 更新组别列表
+    groupList.value = newGroupList;
+  }
+};
+// 提交表单方法
+const submitGroupForm = async () => {
+  try {
+    // 验证表单
+    await eventGroupConfigFormRef.value?.validate();
+
+    buttonLoading.value = true;
+
+    // 将 groupForm 和 groupList 数据整合到 form.value 中
+    form.value = {
+      ...form.value,
+      regularTemplateId: groupForm.value.regularTemplateId,
+      finalTemplateId: groupForm.value.finalTemplateId,
+      startDate: groupForm.value.startDate,
+      finalStartDate: groupForm.value.finalStartDate,
+      name: groupForm.value.name || '', // 如果名称字段在 groupForm 中
+      groups: groupList.value.map((group) => ({
+        groupName: group.name,
+        executionTime: group.time,
+        intervalDays: group.intervalDays
+      }))
+    };
+    if (form.value.id) {
+      await updateEventGroupConfig(form.value).finally(() => (buttonLoading.value = false));
+    } else {
+      await addEventGroupConfig(form.value).finally(() => (buttonLoading.value = false));
+    }
+
+    proxy?.$modal.msgSuccess('操作成功');
+    dialog.visible = false;
+    await getList();
+  } catch (error) {
+    console.error('提交失败:', error);
+    buttonLoading.value = false;
+  }
+};
+// 获取奖励提示内容
+const getRewardTooltipContent = (rewards: any[]) => {
+  return rewards.map((prize) => `第${prize.ranking}名:${prize.quantity} ${prize.itemsName}`).join('\n');
+};
+//生成系列赛相关
+const handleGenerateMatchesForNextSevenDays = async (row?: EventGroupConfigVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认生成对应数据项?').finally(() => (loading.value = false));
+  // 使用 row.generateDay 作为 days 参数传递
+  await generateXiLieTournament(row.id);
+  proxy?.$modal.msgSuccess('生成成功');
+  await getList();
+};
+</script>

+ 112 - 1
src/views/system/physical/judgePosition/index.vue

@@ -71,7 +71,7 @@
       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
     </el-card>
     <!-- 添加或修改职务管理对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+    <!--    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
       <el-form ref="judgePositionFormRef" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="职务名称" prop="name">
           <el-input v-model="form.name" placeholder="请输入职务名称,如 裁判长" />
@@ -86,6 +86,56 @@
           <el-button @click="cancel">取 消</el-button>
         </div>
       </template>
+    </el-dialog>-->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="650px" append-to-body>
+      <el-form ref="groupFormRef" :model="groupForm" :rules="groupRules" label-width="130px">
+        <el-form-item label="名称" prop="judgeId">
+          <el-input placeholder="请输入名称" />
+        </el-form-item>
+        <!-- 组别模板 -->
+        <el-form-item label="常规组别模板" prop="templateName">
+          <el-select v-model="groupForm.templateName" placeholder="请选择赛制类型" clearable>
+            <el-option label="常规赛模版" value="regular" />
+            <el-option label="决赛组别模版" value="final" />
+          </el-select>
+        </el-form-item>
+
+        <!-- 赛制类型 -->
+        <el-form-item label="决赛组别模板" prop="competitionType">
+          <el-select v-model="groupForm.competitionType" placeholder="请选择赛制类型" clearable>
+            <el-option label="常规赛模版" value="regular" />
+            <el-option label="决赛组别模版" value="final" />
+          </el-select>
+        </el-form-item>
+        <!-- 开始日期 -->
+        <el-form-item label="日期" prop="startDate">
+          <el-date-picker v-model="groupForm.startDate" type="date" placeholder="选择开始日期" style="width: 100%" />
+        </el-form-item>
+        <!-- 组别列表 -->
+        <el-form-item label="组别">
+          <div v-for="(item, index) in groupList" :key="index" style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px">
+            <span style="width: 60px">{{ item.name }}组</span>
+            间隔天数:<el-input-number
+              v-model="item.intervalDays"
+              :min="0"
+              :max="7"
+              controls-position="right"
+              placeholder="间隔天数"
+              style="width: 80px"
+            />
+            <el-time-picker v-model="item.time" value-format="HH:mm" format="HH:mm" placeholder="选择时间" style="flex: 1; min-width: 120px" />
+            <el-button type="primary" icon="Plus" @click="addGroup" v-if="index === groupList.length - 1" style="width: 40px; height: 40px" />
+            <el-button type="primary" icon="Minus" @click="removeGroup(index)" v-else style="width: 40px; height: 40px" />
+          </div>
+        </el-form-item>
+      </el-form>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary">确 定</el-button>
+          <el-button>取 消</el-button>
+        </div>
+      </template>
     </el-dialog>
   </div>
 </template>
@@ -235,4 +285,65 @@ const handleExport = () => {
 onMounted(() => {
   getList();
 });
+
+// 组别表单数据
+const groupForm = ref({
+  templateName: '',
+  competitionType: '',
+  startDate: '',
+  generateDays: 1,
+  description: ''
+});
+
+// 组别列表(修改为包含时间和名称的对象数组)
+const groupList = ref<{ name: string; time: string; intervalDays: number }[]>([{ name: 'A', time: '', intervalDays: 0 }]);
+// 表单规则(修改)
+const groupRules = {
+  templateName: [{ required: true, message: '请输入组别模板名称', trigger: 'blur' }],
+  competitionType: [{ required: true, message: '请选择赛制类型', trigger: 'change' }],
+  generateDays: [{ required: true, message: '请输入生成天数', trigger: 'blur' }]
+};
+
+// 添加组别方法(修改)
+// 添加组别方法(修改)
+const addGroup = () => {
+  const lastGroup = groupList.value[groupList.value.length - 1];
+  let nextLetter = 'A';
+
+  // 获取最后一个组别的字母
+  if (lastGroup && lastGroup.name) {
+    const lastChar = lastGroup.name.toUpperCase();
+    // 计算下一个字母的ASCII码
+    const nextCharCode = lastChar.charCodeAt(0) + 1;
+    nextLetter = String.fromCharCode(nextCharCode);
+
+    // 如果超过Z,从A开始循环
+    if (nextCharCode > 90) {
+      nextLetter = 'A';
+    }
+  }
+
+  groupList.value.push({ name: nextLetter, time: '', intervalDays: 0 });
+};
+// 删除组别方法(修正)
+const removeGroup = (index: number) => {
+  if (groupList.value.length > 1) {
+    // 删除该组别
+    groupList.value.splice(index, 1);
+
+    // 重新生成所有组别的字母顺序(从A开始连续分配)
+    const newGroupList = [];
+    for (let i = 0; i < groupList.value.length; i++) {
+      const letter = String.fromCharCode(65 + i); // 65是'A'的ASCII码
+      newGroupList.push({
+        name: letter,
+        time: groupList.value[i].time,
+        intervalDays: groupList.value[i].intervalDays
+      });
+    }
+
+    // 更新组别列表
+    groupList.value = newGroupList;
+  }
+};
 </script>