index.vue 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. <template>
  2. <div class="app-container">
  3. <!-- 搜索表单组件 -->
  4. <SearchForm
  5. v-show="showSearch"
  6. :config="searchConfig"
  7. :model-value="queryParams"
  8. @update:model-value="handleSearchFormUpdate"
  9. :on-search="handleQuery"
  10. :on-reset="resetQuery"
  11. :show-expand="true"
  12. :expand-count="6"
  13. label-width="68px"
  14. />
  15. <el-row :gutter="10" class="mb8">
  16. <el-col :span="1.5">
  17. <el-button
  18. type="primary"
  19. plain
  20. icon="Plus"
  21. @click="handleAdd"
  22. v-hasPermi="['dz:cards:add']"
  23. >制卡</el-button
  24. >
  25. </el-col>
  26. <el-col :span="1.5">
  27. <el-button
  28. type="success"
  29. plain
  30. @click="handleAssignCard"
  31. v-hasPermi="['dz:cards:add']"
  32. style="border-color: #67c23a; color: #67c23a; font-weight: 500"
  33. >
  34. <svg-icon icon-class="peoples" class="mr-1" style="font-size: 16px" />
  35. 分配卡
  36. </el-button>
  37. </el-col>
  38. <!-- <el-col :span="1.5">
  39. <el-button
  40. type="success"
  41. plain
  42. icon="Edit"
  43. :disabled="single"
  44. @click="handleUpdate"
  45. v-hasPermi="['dz:cards:edit']"
  46. >修改</el-button
  47. >
  48. </el-col> -->
  49. <el-col :span="1.5">
  50. <el-button
  51. type="warning"
  52. plain
  53. :disabled="multiple"
  54. @click="handlePayment"
  55. v-hasPermi="['dz:cards:add']"
  56. style="border-color: #e6a23c; color: #e6a23c; font-weight: 500"
  57. >
  58. <svg-icon icon-class="money" class="mr-1" style="font-size: 16px" />
  59. 缴费
  60. </el-button>
  61. </el-col>
  62. <el-col :span="1.5">
  63. <el-button
  64. type="danger"
  65. plain
  66. :disabled="multiple"
  67. @click="handleCloseCard"
  68. v-hasPermi="['dz:cards:add']"
  69. style="border-color: #f56c6c; color: #f56c6c; font-weight: 500"
  70. >
  71. <svg-icon icon-class="lock" class="mr-1" style="font-size: 16px" />
  72. 关卡
  73. </el-button>
  74. </el-col>
  75. <el-col :span="1.5">
  76. <el-button
  77. type="primary"
  78. plain
  79. :disabled="multiple"
  80. @click="handleReopenCard"
  81. v-hasPermi="['dz:cards:add']"
  82. style="border-color: #13c2c2; color: #13c2c2; font-weight: 500"
  83. >
  84. <svg-icon icon-class="enter" class="mr-1" style="font-size: 16px" />
  85. 重开
  86. </el-button>
  87. </el-col>
  88. <el-col :span="1.5">
  89. <el-button
  90. type="danger"
  91. plain
  92. :disabled="multiple"
  93. @click="handleRefund"
  94. v-hasPermi="['dz:cards:add']"
  95. style="border-color: #ff4d4f; color: #ff4d4f; font-weight: 500"
  96. >
  97. <svg-icon icon-class="money" class="mr-1" style="font-size: 16px" />
  98. 退费
  99. </el-button>
  100. </el-col>
  101. <el-col :span="1.5">
  102. <el-button
  103. type="primary"
  104. plain
  105. @click="handleAssociateCampus"
  106. v-hasPermi="['dz:cards:add']"
  107. style="border-color: #1890ff; color: #1890ff; font-weight: 500"
  108. >
  109. <svg-icon icon-class="link" class="mr-1" style="font-size: 16px" />
  110. 关联校区
  111. </el-button>
  112. </el-col>
  113. <el-col :span="1.5">
  114. <el-button
  115. type="success"
  116. plain
  117. @click="handleApplyCard"
  118. v-hasPermi="['dz:cards:add']"
  119. style="border-color: #52c41a; color: #52c41a; font-weight: 500"
  120. >
  121. <svg-icon icon-class="edit" class="mr-1" style="font-size: 16px" />
  122. 申请开卡
  123. </el-button>
  124. </el-col>
  125. <el-col :span="1.5">
  126. <el-button
  127. type="danger"
  128. plain
  129. :disabled="multiple"
  130. icon="Delete"
  131. @click="handleDelete"
  132. v-hasPermi="['dz:cards:remove']"
  133. style="border-color: #ff4d4f; color: #ff4d4f; font-weight: 500"
  134. >
  135. 删除
  136. </el-button>
  137. </el-col>
  138. <el-col :span="1.5">
  139. <el-button
  140. type="primary"
  141. plain
  142. icon="Download"
  143. @click="handleExport"
  144. v-hasPermi="['dz:cards:export']"
  145. style="border-color: #722ed1; color: #722ed1; font-weight: 500"
  146. >导出</el-button
  147. >
  148. </el-col>
  149. <right-toolbar
  150. v-model:showSearch="showSearch"
  151. @queryTable="getList"
  152. ></right-toolbar>
  153. </el-row>
  154. <!-- Table组件 -->
  155. <Table
  156. :data="cardsList"
  157. :columns="tableColumns"
  158. :actions="tableActions"
  159. :loading="loading"
  160. :total="total"
  161. :queryParams="queryParams"
  162. v-bind="tableProps"
  163. @action="handleTableAction"
  164. @selection-change="handleSelectionChange"
  165. @getList="getList"
  166. >
  167. <!-- 姓名-手机插槽 -->
  168. <template #studentInfo="{ row }">
  169. <div class="student-info">
  170. <div class="student-name">{{ row.nickName || "-" }}</div>
  171. <div class="student-phone">{{ row.mobile || "-" }}</div>
  172. </div>
  173. </template>
  174. </Table>
  175. <!-- 弹窗组件 -->
  176. <CardGenerationDialog
  177. v-model="cardGenerationOpen"
  178. :institution-list="institutionList"
  179. :school-list="schoolList"
  180. :card-type-options="card_type"
  181. @success="handleDialogSuccess"
  182. />
  183. <AssignCardDialog
  184. v-model="assignCardOpen"
  185. :school-list="schoolList"
  186. :card-type-options="card_type"
  187. @success="handleDialogSuccess"
  188. />
  189. <EditStudentDialog
  190. v-model="open"
  191. :card-id="currentCardId"
  192. :class-list="classList"
  193. @success="handleDialogSuccess"
  194. />
  195. <PaymentDialog
  196. v-model="paymentOpen"
  197. :card-no="currentCardNo"
  198. :card-ids="selectedCardIds"
  199. :selected-cards="selectedRows"
  200. @success="handlePaymentSuccess"
  201. />
  202. <CloseCardDialog
  203. v-model="closeCardOpen"
  204. :card-no="currentCloseCardNo"
  205. :card-ids="selectedCardIds"
  206. @success="handleCloseCardSuccess"
  207. />
  208. <ReopenCardDialog
  209. v-model="reopenCardOpen"
  210. :card-no="currentReopenCardNo"
  211. :card-ids="selectedCardIds"
  212. @success="handleReopenCardSuccess"
  213. />
  214. <RefundDialog
  215. v-model="refundOpen"
  216. :card-no="currentRefundCardNo"
  217. @confirm="handleRefundConfirm"
  218. />
  219. <AssociateCampusDialog
  220. v-model="associateCampusOpen"
  221. :selected-cards="selectedRows"
  222. @success="handleAssociateCampusSuccess"
  223. />
  224. <ApplyCardDialog
  225. v-model="applyCardOpen"
  226. :selected-cards="selectedRows"
  227. @success="handleApplyCardSuccess"
  228. />
  229. </div>
  230. </template>
  231. <style scoped>
  232. .student-info {
  233. display: flex;
  234. flex-direction: column;
  235. align-items: center;
  236. }
  237. .student-name {
  238. font-weight: 500;
  239. margin-bottom: 2px;
  240. }
  241. .student-phone {
  242. font-size: 12px;
  243. color: #909399;
  244. }
  245. </style>
  246. <script setup name="Cards">
  247. import {
  248. listCards,
  249. getCards,
  250. delCards,
  251. addCards,
  252. updateCards,
  253. } from "@/api/dz/cards";
  254. import SearchForm from "@/components/SearchForm/index.vue";
  255. import Table from "@/components/Table/index.vue";
  256. import CardGenerationDialog from "./components/CardGenerationDialog.vue";
  257. import AssignCardDialog from "./components/AssignCardDialog.vue";
  258. import EditStudentDialog from "./components/EditStudentDialog.vue";
  259. import PaymentDialog from "./components/PaymentDialog.vue";
  260. import CloseCardDialog from "./components/CloseCardDialog.vue";
  261. import ReopenCardDialog from "./components/ReopenCardDialog.vue";
  262. import RefundDialog from "./components/RefundDialog.vue";
  263. import AssociateCampusDialog from "./components/AssociateCampusDialog.vue";
  264. import ApplyCardDialog from "./components/ApplyCardDialog.vue";
  265. import formInfo from "./config/form.js";
  266. import tableConfig from "./config/table.js";
  267. import { listUniversity } from "@/api/dz/school";
  268. import { assignCard, issueCard } from "@/api/dz/cards";
  269. import { listDept } from "@/api/system/dept";
  270. import { listAgent } from "@/api/dz/agent";
  271. const { proxy } = getCurrentInstance();
  272. const {
  273. card_status,
  274. card_distribute_status,
  275. card_time_status,
  276. bool_values,
  277. card_pay_status,
  278. card_type,
  279. } = proxy.useDict(
  280. "card_status",
  281. "card_distribute_status",
  282. "card_time_status",
  283. "bool_values",
  284. "card_pay_status",
  285. "card_type"
  286. );
  287. const cardsList = ref([]);
  288. const schoolList = ref([]);
  289. const classList = ref([]); // 班级列表
  290. const open = ref(false);
  291. const cardGenerationOpen = ref(false); // 制卡对话框
  292. const assignCardOpen = ref(false); // 分配卡对话框
  293. const paymentOpen = ref(false); // 缴费对话框
  294. const closeCardOpen = ref(false); // 关卡对话框
  295. const reopenCardOpen = ref(false); // 重开对话框
  296. const refundOpen = ref(false); // 退费对话框
  297. const associateCampusOpen = ref(false); // 关联校区对话框
  298. const applyCardOpen = ref(false); // 申请开卡对话框
  299. const currentCardNo = ref([]); // 当前缴费的卡号(支持数组)
  300. const currentCloseCardNo = ref([]); // 当前关卡的卡号(支持数组)
  301. const currentReopenCardNo = ref([]); // 当前重开的卡号(支持数组)
  302. const currentRefundCardNo = ref(""); // 当前退费的卡号
  303. const agentList = ref([]); // 代理商列表
  304. const institutionList = ref([]); // 机构列表
  305. const selectedRows = ref([]); // 选中的行
  306. const selectedCardIds = computed(() =>
  307. selectedRows.value.map((row) => row.cardId)
  308. ); // 选中的卡ID列表
  309. const currentCardId = ref(null); // 当前编辑的卡片ID
  310. const loading = ref(true);
  311. const showSearch = ref(true);
  312. const ids = ref([]);
  313. const single = ref(true);
  314. const multiple = ref(true);
  315. const total = ref(0);
  316. const title = ref("");
  317. // 搜索配置
  318. const searchConfig = computed(() => {
  319. const config = [...formInfo.info];
  320. // 动态设置选项数据
  321. config.forEach((item) => {
  322. switch (item.name) {
  323. case "type":
  324. item.option = card_type.value || [];
  325. break;
  326. case "status":
  327. item.option = card_status.value || [];
  328. break;
  329. case "distributeStatus":
  330. item.option = card_distribute_status.value || [];
  331. break;
  332. // 移除registerSchoolId,实体类中不存在
  333. case "timeStatus":
  334. item.option = card_time_status.value || [];
  335. break;
  336. case "payStatus":
  337. item.option = card_pay_status.value || [];
  338. break;
  339. case "isSettlement":
  340. item.option = bool_values.value || [];
  341. break;
  342. case "assignSchoolId":
  343. item.option = schoolList.value || [];
  344. break;
  345. }
  346. });
  347. return config;
  348. });
  349. // 表格配置
  350. const tableColumns = computed(() => {
  351. const columns = [...tableConfig.columns];
  352. // 动态设置字典选项
  353. columns.forEach((column) => {
  354. switch (column.prop) {
  355. case "type":
  356. column.options = card_type.value || [];
  357. break;
  358. case "status":
  359. column.options = card_status.value || [];
  360. break;
  361. case "distributeStatus":
  362. column.options = card_distribute_status.value || [];
  363. break;
  364. case "timeStatus":
  365. column.options = card_time_status.value || [];
  366. break;
  367. case "payStatus":
  368. column.options = card_pay_status.value || [];
  369. break;
  370. case "isSettlement":
  371. column.options = bool_values.value || [];
  372. break;
  373. // 移除studentCategory,实体类中不存在
  374. case "registerSchoolId":
  375. case "assignSchoolId":
  376. column.options = schoolList.value || [];
  377. break;
  378. case "studentCategory":
  379. case "classId":
  380. case "schoolClassId":
  381. case "campusId":
  382. column.options = []; // 需要从相应API获取
  383. break;
  384. }
  385. });
  386. return columns;
  387. });
  388. const tableActions = computed(() => tableConfig.actions);
  389. const tableProps = computed(() => tableConfig.tableProps);
  390. const data = reactive({
  391. form: {},
  392. queryParams: {
  393. pageNum: 1,
  394. pageSize: 10,
  395. // 搜索表单字段
  396. areaIds: [],
  397. assignSchoolId: null,
  398. registerSchoolId: null,
  399. campusId: null,
  400. agentId: null,
  401. cardNo: null,
  402. password: null,
  403. cardNoRange: null,
  404. begin: null,
  405. end: null,
  406. type: null,
  407. studentCategory: null, // 分配考生类型
  408. studentName: null, // 学生姓名
  409. phone: null, // 手机号
  410. registerSchoolId: null, // 注册学校
  411. schoolClassId: null, // 校区班级
  412. distributeStatus: null,
  413. status: null,
  414. timeStatus: null,
  415. isSettlement: null,
  416. // 其他字段(用于数据传输)
  417. cardNo: null,
  418. password: null,
  419. payStatus: null,
  420. isSettlement: null,
  421. deptId: null,
  422. leftAgentId: null,
  423. schoolId: null,
  424. classId: null,
  425. year: null,
  426. endYear: null,
  427. openId: null,
  428. distributeTime: null,
  429. outDate: null,
  430. openTime: null,
  431. payTime: null,
  432. activeTime: null,
  433. settlementTime: null,
  434. refundTime: null,
  435. closeTime: null,
  436. createTime: null,
  437. updateTime: null,
  438. },
  439. rules: {
  440. schoolId: [{ required: true, message: "学校不能为空", trigger: "change" }],
  441. classId: [{ required: true, message: "班级不能为空", trigger: "change" }],
  442. nickName: [{ required: true, message: "姓名不能为空", trigger: "blur" }],
  443. phone: [
  444. { required: true, message: "手机号不能为空", trigger: "blur" },
  445. {
  446. pattern: /^1[3-9]\d{9}$/,
  447. message: "请输入正确的手机号",
  448. trigger: "blur",
  449. },
  450. ],
  451. chineseMathEnglish: [
  452. { required: true, message: "语数英成绩不能为空", trigger: "blur" },
  453. ],
  454. vocationalSkills: [
  455. { required: true, message: "职业技能成绩不能为空", trigger: "blur" },
  456. ],
  457. },
  458. });
  459. const { queryParams, form } = toRefs(data);
  460. // 监听queryParams的原始变化
  461. watch(
  462. () => data.queryParams,
  463. (newParams) => {
  464. if (newParams.areaIds && newParams.areaIds.length > 0) {
  465. getSchoolList();
  466. }
  467. },
  468. { immediate: true, deep: true }
  469. );
  470. /** 查询学习卡列表 */
  471. function getList() {
  472. loading.value = true;
  473. listCards(queryParams.value).then((response) => {
  474. cardsList.value = response.rows;
  475. total.value = response.total;
  476. loading.value = false;
  477. });
  478. }
  479. /** 获取学校列表 */
  480. function getSchoolList() {
  481. // 如果没有选择省市区,则不获取学校列表
  482. if (!queryParams.value.areaIds || queryParams.value.areaIds.length === 0) {
  483. schoolList.value = [];
  484. return;
  485. }
  486. // 构造location参数:如果有省市区选择,取最后一个值(区)作为location
  487. const location =
  488. queryParams.value.areaIds[queryParams.value.areaIds.length - 1];
  489. // 传递pageNum和pageSize参数
  490. const requestParams = {
  491. location,
  492. pageNum: queryParams.value.pageNum || 1,
  493. pageSize: queryParams.value.pageSize || 10,
  494. };
  495. listUniversity(requestParams)
  496. .then((response) => {
  497. // 根据API返回数据结构处理
  498. let schoolData = [];
  499. if (response.data) {
  500. schoolData = Array.isArray(response.data)
  501. ? response.data
  502. : response.data.rows || response.data.list || [];
  503. } else if (response.rows) {
  504. schoolData = response.rows;
  505. } else if (response.list) {
  506. schoolData = response.list;
  507. } else if (Array.isArray(response)) {
  508. schoolData = response;
  509. }
  510. // 确保数据格式符合配置要求
  511. schoolData = schoolData.map((item) => {
  512. // 如果API返回的是 {id, name, ...} 格式,直接使用
  513. if (item.id && item.name) {
  514. return item;
  515. }
  516. // 如果是其他格式,需要转换
  517. return {
  518. id: item.id || item.value || item.schoolId,
  519. name: item.name || item.label || item.schoolName || item.title,
  520. };
  521. });
  522. schoolList.value = schoolData;
  523. })
  524. .catch((error) => {
  525. console.error("获取学校列表失败:", error);
  526. schoolList.value = [];
  527. });
  528. }
  529. // 取消按钮
  530. // 处理弹窗成功事件
  531. function handleDialogSuccess(message) {
  532. proxy.$modal.msgSuccess(message);
  533. getList(); // 刷新列表
  534. }
  535. // 获取机构列表
  536. async function getInstitutionList() {
  537. try {
  538. const response = await listDept({});
  539. institutionList.value = response.data || response.rows || response || [];
  540. } catch (error) {
  541. console.error("获取机构列表失败:", error);
  542. institutionList.value = [];
  543. }
  544. }
  545. // 获取班级列表
  546. async function getClassList() {
  547. try {
  548. // 这里应该调用获取班级列表的API
  549. // 暂时使用模拟数据
  550. classList.value = [
  551. { id: 1, name: "2501" },
  552. { id: 2, name: "2502" },
  553. { id: 3, name: "2503" },
  554. ];
  555. } catch (error) {
  556. console.error("获取班级列表失败:", error);
  557. classList.value = [];
  558. }
  559. }
  560. // 获取代理商列表
  561. async function getAgentList() {
  562. try {
  563. const response = await listAgent({});
  564. const agentData = response.data || response.rows || response || [];
  565. // 确保数据格式符合前端期望
  566. agentList.value = agentData.map((item) => ({
  567. id: item.agentId,
  568. name: item.name,
  569. }));
  570. } catch (error) {
  571. console.error("获取代理商列表失败:", error);
  572. agentList.value = [];
  573. }
  574. }
  575. function cancel() {
  576. open.value = false;
  577. reset();
  578. }
  579. // 表单重置
  580. function reset() {
  581. form.value = {
  582. cardId: null,
  583. cardNo: null,
  584. password: null,
  585. type: null,
  586. status: null,
  587. distributeStatus: null,
  588. timeStatus: null,
  589. payStatus: null,
  590. isSettlement: null,
  591. deptId: null,
  592. agentId: null,
  593. leftAgentId: null,
  594. campusId: null,
  595. assignSchoolId: null,
  596. schoolId: null,
  597. classesId: null,
  598. year: null,
  599. endYear: null,
  600. openId: null,
  601. remark: null,
  602. distributeTime: null,
  603. outDate: null,
  604. openTime: null,
  605. payTime: null,
  606. activeTime: null,
  607. settlementTime: null,
  608. refundTime: null,
  609. closeTime: null,
  610. createTime: null,
  611. updateTime: null,
  612. };
  613. proxy.resetForm("cardsRef");
  614. }
  615. /** 搜索按钮操作 */
  616. /** 表格操作处理 */
  617. function handleTableAction(action, row) {
  618. switch (action.key) {
  619. case "edit":
  620. handleUpdate(row); // 修改时获取行数据
  621. break;
  622. case "delete":
  623. handleDelete(row);
  624. break;
  625. default:
  626. console.warn("Unknown action:", action.key);
  627. }
  628. }
  629. function handleQuery() {
  630. queryParams.value.pageNum = 1;
  631. getList();
  632. }
  633. /** 重置按钮操作 */
  634. function resetQuery() {
  635. proxy.resetForm("queryRef");
  636. handleQuery();
  637. }
  638. /** 处理SearchForm组件的update:model-value事件 */
  639. function handleSearchFormUpdate(newData) {
  640. Object.assign(data.queryParams, newData);
  641. }
  642. // 多选框选中数据
  643. function handleSelectionChange(selection) {
  644. selectedRows.value = selection;
  645. ids.value = selection.map((item) => item.cardId);
  646. single.value = selection.length != 1;
  647. multiple.value = !selection.length;
  648. }
  649. /** 制卡按钮操作 */
  650. function handleAdd() {
  651. cardGenerationOpen.value = true;
  652. getInstitutionList(); // 获取机构列表
  653. }
  654. /** 缴费按钮操作 */
  655. function handlePayment() {
  656. if (selectedRows.value.length === 0) {
  657. proxy.$modal.msgWarning("请选择要缴费的卡片");
  658. return;
  659. }
  660. // 获取所有选中卡片的卡号数组
  661. const cardNos = selectedRows.value.map(
  662. (card) => card.cardNo || card.id || "未知"
  663. );
  664. currentCardNo.value = cardNos;
  665. paymentOpen.value = true;
  666. }
  667. // 处理缴费成功
  668. function handlePaymentSuccess(message) {
  669. proxy.$modal.msgSuccess(message);
  670. getList(); // 刷新列表
  671. }
  672. // 处理缴费确认(保留兼容性)
  673. function handlePaymentConfirm(cardNo) {
  674. proxy.$modal.msgSuccess(`缴费成功!卡号:${cardNo}`);
  675. getList(); // 刷新列表
  676. }
  677. /** 关卡按钮操作 */
  678. function handleCloseCard() {
  679. if (selectedRows.value.length === 0) {
  680. proxy.$modal.msgWarning("请选择要关卡的卡片");
  681. return;
  682. }
  683. // 获取所有选中卡片的卡号数组
  684. const cardNos = selectedRows.value.map(
  685. (card) => card.cardNo || card.id || "未知"
  686. );
  687. currentCloseCardNo.value = cardNos;
  688. closeCardOpen.value = true;
  689. }
  690. // 处理关卡成功
  691. function handleCloseCardSuccess(message) {
  692. proxy.$modal.msgSuccess(message);
  693. getList(); // 刷新列表
  694. }
  695. // 处理关卡确认(保留兼容性)
  696. function handleCloseCardConfirm(cardNo) {
  697. proxy.$modal.msgSuccess(`关卡成功!卡号:${cardNo}`);
  698. getList(); // 刷新列表
  699. }
  700. /** 重开按钮操作 */
  701. function handleReopenCard() {
  702. if (selectedRows.value.length === 0) {
  703. proxy.$modal.msgWarning("请选择要重开的卡片");
  704. return;
  705. }
  706. // 获取所有选中卡片的卡号数组
  707. const cardNos = selectedRows.value.map(
  708. (card) => card.cardNo || card.id || "未知"
  709. );
  710. currentReopenCardNo.value = cardNos;
  711. reopenCardOpen.value = true;
  712. }
  713. // 处理重开成功
  714. function handleReopenCardSuccess(message) {
  715. proxy.$modal.msgSuccess(message);
  716. getList(); // 刷新列表
  717. }
  718. // 处理重开确认(保留兼容性)
  719. function handleReopenCardConfirm(cardNo) {
  720. proxy.$modal.msgSuccess(`重开成功!卡号:${cardNo}`);
  721. getList(); // 刷新列表
  722. }
  723. /** 退费按钮操作 */
  724. function handleRefund() {
  725. if (selectedRows.value.length === 0) {
  726. proxy.$modal.msgWarning("请选择要退费的卡片");
  727. return;
  728. }
  729. // 获取第一个选中卡片的卡号
  730. const firstCard = selectedRows.value[0];
  731. currentRefundCardNo.value = firstCard.cardNo || firstCard.id || "未知";
  732. refundOpen.value = true;
  733. }
  734. // 处理退费确认
  735. function handleRefundConfirm(cardNo) {
  736. proxy.$modal.msgSuccess(`退费成功!卡号:${cardNo}`);
  737. getList(); // 刷新列表
  738. }
  739. /** 关联校区按钮操作 */
  740. function handleAssociateCampus() {
  741. if (selectedRows.value.length === 0) {
  742. // proxy.$modal.msgWarning("请选择要关联校区的卡片");
  743. // return;
  744. }
  745. associateCampusOpen.value = true;
  746. }
  747. // 处理关联校区成功
  748. function handleAssociateCampusSuccess(message) {
  749. proxy.$modal.msgSuccess(message);
  750. getList();
  751. }
  752. // 处理关联校区确认
  753. function handleAssociateCampusConfirm(data) {
  754. proxy.$modal.msgSuccess(
  755. `关联校区成功!卡号段:${data.beginCardNo}-${data.endCardNo}`
  756. );
  757. getList(); // 刷新列表
  758. }
  759. // 获取代理商列表
  760. async function getAgentListData() {
  761. try {
  762. const response = await getAgentList({ pageNum: 1, pageSize: 1000 });
  763. if (response.code === 200) {
  764. agentList.value = response.data || [];
  765. }
  766. } catch (error) {
  767. console.error("获取代理商列表失败:", error);
  768. agentList.value = [];
  769. }
  770. }
  771. /** 申请开卡按钮操作 */
  772. function handleApplyCard() {
  773. if (selectedRows.value.length === 0) {
  774. // proxy.$modal.msgWarning("请选择要申请开卡的卡片");
  775. // return;
  776. }
  777. applyCardOpen.value = true;
  778. }
  779. // 处理申请开卡成功
  780. function handleApplyCardSuccess(message) {
  781. proxy.$modal.msgSuccess(message);
  782. getList();
  783. }
  784. // 处理申请开卡确认
  785. function handleApplyCardConfirm(data) {
  786. proxy.$modal.msgSuccess(
  787. `申请开卡成功!卡号段:${data.beginCardNo}-${data.endCardNo}`
  788. );
  789. getList(); // 刷新列表
  790. }
  791. /** 分配卡按钮操作 */
  792. function handleAssignCard() {
  793. assignCardOpen.value = true;
  794. getInstitutionList(); // 获取机构列表
  795. getAgentList(); // 获取代理商列表
  796. }
  797. /** 修改按钮操作 */
  798. async function handleUpdate(row) {
  799. reset();
  800. const _cardId = row.cardId || ids.value;
  801. currentCardId.value = _cardId;
  802. try {
  803. // 获取学习卡详细信息
  804. const response = await getCards(_cardId);
  805. if (response.code === 200) {
  806. const cardData = response.data;
  807. // 将后端数据对应到表单字段
  808. form.value = {
  809. cardId: cardData.cardId,
  810. cardNo: cardData.cardNo,
  811. password: cardData.password,
  812. type: cardData.type,
  813. status: cardData.status,
  814. distributeStatus: cardData.distributeStatus,
  815. timeStatus: cardData.timeStatus,
  816. payStatus: cardData.payStatus,
  817. isSettlement: cardData.isSettlement,
  818. deptId: cardData.deptId,
  819. agentId: cardData.agentId,
  820. leftAgentId: cardData.leftAgentId,
  821. campusId: cardData.campusId,
  822. assignSchoolId: cardData.assignSchoolId,
  823. schoolId: cardData.schoolId,
  824. classId: cardData.classId,
  825. year: cardData.year,
  826. endYear: cardData.endYear,
  827. openId: cardData.openId,
  828. nickName: cardData.nickName,
  829. mobile: cardData.mobile,
  830. chineseMathEnglish: cardData.chineseMathEnglish,
  831. vocationalSkills: cardData.vocationalSkills,
  832. studentCategory: cardData.studentCategory,
  833. assignExamType: cardData.assignExamType,
  834. areaIds: cardData.areaIds,
  835. remark: cardData.remark,
  836. };
  837. // 获取班级列表
  838. await getClassList();
  839. // 打开编辑弹窗
  840. open.value = true;
  841. } else {
  842. proxy.$modal.msgError("获取学习卡信息失败");
  843. }
  844. } catch (error) {
  845. console.error("获取学习卡详细信息失败:", error);
  846. proxy.$modal.msgError("获取学习卡信息失败");
  847. }
  848. }
  849. /** 提交按钮 */
  850. function submitForm() {
  851. proxy.$refs["cardsRef"].validate((valid) => {
  852. if (valid) {
  853. if (form.value.cardId != null) {
  854. updateCards(form.value).then((response) => {
  855. proxy.$modal.msgSuccess("修改成功");
  856. open.value = false;
  857. getList();
  858. });
  859. } else {
  860. addCards(form.value).then((response) => {
  861. proxy.$modal.msgSuccess("新增成功");
  862. open.value = false;
  863. getList();
  864. });
  865. }
  866. }
  867. });
  868. }
  869. /** 删除按钮操作 */
  870. function handleDelete(row) {
  871. const _cardIds = row.cardId || ids.value;
  872. const cardIdsArray = Array.isArray(_cardIds) ? _cardIds : [_cardIds];
  873. if (cardIdsArray.length === 0) {
  874. proxy.$modal.msgWarning("请选择要删除的数据");
  875. return;
  876. }
  877. const message =
  878. cardIdsArray.length === 1
  879. ? `是否确认删除学习卡编号为"${cardIdsArray[0]}"的数据项?`
  880. : `是否确认删除选中的${cardIdsArray.length}条学习卡数据?`;
  881. proxy.$modal
  882. .confirm(message)
  883. .then(function () {
  884. return delCards(cardIdsArray);
  885. })
  886. .then(() => {
  887. getList();
  888. proxy.$modal.msgSuccess("删除成功");
  889. })
  890. .catch(() => {});
  891. }
  892. /** 导出按钮操作 */
  893. function handleExport() {
  894. proxy.download(
  895. "dz/cards/export",
  896. {
  897. ...queryParams.value,
  898. },
  899. `cards_${new Date().getTime()}.xlsx`
  900. );
  901. }
  902. getList();
  903. // 监听地址选择变化,自动获取学校列表
  904. watch(
  905. () => queryParams.value.areaIds,
  906. (newAreaIds) => {
  907. if (newAreaIds && newAreaIds.length > 0) {
  908. getSchoolList();
  909. } else {
  910. schoolList.value = [];
  911. }
  912. },
  913. { immediate: true, deep: true }
  914. );
  915. </script>