dusenyao пре 1 година
родитељ
комит
b15ec0acd6

+ 12 - 0
src/icons/svg/components/describe.svg

@@ -0,0 +1,12 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <g clip-path="url(#clip0_271_12357)">
+    <path
+      d="M2.66634 2.66797V7.33464H7.33301V2.66797H8.66634V13.3346H7.33301V8.66797H2.66634V13.3346H1.33301V2.66797H2.66634ZM12.333 5.33464C13.7137 5.33464 14.833 6.45392 14.833 7.83464C14.833 8.40624 14.6412 8.93303 14.3184 9.3541L14.2198 9.47477L12.0225 12.0013H14.6663V13.3346H9.99967L9.99921 12.2973L13.2135 8.60004C13.3917 8.39517 13.4997 8.1275 13.4997 7.83464C13.4997 7.1903 12.9773 6.66797 12.333 6.66797C11.7209 6.66797 11.2189 7.13937 11.1702 7.73897L11.1663 7.83464H9.83301C9.83301 6.45392 10.9523 5.33464 12.333 5.33464Z"
+      fill="black" />
+  </g>
+  <defs>
+    <clipPath id="clip0_271_12357">
+      <rect width="16" height="16" fill="white" />
+    </clipPath>
+  </defs>
+</svg>

+ 12 - 0
src/icons/svg/components/divider.svg

@@ -0,0 +1,12 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <g clip-path="url(#clip0_271_12372)">
+    <path
+      d="M1.33301 7.33203H2.66634V8.66536H1.33301V7.33203ZM3.99967 7.33203H11.9997V8.66536H3.99967V7.33203ZM13.333 7.33203H14.6663V8.66536H13.333V7.33203Z"
+      fill="black" />
+  </g>
+  <defs>
+    <clipPath id="clip0_271_12372">
+      <rect width="16" height="16" fill="white" />
+    </clipPath>
+  </defs>
+</svg>

+ 12 - 0
src/icons/svg/components/stem.svg

@@ -0,0 +1,12 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <g clip-path="url(#clip0_271_12354)">
+    <path
+      d="M8.66634 13.3346H7.33301V8.66797H2.66634V13.3346H1.33301V2.66797H2.66634V7.33464H7.33301V2.66797H8.66634V13.3346ZM14 5.33464V13.3346H12.6667L12.6663 6.80397L11.333 7.1613V5.7813L13 5.33464H14Z"
+      fill="black" />
+  </g>
+  <defs>
+    <clipPath id="clip0_271_12354">
+      <rect width="16" height="16" fill="white" />
+    </clipPath>
+  </defs>
+</svg>

+ 13 - 0
src/router/modules/book.js

@@ -0,0 +1,13 @@
+import DEFAULT from '@/layouts/default';
+
+export const createBookPage = {
+  path: '/book',
+  component: DEFAULT,
+  redirect: '/book/create',
+  children: [
+    {
+      path: 'create',
+      component: () => import('@/views/book/create.vue'),
+    },
+  ],
+};

+ 1 - 1
src/router/modules/courseware.js

@@ -10,7 +10,7 @@ const CoursewareModulePage = {
   children: [
     {
       path: 'create',
-      component: () => import('@/views/courseware/create/index.vue'),
+      component: () => import('@/views/book/courseware/create/index.vue'),
     },
   ],
 };

+ 2 - 2
src/router/modules/index.js

@@ -1,5 +1,5 @@
 import { homePage, loginPage, NotFoundPage } from './basic';
-import { createTextbookPage } from './textbook';
+import { createBookPage } from './book';
 import CoursewareRouters from './courseware';
 
-export const routes = [homePage, loginPage, createTextbookPage, ...CoursewareRouters, NotFoundPage];
+export const routes = [homePage, loginPage, createBookPage, ...CoursewareRouters, NotFoundPage];

+ 0 - 13
src/router/modules/textbook.js

@@ -1,13 +0,0 @@
-import DEFAULT from '@/layouts/default';
-
-export const createTextbookPage = {
-  path: '/textbook',
-  component: DEFAULT,
-  redirect: '/textbook/create',
-  children: [
-    {
-      path: 'create',
-      component: () => import('@/views/textbook/create.vue'),
-    },
-  ],
-};

+ 73 - 0
src/utils/common.js

@@ -13,3 +13,76 @@ export function conversionSize(size) {
   }
   return `${_size.toFixed(2)}${units[factor]}`;
 }
