| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529 |
- <template>
- <ModuleBase ref="base" :type="data.type">
- <template #content>
- <!-- <label>标题:</label>
- <RichText
- ref="richText"
- v-model="data.title_con"
- :inline="true"
- :placeholder="'输入标题'"
- :font-size="data?.unified_attrib?.font_size"
- :font-family="data?.unified_attrib?.font"
- toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
- class="title-box"
- /> -->
- <el-table :key="refreshKey" :data="data.option" border style="width: 100%">
- <el-table-column prop="number" label="序号" width="70">
- <template slot-scope="scope">
- <el-input v-model="scope.row.number" />
- </template>
- </el-table-column>
- <el-table-column prop="con" label="内容" width="200">
- <template slot-scope="scope">
- <RichText
- v-if="property.isGetContent"
- ref="richText"
- :key="'richtext-1-' + scope.$index"
- v-model="scope.row.con"
- :inline="true"
- :item-index="scope.$index"
- :font-size="data?.unified_attrib?.font_size"
- :font-family="data?.unified_attrib?.font"
- :font-color="data?.unified_attrib?.text_color"
- toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
- @handleRichTextBlur="handleBlurCon"
- />
- </template>
- </el-table-column>
- <el-table-column v-if="isEnable(data.property.view_pinyin)" prop="con" label="拼音" width="150">
- <template slot-scope="scope">
- <RichText
- v-if="property.isGetContent"
- ref="richText"
- :key="'richtext-2-' + scope.$index"
- v-model="scope.row.pinyin"
- :inline="true"
- :font-size="data?.unified_attrib?.pinyin_size"
- :font-family="'League'"
- :font-color="data?.unified_attrib?.text_color"
- toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
- />
- </template>
- </el-table-column>
- <el-table-column prop="interpret" label="翻译" width="200">
- <template slot-scope="scope">
- <RichText
- v-if="property.isGetContent"
- ref="richText"
- :key="'richtext-3-' + scope.$index"
- v-model="scope.row.interpret"
- :inline="true"
- :font-size="data?.unified_attrib?.font_size"
- :font-family="data?.unified_attrib?.font"
- :font-color="data?.unified_attrib?.text_color"
- toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
- />
- </template>
- </el-table-column>
- <el-table-column prop="note" label="注释" width="200">
- <template slot-scope="scope">
- <RichText
- v-if="property.isGetContent"
- ref="richText"
- :key="'richtext-4-' + scope.$index"
- v-model="scope.row.note"
- :inline="true"
- :font-size="data?.unified_attrib?.font_size"
- :font-family="data?.unified_attrib?.font"
- :font-color="data?.unified_attrib?.text_color"
- toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
- />
- </template>
- </el-table-column>
- <el-table-column prop="img_list" label="图片" width="300">
- <template slot-scope="scope">
- <UploadPicture
- :file-info="scope.row.file_list[0]"
- :item-index="scope.$index"
- :show-upload="!scope.row.file_list[0]"
- @upload="uploadPic"
- @deleteFile="deletePic"
- />
- </template>
- </el-table-column>
- <el-table-column prop="match_jump" label="关联跳转" width="300">
- <template slot-scope="scope">
- <template v-if="scope.row.match_jump.type === 'outer' && scope.row.match_jump.con">
- 已关联:{{ scope.row.match_jump.con }}
- </template>
- <template v-else-if="scope.row.match_jump.type === 'inner' && scope.row.match_jump.source_courseware_name">
- 已关联:{{ scope.row.match_jump.source_courseware_name }}
- </template>
- <div class="match-btn" @click="handleMatch(scope.row)"><SvgIcon icon-class="match" /><span>关联</span></div>
- </template>
- </el-table-column>
- <el-table-column label="操作" width="150">
- <template slot-scope="scope">
- <el-button size="mini" type="text" @click="handleDelete(scope.$index)">删除</el-button>
- <el-button size="mini" type="text" @click="moveElement(scope.row, scope.$index, 'up')">上移</el-button>
- <el-button size="mini" type="text" @click="moveElement(scope.row, scope.$index, 'down')">下移</el-button>
- </template>
- </el-table-column>
- </el-table>
- <el-button icon="el-icon-plus" style="margin: 24px 0" @click="addElement">增加一个</el-button>
- <el-button @click="handleMultilingual">多语言</el-button>
- <MultilingualFill
- :visible.sync="multilingualVisible"
- :text="multilingualText"
- :translations="data.multilingual"
- @SubmitTranslation="handleMultilingualTranslation"
- />
- <el-dialog
- v-if="dialogFlag"
- :visible.sync="dialogFlag"
- :close-on-click-modal="false"
- :modal-append-to-body="false"
- :modal="false"
- width="600px"
- class="Notes-edit-dialog"
- title="关联跳转"
- >
- <div class="check-box">
- <el-form ref="form" :model="matchObj" label-width="80px">
- <el-form-item label="类型">
- <el-radio-group v-model="matchObj.type">
- <el-radio label="outer">外部跳转</el-radio>
- <el-radio label="inner">内部跳转</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="关联链接" v-if="matchObj.type === 'outer'">
- <el-input v-model="matchObj.con"></el-input>
- </el-form-item>
- <el-form-item label="关联节点" v-else>
- <el-cascader
- v-model="matchObj.source_courseware_id_list"
- :options="courseware_node_list"
- :show-all-levels="false"
- @change="handleChangeCourseware"
- clearable
- :ref="refId"
- />
- </el-form-item>
- </el-form>
- <div class="btn-box">
- <el-button type="info" size="small" @click="cancleDialog">取消</el-button>
- <el-button type="primary" size="small" @click="sureMatch">确定</el-button>
- </div>
- </div>
- </el-dialog>
- </template>
- </ModuleBase>
- </template>
- <script>
- import { isEnable } from '@/views/book/courseware/data/common';
- import ModuleMixin from '../../common/ModuleMixin';
- import { ChapterGetBookChapterStruct, PinyinBuild_OldFormat } from '@/api/book';
- import UploadPicture from '../new_word/components/UploadPicture.vue';
- import { getNotesData, getOption } from '@/views/book/courseware/data/notes';
- import cnchar from 'cnchar';
- export default {
- name: 'NotesPage',
- components: { UploadPicture },
- mixins: [ModuleMixin],
- data() {
- return {
- isEnable,
- data: getNotesData(),
- multilingualText: '',
- refreshKey: '',
- dialogFlag: false,
- matchObj: null,
- activeMatchRow: null,
- courseware_node_list: [],
- refId: 'Notes-' + Math.random().toString(36).substring(2, 12),
- };
- },
- watch: {
- 'data.option': 'handleMindMap',
- 'data.property.is_first_sentence_first_hz_pinyin_first_char_upper_case': {
- handler(val, oldVal) {
- if (val === oldVal) return;
- if (isEnable(this.data.property.view_pinyin)) {
- this.handlePinyin();
- }
- },
- deep: true,
- },
- },
- created() {
- this.getBookChapterStructExpandList();
- },
- methods: {
- /**
- * 得到教材章节结构展开列表
- */
- getBookChapterStructExpandList() {
- ChapterGetBookChapterStruct({
- book_id: this.$route.query.project_id,
- node_deep_mode: 0,
- is_contain_producer: 'false',
- is_contain_auditor: 'false',
- }).then(({ nodes }) => {
- this.courseware_node_list = nodes;
- nodes.forEach((item) => {
- item.label = item.name;
- item.pid = '';
- item.nodexIndex = 0;
- item.isLeaf = item.is_leaf === 'true';
- item.value = item.id;
- if (item.nodes) {
- item.children = item.nodes;
- item.lists = item.nodes;
- this.handleData(item, 1);
- }
- });
- });
- },
- // 递归
- handleData(data, nodeIndex) {
- if (data.nodes) {
- data.nodes.forEach((item) => {
- item.label = item.name;
- item.pid = data.id;
- item.nodexIndex = nodeIndex;
- item.isLeaf = item.is_leaf === 'true';
- item.value = item.id;
- if (item.nodes) {
- item.children = item.nodes;
- item.lists = item.nodes;
- this.handleData(item, nodeIndex + 1);
- }
- });
- }
- },
- handleChangeCourseware(val) {
- this.matchObj.source_courseware_id = val[val.length - 1];
- this.matchObj.source_courseware_name = this.$refs[this.refId].getCheckedNodes()[0]
- ? this.$refs[this.refId].getCheckedNodes()[0].pathLabels.join('/')
- : '';
- },
- // 删除行
- handleDelete(index) {
- this.data.option.splice(index, 1);
- },
- // 上移下移
- moveElement(dItem, index, type) {
- let obj = JSON.parse(JSON.stringify(dItem));
- if (type === 'up' && index > 0) {
- this.data.option.splice(index - 1, 0, obj);
- this.data.option.splice(index + 1, 1);
- }
- if (type === 'down' && index < this.data.option.length - 1) {
- this.data.option[index] = this.data.option.splice(index + 1, 1, this.data.option[index])[0];
- }
- },
- // 增加
- addElement() {
- this.data.option.push(getOption());
- },
- handleMindMap() {
- // 思维导图数据
- let node_list = [];
- this.data.option.forEach((item) => {
- node_list.push({
- name: item.con.replace(/<[^>]*>?/gm, ''),
- id: Math.random().toString(36).substring(2, 12),
- });
- if (!item.hasOwnProperty('match_jump')) {
- this.$set(item, 'match_jump', { type: 'outer', con: '', source_courseware_id_list: [] });
- }
- });
- this.data.mind_map.node_list = node_list;
- },
- async handleBlurCon(i) {
- let text = this.data.option[i].con.replace(/<[^>]+>/g, '');
- if (text) {
- this.data.option[i].pinyin = await this.handlePinyins(
- text,
- this.data.property.is_first_sentence_first_hz_pinyin_first_char_upper_case,
- );
- }
- // this.data.option[i].pinyin = cnchar
- // .spell(
- // text,
- // 'array',
- // this.data.property.is_first_sentence_first_hz_pinyin_first_char_upper_case === 'true' ? 'high' : 'low',
- // 'tone',
- // )
- // .join(' ');
- this.handleMindMap();
- },
- async handlePinyin() {
- for (const item of this.data.option) {
- let text = item.con.replace(/<[^>]+>/g, '');
- if (text) {
- item.pinyin = await this.handlePinyins(
- text,
- this.data.property.is_first_sentence_first_hz_pinyin_first_char_upper_case,
- );
- }
- }
- // this.data.option.forEach((item) => {
- // let text = item.con.replace(/<[^>]+>/g, '');
- // item.pinyin = cnchar
- // .spell(
- // text,
- // 'array',
- // this.data.property.is_first_sentence_first_hz_pinyin_first_char_upper_case === 'true' ? 'high' : 'low',
- // 'tone',
- // )
- // .join(' ');
- // });
- },
- // 自动生成拼音
- handlePinyins(text, flag) {
- let data = {
- text,
- is_rich_text: 'false',
- is_first_sentence_first_hz_pinyin_first_char_upper_case: flag || 'false',
- is_fill_space: 'false',
- is_custom_fc: 'false',
- };
- return new Promise((resolve, reject) => {
- PinyinBuild_OldFormat(data).then((res) => {
- if (res.parsed_text) {
- let mergedData = '';
- res.parsed_text.paragraph_list.map((outerArr, i) =>
- outerArr.map((innerArr, j) =>
- innerArr.map((newItem, k) => {
- mergedData += `${newItem.pinyin} `;
- }),
- ),
- );
- resolve(mergedData);
- }
- });
- });
- },
- handleMultilingual() {
- this.multilingualText = this.data.title_con ? this.data.title_con : '<p> </p>';
- this.data.option.forEach((item) => {
- this.multilingualText += item.con ? item.con : '<p> </p>';
- this.multilingualText += item.note ? item.note : '<p> </p>';
- });
- this.multilingualVisible = true;
- },
- // 获取拼音解析文本
- createParsedTextInfoPinyin(text) {
- if (text === '') {
- this.data.paragraph_list_parameter.pinyin_proofread_word_list = [];
- return;
- }
- this.data.paragraph_list_parameter.text = text.replace(/<[^>]+>/g, '');
- this.data.paragraph_list_parameter.is_first_sentence_first_hz_pinyin_first_char_upper_case =
- this.data.property.is_first_sentence_first_hz_pinyin_first_char_upper_case;
- PinyinBuild_OldFormat(this.data.paragraph_list_parameter).then((res) => {
- if (res.parsed_text) {
- const mergedData = res.parsed_text.paragraph_list.map((outerArr, i) =>
- outerArr.map((innerArr, j) =>
- innerArr.map((newItem, k) => {
- // 从 originalData 中找到对应的项
- const originalItem = this.data.paragraph_list[i]?.[j]?.[k];
- // 如果 originalItem 有 activeTextStyle,就合并到 newItem
- if (originalItem?.activeTextStyle) {
- return {
- ...newItem,
- activeTextStyle: originalItem.activeTextStyle,
- };
- }
- // 否则直接返回 newItem
- return newItem;
- }),
- ),
- );
- this.data.paragraph_list = mergedData;
- let pinyin_index = 0;
- this.data.option.forEach((items, index) => {
- items.model_pinyin = [];
- if (items.content && mergedData[pinyin_index] && mergedData[pinyin_index][0]) {
- mergedData[pinyin_index][0].forEach((itemP) => {
- items.model_pinyin.push(itemP);
- });
- pinyin_index++;
- }
- });
- }
- });
- },
- // 填充校对后的拼音
- fillCorrectPinyin({ selectContent: { text, pinyin, activeTextStyle }, i, j, k }) {
- this.data.paragraph_list_parameter.pinyin_proofread_word_list.push({
- paragraph_index: i,
- sentence_index: j,
- word_index: k,
- word: text,
- pinyin,
- });
- if (pinyin) this.data.paragraph_list[i][j][k].pinyin = pinyin;
- if (activeTextStyle) this.data.paragraph_list[i][j][k].activeTextStyle = activeTextStyle;
- },
- uploadPic(file_id, index, file) {
- this.data.option[index].file_list[0] = file;
- this.data.file_id_list.push(file_id);
- this.refreshKey = Math.random();
- },
- deletePic(file_id, index) {
- this.data.option[index].file_list[0] = '';
- this.data.file_id_list = this.data.file_id_list.filter((item) => item !== file_id);
- },
- // 点击关联按钮
- handleMatch(row) {
- this.matchObj = JSON.parse(JSON.stringify(row.match_jump));
- this.activeMatchRow = row;
- this.dialogFlag = true;
- },
- // 确定关联
- sureMatch() {
- this.dialogFlag = false;
- this.activeMatchRow.match_jump = JSON.parse(JSON.stringify(this.matchObj));
- this.matchObj = null;
- },
- cancleDialog() {
- this.dialogFlag = false;
- this.matchObj = null;
- this.activeMatchRow = null;
- },
- },
- };
- </script>
- <style lang="scss" scoped>
- .upload-file {
- display: flex;
- column-gap: 12px;
- align-items: center;
- margin: 8px 0;
- .file-name {
- display: flex;
- column-gap: 14px;
- align-items: center;
- justify-content: space-between;
- max-width: 360px;
- padding: 8px 12px;
- font-size: 14px;
- color: #1d2129;
- background-color: #f7f8fa;
- span {
- display: flex;
- column-gap: 14px;
- align-items: center;
- }
- }
- .svg-icon {
- cursor: pointer;
- }
- }
- .title-box {
- padding: 5px;
- margin: 5px 0;
- background-color: #f2f3f5;
- border: 1px solid #f2f3f5;
- border-radius: 4px;
- :deep p {
- margin: 0;
- }
- }
- .match-btn {
- display: flex;
- column-gap: 12px;
- align-items: center;
- width: 233px;
- padding: 4px 12px;
- font-size: 14px;
- color: #1d2129;
- cursor: pointer;
- background-color: #f2f3f5;
- }
- </style>
- <style lang="scss">
- .tox .tox-editor-header {
- z-index: 3 !important;
- }
- .Notes-edit-dialog {
- .el-dialog__body {
- padding: 0;
- }
- .check-box {
- padding: 24px;
- background: #fff;
- border-radius: 4px;
- box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 25%);
- .btn-box {
- display: block;
- text-align: right;
- .el-button {
- padding: 2px 12px;
- font-size: 12px;
- line-height: 20px;
- }
- }
- }
- }
- </style>
|