浏览代码

feat: save

gemercheung 7 月之前
父节点
当前提交
d22be690dc

+ 0 - 8
packages/backend/src/modules/auth/auth.module.ts

@@ -1,11 +1,3 @@
-/**********************************
- * @Author: Ronnie Zhang
- * @LastEditor: Ronnie Zhang
- * @LastEditTime: 2023/12/07 20:25:41
- * @Email: zclzone@outlook.com
- * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
- **********************************/
-
 import { Module } from '@nestjs/common';
 import { AuthService } from './auth.service';
 import { AuthController } from './auth.controller';

+ 2 - 23
packages/backend/src/modules/menu/dto.ts

@@ -10,6 +10,7 @@ import {
   IsString,
   Length,
 } from 'class-validator';
+import { User } from '../user/user.entity';
 
 export class CreateMenuDto {
   @ApiProperty()
@@ -74,29 +75,7 @@ export class QueryMenuDto extends GetMenuDto {
   parentId?: number;
 }
 
-export class UpdateMenuDto {
-  @ApiProperty()
-  @IsString()
-  @IsOptional()
-  @Length(1, 200, {
-    message: `用户名长度必须大于$constraint1到$constraint2之间,当前传递的值是$value`,
-  })
-  title?: string;
-
-  @ApiProperty({ required: false })
-  @IsBoolean()
-  @IsOptional()
-  enable?: boolean;
-
-  @ApiProperty({ required: false })
-  @IsOptional()
-  @IsNumber()
-  userId?: number;
-
-  @ApiProperty({ required: false })
-  @IsOptional()
-  @IsNumber()
-  categoryId?: number;
+export class UpdateMenuDto extends CreateMenuDto {
 }
 
 export class UploadCoverDto {

+ 5 - 1
packages/backend/src/modules/menu/menu.entity.ts

@@ -49,11 +49,15 @@ export class Menu {
   categoryId: number;
 
   @OneToOne(() => User, {
-    cascade: true,
+    createForeignKeyConstraints: false,
+    onDelete: 'CASCADE',
   })
   @JoinColumn()
   user: User;
 
+  @Column({ nullable: true })
+  userId: number;
+
   @CreateDateColumn()
   createTime: Date;
 

+ 0 - 8
packages/frontend/src/store/modules/permission.js

@@ -1,11 +1,3 @@
-/**********************************
- * @Author: Ronnie Zhang
- * @LastEditor: Ronnie Zhang
- * @LastEditTime: 2023/12/05 21:25:47
- * @Email: zclzone@outlook.com
- * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
- **********************************/
-
 import { isExternal } from '@/utils'
 import { hyphenate } from '@vueuse/core'
 import { defineStore } from 'pinia'

+ 2 - 3
packages/frontend/src/views/article/index.vue

@@ -14,11 +14,11 @@
         </n-input>
       </MeQueryItem>
       <MeQueryItem label="状态" :label-width="50">
-        <n-select
+        <n-select
           v-model:value="queryItems.enable" clearable :options="[
             { label: '启用', value: 1 },
             { label: '停用', value: 0 },
-          ]"
+          ]"
         />
       </MeQueryItem>
     </MeCrud>
@@ -151,7 +151,6 @@ function htmlspecialchars(str) {
 }
 
 function handleEdit(row) {
-  console.log('222')
   router.push(`/article/edit/${row.id}`)
 }
 </script>

+ 5 - 0
packages/frontend/src/views/menu/api.js

@@ -7,4 +7,9 @@ export default {
   delete: id => request.delete(`/menu/${id}`),
   getOne: id => request.get(`/menu/detail/${id}`),
   getLevel: id => request.get(`/menu/level/${id}`),
+  uploadImage: data => request.post('/menu/cover/upload', data, {
+    headers: {
+      'Content-Type': 'multipart/form-data',
+    },
+  }),
 }

+ 86 - 4
packages/frontend/src/views/menu/list.vue

@@ -34,10 +34,39 @@
         >
           <n-input v-model:value="modalForm.title" />
         </n-form-item>
-
-        <n-form-item label="备注" path="remark">
-          <n-input v-model:value="modalForm.remark" />
+        <n-form-item label="封面" path="cover">
+          <n-upload
+            :multiple="false"
+            :default-upload="true"
+            list-type="image-card"
+            :custom-request="uploadCover"
+            :max="1"
+            :default-file-list="previewFileList"
+            @preview="handlePreview"
+            @remove="handleCoverRemove"
+          />
+          <n-modal
+            v-model:show="showModal"
+            preset="card"
+            style="width: 600px"
+            title=""
+          >
+            <img :src="previewImageUrl" style="width: 100%">
+          </n-modal>
+        </n-form-item>
+        <n-form-item
+          label="分类" path="categoryId" :rule="{
+            required: false,
+            type: 'number',
+            trigger: ['change', 'blur'],
+            message: '请输入分类',
+          }"
+        >
+          <n-select
+            v-model:value="modalForm.categoryId" :options="allCategory" clearable filterable tag
+          />
         </n-form-item>
+
         <n-form-item label="是否显示" path="isPublish">
           <NSwitch v-model:value="modalForm.isPublish">
             <template #checked>
@@ -70,12 +99,18 @@ import { useUserStore } from '@/store/index.js'
 import { formatDateTime } from '@/utils'
 import { NButton, NSwitch } from 'naive-ui'
 import { useRoute, useRouter } from 'vue-router'
+import categoryApi from '../category/api'
 import api from './api.js'
 
 const $table = ref(null)
 
 const router = useRouter()
 const { userId } = useUserStore()
+
+const previewFileList = ref([])
+const showModal = ref(false)
+const previewImageUrl = ref('')
+
 const route = useRoute()
 const detail = ref({
   title: '',
@@ -146,7 +181,7 @@ const columns = [
             type: 'primary',
             style: 'margin-left: 12px;',
             disabled: row.code === 'SUPER_ADMIN',
-            onClick: () => handleEdit(row),
+            onClick: () => handleFormEdit(row),
           },
           {
             default: () => '编辑',
@@ -196,4 +231,51 @@ onMounted(() => {
   $table.value?.handleSearch()
   getMenuDetail()
 })
+
+async function uploadCover({ file }) {
+  const data = new FormData()
+  data.append('file', file.file)
+  const res = await api.uploadImage(data)
+  modalForm.value.cover = res.data
+  file.url = res.data
+  file.thumbnailUrl = res.data
+  previewFileList.value = [{
+    id: '0',
+    status: 'finished',
+    url: res.data,
+  }]
+}
+
+function handlePreview(file) {
+  const { url } = file
+  previewImageUrl.value = url
+  showModal.value = true
+}
+
+async function handleFormEdit(data = {}) {
+  modalForm.value = {
+    ...data,
+    userId,
+  }
+  console.log('handleFormEdit', modalForm.value)
+  if (modalForm.value.cover) {
+    previewFileList.value = [{
+      id: '0',
+      status: 'finished',
+      url: modalForm.value.cover,
+    }]
+  }
+  else {
+    previewFileList.value = []
+  }
+  handleEdit(data)
+}
+function handleCoverRemove() {
+  modalForm.value.cover = ''
+  previewFileList.value = []
+  previewImageUrl.value = ''
+}
+
+const allCategory = ref([])
+categoryApi.getAll().then(({ data = [] }) => (allCategory.value = data.map(item => ({ label: item.title, value: item.id }))))
 </script>