natasha 5 days ago
parent
commit
d1ba658bf1

+ 74 - 0
src/views/book/courseware/create/components/question/table/Table.vue

@@ -74,7 +74,14 @@
             <el-input v-else v-model="li.content"></el-input>
           </div>
         </div>
+        <div class="table-node">
+          <div v-for="(value, index) in data.col_width" :key="index" class="table-item">
+            <el-input v-model="value.value"> <template slot="prepend">列宽:</template></el-input>
+          </div>
+        </div>
       </div>
+      <p class="tips">在需要作答的单元格内输入三个以上下划线“___”</p>
+      <el-button @click="identifyText">识别</el-button>
     </template>
   </ModuleBase>
 </template>
@@ -110,17 +117,79 @@ export default {
     },
     'data.property.column_count': {
       handler(val) {
+        const diff = val - this.data.option_list[0].length;
+        for (let i = 0; i < diff; i++) {
+          this.data.col_width.push({
+            value: 100,
+          });
+        }
         this.data.option_list = this.data.option_list.map((row) => {
           if (val < row.length) {
+            this.data.col_width = this.data.col_width.slice(0, val);
             return row.slice(0, val);
           }
           const diff = val - row.length;
+
           return row.concat(Array.from({ length: diff }, getOption));
         });
       },
     },
   },
   methods: {
+    // 识别文本
+    identifyText() {
+      this.data.model_essay = [];
+      this.data.answer.answer_list = [];
+
+      this.data.content
+        .split(/<(p|div)[^>]*>(.*?)<\/(p|div)>/g)
+        .filter((s) => s && !s.match(/^(p|div)$/))
+        .forEach((item) => {
+          if (item.charCodeAt() === 10) return;
+          let str = item
+            // 去除所有的 font-size 样式
+            .replace(/font-size:\s*\d+(\.\d+)?px;/gi, '')
+            // 匹配 class 名为 rich-fill 的 span 标签和三个以上的_,并将它们组成数组
+            .replace(/<span class="rich-fill".*?>(.*?)<\/span>|([_]{3,})/gi, '###$1$2###');
+          this.data.model_essay.push(this.splitRichText(str));
+        });
+    },
+    // 分割富文本
+    splitRichText(str) {
+      let _str = str;
+      let start = 0;
+      let index = 0;
+      let arr = [];
+      let matchNum = 0;
+      while (index !== -1) {
+        index = _str.indexOf('###', start);
+        if (index === -1) break;
+        matchNum += 1;
+        arr.push({ content: _str.slice(start, index), type: 'text' });
+        if (matchNum % 2 === 0 && arr.length > 0) {
+          arr[arr.length - 1].type = 'input';
+          let mark = getRandomNumber();
+          arr[arr.length - 1].mark = mark;
+          let content = arr[arr.length - 1].content;
+          // 设置答案数组
+          let isUnderline = /^_{3,}$/.test(content);
+          this.data.answer.answer_list.push({
+            value: isUnderline ? '' : content,
+            mark,
+            type: isUnderline ? 'any_one' : 'only_one',
+          });
+
+          // 将 content 设置为空,为预览准备
+          arr[arr.length - 1].content = '';
+        }
+        start = index + 3;
+      }
+      let last = _str.slice(start);
+      if (last) {
+        arr.push({ content: last, type: 'text' });
+      }
+      return arr;
+    },
     // 思维导图数据
   },
 };
@@ -206,4 +275,9 @@ export default {
     }
   }
 }
+
+.tips {
+  font-size: 12px;
+  color: #999;
+}
 </style>

+ 2 - 2
src/views/book/courseware/create/components/question/table/TableSetting.vue

@@ -15,11 +15,11 @@
       <el-form-item label="列数">
         <el-input-number v-model="property.column_count" :min="1" />
       </el-form-item>
-      <el-form-item label="自动换行">
+      <!-- <el-form-item label="自动换行">
         <el-radio-group v-model="property.auto_wrap">
           <el-radio v-for="{ value, label } in switchOption" :key="value" :label="value">{{ label }}</el-radio>
         </el-radio-group>
-      </el-form-item>
+      </el-form-item> -->
       <el-divider />
       <el-form-item label="首行颜色">
         <el-color-picker v-model="property.first_line_color" />

+ 8 - 8
src/views/book/courseware/data/bookType.js

@@ -357,14 +357,14 @@ export const bookTypeOption = [
         set: ImageTextSetting,
         preview: ImageTextPreview,
       },
