index.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <script setup lang="ts">
  2. import { reactive, onMounted, ref, nextTick } from "vue";
  3. import { getFaqList, removeFaq } from "@/api/faq";
  4. import { useRenderIcon } from "@/components/ReIcon/src/hooks";
  5. import { ElMessage, ElMessageBox } from "element-plus";
  6. import FaqDialog from "./dialog.vue";
  7. defineOptions({ name: "AdminFaq" });
  8. const queryRef = ref();
  9. const dialogRef = ref();
  10. interface ColumnItem {
  11. label: string;
  12. prop: string;
  13. width?: number;
  14. }
  15. const state = reactive({
  16. formQuery: {
  17. question: "",
  18. status: ""
  19. },
  20. pageQuery: {
  21. pageNum: 1,
  22. pageSize: 10,
  23. total: 0
  24. },
  25. tableData: {
  26. height: 500,
  27. data: [] as Array<any>,
  28. loading: false,
  29. columns: [
  30. { label: "问题", prop: "question", width: 200 },
  31. { label: "状态", prop: "status", width: 150 },
  32. { label: "答案", prop: "answer" }
  33. ] as ColumnItem[]
  34. }
  35. });
  36. onMounted(() => {
  37. loadData();
  38. nextTick(() => {
  39. const bodyHeight = document.body.clientHeight;
  40. const queryHeight = queryRef.value?.$el?.clientHeight || 0;
  41. state.tableData.height = bodyHeight - queryHeight - 230;
  42. });
  43. });
  44. const loadData = (refresh: boolean = false) => {
  45. if (refresh) {
  46. state.pageQuery.pageNum = 1;
  47. }
  48. state.tableData.loading = true;
  49. getFaqList({ ...state.formQuery, ...state.pageQuery })
  50. .then((res: any) => {
  51. const { list, total } = res || {};
  52. state.tableData.data = list || [];
  53. state.pageQuery.total = total || 0;
  54. })
  55. .catch(() => {
  56. state.tableData.data = [];
  57. })
  58. .finally(() => {
  59. state.tableData.loading = false;
  60. });
  61. };
  62. const handleSizeChange = (size: number) => {
  63. state.pageQuery.pageSize = size;
  64. loadData(true);
  65. };
  66. const handleCurrentChange = (page: number) => {
  67. state.pageQuery.pageNum = page;
  68. loadData();
  69. };
  70. const handleSearch = () => {
  71. loadData(true);
  72. };
  73. const handleReset = () => {
  74. state.formQuery = {
  75. question: "",
  76. status: ""
  77. };
  78. loadData(true);
  79. };
  80. const handleAdd = () => dialogRef.value?.open("add");
  81. const handleEdit = (row: any) => dialogRef.value?.open("edit", row);
  82. const handleDelete = (row: any) => {
  83. ElMessageBox.confirm("确定要删除此问题吗?", "提示", {
  84. confirmButtonText: "确定", cancelButtonText: "取消", type: "warning"
  85. }).then(() => {
  86. removeFaq(row.id).then(() => {
  87. ElMessage.success("删除成功");
  88. loadData(true);
  89. });
  90. }).catch(() => {});
  91. };
  92. </script>
  93. <template>
  94. <div class="page-container">
  95. <el-card shadow="hover">
  96. <template #header>
  97. <span class="card-header">常见问题</span>
  98. </template>
  99. <el-form ref="queryRef" :model="state.formQuery" inline class="search-form">
  100. <el-form-item label="问题">
  101. <el-input v-model="state.formQuery.question" placeholder="请输入问题关键词" clearable @keyup.enter="handleSearch" />
  102. </el-form-item>
  103. <el-form-item>
  104. <el-button
  105. type="primary"
  106. :icon="useRenderIcon('ri/search-line')"
  107. @click="handleSearch"
  108. >
  109. 查询
  110. </el-button>
  111. <el-button
  112. :icon="useRenderIcon('ri/refresh-line')"
  113. @click="handleReset"
  114. >
  115. 重置
  116. </el-button>
  117. <el-button
  118. type="success"
  119. :icon="useRenderIcon('ri/add-line')"
  120. @click="handleAdd"
  121. >
  122. 新增
  123. </el-button>
  124. </el-form-item>
  125. </el-form>
  126. <el-table
  127. v-loading="state.tableData.loading"
  128. :data="state.tableData.data"
  129. :height="state.tableData.height"
  130. border
  131. stripe
  132. >
  133. <template #empty>
  134. <el-empty description="暂无数据" />
  135. </template>
  136. <el-table-column
  137. v-for="col in state.tableData.columns"
  138. :key="col.prop"
  139. :prop="col.prop"
  140. :label="col.label"
  141. :width="col.width"
  142. show-overflow-tooltip
  143. />
  144. <el-table-column label="操作" width="150" fixed="right">
  145. <template #default="{ row }">
  146. <el-button type="primary" link size="small" @click="handleEdit(row)">编辑</el-button>
  147. <el-button type="danger" link size="small" @click="handleDelete(row)">删除</el-button>
  148. </template>
  149. </el-table-column>
  150. </el-table>
  151. <div class="pagination-container">
  152. <el-pagination
  153. v-model:current-page="state.pageQuery.pageNum"
  154. v-model:page-size="state.pageQuery.pageSize"
  155. :total="state.pageQuery.total"
  156. :page-sizes="[10, 20, 50, 100]"
  157. layout="total, sizes, prev, pager, next, jumper"
  158. @size-change="handleSizeChange"
  159. @current-change="handleCurrentChange"
  160. />
  161. </div>
  162. </el-card>
  163. <FaqDialog ref="dialogRef" @refresh="loadData" />
  164. </div>
  165. </template>
  166. <style scoped lang="scss">
  167. .page-container {
  168. padding: 15px;
  169. }
  170. .card-header { font-size: 16px; font-weight: 600; }
  171. .search-form {
  172. margin-bottom: 15px;
  173. }
  174. .pagination-container {
  175. display: flex;
  176. justify-content: flex-end;
  177. margin-top: 15px;
  178. }
  179. </style>