+
+// 分割线
+const type = {
+  type: 'divider',
+  property: {
+    height: 40,
+    type: 'solid',
+  },
+};
+
+const data = {
+  id: '1',
+  background_image_url: 'https://file/1/1.jpg',
+  background_position: {
+    x: 0,
+    y: 0,
+    width: 100,
+    height: 100,
+  },
+  // 组件列表
+  component_list: [
+    // 第一行
+    [
+      // 第一行第一列
+      {
+        id: '1-1',
+        type: 'image',
+        width: '100%',
+        component_list: [],
+      },
+    ],
+    // 第二行
+    [
+      // 第二行第一列
+      {
+        id: '2-1',
+        type: 'video',
+        width: '30%',
+        component_list: [],
+      },
+      // 第二行第二列
+      {
+        id: '2-2',
+        type: 'audio',
+        width: '30%',
+        component_list: [],
+      },
+      // 第二行第三列
+      {
+        id: '',
+        type: '',
+        width: '40%',
+        // 组件列表
+        component_list: [
+          // 第二行第三列第一行
+          [
+            {
+              id: '3-1',
+              type: 'image',
+            },
+          ],
+          // 第二行第三列第二行
+          [
+            {
+              id: '3-2',
+              type: 'video',
+            },
+          ],
+        ],
+      },
+    ],
+  ],
+};

+ 1 - 1
src/views/textbook/create.vue → src/views/book/chapter.vue

