index.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. <template>
  2. <div class="p-2">
  3. <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
  4. <div v-show="showSearch" class="mb-[10px]">
  5. <el-card shadow="hover">
  6. <el-form ref="queryFormRef" :model="queryParams" :inline="true">
  7. <el-form-item label="项目类型" prop="projectTypeFilter">
  8. <el-select v-model="projectTypeFilter" placeholder="请选择项目类型" clearable @change="handleProjectTypeFilterChange">
  9. <el-option
  10. v-for="dict in game_project_type"
  11. :key="dict.value"
  12. :label="dict.label"
  13. :value="dict.value"
  14. />
  15. </el-select>
  16. </el-form-item>
  17. <el-form-item label="项目" prop="projectId">
  18. <el-select v-model="queryParams.projectId" placeholder="请选择项目" clearable>
  19. <el-option
  20. v-for="project in filteredProjectList"
  21. :key="project.projectId"
  22. :label="project.projectName"
  23. :value="project.projectId"
  24. />
  25. </el-select>
  26. </el-form-item>
  27. <el-form-item label="组别" prop="groupName">
  28. <el-input v-model="queryParams.groupName" placeholder="请输入组别名称" clearable @keyup.enter="handleQuery" />
  29. </el-form-item>
  30. <el-form-item>
  31. <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
  32. <el-button icon="Refresh" @click="resetQuery">重置</el-button>
  33. </el-form-item>
  34. </el-form>
  35. </el-card>
  36. </div>
  37. </transition>
  38. <el-card shadow="never">
  39. <template #header>
  40. <el-row :gutter="10" class="mb8">
  41. <el-col :span="1.5">
  42. <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:gameEventGroup:add']"> 新增 </el-button>
  43. </el-col>
  44. <el-col :span="1.5">
  45. <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:gameEventGroup:edit']"
  46. >修改
  47. </el-button>
  48. </el-col>
  49. <el-col :span="1.5">
  50. <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:gameEventGroup:remove']"
  51. >删除
  52. </el-button>
  53. </el-col>
  54. <!-- <el-col :span="1.5">
  55. <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:gameEventGroup:export']">导出 </el-button>
  56. </el-col> -->
  57. <right-toolbar v-model:showSearch="showSearch" :columns="columns" @queryTable="getList"></right-toolbar>
  58. </el-row>
  59. </template>
  60. <el-table v-loading="loading" border :data="gameEventGroupList" @selection-change="handleSelectionChange">
  61. <el-table-column type="selection" width="55" align="center" />
  62. <el-table-column label="组别id" align="center" prop="groupId" v-if="columns[0].visible" />
  63. <el-table-column label="项目类型" align="center" v-if="columns[1].visible">
  64. <template #default="scope">
  65. <dict-tag :options="game_project_type" :value="getProjectTypeByProjectId(scope.row.projectId) || ''" />
  66. </template>
  67. </el-table-column>
  68. <el-table-column label="项目" align="center" v-if="columns[2].visible">
  69. <template #default="scope">
  70. {{ getProjectNameByProjectId(scope.row.projectId) }}
  71. </template>
  72. </el-table-column>
  73. <el-table-column label="组别" align="center" prop="groupName" v-if="columns[3].visible" />
  74. <el-table-column label="人/组" align="center" prop="personNum" v-if="columns[4].visible" />
  75. <el-table-column label="组数" align="center" prop="includeGroupNum" v-if="columns[5].visible" />
  76. <el-table-column label="道数" align="center" prop="trackNum" v-if="columns[6].visible" />
  77. <el-table-column label="场地数量" align="center" prop="fieldNum" v-if="columns[7].visible" />
  78. <el-table-column label="每组用时(分钟)" align="center" prop="duration" v-if="columns[8].visible" />
  79. <el-table-column label="比赛时间" align="center" v-if="columns[9].visible">
  80. <template #default="scope">
  81. {{ formatFullDateTime(scope.row.beginTime) }} ~ {{ formatFullDateTime(scope.row.endTime) }}
  82. <!-- {{ scope.row.beginTime }} ~ {{ scope.row.endTime }} -->
  83. </template>
  84. </el-table-column>
  85. <el-table-column label="成员性别" align="center" prop="memberGender" v-if="columns[10].visible">
  86. <template #default="scope">
  87. <dict-tag :options="sys_user_sex" :value="scope.row.memberGender" />
  88. </template>
  89. </el-table-column>
  90. <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  91. <template #default="scope">
  92. <el-tooltip content="分组" placement="top">
  93. <el-button link type="success" icon="Grid" @click="handleGroup(scope.row)" v-hasPermi="['system:gameEventGroup:edit']"></el-button>
  94. </el-tooltip>
  95. <el-tooltip content="修改" placement="top">
  96. <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:gameEventGroup:edit']"></el-button>
  97. </el-tooltip>
  98. <el-tooltip content="删除" placement="top">
  99. <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:gameEventGroup:remove']"></el-button>
  100. </el-tooltip>
  101. </template>
  102. </el-table-column>
  103. </el-table>
  104. <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
  105. </el-card>
  106. <!-- 添加或修改赛事分组对话框 -->
  107. <el-dialog :title="dialog.title" v-model="dialog.visible" width="900px" append-to-body>
  108. <el-form ref="gameEventGroupFormRef" :model="form" :rules="rules" label-width="120px">
  109. <el-row :gutter="20">
  110. <el-col :span="12">
  111. <el-form-item label="项目类型" prop="projectTypeFilter">
  112. <el-select
  113. v-model="formProjectTypeFilter"
  114. placeholder="请选择项目类型"
  115. style="width: 100%"
  116. @change="handleFormProjectTypeFilterChange"
  117. :disabled="!!form.groupId"
  118. >
  119. <el-option
  120. v-for="dict in game_project_type"
  121. :key="dict.value"
  122. :label="dict.label"
  123. :value="dict.value"
  124. />
  125. </el-select>
  126. </el-form-item>
  127. </el-col>
  128. <el-col :span="12">
  129. <el-form-item label="项目" prop="projectId">
  130. <el-select
  131. v-model="form.projectId"
  132. placeholder="请选择项目"
  133. style="width: 100%"
  134. @change="handleFormProjectChange"
  135. :disabled="!formProjectTypeFilter || !!form.groupId"
  136. >
  137. <el-option
  138. v-for="project in filteredFormProjectList"
  139. :key="project.projectId"
  140. :label="project.projectName"
  141. :value="project.projectId"
  142. />
  143. </el-select>
  144. </el-form-item>
  145. </el-col>
  146. </el-row>
  147. <el-row :gutter="20">
  148. <el-col :span="12">
  149. <el-form-item label="组别名称" prop="groupName">
  150. <el-input v-model="form.groupName" placeholder="请输入组别名称" />
  151. </el-form-item>
  152. </el-col>
  153. <el-col :span="12">
  154. <el-form-item label="成员性别" prop="memberGender">
  155. <el-select v-model="form.memberGender" placeholder="请选择性别" style="width: 100%">
  156. <el-option
  157. v-for="dict in sys_user_sex"
  158. :key="dict.value"
  159. :label="dict.label"
  160. :value="dict.value"
  161. />
  162. </el-select>
  163. </el-form-item>
  164. </el-col>
  165. </el-row>
  166. <el-row :gutter="20">
  167. <el-col :span="12">
  168. <el-form-item label="人/组" prop="personNum">
  169. <el-input-number v-model="form.personNum" :min="1" placeholder="请输入每组人数" style="width: 100%" />
  170. </el-form-item>
  171. </el-col>
  172. <el-col :span="12">
  173. <el-form-item label="组数" prop="includeGroupNum">
  174. <el-input-number v-model="form.includeGroupNum" :min="1" placeholder="请输入组数" style="width: 100%" />
  175. </el-form-item>
  176. </el-col>
  177. </el-row>
  178. <el-row :gutter="20">
  179. <el-col :span="12">
  180. <el-form-item label="道数" prop="trackNum">
  181. <el-input-number v-model="form.trackNum" :min="1" placeholder="请输入道数" style="width: 100%" />
  182. </el-form-item>
  183. </el-col>
  184. <el-col :span="12">
  185. <el-form-item label="场地数量" prop="fieldNum">
  186. <el-input-number v-model="form.fieldNum" :min="1" placeholder="请输入场地数量" style="width: 100%" />
  187. </el-form-item>
  188. </el-col>
  189. </el-row>
  190. <el-row :gutter="20">
  191. <el-col :span="12">
  192. <el-form-item label="每组用时(分钟)" prop="duration">
  193. <el-input-number v-model="form.duration" :min="1" placeholder="请输入每组用时" style="width: 100%" />
  194. </el-form-item>
  195. </el-col>
  196. <el-col :span="12">
  197. <el-form-item label="组别开始时间" prop="beginTime">
  198. <el-date-picker
  199. v-model="form.beginTime"
  200. type="datetime"
  201. placeholder="请选择开始时间"
  202. format="YYYY-MM-DD HH:mm:ss"
  203. value-format="YYYY-MM-DD HH:mm:ss"
  204. style="width: 100%"
  205. :disabled="!form.projectId"
  206. :disabled-date="disabledDate"
  207. />
  208. </el-form-item>
  209. </el-col>
  210. </el-row>
  211. <el-row :gutter="20">
  212. <el-col :span="12">
  213. <el-form-item label="组别结束时间" prop="endTime">
  214. <el-input
  215. v-model="calculatedEndTime"
  216. placeholder="自动计算"
  217. disabled
  218. style="width: 100%"
  219. />
  220. </el-form-item>
  221. </el-col>
  222. </el-row>
  223. <el-form-item label="备注" prop="remark">
  224. <el-input v-model="form.remark" type="textarea" placeholder="请输入备注内容" />
  225. </el-form-item>
  226. </el-form>
  227. <template #footer>
  228. <div class="dialog-footer">
  229. <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
  230. <el-button @click="cancel">取 消</el-button>
  231. </div>
  232. </template>
  233. </el-dialog>
  234. </div>
  235. </template>
  236. <script setup name="GameEventGroup" lang="ts">
  237. import { nextTick, ref, onMounted, computed } from 'vue';
  238. import { useRouter } from 'vue-router';
  239. import { listGameEventGroup, getGameEventGroup, delGameEventGroup, addGameEventGroup, updateGameEventGroup } from '@/api/system/gameEventGroup';
  240. import { listGameEventProject } from '@/api/system/gameEventProject';
  241. import { GameEventGroupVO, GameEventGroupQuery, GameEventGroupForm } from '@/api/system/gameEventGroup/types';
  242. import { GameEventProjectVO } from '@/api/system/gameEventProject/types';
  243. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  244. const router = useRouter();
  245. // 字典数据
  246. const { game_project_type, sys_user_sex } = toRefs<any>(proxy?.useDict('game_project_type', 'sys_user_sex'));
  247. const gameEventGroupList = ref<GameEventGroupVO[]>([]);
  248. const projectList = ref<GameEventProjectVO[]>([]);
  249. const buttonLoading = ref(false);
  250. const loading = ref(true);
  251. const showSearch = ref(true);
  252. const ids = ref<Array<string | number>>([]);
  253. const single = ref(true);
  254. const multiple = ref(true);
  255. const total = ref(0);
  256. // 项目类型过滤器(用于查询和表单,不存储在数据中)
  257. const projectTypeFilter = ref<string>('');
  258. const formProjectTypeFilter = ref<string>('');
  259. // 列显隐数据
  260. const columns = ref<FieldOption[]>([
  261. { key: 0, label: '组别id', visible: false },
  262. { key: 1, label: '项目类型', visible: true },
  263. { key: 2, label: '项目', visible: true },
  264. { key: 3, label: '组别', visible: true },
  265. { key: 4, label: '人/组', visible: true },
  266. { key: 5, label: '组数', visible: true },
  267. { key: 6, label: '道数', visible: true },
  268. { key: 7, label: '场地数量', visible: true },
  269. { key: 8, label: '每组用时(分钟)', visible: true },
  270. { key: 9, label: '比赛时间', visible: true },
  271. { key: 10, label: '成员性别', visible: true },
  272. ]);
  273. const queryFormRef = ref<ElFormInstance>();
  274. const gameEventGroupFormRef = ref<ElFormInstance>();
  275. const dialog = reactive<DialogOption>({
  276. visible: false,
  277. title: ''
  278. });
  279. const initFormData: GameEventGroupForm = {
  280. groupId: undefined,
  281. eventId: undefined,
  282. groupName: undefined,
  283. projectList: undefined,
  284. selectedProjects: [],
  285. memberGender: undefined,
  286. sortOrder: undefined,
  287. sortRule: undefined,
  288. status: undefined,
  289. remark: undefined,
  290. includeGroupNum: undefined,
  291. projectId: undefined,
  292. personNum: undefined,
  293. beginTime: undefined,
  294. endTime: undefined,
  295. trackNum: undefined,
  296. fieldNum: undefined,
  297. duration: undefined
  298. };
  299. const data = reactive<PageData<GameEventGroupForm, GameEventGroupQuery>>({
  300. form: { ...initFormData },
  301. queryParams: {
  302. pageNum: 1,
  303. pageSize: 10,
  304. orderByColumn: undefined,
  305. isAsc: undefined,
  306. projectId: undefined,
  307. groupName: undefined
  308. },
  309. rules: {
  310. projectId: [{ required: true, message: '请选择项目', trigger: 'change' }],
  311. groupName: [{ required: true, message: '组别名称不能为空', trigger: 'blur' }],
  312. memberGender: [{ required: true, message: '成员性别不能为空', trigger: 'change' }],
  313. personNum: [{ required: true, message: '每组人数不能为空', trigger: 'blur' }],
  314. includeGroupNum: [{ required: true, message: '组数不能为空', trigger: 'blur' }],
  315. trackNum: [{ required: true, message: '道数不能为空', trigger: 'blur' }],
  316. fieldNum: [{ required: true, message: '场地数量不能为空', trigger: 'blur' }],
  317. duration: [{ required: true, message: '每组用时不能为空', trigger: 'blur' }],
  318. beginTime: [{ required: true, message: '开始时间不能为空', trigger: 'change' }]
  319. }
  320. });
  321. const { queryParams, form, rules } = toRefs(data);
  322. // 过滤后的项目列表(用于查询)
  323. const filteredProjectList = computed(() => {
  324. if (!projectTypeFilter.value) return projectList.value;
  325. return projectList.value.filter(project => project.projectType === projectTypeFilter.value);
  326. });
  327. // 过滤后的项目列表(用于表单)
  328. const filteredFormProjectList = computed(() => {
  329. if (!formProjectTypeFilter.value) return [];
  330. return projectList.value.filter(project => project.projectType === formProjectTypeFilter.value);
  331. });
  332. // 根据项目ID获取项目类型
  333. const getProjectTypeByProjectId = (projectId: string | number) => {
  334. if (!projectId) return '';
  335. const project = projectList.value.find(p => p.projectId === projectId);
  336. return project?.projectType || '';
  337. };
  338. // 根据项目ID获取项目名称
  339. const getProjectNameByProjectId = (projectId: string | number) => {
  340. if (!projectId) return '';
  341. const project = projectList.value.find(p => p.projectId === projectId);
  342. return project?.projectName || '';
  343. };
  344. // 根据项目ID获取项目开始时间
  345. const getProjectStartTimeByProjectId = (projectId: string | number) => {
  346. if (!projectId) return '';
  347. const project = projectList.value.find(p => p.projectId === projectId);
  348. if (project && project.startTime) {
  349. try {
  350. const startDate = new Date(project.startTime);
  351. if (!isNaN(startDate.getTime())) {
  352. const year = startDate.getFullYear();
  353. const month = String(startDate.getMonth() + 1).padStart(2, '0');
  354. const day = String(startDate.getDate()).padStart(2, '0');
  355. const hours = String(startDate.getHours()).padStart(2, '0');
  356. const minutes = String(startDate.getMinutes()).padStart(2, '0');
  357. const seconds = String(startDate.getSeconds()).padStart(2, '0');
  358. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  359. }
  360. } catch (error) {
  361. console.warn('项目开始时间解析失败:', error);
  362. }
  363. }
  364. return '';
  365. };
  366. // 计算预计结束时间
  367. const calculatedEndTime = computed(() => {
  368. if (!form.value.beginTime || !form.value.duration || !form.value.includeGroupNum) {
  369. return '';
  370. }
  371. const beginTime = new Date(form.value.beginTime);
  372. if (isNaN(beginTime.getTime())) return '';
  373. const totalMinutes = form.value.duration * form.value.includeGroupNum;
  374. const endTime = new Date(beginTime.getTime() + totalMinutes * 60 * 1000);
  375. const year = endTime.getFullYear();
  376. const month = String(endTime.getMonth() + 1).padStart(2, '0');
  377. const day = String(endTime.getDate()).padStart(2, '0');
  378. const hours = String(endTime.getHours()).padStart(2, '0');
  379. const minutes = String(endTime.getMinutes()).padStart(2, '0');
  380. const seconds = String(endTime.getSeconds()).padStart(2, '0');
  381. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  382. });
  383. // 禁用日期(限制在项目时间范围内)
  384. const disabledDate = (time: Date) => {
  385. if (!form.value.projectId) return false;
  386. const project = projectList.value.find(p => p.projectId === form.value.projectId);
  387. if (!project || !project.startTime || !project.endTime) return false;
  388. const projectStart = new Date(project.startTime);
  389. const projectEnd = new Date(project.endTime);
  390. // 禁用项目时间范围外的日期
  391. return time <= projectStart || time >= projectEnd;
  392. };
  393. // 格式化完整日期时间
  394. const formatFullDateTime = (dateTime: string | null | undefined): string => {
  395. if (!dateTime) return '-';
  396. // 增加对空字符串的检查
  397. if (dateTime === '') return '-';
  398. let date: Date;
  399. try {
  400. // 尝试解析时间字符串
  401. date = new Date(dateTime);
  402. if (isNaN(date.getTime())) {
  403. return '-';
  404. }
  405. } catch (error) {
  406. console.warn('时间格式化失败:', error);
  407. return '-';
  408. }
  409. const year = date.getFullYear();
  410. const month = String(date.getMonth() + 1).padStart(2, '0');
  411. const day = String(date.getDate()).padStart(2, '0');
  412. const hours = String(date.getHours()).padStart(2, '0');
  413. const minutes = String(date.getMinutes()).padStart(2, '0');
  414. const seconds = String(date.getSeconds()).padStart(2, '0');
  415. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  416. };
  417. /** 查询赛事分组列表 */
  418. const getList = async () => {
  419. loading.value = true;
  420. const res = await listGameEventGroup(queryParams.value);
  421. gameEventGroupList.value = res.rows;
  422. total.value = res.total;
  423. loading.value = false;
  424. };
  425. // 获取赛事项目列表
  426. const getProjectList = async () => {
  427. const res = await listGameEventProject({
  428. pageNum: 1,
  429. pageSize: 1000,
  430. orderByColumn: '',
  431. isAsc: ''
  432. });
  433. projectList.value = res.rows;
  434. };
  435. // 查询条件中项目类型变化
  436. const handleProjectTypeFilterChange = () => {
  437. queryParams.value.projectId = undefined;
  438. };
  439. // 表单中项目类型变化
  440. const handleFormProjectTypeFilterChange = () => {
  441. form.value.projectId = undefined;
  442. form.value.beginTime = undefined;
  443. form.value.endTime = undefined;
  444. form.value.trackNum = undefined;
  445. form.value.fieldNum = undefined;
  446. form.value.duration = undefined;
  447. // 重新获取项目列表以更新过滤
  448. getProjectList();
  449. };
  450. // 表单中项目变化
  451. const handleFormProjectChange = () => {
  452. if (form.value.projectId) {
  453. const selectedProject = projectList.value.find(p => p.projectId === form.value.projectId);
  454. if (selectedProject) {
  455. // 可以在这里设置一些默认值或者进行其他处理
  456. console.log('选中的项目:', selectedProject);
  457. }
  458. }
  459. };
  460. /** 取消按钮 */
  461. const cancel = () => {
  462. reset();
  463. dialog.visible = false;
  464. };
  465. /** 表单重置 */
  466. const reset = () => {
  467. form.value = { ...initFormData };
  468. formProjectTypeFilter.value = '';
  469. gameEventGroupFormRef.value?.resetFields();
  470. };
  471. /** 搜索按钮操作 */
  472. const handleQuery = () => {
  473. queryParams.value.pageNum = 1;
  474. getList();
  475. };
  476. /** 重置按钮操作 */
  477. const resetQuery = () => {
  478. queryFormRef.value?.resetFields();
  479. projectTypeFilter.value = '';
  480. handleQuery();
  481. };
  482. /** 多选框选中数据 */
  483. const handleSelectionChange = (selection: GameEventGroupVO[]) => {
  484. ids.value = selection.map((item) => item.groupId);
  485. single.value = selection.length != 1;
  486. multiple.value = !selection.length;
  487. };
  488. /** 新增按钮操作 */
  489. const handleAdd = () => {
  490. reset();
  491. dialog.visible = true;
  492. dialog.title = '添加赛事分组';
  493. // 获取项目列表
  494. nextTick(() => {
  495. getProjectList();
  496. // 监听项目选择变化,设置默认开始时间
  497. watch(() => form.value.projectId, (newProjectId) => {
  498. if (newProjectId && !form.value.beginTime) {
  499. form.value.beginTime = getProjectStartTimeByProjectId(newProjectId);
  500. }
  501. });
  502. });
  503. };
  504. /** 修改按钮操作 */
  505. const handleUpdate = async (row?: GameEventGroupVO) => {
  506. reset();
  507. const _groupId = row?.groupId || ids.value[0];
  508. const res = await getGameEventGroup(_groupId);
  509. Object.assign(form.value, res.data);
  510. // 根据项目ID设置项目类型过滤器
  511. if (res.data.projectId) {
  512. const project = projectList.value.find(p => p.projectId === res.data.projectId);
  513. if (project) {
  514. formProjectTypeFilter.value = project.projectType;
  515. }
  516. }
  517. // 处理时间字段的回显,增加安全检查
  518. if (res.data.beginTime) {
  519. try {
  520. // 尝试解析时间字符串
  521. const date = new Date(res.data.beginTime);
  522. if (!isNaN(date.getTime())) {
  523. // 如果解析成功,转换为正确的格式
  524. form.value.beginTime = formatFullDateTime(date.toString());
  525. // form.value.beginTime = date.toISOString().replace('T', ' ');
  526. } else {
  527. // 如果解析失败,设置为默认值
  528. console.warn('开始时间格式无效:', res.data.beginTime);
  529. form.value.beginTime = '';
  530. }
  531. } catch (error) {
  532. console.warn('开始时间解析失败:', error);
  533. form.value.beginTime = '';
  534. }
  535. }
  536. if (res.data.endTime) {
  537. try {
  538. // 尝试解析时间字符串
  539. const date = new Date(res.data.endTime);
  540. if (!isNaN(date.getTime())) {
  541. // 如果解析成功,转换为正确的格式
  542. form.value.endTime = formatFullDateTime(date.toString());
  543. } else {
  544. // 如果解析失败,设置为默认值
  545. console.warn('结束时间格式无效:', res.data.endTime);
  546. form.value.endTime = '';
  547. }
  548. } catch (error) {
  549. console.warn('结束时间解析失败:', error);
  550. form.value.endTime = '';
  551. }
  552. }
  553. dialog.visible = true;
  554. dialog.title = '修改赛事分组';
  555. // 获取项目列表
  556. nextTick(() => {
  557. getProjectList();
  558. });
  559. };
  560. /** 提交按钮 */
  561. const submitForm = () => {
  562. gameEventGroupFormRef.value?.validate(async (valid: boolean) => {
  563. if (valid) {
  564. // 校验组数和道数的关系
  565. if (form.value.includeGroupNum && form.value.trackNum && form.value.personNum) {
  566. const totalCapacity = form.value.includeGroupNum * form.value.trackNum;
  567. if (totalCapacity < form.value.personNum) {
  568. const recommendedGroupNum = Math.ceil(form.value.personNum / form.value.trackNum);
  569. proxy?.$modal.msgError(`组数过小请重新输入,推荐组数:${recommendedGroupNum}`);
  570. return;
  571. }
  572. }
  573. // 自动计算结束时间并赋值
  574. if (form.value.beginTime && form.value.duration && form.value.includeGroupNum) {
  575. try {
  576. const beginTime = new Date(form.value.beginTime);
  577. if (isNaN(beginTime.getTime())) {
  578. proxy?.$modal.msgError('开始时间格式无效');
  579. return;
  580. }
  581. const totalMinutes = form.value.duration * form.value.includeGroupNum;
  582. const endTime = new Date(beginTime.getTime() + totalMinutes * 60 * 1000);
  583. const year = endTime.getFullYear();
  584. const month = String(endTime.getMonth() + 1).padStart(2, '0');
  585. const day = String(endTime.getDate()).padStart(2, '0');
  586. const hours = String(endTime.getHours()).padStart(2, '0');
  587. const minutes = String(endTime.getMinutes()).padStart(2, '0');
  588. const seconds = String(endTime.getSeconds()).padStart(2, '0');
  589. form.value.endTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  590. } catch (error) {
  591. proxy?.$modal.msgError('计算结束时间失败');
  592. return;
  593. }
  594. }
  595. // 验证时间范围
  596. if (form.value.beginTime && form.value.endTime) {
  597. try {
  598. const beginTime = new Date(form.value.beginTime);
  599. const endTime = new Date(form.value.endTime);
  600. if (isNaN(beginTime.getTime()) || isNaN(endTime.getTime())) {
  601. proxy?.$modal.msgError('时间格式无效');
  602. return;
  603. }
  604. if (beginTime >= endTime) {
  605. proxy?.$modal.msgError('组别结束时间必须晚于开始时间');
  606. return;
  607. }
  608. // 验证组别时间是否在项目时间范围内
  609. if (form.value.projectId) {
  610. const selectedProject = projectList.value.find(p => p.projectId === form.value.projectId);
  611. if (selectedProject && selectedProject.startTime && selectedProject.endTime) {
  612. const projectStart = new Date(selectedProject.startTime);
  613. const projectEnd = new Date(selectedProject.endTime);
  614. if (beginTime <= projectStart || endTime >= projectEnd) {
  615. proxy?.$modal.msgError('组别比赛时间必须在项目比赛时间范围内');
  616. return;
  617. }
  618. }
  619. }
  620. } catch (error) {
  621. proxy?.$modal.msgError('时间验证失败');
  622. return;
  623. }
  624. }
  625. buttonLoading.value = true;
  626. const submitForm = { ...form.value };
  627. if (form.value.groupId) {
  628. await updateGameEventGroup(submitForm).finally(() => (buttonLoading.value = false));
  629. } else {
  630. await addGameEventGroup(submitForm).finally(() => (buttonLoading.value = false));
  631. }
  632. proxy?.$modal.msgSuccess('操作成功');
  633. dialog.visible = false;
  634. await getList();
  635. }
  636. });
  637. };
  638. /** 删除按钮操作 */
  639. const handleDelete = async (row?: GameEventGroupVO) => {
  640. const _groupIds = row?.groupId || ids.value;
  641. await proxy?.$modal.confirm('是否确认删除赛事分组编号为"' + _groupIds + '"的数据项?').finally(() => (loading.value = false));
  642. await delGameEventGroup(_groupIds);
  643. proxy?.$modal.msgSuccess('删除成功');
  644. await getList();
  645. };
  646. /** 导出按钮操作 */
  647. const handleExport = () => {
  648. proxy?.download(
  649. 'system/gameEventGroup/export',
  650. {
  651. ...queryParams.value
  652. },
  653. `gameEventGroup_${new Date().getTime()}.xlsx`
  654. );
  655. };
  656. /** 分组按钮操作 */
  657. const handleGroup = (row: GameEventGroupVO) => {
  658. router.push({ path: '/system/gameEventGroup/detail', query: { id: row.groupId } });
  659. };
  660. onMounted(() => {
  661. getList();
  662. getProjectList();
  663. });
  664. </script>