api.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. <template>
  2. <div>
  3. <div class="gva-search-box">
  4. <el-form ref="searchForm" :inline="true" :model="searchInfo">
  5. <el-form-item label="路径">
  6. <el-input v-model="searchInfo.path" placeholder="路径" />
  7. </el-form-item>
  8. <el-form-item label="描述">
  9. <el-input v-model="searchInfo.description" placeholder="描述" />
  10. </el-form-item>
  11. <el-form-item label="API组">
  12. <el-input v-model="searchInfo.apiGroup" placeholder="api组" />
  13. </el-form-item>
  14. <el-form-item label="请求">
  15. <el-select v-model="searchInfo.method" clearable placeholder="请选择">
  16. <el-option
  17. v-for="item in methodOptions"
  18. :key="item.value"
  19. :label="`${item.label}(${item.value})`"
  20. :value="item.value"
  21. />
  22. </el-select>
  23. </el-form-item>
  24. <el-form-item>
  25. <el-button size="small" type="primary" icon="search" @click="onSubmit"
  26. >查询</el-button
  27. >
  28. <el-button size="small" icon="refresh" @click="onReset"
  29. >重置</el-button
  30. >
  31. </el-form-item>
  32. </el-form>
  33. </div>
  34. <div class="gva-table-box">
  35. <div class="gva-btn-list">
  36. <el-button
  37. size="small"
  38. type="primary"
  39. icon="plus"
  40. @click="openDialog('addApi')"
  41. >新增</el-button
  42. >
  43. <el-popover v-model="deleteVisible" placement="top" width="160">
  44. <p>确定要删除吗?</p>
  45. <div style="text-align: right; margin-top: 8px">
  46. <el-button
  47. size="small"
  48. type="primary"
  49. link
  50. @click="deleteVisible = false"
  51. >取消</el-button
  52. >
  53. <el-button size="small" type="primary" @click="onDelete"
  54. >确定</el-button
  55. >
  56. </div>
  57. <template #reference>
  58. <el-button
  59. icon="delete"
  60. size="small"
  61. :disabled="!apis.length"
  62. style="margin-left: 10px"
  63. @click="deleteVisible = true"
  64. >删除</el-button
  65. >
  66. </template>
  67. </el-popover>
  68. </div>
  69. <el-table
  70. :data="tableData"
  71. @sort-change="sortChange"
  72. @selection-change="handleSelectionChange"
  73. >
  74. <el-table-column type="selection" width="55" />
  75. <el-table-column
  76. align="left"
  77. label="id"
  78. min-width="60"
  79. prop="ID"
  80. sortable="custom"
  81. />
  82. <el-table-column
  83. align="left"
  84. label="API路径"
  85. min-width="150"
  86. prop="path"
  87. sortable="custom"
  88. />
  89. <el-table-column
  90. align="left"
  91. label="API分组"
  92. min-width="150"
  93. prop="apiGroup"
  94. sortable="custom"
  95. />
  96. <el-table-column
  97. align="left"
  98. label="API简介"
  99. min-width="150"
  100. prop="description"
  101. sortable="custom"
  102. />
  103. <el-table-column
  104. align="left"
  105. label="请求"
  106. min-width="150"
  107. prop="method"
  108. sortable="custom"
  109. >
  110. <template #default="scope">
  111. <div>
  112. {{ scope.row.method }} / {{ methodFiletr(scope.row.method) }}
  113. </div>
  114. </template>
  115. </el-table-column>
  116. <el-table-column align="left" fixed="right" label="操作" width="200">
  117. <template #default="scope">
  118. <el-button
  119. icon="edit"
  120. size="small"
  121. type="primary"
  122. link
  123. @click="editApiFunc(scope.row)"
  124. >编辑</el-button
  125. >
  126. <el-button
  127. icon="delete"
  128. size="small"
  129. type="primary"
  130. link
  131. @click="deleteApiFunc(scope.row)"
  132. >删除</el-button
  133. >
  134. </template>
  135. </el-table-column>
  136. </el-table>
  137. <div class="gva-pagination">
  138. <el-pagination
  139. :current-page="page"
  140. :page-size="pageSize"
  141. :page-sizes="[10, 30, 50, 100]"
  142. :total="total"
  143. layout="total, sizes, prev, pager, next, jumper"
  144. @current-change="handleCurrentChange"
  145. @size-change="handleSizeChange"
  146. />
  147. </div>
  148. </div>
  149. <el-dialog
  150. v-model="dialogFormVisible"
  151. :before-close="closeDialog"
  152. :title="dialogTitle"
  153. >
  154. <warning-bar title="新增API,需要在角色管理内配置权限才可使用" />
  155. <el-form ref="apiForm" :model="form" :rules="rules" label-width="80px">
  156. <el-form-item label="路径" prop="path">
  157. <el-input v-model="form.path" autocomplete="off" />
  158. </el-form-item>
  159. <el-form-item label="请求" prop="method">
  160. <el-select
  161. v-model="form.method"
  162. placeholder="请选择"
  163. style="width: 100%"
  164. >
  165. <el-option
  166. v-for="item in methodOptions"
  167. :key="item.value"
  168. :label="`${item.label}(${item.value})`"
  169. :value="item.value"
  170. />
  171. </el-select>
  172. </el-form-item>
  173. <el-form-item label="api分组" prop="apiGroup">
  174. <el-input v-model="form.apiGroup" autocomplete="off" />
  175. </el-form-item>
  176. <el-form-item label="api简介" prop="description">
  177. <el-input v-model="form.description" autocomplete="off" />
  178. </el-form-item>
  179. </el-form>
  180. <template #footer>
  181. <div class="dialog-footer">
  182. <el-button size="small" @click="closeDialog">取 消</el-button>
  183. <el-button size="small" type="primary" @click="enterDialog"
  184. >确 定</el-button
  185. >
  186. </div>
  187. </template>
  188. </el-dialog>
  189. </div>
  190. </template>
  191. <script>
  192. export default {
  193. name: "Api",
  194. };
  195. </script>
  196. <script setup>
  197. import {
  198. getApiById,
  199. getApiList,
  200. createApi,
  201. updateApi,
  202. deleteApi,
  203. deleteApisByIds,
  204. } from "@/api/api";
  205. import { toSQLLine } from "@/utils/stringFun";
  206. import warningBar from "@/components/warningBar/warningBar.vue";
  207. import { ref } from "vue";
  208. import { ElMessage, ElMessageBox } from "element-plus";
  209. const methodFiletr = (value) => {
  210. const target = methodOptions.value.filter((item) => item.value === value)[0];
  211. return target && `${target.label}`;
  212. };
  213. const apis = ref([]);
  214. const form = ref({
  215. path: "",
  216. apiGroup: "",
  217. method: "",
  218. description: "",
  219. });
  220. const methodOptions = ref([
  221. {
  222. value: "POST",
  223. label: "创建",
  224. type: "success",
  225. },
  226. {
  227. value: "GET",
  228. label: "查看",
  229. type: "",
  230. },
  231. {
  232. value: "PUT",
  233. label: "更新",
  234. type: "warning",
  235. },
  236. {
  237. value: "DELETE",
  238. label: "删除",
  239. type: "danger",
  240. },
  241. ]);
  242. const type = ref("");
  243. const rules = ref({
  244. path: [{ required: true, message: "请输入api路径", trigger: "blur" }],
  245. apiGroup: [{ required: true, message: "请输入组名称", trigger: "blur" }],
  246. method: [{ required: true, message: "请选择请求方式", trigger: "blur" }],
  247. description: [{ required: true, message: "请输入api介绍", trigger: "blur" }],
  248. });
  249. const page = ref(1);
  250. const total = ref(0);
  251. const pageSize = ref(10);
  252. const tableData = ref([]);
  253. const searchInfo = ref({});
  254. const onReset = () => {
  255. searchInfo.value = {};
  256. };
  257. // 搜索
  258. const onSubmit = () => {
  259. page.value = 1;
  260. pageSize.value = 10;
  261. getTableData();
  262. };
  263. // 分页
  264. const handleSizeChange = (val) => {
  265. pageSize.value = val;
  266. getTableData();
  267. };
  268. const handleCurrentChange = (val) => {
  269. page.value = val;
  270. getTableData();
  271. };
  272. // 排序
  273. const sortChange = ({ prop, order }) => {
  274. if (prop) {
  275. if (prop === "ID") {
  276. prop = "id";
  277. }
  278. searchInfo.value.orderKey = toSQLLine(prop);
  279. searchInfo.value.desc = order === "descending";
  280. }
  281. getTableData();
  282. };
  283. // 查询
  284. const getTableData = async () => {
  285. const table = await getApiList({
  286. page: page.value,
  287. pageSize: pageSize.value,
  288. ...searchInfo.value,
  289. });
  290. if (table.code === 0) {
  291. tableData.value = table.data.list;
  292. total.value = table.data.total;
  293. page.value = table.data.page;
  294. pageSize.value = table.data.pageSize;
  295. }
  296. };
  297. getTableData();
  298. // 批量操作
  299. const handleSelectionChange = (val) => {
  300. apis.value = val;
  301. };
  302. const deleteVisible = ref(false);
  303. const onDelete = async () => {
  304. const ids = apis.value.map((item) => item.ID);
  305. const res = await deleteApisByIds({ ids });
  306. if (res.code === 0) {
  307. ElMessage({
  308. type: "success",
  309. message: res.msg,
  310. });
  311. if (tableData.value.length === ids.length && page.value > 1) {
  312. page.value--;
  313. }
  314. deleteVisible.value = false;
  315. getTableData();
  316. }
  317. };
  318. // 弹窗相关
  319. const apiForm = ref(null);
  320. const initForm = () => {
  321. apiForm.value.resetFields();
  322. form.value = {
  323. path: "",
  324. apiGroup: "",
  325. method: "",
  326. description: "",
  327. };
  328. };
  329. const dialogTitle = ref("新增Api");
  330. const dialogFormVisible = ref(false);
  331. const openDialog = (key) => {
  332. switch (key) {
  333. case "addApi":
  334. dialogTitle.value = "新增Api";
  335. break;
  336. case "edit":
  337. dialogTitle.value = "编辑Api";
  338. break;
  339. default:
  340. break;
  341. }
  342. type.value = key;
  343. dialogFormVisible.value = true;
  344. };
  345. const closeDialog = () => {
  346. initForm();
  347. dialogFormVisible.value = false;
  348. };
  349. const editApiFunc = async (row) => {
  350. const res = await getApiById({ id: row.ID });
  351. form.value = res.data.api;
  352. openDialog("edit");
  353. };
  354. const enterDialog = async () => {
  355. apiForm.value.validate(async (valid) => {
  356. if (valid) {
  357. switch (type.value) {
  358. case "addApi":
  359. {
  360. const res = await createApi(form.value);
  361. if (res.code === 0) {
  362. ElMessage({
  363. type: "success",
  364. message: "添加成功",
  365. showClose: true,
  366. });
  367. }
  368. getTableData();
  369. closeDialog();
  370. }
  371. break;
  372. case "edit":
  373. {
  374. const res = await updateApi(form.value);
  375. if (res.code === 0) {
  376. ElMessage({
  377. type: "success",
  378. message: "编辑成功",
  379. showClose: true,
  380. });
  381. }
  382. getTableData();
  383. closeDialog();
  384. }
  385. break;
  386. default:
  387. // eslint-disable-next-line no-lone-blocks
  388. {
  389. ElMessage({
  390. type: "error",
  391. message: "未知操作",
  392. showClose: true,
  393. });
  394. }
  395. break;
  396. }
  397. }
  398. });
  399. };
  400. const deleteApiFunc = async (row) => {
  401. ElMessageBox.confirm("此操作将永久删除所有角色下该api, 是否继续?", "提示", {
  402. confirmButtonText: "确定",
  403. cancelButtonText: "取消",
  404. type: "warning",
  405. }).then(async () => {
  406. const res = await deleteApi(row);
  407. if (res.code === 0) {
  408. ElMessage({
  409. type: "success",
  410. message: "删除成功!",
  411. });
  412. if (tableData.value.length === 1 && page.value > 1) {
  413. page.value--;
  414. }
  415. getTableData();
  416. }
  417. });
  418. };
  419. </script>
  420. <style scoped lang="scss">
  421. .button-box {
  422. padding: 10px 20px;
  423. .el-button {
  424. float: right;
  425. }
  426. }
  427. .warning {
  428. color: #dc143c;
  429. }
  430. </style>