-      // {
-      //   value: 'table',
-      //   label: '表格',
-      //   icon: '',
-      //   component: Table,
-      //   set: TableSetting,
-      //   preview: TablePreview,
-      // },
+      {
+        value: 'table',
+        label: '表格',
+        icon: '',
+        component: Table,
+        set: TableSetting,
+        preview: TablePreview,
+      },
       {
         value: 'pinyin_base',
         label: '拼音组件',

+ 11 - 2
src/views/book/courseware/data/table.js

@@ -34,8 +34,8 @@ export function getTableProperty() {
     row_count: 2,
     column_count: 3,
     auto_wrap: switchOption[0].value, // 自动换行
-    first_line_color: '#fff', // 首行颜色
-    first_column_color: '#fff', // 首列颜色
+    first_line_color: '', // 首行颜色
+    first_column_color: '', // 首列颜色
     border_color: '#e6e6e6', // 边框颜色
     decoration_color: '#e7b576', // 装饰颜色
   };
@@ -67,6 +67,15 @@ export function getTableData() {
       isStrikethrough: false,
       textAlign: ''
     },
+    col_width: [
+      {
+        value:100
+      },{
+        value:100
+      },{
+        value:100
+      }
+    ], // 列宽
     property: getTableProperty(),
     mind_map: {
       node_list: [{ name: '表格' }],

+ 59 - 317
src/views/book/courseware/preview/components/table/TablePreview.vue

@@ -4,34 +4,62 @@
     <SerialNumberPosition v-if="isEnable(data.property.sn_display_mode)" :property="data.property" />
 
     <div class="main">
-      <table
-        border
+      <div
+        class="table-box"
         :style="{
           width: data.property.width + 'px',
           height: data.property.height + 'px',
-          border: '1px solid ' + data.property.border_color,
         }"
       >
-        <tr v-for="(row, i) in data.option_list" :key="`tr-${i}`">
-          <template v-for="col in row">
-            <td
-              :key="col.mark"
-              :style="{
-                border: '1px solid ' + data.property.border_color,
-              }"
-            >
-              <div :style="[tdStyle]" class="cell-wrap" v-html="col.content"></div>
-            </td>
-          </template>
-        </tr>
-      </table>
+        <table
+          :style="{
+            width: table_width + 'px',
+            height: data.property.height + 'px',
+          }"
+        >
+          <colgroup>
+            <col v-for="(item, i) in data.col_width" :key="`col-${i}`" :style="{ width: `${item.value}px` }" />
+          </colgroup>
+          <tr v-for="(row, i) in data.option_list" :key="`tr-${i}`">
+            <template v-for="(col, j) in row">
+              <td
+                :key="col.mark"
+                :style="{
+                  borderTop: i === 0 ? '1px solid ' + data.property.border_color : '',
+                  borderBottom: '1px solid ' + data.property.border_color,
+                  borderLeft:
+                    i === 0 && data.property.first_line_color
+                      ? '1px solid ' + data.property.border_color
+                      : j === 0
+                        ? '2px solid ' + data.property.decoration_color
+                        : '1px dotted ' + data.property.border_color,
+                  borderRight:
+                    i === 0 && data.property.first_line_color
+                      ? '1px solid ' + data.property.border_color
+                      : j === row.length - 1
+                        ? '2px solid ' + data.property.decoration_color
+                        : '1px dotted ' + data.property.border_color,
+                  borderRadius: i === 0 && data.property.first_line_color ? '5px ' : '0',
+                  background:
+                    i === 0 && data.property.first_line_color
+                      ? data.property.first_line_color
+                      : j === 0
+                        ? data.property.first_column_color
+                        : '',
+                }"
+              >
+                <div :style="[tdStyle]" class="cell-wrap" v-html="col.content"></div>
+              </td>
+            </template>
+          </tr>
+        </table>
+      </div>
     </div>
   </div>
 </template>
 
 <script>
 import { getTableData } from '@/views/book/courseware/data/table';
-import { getRandomNumber } from '@/utils/index.js';
 
 import PreviewMixin from '../common/PreviewMixin';
 
