Procházet zdrojové kódy

fix: 将字典管理的文件上传接口统一用minio模块的

louhangfei před 11 měsíci
rodič
revize
0da7e23a35

+ 0 - 13
src/api/dict/index.ts

@@ -1,5 +1,4 @@
 import { http } from '@/utils/http/axios';
-import { InteractionFilled } from '@vicons/antd';
 
 export interface QueryDictPageParams {
   /*页号 */
@@ -278,15 +277,3 @@ export interface UpdateDictParams {
 export function updateDict(params: UpdateDictParams): Promise<null> {
   return http.request({ url: `/admin/dict/updateDict`, data: params, method: 'POST' });
 }
-
-export const uploadDictImage = (file: Blob, bizType: string) => {
-  const formData = new FormData();
-  formData.append('bizType', bizType);
-  formData.append('file', file);
-  return http.request({
-    url: `/admin/minio/uploadFile`,
-    method: 'post',
-    data: formData,
-    headers: { 'Content-Type': 'multipart/form-data' },
-  });
-};

+ 8 - 1
src/api/minio/index.ts

@@ -1,9 +1,16 @@
 import { http } from '@/utils/http/axios';
+
+// 上传文件的文件夹
+export enum UPLOAD_BIZ_TYPE {
+  ATTACHMENT = 'ATTACHMENT',
+  // 字典
+  DICTIONARY = 'DICTIONARY',
+}
 /**
  * 上传文件到MINIO
  */
 
-export const uploadFileApi = (data: { bizType: string; fileName: string; file: File }) => {
+export const uploadFileApi = (data: { bizType: UPLOAD_BIZ_TYPE; fileName: string; file: File }) => {
   const formData = new FormData();
   const { bizType, fileName, file } = data;
   formData.append('bizType', bizType);

+ 0 - 5
src/views/disaster/constant/index.ts

@@ -155,11 +155,6 @@ export const DISASTER_LEVEL = [
   },
 ];
 
-// 上传文件的文件夹
-export const BIZ_TYPE = {
-  ATTACHMENT: 'ATTACHMENT',
-};
-
 //管理权限
 export const DISASTER_PERMISSIONS = {
   WARNING_INFO: 'disaster_business_module:warn_info',

+ 2 - 3
src/views/disaster/disaster-warning/PageDefenseNoticeItem.vue

@@ -22,8 +22,7 @@
   import BackIcon from 'assets/svg/back.svg';
   import { ElMessage } from 'element-plus';
   import type { DefenseNoticeRuleForm } from './src/type';
-  import { uploadFileApi } from '@/api/minio';
-  import { BIZ_TYPE } from '@/views/disaster/constant';
+  import { uploadFileApi, UPLOAD_BIZ_TYPE } from '@/api/minio';
   import type { FileItem } from '@/views/disaster/types';
   import { createDefenseNoticeItem, editDefenseNoticeItem } from '@/api/disaster-warning/index';
   const router = useRouter();
@@ -53,7 +52,7 @@
   const formatAttachmentList = async (file: FileItem) => {
     if (!file.file) return file;
     const fileName = file.fileName;
-    const res = await uploadFileApi({ bizType: BIZ_TYPE.ATTACHMENT, fileName, file: file.file });
+    const res = await uploadFileApi({ bizType: UPLOAD_BIZ_TYPE.ATTACHMENT, fileName, file: file.file });
     const fileType = file.fileType;
     const fileSize = file.fileSize;
     const fileId = file.fileId;

+ 330 - 300
src/views/system/dictionary/components/AddDict.vue

@@ -11,8 +11,12 @@
 
       <el-form-item label="字典分类" prop="dictType">
         <el-select v-model="formData.dictType" placeholder="请选择">
-          <el-option v-for="(item, index) in dictionaryTypeOptions" :key="index" :label="item.label"
-            :value="item.value" />
+          <el-option
+            v-for="(item, index) in dictionaryTypeOptions"
+            :key="index"
+            :label="item.label"
+            :value="item.value"
+          />
         </el-select>
       </el-form-item>
       <div class="subDictWrapper">
@@ -28,39 +32,51 @@
                       <Top />
                     </el-icon>
                   </el-button>
-                  <el-button v-if="index < formData.sysDictDataList.length - 1" type="primary" link
-                    @click="moveDictItem(index, 'down')">
+                  <el-button
+                    v-if="index < formData.sysDictDataList.length - 1"
+                    type="primary"
+                    link
+                    @click="moveDictItem(index, 'down')"
+                  >
                     <el-icon>
                       <Bottom />
                     </el-icon>
                   </el-button>
-                  <el-button v-if="formData.sysDictDataList.length > 1" type="danger" link
-                    @click="removeDictItem(index)">
-                    <el-icon>
-                      <Delete />
-                    </el-icon>删除
+                  <el-button
+                    v-if="formData.sysDictDataList.length > 1"
+                    type="danger"
+                    link
+                    @click="removeDictItem(index)"
+                  >
+                    <el-icon> <Delete /> </el-icon>删除
                   </el-button>
                 </div>
               </div>
 
-              <el-form-item :label="`字典项值`" :prop="`sysDictDataList.${index}.itemValue`"
-                :rules="[{ required: true, message: '请输入字典项值', trigger: 'blur' }]">
+              <el-form-item
+                :label="`字典项值`"
+                :prop="`sysDictDataList.${index}.itemValue`"
+                :rules="[{ required: true, message: '请输入字典项值', trigger: 'blur' }]"
+              >
                 <el-input v-model="item.itemValue" placeholder="请输入" />
               </el-form-item>
-              <el-form-item :label="`字典项编码`" :prop="`sysDictDataList.${index}.itemCode`"
-                :rules="[{ required: true, message: '请输入字典项编码', trigger: 'blur' }]">
+              <el-form-item
+                :label="`字典项编码`"
+                :prop="`sysDictDataList.${index}.itemCode`"
+                :rules="[{ required: true, message: '请输入字典项编码', trigger: 'blur' }]"
+              >
                 <el-input v-model="item.itemCode" placeholder="请输入" />
               </el-form-item>
               <el-form-item label="图标">
                 <el-upload
-                   v-model:file-list="item.fileList"
+                  v-model:file-list="item.fileList"
                   :auto-upload="false"
-                  :action="actionUrl" 
-                  list-type="picture-card" 
+                  list-type="picture-card"
                   :limit="1"
-                  :on-preview="(file) => handlePictureCardPreview(file, index)" :on-remove="() => handleRemove(index)"
-                  :on-change="(file, fileList) => handleChange(file, fileList, index)"
-                  >
+                  :on-preview="(file) => handlePictureCardPreview(file, index)"
+                  :on-remove="() => handleRemove(index)"
+                  :on-change="(file) => handleChange(file, index)"
+                >
                   <el-icon>
                     <Plus />
                   </el-icon>
@@ -75,19 +91,27 @@
         <el-button type="primary" link @click="addDictItem">
           <el-icon>
             <CirclePlus />
-          </el-icon> 新增字典分类
+          </el-icon>
+          新增字典分类
         </el-button>
       </el-form-item>
 
       <el-form-item label="字典描述" prop="description">
-        <el-input v-model="formData.description" type="textarea" :rows="3" placeholder="请描述灾害处置过程, 不超过1000字"
-          maxlength="1000" show-word-limit />
+        <el-input
+          v-model="formData.description"
+          type="textarea"
+          :rows="3"
+          placeholder="请描述灾害处置过程, 不超过1000字"
+          maxlength="1000"
+          show-word-limit
+        />
       </el-form-item>
 
       <el-form-item label="状态" prop="status">
         <el-radio-group v-model="formData.status">
-          <el-radio-button v-for="item in dictionaryStatusOptions" :key="item.value" :value="item.value">{{ item.label
-            }}</el-radio-button>
+          <el-radio-button v-for="item in dictionaryStatusOptions" :key="item.value" :value="item.value">{{
+            item.label
+          }}</el-radio-button>
         </el-radio-group>
       </el-form-item>
 
@@ -106,214 +130,76 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, reactive, PropType, watch, computed } from 'vue';
-import {
-  ElForm,
-  ElFormItem,
-  ElInput,
-  ElSelect,
-  ElOption,
-  ElButton,
-  ElRadioGroup,
-  ElRadioButton,
-  ElInputNumber,
-  ElUpload,
-  ElIcon,
-  ElDialog,
-  ElDivider,
-  FormInstance,
-  FormRules,
-  UploadProps,
-  UploadUserFile,
-} from 'element-plus';
-import { Plus, Delete, CirclePlus, Minus, Picture, Top, Bottom } from '@element-plus/icons-vue';
-import { dictionaryTypeOptions, DictionaryStatus, dictionaryStatusOptions } from '../constants';
-import { queryDictTypeDetail, uploadDictImage } from '@/api/dict'
-import { getHeaders } from '@/utils/http/axios';
-import { useGlobSetting } from '@/hooks/setting';
-import urlJoin from 'url-join';
-
-interface SysDictDataItem {
-  id?: string | number; // 可选,用于编辑时
-  dictId: string | number | undefined; // 关联的字典ID
-  dictCode: string;
-  itemValue: string;
-  itemCode: string;
-  itemSort: number | undefined;
-  isDefault: 0 | 1,
-  imageUrl?: string; // 用于显示已上传的图片
-  status: DictionaryStatus.disabled | DictionaryStatus.enabled;
-}
-
-interface FormData {
-  dictId?: string | number; // 可选,用于编辑时
-  dictName: string;
-  dictCode: string;
-  dictType: string;
-  sysDictDataList: SysDictDataItem[];
-  description: string;
-  status: DictionaryStatus.disabled | DictionaryStatus.enabled;
-}
-
-const props = defineProps({
-  dictCode: {
-    type: String,
-    default: '',
+  import { ref, reactive, watch } from 'vue';
+  import {
+    ElForm,
+    ElFormItem,
+    ElInput,
+    ElSelect,
+    ElOption,
+    ElButton,
+    ElRadioGroup,
+    ElRadioButton,
+    ElUpload,
+    ElIcon,
+    ElDialog,
+    FormInstance,
+    FormRules,
+    UploadProps,
+    UploadUserFile,
+  } from 'element-plus';
+  import { Plus, Delete, CirclePlus, Top, Bottom } from '@element-plus/icons-vue';
+  import { dictionaryTypeOptions, DictionaryStatus, dictionaryStatusOptions } from '../constants';
+  import { queryDictTypeDetail } from '@/api/dict';
+  import { uploadFileApi, UPLOAD_BIZ_TYPE } from '@/api/minio';
+  import { cloneDeep } from 'lodash-es';
+
+  interface SysDictDataItem {
+    id?: string | number; // 可选,用于编辑时
+    dictId: string | number | undefined; // 关联的字典ID
+    dictCode: string;
+    itemValue: string;
+    itemCode: string;
+    itemSort: number | undefined;
+    isDefault: 0 | 1;
+    imageUrl?: string; // 用于显示已上传的图片
+    status: DictionaryStatus.disabled | DictionaryStatus.enabled;
+    fileList?: FileListItem[]; // 用于图片上传;
   }
-});
-
-const { urlPrefix } = useGlobSetting();
-const actionUrl = computed(() => {
-  return urlJoin(urlPrefix!, `/admin/minio/uploadFile`);
-});
-
-const emit = defineEmits(['submit', 'close']);
-const handleClose = () => {
-  emit('close');
-};
-
-const formRef = ref<FormInstance>();
-const formData = reactive<FormData>({
-  dictName: '',
-  dictCode: '',
-  dictType: '',
-  sysDictDataList: [
-    {
-      id: undefined,
-      dictId: undefined,
-      dictCode: '',
-      itemCode: '',
-      itemValue: '',
-      itemSort: 1, // 默认排序值
-      isDefault: 0,
-      status: DictionaryStatus.disabled,
-      imageUrl: '',
-    },
-  ],
-  description: '',
-  status: DictionaryStatus.disabled,
-});
-
-watch(() => props.dictCode, async (newCode) => {
-  if (!newCode) return;
-  
-  const res = await queryDictTypeDetail(newCode);
-  
-  // 处理字典项数据转换
-  const processDictItem = (item: any) => ({
-    ...item,
-    fileList: item.imageUrl ? [{
-      name: item.imageUrl.split('/').pop() || '',
-      url: item.imageUrl
-    }] : []
-  });
-
-  Object.assign(formData, {
-    ...res,
-    sysDictDataList: res.sysDictDataList?.map(processDictItem) ?? []
-  });
- 
-}, { immediate: true });
-
-const formRules = reactive<FormRules<FormData>>({
-  dictName: [{ required: true, message: '请选择字典名称', trigger: 'change' }],
-  dictCode: [{ required: true, message: '请选择字典编码', trigger: 'change' }],
-  dictType: [{ required: true, message: '请选择字典分类', trigger: 'change' }],
-  description: [{ max: 1000, message: '描述不超过1000字', trigger: 'blur' }],
-  status: [{ required: true, message: '请选择状态', trigger: 'change' }],
-});
-
-const addDictItem = () => {
-  formData.sysDictDataList.push({
-    id: undefined,
-    dictId: formData.dictId,
-    dictCode: formData.dictCode,
-    itemCode: '',
-    itemValue: '',
-    itemSort: 1, // 默认排序值
-    isDefault: 0,
-    status: DictionaryStatus.disabled,
-    imageUrl: '',
-  },
-  );
-};
-
-const removeDictItem = (index: number) => {
-  formData.sysDictDataList.splice(index, 1);
-};
-
-// 图片上传相关
-const dialogImageUrl = ref('');
-const dialogVisible = ref(false);
 
-const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
-  dialogImageUrl.value = uploadFile.url!;
-  dialogVisible.value = true;
-};
-
-const handleRemove = (itemIndex: number) => {
-  if (formData.sysDictDataList[itemIndex]) {
-    formData.sysDictDataList[itemIndex].imageUrl = ''; // 如果有单独的 URL 字段
-  }
-};
-
-const handleChange = (uploadFile: UploadUserFile, uploadFiles: UploadUserFile[], itemIndex: number) => {
-  // Element Plus 的 onChange 会在文件状态改变时触发多次,通常在 ready 状态时文件已可选
-  // 这里简单地将文件对象存起来,实际上传应在 handleSubmit 中处理
-  if (formData.sysDictDataList[itemIndex]) {
-    if (!uploadFile.raw) return;
-    uploadDictImage(uploadFile.raw, 'DICTIONARY').then((res) => {
-      formData.sysDictDataList[itemIndex].imageUrl = res.url;
-    })
+  interface FileListItem {
+    name: string;
+    url: string;
   }
-};
-
-const handleSubmit = async () => {
-  if (!formRef.value) return;
-
-  await formRef.value.validate((valid: boolean ) => {
-    if (valid) {
-      formData.sysDictDataList.forEach(item => {
-        item.dictCode = formData.dictCode;
-        if(item.fileList && item.fileList.length > 0) {
-          delete item.fileList;
-        }
-      });
-      
-      emit('submit', JSON.parse(JSON.stringify(formData))); // 暂时发送原始数据,上传需单独处理
-    } else {
 
-      return false;
-    }
-  });
-};
-
-// 移动方法
-const moveDictItem = (index: number, direction: 'up' | 'down') => {
-  const items = formData.sysDictDataList;
-  if (direction === 'up' && index > 0) {
-    // 交换位置
-    [items[index - 1], items[index]] = [items[index], items[index - 1]];
-  } else if (direction === 'down' && index < items.length - 1) {
-    // 交换位置
-    [items[index + 1], items[index]] = [items[index], items[index + 1]];
+  interface FormData {
+    dictId?: string | number; // 可选,用于编辑时
+    dictName: string;
+    dictCode: string;
+    dictType: string;
+    sysDictDataList: SysDictDataItem[];
+    description: string;
+    status: DictionaryStatus.disabled | DictionaryStatus.enabled;
   }
-  
-  // 根据最新位置重新设置排序值
-  items.forEach((item, idx) => {
-    item.itemSort = idx + 1;
+
+  const props = defineProps({
+    dictCode: {
+      type: String,
+      default: '',
+    },
   });
-};
-              
-const handleCancel = () => {
-  emit('close');
-};
-
-// 暴露方法给父组件,例如重置表单
-defineExpose({
-  resetForm: () => {
-    formRef.value?.resetFields();
-    formData.sysDictDataList = [
+
+  const emit = defineEmits(['submit', 'close']);
+  const handleClose = () => {
+    emit('close');
+  };
+
+  const formRef = ref<FormInstance>();
+  const formData = reactive<FormData>({
+    dictName: '',
+    dictCode: '',
+    dictType: '',
+    sysDictDataList: [
       {
         id: undefined,
         dictId: undefined,
@@ -325,28 +211,218 @@ defineExpose({
         status: DictionaryStatus.disabled,
         imageUrl: '',
       },
-    ];
-    
-  },
-  getFormData: () => formData, // 允许父组件获取当前表单数据
-});
+    ],
+    description: '',
+    status: DictionaryStatus.disabled,
+  });
+
+  watch(
+    () => props.dictCode,
+    async (newCode) => {
+      if (!newCode) return;
+
+      const res = await queryDictTypeDetail(newCode);
+
+      // 处理字典项数据转换
+      const processDictItem = (item: any) => ({
+        ...item,
+        fileList: item.imageUrl
+          ? [
+              {
+                name: item.imageUrl.split('/').pop() || '',
+                url: item.imageUrl,
+              },
+            ]
+          : [],
+      });
+
+      Object.assign(formData, {
+        ...res,
+        sysDictDataList: res.sysDictDataList?.map(processDictItem) ?? [],
+      });
+    },
+    { immediate: true },
+  );
+
+  const formRules = reactive<FormRules<FormData>>({
+    dictName: [{ required: true, message: '请选择字典名称', trigger: 'change' }],
+    dictCode: [{ required: true, message: '请选择字典编码', trigger: 'change' }],
+    dictType: [{ required: true, message: '请选择字典分类', trigger: 'change' }],
+    description: [{ max: 1000, message: '描述不超过1000字', trigger: 'blur' }],
+    status: [{ required: true, message: '请选择状态', trigger: 'change' }],
+  });
+
+  const addDictItem = () => {
+    formData.sysDictDataList.push({
+      id: undefined,
+      dictId: formData.dictId,
+      dictCode: formData.dictCode,
+      itemCode: '',
+      itemValue: '',
+      itemSort: 1, // 默认排序值
+      isDefault: 0,
+      status: DictionaryStatus.disabled,
+      imageUrl: '',
+    });
+  };
+
+  const removeDictItem = (index: number) => {
+    formData.sysDictDataList.splice(index, 1);
+  };
+
+  // 图片上传相关
+  const dialogImageUrl = ref('');
+  const dialogVisible = ref(false);
+
+  const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
+    dialogImageUrl.value = uploadFile.url!;
+    dialogVisible.value = true;
+  };
+
+  const handleRemove = (itemIndex: number) => {
+    if (formData.sysDictDataList[itemIndex]) {
+      formData.sysDictDataList[itemIndex].imageUrl = ''; // 如果有单独的 URL 字段
+    }
+  };
+
+  const handleChange = (uploadFile: UploadUserFile, itemIndex: number) => {
+    // Element Plus 的 onChange 会在文件状态改变时触发多次,通常在 ready 状态时文件已可选
+    // 这里简单地将文件对象存起来,实际上传应在 handleSubmit 中处理
+    if (formData.sysDictDataList[itemIndex]) {
+      if (!uploadFile.raw) return;
+
+      uploadFileApi({
+        file: uploadFile.raw,
+        bizType: UPLOAD_BIZ_TYPE['DICTIONARY'],
+        fileName: uploadFile.raw.name,
+      }).then((res) => {
+        formData.sysDictDataList[itemIndex].imageUrl = res.url;
+      });
+    }
+  };
+
+  const handleSubmit = async () => {
+    if (!formRef.value) return;
+
+    await formRef.value.validate((valid: boolean) => {
+      if (valid) {
+        const cloneFormData = cloneDeep(formData) as FormData;
+        const submitDictDataList = cloneFormData.sysDictDataList.map((item) => {
+          // eslint-disable-next-line @typescript-eslint/no-unused-vars
+          const { fileList, ...rest } = item;
+          item.dictCode = formData.dictCode;
+          return rest;
+        });
+        cloneFormData.sysDictDataList = submitDictDataList;
+
+        emit('submit', JSON.parse(JSON.stringify(cloneFormData))); // 暂时发送原始数据,上传需单独处理
+      }
+    });
+  };
+
+  // 移动方法
+  const moveDictItem = (index: number, direction: 'up' | 'down') => {
+    const items = formData.sysDictDataList;
+    if (direction === 'up' && index > 0) {
+      // 交换位置
+      [items[index - 1], items[index]] = [items[index], items[index - 1]];
+    } else if (direction === 'down' && index < items.length - 1) {
+      // 交换位置
+      [items[index + 1], items[index]] = [items[index], items[index + 1]];
+    }
+
+    // 根据最新位置重新设置排序值
+    items.forEach((item, idx) => {
+      item.itemSort = idx + 1;
+    });
+  };
+
+  const handleCancel = () => {
+    emit('close');
+  };
+
+  // 暴露方法给父组件,例如重置表单
+  defineExpose({
+    resetForm: () => {
+      formRef.value?.resetFields();
+      formData.sysDictDataList = [
+        {
+          id: undefined,
+          dictId: undefined,
+          dictCode: '',
+          itemCode: '',
+          itemValue: '',
+          itemSort: 1, // 默认排序值
+          isDefault: 0,
+          status: DictionaryStatus.disabled,
+          imageUrl: '',
+        },
+      ];
+    },
+    getFormData: () => formData, // 允许父组件获取当前表单数据
+  });
 </script>
 
 <style lang="scss" scoped>
-.add-dict-form {
+  .add-dict-form {
+    .el-select,
+    .el-input-number {
+      width: 100%;
+    }
+  }
 
-  .el-select,
-  .el-input-number {
-    width: 100%;
+  .dict-item-group {
+    padding: 15px;
+    border: 1px solid #dcdfe6;
+    border-radius: 4px;
+    margin-bottom: 20px;
+    position: relative;
+
+    .dict-item-header {
+      display: flex;
+      justify-content: flex-end;
+      align-items: center;
+      margin-bottom: 10px;
+
+      h4 {
+        margin: 0;
+        font-size: 16px;
+      }
+    }
   }
-}
 
-.dict-item-group {
-  padding: 15px;
-  border: 1px solid #dcdfe6;
-  border-radius: 4px;
-  margin-bottom: 20px;
-  position: relative;
+  .form-footer {
+    text-align: right;
+    margin-top: 20px;
+  }
+
+  // 覆盖 el-upload 的样式,使其适应小图标场景
+  :deep(.el-upload--picture-card) {
+    width: 100px;
+    height: 100px;
+    line-height: 110px;
+  }
+
+  :deep(.el-upload-list--picture-card .el-upload-list__item) {
+    width: 100px;
+    height: 100px;
+  }
+
+  .subDictWrapper {
+    display: flex;
+
+    .dictItemsLabel {
+      width: 30%;
+      font-size: 14px;
+      color: #606266;
+      text-align: right;
+      margin-right: 26px;
+    }
+
+    .subDictList {
+      flex: 1;
+    }
+  }
 
   .dict-item-header {
     display: flex;
@@ -354,68 +430,22 @@ defineExpose({
     align-items: center;
     margin-bottom: 10px;
 
-    h4 {
-      margin: 0;
-      font-size: 16px;
-    }
-  }
-}
-
-.form-footer {
-  text-align: right;
-  margin-top: 20px;
-}
-
-// 覆盖 el-upload 的样式,使其适应小图标场景
-:deep(.el-upload--picture-card) {
-  width: 100px;
-  height: 100px;
-  line-height: 110px;
-}
-
-:deep(.el-upload-list--picture-card .el-upload-list__item) {
-  width: 100px;
-  height: 100px;
-}
-
-.subDictWrapper {
-  display: flex;
-
-  .dictItemsLabel {
-    width: 30%;
-    font-size: 14px;
-    color: #606266;
-    text-align: right;
-    margin-right: 26px;
-  }
-
-  .subDictList {
-    flex: 1;
-  }
-}
-
-.dict-item-header {
-  display: flex;
-  justify-content: flex-end;
-  align-items: center;
-  margin-bottom: 10px;
-  
-  .move-buttons {
-    margin-right: auto;
-    .el-button {
-      padding: 5px;
-      margin-right: 8px;
+    .move-buttons {
+      margin-right: auto;
+      .el-button {
+        padding: 5px;
+        margin-right: 8px;
+      }
     }
   }
-}
-
-.dialog-content {
-  width: 100%;
-  height: 100%;
 
-  img {
+  .dialog-content {
     width: 100%;
     height: 100%;
+
+    img {
+      width: 100%;
+      height: 100%;
+    }
   }
-}
 </style>