yujialong 1 year ago
parent d40a254096
commit 4544cb7d95
  1. 31
      package-lock.json
  2. 2
      package.json
  3. 471
      src/components/quill/index.vue
  4. 13
      src/pages/product/list/index.vue
  5. 66
      src/pages/product/show/index.vue
  6. 2
      src/setting.js

31
package-lock.json generated

@ -3435,6 +3435,11 @@
"integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==",
"dev": true "dev": true
}, },
"cssfilter": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
"integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw=="
},
"cssnano": { "cssnano": {
"version": "4.1.10", "version": "4.1.10",
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz",
@ -6592,12 +6597,8 @@
"highlight.js": { "highlight.js": {
"version": "9.16.2", "version": "9.16.2",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.16.2.tgz", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.16.2.tgz",
"integrity": "sha512-feMUrVLZvjy0oC7FVJQcSQRqbBq9kwqnYE4+Kj9ZjbHh3g+BisiPgF49NyQbVLNdrL/qqZr3Ca9yOKwgn2i/tw==" "integrity": "sha512-feMUrVLZvjy0oC7FVJQcSQRqbBq9kwqnYE4+Kj9ZjbHh3g+BisiPgF49NyQbVLNdrL/qqZr3Ca9yOKwgn2i/tw==",
}, "dev": true
"highlight.js-async-webpack": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/highlight.js-async-webpack/-/highlight.js-async-webpack-1.0.4.tgz",
"integrity": "sha1-wGtnv5nwSQRdYrdW5YVbCRLsYWw="
}, },
"hmac-drbg": { "hmac-drbg": {
"version": "1.0.1", "version": "1.0.1",
@ -7993,12 +7994,11 @@
} }
}, },
"mavon-editor": { "mavon-editor": {
"version": "2.7.7", "version": "2.10.4",
"resolved": "https://registry.npmjs.org/mavon-editor/-/mavon-editor-2.7.7.tgz", "resolved": "https://registry.npmjs.org/mavon-editor/-/mavon-editor-2.10.4.tgz",
"integrity": "sha512-lXnYe+dztKepbv8bi2nedRqG/AwyUDF8gmkv9lHD3fpVJ1+pzAS6YILRIryKCvO9qPIOPEThHsda2DxtlzRsZA==", "integrity": "sha512-CFsBLkgt/KZBDg+SJYe2fyYv4zClY149PiwpH0rDAiiP4ae1XNs0GC8nBsoTeipsHcebDLN1QMkt3bUsnMDjQw==",
"requires": { "requires": {
"highlight.js": "^9.11.0", "xss": "^1.0.6"
"highlight.js-async-webpack": "^1.0.4"
} }
}, },
"md5.js": { "md5.js": {
@ -13304,6 +13304,15 @@
"async-limiter": "~1.0.0" "async-limiter": "~1.0.0"
} }
}, },
"xss": {
"version": "1.0.14",
"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.14.tgz",
"integrity": "sha512-og7TEJhXvn1a7kzZGQ7ETjdQVS2UfZyTlsEdDOqvQF7GoxNfY+0YLCzBy1kPdsDDx4QuNAonQPddpsn6Xl/7sw==",
"requires": {
"commander": "^2.20.3",
"cssfilter": "0.0.10"
}
},
"xtend": { "xtend": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",

@ -15,7 +15,7 @@
"element-theme": "^2.0.1", "element-theme": "^2.0.1",
"element-ui": "^2.13.0", "element-ui": "^2.13.0",
"js-cookie": "^2.2.1", "js-cookie": "^2.2.1",
"mavon-editor": "^2.6.17", "mavon-editor": "^2.10.4",
"postcss-px2rem": "^0.3.0", "postcss-px2rem": "^0.3.0",
"px2rem-loader": "^0.1.9", "px2rem-loader": "^0.1.9",
"sortablejs": "^1.14.0", "sortablejs": "^1.14.0",

@ -1,17 +1,38 @@
<template> <template>
<div class="quill" ref="quill" :class="classes"> <div>
<div ref="editor" :style="styles" v-loading="loading"></div> <el-radio-group v-if="!readonly"
class="type-radio"
v-model="type"
@change="typeChange">
<el-radio :label="0">富文本</el-radio>
<el-radio :label="1">markdown</el-radio>
</el-radio-group>
<div v-show="!type"
class="quill"
ref="quill"
:class="classes">
<div ref="editor"
:style="styles"
v-loading="loading"></div>
<el-upload <el-upload :headers="headers"
:headers="headers" :action="this.api.fileupload"
:action="this.api.fileupload" :before-upload="beforeUpload"
:before-upload="beforeUpload" :on-success="editorUploadSuccess"
:on-success="editorUploadSuccess" style="display: none">
style="display: none" <el-button :id="'editorUpload' + index"
> type="primary">点击上传</el-button>
<el-button :id="'editorUpload' + index" type="primary">点击上传</el-button> </el-upload>
</el-upload>
</div> </div>
<mavon-editor class="md"
v-model="mdVal"
v-show="type"
ref="md"
:ishljs="true"
:subfield="false"
@change="mdChange"
@imgAdd="imgAdd" />
</div>
</template> </template>
<script> <script>
@ -22,213 +43,256 @@ import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css"; import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css"; import "quill/dist/quill.bubble.css";
import toolbarOptions from "./options"; import toolbarOptions from "./options";
import axios from 'axios'
import { mavonEditor } from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
export default { export default {
name: "quill", name: "quill",
props: { components: {
value: { mavonEditor
type: String, },
default: "" props: {
}, value: {
readonly: { type: String,
type: Boolean, default: ""
default: false },
}, readonly: {
toTop: { type: Boolean,
type: Boolean, default: false
default: true },
}, toTop: {
border: { type: Boolean,
type: Boolean, default: true
default: false
},
height: {
type: Number
},
minHeight: {
type: Number
},
/*
* 原本的readOnly失效,对比其他项目发现是quill版本不同导致
* 使用props传入elseRead = 'true'手动隐藏工具栏
*/
elseRead: {
type: String, default: "false"
},
//
index: {
type: Number,
default: 0
},
}, },
data() { border: {
const that = this type: Boolean,
return { default: false
headers: {
token: util.local.get(Setting.tokenKey)
},
Quill: null,
currentValue: "",
options: {
theme: "snow",
bounds: document.body,
debug: "warn",
modules: {
toolbar: {
container: toolbarOptions,
handlers: {
"image": function(value) {
if (value) {
// iview
document.querySelector("#editorUpload" + that.index).click();
} else {
this.Quill.format("image", false);
}
}
}
}
},
placeholder: "",
readOnly: this.readonly
},
loading: false
};
}, },
computed: { height: {
classes() { type: Number
return [ },
{ minHeight: {
"quill-no-border": !this.border type: Number
},
/*
* 原本的readOnly失效,对比其他项目发现是quill版本不同导致
* 使用props传入elseRead = 'true'手动隐藏工具栏
*/
elseRead: {
type: String, default: "false"
},
//
index: {
type: Number,
default: 0
},
},
data () {
const that = this
return {
headers: {
token: util.local.get(Setting.tokenKey)
},
type: 0,
mdVal: '',
Quill: null,
currentValue: "",
options: {
theme: "snow",
bounds: document.body,
debug: "warn",
modules: {
toolbar: {
container: toolbarOptions,
handlers: {
"image": function (value) {
if (value) {
// iview
document.querySelector("#editorUpload" + that.index).click();
} else {
this.Quill.format("image", false);
} }
]; }
},
styles() {
let style = {};
if (this.minHeight) {
style.minHeight = `${this.minHeight}px`;
} }
if (this.height) { }
style.height = `${this.height}px`; },
} placeholder: "",
return style; readOnly: this.readonly
},
loading: false
};
},
computed: {
classes () {
return [
{
"quill-no-border": !this.border
} }
];
},
styles () {
let style = {};
if (this.minHeight) {
style.minHeight = `${this.minHeight}px`;
}
if (this.height) {
style.height = `${this.height}px`;
}
return style;
}
},
watch: {
value: {
handler (val) {
if (!this.type) {
if (val !== this.currentValue) {
this.currentValue = val;
if (this.Quill) {
this.Quill.pasteHTML(this.value);
}
}
if (!this.mdVal) this.mdVal = val
}
},
immediate: true
}
},
created () {
},
mounted () {
this.init();
//
if (this.elseRead === "true") {
let children = this.$refs.quill.children[0].style;
children.padding = "0";
children.overflow = "hidden";
children.height = "0";
children.borderTop = "0";
}
},
beforeDestroy () {
//
this.Quill = null;
},
methods: {
//
typeChange (val) {
if (!this.mdVal) this.mdVal = this.value
}, },
watch: {
value: { init () {
handler(val) { const editor = this.$refs.editor;
if (val !== this.currentValue) { //
this.currentValue = val; this.Quill = new Quill(editor, this.options);
if (this.Quill) { const ins = this.Quill
this.Quill.pasteHTML(this.value); //
} ins.pasteHTML(this.currentValue);
} if (this.toTop) {
}, this.$nextTick(() => {
immediate: true window.scrollTo(0, 0)
})
}
//
ins.on('text-change', (delta, oldDelta, source) => {
const html = this.$refs.editor.children[0].innerHTML;
const text = ins.getText();
const quill = this.Quill;
//
this.currentValue = html;
// v-model
this.$emit('input', html);
//
this.$emit('on-change', { html, text, quill });
});
// quill
ins.on('text-change', (delta, oldDelta, source) => {
this.$emit('on-text-change', delta, oldDelta, source);
});
ins.on('selection-change', (range, oldRange, source) => {
this.$emit('on-selection-change', range, oldRange, source);
});
ins.on('editor-change', (eventName, ...args) => {
this.$emit('on-editor-change', eventName, ...args);
});
//
ins.root.addEventListener('paste', evt => {
if (evt.clipboardData && evt.clipboardData.files && evt.clipboardData.files.length) {
evt.preventDefault();
//
[].forEach.call(evt.clipboardData.files, file => {
if (!file.type.match(/^image\/(gif|jpe?g|a?png|bmp)/i)) {
return
}
const param = new FormData()
param.append('file', file)
// base64
this.$post(this.api.fileupload, param, {
headers: { "Content-Type": "multipart/form-data" }
}).then(res => {
var range = ins.getSelection()
if (range) {
//
ins.insertEmbed(range.index, 'image', res.data.filesResult.fileUrl)
//
ins.setSelection(range.index + 1)
}
}).catch(res => { })
});
} }
}, false)
}, },
created() { beforeUpload (file) {
this.loading = true;
}, },
mounted() { // quill
this.init(); editorUploadSuccess (res) {
// //
if (this.elseRead === "true") { let quill = this.Quill;
let children = this.$refs.quill.children[0].style; //
children.padding = "0"; if (res.data.filesResult.fileUrl) {
children.overflow = "hidden"; //
children.height = "0"; let length = quill.getSelection().index;
children.borderTop = "0"; // res
} quill.insertEmbed(length, "image", res.data.filesResult.fileUrl);
//
quill.setSelection(length + 1);
} else {
util.successMsg("图片插入失败");
}
this.loading = false;
}, },
beforeDestroy() {
// //
this.Quill = null; mdChange (val) {
this.$emit('input', val)
}, },
methods: { // markdown
init () { imgAdd (pos, $file) {
const editor = this.$refs.editor; let $vm = this.$refs.md
// // ..
this.Quill = new Quill(editor, this.options); const formData = new FormData();
const ins = this.Quill formData.append('file', $file);
// axios({
ins.pasteHTML(this.currentValue); url: this.api.fileupload,
if(this.toTop){ method: 'post',
this.$nextTick(() => { data: formData,
window.scrollTo(0,0) headers: {
}) token: this.token,
} 'Content-Type': 'multipart/form-data'
//
ins.on('text-change', (delta, oldDelta, source) => {
const html = this.$refs.editor.children[0].innerHTML;
const text = ins.getText();
const quill = this.Quill;
//
this.currentValue = html;
// v-model
this.$emit('input', html);
//
this.$emit('on-change', { html, text, quill });
});
// quill
ins.on('text-change', (delta, oldDelta, source) => {
this.$emit('on-text-change', delta, oldDelta, source);
});
ins.on('selection-change', (range, oldRange, source) => {
this.$emit('on-selection-change', range, oldRange, source);
});
ins.on('editor-change', (eventName, ...args) => {
this.$emit('on-editor-change', eventName, ...args);
});
//
ins.root.addEventListener('paste', evt => {
if (evt.clipboardData && evt.clipboardData.files && evt.clipboardData.files.length) {
evt.preventDefault();
//
[].forEach.call(evt.clipboardData.files, file => {
if (!file.type.match(/^image\/(gif|jpe?g|a?png|bmp)/i)) {
return
}
const param = new FormData()
param.append('file', file)
// base64
this.$post(this.api.fileupload, param, {
headers: { "Content-Type": "multipart/form-data" }
}).then(res => {
var range = ins.getSelection()
if (range) {
//
ins.insertEmbed(range.index, 'image', res.data.filesResult.fileUrl)
//
ins.setSelection(range.index + 1)
}
}).catch(res => {})
});
}
}, false)
}, },
beforeUpload(file) { }).then((res) => {
this.loading = true; $vm.$img2Url(pos, res.data.data.filesResult.fileUrl);
}, })
editorUploadSuccess(res) { },
// }
let quill = this.Quill;
//
if (res.data.filesResult.fileUrl) {
//
let length = quill.getSelection().index;
// res
quill.insertEmbed(length, "image", res.data.filesResult.fileUrl);
//
quill.setSelection(length + 1);
} else {
util.successMsg("图片插入失败");
}
this.loading = false;
}
}
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.type-radio {
margin-bottom: 20px;
}
.quill-no-border { .quill-no-border {
.ql-toolbar.ql-snow { .ql-toolbar.ql-snow {
border: none; border: none;
@ -257,5 +321,10 @@ export default {
transform: translateY(10px); transform: translateY(10px);
} }
} }
.md {
max-height: 300px;
}
/deep/.v-note-wrapper .v-note-panel {
min-height: 200px;
}
</style> </style>

@ -1,14 +1,13 @@
<template> <template>
<div class="wrap"> <div class="wrap">
<el-carousel :interval="6000" <el-carousel :interval="6000"
:height="carouselHeight"> height="354px">
<template v-for="(item, i) in banners"> <template v-for="(item, i) in banners">
<el-carousel-item :key="i"> <el-carousel-item :key="i">
<div :class="['banner-item', {'cursor-pointer': item.url}]" <div :class="['banner-item', {'cursor-pointer': item.url}]"
@click="openLink(item)"> @click="openLink(item)">
<img :src="item.banner" <img :src="item.banner"
alt="" alt="">
:style="{height: carouselHeight}">
<!-- <img src="https://huoran.oss-cn-shenzhen.aliyuncs.com/20230726/png/1684091617063493632.png" <!-- <img src="https://huoran.oss-cn-shenzhen.aliyuncs.com/20230726/png/1684091617063493632.png"
alt="" alt=""
:style="{height: carouselHeight}"> --> :style="{height: carouselHeight}"> -->
@ -548,7 +547,7 @@ export default {
position: relative; position: relative;
img { img {
width: 100%; width: 100%;
height: 100%; height: 354px;
} }
.texts { .texts {
position: absolute; position: absolute;
@ -559,10 +558,10 @@ export default {
} }
h6 { h6 {
margin-bottom: 25px; margin-bottom: 25px;
font-size: 44px; font-size: 36px;
} }
.sub { .sub {
font-size: 22px; font-size: 24px;
} }
} }
.inner-wrap { .inner-wrap {
@ -749,7 +748,7 @@ export default {
} }
img { img {
width: 100%; width: 100%;
height: 140px; height: 155px;
transition: 0.3s; transition: 0.3s;
} }
.my-school { .my-school {

@ -9,23 +9,19 @@
</el-card> </el-card>
<div class="inner"> <div class="inner">
<div class="top"> <div class="top">
<div class="pics" <el-carousel class="pics"
v-if="form.mall.coverDrawing"> :interval="6000"
<el-image :class="['cover', {full: !form.interfaceDiagrams}]" height="278px"
:src="form.mall.coverDrawing" :arrow="form.pics.length > 1 ? 'hover' : 'never'"
:preview-src-list="form.pics"> :indicator-position="form.pics.length > 1 ? '' : 'none'">
</el-image> <el-carousel-item v-for="(item, i) in form.pics"
<div v-if="form.interfaceDiagrams" :key="i">
class="interface"> <el-image class="pic"
<div class="pic" :src="item"
v-for="(pic, i) in form.interfaceDiagrams" :preview-src-list="form.pics">
:key="i"> </el-image>
<el-image :src="pic" </el-carousel-item>
:preview-src-list="form.pics"> </el-carousel>
</el-image>
</div>
</div>
</div>
<div class="right" <div class="right"
id="fields"> id="fields">
<h6>{{ form.mall.productName }}</h6> <h6>{{ form.mall.productName }}</h6>
@ -224,6 +220,7 @@ export default {
}, },
], ],
form: { form: {
pics: [],
classificationIds: [], classificationIds: [],
mall: { mall: {
coverDrawing: '' coverDrawing: ''
@ -393,33 +390,12 @@ export default {
background-color: #fff; background-color: #fff;
border-radius: 10px; border-radius: 10px;
.pics { .pics {
display: flex; width: 484px;
flex-wrap: wrap;
width: 502px;
margin-right: 20px; margin-right: 20px;
.cover {
width: 370px;
height: 278px;
margin-right: 10px;
border-radius: 8px;
overflow: hidden;
&.full {
width: 100%;
}
}
.pic { .pic {
width: 114px; width: 100%;
height: 86px; height: 100%;
margin-bottom: 10px;
border-radius: 8px; border-radius: 8px;
overflow: hidden;
.el-image {
width: 100%;
height: 100%;
}
&:last-child {
margin-bottom: 0;
}
} }
} }
.right { .right {
@ -494,6 +470,8 @@ export default {
} }
} }
.tab { .tab {
position: sticky;
// top: 120px;
display: inline-flex; display: inline-flex;
margin-left: 10px; margin-left: 10px;
li { li {
@ -521,7 +499,7 @@ export default {
display: flex; display: flex;
margin-top: 20px; margin-top: 20px;
.detail { .detail {
width: 835px; width: calc(100% - 294px);
padding: 20px 24px; padding: 20px 24px;
background-color: #fff; background-color: #fff;
border-radius: 10px; border-radius: 10px;
@ -579,7 +557,7 @@ export default {
} }
} }
.products { .products {
width: 295px; width: 270px;
margin-left: 24px; margin-left: 24px;
& > h6 { & > h6 {
font-size: 14px; font-size: 14px;
@ -598,7 +576,7 @@ export default {
overflow: hidden; overflow: hidden;
img { img {
width: 100%; width: 100%;
height: 140px; height: 155px;
transition: 0.3s; transition: 0.3s;
} }
.my-school { .my-school {

@ -27,7 +27,7 @@ if (isPro) {
host = "http://121.37.12.51/"; // 中台测试服 host = "http://121.37.12.51/"; // 中台测试服
// host = 'https://www.occupationlab.com/' // 正式服 // host = 'https://www.occupationlab.com/' // 正式服
// host = "http://192.168.31.217:9000/"; // 榕 // host = "http://192.168.31.217:9000/"; // 榕
host = 'http://192.168.31.51:9000/'; // 赓 // host = 'http://192.168.31.51:9000/'; // 赓
} }
const Setting = { const Setting = {

Loading…
Cancel
Save