Bläddra i källkod

feat: 后台管理增加咨询管理

IlhamTahir 1 år sedan
förälder
incheckning
b0dbad17fe

+ 2 - 1
components.d.ts

@@ -18,6 +18,7 @@ declare module 'vue' {
     TAvatar: typeof import('tdesign-vue-next')['Avatar']
     TButton: typeof import('tdesign-vue-next')['Button']
     TCard: typeof import('tdesign-vue-next')['Card']
+    TCol: typeof import('tdesign-vue-next')['Col']
     TDialog: typeof import('tdesign-vue-next')['Dialog']
     TDropdown: typeof import('tdesign-vue-next')['Dropdown']
     TForm: typeof import('tdesign-vue-next')['Form']
@@ -33,8 +34,8 @@ declare module 'vue' {
     TPopconfirm: typeof import('tdesign-vue-next')['Popconfirm']
     TRadioButton: typeof import('tdesign-vue-next')['RadioButton']
     TRadioGroup: typeof import('tdesign-vue-next')['RadioGroup']
+    TRow: typeof import('tdesign-vue-next')['Row']
     TSelect: typeof import('tdesign-vue-next')['Select']
-    TSelectInput: typeof import('tdesign-vue-next')['SelectInput']
     TSpace: typeof import('tdesign-vue-next')['Space']
     TTable: typeof import('tdesign-vue-next')['Table']
     TTag: typeof import('tdesign-vue-next')['Tag']

+ 17 - 23
src/components/ImageUpload.vue

@@ -9,7 +9,7 @@ const sizeLimit = ref<UploadProps['sizeLimit']>({
   size: 2,
   unit: 'MB',
 });
-const file1 = ref<UploadProps['value']>([]);
+const fileList = ref<UploadProps['value']>([]);
 const disabled = ref<boolean>(false);
 const autoUpload = ref<boolean>(true);
 const showImageFileName = ref<boolean>(true);
@@ -19,8 +19,7 @@ const handleFail: UploadProps['onFail'] = ({ file }) => {
 };
 const handleSuccess: UploadProps['onSuccess'] = ({ file }) => {
   if(file?.url){
-    console.log(file1.value,'file1')
-    emits('on-success',file.url)
+    emits('update:modelValue',file.url)
   }
 }
 const appStore = useAppStore()
@@ -28,35 +27,33 @@ const appStore = useAppStore()
 const uploadHeaders = ref<UploadProps['headers']>({
   Authorization: `Bearer ${appStore.token}`
 })
-const props = defineProps({
-  imageUrl:{
-    type:Object,
-    default:() => {
-      return { url: '' }
-    }
-  }
+
+
+const props = withDefaults(defineProps<{
+  modelValue: string
+}>(), {
+  modelValue: ''
 })
 
-const emits = defineEmits(['on-success'])
-watch(() => props.imageUrl,(newVal) => {
+
+const emits = defineEmits<{
+  'update:modelValue': [string]
+}>()
+watch(() => props.modelValue,(newVal) => {
   if (!newVal) return
-  if (newVal.url !== '') {
-    file1.value = [{...newVal}]
-  } else {
-    file1.value = []
-  }
+  fileList.value = [{url: newVal}]
 
 },{
   deep:true,
   immediate:true
 })
+
 </script>
 
 <template>
   <div>
     <t-upload
-      ref="uploadRef1"
-      v-model="file1"
+      v-model="fileList"
       :image-viewer-props="imageViewerProps"
       :size-limit="sizeLimit"
       action="/api/files/upload"
@@ -76,10 +73,7 @@ watch(() => props.imageUrl,(newVal) => {
       @fail="handleFail"
       @success="handleSuccess"
     >
-      <!-- custom UI -->
-      <!-- <template #fileListDisplay="{ files }">
-        <div>{{ JSON.stringify(files) }}</div>
-      </template> -->
+
     </t-upload>
   </div>
 </template>

+ 1 - 2
src/layouts/components/UserArea.vue

@@ -2,9 +2,8 @@
 import { ChevronDownIcon } from 'tdesign-icons-vue-next'
 import type { DropdownOption } from 'tdesign-vue-next'
 import { useAppStore } from '@/stores/app'
-import type { User } from '@/models/user'
 const appStore = useAppStore()
-const currentUser: User = appStore.currentUser
+const currentUser = appStore.currentUser
 const options: DropdownOption[] = [
   {
     content: '退出登录',

+ 6 - 2
src/model/article.ts

@@ -2,8 +2,8 @@ import type { AuditBaseModel,Paging } from '@/model/base'
 import type { Category } from './category'
 
 export enum ArticleStatus {
-    Draft = 'draft',
-    Published = 'published',
+    DRAFT = 'draft',
+    PUBLISHED = 'published',
     Closed = 'closed'
 }
 
@@ -12,6 +12,8 @@ export interface Article extends AuditBaseModel{
   content:string
   category: Category
   status: ArticleStatus
+  thumbnail: string
+  description: string
 }
 
 
@@ -26,4 +28,6 @@ export interface CreateArticleRequest{
   categoryId: string
   title: string
   content: string
+  thumbnail: string
+  description:string
 }

+ 29 - 1
src/pages/article/components/ArticleDialog.vue

@@ -11,6 +11,7 @@ import { MessagePlugin } from 'tdesign-vue-next'
 import { updateArticle, createArticle } from '@/api/article'
 import { searchCategories } from '@/api/category'
 import Editor from '@/components/Editor.vue'
+import ImageUpload from '@/components/ImageUpload.vue'
 const props = defineProps<{
   headerTitle?: String | null
   article: Article | null
@@ -19,7 +20,7 @@ const props = defineProps<{
 const formRef = ref<FormInstanceFunctions | null>(null)
 const headerText = computed(() => `${props.article ? '编辑' : '创建'}${props.headerTitle || ''}`)
 const confirmBtnText = computed(() => (props.article ? '保存' : '确定'))
-const articleData = reactive<CreateArticleRequest>({ title: '', categoryId: '', content: ''})
+const articleData = reactive<CreateArticleRequest>({ title: '', categoryId: '', content: '', thumbnail: '', description: ''})
 
 const rules: FormRules<CreateArticleRequest> = {
   title: [
@@ -77,6 +78,26 @@ const rules: FormRules<CreateArticleRequest> = {
       type: 'error',
       trigger: 'blur'
     }
+  ],
+  thumbnail: [
+    {
+      required: true,
+      message: '请上传封面图',
+      type: 'error',
+      trigger: 'blur'
+    },
+    {
+      whitespace: true,
+      message: '请上传封面图'
+    }
+  ],
+  description: [
+    {
+      max: 500,
+      message: '描述不超过500字',
+      type: 'error',
+      trigger: 'blur'
+    }
   ]
 }
 watch(
@@ -85,6 +106,7 @@ watch(
     articleData.categoryId = newArticleData?.category.id || ''
     articleData.title = newArticleData?.title || ''
     articleData.content = newArticleData?.content || ''
+    articleData.thumbnail = newArticleData?.thumbnail || ''
   },
   { deep: true }
 )
@@ -143,6 +165,9 @@ fetchCategories('')
         <TFormItem label="咨询标题:" name="title" help="名称长度大于2个汉字,小于120个汉字">
           <t-input v-model.trim="articleData.title" clearable placeholder="请输入咨询标题" />
         </TFormItem>
+        <TFormItem label="咨询描述:" name="description" help="描述长度小于500字符">
+          <TTextarea v-model.trim="articleData.description" clearable placeholder="请输入咨询标题" :maxcharacter="500"/>
+        </TFormItem>
         <TFormItem label="咨询分类:" name="categoryId">
           <TSelect
             v-model="articleData.categoryId"
@@ -152,6 +177,9 @@ fetchCategories('')
             @search="fetchCategories"
           />
         </TFormItem>
+        <TFormItem label="轮播图:" name="thumbnail">
+          <ImageUpload v-model="articleData.thumbnail"/>
+        </TFormItem>
         <TFormItem label="内容:" name="content">
           <Editor v-model="articleData.content"></Editor>
         </TFormItem>

+ 0 - 1
tsconfig.node.json

@@ -11,7 +11,6 @@
     "composite": true,
     "noEmit": true,
     "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
-
     "module": "ESNext",
     "moduleResolution": "Bundler",
     "types": ["node"]