index.vue 27 KB

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