index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. <template>
  2. <div v-loading="pageLoading" class="app-container" :element-loading-text="loadingText">
  3. <PageSearch
  4. ref="searchRef"
  5. :search-config="searchConfig"
  6. @query-click="handleQueryClick"
  7. @reset-click="handleResetClick"
  8. />
  9. <PageContent ref="contentRef" :content-config="contentConfig">
  10. <template #toolbar="{ toolbarRight, onToolbar, removeIds, cols }">
  11. <CrudToolbarLeft
  12. :remove-ids="removeIds"
  13. :perm-create="['module_payment:rule:create']"
  14. @add="handleOpenDialog('create')"
  15. />
  16. <div class="data-table__toolbar--right">
  17. <CrudToolbarRight :buttons="toolbarRight" :cols="cols" :on-toolbar="onToolbar" />
  18. </div>
  19. </template>
  20. <template #table="{ data, loading, tableRef, onSelectionChange }">
  21. <div class="data-table__content">
  22. <el-table
  23. :ref="tableRef as any"
  24. v-loading="loading"
  25. :data="data"
  26. height="100%"
  27. border
  28. @selection-change="onSelectionChange"
  29. >
  30. <template #empty>
  31. <el-empty :image-size="80" description="暂无数据" />
  32. </template>
  33. <el-table-column
  34. v-if="contentCols.find((col) => col.prop === 'selection')?.show"
  35. type="selection"
  36. min-width="55"
  37. align="center"
  38. />
  39. <el-table-column
  40. v-if="contentCols.find((col) => col.prop === 'rule_id')?.show"
  41. key="rule_id"
  42. label="规则ID"
  43. prop="rule_id"
  44. min-width="150"
  45. show-overflow-tooltip
  46. />
  47. <el-table-column
  48. v-if="contentCols.find((col) => col.prop === 'institution_id')?.show"
  49. key="institution_id"
  50. label="制度ID"
  51. prop="institution_id"
  52. min-width="150"
  53. show-overflow-tooltip
  54. />
  55. <el-table-column
  56. v-if="contentCols.find((col) => col.prop === 'name')?.show"
  57. key="name"
  58. label="规则名称"
  59. prop="name"
  60. min-width="150"
  61. show-overflow-tooltip
  62. />
  63. <el-table-column
  64. v-if="contentCols.find((col) => col.prop === 'max_amount')?.show"
  65. key="max_amount"
  66. label="单笔限额"
  67. prop="max_amount"
  68. min-width="100"
  69. align="right"
  70. >
  71. <template #default="scope">
  72. {{ scope.row.max_amount ? `¥${scope.row.max_amount.toFixed(2)}` : "-" }}
  73. </template>
  74. </el-table-column>
  75. <el-table-column
  76. v-if="contentCols.find((col) => col.prop === 'max_day_amount')?.show"
  77. key="max_day_amount"
  78. label="日限额"
  79. prop="max_day_amount"
  80. min-width="100"
  81. align="right"
  82. >
  83. <template #default="scope">
  84. {{ scope.row.max_day_amount ? `¥${scope.row.max_day_amount.toFixed(2)}` : "-" }}
  85. </template>
  86. </el-table-column>
  87. <el-table-column
  88. v-if="contentCols.find((col) => col.prop === 'max_month_amount')?.show"
  89. key="max_month_amount"
  90. label="月限额"
  91. prop="max_month_amount"
  92. min-width="100"
  93. align="right"
  94. >
  95. <template #default="scope">
  96. {{ scope.row.max_month_amount ? `¥${scope.row.max_month_amount.toFixed(2)}` : "-" }}
  97. </template>
  98. </el-table-column>
  99. <el-table-column
  100. v-if="contentCols.find((col) => col.prop === 'created_time')?.show"
  101. key="created_time"
  102. label="创建时间"
  103. prop="created_time"
  104. min-width="160"
  105. sortable
  106. />
  107. <el-table-column
  108. v-if="contentCols.find((col) => col.prop === 'operation')?.show"
  109. fixed="right"
  110. label="操作"
  111. align="center"
  112. min-width="160"
  113. >
  114. <template #default="scope">
  115. <el-button
  116. v-hasPerm="['module_payment:rule:detail']"
  117. type="info"
  118. size="small"
  119. link
  120. icon="View"
  121. @click="handleOpenDialog('detail', scope.row.rule_id)"
  122. >
  123. 详情
  124. </el-button>
  125. <el-button
  126. v-hasPerm="['module_payment:rule:update']"
  127. type="primary"
  128. size="small"
  129. link
  130. icon="edit"
  131. @click="handleOpenDialog('update', scope.row.rule_id)"
  132. >
  133. 编辑
  134. </el-button>
  135. <el-button
  136. v-hasPerm="['module_payment:rule:delete']"
  137. type="danger"
  138. size="small"
  139. link
  140. icon="delete"
  141. @click="handleDelete(scope.row.rule_id)"
  142. >
  143. 删除
  144. </el-button>
  145. </template>
  146. </el-table-column>
  147. </el-table>
  148. </div>
  149. </template>
  150. </PageContent>
  151. <EnhancedDialog
  152. v-model="dialogVisible.visible"
  153. :title="dialogVisible.title"
  154. @close="handleCloseDialog"
  155. >
  156. <template v-if="dialogVisible.type === 'detail'">
  157. <RuleDetail :rule-id="currentRuleId" />
  158. </template>
  159. <template v-else>
  160. <RuleForm
  161. ref="formRef"
  162. :type="dialogVisible.type"
  163. :rule-id="currentRuleId"
  164. :institution-id="institutionIdFromUrl"
  165. @success="handleFormSuccess"
  166. />
  167. </template>
  168. <template #footer>
  169. <div class="dialog-footer">
  170. <el-button v-if="dialogVisible.type !== 'detail'" type="primary" @click="handleSubmit">
  171. 确定
  172. </el-button>
  173. <el-button v-else type="primary" @click="handleCloseDialog">确定</el-button>
  174. <el-button @click="handleCloseDialog">取消</el-button>
  175. </div>
  176. </template>
  177. </EnhancedDialog>
  178. </div>
  179. </template>
  180. <script setup lang="ts">
  181. defineOptions({
  182. name: "Rule",
  183. inheritAttrs: false,
  184. });
  185. import RuleAPI, { RulePageQuery } from "@/api/module_payment/rule";
  186. import CrudToolbarLeft from "@/components/CURD/CrudToolbarLeft.vue";
  187. import CrudToolbarRight from "@/components/CURD/CrudToolbarRight.vue";
  188. import PageSearch from "@/components/CURD/PageSearch.vue";
  189. import PageContent from "@/components/CURD/PageContent.vue";
  190. import EnhancedDialog from "@/components/CURD/EnhancedDialog.vue";
  191. import RuleForm from "./components/RuleForm.vue";
  192. import RuleDetail from "./components/RuleDetail.vue";
  193. import type { ISearchConfig, IContentConfig } from "@/components/CURD/types";
  194. import { useCrudList } from "@/components/CURD/useCrudList";
  195. import { useLoadingAction } from "@/composables/useLoadingAction";
  196. import { useRoute } from "vue-router";
  197. import { ElMessage } from "element-plus";
  198. import { ref, reactive, computed } from "vue";
  199. const route = useRoute();
  200. const { searchRef, contentRef, handleQueryClick, handleResetClick, refreshList } =
  201. useCrudList();
  202. const formRef = ref();
  203. const { pageLoading, loadingText, execute: loadingExecute } = useLoadingAction();
  204. const institutionIdFromUrl = computed(() => route.query.institution_id as string | undefined);
  205. const searchConfig = reactive<ISearchConfig>({
  206. permPrefix: "module_payment:rule",
  207. colon: true,
  208. isExpandable: true,
  209. showNumber: 2,
  210. form: { labelWidth: "auto" },
  211. formItems: [
  212. {
  213. prop: "institution_id",
  214. label: "制度ID",
  215. type: "input",
  216. attrs: { placeholder: "请输入制度ID", clearable: true },
  217. },
  218. {
  219. prop: "name",
  220. label: "规则名称",
  221. type: "input",
  222. attrs: { placeholder: "请输入规则名称", clearable: true },
  223. },
  224. ],
  225. });
  226. const contentCols = reactive<
  227. Array<{
  228. prop?: string;
  229. label?: string;
  230. show?: boolean;
  231. }>
  232. >([
  233. { prop: "selection", label: "选择框", show: false },
  234. { prop: "index", label: "序号", show: true },
  235. { prop: "rule_id", label: "规则ID", show: true },
  236. { prop: "institution_id", label: "制度ID", show: true },
  237. { prop: "name", label: "规则名称", show: true },
  238. { prop: "max_amount", label: "单笔限额", show: true },
  239. { prop: "max_day_amount", label: "日限额", show: true },
  240. { prop: "max_month_amount", label: "月限额", show: true },
  241. { prop: "created_time", label: "创建时间", show: true },
  242. { prop: "operation", label: "操作", show: true },
  243. ]);
  244. const contentConfig = reactive<IContentConfig<RulePageQuery>>({
  245. permPrefix: "module_payment:rule",
  246. pk: "rule_id",
  247. cols: contentCols as IContentConfig["cols"],
  248. hideColumnFilter: false,
  249. toolbar: [],
  250. defaultToolbar: ["refresh", "filter"],
  251. pagination: true,
  252. initialParams: computed(() => ({
  253. institution_id: institutionIdFromUrl.value,
  254. })) as Record<string, unknown>,
  255. indexAction: async (params) => {
  256. const query: RulePageQuery = {
  257. page_no: params.page_no,
  258. page_size: params.page_size,
  259. };
  260. if (params.institution_id) query.institution_id = params.institution_id;
  261. if (params.name) query.name = params.name;
  262. const res = await RuleAPI.listRule(query);
  263. return {
  264. list: res.data.data?.items || res.data.data?.list || [],
  265. total: res.data.data?.total || 0,
  266. };
  267. },
  268. });
  269. const dialogVisible = reactive({
  270. title: "",
  271. visible: false,
  272. type: "create" as "create" | "update" | "detail",
  273. });
  274. const currentRuleId = ref<string>();
  275. function handleOpenDialog(type: "create" | "update" | "detail", ruleId?: string) {
  276. dialogVisible.type = type;
  277. currentRuleId.value = ruleId;
  278. if (type === "create") {
  279. dialogVisible.title = "创建使用规则";
  280. } else if (type === "update") {
  281. dialogVisible.title = "编辑使用规则";
  282. } else {
  283. dialogVisible.title = "使用规则详情";
  284. }
  285. dialogVisible.visible = true;
  286. }
  287. async function handleCloseDialog() {
  288. dialogVisible.visible = false;
  289. }
  290. function handleSubmit() {
  291. formRef.value?.submitForm();
  292. }
  293. function handleFormSuccess() {
  294. dialogVisible.visible = false;
  295. refreshList();
  296. }
  297. async function handleDelete(ruleId?: string) {
  298. if (!ruleId) return;
  299. await loadingExecute({
  300. confirmMessage: "确认删除该使用规则?",
  301. confirmTitle: "警告",
  302. confirmType: "warning",
  303. loadingText: "正在删除...",
  304. action: () => RuleAPI.deleteRule(ruleId),
  305. onSuccess: () => {
  306. ElMessage.success("删除成功");
  307. refreshList();
  308. },
  309. });
  310. }
  311. </script>