ソースを参照

feat(tournaments): 添加玩法类型和晋级条件功能

- 新增玩法类型字段(gameVariant)及下拉选择器
- 添加目标锦标赛选择器,支持远程搜索和分
fugui001 1 ヶ月 前
コミット
d29031f633

+ 6 - 0
src/api/system/business/tournaments/types.ts

@@ -60,6 +60,8 @@ export interface TournamentsVO {
    * 报名时间
    */
   signTime?: number;
+  gameVariant?: string;
+  qualifierType?: string;
 
   /**
    * 道具ID
@@ -166,6 +168,10 @@ export interface TournamentsForm extends BaseEntity {
   delayCardTime?: string;
   competitionBg?: string;
   minPlayers?: number;
+  gameVariant?: string;
+  qualifierType?: string;
+  qualifierValue?: number;
+  targetTournamentId?: number;
 }
 
 export interface ItemsPrize {

+ 6 - 1
src/api/system/business/tournamentsTemplate/types.ts

@@ -60,7 +60,8 @@ export interface TournamentsVO {
    * 报名时间
    */
   signTime?: number;
-
+  gameVariant?: number;
+  qualifierType?: number;
   /**
    * 道具ID
    */
@@ -103,6 +104,10 @@ export interface TournamentsForm extends BaseEntity {
    * 游戏类型
    */
   gameType?: string;
+  gameVariant?: string;
+  qualifierType?: string;
+  qualifierValue?: string;
+  targetTournamentId?: number;
 
   /**
    * 起始记分牌数量

+ 111 - 3
src/views/system/business/tournaments/index.vue

@@ -152,6 +152,12 @@
             </span>
           </template>
         </el-table-column>
+        <el-table-column label="玩法类型" align="center" prop="gameVariant">
+          <template #default="scope">
+            {{ getGameVariantText(scope.row.gameVariant) }}
+          </template>
+        </el-table-column>
+
         <!--        <el-table-column label="是否删除" align="center">
           <template #default="scope">
             <span
@@ -172,7 +178,7 @@
               <el-tooltip content="复制" placement="top" v-hasPermi="['business:tournaments:copy']">
                 <el-button link type="primary" icon="Files" @click="handleCopy(scope.row)"> 复制 </el-button>
               </el-tooltip>
-<!--              <el-tooltip content="恢复" placement="top">
+              <!--              <el-tooltip content="恢复" placement="top">
                 <el-button link type="primary" icon="Files" @click="handleRecoverTournament(scope.row)" v-hasPermi="['business:tournaments:query']"
                   >恢复</el-button
                 >
@@ -364,7 +370,34 @@
             </el-option>
           </el-select>
         </el-form-item>
+        <el-form-item label="玩法类型" prop="gameVariant">
+          <el-select aria-required="true" v-model="form.gameVariant" placeholder="请选择" :disabled="dialog.mode === 'view'">
+            <el-option v-for="dict in game_variant_type" :key="dict.value" :label="dict.label" :value="dict.value"> </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="目标锦标赛" prop="targetTournamentId">
+          <el-select
+            v-model="form.targetTournamentId"
+            placeholder="请选择比赛"
+            :disabled="dialog.mode === 'view'"
+            @visible-change="handleSelectVisibleChange"
+            remote
+            :remote-method="remoteMethod"
+            :loading="selectLoading"
+            clearable
+          >
+            <el-option v-for="item in selectOptions" :key="item.id" :label="item.name" :value="item.id" />
+          </el-select>
+        </el-form-item>
 
+        <el-form-item label="晋级条件类型" prop="qualifierType">
+          <el-select aria-required="true" v-model="form.qualifierType" placeholder="请选择" :disabled="dialog.mode === 'view'">
+            <el-option v-for="dict in qualifier_type" :key="dict.value" :label="dict.label" :value="dict.value"> </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="晋级条件值" prop="qualifierValue" v-if="form.qualifierType !== '0'">
+          <el-input v-model="form.qualifierValue" placeholder="请输入晋级条件值" :disabled="dialog.mode === 'view'" />
+        </el-form-item>
         <el-form-item label="报名时长" prop="signTime">
           <el-select v-model="form.signTime" placeholder="请选择" :disabled="dialog.mode === 'view'">
             <el-option v-for="dict in tournaments_time" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
@@ -651,8 +684,8 @@ import { ref } from 'vue';
 import LevelsIndex from '@/views/system/business/levels/index.vue';
 import { ClaimsVO } from '@/api/system/business/claims/types';
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { tournaments_type, tournaments_time, tournaments_status } = toRefs<any>(
-  proxy?.useDict('tournaments_type', 'tournaments_time', 'tournaments_status')
+const { tournaments_type, tournaments_time, tournaments_status, game_variant_type, qualifier_type } = toRefs<any>(
+  proxy?.useDict('tournaments_type', 'tournaments_time', 'tournaments_status', 'game_variant_type', 'qualifier_type')
 );
 
 const tournamentsList = ref<TournamentsVO[]>([]);
@@ -845,6 +878,7 @@ const competitionBg = ref('');
 const fileList2 = ref([]);
 
 import { parseTime } from '@/utils/dateUtils';
+import { ElSelect } from 'element-plus';
 // 单选控制变量(用于绑定 el-radio)
 const selectedRadio = ref<number | null>(null);
 
@@ -867,6 +901,8 @@ const initFormData: TournamentsForm = {
   name: undefined,
   startTime: undefined,
   gameType: undefined,
+  gameVariant: null,
+  qualifierType: '0',
   startingChips: undefined,
   levelDuration: undefined,
   lateRegistrationLevel: undefined,
@@ -907,6 +943,8 @@ const data = reactive<PageData<TournamentsForm, TournamentsQuery>>({
     name: [{ required: true, message: '赛事名称不能为空', trigger: 'blur' }],
     startTime: [{ required: true, message: '比赛开始时间不能为空', trigger: 'blur' }],
     gameType: [{ required: true, message: '游戏类型不能为空', trigger: 'change' }],
+    gameVariant: [{ required: true, message: '玩法类型不能为空', trigger: 'change' }],
+    qualifierType: [{ required: true, message: '晋级条件类型不能为空', trigger: 'change' }],
     lateRegistrationLevel: [{ required: true, message: '截止报名级别不能为空', trigger: 'change' }],
     signTime: [{ required: true, message: '报名时间不能为空', trigger: 'change' }],
     itemsId: [{ required: true, message: '报名条件不能为空', trigger: 'change' }],
@@ -1098,6 +1136,8 @@ const handleUpdate = async (row?: TournamentsVO, mode: 'edit' | 'view' = 'edit')
   // 设置表单数据
   Object.assign(form.value, res.data);
   form.value.signTime = String(res.data.signTime);
+  form.value.gameVariant = String(res.data.gameVariant);
+  form.value.qualifierType = String(res.data.qualifierType);
   form.value.gameType = String(res.data.gameType); // 转为字符串
   competitionIcon.value = res.data.competitionIcon;
   competitionBg.value = res.data.competitionBg;
@@ -1262,6 +1302,9 @@ onMounted(() => {
   getList();
   loadItemOptions();
   loadItemStructuresOptions();
+
+  // 直接调用 loadSelectData 来加载初始数据
+  loadSelectData('');
 });
 
 async function getAssignList() {
@@ -1717,6 +1760,71 @@ const isProdEnvironment = computed(() => {
   // 根据实际项目中的环境变量判断是否为正式环境
   return import.meta.env.MODE === 'production' || import.meta.env.VITE_APP_ENV === 'prod';
 });
+// 在 setup 中添加
+const selectOptions = ref<TournamentsVO[]>([]);
+const selectLoading = ref(false);
+const selectPageNum = ref(1);
+const selectPageSize = ref(30); // 每页数量
+const selectTotal = ref(0);
+// 远程搜索方法
+const remoteMethod = async (query: string) => {
+  if (query !== '') {
+    selectPageNum.value = 1;
+    await loadSelectData(query);
+  } else {
+    selectOptions.value = [];
+  }
+};
+
+// 加载数据(支持分页)
+const loadSelectData = async (query: string) => {
+  selectLoading.value = true;
+  const params = {
+    pageNum: selectPageNum.value,
+    pageSize: selectPageSize.value,
+    status: 0, // 只查 status=0
+    name: query, // 搜索关键词
+    sortBy: 'name',
+    isAsc: true
+  };
+
+  try {
+    const res = await listTournaments(params);
+    const rows = res.rows || [];
+    if (selectPageNum.value === 1) {
+      selectOptions.value = rows;
+    } else {
+      selectOptions.value.push(...rows);
+    }
+
+    selectTotal.value = res.total;
+  } catch (error) {
+    console.error('加载比赛列表失败:', error);
+  } finally {
+    selectLoading.value = false;
+  }
+};
+
+// 监听下拉框展开时触发加载
+const handleSelectVisibleChange = async (visible: boolean) => {
+  if (visible && selectOptions.value.length === 0) {
+    await remoteMethod('');
+  }
+};
+// 添加游戏玩法类型文本转换函数
+const getGameVariantText = (value: string | number | null | undefined): string => {
+  const numValue = Number(value);
+  switch (numValue) {
+    case 0:
+      return '德州扑克';
+    case 1:
+      return '奥马哈';
+    case 2:
+      return '短牌';
+    default:
+      return '未知';
+  }
+}
 </script>
 <style scoped>
 .more-rewards {

+ 90 - 4
src/views/system/business/tournamentsTemplate/index.vue

@@ -45,6 +45,7 @@
         :default-sort="{ prop: 'startTime', order: sortData.order }"
       >
         <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="模版比赛ID" align="center" prop="id" />
         <el-table-column label="比赛名" align="center" prop="name" />
         <el-table-column label="比赛Logo" align="center">
           <template #default="scope">
@@ -245,7 +246,33 @@
             </el-option>
           </el-select>
         </el-form-item>
-
+        <el-form-item label="玩法类型" prop="gameVariant">
+          <el-select aria-required="true" v-model="form.gameVariant" placeholder="请选择" :disabled="dialog.mode === 'view'">
+            <el-option v-for="dict in game_variant_type" :key="dict.value" :label="dict.label" :value="dict.value"> </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="目标锦标赛" prop="targetTournamentId">
+          <el-select
+            v-model="form.targetTournamentId"
+            placeholder="请选择比赛"
+            :disabled="dialog.mode === 'view'"
+            @visible-change="handleSelectVisibleChange"
+            remote
+            :remote-method="remoteMethod"
+            :loading="selectLoading"
+            clearable
+          >
+            <el-option v-for="item in selectOptions" :key="item.id" :label="item.name" :value="item.id" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="晋级条件类型" prop="qualifierType">
+          <el-select aria-required="true" v-model="form.qualifierType" placeholder="请选择" :disabled="dialog.mode === 'view'">
+            <el-option v-for="dict in qualifier_type" :key="dict.value" :label="dict.label" :value="dict.value"> </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="晋级条件值" prop="qualifierValue" v-if="form.qualifierType !== '0'">
+          <el-input v-model="form.qualifierValue" placeholder="请输入晋级条件值" :disabled="dialog.mode === 'view'" />
+        </el-form-item>
         <el-form-item label="报名时间" prop="signTime">
           <el-select v-model="form.signTime" placeholder="请选择" :disabled="dialog.mode === 'view'">
             <el-option v-for="dict in tournaments_time" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
@@ -420,9 +447,11 @@ import { selectBlingStructuresInfo } from '@/api/system/business/structures';
 import { TournamentsVO, TournamentsQuery, TournamentsForm, TournamentsBindStructuresVO } from '@/api/system/business/tournamentsTemplate/types';
 import { ref } from 'vue';
 import LevelsIndex from '@/views/system/business/levels/index.vue';
+import { ElSelect } from 'element-plus';
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { tournaments_type, tournaments_time } = toRefs<any>(proxy?.useDict('tournaments_type', 'tournaments_time'));
-
+const { tournaments_type, tournaments_time, tournaments_status, game_variant_type, qualifier_type } = toRefs<any>(
+  proxy?.useDict('tournaments_type', 'tournaments_time', 'tournaments_status', 'game_variant_type', 'qualifier_type')
+);
 const tournamentsList = ref<TournamentsVO[]>([]);
 const buttonLoading = ref(false);
 const loading = ref(true);
@@ -637,6 +666,7 @@ const assignQuery = reactive<{
 const initFormData: TournamentsForm = {
   id: undefined,
   name: undefined,
+  qualifierType: '0',
   startTime: undefined,
   gameType: undefined,
   startingChips: undefined,
@@ -679,6 +709,8 @@ const data = reactive<PageData<TournamentsForm, TournamentsQuery>>({
     name: [{ required: true, message: '赛事名称不能为空', trigger: 'blur' }],
     startTime: [{ required: true, message: '比赛开始时间不能为空', trigger: 'blur' }],
     gameType: [{ required: true, message: '游戏类型不能为空', trigger: 'change' }],
+    gameVariant: [{ required: true, message: '玩法类型不能为空', trigger: 'change' }],
+    qualifierType: [{ required: true, message: '晋级条件类型不能为空', trigger: 'change' }],
     lateRegistrationLevel: [{ required: true, message: '截止报名级别不能为空', trigger: 'change' }],
     signTime: [{ required: true, message: '报名时间不能为空', trigger: 'change' }],
     itemsId: [{ required: true, message: '报名条件不能为空', trigger: 'change' }],
@@ -860,7 +892,6 @@ const resetFormPrize = () => {
 /** 修改按钮操作 */
 const handleUpdate = async (row?: TournamentsVO, mode: 'edit' | 'view' = 'edit') => {
   reset(); // 重置表单
-
   const _id = row?.id || ids.value[0];
   const res = await getTournaments(_id);
   // 确保 gameType 是 number 类型
@@ -870,6 +901,8 @@ const handleUpdate = async (row?: TournamentsVO, mode: 'edit' | 'view' = 'edit')
   Object.assign(form.value, res.data);
   form.value.gameType = gameType; // 确保赋值正确
   form.value.signTime = signTime;
+  form.value.gameVariant = String(res.data.gameVariant);
+  form.value.qualifierType = String(res.data.qualifierType);
   competitionBg.value = res.data.competitionBg;
   competitionIcon.value = res.data.competitionIcon;
   // 处理奖励表单数据
@@ -966,6 +999,8 @@ onMounted(() => {
   getList();
   loadItemOptions();
   loadItemStructuresOptions();
+  // 直接调用 loadSelectData 来加载初始数据
+  loadSelectData('');
 });
 
 async function getAssignList() {
@@ -1202,6 +1237,57 @@ const isProdEnvironment = computed(() => {
   // 根据实际项目中的环境变量判断是否为正式环境
   return import.meta.env.MODE === 'production' || import.meta.env.VITE_APP_ENV === 'prod';
 });
+// 在 setup 中添加
+const selectOptions = ref<TournamentsVO[]>([]);
+const selectLoading = ref(false);
+const selectPageNum = ref(1);
+const selectPageSize = ref(30); // 每页数量
+const selectTotal = ref(0);
+// 远程搜索方法
+const remoteMethod = async (query: string) => {
+  if (query !== '') {
+    selectPageNum.value = 1;
+    await loadSelectData(query);
+  } else {
+    selectOptions.value = [];
+  }
+};
+
+// 加载数据(支持分页)
+const loadSelectData = async (query: string) => {
+  selectLoading.value = true;
+  const params = {
+    pageNum: selectPageNum.value,
+    pageSize: selectPageSize.value,
+    //status: 0, // 只查 status=0
+    name: query, // 搜索关键词
+    sortBy: 'name',
+    isAsc: true
+  };
+
+  try {
+    const res = await listTournaments(params);
+    const rows = res.rows || [];
+    if (selectPageNum.value === 1) {
+      selectOptions.value = rows;
+    } else {
+      selectOptions.value.push(...rows);
+    }
+
+    selectTotal.value = res.total;
+  } catch (error) {
+    console.error('加载比赛列表失败:', error);
+  } finally {
+    selectLoading.value = false;
+  }
+};
+
+// 监听下拉框展开时触发加载
+const handleSelectVisibleChange = async (visible: boolean) => {
+  if (visible && selectOptions.value.length === 0) {
+    await remoteMethod('');
+  }
+};
 </script>
 <style scoped>
 .more-rewards {