Explorar o código

基础组件修改

zq hai 1 ano
pai
achega
7335778e36

+ 5 - 1
src/api/book.js

@@ -114,6 +114,7 @@ export function GetCoursewareList_Chapter(data) {
  * 保存互动课件内容
  */
 export function SaveCoursewareContent(data) {
+  console.log(data);
   return http.post(`${process.env.VUE_APP_BookWebSI}?MethodName=book-courseware_manager-SaveCoursewareContent`, data);
 }
 
@@ -148,5 +149,8 @@ export function GetCoursewareComponentContent(data) {
  * 得到互动课件组件内容(展示内容)
  */
 export function GetCoursewareComponentContent_View(data) {
-  return http.post(`book-courseware_manager-GetCoursewareComponentContent_View`, data);
+  return http.post(
+    `${process.env.VUE_APP_BookWebSI}?MethodName=book-courseware_manager-GetCoursewareComponentContent_View`,
+    data,
+  );
 }

+ 3 - 0
src/icons/svg/components/1x.svg

@@ -0,0 +1,3 @@
+<svg width="19" height="15" viewBox="0 0 19 15" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4.6 0.719999H5.88V15H4.24V2.72C3.34 3.64 2.22 4.28 0.88 4.68V3.04C1.52 2.86 2.2 2.58 2.88 2.18C3.56 1.74 4.12 1.26 4.6 0.719999ZM8.56734 4.66H10.4473L13.1273 8.34L15.7873 4.66H17.6673L14.0073 9.52L18.1073 15H16.2073L13.1273 10.7L10.0273 15H8.12734L12.2273 9.52L8.56734 4.66Z" fill="black"/>
+</svg>

+ 3 - 0
src/icons/svg/components/next.svg

@@ -0,0 +1,3 @@
+<svg width="21" height="22" viewBox="0 0 21 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8.80975 11.0015L0.821533 18.9896L3.17855 21.3466L13.5237 11.0015L3.17855 0.65625L0.821533 3.01327L8.80975 11.0015ZM20.3334 1.00143V21.0015H17.0001V1.00143H20.3334Z" fill="black"/>
+</svg>

+ 3 - 0
src/icons/svg/components/paused.svg

@@ -0,0 +1,3 @@
+<svg width="12" height="16" viewBox="0 0 12 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M11.376 8.41531L0.77735 15.4811C0.54759 15.6343 0.23715 15.5722 0.0839701 15.3424C0.0292201 15.2603 0 15.1638 0 15.0651V0.933594C0 0.657454 0.22386 0.433594 0.5 0.433594C0.59871 0.433594 0.69522 0.462814 0.77735 0.517574L11.376 7.58331C11.6057 7.73651 11.6678 8.04691 11.5146 8.27671C11.478 8.33161 11.4309 8.37871 11.376 8.41531Z" fill="black"/>
+</svg>

+ 3 - 0
src/icons/svg/components/playing.svg

@@ -0,0 +1,3 @@
+<svg width="40" height="48" viewBox="0 0 40 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0 0.667969H6.66667V47.3346H0V0.667969ZM33.3333 0.667969H40V47.3346H33.3333V0.667969Z" fill="black"/>
+</svg>

+ 3 - 0
src/icons/svg/components/pre.svg

@@ -0,0 +1,3 @@
+<svg width="21" height="22" viewBox="0 0 21 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12.1904 11.0015L20.1786 3.01327L17.8216 0.65625L7.47641 11.0015L17.8216 21.3466L20.1786 18.9896L12.1904 11.0015ZM0.666748 21.0015V1.00143H4.00008V21.0015H0.666748Z" fill="black"/>
+</svg>

+ 3 - 0
src/icons/svg/components/quit.svg

@@ -0,0 +1,3 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M6.05759 7.00138L0.862305 1.80609L1.80511 0.863281L7.00039 6.05851L12.1957 0.863281L13.1385 1.80609L7.94319 7.00138L13.1385 12.1966L12.1957 13.1394L7.00039 7.94418L1.80511 13.1394L0.862305 12.1966L6.05759 7.00138Z" fill="black"/>
+</svg>

+ 10 - 4
src/views/book/courseware/create/components/base/audio/Audio.vue

@@ -2,12 +2,14 @@
   <ModuleBase :type="data.type">
     <template #content>
       <UploadFile
-        :id="data.id"
+        :courseware-id="courseware_id"
+        :component-id="id"
         :module-data="data"
         :label-text="labelText"
         :accept-file-type="acceptFileType"
         :upload-tip="uploadTip"
         :icon-class="iconClass"
+        @saveDate="saveDate"
       />
     </template>
   </ModuleBase>
@@ -25,15 +27,19 @@ export default {
   data() {
     return {
       data: getAudioData(),
-      file_list: [],
       labelText: '音频',
       acceptFileType: '.mp3,.acc,.wma',
       uploadTip: '支持上传mp3、acc、wma,等格式音频文件,单个文件最大100MB,总文件体积不超1G。',
       iconClass: 'note',
     };
   },
-  computed: {},
-  methods: {},
+  methods: {
+    saveDate(file) {
+      this.data.id = this.id;
+      this.data.file_list.push(file);
+      this.data.file_id_list.push(file.file_id);
+    },
+  },
 };
 </script>
 

+ 31 - 4
src/views/book/courseware/create/components/base/common/UploadFile.vue

@@ -28,7 +28,7 @@
             <span>{{ file.file_name ?? file.name }}</span>
             <!-- <span>({{ file.size }})</span> -->
           </span>
-          <span v-show="file.progress > 0 && file.progress < 100"> {{ file.progress }}% </span>
+          <span v-show="file.progress > 0"> {{ file.progress }}% </span>
           <span v-show="file.file_id"> 完成 </span>
         </div>
         <SvgIcon icon-class="delete-black" size="12" @click="removeFile(file, i)" />
@@ -44,6 +44,7 @@
 import { fileUpload } from '@/api/app';
 import { conversionSize } from '@/utils/common';
 import FillDescribe from '../../common/FillDescribe';
+import { GetCoursewareComponentContent_View } from '@/api/book';
 
 export default {
   name: 'UploadFile',
@@ -51,6 +52,16 @@ export default {
     FillDescribe,
   },
   props: {
+    // 课件id
+    coursewareId: {
+      type: String,
+      default: '',
+    },
+    // 组件id
+    componentId: {
+      type: String,
+      default: '',
+    },
     // 组件标签
     labelText: {
       type: String,
@@ -87,17 +98,28 @@ export default {
   },
   computed: {},
   watch: {},
+  created() {
+    this.getCoursewareComponentContent_View();
+  },
   methods: {
+    // 获取数据
+    getCoursewareComponentContent_View() {
+      GetCoursewareComponentContent_View({ courseware_id: this.coursewareId, component_id: this.componentId }).then(
+        ({ content }) => {
+          if (content) this.file_list = JSON.parse(content).file_list;
+        },
+      );
+    },
+
     // 显示自定义样式文件列表
     onFileChange(file, fileList) {
       this.afterSelectFile(file);
-      console.log(123);
       fileList.forEach((file) => {
         if (!file.progress || file.progress <= 0) file.progress = 0;
         if (!file.title) file.title = '';
         if (!file.describe) file.describe = '';
       });
-      this.file_list = fileList;
+      this.file_list.push(file);
     },
 
     // 删除文件
@@ -158,7 +180,7 @@ export default {
       }
       const totalSize = files.reduce((sum, cur) => sum + Number(cur.size || 0), 0);
       if (totalSize > this.moduleData.total_size * 1024 * 1024) {
-        this.$message.error(`文件总大小不能超过${conversionSize(this.moduleData.total_size)}`);
+        this.$message.error(`文件总大小不能超过${conversionSize(this.moduleData.total_size)}!`);
         return false;
       }
 
@@ -179,6 +201,7 @@ export default {
           if (file_index > -1) {
             this.file_list[file_index] = file_info_list[0];
             this.file_id_list.push(file_info_list[0].file_id);
+            this.$emit('saveDate', file_info_list[0]);
           }
         });
       });
@@ -255,6 +278,10 @@ export default {
     }
   }
 
+  .old_file_list {
+    margin-top: 16px;
+  }
+
   .file-list {
     display: flex;
     flex-direction: column;

+ 11 - 3
src/views/book/courseware/create/components/base/picture/Picture.vue

@@ -2,12 +2,14 @@
   <ModuleBase :type="data.type">
     <template #content>
       <UploadFile
-        id="PictureUploadPage"
+        :courseware-id="courseware_id"
+        :component-id="id"
         :module-data="data"
         :label-text="labelText"
         :accept-file-type="acceptFileType"
         :upload-tip="uploadTip"
         :icon-class="iconClass"
+        @saveDate="saveDate"
       />
     </template>
   </ModuleBase>
@@ -25,7 +27,6 @@ export default {
   data() {
     return {
       data: getPictureData(),
-      file_info_list: [],
       labelText: '图片',
       acceptFileType: '.jpg,.png,.jpeg',
       uploadTip: '支持上传jpg、png、jpeg,等格式图片文件,单个文件最大1MB,总文件体积不超100MB。',
@@ -33,7 +34,14 @@ export default {
     };
   },
   computed: {},
-  methods: {},
+  methods: {
+    saveDate(file) {
+      console.log('图片', this.data);
+      this.data.id = this.id;
+      this.data.file_list.push(file);
+      this.data.file_id_list.push(file.file_id);
+    },
+  },
 };
 </script>
 

+ 18 - 13
src/views/book/courseware/create/components/base/picture/PictureSetting.vue

@@ -3,7 +3,7 @@
     <el-form :model="property" :label-position="labelPosition" label-width="72px">
       <el-form-item label="序号" class="serial-number">
         <el-input v-model="property.serial_number" />
-        <SvgIcon icon-class="switch" size="14" />
+        <SvgIcon icon-class="switch" size="14" @click="switchSerialNumber(property)" />
       </el-form-item>
       <el-form-item>
         <el-radio
@@ -78,12 +78,7 @@
       </el-form-item>
       <el-divider />
       <el-form-item label="查看方式">
-        <el-radio
-          v-for="{ value, label } in viewMethodList"
-          :key="value"
-          v-model="property.view_method"
-          :label="value"
-        >
+        <el-radio v-for="{ value, label } in viewMethodList" :key="value" v-model="property.view_method" :label="value">
           {{ label }}
         </el-radio>
       </el-form-item>
@@ -92,18 +87,27 @@
 </template>
 
 <script>
-import { snGenerationMethodList, viewMethodList } from '@/views/book/courseware/data/common';
+import SettingMixin from '@/views/book/courseware/create/components/common/SettingMixin';
+import {
+  snGenerationMethodList,
+  viewMethodList,
+  switchSerialNumber,
+  checkString,
+} from '@/views/book/courseware/data/common';
 
 export default {
-  name: 'AudioSetting',
+  name: 'PictureSetting',
+  mixins: [SettingMixin],
   data() {
     return {
+      switchSerialNumber,
+      checkString,
       snGenerationMethodList,
       viewMethodList,
       labelPosition: 'left',
-      isSet: false, // 父组件是否已设置
       property: {
         serial_number: 1, // 序号
+        sn_type: 'number',
         sn_position: 'top-start', // 序号位置:top-start top top-end 等
         sn_generation_method: snGenerationMethodList[0].value, // 序号生成方式:recalculate 重新计算follow 跟随
         view_method: viewMethodList[0].value, // 查看方式:independent 独立 list 列表icon 图标
@@ -111,9 +115,10 @@ export default {
     };
   },
   watch: {
-    setting: {
+    property: {
       handler(val) {
         if (this.isSet) {
+          val.sn_type = checkString(val.serial_number);
           this.$emit('updateSetting', val);
         }
       },
@@ -125,9 +130,9 @@ export default {
      * @description 设置属性
      * @param {Object} setting 属性
      */
-    setSetting(setting) {
+    setSetting(property) {
       this.isSet = true;
-      this.setting = setting;
+      this.property = property;
     },
 
     /**

+ 1 - 0
src/views/book/courseware/create/components/common/ModuleMixin.js

@@ -61,6 +61,7 @@ const mixin = {
       this.componentMove({ ...data, id: this.id });
     },
     saveCoursewareComponentContent() {
+      console.log(JSON.stringify(this.data));
       SaveCoursewareComponentContent({
         courseware_id: this.courseware_id,
         component_id: this.id,

+ 3 - 8
src/views/book/courseware/data/audio.js

@@ -2,10 +2,10 @@ import { snGenerationMethodList, audioViewMethodList } from '@/views/book/course
 
 export function getAudioData() {
   return {
-    id: '1',
+    id: '',
     type: 'audio',
     title: '音频',
-    single_size: 1000, // 单位MB
+    single_size: 100, // 单位MB
     total_size: 1024, // 单位MB
     property: {
       serial_number: 1, // 序号
@@ -16,11 +16,6 @@ export function getAudioData() {
     },
     file_id_list: [], // 文件 id['20032-121212', '20032-121216']
     // 内容中包含的文件列表,
-    file_list: [
-      {
-        file_id: '',
-        file_url: '',
-      },
-    ],
+    file_list: [],
   };
 }

+ 1 - 1
src/views/book/courseware/data/divider.js

@@ -1,6 +1,6 @@
 export function getDividerData() {
   return {
-    id: '1',
+    id: '',
     type: 'divider',
     title: '分割线',
     property: {

+ 3 - 10
src/views/book/courseware/data/picture.js

@@ -2,10 +2,10 @@ import { snGenerationMethodList, viewMethodList } from '@/views/book/courseware/
 
 export function getPictureData() {
   return {
-    id: '1',
+    id: '',
     type: 'picture',
     title: '图片',
-    single_size: 1, // 单位MB
+    single_size: 2, // 单位MB
     total_size: 100, // 单位MB
     property: {
       serial_number: 1, // 序号
@@ -16,13 +16,6 @@ export function getPictureData() {
     },
     file_id_list: [], // 文件 id['20032-121212', '20032-121216']
     // 内容中包含的文件列表,
-    file_list: [
-      {
-        file_id: '',
-        file_url: '',
-        file_title: '', // 标题
-        file_describe: '', // 介绍
-      },
-    ],
+    file_list: [],
   };
 }

+ 1 - 1
src/views/book/courseware/data/spacing.js

@@ -1,6 +1,6 @@
 export function getSpacingData() {
   return {
-    id: '1',
+    id: '',
     type: 'spacing',
     title: '间距',
     property: {

+ 122 - 0
src/views/book/courseware/preview/components/audio/Audio.vue

@@ -0,0 +1,122 @@
+<template>
+  <ModuleBase :type="data.type">
+    <template #content>
+      <UploadFile
+        :id="id"
+        ref="audioUploadFile"
+        :module-data="data"
+        :label-text="labelText"
+        :accept-file-type="acceptFileType"
+        :upload-tip="uploadTip"
+        :icon-class="iconClass"
+        @saveDate="saveDate"
+      />
+      <!-- <ul>
+        <li v-for="(file, i) in file_list" :key="i">
+          <audio
+            :id="file.file_id"
+            :src="file.file_url"
+            controls
+            @error=""
+            @play=""
+            @pause=""
+            @timeupdate=""
+            @ended=""
+          ></audio>
+        </li>
+      </ul> -->
+    </template>
+  </ModuleBase>
+</template>
+
+<script>
+import { getAudioData } from '@/views/book/courseware/data/audio';
+import { GetCoursewareComponentContent_View } from '@/api/book';
+import ModuleMixin from '../../common/ModuleMixin';
+import UploadFile from '../common/UploadFile.vue';
+
+export default {
+  name: 'AudioPage',
+  components: { UploadFile },
+  mixins: [ModuleMixin],
+  data() {
+    return {
+      data: getAudioData(),
+      componentId: this.id,
+      coursewareId: this.courseware_id,
+      file_list: [
+        {
+          file_id: '1',
+          file_url:
+            'https://file-kf.helxsoft.cn/CSFileServer/URL/002/69F3878866F2A1B7DF04C4EFE9ACD04120240402145413PKA8LLFPXRT1BKURSBNIFXGK8EV5VCBIVL9WGCFB_00201-20240402-14-UAG696HY.mp3',
+        },
+        {
+          file_id: '2',
+          file_url:
+            'https://file-kf.helxsoft.cn/CSFileServer/URL/002/69F3878866F2A1B7DF04C4EFE9ACD04120240402145413PKA8LLFPXRT1BKURSBNIFXGK8EV5VCBIVL9WGCFB_00201-20240402-14-UAG696HY.mp3',
+        },
+        {
+          file_id: '3',
+          file_url:
+            'https://file-kf.helxsoft.cn/CSFileServer/URL/002/69F3878866F2A1B7DF04C4EFE9ACD04120240402145413PKA8LLFPXRT1BKURSBNIFXGK8EV5VCBIVL9WGCFB_00201-20240402-14-UAG696HY.mp3',
+        },
+        {
+          file_id: '4',
+          file_url:
+            'https://file-kf.helxsoft.cn/CSFileServer/URL/002/69F3878866F2A1B7DF04C4EFE9ACD04120240402145413PKA8LLFPXRT1BKURSBNIFXGK8EV5VCBIVL9WGCFB_00201-20240402-14-UAG696HY.mp3',
+        },
+        {
+          file_id: '5',
+          file_url:
+            'https://file-kf.helxsoft.cn/CSFileServer/URL/002/69F3878866F2A1B7DF04C4EFE9ACD04120240402145413PKA8LLFPXRT1BKURSBNIFXGK8EV5VCBIVL9WGCFB_00201-20240402-14-UAG696HY.mp3',
+        },
+        {
+          file_id: '6',
+          file_url:
+            'https://file-kf.helxsoft.cn/CSFileServer/URL/002/69F3878866F2A1B7DF04C4EFE9ACD04120240402145413PKA8LLFPXRT1BKURSBNIFXGK8EV5VCBIVL9WGCFB_00201-20240402-14-UAG696HY.mp3',
+        },
+        {
+          file_id: '7',
+          file_url:
+            'https://file-kf.helxsoft.cn/CSFileServer/URL/002/69F3878866F2A1B7DF04C4EFE9ACD04120240402145413PKA8LLFPXRT1BKURSBNIFXGK8EV5VCBIVL9WGCFB_00201-20240402-14-UAG696HY.mp3',
+        },
+        {
+          file_id: '8',
+          file_url:
+            'https://file-kf.helxsoft.cn/CSFileServer/URL/002/69F3878866F2A1B7DF04C4EFE9ACD04120240402145413PKA8LLFPXRT1BKURSBNIFXGK8EV5VCBIVL9WGCFB_00201-20240402-14-UAG696HY.mp3',
+        },
+        {
+          file_id: '9',
+          file_url:
+            'https://file-kf.helxsoft.cn/CSFileServer/URL/002/69F3878866F2A1B7DF04C4EFE9ACD04120240402145413PKA8LLFPXRT1BKURSBNIFXGK8EV5VCBIVL9WGCFB_00201-20240402-14-UAG696HY.mp3',
+        },
+      ],
+      labelText: '音频',
+      acceptFileType: '.mp3,.acc,.wma',
+      uploadTip: '支持上传mp3、acc、wma,等格式音频文件,单个文件最大100MB,总文件体积不超1G。',
+      iconClass: 'note',
+    };
+  },
+  created() {
+    this.getCoursewareComponentContent_View();
+  },
+  methods: {
+    saveDate(file) {
+      this.data.id = this.componentId;
+      this.data.file_list.push(file);
+      this.data.file_id_list.push(file.file_id);
+    },
+    getCoursewareComponentContent_View() {
+      GetCoursewareComponentContent_View({ courseware_id: this.coursewareId, component_id: this.componentId }).then(
+        (res) => {
+          this.data = JSON.parse(JSON.parse(res.replace(/\n/g, '').replace(/\t/g, '')).content);
+          // if (content) this.data = JSON.parse(content);
+          // console.log(JSON.parse(content));
+        },
+      );
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 35 - 0
src/views/book/courseware/preview/components/divider/Divider.vue

@@ -0,0 +1,35 @@
+<template>
+  <ModuleBase :type="data.type">
+    <template #content>
+      <hr :style="settingStyle" />
+    </template>
+  </ModuleBase>
+</template>
+
+<script>
+import { getDividerData } from '@/views/book/courseware/data/divider';
+
+import ModuleMixin from '../../common/ModuleMixin';
+
+export default {
+  name: 'DividerPage',
+  mixins: [ModuleMixin],
+  data() {
+    return {
+      data: getDividerData(),
+    };
+  },
+  computed: {
+    settingStyle() {
+      return {
+        margin: `${this.data.property.height / 2}px 0`,
+        border: 'none',
+        borderTop: `1px ${this.data.property.line_type} #ebebeb`,
+      };
+    },
+  },
+  methods: {},
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 40 - 0
src/views/book/courseware/preview/components/picture/Picture.vue

@@ -0,0 +1,40 @@
+<template>
+  <ModuleBase :type="data.type">
+    <template #content>
+      <UploadFile
+        :id="id"
+        :module-data="data"
+        :label-text="labelText"
+        :accept-file-type="acceptFileType"
+        :upload-tip="uploadTip"
+        :icon-class="iconClass"
+      />
+    </template>
+  </ModuleBase>
+</template>
+
+<script>
+import { getPictureData } from '@/views/book/courseware/data/picture';
+import ModuleMixin from '../../common/ModuleMixin';
+import UploadFile from '../common/UploadFile.vue';
+
+export default {
+  name: 'PicturePage',
+  components: { UploadFile },
+  mixins: [ModuleMixin],
+  data() {
+    return {
+      data: getPictureData(),
+      file_info_list: [],
+      labelText: '图片',
+      acceptFileType: '.jpg,.png,.jpeg',
+      uploadTip: '支持上传jpg、png、jpeg,等格式图片文件,单个文件最大1MB,总文件体积不超100MB。',
+      iconClass: 'picture',
+    };
+  },
+  computed: {},
+  methods: {},
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 36 - 0
src/views/book/courseware/preview/components/spacing/Spacing.vue

@@ -0,0 +1,36 @@
+<template>
+  <ModuleBase :type="data.type">
+    <template #content>
+      <div :style="settingStyle"></div>
+    </template>
+  </ModuleBase>
+</template>
+
+<script>
+import { getSpacingData } from '@/views/book/courseware/data/spacing';
+
+import ModuleMixin from '../../common/ModuleMixin';
+
+export default {
+  name: 'SpacingPage',
+  components: {},
+  mixins: [ModuleMixin],
+  data() {
+    return {
+      data: getSpacingData(),
+    };
+  },
+  computed: {
+    settingStyle() {
+      return {
+        height: `${this.data.property.height}px`,
+        width: '100%',
+        backgroundColor: '#f0f0f0',
+      };
+    },
+  },
+  methods: {},
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 97 - 12
src/views/book/courseware/preview/index.vue

@@ -1,7 +1,24 @@
 <template>
   <div class="preview">
-    <div></div>
     <div>
+      <div v-for="{ id, name, nodes: children } in nodes" :key="id" class="catalogue">
+        <div class="catalogue-title">{{ name }}</div>
+        <template v-for="item in children">
+          <div :key="item.id" :class="['catalogue-item', item.is_leaf_chapter === 'true' ? 'content' : 'subdirectory']">
+            <span class="name">{{ item.name }}</span>
+          </div>
+          <div v-for="li in item.nodes" :key="li.id">
+            <div :class="['catalogue-item', 'children']">
+              <span class="name">{{ li?.name }}</span>
+            </div>
+          </div>
+        </template>
+      </div>
+    </div>
+    <div class="content-area">
+      <div class="content-top">
+        <el-button><SvgIcon icon-class="quit" /> 退出预览</el-button>
+      </div>
       <div
         class="content"
         :style="[
@@ -101,24 +118,92 @@ export default {
 
 <style lang="scss" scoped>
 .preview {
-  .content {
+  display: flex;
+  height: calc(100vh - 66px);
+  background-color: #ececec;
+
+  .catalogue {
     display: flex;
     flex-direction: column;
-    row-gap: 6px;
-    width: 100%;
-    min-height: calc(100% - 56px);
+    row-gap: 8px;
+    height: 100%;
     padding: 24px;
     background-color: #fff;
-    background-repeat: no-repeat;
-    border-radius: 4px;
 
-    .row {
-      display: grid;
-      row-gap: 16px;
-      align-items: start;
+    &-title {
+      padding: 8px 0;
+      font-weight: bold;
+      color: #000;
+    }
+
+    &-item {
+      display: flex;
+      column-gap: 8px;
+      padding: 8px 52px 8px 16px;
+      font-size: 14px;
+      border-bottom: 1px solid #ebebeb;
+
+      &:hover {
+        background-color: #f3f3f3;
+      }
+
+      &.subdirectory {
+        .name {
+          font-weight: bold;
+        }
+      }
 
-      .col {
+      &.children {
+        padding-left: 32px;
+      }
+
+      .name {
+        flex: 1;
+        color: #000;
+      }
+
+      .time,
+      .edit {
+        color: #929292;
+      }
+
+      .edit {
+        margin-left: 24px;
+        cursor: pointer;
+      }
+    }
+  }
+
+  .content-area {
+    width: calc(100vw - 320px);
+    margin: 18px 60px;
+
+    .content-top {
+      display: flex;
+      justify-content: end;
+      width: 100%;
+      margin-bottom: 18px;
+    }
+
+    .content {
+      display: flex;
+      flex-direction: column;
+      row-gap: 6px;
+      width: 100%;
+      min-height: calc(100% - 56px);
+      padding: 24px;
+      background-color: #fff;
+      background-repeat: no-repeat;
+      border-radius: 4px;
+
+      .row {
         display: grid;
+        row-gap: 16px;
+        align-items: start;
+
+        .col {
+          display: grid;
+        }
       }
     }
   }