index.vue 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <style scoped lang="scss">
  2. .group-card {
  3. margin-bottom: 16px;
  4. .group-header {
  5. display: flex;
  6. align-items: center;
  7. justify-content: space-between;
  8. padding: 12px 16px;
  9. background-color: var(--el-fill-color-light);
  10. border-radius: 6px 6px 0 0;
  11. border: 1px solid var(--el-border-color-light);
  12. border-bottom: none;
  13. .group-info {
  14. display: flex;
  15. align-items: center;
  16. gap: 12px;
  17. .group-title {
  18. font-weight: 600;
  19. font-size: 15px;
  20. }
  21. }
  22. .group-actions {
  23. display: flex;
  24. gap: 8px;
  25. }
  26. }
  27. .item-table-wrap {
  28. border: 1px solid var(--el-border-color-light);
  29. border-top: none;
  30. border-radius: 0 0 6px 6px;
  31. padding: 0;
  32. }
  33. }
  34. .station-tags {
  35. display: flex;
  36. flex-wrap: wrap;
  37. gap: 4px;
  38. margin-top: 4px;
  39. }
  40. </style>
  41. <template>
  42. <div class="system-container layout-padding">
  43. <el-card shadow="hover" class="layout-padding-auto">
  44. <div class="page-search mb10" style="display: flex; align-items: center; gap: 10px;">
  45. <el-button v-auth="'rechargeConfig.add'" size="default" plain type="success" @click="handleGroupAdd">
  46. <SvgIcon name="ele-FolderAdd"/>
  47. 创建分组
  48. </el-button>
  49. </div>
  50. <div v-loading="state.loading">
  51. <el-empty v-if="!state.loading && state.groups.length === 0" description="暂无充值配置分组" />
  52. <div v-for="g in state.groups" :key="g.group.id" class="group-card">
  53. <div class="group-header">
  54. <div class="group-info">
  55. <span class="group-title">
  56. <el-tag v-if="g.group.isDefault" type="danger" effect="light">默认</el-tag>
  57. {{ g.group.name || (g.group.isDefault ? '平台默认配置' : '未命名分组') }}
  58. </span>
  59. <div class="station-tags">
  60. <el-tag
  61. v-for="sid in g.stationIds"
  62. :key="sid"
  63. type="success"
  64. size="small"
  65. closable
  66. @close="handleRemoveStation(g.group.id, sid)">
  67. {{ sid }}
  68. </el-tag>
  69. <el-button size="small" text type="primary" @click="handleAssignStation(g.group.id)">+ 关联站点</el-button>
  70. </div>
  71. </div>
  72. <div class="group-actions">
  73. <el-button v-auth="'rechargeConfig.add'" size="small" type="primary" plain @click="handleItemAdd(g.group.id)">+ 配置项</el-button>
  74. <el-button v-auth="'rechargeConfig.remove'" size="small" type="danger" plain @click="handleGroupRemove(g.group)">删除</el-button>
  75. </div>
  76. </div>
  77. <div class="item-table-wrap">
  78. <el-table border :data="g.items" size="small" v-loading="g.itemsLoading">
  79. <template #empty>
  80. <el-empty :image-size="40" description="暂无配置项" />
  81. </template>
  82. <el-table-column label="充值金额" prop="rechargeAmount" width="140">
  83. <template #default="{ row }">
  84. {{ u.fmt.fmtMoney(row.rechargeAmount) }}
  85. </template>
  86. </el-table-column>
  87. <el-table-column label="赠款金额" prop="grantsAmount" width="140">
  88. <template #default="{ row }">
  89. {{ u.fmt.fmtMoney(row.grantsAmount) }}
  90. </template>
  91. </el-table-column>
  92. <el-table-column label="标签" prop="label" min-width="120">
  93. <template #default="{ row }">
  94. {{ row.label || '-' }}
  95. </template>
  96. </el-table-column>
  97. <el-table-column label="操作" prop="action" width="160" align="center" fixed="right">
  98. <template #default="{ row }">
  99. <el-button v-auth="'rechargeConfig.modify'" type="warning" size="small" text @click="handleItemEdit(g.group.id, row)">编辑</el-button>
  100. <el-button v-auth="'rechargeConfig.remove'" type="danger" size="small" text @click="handleItemRemove(row)">删除</el-button>
  101. </template>
  102. </el-table-column>
  103. </el-table>
  104. </div>
  105. </div>
  106. </div>
  107. </el-card>
  108. </div>
  109. <GroupDialog ref="groupDialogRef" @refresh="loadData" />
  110. <AssignStationDialog ref="assignStationDialogRef" @refresh="loadData" />
  111. <ItemDialog ref="itemDialogRef" @refresh="loadData" />
  112. </template>
  113. <script setup lang="ts" name="AdminRechargeConfig">
  114. import { defineAsyncComponent, reactive, onMounted, ref } from 'vue';
  115. import { $body, $get } from "/@/utils/request";
  116. import u from '/@/utils/u'
  117. import { Msg } from "/@/utils/message";
  118. const GroupDialog = defineAsyncComponent(() => import("./groupDialog.vue"));
  119. const AssignStationDialog = defineAsyncComponent(() => import("./assignStationDialog.vue"));
  120. const ItemDialog = defineAsyncComponent(() => import("./itemDialog.vue"));
  121. const groupDialogRef = ref();
  122. const assignStationDialogRef = ref();
  123. const itemDialogRef = ref();
  124. interface GroupRow {
  125. group: any;
  126. stationIds: string[];
  127. items: any[];
  128. itemsLoading: boolean;
  129. }
  130. const state = reactive({
  131. loading: false,
  132. groups: [] as GroupRow[],
  133. });
  134. onMounted(() => {
  135. loadData();
  136. });
  137. const loadData = () => {
  138. state.loading = true;
  139. $get('/rechargeConfig/group/list').then((groups: any) => {
  140. state.groups = (groups || []).map((g: any) => ({
  141. group: g.group,
  142. stationIds: g.stationIds || [],
  143. items: [],
  144. itemsLoading: false,
  145. }));
  146. state.groups.forEach((g) => loadItems(g));
  147. state.loading = false;
  148. }).catch(() => {
  149. state.loading = false;
  150. });
  151. };
  152. const loadItems = (g: GroupRow) => {
  153. g.itemsLoading = true;
  154. $get('/rechargeConfig/item/list', { groupId: g.group.id }).then((items: any) => {
  155. g.items = items || [];
  156. g.itemsLoading = false;
  157. }).catch(() => {
  158. g.itemsLoading = false;
  159. });
  160. };
  161. const handleGroupAdd = () => {
  162. groupDialogRef.value.open('add', null);
  163. };
  164. const handleGroupRemove = (group: any) => {
  165. Msg.confirm('此操作将永久删除该分组及其所有配置项,是否继续?').then(() => {
  166. $get(`/rechargeConfig/group/remove/${group.id}`).then(() => {
  167. Msg.message("删除成功", 'success');
  168. loadData();
  169. }).catch(() => {
  170. Msg.message("删除失败", 'error');
  171. });
  172. });
  173. };
  174. const handleAssignStation = (groupId: number) => {
  175. assignStationDialogRef.value.open(groupId);
  176. };
  177. const handleRemoveStation = (groupId: number, stationId: string) => {
  178. $body('/rechargeConfig/group/removeStation', { groupId, stationId }).then(() => {
  179. Msg.message("已移除", 'success');
  180. loadData();
  181. });
  182. };
  183. const handleItemAdd = (groupId: number) => {
  184. itemDialogRef.value.open('add', { groupId });
  185. };
  186. const handleItemEdit = (groupId: number, row: any) => {
  187. itemDialogRef.value.open('edit', { ...row, groupId });
  188. };
  189. const handleItemRemove = (row: any) => {
  190. Msg.confirm('此操作将永久删除该配置项,是否继续?').then(() => {
  191. $get(`/rechargeConfig/item/remove/${row.id}`).then(() => {
  192. Msg.message("删除成功", 'success');
  193. loadData();
  194. }).catch(() => {
  195. Msg.message("删除失败", 'error');
  196. });
  197. });
  198. };
  199. </script>