index.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  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="teamName">
  8. <el-input v-model="queryParams.teamName" placeholder="请输入队伍名称" clearable @keyup.enter="handleQuery" />
  9. </el-form-item>
  10. <el-form-item label="号码" prop="athleteCode">
  11. <el-input v-model="queryParams.athleteCode" placeholder="请输入运动员号码" clearable @keyup.enter="handleQuery" />
  12. </el-form-item>
  13. <el-form-item label="姓名" prop="name">
  14. <el-input v-model="queryParams.name" placeholder="请输入姓名" clearable @keyup.enter="handleQuery" />
  15. </el-form-item>
  16. <el-form-item label="手机号" prop="phone">
  17. <el-input v-model="queryParams.phone" placeholder="请输入手机号" clearable @keyup.enter="handleQuery" />
  18. </el-form-item>
  19. <el-form-item label="居住地址" prop="location">
  20. <el-input v-model="queryParams.location" placeholder="请输入居住地址" clearable @keyup.enter="handleQuery" />
  21. </el-form-item>
  22. <el-form-item>
  23. <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
  24. <el-button icon="Refresh" @click="resetQuery">重置</el-button>
  25. </el-form-item>
  26. </el-form>
  27. </el-card>
  28. </div>
  29. </transition>
  30. <el-card shadow="never">
  31. <template #header>
  32. <el-row :gutter="10" class="mb8">
  33. <el-col :span="1.5">
  34. <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:gameAthlete:add']"> 新增 </el-button>
  35. </el-col>
  36. <el-col :span="1.5">
  37. <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:gameAthlete:edit']"
  38. >修改
  39. </el-button>
  40. </el-col>
  41. <el-col :span="1.5">
  42. <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:gameAthlete:remove']"
  43. >删除
  44. </el-button>
  45. </el-col>
  46. <!-- <el-col :span="1.5">
  47. <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:gameAthlete:export']">导出 </el-button>
  48. </el-col> -->
  49. <el-col :span="1.5">
  50. <el-button type="info" plain icon="Upload" @click="handleImport" v-hasPermi="['system:gameAthlete:import']"> 导入 </el-button>
  51. </el-col>
  52. <right-toolbar v-model:showSearch="showSearch" :columns="columns" @queryTable="getList"></right-toolbar>
  53. </el-row>
  54. </template>
  55. <el-table v-loading="loading" border :data="gameAthleteList" @selection-change="handleSelectionChange">
  56. <el-table-column type="selection" width="55" align="center" />
  57. <el-table-column label="运动员id" align="center" prop="athleteId" v-if="columns[0].visible" />
  58. <el-table-column label="赛事名称" align="center" prop="eventName" width="120px" v-if="columns[1].visible" />
  59. <el-table-column label="号码" align="center" prop="athleteCode" width="100px" v-if="columns[2].visible" />
  60. <el-table-column label="姓名" align="center" prop="name" v-if="columns[3].visible" />
  61. <el-table-column label="性别" align="center" prop="gender" v-if="columns[4].visible">
  62. <template #default="scope">
  63. <dict-tag :options="sys_user_sex" :value="scope.row.gender" />
  64. </template>
  65. </el-table-column>
  66. <el-table-column label="年龄" align="center" prop="age" v-if="columns[5].visible" />
  67. <el-table-column label="参与项目" align="center" prop="projectList" width="200px" v-if="columns[6].visible">
  68. <template #default="scope">
  69. {{ formatProjectList(scope.row.projectList) }}
  70. </template>
  71. </el-table-column>
  72. <el-table-column label="证件号" align="center" prop="idCard" v-if="columns[7].visible" />
  73. <el-table-column label="队伍" align="center" prop="teamId" v-if="columns[8].visible">
  74. <template #default="scope">
  75. {{ getTeamNameById(scope.row.teamId) }}
  76. </template>
  77. </el-table-column>
  78. <!-- <el-table-column label="芯片号" align="center" prop="chipCode" v-if="columns[9].visible" /> -->
  79. <!-- <el-table-column label="手机号" align="center" prop="phone" v-if="columns[10].visible" /> -->
  80. <!-- <el-table-column label="居住地址" align="center" prop="location" v-if="columns[11].visible" /> -->
  81. <!-- <el-table-column label="T恤尺码" align="center" prop="tshirtSize" v-if="columns[12].visible" /> -->
  82. <!-- <el-table-column label="组别" align="center" prop="groupType" v-if="columns[13].visible" /> -->
  83. <!-- <el-table-column label="号码" align="center" prop="number" v-if="columns[14].visible" /> -->
  84. <el-table-column label="状态" align="center" prop="status" v-if="columns[9].visible" />
  85. <el-table-column label="备注" align="center" prop="remark" v-if="columns[10].visible" />
  86. <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right">
  87. <template #default="scope">
  88. <el-tooltip content="修改" placement="top">
  89. <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:gameAthlete:edit']"></el-button>
  90. </el-tooltip>
  91. <el-tooltip content="删除" placement="top">
  92. <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:gameAthlete:remove']"></el-button>
  93. </el-tooltip>
  94. </template>
  95. </el-table-column>
  96. </el-table>
  97. <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
  98. </el-card>
  99. <!-- 添加或修改参赛队员对话框 -->
  100. <el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
  101. <el-form ref="gameAthleteFormRef" :model="form" :rules="rules" label-width="80px">
  102. <el-form-item label="队伍" prop="teamId">
  103. <el-select v-model="form.teamId" placeholder="请选择队伍">
  104. <el-option v-for="team in gameTeamList" :key="team.teamId" :label="team.teamName" :value="team.teamId" />
  105. </el-select>
  106. </el-form-item>
  107. <el-form-item label="号码" prop="athleteCode">
  108. <el-input v-model="form.athleteCode" placeholder="请输入运动员编号" />
  109. </el-form-item>
  110. <el-form-item label="姓名" prop="name">
  111. <el-input v-model="form.name" placeholder="请输入姓名" />
  112. </el-form-item>
  113. <el-form-item label="性别" prop="gender">
  114. <el-radio-group v-model="form.gender">
  115. <el-radio v-for="dict in sys_user_sex" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
  116. </el-radio-group>
  117. </el-form-item>
  118. <el-form-item label="年龄" prop="age">
  119. <el-input v-model="form.age" placeholder="请输入年龄" />
  120. </el-form-item>
  121. <el-form-item label="参与项目" prop="projectList">
  122. <el-transfer
  123. v-model="projectListStr"
  124. :data="gameEventProjectList"
  125. :titles="['可选项目', '已选项目']"
  126. :button-texts="['移除', '添加']"
  127. filterable
  128. style="width: 100%"
  129. />
  130. </el-form-item>
  131. <el-form-item label="备注" prop="remark">
  132. <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
  133. </el-form-item>
  134. </el-form>
  135. <template #footer>
  136. <div class="dialog-footer">
  137. <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
  138. <el-button @click="cancel">取 消</el-button>
  139. </div>
  140. </template>
  141. </el-dialog>
  142. <!-- 用户导入对话框 -->
  143. <el-dialog v-model="upload.open" :title="upload.title" width="400px" append-to-body>
  144. <el-upload
  145. ref="uploadRef"
  146. :limit="1"
  147. accept=".xlsx, .xls"
  148. :headers="upload.headers"
  149. :action="upload.url + '?updateSupport=' + upload.updateSupport"
  150. :disabled="upload.isUploading"
  151. :on-progress="handleFileUploadProgress"
  152. :on-success="handleFileSuccess"
  153. :auto-upload="false"
  154. drag
  155. >
  156. <el-icon class="el-icon--upload">
  157. <i-ep-upload-filled />
  158. </el-icon>
  159. <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
  160. <template #tip>
  161. <div class="text-center el-upload__tip">
  162. <!-- <div class="el-upload__tip">-->
  163. <!-- <el-checkbox v-model="upload.updateSupport" />-->
  164. <!-- 是否更新已经存在的用户数据-->
  165. <!-- </div>-->
  166. <span>仅允许导入xls、xlsx格式文件。</span>
  167. <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板 </el-link>
  168. </div>
  169. </template>
  170. </el-upload>
  171. <template #footer>
  172. <div class="dialog-footer">
  173. <el-button type="primary" @click="submitFileForm">确 定</el-button>
  174. <el-button @click="upload.open = false">取 消</el-button>
  175. </div>
  176. </template>
  177. </el-dialog>
  178. </div>
  179. </template>
  180. <script setup name="GameAthlete" lang="ts">
  181. import { nextTick, ref, onMounted } from 'vue';
  182. import { listGameAthlete, getGameAthlete, delGameAthlete, addGameAthlete, updateGameAthlete } from '@/api/system/gameAthlete';
  183. import { listGameTeam, updateTeamAthletes } from '@/api/system/gameTeam';
  184. import { listGameEventProject } from '@/api/system/gameEventProject';
  185. // import { getDefaultEvent } from '@/api/system/gameEvent';
  186. import { GameAthleteVO, GameAthleteQuery, GameAthleteForm } from '@/api/system/gameAthlete/types';
  187. import { GameTeamVO } from '@/api/system/gameTeam/types';
  188. import { GameEventVO } from '@/api/system/gameEvent/types';
  189. import { globalHeaders } from '@/utils/request';
  190. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  191. const { sys_user_sex } = toRefs<any>(proxy?.useDict('sys_user_sex'));
  192. const defaultEvent = ref<GameEventVO | null>(null); // 默认赛事信息
  193. const gameTeamList = ref<GameTeamVO[]>([]); // 队伍列表
  194. const gameAthleteList = ref<GameAthleteVO[]>([]);
  195. const gameEventProjectList = ref<Array<{ key: string; label: string }>>([]); // 赛事项目列表(用于穿梭框)
  196. const buttonLoading = ref(false);
  197. const loading = ref(true);
  198. const showSearch = ref(true);
  199. const ids = ref<Array<string | number>>([]);
  200. const single = ref(true);
  201. const multiple = ref(true);
  202. const total = ref(0);
  203. // 列显隐数据
  204. const columns = ref<FieldOption[]>([
  205. { key: 0, label: '运动员id', visible: false },
  206. { key: 1, label: '赛事名称', visible: false },
  207. { key: 2, label: '号码', visible: true },
  208. { key: 3, label: '姓名', visible: true },
  209. { key: 4, label: '性别', visible: true },
  210. { key: 5, label: '年龄', visible: true },
  211. { key: 6, label: '参与项目', visible: true },
  212. { key: 7, label: '证件号', visible: true },
  213. { key: 8, label: '队伍', visible: true },
  214. // { key: 9, label: '芯片号', visible: true },
  215. // { key: 10, label: '手机号', visible: true },
  216. // { key: 11, label: '居住地址', visible: true },
  217. // { key: 12, label: 'T恤尺码', visible: true },
  218. // { key: 13, label: '组别', visible: true },
  219. // { key: 14, label: '号码', visible: true },
  220. { key: 9, label: '状态', visible: true },
  221. { key: 10, label: '备注', visible: true },
  222. ]);
  223. const queryFormRef = ref<ElFormInstance>();
  224. const gameAthleteFormRef = ref<ElFormInstance>();
  225. const uploadRef = ref<ElUploadInstance>();
  226. const dialog = reactive<DialogOption>({
  227. visible: false,
  228. title: ''
  229. });
  230. /*** 用户导入参数 */
  231. const upload = reactive<ImportOption>({
  232. // 是否显示弹出层(用户导入)
  233. open: false,
  234. // 弹出层标题(用户导入)
  235. title: '',
  236. // 是否禁用上传
  237. isUploading: false,
  238. // 是否更新已经存在的用户数据
  239. updateSupport: 0,
  240. // 设置上传的请求头部
  241. headers: globalHeaders(),
  242. // 上传的地址
  243. url: import.meta.env.VITE_APP_BASE_API + '/system/gameAthlete/import'
  244. });
  245. const initFormData: GameAthleteForm = {
  246. athleteId: undefined,
  247. userId: undefined,
  248. eventId: undefined,
  249. teamId: undefined,
  250. athleteCode: undefined,
  251. name: undefined,
  252. gender: undefined,
  253. age: undefined,
  254. idCard: undefined,
  255. chipCode: undefined,
  256. phone: undefined,
  257. location: undefined,
  258. tshirtSize: undefined,
  259. groupType: undefined,
  260. projectValue: undefined,
  261. projectList: [],
  262. selectedProjects: [], // 添加已选项目列表
  263. status: undefined,
  264. remark: undefined
  265. };
  266. const data = reactive<PageData<GameAthleteForm, GameAthleteQuery>>({
  267. form: { ...initFormData},
  268. queryParams: {
  269. pageNum: 1,
  270. pageSize: 10,
  271. eventId: undefined,
  272. eventName: undefined,
  273. teamId: undefined,
  274. teamName: undefined,
  275. athleteCode: undefined,
  276. name: undefined,
  277. groupType: undefined,
  278. status: undefined,
  279. phone: undefined,
  280. location: undefined,
  281. params: {},
  282. orderByColumn: '',
  283. isAsc: ''
  284. },
  285. rules: {
  286. teamId: [{ required: true, message: '队伍ID不能为空', trigger: 'blur' }],
  287. athleteCode: [{ required: true, message: '运动员编号不能为空', trigger: 'blur' }],
  288. gender: [{ required: true, message: '性别不能为空', trigger: 'blur' }],
  289. }
  290. });
  291. // 添加额外的ref用于处理默认事件ID
  292. const defaultEventId = computed(() => defaultEvent.value?.eventId);
  293. // 监听默认事件变化
  294. watchEffect(() => {
  295. if (defaultEventId.value) {
  296. form.value.eventId = defaultEventId.value;
  297. queryParams.value.eventId = defaultEventId.value;
  298. }
  299. });
  300. const { queryParams, form, rules } = toRefs(data);
  301. /** 获取默认赛事 */
  302. // const getDefaultEventInfo = async () => {
  303. // try {
  304. // const res = await getDefaultEvent();
  305. // defaultEvent.value = res.data;
  306. // } catch (error) {
  307. // proxy?.$modal.msgError('获取默认赛事信息失败');
  308. // }
  309. // };
  310. /** 获取队伍名称 */
  311. const getTeamNameById = (teamId: string | number | null | undefined) => {
  312. if (!teamId) return '';
  313. const team = gameTeamList.value.find((team) => team.teamId === teamId);
  314. return team ? team.teamName : '';
  315. };
  316. // 获取赛事项目列表
  317. const getProjectList = async (eventId?: string) => {
  318. const res = await listGameEventProject({
  319. pageNum: 1,
  320. pageSize: 1000,
  321. orderByColumn: '',
  322. isAsc: ''
  323. });
  324. console.log(res);
  325. gameEventProjectList.value = res.rows.map((item) => ({
  326. key: String(item.projectId),
  327. label: `${item.projectName}`
  328. }));
  329. };
  330. // 格式化项目列表显示
  331. const formatProjectList = (projectList: number[]) => {
  332. if (!projectList) return '';
  333. // 将逗号分隔的ID列表转换为项目名称列表
  334. // const projectIds = projectValue.split(',');
  335. // const projectNames = projectIds.map((id) => {
  336. // const project = gameEventProjectList.value.find((p) => p.key === id);
  337. // return project ? project.label : id;
  338. // });
  339. const projectNames = gameEventProjectList.value.filter((p) => projectList.includes(Number(p.key))).map((p) => p.label);
  340. return projectNames.join(',');
  341. };
  342. /** 查询参赛队员列表 */
  343. const getList = async () => {
  344. loading.value = true;
  345. const res = await listGameAthlete(queryParams.value);
  346. gameAthleteList.value = res.rows;
  347. total.value = res.total;
  348. loading.value = false;
  349. };
  350. // 获取队伍列表
  351. const getTeamList = async () => {
  352. const res = await listGameTeam({
  353. pageNum: 1,
  354. pageSize: 1000,
  355. orderByColumn: '',
  356. isAsc: ''
  357. });
  358. gameTeamList.value = res.rows || [];
  359. };
  360. /** 取消按钮 */
  361. const cancel = () => {
  362. reset();
  363. dialog.visible = false;
  364. };
  365. /** 表单重置 */
  366. const reset = () => {
  367. form.value = { ...initFormData };
  368. gameAthleteFormRef.value?.resetFields();
  369. };
  370. /** 搜索按钮操作 */
  371. const handleQuery = () => {
  372. queryParams.value.pageNum = 1;
  373. getList();
  374. };
  375. /** 重置按钮操作 */
  376. const resetQuery = () => {
  377. queryFormRef.value?.resetFields();
  378. // // 保留默认赛事ID
  379. // queryParams.value.eventId = defaultEvent.value?.eventId;
  380. handleQuery();
  381. };
  382. /** 多选框选中数据 */
  383. const handleSelectionChange = (selection: GameAthleteVO[]) => {
  384. ids.value = selection.map((item) => item.athleteId);
  385. single.value = selection.length != 1;
  386. multiple.value = !selection.length;
  387. };
  388. /** 新增按钮操作 */
  389. const handleAdd = () => {
  390. reset();
  391. dialog.visible = true;
  392. dialog.title = '添加参赛队员';
  393. // 获取项目列表
  394. // nextTick(() => {
  395. // if (form.value.eventId) {
  396. // getProjectList(String(form.value.eventId));
  397. // }
  398. // });
  399. };
  400. /** 修改按钮操作 */
  401. const handleUpdate = async (row?: GameAthleteVO) => {
  402. reset();
  403. const _athleteId = row?.athleteId || ids.value[0];
  404. const res = await getGameAthlete(_athleteId);
  405. Object.assign(form.value, res.data);
  406. // 处理项目列表,将逗号分隔的字符串转换为数组
  407. if (res.data.projectList) {
  408. form.value.selectedProjects = res.data.projectList;
  409. } else if (res.data.projectValue) {
  410. form.value.selectedProjects = res.data.projectValue.split(',').map(Number);
  411. } else {
  412. form.value.selectedProjects = [];
  413. }
  414. dialog.visible = true;
  415. dialog.title = '修改参赛队员';
  416. // 获取项目列表
  417. // nextTick(() => {
  418. // if (form.value.eventId) {
  419. // getProjectList(String(form.value.eventId));
  420. // }
  421. // });
  422. };
  423. // 添加一个计算属性用于处理projectList2的类型转换
  424. const projectListStr = computed({
  425. get: () => form.value.selectedProjects.map(id => String(id)),
  426. set: (value) => {
  427. form.value.selectedProjects = value.map(id => Number(id));
  428. }
  429. });
  430. /** 提交按钮 */
  431. const submitForm = () => {
  432. gameAthleteFormRef.value?.validate(async (valid: boolean) => {
  433. if (valid) {
  434. buttonLoading.value = true;
  435. try {
  436. // 处理项目列表数据,将数组转换为逗号分隔的字符串
  437. const submitForm = { ...form.value };
  438. if (submitForm.selectedProjects && submitForm.selectedProjects.length > 0) {
  439. submitForm.projectList = submitForm.selectedProjects;
  440. // submitForm.projectValue = submitForm.selectedProjects.join(',');
  441. } else {
  442. // submitForm.projectValue = '';
  443. submitForm.projectList = [];
  444. }
  445. // 删除selectedProjects属性,因为它不需要提交到后端
  446. delete submitForm.selectedProjects;
  447. let result;
  448. if (form.value.athleteId) {
  449. result = await updateGameAthlete(submitForm);
  450. } else {
  451. result = await addGameAthlete(submitForm);
  452. }
  453. // 更新队伍表中的运动员列表
  454. if (submitForm.teamId) {
  455. try {
  456. // 获取当前队伍的所有运动员
  457. const currentTeamAthletes = gameAthleteList.value
  458. .filter(athlete => athlete.teamId === submitForm.teamId)
  459. .map(athlete => athlete.athleteId);
  460. // 添加新运动员到列表中
  461. if (!form.value.athleteId) {
  462. // 新增运动员,需要从返回结果中获取新ID
  463. const newAthleteId = result.data?.athleteId || submitForm.athleteId;
  464. if (newAthleteId) {
  465. currentTeamAthletes.push(newAthleteId);
  466. }
  467. } else {
  468. // 更新运动员,检查是否改变了队伍
  469. const originalAthlete = gameAthleteList.value.find(a => a.athleteId === form.value.athleteId);
  470. if (originalAthlete && originalAthlete.teamId !== submitForm.teamId) {
  471. // 运动员改变了队伍,需要从原队伍中移除,添加到新队伍中
  472. // 从原队伍中移除运动员
  473. if (originalAthlete.teamId) {
  474. const originalTeamAthletes = gameAthleteList.value
  475. .filter(athlete => athlete.teamId === originalAthlete.teamId && athlete.athleteId !== form.value.athleteId)
  476. .map(athlete => athlete.athleteId);
  477. await updateTeamAthletes(originalAthlete.teamId, originalTeamAthletes);
  478. }
  479. // 添加到新队伍中
  480. if (!currentTeamAthletes.includes(form.value.athleteId)) {
  481. currentTeamAthletes.push(form.value.athleteId);
  482. }
  483. } else if (originalAthlete && originalAthlete.teamId === submitForm.teamId) {
  484. // 运动员在同一队伍中,确保在列表中
  485. if (!currentTeamAthletes.includes(form.value.athleteId)) {
  486. currentTeamAthletes.push(form.value.athleteId);
  487. }
  488. }
  489. }
  490. // 更新队伍表中的运动员列表
  491. await updateTeamAthletes(submitForm.teamId, currentTeamAthletes);
  492. } catch (error) {
  493. console.error('更新队伍运动员列表失败:', error);
  494. proxy?.$modal.msgWarning('运动员信息保存成功,但更新队伍运动员列表失败');
  495. }
  496. }
  497. proxy?.$modal.msgSuccess('操作成功');
  498. dialog.visible = false;
  499. await getList();
  500. } catch (error) {
  501. console.error('操作失败:', error);
  502. proxy?.$modal.msgError('操作失败');
  503. } finally {
  504. buttonLoading.value = false;
  505. }
  506. }
  507. });
  508. };
  509. /** 删除按钮操作 */
  510. const handleDelete = async (row?: GameAthleteVO) => {
  511. const _athleteIds = row?.athleteId || ids.value;
  512. await proxy?.$modal.confirm('是否确认删除参赛队员编号为"' + _athleteIds + '"的数据项?').finally(() => (loading.value = false));
  513. try {
  514. await delGameAthlete(_athleteIds);
  515. // 从队伍表中移除被删除的运动员
  516. const athleteIdsToRemove = Array.isArray(_athleteIds) ? _athleteIds : [_athleteIds];
  517. const teamsToUpdate = new Set<number | string>();
  518. // 收集需要更新的队伍ID
  519. athleteIdsToRemove.forEach(athleteId => {
  520. const athlete = gameAthleteList.value.find(a => a.athleteId === athleteId);
  521. if (athlete && athlete.teamId) {
  522. teamsToUpdate.add(athlete.teamId);
  523. }
  524. });
  525. // 更新每个相关队伍中的运动员列表
  526. for (const teamId of teamsToUpdate) {
  527. try {
  528. const currentTeamAthletes = gameAthleteList.value
  529. .filter(athlete => athlete.teamId === teamId && !athleteIdsToRemove.includes(athlete.athleteId))
  530. .map(athlete => athlete.athleteId);
  531. await updateTeamAthletes(teamId, currentTeamAthletes);
  532. } catch (error) {
  533. console.error(`更新队伍 ${teamId} 运动员列表失败:`, error);
  534. proxy?.$modal.msgWarning(`运动员删除成功,但更新队伍 ${teamId} 运动员列表失败`);
  535. }
  536. }
  537. proxy?.$modal.msgSuccess('删除成功');
  538. await getList();
  539. } catch (error) {
  540. console.error('删除失败:', error);
  541. proxy?.$modal.msgError('删除失败');
  542. }
  543. };
  544. /** 导出按钮操作 */
  545. const handleExport = () => {
  546. proxy?.download(
  547. 'system/gameAthlete/export',
  548. {
  549. ...queryParams.value
  550. },
  551. `gameAthlete_${new Date().getTime()}.xlsx`
  552. );
  553. };
  554. /** 导入按钮操作 */
  555. const handleImport = () => {
  556. upload.title = '参赛队员导入';
  557. upload.open = true;
  558. };
  559. /**文件上传中处理 */
  560. const handleFileUploadProgress = () => {
  561. upload.isUploading = true;
  562. };
  563. /** 文件上传成功处理 */
  564. const handleFileSuccess = (response: any, file: UploadFile) => {
  565. upload.open = false;
  566. upload.isUploading = false;
  567. uploadRef.value?.handleRemove(file);
  568. ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + '</div>', '导入结果', {
  569. dangerouslyUseHTMLString: true
  570. });
  571. getList();
  572. };
  573. /** 提交上传文件 */
  574. function submitFileForm() {
  575. uploadRef.value?.submit();
  576. }
  577. /** 下载模板操作 */
  578. const importTemplate = () => {
  579. proxy?.download('system/gameAthlete/importTemplate', {}, `game_athlete_template_${new Date().getTime()}.xlsx`);
  580. };
  581. onMounted(() => {
  582. getList();
  583. getTeamList();
  584. getProjectList();
  585. });
  586. </script>