@@ -4,7 +4,7 @@
 
 <script>
 export default {
-  name: 'CreateTextbookPage',
+  name: 'ChapterPage',
   data() {
     return {};
   },

+ 27 - 0
src/views/book/courseware/create/components/base/divider/Divider.vue

@@ -0,0 +1,27 @@
+<template>
+  <ModuleBase :type="data.type">
+    <template #content>
+      <el-divider />
+    </template>
+  </ModuleBase>
+</template>
+
+<script>
+import { DividerData } from '@/views/book/courseware/data/divider';
+
+import ModuleMixin from '../../common/ModuleMixin';
+
+export default {
+  name: 'Divider',
+  components: {},
+  mixins: [ModuleMixin],
+  data() {
+    return {
+      data: DividerData,
+    };
+  },
+  methods: {},
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 52 - 0
src/views/book/courseware/create/components/base/divider/DividerSetting.vue

@@ -0,0 +1,52 @@
+<template>
+  <div>
+    <el-form :model="setting" :label-position="labelPosition" label-width="80px">
+      <el-form-item label="高度">
+        <el-input v-model="setting.height" />
+      </el-form-item>
+      <el-form-item label="类型">
+        <el-select v-model="setting.type">
+          <el-option label="实线" value="solid" />
+        </el-select>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'DividerSetting',
+  data() {
+    return {
+      labelPosition: 'right',
+      isSet: false, // 父组件是否已设置
+      setting: {
+        height: 100,
+        type: 'solid',
+      },
+    };
+  },
+  watch: {
+    setting: {
+      handler(val) {
+        if (this.isSet) {
+          this.$emit('updateSetting', val);
+        }
+      },
+      deep: true,
+    },
+  },
+  methods: {
+    /**
+     * @description 设置属性
+     * @param {Object} setting 属性
+     */
+    setSetting(setting) {
+      this.isSet = true;
+      this.setting = setting;
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 14 - 13
src/views/courseware/create/components/common/ModuleBase.vue → src/views/book/courseware/create/components/common/ModuleBase.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="module">
-    <div class="module-content">
-      <slot name="title"></slot>
+    <div class="module-top">
+      <span class="title">{{ componentNameList[type] }}</span>
       <div>
         <span><SvgIcon icon-class="copy" size="14" /></span>
         <span><SvgIcon icon-class="setup" size="14" /></span>
@@ -15,25 +15,20 @@
 </template>
 
 <script>
+import { componentNameList } from '@/views/book/courseware/data/bookType.js';
+
 export default {
   name: 'ModuleBase',
   props: {
-    title: {
+    type: {
       type: String,
-      default: '',
-    },
-    isChild: {
-      type: Boolean,
-      default: false,
-    },
-    isChange: {
-      type: Boolean,
-      default: false,
+      default: 'text',
     },
   },
   data() {
     return {
       isShow: false,
+      componentNameList,
     };
   },
 };
@@ -41,6 +36,12 @@ export default {
 
 <style lang="scss" scoped>
 .module {
-  border: 1px solid #EBEBEB;
+  padding: 8px;
+  border: 1px solid #272727;
+
+  &-top {
+    display: flex;
+    justify-content: space-between;
+  }
 }
 </style>

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

@@ -0,0 +1,37 @@
+// 组件混入
+import ModuleBase from './ModuleBase.vue';
+
+const mixin = {
+  data() {
+    return {};
+  },
+  props: {
+    questionId: {
+      type: String,
+      default: '',
+    },
+  },
+  components: {
+    ModuleBase,
+  },
+  mounted() {
+    // TODO: 为了先显示设置页面,以后需要修改
+    this.$emit('showSetting', this.data.setting);
+  },
+  watch: {},
+  methods: {
+    // 显示设置
+    showSetting() {
+      this.$emit('showSetting', this.data.setting);
+    },
+    /**
+     * @description 更新属性
+     * @param {Object} setting 属性
+     */
+    updateSetting(setting) {
+      this.data.setting = setting;
+    },
+  },
+};
+
+export default mixin;

+ 0 - 0
src/views/courseware/create/components/common/ModuleProperty.vue → src/views/book/courseware/create/components/common/ModuleProperty.vue


+ 148 - 0
src/views/book/courseware/create/index.vue

@@ -0,0 +1,148 @@
+<template>
+  <div class="create">
+    <div class="create-left">
+      <div class="back-container">
+        <el-button class="back" @click="back"><i class="el-icon-arrow-left"></i> 返回</el-button>
+        <span class="title">Frame 1</span>
+      </div>
+      <div v-for="{ value, label, children } in bookTypeOption" :key="value" class="components">
+        <div class="components-title">{{ label }}</div>
+        <div
+          v-for="{ value: childValue, icon, label: childLabel } in children"
+          :key="childValue"
+          class="components-item"
+          @click="curType = childValue"
+        >
+          <SvgIcon v-if="icon" :icon-class="icon" />
+          <span>{{ childLabel }}</span>
+        </div>
+      </div>
+    </div>
+    <div class="create-middle">
+      <div></div>
+      <div class="canvas">
+        <component :is="componentList[curType]" ref="components" @showSetting="showSetting" />
+      </div>
+    </div>
+    <div class="create-right">
+      <div class="setting-tittle">设置</div>
+      <component :is="componentSettingList[curType]" ref="setting" @updateSetting="updateSetting" />
+    </div>
+  </div>
+</template>
+
+<script>
+import { bookTypeOption, componentList, componentSettingList } from '../data/bookType';
+
+export default {
+  name: 'CreatePage',
+  data() {
+    return {
+      curType: 'divider',
+      componentList,
+      componentSettingList,
+      bookTypeOption,
+    };
+  },
+  methods: {
+    back() {
+      this.$router.push('/');
+    },
+    showSetting(setting) {
+      this.$refs.setting.setSetting(setting);
+    },
+    updateSetting(setting) {
+      this.$refs.components.updateSetting(setting);
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.create {
+  display: flex;
+  height: 100%;
+
+  &-left {
+    display: flex;
+    flex-direction: column;
+    width: 200px;
+    overflow: auto;
+    background-color: #fff;
+
+    .back-container {
+      display: flex;
+      flex-direction: column;
+      row-gap: 8px;
+      padding: 4px;
+
+      .back {
+        color: #000;
+        text-align: left;
+        background-color: #f4f4f4;
+      }
+
+      .title {
+        padding: 0 16px;
+        font-size: 14px;
+        font-weight: bold;
+      }
+    }
+
+    .components {
+      display: flex;
+      flex-direction: column;
+      padding: 24px 8px 4px;
+      margin-top: 12px;
+      border-top: 1px solid #e5e6eb;
+
+      .components-title {
+        padding-left: 8px;
+        font-size: 14px;
+        font-weight: bold;
+        color: #999;
+      }
+
+      .components-item {
+        display: flex;
+        align-items: center;
+        padding: 5px 16px;
+        cursor: pointer;
+
+        svg {
+          width: 16px;
+          height: 16px;
+          margin-right: 8px;
+        }
+      }
+    }
+  }
+
+  &-middle {
+    flex: 1;
+    padding: 24px 20px;
+    overflow: auto;
+    background-color: #ececec;
+
+    .canvas {
+      width: 100%;
+      min-height: 100%;
+      padding: 24px;
+      background-color: #fff;
+      border-radius: 4px;
+    }
+  }
+
+  &-right {
+    width: 200px;
+    padding: 16px 8px;
+    background-color: #fff;
+
+    .setting-tittle {
+      margin-bottom: 16px;
+      font-weight: bold;
+      color: #000;
+    }
+  }
+}
+</style>

+ 54 - 0
src/views/book/courseware/data/bookType.js

@@ -0,0 +1,54 @@
+import DividerPage from '../create/components/base/divider/Divider.vue';
+import DividerSetting from '../create/components/base/divider/DividerSetting.vue';
+
+export const bookTypeOption = [
+  {
+    value: 'base',
+    label: '基础组件',
+    children: [
+      {
+        value: 'stem',
+        label: '题干',
+        icon: 'stem',
+        component: '',
+        // 设置页面
+        set: '',
+      },
+      {
+        value: 'divider',
+        label: '分割线',
+        icon: 'divider',
+        component: DividerPage,
+        set: DividerSetting,
+      },
+    ],
+  },
+  {
+    value: 'question',
+    label: '题型组件',
+    children: [
+      {
+        value: 'select',
+        label: '选择组件',
+        icon: '',
+        component: '',
+        set: '',
+      },
+    ],
+  },
+];
+
+// 组件列表
+export const componentList = bookTypeOption
+  .flatMap((item) => item.children)
+  .reduce((prev, { value, component }) => ({ ...prev, [value]: component }), {});
+
+// 组件设置列表
+export const componentSettingList = bookTypeOption
+  .flatMap((item) => item.children)
+  .reduce((prev, { value, set }) => ({ ...prev, [value]: set }), {});
+
+// 组件名称类别
+export const componentNameList = bookTypeOption
+  .flatMap((item) => item.children)
+  .reduce((prev, { value, label }) => ({ ...prev, [value]: label }), {});

+ 8 - 0
src/views/book/courseware/data/divider.js

@@ -0,0 +1,8 @@
+export let DividerData = {
+  type: 'divider',
+  title: '分割线',
+  setting: {
+    height: 100,
+    type: 'solid',
+  },
+};

+ 141 - 0
src/views/book/create.vue

@@ -0,0 +1,141 @@
+<template>
+  <div class="create">
+    <div class="breadcrumb">
+      <ul>
+        <li v-for="(item, i) in breadcrumbList" :key="item">
+          <span v-if="i !== 0" class="separator">></span>
+          <span class="breadcrumb-name">
+            {{ item }}
+          </span>
+        </li>
+      </ul>
+    </div>
+    <div class="basic-info">
+      <div class="basic-info-title">基本信息</div>
+      <el-form ref="form" :model="form" label-width="80px">
+        <el-form-item label="书籍名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="作者" prop="author">
+          <el-input v-model="form.author" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="现价" prop="current_price">
+          <el-input v-model="form.current_price" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="原价" prop="original_price">
+          <el-input v-model="form.original_price" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="标签" prop="tags">
+          <el-input v-model="form.tags" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="分类" prop="classify">
+          <el-input v-model="form.classify" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="简介" prop="brief_introduction">
+          <el-input
+            v-model="form.brief_introduction"
+            type="textarea"
+            :autosize="{ minRows: 6 }"
+            :maxlength="500"
+            show-word-limit
+            placeholder="请输入更多内容"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="confirm">确定</el-button>
+          <el-button @click="$router.push('/')">取消</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'CreateBookPage',
+  data() {
+    return {
+      form: {
+        name: '',
+        author: '',
+        current_price: '',
+        original_price: '',
+        tags: '',
+        classify: '',
+        brief_introduction: '',
+      },
+      breadcrumbList: ['教材管理', '新建教材', '基本信息'],
+    };
+  },
+  methods: {
+    confirm() {
+      this.$router.push('/courseware');
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.create {
+  padding: 8px 24px;
+
+  .breadcrumb {
+    display: flex;
+    align-items: center;
+
+    > ul {
+      display: flex;
+
+      li {
+        font-weight: 400;
+        color: $font-light-color;
+
+        .separator {
+          margin: 0 8px;
+          color: #c9cdd4;
+        }
+
+        .breadcrumb-name {
+          font-size: 14px;
+        }
+
+        &:not(:last-child) {
+          cursor: pointer;
+        }
+
+        &:nth-last-child(1) {
+          font-weight: bold;
+          color: $font-color;
+        }
+      }
+    }
+  }
+
+  .basic-info {
+    width: 1200px;
+    padding: 24px;
+    margin: 24px auto 16px;
+    background-color: #fff;
+    border-radius: 4px;
+
+    &-title {
+      margin-bottom: 24px;
+      font-size: 18px;
+      font-weight: bold;
+    }
+
+    .el-form {
+      .el-input,
+      .el-textarea {
+        width: 400px;
+
+        :deep .el-input__inner,
+        :deep .el-textarea__inner {
+          background-color: #fff;
+          border-color: #dcdcdc;
+        }
+      }
+    }
+  }
+}
+</style>

+ 15 - 0
src/views/book/setting.vue

@@ -0,0 +1,15 @@
+<template>
+  <div></div>
+</template>
+
+<script>
+export default {
+  name: 'SettingPage',
+  data() {
+    return {};
+  },
+  methods: {},
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 0 - 58
src/views/courseware/create/components/base/Divider.vue

@@ -1,58 +0,0 @@
-<template>
-  <div class="divider">
-    <ModuleBase>
-      <template #title>
-        <span>分割线</span>
-      </template>
-      <template #content>
-        <el-divider />
-      </template>
-    </ModuleBase>
-    <ModuleProperty>
-      <template #property>
-        <el-form :label-position="labelPosition" label-width="80px">
-          <el-form-item label="高度">
-            <el-input />
-          </el-form-item>
-          <el-form-item label="类型">
-            <el-select>
-              <el-option label="实线" />
-            </el-select>
-          </el-form-item>
-        </el-form>
-      </template>
-    </ModuleProperty>
-  </div>
-</template>
-
-<script>
-import ModuleMixin from '../common/ModuleMixin';
-export default {
-  name: 'Divider',
-  components: {},
-  mixins: [ModuleMixin],
-  data() {
-    return {
-      labelPosition: 'right',
-    };
-  },
-  methods: {},
-};
-</script>
-
-<style lang="scss" scoped>
-.divider{
-
-  .content {
-    display: flex;
-    justify-content: flex-start;
-    width: 50%;
-    height: 100px;
-    border: 1px solid red;
-
-    .property {
-      width: 200px;
-    }
-  }
-}
-</style>

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

@@ -1,34 +0,0 @@
-// 组件混入
-import ModuleBase from './ModuleBase.vue';
-import ModuleProperty from './ModuleProperty.vue';
-
-const mixin = {
-  data() {
-    return {};
-  },
-  provide: [],
-  inject: [],
-  props: {
-    questionId: {
-      type: String,
-      default: '',
-    },
-    isChild: {
-      type: Boolean,
-      default: false,
-    },
-    isChange: {
-      type: Boolean,
-      default: false,
-    },
-  },
-  components: {
-    ModuleBase,
-    ModuleProperty,
-  },
-  created() {},
-  watch: {},
-  methods: {},
-};
-
-export default mixin;

+ 0 - 20
src/views/courseware/create/index.vue

@@ -1,20 +0,0 @@
-<template>
-  <div>
-    <Divider />
-  </div>
-</template>
-<script>
-import ModuleMixin from '../create/components/common/ModuleMixin.js';
-import Divider from '../create/components/base/Divider.vue';
-export default {
-  name: 'Create',
-  components: {
-    Divider,
-  },
-  mixins: [ModuleMixin],
-  data() {
-    return {};
-  },
-  methods: {},
-};
-</script>

+ 4 - 4
src/views/home/index.vue

@@ -2,7 +2,7 @@
   <div class="home">
     <div class="home-title">
       <span>教材列表</span>
-      <el-button type="primary" @click="createTextbook">创建教材</el-button>
+      <el-button type="primary" @click="createBook">创建教材</el-button>
     </div>
     <div class="home-tabs">
       <span
@@ -54,7 +54,7 @@ export default {
       cur_page: 1,
       page_capacity: 10,
       total: 0,
-      tab: 'draft',
+      tab: 'published',
       tabList: [
         {
           label: '已上架',
@@ -68,8 +68,8 @@ export default {
     };
   },
   methods: {
-    createTextbook() {
-      this.$router.push('/textbook/create');
+    createBook() {
+      this.$router.push('/book/create');
     },
     changePage(number) {
       this.cur_page = number;