gemercheung 7 månader sedan
förälder
incheckning
0e6b00fc43

+ 12 - 0
packages/backend/src/modules/menu/dto.ts

@@ -49,6 +49,16 @@ export class CreateMenuDto {
   @IsNumber()
   @IsOptional()
   parentId?: number;
+
+  @ApiProperty({ nullable: true, required: false, default: 3 })
+  @IsNumber()
+  @IsOptional()
+  grid?: number;
+
+  @ApiProperty({ nullable: true, required: false, default: 0 })
+  @IsNumber()
+  @IsOptional()
+  level?: number;
 }
 
 export class GetMenuDto {
@@ -76,6 +86,8 @@ export class QueryMenuDto extends GetMenuDto {
 }
 
 export class UpdateMenuDto extends CreateMenuDto {
+  @Exclude()
+  user?: User;
 }
 
 export class UploadCoverDto {

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

@@ -76,4 +76,7 @@ export class Menu {
 
   @Column({ nullable: true })
   parentId: number;
+
+  @Column({ nullable: true, default: 3 })
+  grid: number;
 }

+ 2 - 1
packages/frontend/src/composables/useCrud.js

@@ -31,7 +31,7 @@ export function useCrud({ name, initForm = {}, doCreate, doDelete, doUpdate, ref
   /** 修改 */
   function handleEdit(row, title, editcallback) {
     handleOpen({ action: 'edit', title, row })
-    if (typeof addcallback === 'function') {
+    if (typeof editcallback === 'function') {
       handleEditcallback = editcallback
     }
   }
@@ -79,6 +79,7 @@ export function useCrud({ name, initForm = {}, doCreate, doDelete, doUpdate, ref
         cb: () => {
           $message.success('保存成功')
           handleEditcallback && handleEditcallback()
+          // debugger
         },
       },
     }

+ 23 - 2
packages/frontend/src/views/menu/index.vue

@@ -9,9 +9,30 @@
 
     <n-flex class="flex" justify="justify-center" size="large">
       <template v-for="(item) of topMenu" :key="item.id">
-        <n-card class="min-h-220 min-w-200 w-30%" :title="item.title">
+        <n-card class="min-h-220 min-w-200 w-32%" :title="item.title">
           <div class="ml-20 flex-col">
-            {{ item.children.length }}
+            <!-- {{ item.children.length }} -->
+            <template v-if="item.children.length > 0">
+              <n-grid x-gap="12" :cols="item.grid || 3">
+                <n-gi v-for="(child) of item.children" :key="child.id">
+                  <n-card :bordered="false" size="small">
+                    <template #cover>
+                      <!-- <div style="width: 100%;height: 50px;overflow: hidden;"> -->
+                      <n-image preview-disabled :src="child.cover" object-fit="scale-down" style="width: 100%;height: 50px;overflow: hidden;" />
+                      <!-- </div> -->
+                    </template>
+                    <div class="text-center text-12">
+                      {{ child.title }}
+                    </div>
+                  </n-card>
+                </n-gi>
+              </n-grid>
+            </template>
+            <template v-else>
+              <div class="mt-20 min-h-150 flex items-center justify-center text-center">
+                暂没子菜单
+              </div>
+            </template>
           </div>
           <template #header-extra>
             <n-dropdown

+ 51 - 10
packages/frontend/src/views/menu/list.vue

@@ -1,10 +1,15 @@
 <template>
-  <CommonPage back :title="detail.title ">
+  <CommonPage back :title="detail.title">
     <template #action>
-      <NButton type="primary" @click="handleAdd()">
-        <i class="i-material-symbols:add mr-4 text-18" />
-        新增子菜单
-      </NButton>
+      <n-space>
+        <NButton type="tertiary" @click="handleTopMenuEdit">
+          编辑
+        </NButton>
+        <NButton type="primary" @click="handleSubAdd()">
+          <i class="i-material-symbols:add mr-4 text-18" />
+          新增子菜单
+        </NButton>
+      </n-space>
     </template>
 
     <MeCrud ref="$table" v-model:query-items="queryItems" :scroll-x="1200" :columns="columns" :get-data="api.read">
@@ -24,7 +29,7 @@
     </MeCrud>
 
     <MeModal ref="modalRef" width="520px">
-      <n-form ref="modalFormRef" label-placement="left" label-align="left" :label-width="80" :model="modalForm">
+      <n-form ref="modalFormRef" label-placement="left" label-align="left" :label-width="95" :model="modalForm">
         <n-form-item
           label="名称" path="title" :rule="{
             required: true,
@@ -34,7 +39,7 @@
         >
           <n-input v-model:value="modalForm.title" />
         </n-form-item>
-        <n-form-item label="封面" path="cover">
+        <n-form-item v-if="modalForm.level !== 0" label="封面" path="cover">
           <n-upload
             :multiple="false"
             :default-upload="true"
@@ -66,7 +71,12 @@
             v-model:value="modalForm.categoryId" :options="allCategory" clearable filterable tag
           />
         </n-form-item>
-
+        <n-form-item
+          v-if="modalForm.level === 0"
+          label="一行显示数" path="grid"
+        >
+          <n-input-number v-model:value="modalForm.grid" style="width:100%" />
+        </n-form-item>
         <n-form-item label="是否显示" path="isPublish">
           <NSwitch v-model:value="modalForm.isPublish">
             <template #checked>
@@ -97,7 +107,7 @@ import { MeCrud, MeModal, MeQueryItem } from '@/components'
 import { useCrud } from '@/composables'
 import { useUserStore } from '@/store/index.js'
 import { formatDateTime } from '@/utils'
-import { NButton, NSwitch } from 'naive-ui'
+import { NButton, NImage, NSwitch } from 'naive-ui'
 import { useRoute, useRouter } from 'vue-router'
 import categoryApi from '../category/api'
 import api from './api.js'
@@ -142,6 +152,17 @@ const columns = [
   { title: '标题名', key: 'title', width: '200' },
   { title: '分类', key: 'category.title' },
   {
+    title: '封面图',
+    key: 'cover',
+    render: row => row.cover
+      ? h(NImage, {
+          src: row.cover,
+          height: 60,
+          width: 80,
+        })
+      : null,
+  },
+  {
     title: '创建时间',
     key: 'createTime',
     render: row => h('span', formatDateTime(row.createTime)),
@@ -224,7 +245,9 @@ async function handleEnable(row) {
 watchEffect(() => {
   if (userId) {
     modalForm.value.userId = userId
-    modalForm.value.parentId = detail.value.id
+    if (modalForm.value.level !== 0) {
+      modalForm.value.parentId = detail.value.id
+    }
   }
 })
 onMounted(() => {
@@ -276,6 +299,24 @@ function handleCoverRemove() {
   previewImageUrl.value = ''
 }
 
+function handleSubAdd() {
+  modalForm.value.level = 1
+  handleAdd({ level: 1 })
+}
+
+function handleTopMenuEdit() {
+  modalForm.value = {
+    cover: '',
+    ...detail.value,
+    userId,
+    level: 0,
+    parentId: null,
+  }
+  handleEdit(modalForm.value, '编辑顶层菜单', () => {
+    getMenuDetail()
+  })
+}
+
 const allCategory = ref([])
 categoryApi.getAll().then(({ data = [] }) => (allCategory.value = data.map(item => ({ label: item.title, value: item.id }))))
 </script>