@@ -42,32 +70,7 @@ export default {
   data() {
     return {
       data: getTableData(),
-      cid: getRandomNumber(),
-      themeColor: 'red',
-      curTime: 0,
-      playing: false,
-      stopAudio: true,
-      unWatch: null,
-      lrcArray: [],
-      fileName: '',
-      // 底色行、列
-      selectRow: -1,
-      selectColumn: -1,
-      // 行、列选中
-      selectedLine: {
-        type: '',
-        index: 0,
-      },
-      // 点击选中
-      selectCell: {
-        row: -1,
-        column: -1,
-      },
-      isRepeat: false,
-      // 跟读所需属性
-      wavblob: null,
-      isRecord: false,
-      matrixSelectLrc: null,
+      table_width: 0,
     };
   },
   computed: {
@@ -90,256 +93,17 @@ export default {
     },
   },
   watch: {},
-  created() {},
+  created() {
+    this.handleData();
+  },
   mounted() {},
   beforeDestroy() {},
   methods: {
-    handleWav(data) {
-      this.data.record_list = data;
-    },
-    // 鼠标移入移出
-    matrixCellMouseenter(i, j, type) {
-      if (type === 'connection') {
-        this.selectRow = -1;
-        this.selectColumn = -1;
-      } else {
-        this.selectRow = i;
-        this.selectColumn = j;
-      }
-    },
-
-    clearSelectCell() {
-      this.selectRow = -1;
-      this.selectColumn = -1;
-    },
-
-    // 单击单元格
-    matrixCellClick(row, column) {
-      if (this.playing) this.handleParentPlay();
-      if (this.unWatch) this.unWatch();
-      this.lrcArray = [];
-      if (row === this.selectCell.row && column === this.selectCell.column) {
-        this.selectCell = { row: -1, column: -1 };
-        return;
-      }
-      this.selectedLine = { type: '', index: -1 };
-      this.selectCell = { row, column };
-      this.handleChangeTime(this.data.option_list[row][column].lrc_data);
-      // 设置录音文件名
-      this.setRecordingFileName(row, column);
-    },
-
-    setRecordingFileName(row, column) {
-      return `录音第${column}列第${row}行`;
-    },
-
-    /**
-     * 判断 click 点击是否语音矩阵可操作区域
-     * @param {PointerEvent} event
-     */
-    restoreAudioStatus(event) {
-      const whitePath = [
-        'column-green',
-        'column-red',
-        'column-brown',
-        'matrix-checkbox-column-',
-        'matrix-checkbox-row-',
-        'audio-simple-image',
-        'audio-simple-repeat',
-        'luyin-box',
-      ];
-      const operable = event.composedPath().some((item) => {
-        const className = item.className;
-        if (!className || typeof className !== 'string') return false;
-        return whitePath.some((path) => className.includes(path));
-      });
-      if (!operable) {
-        this.selectedLine = { type: '', index: -1 };
-        this.selectCell = { row: -1, column: -1 };
-        if (this.playing) this.handleParentPlay();
-        if (this.unWatch) this.unWatch();
-      }
-    },
-
-    checkboxMouseenter(isSelected, type) {
-      if (!isSelected) return this.clearSelectCell();
-      if (type === 'row') this.selectColumn = -1;
-      if (type === 'column') this.selectRow = -1;
-    },
-
-    // 选中行、列
-    selectRowOrColumn(index, type) {
-      this.handleParentPlay();
-      this.lrcArray = [];
-      this.selectCell = { row: -1, column: -1 };
-      if (this.unWatch) this.unWatch();
-      if (this.selectedLine.type === type && this.selectedLine.index === index) {
-        this.selectedLine = { type: '', index: -1 };
-        return;
-      }
-      this.selectedLine = { type, index };
-      let number = index;
-      if (type === 'column') {
-        this.data.option_list[index].forEach((item, i) => {
-          if (i >= index) return;
-        });
-      }
-      this.fileName = `第 ${number + 1} ${type === 'row' ? '行' : '列'}`;
-    },
-
-    playAudio() {
-      if (!this.hasSelectedCell) return;
-      if (this.playing) return this.handleParentPlay();
-      if (this.lrcArray.length > 0) return this.$refs.audioLine.PlayAudio();
-      if (this.unWatch) this.unWatch();
-
-      this.lrcArray = [];
-      const { type, index } = this.selectedLine;
-
-      if (type.length > 0 && index >= 0 && type === 'row') {
-        this.data.option_list[index].forEach((item) => {
-          const data = this.getLrcData(item);
-          if (data) this.lrcArray.push(data);
-        });
-        if (this.lrcArray.length > 0) this.lrcPlay(this.lrcArray[0], 0);
-        return;
-      }
-
-      if (type.length > 0 && index >= 0 && type === 'column') {
-        this.data.option_list.forEach((item) => {
-          const data = this.getLrcData(item[index]);
-          if (data) this.lrcArray.push(data);
-        });
-        if (this.lrcArray.length > 0) this.lrcPlay(this.lrcArray[0], 0);
-        return;
-      }
-
-      const { row, column } = this.selectCell;
-      if (row >= 0 && column >= 0) {
-        this.handleChangeTime(this.data.option_list[row][column].lrc_data);
-      }
-    },
-
-    lrcPlay({ begin_time, end_time }, index) {
-      this.handleParentPlay();
-      this.$nextTick(() => {
-        this.$refs.audioLine.onTimeupdateTime(begin_time / 1000);
-        this.$refs.audioLine.PlayAudio();
-        if (end_time === -1) return;
-        const end = end_time / 1000 - 0.01;
-        this.unWatch = this.$watch('curTime', (val) => {
-          if (val >= end) {
-            if (!this.hasSelectedCell) return this.unWatch();
-            this.handleParentPlay();
-            this.$refs.audioLine.onTimeupdateTime(end);
-            this.unWatch();
-            const i = index + 1;
-            if (i < this.lrcArray.length) {
-              return this.lrcPlay(this.lrcArray[i], i);
-            }
-            if (this.isRepeat) {
-              return this.lrcPlay(this.lrcArray[0], 0);
-            }
-            this.lrcArray = [];
-          }
-        });
-      });
-    },
-
-    playChange(playing) {
-      this.playing = playing;
-      // 子组件通信,同时只能播放一个音频
-      if (playing) Bus.$emit('audioPause', this.cid);
-    },
-
-    pauseOtherAudio() {
-      Bus.$emit('audioPause', this.cid);
-      this.stopAudio = true;
-    },
-
-    // 暂停音频播放
-    handleParentPlay() {
-      this.stopAudio = true;
-    },
-    // 音频播放时改变布尔值
-    handleChangeStopAudio() {
-      this.stopAudio = false;
-    },
-
-    getCurTime(curTime) {
-      this.curTime = curTime;
-    },
-
-    getWavblob(wavblob) {
-      this.wavblob = wavblob;
-    },
-
-    getSelectData({ type, index, row, column }) {
-      if (type === '') return;
-      const arr = [];
-      if (type.length > 0 && index >= 0 && type === 'row') {
-        this.data.option_list[index].forEach((item) => {
-          const data = this.getLrcData(item);
-          if (data) arr.push(data);
-        });
-        this.matrixSelectLrc = arr;
-        return;
-      }
-
-      if (type.length > 0 && index >= 0 && type === 'column') {
-        this.data.option_list.forEach((item) => {
-          const data = this.getLrcData(item[index]);
-          if (data) arr.push(data);
-        });
-        this.matrixSelectLrc = arr;
-        return;
-      }
-
-      if (type === 'cell' && row >= 0 && column >= 0) {
-        const lrcData = this.data.option_list[row][column].lrc_data;
-        if (lrcData.end_time === -1) lrcData.end_time = this.mp3Duration;
-        this.matrixSelectLrc = [lrcData];
-      }
-    },
-
-    getLrcData({ content, lrc_data }) {
-      if (content.length > 0) {
-        if (lrc_data.end_time === -1) {
-          return {
-            begin_time: lrc_data.begin_time,
-            end_time: this.mp3Duration,
-            text: lrc_data.text,
-          };
-        }
-        return lrc_data;
-      }
-      return false;
-    },
-
-    sentPause(isRecord) {
-      this.isRecord = isRecord;
-    },
-
-    handleChangeTime({ begin_time, end_time }) {
-      if (this.unWatch) this.unWatch();
-      this.handleParentPlay();
-      this.$nextTick(() => {
-        this.$refs.audioLine.onTimeupdateTime(begin_time / 1000);
-        this.$refs.audioLine.PlayAudio();
-        // 监听是否已到结束时间,为了选中效果 - 0.01
-        if (end_time === -1) return;
-        const end = end_time / 1000 - 0.01;
-        this.unWatch = this.$watch('curTime', (val) => {
-          if (val >= end) {
-            this.handleParentPlay();
-            this.$refs.audioLine.onTimeupdateTime(end);
-            this.unWatch();
-            this.unWatch = null;
-            if (this.isRepeat) {
-              this.handleChangeTime({ begin_time, end_time });
-            }
-          }
-        });
+    handleData() {
+      this.table_width = 0;
+      console.log(2);
+      this.data.col_width.forEach((item) => {
+        this.table_width += Number(item.value);
       });
     },
   },
@@ -358,35 +122,13 @@ $border-color: #e6e6e6;
   .main {
     color: #262626;
 
-    table {
-      border-spacing: 3px;
-      border-collapse: separate;
-    }
-  }
-}
-
-.NNPE-tableList-tr-last {
-  .voice-matrix {
-    padding-bottom: 0;
-  }
-}
-</style>
-
-<style lang="scss">
-.voice-matrix {
-  &-audio {
-    .audioLine {
-      border-radius: 8px 8px 0 0 !important;
+    .table-box {
+      overflow: auto;
     }
 
-    .el-slider {
-      width: 100% !important;
-    }
-  }
-
-  .luyin-box {
-    .el-select .el-input {
-      width: 136px;
+    table {
+      // border-spacing: 3px;
+      border-collapse: separate;
     }
   }
 }