index.vue 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201
  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" label-width="100px">
  7. <el-form-item label="赛事编号" prop="eventCode">
  8. <el-input v-model="queryParams.eventCode" placeholder="请输入赛事编号" clearable @keyup.enter="handleQuery" />
  9. </el-form-item>
  10. <el-form-item label="赛事名称" prop="eventName">
  11. <el-input v-model="queryParams.eventName" placeholder="请输入赛事名称" clearable @keyup.enter="handleQuery" />
  12. </el-form-item>
  13. <el-form-item label="赛事类型" prop="eventType">
  14. <el-select v-model="queryParams.eventType" placeholder="请选择赛事类型" clearable>
  15. <el-option v-for="dict in game_event_type" :key="dict.value" :label="dict.label" :value="dict.value" />
  16. </el-select>
  17. </el-form-item>
  18. <el-form-item label="是否默认赛事" prop="isDefault">
  19. <el-select v-model="queryParams.isDefault" placeholder="请选择是否默认赛事" clearable>
  20. <el-option v-for="dict in sys_yes_no" :key="dict.value" :label="dict.label" :value="dict.value" />
  21. </el-select>
  22. </el-form-item>
  23. <el-form-item label="状态" prop="status">
  24. <el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
  25. <el-option v-for="dict in game_event_status" :key="dict.value" :label="dict.label" :value="dict.value" />
  26. </el-select>
  27. </el-form-item>
  28. <el-form-item>
  29. <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
  30. <el-button icon="Refresh" @click="resetQuery">重置</el-button>
  31. </el-form-item>
  32. </el-form>
  33. </el-card>
  34. </div>
  35. </transition>
  36. <el-card shadow="never">
  37. <template #header>
  38. <el-row :gutter="10" class="mb8">
  39. <el-col :span="1.5">
  40. <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:gameEvent:add']">新增</el-button>
  41. </el-col>
  42. <el-col :span="1.5">
  43. <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:gameEvent:edit']">修改</el-button>
  44. </el-col>
  45. <el-col :span="1.5">
  46. <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:gameEvent:remove']">删除</el-button>
  47. </el-col>
  48. <el-col :span="1.5">
  49. <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:gameEvent:export']">导出</el-button>
  50. </el-col>
  51. <!-- 新增的操作按钮,基于默认赛事 -->
  52. <el-col :span="1.5">
  53. <el-button type="warning" plain icon="Download" @click="handleDownloadTemplateDefault" v-hasPermi="['system:gameEvent:download']"
  54. >下载报名表模板
  55. </el-button>
  56. </el-col>
  57. <el-col :span="1.5">
  58. <el-button type="info" plain icon="FolderOpened" @click="handleImportRegistrationDefault" v-hasPermi="['system:gameEvent:import']"
  59. >导入报名表
  60. </el-button>
  61. </el-col>
  62. <el-col :span="1.5">
  63. <el-button type="success" plain icon="User" @click="handleAddParticipantDefault" v-hasPermi="['system:gameEvent:addParticipant']"
  64. >参赛者
  65. </el-button>
  66. </el-col>
  67. <el-col :span="1.5">
  68. <el-button type="primary" plain icon="Avatar" @click="handleAddRefereeDefault" v-hasPermi="['system:gameEvent:addReferee']"
  69. >裁判
  70. </el-button>
  71. </el-col>
  72. <el-col :span="1.5">
  73. <el-button type="info" plain icon="View" @click="handlePreviewDefault" v-hasPermi="['system:gameEvent:view']">预览 </el-button>
  74. </el-col>
  75. <!-- <el-col :span="1.5">
  76. <el-button type="warning" plain icon="DataAnalysis" @click="handleGameDataDefault" v-hasPermi="['system:gameEvent:gameData']"
  77. >排行榜
  78. </el-button>
  79. </el-col> -->
  80. <!-- <el-col :span="1.5">
  81. <el-button type="primary" plain icon="EditPen" @click="handleWriteArticleDefault" v-hasPermi="['system:gameEvent:writeArticle']"
  82. >编写文章
  83. </el-button>
  84. </el-col> -->
  85. <el-col :span="1.5">
  86. <el-button type="primary" plain icon="Download" @click="handleExportNumberTableDefault" v-hasPermi="['system:gameEvent:numberExport']"
  87. >导出号码对照表
  88. </el-button>
  89. </el-col>
  90. <el-col :span="1.5">
  91. <el-button type="success" plain icon="Postcard" @click="handleGenerateBib" v-hasPermi="['system:gameEvent:numberBib']"
  92. >生成参赛号码布
  93. </el-button>
  94. </el-col>
  95. <!-- <el-col :span="1.5">
  96. <el-button type="info" plain icon="List" @click="handleTaskList" v-hasPermi="['system:gameEvent:numberBib']"
  97. >任务列表
  98. </el-button>
  99. </el-col> -->
  100. <right-toolbar v-model:showSearch="showSearch" :columns="columns" @queryTable="getList"></right-toolbar>
  101. </el-row>
  102. </template>
  103. <el-table v-loading="loading" border :data="gameEventList" @selection-change="handleSelectionChange">
  104. <!-- 第一列:多选列 -->
  105. <el-table-column type="selection" width="55" align="center" />
  106. <!-- 第二列:操作列 -->
  107. <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="160">
  108. <template #default="scope">
  109. <el-tooltip content="修改" placement="top">
  110. <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:gameEvent:edit']"> 修改 </el-button>
  111. </el-tooltip>
  112. <el-tooltip content="生成赛事链接" placement="top">
  113. <el-button link type="warning" icon="Edit" @click="handleUpdateCode(scope.row)" v-hasPermi="['system:gameEvent:edit']"> 生成赛事码 </el-button>
  114. </el-tooltip>
  115. </template>
  116. </el-table-column>
  117. <el-table-column label="序号" align="center" type="index" />
  118. <el-table-column label="赛事id" align="center" prop="eventId" v-if="columns[0].visible" />
  119. <el-table-column label="赛事编号" align="center" prop="eventCode" v-if="columns[1].visible" />
  120. <el-table-column label="赛事名称" align="center" prop="eventName" v-if="columns[2].visible" />
  121. <el-table-column label="赛事类型" align="center" prop="eventType" v-if="columns[3].visible">
  122. <template #default="scope">
  123. <dict-tag :options="game_event_type" :value="scope.row.eventType" />
  124. </template>
  125. </el-table-column>
  126. <el-table-column label="举办地点" align="center" prop="location" v-if="columns[4].visible" />
  127. <el-table-column label="用途" align="center" prop="purpose" v-if="columns[5].visible">
  128. <template #default="scope">
  129. <dict-tag :options="game_event_purpose" :value="scope.row.purpose" />
  130. </template>
  131. </el-table-column>
  132. <el-table-column label="开始时间" align="center" prop="startTime" width="180" v-if="columns[6].visible">
  133. <template #default="scope">
  134. <span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
  135. </template>
  136. </el-table-column>
  137. <el-table-column label="结束时间" align="center" prop="endTime" width="180" v-if="columns[7].visible">
  138. <template #default="scope">
  139. <span>{{ parseTime(scope.row.endTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
  140. </template>
  141. </el-table-column>
  142. <el-table-column label="赛事链接" align="center" prop="eventUrl" width="100" v-if="columns[8].visible">
  143. <template #default="scope">
  144. <image-preview :src="scope.row.eventUrl" :width="50" :height="50" />
  145. </template>
  146. </el-table-column>
  147. <el-table-column label="裁判码" align="center" prop="refereeUrlUrl" width="100" v-if="columns[9].visible">
  148. <template #default="scope">
  149. <image-preview :src="scope.row.refereeUrlUrl" :width="50" :height="50" />
  150. </template>
  151. </el-table-column>
  152. <el-table-column label="举办单位" align="center" prop="unit" v-if="columns[10].visible" />
  153. <el-table-column label="是否默认赛事" align="center" prop="isDefault" v-if="columns[11].visible">
  154. <template #default="scope">
  155. <el-switch v-model="scope.row.isDefault" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)" v-hasPermi="['system:gameEvent:edit']"></el-switch>
  156. </template>
  157. </el-table-column>
  158. <el-table-column label="创建时间" align="center" prop="createTime" width="180" v-if="columns[12].visible">
  159. <template #default="scope">
  160. <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
  161. </template>
  162. </el-table-column>
  163. <el-table-column label="更新时间" align="center" prop="updateTime" width="180" v-if="columns[13].visible">
  164. <template #default="scope">
  165. <span>{{ parseTime(scope.row.updateTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
  166. </template>
  167. </el-table-column>
  168. <el-table-column label="状态" align="center" prop="status" v-if="columns[14].visible">
  169. <template #default="scope">
  170. <dict-tag :options="game_event_status" :value="scope.row.status" />
  171. </template>
  172. </el-table-column>
  173. <el-table-column label="备注" align="center" prop="remark" v-if="columns[15].visible" />
  174. </el-table>
  175. <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
  176. </el-card>
  177. <!-- 注册 RefereeForm 组件 -->
  178. <RefereeForm ref="refereeFormRef" />
  179. <!-- 注册 BibViewerDialog 组件 -->
  180. <BibViewerDialog ref="bibViewerDialogRef" />
  181. <!-- 排行榜对话框 -->
  182. <!-- <el-dialog :title="`赛事 ${currentEventId} 排行榜`" v-model="rankingBoardVisible" width="800px" append-to-body>
  183. <RankingBoard :eventId="currentEventId" v-if="rankingBoardVisible" />
  184. </el-dialog> -->
  185. <!-- 文章编写对话框 -->
  186. <!-- <el-dialog v-model="articleDialog.visible" :title="articleDialog.title" width="1200px" append-to-body>
  187. <el-tabs v-model="activeTab" @tab-click="handleTabClick">
  188. <el-tab-pane label="竞赛流程" name="competition-process">
  189. <div class="article-form">
  190. <el-form-item label="标题">
  191. <el-input v-model="articleData.competitionProcess.title" placeholder="请输入标题" />
  192. </el-form-item>
  193. <el-form-item label="内容">
  194. <Editor v-model="articleData.competitionProcess.content" :min-height="300" />
  195. </el-form-item>
  196. <el-form-item label="备注">
  197. <el-input v-model="articleData.competitionProcess.remark" placeholder="请输入备注" type="textarea" :rows="3" />
  198. </el-form-item>
  199. </div>
  200. </el-tab-pane>
  201. <el-tab-pane label="竞赛项目" name="competition-items">
  202. <div class="article-form">
  203. <el-form-item label="标题">
  204. <el-input v-model="articleData.competitionItems.title" placeholder="请输入标题" />
  205. </el-form-item>
  206. <el-form-item label="内容">
  207. <Editor v-model="articleData.competitionItems.content" :min-height="300" />
  208. </el-form-item>
  209. <el-form-item label="备注">
  210. <el-input v-model="articleData.competitionItems.remark" placeholder="请输入备注" type="textarea" :rows="3" />
  211. </el-form-item>
  212. </div>
  213. </el-tab-pane>
  214. <el-tab-pane label="活动议程" name="activity-agenda">
  215. <div class="article-form">
  216. <el-form-item label="标题">
  217. <el-input v-model="articleData.activityAgenda.title" placeholder="请输入标题" />
  218. </el-form-item>
  219. <el-form-item label="内容">
  220. <Editor v-model="articleData.activityAgenda.content" :min-height="300" />
  221. </el-form-item>
  222. <el-form-item label="备注">
  223. <el-input v-model="articleData.activityAgenda.remark" placeholder="请输入备注" type="textarea" :rows="3" />
  224. </el-form-item>
  225. </div>
  226. </el-tab-pane>
  227. <el-tab-pane label="项目介绍" name="project-introduction">
  228. <div class="article-form">
  229. <el-form-item label="标题">
  230. <el-input v-model="articleData.projectIntroduction.title" placeholder="请输入标题" />
  231. </el-form-item>
  232. <el-form-item label="内容">
  233. <Editor v-model="articleData.projectIntroduction.content" :min-height="300" />
  234. </el-form-item>
  235. <el-form-item label="备注">
  236. <el-input v-model="articleData.projectIntroduction.remark" placeholder="请输入备注" type="textarea" :rows="3" />
  237. </el-form-item>
  238. </div>
  239. </el-tab-pane>
  240. <el-tab-pane label="竞赛流程" name="competition-flow">
  241. <div class="article-form">
  242. <el-form-item label="标题">
  243. <el-input v-model="articleData.competitionFlow.title" placeholder="请输入标题" />
  244. </el-form-item>
  245. <el-form-item label="内容">
  246. <Editor v-model="articleData.competitionFlow.content" :min-height="300" />
  247. </el-form-item>
  248. <el-form-item label="备注">
  249. <el-input v-model="articleData.competitionFlow.remark" placeholder="请输入备注" type="textarea" :rows="3" />
  250. </el-form-item>
  251. </div>
  252. </el-tab-pane>
  253. <el-tab-pane label="赛事分组" name="event-grouping">
  254. <div class="article-form">
  255. <el-form-item label="标题">
  256. <el-input v-model="articleData.eventGrouping.title" placeholder="请输入标题" />
  257. </el-form-item>
  258. <el-form-item label="内容">
  259. <Editor v-model="articleData.eventGrouping.content" :min-height="300" />
  260. </el-form-item>
  261. <el-form-item label="备注">
  262. <el-input v-model="articleData.eventGrouping.remark" placeholder="请输入备注" type="textarea" :rows="3" />
  263. </el-form-item>
  264. </div>
  265. </el-tab-pane>
  266. <el-tab-pane label="运动员号码簿" name="athlete-handbook">
  267. <div class="article-form">
  268. <el-form-item label="标题">
  269. <el-input v-model="articleData.athleteHandbook.title" placeholder="请输入标题" />
  270. </el-form-item>
  271. <el-form-item label="内容">
  272. <Editor v-model="articleData.athleteHandbook.content" :min-height="300" />
  273. </el-form-item>
  274. <el-form-item label="备注">
  275. <el-input v-model="articleData.athleteHandbook.remark" placeholder="请输入备注" type="textarea" :rows="3" />
  276. </el-form-item>
  277. </div>
  278. </el-tab-pane>
  279. <el-tab-pane label="项目场地" name="project-venue">
  280. <div class="article-form">
  281. <el-form-item label="标题">
  282. <el-input v-model="articleData.projectVenue.title" placeholder="请输入标题" />
  283. </el-form-item>
  284. <el-form-item label="内容">
  285. <Editor v-model="articleData.projectVenue.content" :min-height="300" />
  286. </el-form-item>
  287. <el-form-item label="备注">
  288. <el-input v-model="articleData.projectVenue.remark" placeholder="请输入备注" type="textarea" :rows="3" />
  289. </el-form-item>
  290. </div>
  291. </el-tab-pane>
  292. <el-tab-pane label="交通指示" name="traffic-guide">
  293. <div class="article-form">
  294. <el-form-item label="标题">
  295. <el-input v-model="articleData.trafficGuide.title" placeholder="请输入标题" />
  296. </el-form-item>
  297. <el-form-item label="内容">
  298. <Editor v-model="articleData.trafficGuide.content" :min-height="300" />
  299. </el-form-item>
  300. <el-form-item label="备注">
  301. <el-input v-model="articleData.trafficGuide.remark" placeholder="请输入备注" type="textarea" :rows="3" />
  302. </el-form-item>
  303. </div>
  304. </el-tab-pane>
  305. <el-tab-pane label="快捷报名" name="quick-registration">
  306. <div class="article-form">
  307. <el-form-item label="标题">
  308. <el-input v-model="articleData.quickRegistration.title" placeholder="请输入标题" />
  309. </el-form-item>
  310. <el-form-item label="内容">
  311. <Editor v-model="articleData.quickRegistration.content" :min-height="300" />
  312. </el-form-item>
  313. <el-form-item label="备注">
  314. <el-input v-model="articleData.quickRegistration.remark" placeholder="请输入备注" type="textarea" :rows="3" />
  315. </el-form-item>
  316. </div>
  317. </el-tab-pane>
  318. <el-tab-pane label="报名咨询" name="registration-consultation">
  319. <div class="article-form">
  320. <el-form-item label="标题">
  321. <el-input v-model="articleData.registrationConsultation.title" placeholder="请输入标题" />
  322. </el-form-item>
  323. <el-form-item label="内容">
  324. <Editor v-model="articleData.registrationConsultation.content" :min-height="300" />
  325. </el-form-item>
  326. <el-form-item label="备注">
  327. <el-input v-model="articleData.registrationConsultation.remark" placeholder="请输入备注" type="textarea" :rows="3" />
  328. </el-form-item>
  329. </div>
  330. </el-tab-pane>
  331. </el-tabs>
  332. <template #footer>
  333. <div class="dialog-footer">
  334. <el-button @click="handleCloseArticleDialog">取 消</el-button>
  335. <el-button type="primary" @click="handleSaveArticle">保 存</el-button>
  336. </div>
  337. </template>
  338. </el-dialog> -->
  339. <!-- 用户导入对话框 -->
  340. <el-dialog v-model="upload.open" :title="upload.title" width="400px" append-to-body>
  341. <el-upload
  342. ref="uploadRef"
  343. :limit="1"
  344. accept=".xlsx"
  345. :headers="upload.headers"
  346. :action="upload.url + '?updateSupport=' + upload.updateSupport"
  347. :disabled="upload.isUploading"
  348. :on-progress="handleFileUploadProgress"
  349. :on-success="handleFileSuccess"
  350. :auto-upload="false"
  351. drag
  352. >
  353. <el-icon class="el-icon--upload">
  354. <i-ep-upload-filled />
  355. </el-icon>
  356. <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
  357. <template #tip>
  358. <div class="text-center el-upload__tip">
  359. <span>仅允许导入.xlsx格式文件。</span>
  360. </div>
  361. </template>
  362. </el-upload>
  363. <template #footer>
  364. <div class="dialog-footer">
  365. <el-button type="primary" @click="submitFileForm">确 定</el-button>
  366. <el-button @click="upload.open = false">取 消</el-button>
  367. </div>
  368. </template>
  369. </el-dialog>
  370. <!-- 导入结果对话框 -->
  371. <el-dialog v-model="showImportResult" title="导入结果详情" width="800px" append-to-body>
  372. <div v-if="importResult">
  373. <el-alert
  374. :title="`共处理 ${importResult.totalCount} 条数据,成功 ${importResult.validCount} 条,失败 ${importResult.errorCount} 条`"
  375. :type="importResult.success ? 'success' : 'warning'"
  376. :closable="false"
  377. class="mb-4"
  378. />
  379. <div v-if="importResult.validationResult && importResult.validationResult.errors.length > 0">
  380. <h4>失败原因详情:</h4>
  381. <el-table :data="importResult.validationResult.errors" border max-height="400">
  382. <el-table-column prop="rowIndex" label="行号" width="80" align="center" />
  383. <el-table-column prop="athleteName" label="运动员姓名" width="120" />
  384. <el-table-column prop="teamName" label="队伍名称" width="150" />
  385. <el-table-column prop="projectName" label="相关项目" width="150" />
  386. <el-table-column prop="errorMessage" label="失败原因" />
  387. </el-table>
  388. </div>
  389. </div>
  390. <template #footer>
  391. <div class="dialog-footer">
  392. <el-button type="primary" @click="showImportResult = false">确定</el-button>
  393. </div>
  394. </template>
  395. </el-dialog>
  396. </div>
  397. </template>
  398. <script setup name="GameEvent" lang="ts">
  399. import { listGameEvent, changeEventDefault, delGameEvent, addGameEvent, updateGameEvent, updateGameEventWxCode } from '@/api/system/gameEvent';
  400. import { GameEventVO, GameEventQuery, GameEventForm } from '@/api/system/gameEvent/types';
  401. import { getEventMdByEventAndType, editEventMd } from '@/api/system/eventMd';
  402. import { EventMdVO, EventMdForm } from '@/api/system/eventMd/types';
  403. import { useRouter } from 'vue-router';
  404. import { ref } from 'vue';
  405. import RefereeForm from '@/views/system/gameEvent/RefereeForm.vue';
  406. import BibViewerDialog from '@/views/system/gameEvent/components/bibViewerDialog.vue';
  407. import { useTagsViewStore } from '@/store/modules/tagsView';
  408. import { globalHeaders } from '@/utils/request';
  409. import { useGameEventStore } from '@/store/modules/gameEvent';
  410. const router = useRouter();
  411. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  412. const { game_event_type, game_event_status, sys_yes_no, game_event_purpose } = toRefs<any>(
  413. proxy?.useDict('game_event_type', 'game_event_status', 'sys_yes_no', 'game_event_purpose')
  414. );
  415. // 定义 RefereeForm 组件的类型
  416. interface RefereeFormInstance {
  417. openDialog: (eventId: string) => void;
  418. }
  419. const refereeFormRef = ref<(InstanceType<typeof RefereeForm> & RefereeFormInstance) | null>(null);
  420. const bibViewerDialogRef = ref<InstanceType<typeof BibViewerDialog> | null>(null);
  421. const gameEventList = ref<GameEventVO[]>([]);
  422. const buttonLoading = ref(false);
  423. const loading = ref(true);
  424. const showSearch = ref(true);
  425. const ids = ref<Array<string | number>>([]);
  426. const single = ref(true);
  427. const multiple = ref(true);
  428. const total = ref(0);
  429. // 列显隐数据
  430. const columns = ref<FieldOption[]>([
  431. { key: 0, label: '赛事id', visible: false },
  432. { key: 1, label: '赛事编号', visible: true },
  433. { key: 2, label: '赛事名称', visible: true },
  434. { key: 3, label: '赛事类型', visible: true },
  435. { key: 4, label: '举办地点', visible: true },
  436. { key: 5, label: '用途', visible: true },
  437. { key: 6, label: '开始时间', visible: true },
  438. { key: 7, label: '结束时间', visible: true },
  439. { key: 8, label: '赛事链接', visible: true },
  440. { key: 9, label: '裁判码', visible: true },
  441. { key: 10, label: '举办单位', visible: true },
  442. { key: 11, label: '是否默认赛事', visible: true },
  443. { key: 12, label: '创建时间', visible: true },
  444. { key: 13, label: '更新时间', visible: true },
  445. { key: 14, label: '状态', visible: true },
  446. { key: 15, label: '备注', visible: true }
  447. ]);
  448. const queryFormRef = ref<ElFormInstance>();
  449. const gameEventFormRef = ref<ElFormInstance>();
  450. const dialog = reactive<DialogOption>({
  451. visible: false,
  452. title: ''
  453. });
  454. const uploadRef = ref<ElUploadInstance>();
  455. /*** 用户导入参数 */
  456. const upload = reactive<ImportOption>({
  457. // 是否显示弹出层(用户导入)
  458. open: false,
  459. // 弹出层标题(用户导入)
  460. title: '',
  461. // 是否禁用上传
  462. isUploading: false,
  463. // 是否更新已经存在的用户数据
  464. updateSupport: 0,
  465. // 设置上传的请求头部
  466. headers: globalHeaders(),
  467. // 上传的地址
  468. url: import.meta.env.VITE_APP_BASE_API + '/system/enroll/importData'
  469. });
  470. const importResult = ref(null);
  471. const showImportResult = ref(false);
  472. const initFormData: GameEventForm = {
  473. eventId: undefined,
  474. eventCode: undefined,
  475. eventName: undefined,
  476. eventType: undefined,
  477. location: undefined,
  478. purpose: undefined,
  479. startTime: undefined,
  480. endTime: undefined,
  481. eventUrl: undefined,
  482. refereeUrl: undefined,
  483. registerUrl: undefined,
  484. unit: undefined,
  485. isDefault: undefined,
  486. status: undefined,
  487. remark: undefined
  488. };
  489. const data = reactive<PageData<GameEventForm, GameEventQuery>>({
  490. form: { ...initFormData },
  491. queryParams: {
  492. pageNum: 1,
  493. pageSize: 10,
  494. eventCode: undefined,
  495. eventName: undefined,
  496. eventType: undefined,
  497. purpose: undefined,
  498. startTime: undefined,
  499. isDefault: undefined,
  500. status: undefined,
  501. params: {},
  502. orderByColumn: '',
  503. isAsc: ''
  504. },
  505. rules: {
  506. eventCode: [{ required: true, message: '赛事编号不能为空', trigger: 'blur' }],
  507. eventName: [{ required: true, message: '赛事名称不能为空', trigger: 'blur' }],
  508. eventType: [{ required: true, message: '赛事类型不能为空', trigger: 'change' }]
  509. }
  510. });
  511. const { queryParams, form, rules } = toRefs(data);
  512. // 使用gameEvent store
  513. const gameEventStore = useGameEventStore();
  514. /** 查询赛事基本信息列表 */
  515. const getList = async () => {
  516. loading.value = true;
  517. const res = await listGameEvent(queryParams.value);
  518. gameEventList.value = res.rows;
  519. total.value = res.total;
  520. loading.value = false;
  521. };
  522. /** 取消按钮 */
  523. const cancel = () => {
  524. reset();
  525. dialog.visible = false;
  526. };
  527. /** 表单重置 */
  528. const reset = () => {
  529. form.value = { ...initFormData };
  530. gameEventFormRef.value?.resetFields();
  531. };
  532. /** 搜索按钮操作 */
  533. const handleQuery = () => {
  534. queryParams.value.pageNum = 1;
  535. getList();
  536. };
  537. /** 重置按钮操作 */
  538. const resetQuery = () => {
  539. queryFormRef.value?.resetFields();
  540. handleQuery();
  541. };
  542. /** 多选框选中数据 */
  543. const handleSelectionChange = (selection: GameEventVO[]) => {
  544. ids.value = selection.map((item) => item.eventId);
  545. single.value = selection.length != 1;
  546. multiple.value = !selection.length;
  547. };
  548. /** 新增按钮操作 */
  549. const handleAdd = () => {
  550. router.push('/system/gameEvent/add');
  551. };
  552. /** 修改按钮操作 */
  553. const handleUpdate = async (row?: GameEventVO) => {
  554. const _eventId = row?.eventId || ids.value[0];
  555. router.push(`/system/gameEvent/edit/${_eventId}`);
  556. };
  557. /** 生成赛事码按钮操作 */
  558. const handleUpdateCode = async (row?: GameEventVO) => {
  559. const _eventId = row?.eventId || ids.value[0];
  560. await updateGameEventWxCode(_eventId);
  561. await getList();
  562. };
  563. /** 提交按钮 */
  564. const submitForm = () => {
  565. gameEventFormRef.value?.validate(async (valid: boolean) => {
  566. if (valid) {
  567. buttonLoading.value = true;
  568. if (form.value.eventId) {
  569. await updateGameEvent(form.value).finally(() => (buttonLoading.value = false));
  570. } else {
  571. await addGameEvent(form.value).finally(() => (buttonLoading.value = false));
  572. }
  573. proxy?.$modal.msgSuccess('操作成功');
  574. dialog.visible = false;
  575. await getList();
  576. }
  577. });
  578. };
  579. /** 删除按钮操作 */
  580. const handleDelete = async (row?: GameEventVO) => {
  581. const _ids = row?.eventId || ids.value;
  582. if (!_ids || (Array.isArray(_ids) && _ids.length === 0)) {
  583. proxy?.$modal.msgError('请选择要删除的赛事');
  584. return;
  585. }
  586. // 如果是单个删除,需要检查时间限制
  587. if (row) {
  588. const endTime = new Date(row.endTime);
  589. const currentTime = new Date();
  590. const daysDiff = Math.floor((currentTime.getTime() - endTime.getTime()) / (1000 * 60 * 60 * 24));
  591. if (daysDiff < 100) {
  592. proxy?.$modal.msgError(`该赛事结束时间不足100天,无法删除。距离可删除时间还有 ${100 - daysDiff} 天。`);
  593. return;
  594. }
  595. await proxy?.$modal.confirm('是否确认删除赛事编号为"' + row.eventCode + '"的数据项?').finally(() => (loading.value = false));
  596. await delGameEvent(row.eventId);
  597. proxy?.$modal.msgSuccess('删除成功');
  598. } else {
  599. // 批量删除
  600. const selectedEvents = gameEventList.value.filter((event) => ids.value.includes(event.eventId));
  601. const invalidEvents = selectedEvents.filter((event) => {
  602. const endTime = new Date(event.endTime);
  603. const currentTime = new Date();
  604. const daysDiff = Math.floor((currentTime.getTime() - endTime.getTime()) / (1000 * 60 * 60 * 24));
  605. return daysDiff < 100;
  606. });
  607. if (invalidEvents.length > 0) {
  608. const eventNames = invalidEvents.map((event) => event.eventName).join('、');
  609. proxy?.$modal.msgError(`以下赛事结束时间不足100天,无法删除:${eventNames}`);
  610. return;
  611. }
  612. const eventCodes = selectedEvents.map((event) => event.eventCode).join('、');
  613. await proxy?.$modal.confirm(`是否确认删除以下赛事:${eventCodes}?`).finally(() => (loading.value = false));
  614. await delGameEvent(ids.value);
  615. proxy?.$modal.msgSuccess(`成功删除 ${selectedEvents.length} 个赛事`);
  616. }
  617. await getList();
  618. };
  619. /** 判断是否可以删除赛事 */
  620. const canDelete = (row: GameEventVO): boolean => {
  621. const endTime = new Date(row.endTime);
  622. const currentTime = new Date();
  623. const daysDiff = Math.floor((currentTime.getTime() - endTime.getTime()) / (1000 * 60 * 60 * 24));
  624. return daysDiff >= 100;
  625. };
  626. /** 获取删除按钮的提示信息 */
  627. const getDeleteTooltip = (row: GameEventVO): string => {
  628. if (canDelete(row)) {
  629. return '删除';
  630. } else {
  631. const endTime = new Date(row.endTime);
  632. const currentTime = new Date();
  633. const daysDiff = Math.floor((currentTime.getTime() - endTime.getTime()) / (1000 * 60 * 60 * 24));
  634. return `赛事结束时间不足100天,无法删除。距离可删除时间还有 ${100 - daysDiff} 天。`;
  635. }
  636. };
  637. /** 导出按钮操作 */
  638. const handleExport = () => {
  639. proxy?.download(
  640. 'system/gameEvent/export',
  641. {
  642. ...queryParams.value
  643. },
  644. `赛事详情_${new Date().getTime()}.xlsx`
  645. );
  646. };
  647. /* 下载模板 */
  648. const handleDownloadTemplate = (row: GameEventVO) => {
  649. proxy?.download(
  650. 'system/enroll/importTemplate',
  651. {
  652. eventId: row.eventId
  653. },
  654. `event_enroll_template_${new Date().getTime()}.xlsx`
  655. );
  656. };
  657. // 导入报名表逻辑
  658. const handleImportRegistration = (row) => {
  659. upload.url = import.meta.env.VITE_APP_BASE_API + `/system/enroll/importDataWithValidation/${row.eventId}`;
  660. upload.title = '报名表导入';
  661. upload.open = true;
  662. };
  663. /**文件上传中处理 */
  664. const handleFileUploadProgress = () => {
  665. upload.isUploading = true;
  666. };
  667. /** 文件上传成功处理 */
  668. const handleFileSuccess = (response: any, file: UploadFile) => {
  669. upload.open = false;
  670. upload.isUploading = false;
  671. uploadRef.value?.handleRemove(file);
  672. if (response.code === 200) {
  673. const result = response.data;
  674. importResult.value = result;
  675. showImportResult.value = true;
  676. // 显示导入结果
  677. if (result.success) {
  678. proxy?.$modal.msgSuccess(`导入成功!共处理${result.totalCount}条数据,成功${result.validCount}条,失败${result.errorCount}条`);
  679. } else {
  680. proxy?.$modal.msgWarning(`导入完成!共处理${result.totalCount}条数据,成功${result.validCount}条,失败${result.errorCount}条`);
  681. }
  682. } else {
  683. proxy?.$modal.msgError('导入失败:' + response.msg);
  684. }
  685. getList();
  686. };
  687. /** 提交上传文件 */
  688. function submitFileForm() {
  689. uploadRef.value?.submit();
  690. }
  691. // 添加参赛者操作
  692. const handleAddParticipant = (row: GameEventVO) => {
  693. // 跳转到新增或编辑参赛者信息页面,并传递 eventName 参数
  694. router.push({
  695. name: 'GameEventAthlete',
  696. params: { eventId: row.eventId, eventName: row.eventName }
  697. });
  698. };
  699. // 添加裁判按钮操作
  700. const handleAddReferee = async (row: GameEventVO) => {
  701. try {
  702. if (!row.eventId) {
  703. proxy?.$modal.msgError('赛事ID不能为空');
  704. return;
  705. }
  706. if (!refereeFormRef.value) {
  707. proxy?.$modal.msgError('裁判表单组件未初始化');
  708. return;
  709. }
  710. // 打开裁判表单对话框并传递 eventId
  711. refereeFormRef.value.openDialog(String(row.eventId));
  712. } catch (error) {
  713. console.error('添加裁判失败:', error);
  714. proxy?.$modal.msgError('添加裁判失败');
  715. }
  716. };
  717. // 预览按钮点击事件
  718. const handlePreview = (row: GameEventVO) => {
  719. // 跳转到赛事详情页面
  720. router.push({
  721. name: 'GameEventDetail',
  722. params: { eventId: row.eventId }
  723. });
  724. };
  725. // 比赛成绩按钮点击事件
  726. const handleGameData = (row: GameEventVO) => {
  727. router.push({
  728. name: 'RankingBoardPage',
  729. params: { eventId: row.eventId }
  730. });
  731. };
  732. // 文章编写相关数据
  733. const articleDialog = reactive({
  734. visible: false,
  735. title: '',
  736. currentEventId: undefined as string | number | undefined
  737. });
  738. const activeTab = ref('competition-process');
  739. // 标签页与类型值的映射关系
  740. const tabTypeMapping: Record<string, number> = {
  741. 'competition-process': 1, // 竞赛流程
  742. 'competition-items': 2, // 竞赛项目
  743. 'activity-agenda': 3, // 活动议程
  744. 'project-introduction': 4, // 项目介绍
  745. 'competition-flow': 5, // 竞赛流程
  746. 'event-grouping': 6, // 赛事分组
  747. 'athlete-handbook': 7, // 运动员号码簿
  748. 'project-venue': 8, // 项目场地
  749. 'traffic-guide': 9, // 交通指示
  750. 'quick-registration': 10, // 快捷报名
  751. 'registration-consultation': 11 // 报名咨询
  752. };
  753. const articleData = reactive({
  754. competitionProcess: { id: undefined, title: '', content: '', remark: '' },
  755. competitionItems: { id: undefined, title: '', content: '', remark: '' },
  756. activityAgenda: { id: undefined, title: '', content: '', remark: '' },
  757. projectIntroduction: { id: undefined, title: '', content: '', remark: '' },
  758. competitionFlow: { id: undefined, title: '', content: '', remark: '' },
  759. eventGrouping: { id: undefined, title: '', content: '', remark: '' },
  760. athleteHandbook: { id: undefined, title: '', content: '', remark: '' },
  761. projectVenue: { id: undefined, title: '', content: '', remark: '' },
  762. trafficGuide: { id: undefined, title: '', content: '', remark: '' },
  763. quickRegistration: { id: undefined, title: '', content: '', remark: '' },
  764. registrationConsultation: { id: undefined, title: '', content: '', remark: '' }
  765. });
  766. // 打开排行榜组件并传递赛事ID
  767. // const openRankingBoard = (eventId: string) => {
  768. // currentEventId.value = eventId;
  769. // rankingBoardVisible.value = true;
  770. // };
  771. /** 状态修改 */
  772. const handleStatusChange = async (row: GameEventVO) => {
  773. const text = row.isDefault === '0' ? '启用' : '停用';
  774. try {
  775. await proxy?.$modal.confirm('确认要"' + text + '""' + row.eventName + '"为默认赛事吗?');
  776. await changeEventDefault(row.eventId, row.isDefault);
  777. await getList();
  778. // 更新全局默认赛事信息
  779. await gameEventStore.fetchDefaultEvent();
  780. // localStorage.setItem('defaultEventId', row.eventId);
  781. proxy?.$modal.msgSuccess(text + '成功');
  782. // 刷新当前标签页
  783. await useTagsViewStore().delOthersViews(router.currentRoute.value);
  784. } catch {
  785. return;
  786. } finally {
  787. row.isDefault = row.isDefault === '0' ? '1' : '0';
  788. }
  789. };
  790. /** 编写文章按钮操作 */
  791. const handleWriteArticle = async (row: GameEventVO) => {
  792. articleDialog.title = `编写文章 - ${row.eventName}`;
  793. articleDialog.currentEventId = row.eventId;
  794. articleDialog.visible = true;
  795. activeTab.value = 'competition-process';
  796. // 加载默认标签页(竞赛流程)的数据
  797. await loadTabData('competition-process');
  798. };
  799. /** 加载指定标签页的数据 */
  800. const loadTabData = async (tabName: string) => {
  801. const type = tabTypeMapping[tabName];
  802. if (articleDialog.currentEventId && type) {
  803. try {
  804. const response = await getEventMdByEventAndType(articleDialog.currentEventId, type);
  805. const eventMd = response.data;
  806. const dataKey = getDataKeyByTabName(tabName);
  807. if (dataKey && articleData[dataKey]) {
  808. if (eventMd) {
  809. articleData[dataKey].id = eventMd.id;
  810. articleData[dataKey].title = eventMd.title || '';
  811. articleData[dataKey].content = eventMd.content || '';
  812. articleData[dataKey].remark = eventMd.remark || '';
  813. } else {
  814. articleData[dataKey].id = undefined;
  815. articleData[dataKey].title = '';
  816. articleData[dataKey].content = '';
  817. articleData[dataKey].remark = '';
  818. }
  819. }
  820. } catch (error) {
  821. const dataKey = getDataKeyByTabName(tabName);
  822. if (dataKey && articleData[dataKey]) {
  823. articleData[dataKey].id = undefined;
  824. articleData[dataKey].title = '';
  825. articleData[dataKey].content = '';
  826. articleData[dataKey].remark = '';
  827. }
  828. }
  829. }
  830. };
  831. /** 标签页点击事件 */
  832. const handleTabClick = async (tab: any) => {
  833. const tabName = tab.props.name;
  834. await loadTabData(tabName);
  835. };
  836. /** 根据标签页名称获取数据键名 */
  837. const getDataKeyByTabName = (tabName: string): keyof typeof articleData | null => {
  838. const mapping: Record<string, keyof typeof articleData> = {
  839. 'competition-process': 'competitionProcess',
  840. 'competition-items': 'competitionItems',
  841. 'activity-agenda': 'activityAgenda',
  842. 'project-introduction': 'projectIntroduction',
  843. 'competition-flow': 'competitionFlow',
  844. 'event-grouping': 'eventGrouping',
  845. 'athlete-handbook': 'athleteHandbook',
  846. 'project-venue': 'projectVenue',
  847. 'traffic-guide': 'trafficGuide',
  848. 'quick-registration': 'quickRegistration',
  849. 'registration-consultation': 'registrationConsultation'
  850. };
  851. return mapping[tabName] || null;
  852. };
  853. /** 关闭文章编写对话框 */
  854. const handleCloseArticleDialog = () => {
  855. // 清空所有文章数据
  856. Object.keys(articleData).forEach((key) => {
  857. const dataKey = key as keyof typeof articleData;
  858. articleData[dataKey].id = undefined;
  859. articleData[dataKey].title = '';
  860. articleData[dataKey].content = '';
  861. articleData[dataKey].remark = '';
  862. });
  863. // 重置对话框状态
  864. articleDialog.visible = false;
  865. articleDialog.currentEventId = undefined;
  866. activeTab.value = 'competition-process';
  867. };
  868. /** 保存文章 */
  869. const handleSaveArticle = async () => {
  870. if (!articleDialog.currentEventId) {
  871. proxy?.$modal.msgError('赛事ID不能为空');
  872. return;
  873. }
  874. const currentTabName = activeTab.value;
  875. const type = tabTypeMapping[currentTabName];
  876. const dataKey = getDataKeyByTabName(currentTabName);
  877. if (!dataKey || !articleData[dataKey]) {
  878. proxy?.$modal.msgError('获取当前标签页数据失败');
  879. return;
  880. }
  881. const currentData = articleData[dataKey];
  882. if (!currentData.title?.trim()) {
  883. proxy?.$modal.msgError('标题不能为空');
  884. return;
  885. }
  886. try {
  887. const formData: EventMdForm = {
  888. id: currentData.id,
  889. eventId: articleDialog.currentEventId,
  890. title: currentData.title,
  891. content: currentData.content || '',
  892. type: type,
  893. remark: currentData.remark || ''
  894. };
  895. await editEventMd(formData);
  896. proxy?.$modal.msgSuccess('文章保存成功');
  897. // 重新加载当前标签页数据以获取最新的ID
  898. await loadTabData(currentTabName);
  899. } catch (error) {
  900. console.error('保存文章失败:', error);
  901. proxy?.$modal.msgError('保存文章失败');
  902. }
  903. };
  904. // 基于默认赛事的操作函数
  905. /** 下载模板(默认赛事) */
  906. const handleDownloadTemplateDefault = async () => {
  907. const defaultEvent = gameEventStore.defaultEventInfo;
  908. if (!defaultEvent) {
  909. proxy?.$modal.msgError('请先设置默认赛事');
  910. return;
  911. }
  912. handleDownloadTemplate(defaultEvent);
  913. };
  914. /** 导入报名信息(默认赛事) */
  915. const handleImportRegistrationDefault = async () => {
  916. const defaultEvent = gameEventStore.defaultEventInfo;
  917. if (!defaultEvent) {
  918. proxy?.$modal.msgError('请先设置默认赛事');
  919. return;
  920. }
  921. handleImportRegistration(defaultEvent);
  922. };
  923. /** 添加参赛者(默认赛事) */
  924. const handleAddParticipantDefault = async () => {
  925. const defaultEvent = gameEventStore.defaultEventInfo;
  926. if (!defaultEvent) {
  927. proxy?.$modal.msgError('请先设置默认赛事');
  928. return;
  929. }
  930. handleAddParticipant(defaultEvent);
  931. };
  932. /** 添加裁判(默认赛事) */
  933. const handleAddRefereeDefault = async () => {
  934. try {
  935. const defaultEvent = gameEventStore.defaultEventInfo;
  936. if (!defaultEvent) {
  937. proxy?.$modal.msgError('请先设置默认赛事');
  938. return;
  939. }
  940. await handleAddReferee(defaultEvent);
  941. } catch (error) {
  942. console.error('默认赛事添加裁判失败:', error);
  943. proxy?.$modal.msgError('添加裁判失败');
  944. }
  945. };
  946. /** 预览(默认赛事) */
  947. const handlePreviewDefault = async () => {
  948. const defaultEvent = gameEventStore.defaultEventInfo;
  949. if (!defaultEvent) {
  950. proxy?.$modal.msgError('请先设置默认赛事');
  951. return;
  952. }
  953. handlePreview(defaultEvent);
  954. };
  955. /** 比赛数据(默认赛事) */
  956. const handleGameDataDefault = async () => {
  957. const defaultEvent = gameEventStore.defaultEventInfo;
  958. if (!defaultEvent) {
  959. proxy?.$modal.msgError('请先设置默认赛事');
  960. return;
  961. }
  962. handleGameData(defaultEvent);
  963. };
  964. /** 编写文章(默认赛事) */
  965. const handleWriteArticleDefault = async () => {
  966. const defaultEvent = gameEventStore.defaultEventInfo;
  967. if (!defaultEvent) {
  968. proxy?.$modal.msgError('请先设置默认赛事');
  969. return;
  970. }
  971. router.push({
  972. name: 'ArticleEditor',
  973. params: { eventId: defaultEvent.eventId }
  974. });
  975. // handleWriteArticle(defaultEvent);
  976. };
  977. const handleExportNumberTableDefault = async () => {
  978. await proxy?.download('system/number/export', {}, `号码对照表_${new Date().getTime()}.xlsx`);
  979. };
  980. // 生成参赛证相关 - 已移动到 BibViewerDialog 组件中
  981. // 生成参赛证按钮处理
  982. const handleGenerateBib = () => {
  983. if (bibViewerDialogRef.value) {
  984. bibViewerDialogRef.value.bibDialog.visible = true;
  985. }
  986. };
  987. // 任务列表按钮处理
  988. const handleTaskList = () => {
  989. router.push('/system/gameEvent/taskList');
  990. };
  991. onMounted(() => {
  992. // 获取默认赛事信息
  993. gameEventStore.fetchDefaultEvent();
  994. getList();
  995. // 检查组件引用是否正确初始化
  996. nextTick(() => {
  997. console.log('组件引用检查:');
  998. console.log('refereeFormRef.value:', refereeFormRef.value);
  999. console.log('bibViewerDialogRef.value:', bibViewerDialogRef.value);
  1000. });
  1001. });
  1002. // 监听路由变化,当从编辑页返回时检查是否需要刷新列表
  1003. onActivated(() => {
  1004. // 检查是否有需要刷新的标识
  1005. const needRefresh = sessionStorage.getItem('needRefreshGameEventList');
  1006. if (needRefresh === 'true') {
  1007. // 清除标识
  1008. sessionStorage.removeItem('needRefreshGameEventList');
  1009. // 刷新列表数据
  1010. getList();
  1011. }
  1012. });
  1013. </script>
  1014. <style scoped>
  1015. .operation-buttons {
  1016. display: flex;
  1017. flex-direction: column;
  1018. gap: 4px;
  1019. align-items: center;
  1020. min-width: 200px;
  1021. }
  1022. .button-row {
  1023. display: flex;
  1024. gap: 6px;
  1025. justify-content: center;
  1026. align-items: center;
  1027. flex-wrap: wrap;
  1028. }
  1029. .operation-buttons .el-button {
  1030. min-width: 28px;
  1031. min-height: 28px;
  1032. padding: 4px 6px;
  1033. border-radius: 4px;
  1034. transition: all 0.2s ease;
  1035. display: flex;
  1036. align-items: center;
  1037. justify-content: center;
  1038. }
  1039. .operation-buttons .el-button:hover {
  1040. transform: translateY(-1px);
  1041. box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
  1042. }
  1043. .operation-buttons .el-button[disabled] {
  1044. opacity: 0.5;
  1045. cursor: not-allowed;
  1046. }
  1047. .operation-buttons .el-button[disabled]:hover {
  1048. transform: none;
  1049. box-shadow: none;
  1050. }
  1051. /* 为不同类型的按钮设置不同的颜色主题 */
  1052. .operation-buttons .el-button--primary {
  1053. color: #409eff;
  1054. }
  1055. .operation-buttons .el-button--danger {
  1056. color: #f56c6c;
  1057. }
  1058. .operation-buttons .el-button--warning {
  1059. color: #e6a23c;
  1060. }
  1061. .operation-buttons .el-button--info {
  1062. color: #909399;
  1063. }
  1064. .operation-buttons .el-button--success {
  1065. color: #67c23a;
  1066. }
  1067. /* 响应式设计 */
  1068. @media (max-width: 1400px) {
  1069. .operation-buttons {
  1070. min-width: 180px;
  1071. }
  1072. .button-row {
  1073. gap: 4px;
  1074. }
  1075. .operation-buttons .el-button {
  1076. min-width: 24px;
  1077. min-height: 24px;
  1078. padding: 3px 5px;
  1079. }
  1080. }
  1081. @media (max-width: 1200px) {
  1082. .operation-buttons {
  1083. min-width: 160px;
  1084. gap: 2px;
  1085. }
  1086. .button-row {
  1087. gap: 2px;
  1088. }
  1089. .operation-buttons .el-button {
  1090. min-width: 22px;
  1091. min-height: 22px;
  1092. padding: 2px 4px;
  1093. }
  1094. }
  1095. </style>