deepchart后台管理系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

384 lines
9.4 KiB

3 weeks ago
  1. <template>
  2. <div class="page-container">
  3. <div class="search-container">
  4. <el-button type="danger" @click="addArticle">添加关联文章</el-button>
  5. </div>
  6. <!-- 数据 -->
  7. <el-table
  8. :data="tableData"
  9. style="width: 100%; margin-top: 20px"
  10. header-cell-class-name="table-header"
  11. @sort-change="handleSortChange"
  12. :default-sort="{ prop: null, order: null }"
  13. class="table-rounded"
  14. :loading="tableLoading"
  15. >
  16. <el-table-column
  17. prop="id"
  18. label="序号"
  19. align="center"
  20. header-align="center"
  21. width="80"
  22. >
  23. <template #default="scope">
  24. {{ (currentPage - 1) * pageSize + scope.$index + 1 }}
  25. </template>
  26. </el-table-column>
  27. <el-table-column
  28. prop="article_id"
  29. label="文章id"
  30. align="center"
  31. header-align="center"
  32. />
  33. <el-table-column
  34. prop="article_title"
  35. label="关联文章"
  36. align="center"
  37. header-align="center"
  38. />
  39. <el-table-column label="状态" prop="status" align="center" header-align="center">
  40. <template #default="scope">
  41. <el-switch
  42. v-model="scope.row.status"
  43. :active-value="1"
  44. :inactive-value="0"
  45. inline-prompt
  46. style="
  47. --el-switch-on-color: #13ce66;
  48. --el-switch-off-color: #ff4949;
  49. "
  50. active-text="ON"
  51. inactive-text="OFF"
  52. :disabled="activeRecordId && activeRecordId !== scope.row.id"
  53. :before-change="() => beforeChangeState(scope.row)"
  54. >
  55. </el-switch>
  56. </template>
  57. </el-table-column>
  58. <el-table-column label="操作" align="center" header-align="center">
  59. <template #default="scope">
  60. <el-button type="text" @click="deleteArticle(scope.row)">删除</el-button>
  61. <el-button type="text" @click="editArticle(scope.row)">编辑</el-button>
  62. </template>
  63. </el-table-column>
  64. </el-table>
  65. <!-- 分页组件 -->
  66. <div class="demo-pagination-block">
  67. <el-pagination
  68. @size-change="handleSizeChange"
  69. @current-change="handleCurrentChange"
  70. :current-page="currentPage"
  71. :page-sizes="[10, 15, 20, 50, 100]"
  72. :page-size="pageSize"
  73. layout="total, sizes, prev, pager, next, jumper"
  74. :total="datatotal"
  75. />
  76. </div>
  77. <el-dialog v-model="dialogFormVisible" width="500" :show-close="false" :title="isEditMode ? '更改关联文章' : '添加关联文章'">
  78. <el-form
  79. :model="form"
  80. style="width: 400px; margin: 0 auto"
  81. :rules="rules"
  82. ref="formRef"
  83. >
  84. <el-form-item label="文章id" prop="article_id">
  85. <el-input
  86. v-model="form.article_id"
  87. type="number"
  88. autocomplete="off"
  89. placeholder="请输入文章id"
  90. clearable
  91. />
  92. </el-form-item>
  93. </el-form>
  94. <template #footer>
  95. <div class="dialog-footer">
  96. <el-button @click="dialogFormVisible = false">取消</el-button>
  97. <el-button type="danger" @click="submitForm(formRef)">
  98. 提交
  99. </el-button>
  100. </div>
  101. </template>
  102. </el-dialog>
  103. </div>
  104. </template>
  105. <script setup>
  106. import { ref, reactive, onMounted, computed, watch } from "vue";
  107. import { ElMessage, ElMessageBox } from "element-plus";
  108. import router from "../../router";
  109. import {
  110. getLearningPageListApi,
  111. addLearningPageApi,
  112. deleteLearningPageApi,
  113. changeLearningPageStatusApi,
  114. } from "../../api/eventManagement";
  115. const formRef = ref();
  116. const form = reactive({
  117. id: null,
  118. article_id: null,
  119. });
  120. const validateNum = (rule, value, callback) => {
  121. if (value === "" || value === null || value === undefined) {
  122. callback();
  123. return;
  124. }
  125. if (Number(value) < 0) {
  126. callback(new Error("不能为负数"));
  127. } else {
  128. callback();
  129. }
  130. };
  131. const rules = {
  132. article_id: [
  133. { required: true, message: "请输入文章id", trigger: "blur" },
  134. { validator: validateNum, trigger: "blur" },
  135. ],
  136. };
  137. // token
  138. const token = localStorage.getItem("token");
  139. const dialogFormVisible = ref(false);
  140. const isEditMode = ref(false);
  141. // 表格数据
  142. const tableData = ref([]);
  143. const tableLoading = ref(false);
  144. const datatotal = ref(0);
  145. const activeRecordId = ref(null);
  146. // 分页参数
  147. const currentPage = ref(1);
  148. const pageSize = ref(15);
  149. const beforeChangeState = (row) => {
  150. return new Promise(async (resolve, reject) => {
  151. try {
  152. const targetStatus = row.status === 1 ? 0 : 1;
  153. // 检查是否有其他记录处于on状态
  154. if (targetStatus === 1 && activeRecordId.value && activeRecordId.value !== row.id) {
  155. ElMessage.error("已有状态为ON的记录,无法修改其他记录的状态");
  156. reject(new Error("已有状态为ON的记录"));
  157. return;
  158. }
  159. await changeLearningPageStatusApi({
  160. token: token,
  161. id: row.id,
  162. status: targetStatus,
  163. });
  164. ElMessage.success("状态更新成功");
  165. resolve(true);
  166. fetchTableData();
  167. } catch (error) {
  168. reject(new Error("状态更新失败"));
  169. }
  170. });
  171. };
  172. // 重置表单数据
  173. const resetForm = () => {
  174. form.id = null;
  175. form.article_id = null;
  176. };
  177. // 添加按钮
  178. const addArticle = () => {
  179. resetForm();
  180. isEditMode.value = false;
  181. dialogFormVisible.value = true;
  182. };
  183. // 编辑按钮
  184. const editArticle = (row) => {
  185. form.id = row.id;
  186. form.article_id = row.article_id;
  187. isEditMode.value = true;
  188. dialogFormVisible.value = true;
  189. };
  190. const submitForm = async () => {
  191. try {
  192. await formRef.value.validate();
  193. const requestParams = {
  194. token: token,
  195. article_id: form.article_id,
  196. };
  197. if (isEditMode.value) {
  198. requestParams.id = form.id;
  199. await addLearningPageApi(requestParams);
  200. ElMessage.success("编辑成功");
  201. } else {
  202. await addLearningPageApi(requestParams);
  203. ElMessage.success("添加成功");
  204. }
  205. dialogFormVisible.value = false;
  206. fetchTableData();
  207. } catch (error) {}
  208. };
  209. const deleteArticle = async (row) => {
  210. try {
  211. await ElMessageBox.confirm("确定要删除吗?", "确认删除", {
  212. confirmButtonText: "确定",
  213. cancelButtonText: "取消",
  214. type: "warning",
  215. confirmButtonClass: "custom-confirm-btn",
  216. });
  217. const requestParams = {
  218. token: token,
  219. id: row.id,
  220. };
  221. const data = await deleteLearningPageApi(requestParams);
  222. ElMessage.success("删除成功");
  223. fetchTableData();
  224. } catch (error) {
  225. if (error === "cancel") {
  226. ElMessage.info("已取消删除");
  227. } else {
  228. ElMessage.error("删除失败");
  229. }
  230. }
  231. };
  232. // 获取表格数据
  233. const fetchTableData = async () => {
  234. try {
  235. tableLoading.value = true;
  236. const requestParams = {
  237. token: token,
  238. page: currentPage.value,
  239. page_size: pageSize.value,
  240. };
  241. const data = await getLearningPageListApi(requestParams);
  242. tableData.value = data.list;
  243. datatotal.value = data.total;
  244. // 检查是否有状态为on的记录
  245. const activeRecord = data.list.find(item => item.status === 1);
  246. activeRecordId.value = activeRecord ? activeRecord.id : null;
  247. } catch (error) {
  248. console.error("获取表格数据失败:", error);
  249. tableData.value = [];
  250. datatotal.value = 0;
  251. activeRecordId.value = null;
  252. } finally {
  253. tableLoading.value = false;
  254. }
  255. };
  256. // 组件挂载时:获取地区列表 + 初始化表格数据
  257. onMounted(() => {
  258. fetchTableData();
  259. });
  260. // 分页方法
  261. const handleSizeChange = (val) => {
  262. pageSize.value = val;
  263. fetchTableData();
  264. console.log(`每页 ${val}`);
  265. };
  266. const handleCurrentChange = (val) => {
  267. currentPage.value = val;
  268. fetchTableData();
  269. console.log(`当前页: ${val}`);
  270. };
  271. const handleSortChange = (val) => {
  272. console.log("排序改变:", val);
  273. };
  274. </script>
  275. <style scoped>
  276. /* 父容器 */
  277. .page-container {
  278. position: relative;
  279. min-height: 600px;
  280. }
  281. /* 搜索区域 */
  282. .search-container {
  283. display: flex;
  284. height: auto;
  285. flex-direction: column;
  286. justify-content: center;
  287. align-items: flex-start;
  288. gap: 12px;
  289. align-self: stretch;
  290. border-radius: 8px;
  291. background: #fefaf9;
  292. box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
  293. padding: 15px;
  294. margin-bottom: 20px;
  295. }
  296. /* 表格样式 */
  297. .table-rounded {
  298. border-radius: 12px !important;
  299. overflow: hidden !important;
  300. border: 1px solid #e4e7ed !important;
  301. height: 750px;
  302. }
  303. .table-header {
  304. text-align: center !important;
  305. font-weight: 800 !important;
  306. font-size: 15px !important;
  307. color: #333 !important;
  308. background-color: #f8f9fa !important;
  309. }
  310. .el-table__cell {
  311. border-right: none !important;
  312. border-bottom: 1px solid #e4e7ed !important;
  313. }
  314. .el-table__header th.el-table__cell {
  315. border-right: none !important;
  316. border-bottom: 1px solid #e4e7ed !important;
  317. }
  318. .el-table__row:hover .el-table__cell {
  319. background-color: #fafafa !important;
  320. }
  321. /* 分页组件样式 */
  322. .demo-pagination-block {
  323. display: flex;
  324. width: 100%;
  325. height: 44px;
  326. padding: 0 16px;
  327. align-items: center;
  328. gap: 16px;
  329. position: absolute;
  330. margin-top: 10px;
  331. border-radius: 0 0 3px 3px;
  332. border-top: 1px solid #eaeaea;
  333. background: #fefbfb;
  334. box-sizing: border-box;
  335. }
  336. .tip {
  337. font-size: 12px;
  338. color: #8c939d;
  339. }
  340. </style>
  341. <style>
  342. .custom-confirm-btn {
  343. background: #e13d52;
  344. border-color: #e13d52;
  345. color: white !important;
  346. border-radius: 6px !important;
  347. padding: 8px 16px !important;
  348. }
  349. .custom-confirm-btn:hover {
  350. background: #d88b95;
  351. border-color: #d88b95;
  352. }
  353. </style>