Browse Source

feat: 添加置顶操作

rindy 5 tháng trước cách đây
mục cha
commit
c0051f6cbd

+ 10 - 0
packages/backend/src/modules/article/article.controller.ts

@@ -48,4 +48,14 @@ export class ArticleController {
   update(@Param('id') id: string, @Body() updateCategoryDto: UpdateArticleDto) {
     return this.articleService.update(+id, updateCategoryDto);
   }
+
+  @Post('up/:id')
+  up(@Param('id') id: string,) {
+    return this.articleService.up(+id);
+  }
+
+  @Post('down/:id')
+  down(@Param('id') id: string,) {
+    return this.articleService.down(+id);
+  }
 }

+ 3 - 0
packages/backend/src/modules/article/article.entity.ts

@@ -40,6 +40,9 @@ export class Article extends TranslatableEntity<ArticleTranslation> {
   @Column({ default: 0 })
   readCount: number;
 
+  @Column({ default: 0 })
+  order: number;
+
   @OneToOne(() => Category, {
     cascade: true,
     onDelete: 'CASCADE',

+ 39 - 1
packages/backend/src/modules/article/article.service.ts

@@ -48,7 +48,7 @@ export class ArticleService {
         },
       },
       order: {
-        // title: 'ASC',
+        order: 'DESC',
         createTime: 'DESC',
       },
       take: pageSize,
@@ -102,4 +102,42 @@ export class ArticleService {
     await this.articleRepo.save(updateArticle);
     return true;
   }
+
+  /**
+   * 置顶
+   * @param id
+   * @returns
+   */
+  async up(id: number) {
+    const article = await this.articleRepo.findOne({ where: { id } });
+    if (!article) throw new BadRequestException('权限不存在或者已删除');
+
+    await this.articleRepo.query(
+      'call update_article_order()',
+    );
+
+    const updateArticle = this.articleRepo.merge(article, { order: 999999 });
+
+    delete updateArticle.userId;
+    delete updateArticle.user;
+    await this.articleRepo.save(updateArticle);
+    return true;
+  }
+
+  /**
+   * 取消置顶
+   * @param id
+   * @returns
+   */
+  async down(id: number) {
+    const article = await this.articleRepo.findOne({ where: { id } });
+    if (!article) throw new BadRequestException('权限不存在或者已删除');
+
+    const updateArticle = this.articleRepo.merge(article, { order: 0 });
+
+    delete updateArticle.userId;
+    delete updateArticle.user;
+    await this.articleRepo.save(updateArticle);
+    return true;
+  }
 }

+ 4 - 0
packages/frontend/src/styles/global.css

@@ -89,3 +89,7 @@ body {
 .dark::view-transition-old(root) {
   z-index: 9999;
 }
+
+.n-data-table .n-data-table-td.n-data-table-td--fixed-right {
+  white-space: nowrap;
+}

+ 2 - 0
packages/frontend/src/views/article/api.js

@@ -7,6 +7,8 @@ export default {
   delete: id => request.delete(`/article/${id}`),
   getOne: id => request.get(`/article/detail/${id}`),
   getAll: data => request.get('/article?enable=1', data),
+  up: id => request.post(`/article/up/${id}`),
+  down: id => request.post(`/article/down/${id}`),
   uploadImage: data => request.post('/menu/cover/upload', data, {
     headers: {
       'Content-Type': 'multipart/form-data',

+ 56 - 13
packages/frontend/src/views/article/index.vue

@@ -14,12 +14,10 @@
         </n-input>
       </MeQueryItem>
       <MeQueryItem label="状态" :label-width="50">
-        <n-select
-          v-model:value="queryItems.enable" clearable :options="[
-            { label: '启用', value: 1 },
-            { label: '停用', value: 0 },
-          ]"
-        />
+        <n-select v-model:value="queryItems.enable" clearable :options="[
+          { label: '启用', value: 1 },
+          { label: '停用', value: 0 },
+        ]" />
       </MeQueryItem>
     </MeCrud>
   </CommonPage>
@@ -29,7 +27,7 @@
 import { MeCrud, MeQueryItem } from '@/components'
 import { useCrud } from '@/composables'
 import { formatDateTime } from '@/utils'
-import { NButton, NSwitch } from 'naive-ui'
+import { NButton, NSwitch, NDropdown } from 'naive-ui'
 import api from './api'
 
 defineOptions({ name: 'RoleMgt' })
@@ -54,6 +52,17 @@ const { handleDelete }
     refresh: (_, keepCurrentPage) => $table.value?.handleSearch(keepCurrentPage),
   })
 
+const topOptions = [
+  {
+    label: '设置置顶',
+    key: 'up',
+  },
+  {
+    label: '取消置顶',
+    key: 'down',
+  }
+]
+
 const columns = [
   { title: 'ID', key: 'id', width: '80' },
   { title: '标题', key: 'title', width: '200' },
@@ -93,23 +102,39 @@ const columns = [
   {
     title: '操作',
     key: 'actions',
-    width: 200,
+    //width: 200,
     align: 'center',
     fixed: 'right',
     render(row) {
       return [
+        h(NDropdown, {
+          options:topOptions,
+          trigger: 'click',
+          onSelect: (key) => handleUpDown(row,key)
+        }, {
+          default: () => h(NButton,
+            {
+              bordered: false,
+              type: 'info',
+              size: "small"
+            },
+            {
+              default: () => '置顶',
+              // icon: () => h('i', { class: 'i-fe:more-horizontal mr-4 text-16' }),
+            })
+        }),
         h(
           NButton,
           {
             size: 'small',
             type: 'primary',
-            style: 'margin-left: 12px;',
+            style: 'margin-left: 6px;margin-right: 6px;',
             disabled: row.code === 'SUPER_ADMIN',
             onClick: () => handleEdit(row),
           },
           {
             default: () => '编辑',
-            icon: () => h('i', { class: 'i-material-symbols:edit-outline text-14' }),
+            // icon: () => h('i', { class: 'i-material-symbols:edit-outline text-14' }),
           },
         ),
 
@@ -118,13 +143,12 @@ const columns = [
           {
             size: 'small',
             type: 'error',
-            style: 'margin-left: 12px;',
             disabled: row.code === 'SUPER_ADMIN',
             onClick: () => handleDelete(row.id),
           },
           {
             default: () => '删除',
-            icon: () => h('i', { class: 'i-material-symbols:delete-outline text-14' }),
+            // icon: () => h('i', { class: 'i-material-symbols:delete-outline text-14' }),
           },
         ),
       ]
@@ -157,4 +181,23 @@ function htmlspecialchars(str) {
 function handleEdit(row) {
   router.push(`/article/edit/${row.id}`)
 }
-</script>
+
+async function handleUpDown(row,key) {
+  row.enableLoading = true
+  try {
+    if(key == 'up') {
+      await api.up(row.id)
+    } else {
+      await api.down(row.id)
+    }
+    
+    row.enableLoading = false
+    $message.success('操作成功')
+    $table.value?.handleSearch()
+  }
+  catch (error) {
+    console.error(error)
+    row.enableLoading = false
+  }
+}
+</script>