Commit 4a85d0ef authored by zL's avatar zL

提交部分代码

parent 02bd2d4e
......@@ -2,13 +2,13 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="./refactoring/favicon.ico">
<title>商品溯源</title>
<link rel="stylesheet" href="//at.alicdn.com/t/font_1321935_v0o359opzio.css">
<script src="https://cdn.bootcss.com/tinymce/4.7.4/tinymce.min.js"></script>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="./refactoring/favicon.ico">
<title>商品溯源</title>
<link rel="stylesheet" href="//at.alicdn.com/t/font_1321935_v0o359opzio.css">
<script src="https://cdn.bootcss.com/tinymce/4.7.4/tinymce.min.js"></script>
</head>
<body>
......@@ -17,11 +17,11 @@
continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
<style>
</style>
<script>
</script>
</html>
</html>
\ No newline at end of file
<template>
<div class="name_editor">
<input
ref="name_input_dom"
class="input_text"
type="text"
placeholder="请输入存证名称"
:readonly="!operation"
:value="value"
@input="emitChange"
maxlength="10"
@keyup.enter="$event.target.blur()"
:class="{ noMsg: value.trim().length === 0 }"
:style="getWidth"
/>
<i
class="iconfont icon_edit iconpen"
v-if="operation"
@click="startEdit"
></i>
<slot></slot>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
@Component
export default class NameEditor extends Vue {
@Prop() value!: string;
@Prop() operation!: Boolean;
public inputW: string = "177px";
get getWidth() {
return {
width: this.inputW,
};
}
@Watch("value")
public onChange(newVal: number, oldVal: number) {
if (this.value.length === 0) {
this.inputW = "177px";
} else if (localStorage.getItem("bootPage") === "show2") {
this.inputW = "240px";
} else {
this.inputW = this.value.length * 25 + "px";
}
}
created() {
this.startEdit();
}
public startEdit() {
this.$nextTick(() => {
(this.$refs.name_input_dom as HTMLInputElement).focus();
});
}
public emitChange(e: any) {
this.$emit("input", e.target.value);
}
}
</script>
<style scoped lang="less">
.name_editor {
display: inline-block;
font-size: 24px;
font-weight: 600;
}
.icon_edit {
vertical-align: middle;
margin-left: 13px;
color: #e1e1e1;
font-size: 18px;
cursor: pointer;
}
.noMsg {
caret-color: #c4c4c4;
}
.input_text {
vertical-align: middle;
color: #000;
font-family: inherit;
border: none;
padding: 0;
outline: none;
font-size: inherit;
font-weight: inherit;
background: transparent;
&::-webkit-input-placeholder {
/* WebKit browsers */
text-indent: 6px;
color: #c4c4c4;
font-size: 24px;
font-weight: 600;
color: rgba(196, 196, 196, 1);
}
&:-moz-placeholder {
text-indent: 6px;
color: #c4c4c4;
font-size: 24px;
font-weight: 600;
color: rgba(196, 196, 196, 1);
}
&::-moz-placeholder {
/* Mozilla Firefox 19+ */
text-indent: 6px;
color: #c4c4c4;
font-size: 24px;
font-weight: 600;
color: rgba(196, 196, 196, 1);
}
&:-ms-input-placeholder {
/* Internet Explorer 10+ */
text-indent: 6px;
color: #c4c4c4;
font-size: 24px;
font-weight: 600;
color: rgba(196, 196, 196, 1);
}
}
</style>
<template>
<!-- 添加一级标题组件 -->
<div class="add_level1_button" @click="$emit('click')">
<div class="button">
<i class="iconfont icontianjia button-icon"></i>
</div>
<span class="label">{{title}}</span>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
@Component
export default class AddLevel1Button extends Vue {
@Prop() title!:string;
}
</script>
<style scoped>
.add_level1_button {
display: inline-block;
cursor: pointer;
}
.button {
display: inline-block;
width: 39px;
height: 39px;
background: #15CBBA;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2);
border-radius: 50%;
color: #fff;
text-align: center;
line-height: 39px;
}
.button-icon {
font-size: 15px;
}
.label {
margin-left: 15px;
color: #15CBBA;
font-size: 14px;
line-height: 39px;
font-weight: 500;
}
</style>
<template>
<div>
<div class="title">{{item.state}}</div>
<div class="progress-bar">
<div class="progress-bar__outer">
<div class="progress-bar__inner" :style="Style" :class="{'bgw':suss}"></div>
</div>
</div>
<div class="svgbox" @click="$emit('termination')">
<!-- <svg class="icon" aria-hidden="true">
<use xlink:href="#iconshanchu4" />
</svg> -->
<i class="iconfont iconshanchu5"></i>
</div>
</div>
</template>
<script>
export default {
data() {
return {
suss: false
};
},
props: ["item"],
watch: {
item: {
handler(val, oldVal) {
if (val.speed === 100) {
val.state = "上传成功";
this.suss = true;
}
},
deep: true,
immediate: true
}
},
computed: {
Style() {
const style = {
width: this.item.speed + "%"
};
return style;
}
}
};
</script>
<style type="text/css">
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
<style lang="less" scoped>
.svgbox {
// font-size: 22px;
cursor: pointer;
float: right;
margin-left: 46px;
}
.title {
width: 56px;
font-size: 14px;
float: left;
font-weight: 500;
color: rgba(53, 53, 53, 1);
line-height: 40px;
}
.progress-bar {
display: inline-block;
vertical-align: middle;
width: 270px;
box-sizing: border-box;
.progress-bar__outer {
height: 6px;
border-radius: 100px;
background-color: #ebeef5;
overflow: hidden;
position: relative;
vertical-align: middle;
}
.progress-bar__inner {
position: absolute;
left: 0;
top: 0;
height: 100%;
background-color: #5779f4;
text-align: right;
border-radius: 100px;
line-height: 1;
white-space: nowrap;
transition: width 0.6s ease;
&::after {
display: inline-block;
content: "";
height: 100%;
vertical-align: middle;
}
}
.bgw {
background: white !important;
transition: none !important;
}
}
</style>
\ No newline at end of file
<template>
<div>
<base-form
v-if="property.type === PropertyType.Input"
:label="property.label"
:value="property.value"
@changeValue="changeValue"
:isDisabled="isDisabled"
/>
<date-form
v-else-if="property.type === PropertyType.Date"
:label="property.label"
:value="property.value"
@changeValue="changeValue"
:isDisabled="isDisabled"
/>
<select-form
v-else-if="property.type === PropertyType.Select"
:label="property.label"
@changeValue="changeValue"
:property="property"
:isDisabled="isDisabled"
/>
<image-form
v-else-if="property.type === PropertyType.Image"
:property="property"
:disable="isDisabled"
/>
<editor-form
v-else-if="property.type === PropertyType.Editor"
:property="property"
:label="property.label"
/>
<PDF-forms
v-else-if="property.type === PropertyType.File"
:property="property"
:disable="isDisabled"
/>
<video-forms
v-else-if="property.type === PropertyType.Video"
:property="property"
/>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
import { Property } from "@/plugins/types2";
import { PropertyType } from "@/plugins/types";
import ImageForm from "@/components/editTemplate/form/ImageForm.vue";
import SelectForm from "@/components/editTemplate/form/SelectForm.vue";
import PDFForms from "@/components/editTemplate/form/PDFForms.vue";
import VideoForms from "@/components/editTemplate/form/VideoForm.vue";
import BaseForm from "@/components/editTemplate/form/BaseForm.vue";
import DateForm from "@/components/editTemplate/form/DateForm.vue";
import EditorForm from "@/components/editTemplate/form/EditorForm.vue";
@Component({
components: {
BaseForm,
DateForm,
SelectForm,
ImageForm,
EditorForm,
PDFForms,
VideoForms,
},
})
export default class PropertyItem extends Vue {
// todo ui图未切分
@Prop() property!: Property;
@Prop() isDisabled!: boolean;
public PropertyType = PropertyType;
public created() {}
public changeValue(newData: any, key: string) {
this.$nextTick(() => {
const property: any = this.property;
property[key] = newData;
});
}
}
</script>
<style scoped>
</style>
<template>
<div class="root_unit" v-if="unit.title !== 'ext'">
<select-box
class="title_box"
:select="selectedItem === unit"
:check="unit.type"
@click.native="emitSelect(unit)"
draggable="false"
@del="del"
@addNextlevel="addNextlevel"
@modifyTitle="modifyTitle"
@modifyForms="modifyForms"
>
<h2 class="title">
<div class="label-text" :title="unit.title">{{ unit.title }}</div>
</h2>
</select-box>
<template v-for="(item, index) in unit.children">
<select-box
class="property_box property_box-item property_box-item1"
:class="{
'half-transparent': startN == index && isInDragging && endN > -1,
}"
:select="selectedItem === item"
@click="emitSelect(item)"
@del="del"
:show="3"
@addNextlevel="addNextlevel"
@modifyTitle="modifyTitle"
@modifyForms="modifyForms"
@dragstart="dragstart(item, index)"
@dragend="dragend()"
@dragover="dragover(item, index)"
:key="item.id"
>
<div class="blue-line-con" v-show="isInDragging && endN === index">
<div class="blue-line"></div>
</div>
<property-item class="property-item" :property="item"></property-item>
</select-box>
</template>
</div>
</template>
<script lang="ts">
import PropertyItem from "./PropertyItem.vue";
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
import SelectBox from "./SelectBox.vue";
import { Property, Unit } from "@/plugins/types2";
@Component({
components: {
PropertyItem,
SelectBox,
},
})
export default class RootUnit extends Vue {
@Prop() unit!: Unit;
@Prop() selectedItem!: Unit | Property | null;
@Prop() isDisabled!: boolean;
public emitSelect(item: Unit | Property) {
this.$emit("selected", item);
}
public Unit = Unit;
public Property = Property;
public startN: number = -1;
public endN: number = -1;
public isInDragging: boolean = false;
public created() {}
// 修改表现形式
public modifyForms() {
let that: any = this.selectedItem;
if (this.selectedItem && this.selectedItem.type === 3) {
return false;
}
if (this.selectedItem && this.selectedItem.type === 6) {
if (that.value.trim() !== "") {
that.value = this.timeFormate(that.value);
this.selectedItem = that;
}
}
this.$emit("modifyForms");
}
public timeFormate(timestamp: number) {
let date = new Date(timestamp * 1000);
let Y = date.getFullYear() + "-";
let M =
(date.getMonth() + 1 < 10
? "0" + (date.getMonth() + 1)
: date.getMonth() + 1) + "-";
let D = date.getDate() < 10 ? "0" + date.getDate() : date.getDate() + " ";
return Y + M + D;
}
public modifyTitle() {
this.$emit("modifyTitle");
}
public addNextlevel() {
this.$emit("addNextlevel");
}
public del() {
this.$emit("del");
}
// 拖放开始
dragstart(item: Unit | Property, index: number) {
this.endN = -1; //执行dragover操作时,start element才进入虚化
this.startN = index;
this.isInDragging = true;
}
// 拖动结束
dragend() {
this.isInDragging = false;
if (this.startN === this.endN || this.endN < 0) {
return false;
} else {
var Property = this.unit.children[this.startN]; //目标
this.unit.children.splice(this.endN, 0, Property);
if (this.startN > this.endN) {
this.unit.children.splice(this.startN + 1, 1);
} else if (this.startN < this.endN) {
this.unit.children.splice(this.startN, 1);
}
this.$forceUpdate();
}
}
// 进入另一个目标元素
dragover(item: Unit, index: number) {
this.endN = index;
}
dragoverExt(e: any) {}
}
</script>
<style scoped lang="less">
.title {
width: 602px; /* 620 - 18 */
padding-left: 18px;
margin: 0;
line-height: 42px;
font-size: 16px;
color: #292929;
}
.title_box {
width: 620px;
}
.unit_box {
width: 1060px; /* todo 选中效果ui未给出 */
margin-top: 10px;
padding: 10px 0;
}
.property_box {
margin-top: 10px;
width: 1170px;
}
.blue-line-con {
position: relative;
height: 1px;
}
.blue-line {
height: 1px;
background-color: #3f79fe;
width: 300px;
display: inline-block;
position: absolute;
top: 0px;
left: 50%;
transform: translate(-50%, 0);
}
.half-transparent {
opacity: 0.3;
}
</style>
<style>
.property_box-item1 .base_form:hover {
overflow: visible;
}
/*
* 二级hover下,显示item头
*/
.property_box-item1 .base_form:hover .pre-tag,
.property_box-item1 .image_form:hover .pre-tag,
.property_box-item1 .title:hover .pre-tag {
display: block !important;
}
/*
* 被选中的二级item,即使在hover状态下,也不显示item头
*/
.property_box-item1.js-select_box_active .base_form:hover .pre-tag,
.property_box-item1.js-select_box_active .image_form:hover .pre-tag,
.property_box-item1.js-select_box_active .title:hover .pre-tag {
display: none !important;
}
/*
* 即使二级item被选中,对应的三级hover下也显示item头
*/
.property_box-item1.js-select_box_active
.property_box-item2
.base_form:hover
.pre-tag,
.property_box-item1.js-select_box_active
.property_box-item2
.image_form:hover
.pre-tag,
.property_box-item1.js-select_box_active
.property_box-item2
.title:hover
.pre-tag {
display: block !important;
}
</style>
<template>
<div
class="select_box"
:class="{'js-select_box_active':select}"
@click.stop="$emit('click')"
draggable="true"
@dragstart.stop="dragstart"
@dragend.stop="dragend"
@dragover.stop="dragover"
>
<i
class="iconfont iconshezhi"
:class="{iconshezhi_right:check===3}"
v-show="select"
@click="showMenu"
></i>
<ul class="menu-change" v-show="select && isMenuShowing" @mousedown.stop>
<li class="menu-item menu-item__one" v-if="check!==3" @click.stop="modifyForms">修改表现形式</li>
<li class="menu-item menu-item__two" @click.stop="modifyTitle">修改标题</li>
<li class="menu-item menu-item__two" v-if="show!==3" @click.stop="addNextlevel">添加下一级</li>
<li class="menu-item menu-item__two" @click.stop="del">删除</li>
</ul>
<slot></slot>
<div v-show="select">
<div class="dash dash_1"></div>
<div class="dash dash_2"></div>
<div class="dash dash_3"></div>
<div class="dash dash_4"></div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
@Component
export default class SelectBox extends Vue {
isMenuShowing: boolean = false;
@Prop({ type: Boolean, required: true }) select!: boolean;
@Prop() check!: Number;
@Prop() show!: Number;
// @Prop({ type: Boolean, required: true }) show!: Boolean;
public dragstart($event: any) {
$event.dataTransfer.setData("imgInfo", $event.target.id);
this.$emit("dragstart");
}
public dragend($event: any) {
this.$emit("dragend");
}
public dragover($event: any) {
this.$emit("dragover");
}
// 修改表现形式
public modifyForms() {
this.onMenuBlur();
this.$emit("modifyForms");
}
// 修改标题
public modifyTitle() {
this.onMenuBlur();
this.$emit("modifyTitle");
}
// 添加下一级
public addNextlevel() {
this.onMenuBlur();
this.$emit("addNextlevel");
}
// 执行删除
public del() {
this.onMenuBlur();
this.$emit("del");
}
// 显示操作栏
public showMenu() {
this.isMenuShowing = true;
document.addEventListener("mousedown", this.onMenuBlur);
}
//隐藏操作栏
public onMenuBlur() {
this.isMenuShowing = false;
document.removeEventListener("mousedown", this.onMenuBlur);
}
}
</script>
<style scoped lang="less">
.menu-change {
z-index: 100; /* 避免被底部挡住 */
position: absolute;
top: 100%;
right: 50px;
margin: 0;
padding: 0;
width: 124px;
list-style: none;
background: #fff;
text-align: center;
border: 1px solid #e7e7e7;
border-radius: 2px;
// overflow: hidden;
}
.menu-item__one {
&::after {
content: "";
display: block;
position: absolute;
width: 10px;
height: 10px;
border-top: 1px solid #e7e7e7;
border-left: 1px solid #e7e7e7;
background: white;
top: -6px;
left: 70px;
transform: rotate(45deg);
}
&:hover {
background: rgba(242, 244, 246, 1);
&::after {
background: rgba(242, 244, 246, 1);
}
}
}
.menu-item {
line-height: 40px;
color: #797d84;
font-size: 14px;
cursor: pointer;
}
.menu-item__two {
&:hover {
background: rgba(242, 244, 246, 1);
}
}
.select_box {
position: relative;
box-sizing: border-box;
border: 1px solid transparent;
}
.js-select_box_active {
border: 1px dashed rgba(63, 121, 254, 0.5);
}
.iconshezhi {
color: #e6e6e6;
font-size: 24px;
margin-left: 22px;
cursor: pointer;
position: absolute;
right: 88px;
z-index: 98;
top: 50%;
transform: translateY(-50%);
}
// .iconshezhi_right{
// // right: 188px;
// }
.check {
background: rgba(63, 121, 254, 0.5);
}
.dash {
position: absolute;
width: 8px;
height: 8px;
border: 1px solid #d8d9da;
background: #fff;
}
.dash_1 {
top: -5px;
left: -5px;
}
.dash_2 {
top: -5px;
right: -5px;
}
.dash_3 {
right: -5px;
bottom: -5px;
}
.dash_4 {
left: -5px;
bottom: -5px;
}
.pre-tag {
position: absolute;
left: -30px;
top: 23px;
display: none;
}
</style>
<template>
<div class="set_bar">
<h2 class="title">修改标题名</h2>
<el-input
class="edit"
v-model="editTitle"
placeholder="请输入标题名"
:maxlength="titleLength"
@input="changeEdit"
></el-input>
<h2 class="title">设置表现形式</h2>
<ul class="menu">
<set-select-item
label="输入框"
:selected="type === PropertyType.Input"
:disabled="selectedDisabled"
@click.native="handleSelect(PropertyType.Input)"
>
<div class="menu-item-example menu-item-example_input"></div>
</set-select-item>
<set-select-item
label="下拉框"
:selected="type === PropertyType.Select"
:disabled="selectedDisabled"
@click.native="handleSelect(PropertyType.Select)"
>
<div class="menu-item-example menu-item-example_select">
<span>下拉框</span>
<i class="iconfont iconxiangxia"></i>
</div>
</set-select-item>
<set-select-item
label="上传图片"
:selected="type === PropertyType.Image"
:disabled="selectedDisabled"
@click.native="handleSelect(PropertyType.Image)"
>
<div class="menu-item-example menu-item-example_image">
<i class="iconfont iconjiahao"></i>
</div>
</set-select-item>
<set-select-item
label="日期"
:selected="type === PropertyType.Date"
:disabled="selectedDisabled"
@click.native="handleSelect(PropertyType.Date)"
>
<div class="menu-item-example menu-item-example_date">
<i class="iconfont iconxingzhuang"></i>
</div>
</set-select-item>
<set-select-item
label="上传PDF"
:selected="type === PropertyType.File"
:disabled="selectedDisabled"
@click.native="handleSelect(PropertyType.File)"
>
<div class="menu-item-example menu-item-example_up">
<i class="iconfont iconshangchuanwenjianbeifen"></i>
</div>
</set-select-item>
<set-select-item
label="上传视频"
:selected="type === PropertyType.Video"
:disabled="selectedDisabled"
@click.native="handleSelect(PropertyType.Video)"
>
<div class="menu-item-example menu-item-example_up">
<i class="iconfont iconshangchuanwenjianbeifen"></i>
</div>
</set-select-item>
<set-select-item
label="编辑器"
:selected="type === PropertyType.Editor"
:disabled="selectedDisabled"
@click.native="handleSelect(PropertyType.Editor)"
>
<div class="editor"></div>
</set-select-item>
</ul>
<div class="btn_wrapper">
<button
class="g-btn_primary"
:class="{ 'js-btn_disabled': addDisabled }"
@click="emitAddChild"
>
添加下一级
</button>
<button
class="g-btn_primary"
:class="{ 'js-btn_disabled': deleteDisabled }"
@click="emitDelete"
>
删除
</button>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
import { PropertyType } from "@/plugins/types";
import SetSelectItem from "./SetSelectItem.vue";
import { Property, Unit } from "@/plugins/types2";
@Component({
components: {
SetSelectItem,
},
})
export default class SetBar extends Vue {
@Prop() public selectTarget!: Unit | Property | null;
public PropertyType = PropertyType;
public editTitle = ``;
public titleLength = 100;
public get type() {
const target = this.selectTarget;
if (target) {
if (target instanceof Property) {
return target.type;
}
}
return PropertyType.Input;
}
@Watch("selectTarget.title")
public editTitleChange(val: string) {
if (val) {
this.editTitle = val;
}
}
@Watch("selectTarget.label")
public editLabelChange(val: string) {
if (val) {
this.editTitle = val;
}
}
public changeEdit() {
this.$nextTick(() => {
if (this.selectTarget) {
if (this.selectTarget.hasOwnProperty("title"))
(this.selectTarget as Unit).title = this.editTitle;
if (this.selectTarget.hasOwnProperty("label"))
(this.selectTarget as Property).label = this.editTitle;
}
});
}
public get selectedDisabled() {
return !(this.selectTarget && this.selectTarget instanceof Property);
}
public get addDisabled() {
const target = this.selectTarget;
const isL3 = target && (target as Property).parent;
// (target as Property).parent.parent;
return !(this.selectTarget && !isL3);
}
public get deleteDisabled() {
const target = this.selectTarget;
return !target || (target instanceof Unit && target.children.length > 0);
}
public handleSelect(val: PropertyType) {
if (this.selectedDisabled) return;
this.$emit("select-type", val);
}
public emitAddChild() {
if (this.addDisabled) {
return;
}
this.$emit("add-child");
}
public emitDelete() {
if (this.deleteDisabled) {
return;
}
this.$emit("delete");
}
}
</script>
<style type="text/css">
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
<style scoped lang="less">
.set_bar {
position: relative;
height: 100%;
padding: 0 5px;
background: #fff;
border-left: 1px solid #f0f0f0;
}
.editor {
width: 125px;
vertical-align: middle;
display: inline-block;
background: white;
vertical-align: middle;
box-sizing: border-box;
margin-left: 10px;
display: inline-block;
height: 35px;
border: 1px solid #e7e7e7;
border-radius: 4px;
color: rgba(53, 53, 53, 0.4);
font-size: 12px;
}
.edit {
width: 220px;
margin-left: 19px;
margin-top: 19px;
/deep/.el-input__inner {
height: 30px !important;
line-height: 30px !important;
font-size: 12px;
&::-webkit-input-placeholder {
/* WebKit browsers */
// color: #999;
font-size: 12px;
}
&::-moz-placeholder {
/* Mozilla Firefox 19+ */
// color: #999;
font-size: 12px;
}
}
}
.title {
margin: 0;
padding-left: 19px;
padding-top: 10px;
color: var(--base-color);
font-size: 14px;
font-weight: 400;
line-height: 44px;
border-bottom: 1px solid #f1f1f1;
}
.menu {
margin: 0;
padding: 0;
list-style: none;
}
.menu-item {
padding-left: 23px;
line-height: 35px;
font-size: 0;
margin-top: 18px; /* todo ui间距不统一,文字非对齐 */
}
.menu-item-icon_check {
vertical-align: middle;
display: inline-block;
width: 15px;
height: 15px;
border: 1px solid #d1d1d1;
border-radius: 50%;
cursor: pointer;
}
.menu-item_icon_check_active {
vertical-align: middle;
color: #50b74d;
font-size: 17px;
}
.menu-item-name {
vertical-align: middle;
display: inline-block;
width: 56px;
margin-left: 9px;
color: var(--base-color);
font-size: 14px;
}
.menu-item-name_active {
color: #4fb64c;
}
.menu-item-example {
vertical-align: middle;
box-sizing: border-box;
margin-left: 10px;
display: inline-block;
height: 35px;
border: 1px solid #e7e7e7;
border-radius: 4px;
color: rgba(53, 53, 53, 0.4);
font-size: 12px;
}
.menu-item-example_input {
width: 125px;
padding-left: 13px;
height: 25px;
background: white;
line-height: 25px;
}
.menu-item-example_select {
width: 125px;
padding: 0 5px 0 12px;
height: 25px;
line-height: 25px;
background: white;
i {
float: right;
font-size: 12px;
transform: scale(0.46);
}
}
.menu-item-example_image {
width: 25px;
height: 25px;
text-align: center;
background: white;
line-height: 23px;
font-size: 12px;
i {
font-size: 12px;
}
}
.menu-item-example_up {
width: 35px;
height: 25px;
background: rgba(255, 255, 255, 1);
border-radius: 4px;
text-align: center;
line-height: 25px;
border: 1px solid rgba(231, 231, 231, 1);
}
.menu-item-example_date {
width: 125px;
padding: 0 8px 0 12px;
height: 25px;
line-height: 25px;
background: white;
& i {
float: right;
font-size: 13px;
}
}
.btn_wrapper {
position: absolute;
right: 0;
bottom: 39px;
left: 0;
text-align: center;
& > button {
margin-top: 20px;
width: 220px;
height: 35px;
}
}
.js-btn_disabled {
background: #c5cfe8;
cursor: not-allowed;
}
</style>
<template>
<div class="set_select_item">
<template v-if="selected">
<i
class="iconfont iconxingzhuang2 icon_selected"
:class="{ 'js-selected_disable': disabled }"
></i>
<span
class="label_check label_selected"
:class="{ 'js-selected_disable': disabled }"
>{{ label }}</span
>
</template>
<template v-else>
<div class="icon_check"></div>
<span class="label_check">{{ label }}</span>
</template>
<slot></slot>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
@Component
export default class SetSelectItem extends Vue {
@Prop() public selected!: boolean;
@Prop() public label!: string;
@Prop() public disabled!: boolean;
public handleClick() {}
}
</script>
<style scoped>
.set_select_item {
padding-left: 23px;
line-height: 35px;
font-size: 0;
margin-top: 8px;
}
.icon_selected {
vertical-align: middle;
color: #15cbba;
font-size: 17px;
}
.icon_check {
vertical-align: middle;
display: inline-block;
width: 15px;
height: 15px;
border: 1px solid #d1d1d1;
border-radius: 50%;
cursor: pointer;
}
.label_check {
vertical-align: middle;
display: inline-block;
width: 56px;
margin-left: 9px;
color: var(--base-color);
font-size: 12px;
}
.label_selected {
color: #15cbba;
}
.js-selected_disable {
color: #acaab7;
}
</style>
<template>
<div class="base_form">
<div class="label">
<img class="pre-tag" src="../../../assets/images/template/pre-tag.png" />
<div class="label-text" :title="label">{{label}}</div>
</div>
<div class="input-box">
<input
class="input"
v-if="showInput"
v-model="inputValue"
@input="change"
type="text"
:placeholder="'请输入' + label"
:readonly="isDisabled"
/>
<i v-if="iconDown" class="iconfont iconxiangxia icon_down"></i>
</div>
<slot></slot>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
/**
* 以普通输入框为基础
* @author yuanzeyu
* @date 2019-05-29
* @desc
*/
@Component
export default class BaseForm extends Vue {
@Prop({ type: String, required: true }) label!: string;
@Prop({ type: String, default: `` }) value!: string;
@Prop({ type: String, default: `` }) watchValue!: string; // 用于显示的值
@Prop({ type: Boolean, default: true }) showInput!: boolean;
@Prop() isDisabled!: boolean;
@Prop({ type: Boolean, default: false }) iconDown!: boolean;
public inputValue = ``;
mounted() {
this.inputValue = this.watchValue ? this.watchValue : this.value;
}
@Watch(`watchValue`)
watchValueCb(val: any) {
this.inputValue = this.watchValue;
}
public change() {
this.$nextTick(() => {
this.$emit(`changeValue`, this.inputValue, `value`);
});
}
}
</script>
<style scoped lang="less">
.base_form {
flex-shrink: 0;
padding-left: 18px;
line-height: 65px;
height: 65px;
font-size: 0;
display: flex;
justify-content: flex-start;
align-items: center;
}
.label {
display: inline-block;
width: 150px; /* 104 - 18 */
flex-shrink: 0;
height: 44px;
cursor: pointer;
line-height: 44px;
color: #797d84; /* todo ui图颜色不一致 */
font-size: 14px;
font-weight: 300;
position: relative;
}
.label-text {
text-overflow: ellipsis;
white-space: nowrap; /*规定段落中的文本不进行换行 */
overflow: hidden;
}
.icon_down {
position: absolute;
right: 26px;
color: #b8b8b8;
font-size: 12px; /* todo ui图有空白 */
transform: scale(0.67);
cursor: pointer;
}
.input-box {
position: relative;
line-height: 65px;
}
.input {
box-sizing: border-box;
width: 800px;
flex-shrink: 0;
margin-top: 11px;
min-height: 44px;
border-radius: 4px;
border: 1px solid #e8e8e8; /* todo 边框、背景色ui图颜色不一致 */
outline: none;
padding-left: 24px;
font-size: 14px;
font-weight: 300;
color: var(--base-color);
&::-webkit-input-placeholder {
color: #bababa;
}
&::-moz-placeholder {
/* Mozilla Firefox 19+ */
color: #bababa;
}
&:-ms-input-placeholder {
/* Internet Explorer 10+ */
color: #bababa;
}
}
.pre-tag {
position: absolute;
left: -30px;
top: 14px;
display: none;
}
</style>
<template>
<div>
<div v-if="!isDisabled" class="base_form date_form">
<div class="label">
<img class="pre-tag" src="../../../assets/images/template/pre-tag.png" />
<div class="label-text" :title="label">{{label}}</div>
</div>
<el-date-picker
class="date-picker"
@change="change"
v-model="inputValue"
type="date"
placeholder="请选择日期"
></el-date-picker>
</div>
<base-form v-else :label="label" isDisabled>
<i class="iconfont iconxingzhuang icon_date"></i>
</base-form>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
import BaseForm from "./BaseForm.vue";
@Component({
components: {
BaseForm
}
})
export default class DateForm extends Vue {
@Prop() label!: string;
@Prop() isDisabled!: boolean;
@Prop() value!: string;
public inputValue: Date | string = ``;
mounted() {
// if ((new Date(Number(this.value + "000")))==='Invalid Date') {
// }
if (this.value) {
if (this.isValidDate(new Date(Number(this.value + "000")))) {
this.inputValue = new Date(Number(this.value + "000"));
} else {
this.inputValue = "";
}
} else {
this.inputValue = "";
}
}
public isValidDate(date: any) {
return date instanceof Date && !isNaN(date.getTime());
}
public change() {
this.$nextTick(() => {
let date = new Date(this.inputValue);
let t: string = String(date.valueOf());
this.$emit(`changeValue`, t.substring(0, t.length - 3), `value`);
});
}
}
</script>
<style scoped lang="less">
.base_form {
position: relative;
padding-left: 18px;
line-height: 65px;
height: 65px;
font-size: 0;
display: flex;
justify-content: flex-start;
align-items: center;
}
.label {
display: inline-block;
width: 150px; /* 104 - 18 */
flex-shrink: 0;
height: 44px;
line-height: 44px;
color: #797d84; /* todo ui图颜色不一致 */
font-size: 14px;
font-weight: 300;
position: relative;
}
.label-text {
text-overflow: ellipsis;
white-space: nowrap; /*规定段落中的文本不进行换行 */
overflow: hidden;
}
.date-picker {
width: 800px;
flex-shrink: 0;
/deep/.el-input__inner {
padding-left: 22px;
height: 44px;
// color: #e8e8e8;
&:focus {
border-color: #dcdfe6 !important;
}
}
/deep/.el-input__prefix {
position: absolute;
top: 0;
left: 750px;
text-align: center;
height: 100%;
color: #c0c4cc;
}
}
.icon_date {
color: #8a8a8a;
position: absolute;
right: 24px;
}
.pre-tag {
position: absolute;
left: -30px;
top: 14px;
display: none;
}
</style>
<template>
<div>
<div class="base_form">
<div class="label">
<img
class="pre-tag"
src="../../../assets/images/template/pre-tag.png"
/>
<div class="label-text" :title="label">{{ label }}</div>
</div>
<tinymce
@input="getContent"
:value="richTextValue"
class="tinymce"
></tinymce>
</div>
</div>
</template>
<script>
import tinymce from "@/views/template/tinymce.vue";
export default {
// 引入组件
components: {
tinymce,
},
props: ["label", "property"],
data() {
return {
richTextValue: "",
};
},
mounted() {
this.richTextValue = this.property.value;
},
computed: {},
methods: {
getContent(val) {
// this.richTextValue = val;
this.property.value = val;
},
},
};
</script>
<style scoped lang="less">
/deep/.mce-resizehandle {
display: none;
}
.base_form {
position: relative;
padding-left: 18px;
height: 480px;
font-size: 0;
display: flex;
justify-content: flex-start;
}
.tinymce {
width: 800px;
height: 300px;
margin: 0;
margin-top: 20px;
}
.label {
display: inline-block;
width: 150px; /* 104 - 18 */
flex-shrink: 0;
height: 44px;
line-height: 480px;
color: #797d84; /* todo ui图颜色不一致 */
font-size: 14px;
font-weight: 300;
position: relative;
}
.label-text {
text-overflow: ellipsis;
white-space: nowrap; /*规定段落中的文本不进行换行 */
overflow: hidden;
}
.pre-tag {
position: absolute;
left: -30px;
top: 14px;
display: none;
}
</style>
<template>
<div class="image_form">
<div class="label">
<img class="pre-tag" src="../../../assets/images/template/pre-tag.png" />
<div class="label-text" :title="property.label">{{property.label}}</div>
</div>
<div
class="form_icon_require"
:class="{'js-form_icon_require_empty':imageInfo.imgList.length===0}"
>*</div>
<div class="content_wrapper">
<div class="list_wrapper">
<div class="list-items">
<div class="list-item" v-for="(item, index) in imageInfo.imgList" :key="index">
<img class="list-item-img" :src="item.url||item.dataUrl" />
<i class="iconfont iconshanchu3" @click="deleteimg(item,index)"></i>
</div>
<div class="add_wrapper">
<div class="content-upload_box" @click="showSelectFile">
<i class="iconfont iconjiahao"></i>
</div>
</div>
</div>
</div>
</div>
<input ref="inputDom" type="file" accept="image/jpeg, image/png" @change="fileChange" hidden />
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
import { ImageInfo } from "@/utils/app/AddProductTypes";
import { Property } from "@/plugins/types2";
import { GO_URLS } from "@/config/URLS";
@Component
export default class ImageForm extends Vue {
@Prop({ type: Boolean, default: false }) disable!: boolean;
@Prop() property!: Property;
public imageInfo: any = {
imgList: [],
};
mounted() {
if (!Array.isArray(this.property.value)) return;
this.property.value.forEach((url) => {
this.PushList(url);
});
}
@Watch(`imageInfo.imgList`)
imageInfoChange() {
this.property.value = this.imageInfo.imgList;
}
public async PushList(url: any) {
if (!url) return false;
this.imageInfo.imgList.push({
url: await this.requestPictures(url.value),
hash: url.value, //同时保存hash
});
}
// 图片替换
public async requestPictures(string: string) {
const res = await this.$ajax({
type: "post",
url: GO_URLS.getFiles,
params: { hashes: [string] },
});
if (res) {
return res.data.files[0].url;
}
}
public showSelectFile() {
if (this.disable) {
return;
}
if (this.imageInfo.imgList.length > 10) {
return;
}
(this.$refs.inputDom as any).click();
}
// 删除图片
deleteimg(item: any, index: number) {
this.imageInfo.imgList.splice(index, 1);
}
public fileChange(e: any) {
const file: File = e.target.files[0];
if (!file) {
return;
}
const fr = new FileReader();
fr.onload = (event: any) => {
this.imageInfo.imgList.push({
url: "",
dataUrl: event.target.result,
file,
hash: "",
});
};
fr.readAsDataURL(file);
e.target.value = null;
}
}
</script>
<style scoped lang="less">
.image_form {
flex-shrink: 0;
position: relative;
padding-top: 10px;
padding-left: 18px;
padding-bottom: 10px;
font-size: 0;
display: flex;
justify-content: flex-start;
// align-items: center;
}
.label {
display: inline-block;
width: 150px; /* 104 - 18 */
height: 44px;
line-height: 44px;
color: #797d84; /* todo ui图颜色不一致 */
font-size: 14px;
font-weight: 300;
position: relative;
}
.label-text {
text-overflow: ellipsis;
flex-shrink: 0;
white-space: nowrap; /*规定段落中的文本不进行换行 */
overflow: hidden;
}
.content_wrapper {
flex: 1;
display: flex;
}
.list_wrapper {
width: 452px;
}
.add_wrapper {
margin-right: 10px;
float: left;
}
.list-items {
float: left;
}
.content-upload_box {
width: 80px;
height: 80px;
border-radius: 4px;
border: 1px solid rgba(215, 215, 215, 1);
text-align: center;
line-height: 80px;
.iconjiahao {
font-size: 24px;
color: #d7d7d7;
}
}
// 图片
.list-item {
float: left;
margin-right: 10px;
margin-bottom: 10px;
width: 80px;
height: 80px;
background: rgba(216, 216, 216, 1);
border-radius: 4px;
text-align: center;
position: relative;
.list-item-img {
width: 100%;
height: 100%;
border-radius: 4px;
border: 1px solid #d7d7d7;
overflow: hidden;
}
.iconshanchu3 {
position: absolute;
right: -10px;
font-size: 18px;
top: -10px;
cursor: pointer;
}
}
.form_icon_require {
position: absolute;
left: -10px;
top: 0;
color: #ff6565;
font-size: 14px;
line-height: 44px;
display: none;
}
.pre-tag {
position: absolute;
left: -30px;
top: 14px;
display: none;
}
</style>
<template>
<div class="base_form">
<div class="label">
<img class="pre-tag" src="../../../assets/images/template/pre-tag.png" />
<div class="label-text" :title="label">{{label}}</div>
</div>
<!-- 显示区域 -->
<div v-if="pdfSHOW">
<div class="up" @click="upFile">
<i class="iconfont iconpdf"></i>
上传PDF
</div>
<div class="show" v-for="(item,index) in localObjects" :key="index">
<i class="iconfont iconpdf-"></i>
<p @click="openPDF(item)">{{item.name}}</p>
<i class="iconfont iconshanchu2" @click="deletePDF(index)"></i>
</div>
</div>
<!-- 上传区域 -->
<div class="upload-area" @click="upFile" v-else>
<i class="iconfont iconpdf icon"></i>
<p>上传PDF</p>
<p>大小不大于10M</p>
</div>
<input type="file" hidden ref="inputDom" accept="application/pdf" @change="fileChange" />
</div>
</template>
<script>
import { GO_URLS } from "@/config/URLS";
export default {
data() {
return {
label: "", // 标题
pdfURL: "",
pdfSHOW: false,
localObjects: [], // 本地展示用
localHash: [], // 本地hash
};
},
props: ["property"],
mounted() {
// 初始化标题
this.label = this.property.label;
// 数据回显
if (this.property.value.length > 0) {
this.pdfSHOW = true;
// console.log(this.property);
let hashes = [];
for (let index = 0; index < this.property.value.length; index++) {
const element = this.property.value[index];
hashes.push(element.value);
// this.getVideos();
// console.log(hashes);
}
if (hashes.length === this.property.value.length) {
this.getPDF(hashes);
}
// this.getPDF(this.property.value);
}
},
watch: {
property: {
//深度监听
handler(val, oldVal) {
// 标题修改后对应的修改
this.label = val.label;
},
deep: true,
},
localHash: {
handler(newV, oldV) {
this.property.value = newV;
if (newV.length > 0) {
this.pdfSHOW = true;
}
},
deep: true,
},
},
methods: {
upFile() {
this.$refs.inputDom.click();
},
async fileChange(e) {
const file = e.target.files[0];
if (!file) return;
if (file.size > 10485760) {
this.$message({
message: "上传文件超过最大限制",
type: "warning",
});
return;
}
const formData = new FormData();
formData.append("file_data", file);
const res = await this.$ajax({
type: "post",
url: GO_URLS.upload + `?file_type=pdf`,
params: formData,
});
if (res) {
// 上传成功
this.$message({
message: "上传成功",
type: "success",
});
this.localHash.push(res.data.hash);
this.pdfSHOW = true;
this.localObjects.push(res.data);
}
},
// 获取pdf文件
async getPDF(hashes) {
const data = await this.$ajax({
type: "post",
params: { hashes },
url: GO_URLS.getFiles,
});
if (data) {
this.localObjects = data.data.files;
for (let index = 0; index < data.data.files.length; index++) {
const element = data.data.files[index];
this.localHash.push(element.hash);
}
}
},
// 打开pdf文件
openPDF(item) {
window.open(item.fileUrl);
},
// 删除pdf
deletePDF(index) {
this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
this.localHash.splice(index, 1);
this.localObjects.splice(index, 1);
this.$message({
type: "success",
message: "删除成功!",
});
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除",
});
});
},
},
};
</script>
<style lang="less" scoped>
.base_form {
flex-shrink: 0;
padding-left: 18px;
font-size: 0;
padding-top: 10px;
padding-bottom: 10px;
display: flex;
justify-content: flex-start;
}
.label {
display: inline-block;
width: 150px;
flex-shrink: 0;
cursor: pointer;
color: #797d84;
line-height: 44px;
font-size: 14px;
font-weight: 300;
position: relative;
}
.pre-tag {
position: absolute;
left: -30px;
top: 14px;
display: none;
}
.label-text {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.upload-area {
width: 151px;
height: 89px;
border-radius: 4px;
border: 1px dashed #e5e5e5;
text-align: center;
padding-top: 10px;
cursor: pointer;
.icon {
font-size: 32px;
color: #797d84;
}
p {
margin: 0;
padding: 0;
padding-top: 8px;
font-size: 12px;
font-weight: 400;
color: rgba(121, 125, 132, 1);
&:last-child {
font-size: 10px;
padding-top: 2px;
color: rgba(152, 159, 165, 1);
}
}
}
.show {
line-height: 1;
cursor: pointer;
padding-top: 20px;
padding-bottom: 4px;
&:hover {
.iconshanchu2 {
display: inline-block;
}
}
.icon {
font-size: 16px;
}
p {
font-size: 12px;
margin: 0;
display: inline-block;
padding: 0;
padding-left: 4px;
font-weight: 400;
color: rgba(63, 121, 254, 1);
}
.iconshanchu2 {
display: none;
}
i {
color: rgba(63, 121, 254, 1);
padding-left: 10px;
font-size: 12px;
}
}
.up {
width: 151px;
height: 36px;
cursor: pointer;
border-radius: 4px;
border: 1px dashed rgba(229, 229, 229, 1);
font-size: 12px;
font-weight: 400;
text-align: center;
line-height: 36px;
color: rgba(121, 125, 132, 1);
.icon {
font-size: 14px;
padding-right: 6px;
}
}
</style>
\ No newline at end of file
<template>
<base-form
:label="label"
:watchValue="property.value"
@click.native="showOptions"
:isDisabled="true"
:iconDown="true"
>
<ul v-if="selectShowing" class="menu" @click.stop @mousedown.stop>
<li v-for="(item, index) in property.options" class="menu-item" :key="item.id">
<input
class="menu-item-input"
v-model="property.options[index]"
type="text"
placeholder="请输入下拉内容"
@click="chooseLabel(index)"
/>
<i v-if="index===0" class="iconfont icontianjiafenlei menu-item-icon_add" @click="addOptions"></i>
<i
v-else
class="iconfont iconshanchu2 menu-item-icon_delete"
@click.stop="deleteOption(index)"
></i>
</li>
</ul>
</base-form>
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
import BaseForm from "./BaseForm.vue";
import { Property } from "@/plugins/types2";
import { getUuid } from "@/utils/tool";
/**
* 选项表单项
* @author yuanzeyu
* @date 2019-05-29
* @desc
*/
@Component({
components: {
BaseForm
}
})
export default class SelectForm extends Vue {
// todo 需求ui未给清,已第一行显示添加按钮实现,第一行删不了,无查重和必填
@Prop() label!: string;
@Prop() property!: Property;
@Prop() isDisabled!: boolean;
public selectShowing: boolean = false;
created() {}
public addOptions() {
this.property.options.push("");
}
public deleteOption(index: number) {
this.property.options.splice(index, 1);
}
chooseLabel(index: number) {
if (index === 0 || this.isDisabled || this.property.options[index] === ``)
return;
this.$emit(`changeValue`, this.property.options[index], `value`);
this.onHindOptions();
}
// 展开ul
public showOptions() {
this.selectShowing = true;
this.property.options.unshift("");
document.addEventListener("mousedown", this.onHindOptions);
}
public onHindOptions() {
this.property.options = this.property.options.filter(
item => item.length > 0
);
this.selectShowing = false;
document.removeEventListener("mousedown", this.onHindOptions);
}
}
</script>
<style scoped lang="less">
.menu {
z-index: 1;
position: absolute;
top: 64px; /* (65 - 44)/2 + 44 + 9 */
left: 168px;
width: 800px;
flex-shrink: 0;
background: #fff;
margin: 0;
padding: 0;
box-shadow: 0 0 0 1px rgba(224, 231, 238, 1);
border-radius: 5px;
list-style: none;
}
.menu-item {
height: 46px;
line-height: 46px;
&:not(:last-child) {
border-bottom: 1px solid #e0e7ee;
}
}
.menu-item:hover {
background: #f2f2f2;
}
.menu-item-input {
vertical-align: top;
box-sizing: border-box;
width: 760px;
padding: 0 15px;
border: none;
background: transparent;
line-height: 46px;
font-size: 13px;
color: var(--base-color); /* todo ui未给出输入后效果 */
outline: none;
&::placeholder {
color: #8796a8;
}
}
.menu-item-icon_add {
color: var(--normal-blur);
font-size: 14px; /* todo ui选区错误 */
cursor: pointer;
}
.menu-item-icon_delete {
color: #c5cfe8;
font-size: 15px;
cursor: pointer;
}
</style>
<template>
<div class="base_form">
<div class="label">
<img class="pre-tag" src="../../../assets/images/template/pre-tag.png" />
<div class="label-text">{{ property.label }}</div>
</div>
<div>
<div class="upload" @click="upFile">
<i class="iconfont iconshangchuanwenjianbeifen"></i>&nbsp;&nbsp;上传视频
</div>
<ul class="list">
<li v-for="(item, index) in locaVideos" :key="index">
<div class="video-file">
<div class="svgbox">
<i class="iconfont iconbofanganniu"></i>
</div>
{{ item.name }}
</div>
<Progress
class="left"
:item="item"
@termination="termination(index)"
></Progress>
</li>
</ul>
</div>
<input
type="file"
hidden
ref="inputDom"
accept="video/mp4"
@change="fileChange"
/>
</div>
</template>
<script>
// 进度条组件
import { getLoginCode } from "@/plugins/storage";
import Progress from "../Progress.vue";
import { GO_URLS } from "@/config/URLS";
let xhr;
export default {
data() {
return {
// label: "", // 标题,
hashList: [], // 用于存证的hash
locaVideos: [], // 本地展示用
Speed: { Result: "上传中", num: 0 },
isFlag: true,
};
},
props: ["property"],
components: {
//组件
Progress,
},
watch: {
hashList: {
handler(newV, oldV) {
this.property.value = newV;
},
deep: true,
},
},
created() {
// 初始化标题
// this.label = this.property.label;
// 数据回显
if (this.property.value.length > 0 && this.isFlag) {
this.isFlag = false;
let hashes = [];
for (let index = 0; index < this.property.value.length; index++) {
const element = this.property.value[index];
hashes.push(element.value);
// this.getVideos();
}
if (hashes.length === this.property.value.length) {
this.getVideos(hashes);
}
}
},
methods: {
// 获取已有数据
async getVideos(hashes) {
let res = await this.$ajax({
type: "post",
params: { hashes },
url: GO_URLS.getFiles,
});
if (res) {
this.locaVideos = [];
this.hashList = [];
for (let index = 0; index < res.data.files.length; index++) {
const element = res.data.files[index];
this.locaVideos.push({
name: element.name,
state: "上传成功",
speed: 100,
});
this.hashList.push(element.hash);
}
}
// this.localObjects = data.data;
},
// 删除当前视频||终止上传
termination(index) {
if (xhr) {
xhr.abort();
}
this.hashList.splice(index, 1);
this.locaVideos.splice(index, 1);
},
//
upFile() {
this.$refs.inputDom.click();
},
// 视频上传
fileChange(e) {
const file = e.target.files[0];
if (!file) return;
if (file.type && file.type.indexOf("video/") >= 0) {
// file.size单位为字节B
if (file.size > 20971520) {
this.$message({
message: "上传视频超过最大限制",
type: "warning",
});
return;
}
e.target.value = "";
this.UpladFile(file);
} else {
this.$message({
message: "请上传视频文件",
type: "warning",
});
}
},
// 请求拆分
UpladFile(file) {
const formData = new FormData();
formData.append("file_data", file);
var url = "";
url = GO_URLS.upload + `?file_type=mp4`;
xhr = new XMLHttpRequest();
xhr.open("post", url, true);
//设置请求头参数
let token = "Bearer " + getLoginCode();
// let UrlPrefixObj = require("../../../../config/UrlPrefix");
// xhr.setRequestHeader("platform", UrlPrefixObj.model.PLATFORM_ID);
xhr.setRequestHeader("Authorization", token);
// Authorization:
xhr.onload = this.uploadComplete; //请求完成、
xhr.onerror = this.uploadFailed; //请求失败
var that = this; // 防止xhr改变this指向
xhr.upload.onprogress = function (event) {
if (event.lengthComputable) {
const state = that.locaVideos.some((item) => item.name === file.name);
if (state) {
// 存在
for (let index = 0; index < that.locaVideos.length; index++) {
if (that.locaVideos[index].name === file.name) {
that.locaVideos[index].speed =
(event.loaded / event.total) * 100;
}
}
return;
}
that.locaVideos.push({
name: file.name,
state: "上传中",
speed: (event.loaded / event.total) * 100,
});
}
};
xhr.send(formData);
},
// 请求完成
uploadComplete(xhr) {
//服务断接收完文件返回的结果
this.hashList.push(JSON.parse(xhr.target.response).data.hash);
},
// 失败回调
uploadFailed(xhr) {
//上传失败
},
},
};
</script>
<style type="text/css">
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
<style lang="less" scoped>
.base_form {
flex-shrink: 0;
padding-left: 18px;
font-size: 0;
padding-top: 10px;
padding-bottom: 10px;
display: flex;
justify-content: flex-start;
}
.label {
display: inline-block;
width: 150px;
flex-shrink: 0;
cursor: pointer;
color: #797d84;
line-height: 44px;
font-size: 14px;
font-weight: 300;
position: relative;
}
.pre-tag {
position: absolute;
left: -30px;
top: 14px;
display: none;
}
.label-text {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.upload {
width: 151px;
line-height: 36px;
text-align: center;
color: white;
font-size: 12px;
background: rgba(87, 121, 244, 1);
cursor: pointer;
border-radius: 4px;
}
.video-file {
font-size: 14px;
float: left;
// margin-right: 400px;
}
.svgbox {
// font-size: 22px;
margin-right: 6px;
float: left;
color: rgba(87, 121, 244, 1);
}
.list {
margin: 0;
margin-top: 20px;
padding: 0;
li {
line-height: 40px;
width: 800px;
overflow: hidden;
}
}
.left {
float: right;
}
</style>
\ No newline at end of file
......@@ -63,6 +63,18 @@ let router = new Router({ // todo 移除旧页面
name: 'personVerify',
component: () => import(/* webpackChunkName: "personVerify" */ '@/views/userCenter/PersonVerify.vue')
},
{
path: '/templateManage',
name: 'templateManage',
component: () => import(/* webpackChunkName: "templateManage" */ '@/views/template/Index.vue'),
children: [
{
path: '/editTemplate',
name: 'editTemplate',
component: () => import(/* webpackChunkName: "editTemplate" */ '@/views/template/editTemplate.vue'),
}
]
}
]
}
// {
......@@ -74,11 +86,7 @@ let router = new Router({ // todo 移除旧页面
// // name: 'templateManage',
// // component: () => import(/* webpackChunkName: "templateManage" */ '../refactoring/views/template/Index.vue'),
// // children: [
// // {
// // path: '/editTemplate',
// // name: 'editTemplate',
// // component: () => import(/* webpackChunkName: "editTemplate" */ '../refactoring/views/template/editTemplate.vue'),
// // }
// // // {
// // // path: '/viewTemplate',
// // // name: 'viewTemplate',
......
import {
PropertyType,
RootUnit as RootUnitType,
TmplSelectProperty,
TemplateProperty,
UnitProperty,
} from "./types";
import { Property, Unit } from "./types2";
/**
* 将本地模板转换为接口json
* @param local
*/
export function formatApiJson(local: Unit[]): RootUnitType[] {
return local.map((unit) => {
return {
data: unit.children.map((item) => formatL2Local2Api(item)),
type: 3,
key: '',
label: unit.title
};
});
}
/**
* 将本地的二级字段转换为接口二级字段
* @param localL2
*/
function formatL2Local2Api(localL2: Property | Unit): TemplateProperty | TmplSelectProperty | UnitProperty {
if (localL2 instanceof Property) {
return formatProperty2Api(localL2);
} else {
const children = localL2.children as Property[];
return {
key: '',
type: PropertyType.Unit,
// label: localL2.title,
value: children.map((l3) => formatProperty2Api(l3))
};
}
}
function formatProperty2Api(property: Property): TemplateProperty | TmplSelectProperty | any {
if (property.type === PropertyType.Select) {
return {
key: property.key,
type: PropertyType.Select,
label: property.label,
options: property.options,
data: {
type: "text",
format: "string(string, html, json, base64)",
value: property.value,
},
};
} else if (property.type === PropertyType.Image) {
// let urls = null;
let data = {}
if (property.value && property.value !== '') {
let dd = Array.from(property.value);
// urls = (property.value as any).map((value: any) => value.url)
data = dd.map((value: any) => ({
format: "hash(hash)",
type: "image",
value: value.hash || ''
}))
}
else {
// urls = [];
data = {}
}
return {
key: property.key,
type: (property.type as PropertyType.Image),
data: data,
label: property.label
};
} else if (property.type === PropertyType.File) {
let data = {}
if (property.value) {
let dd = Array.from(property.value);
data = (dd as any).map((value: any) => ({
format: "hash(hash)",
type: "file",
value: value
}))
}
else {
data = {}
}
return {
key: property.key,
type: (property.type as PropertyType.File),
data: data,
label: property.label
};
} else if (property.type === PropertyType.Input) {
// 针对扩展数据ext做保留key的处理
return {
data: {
format: "string",
type: "text",
value: property.value
},
type: PropertyType.Input,
key: property.parent.title === 'ext' ? property.label : property.key,
label: property.label
};
} else if (property.type === PropertyType.Date) {
return {
data: {
format: "utc",
type: "date",
value: property.value
},
type: PropertyType.Date,
key: property.key,
label: property.label
};
} else if (property.type === PropertyType.Video) {
let data = {}
if (property.value) {
let dd = Array.from(property.value);
data = (dd as any).map((value: any) => ({
format: "hash(hash)",
type: "media",
value: value
}))
}
else {
data = {}
}
return {
key: property.key,
type: (property.type as PropertyType.Video),
data: data,
label: property.label
};
}
//Video
else {
return {
data: {
format: "string",
type: "text",
value: property.value
},
type: (property.type as PropertyType.Image),
key: property.key,
label: property.label
};
}
}
// 接口json数据转换为本地
export function formatTemplateApi2Local(apiList: RootUnitType[]): Unit[] {
return apiList.map((rootUnit) => {
const unit = new Unit(rootUnit.label);
unit.children = rootUnit.data.map((l2) => {
return formatApiProperty2Local(l2, unit);
// }
})
return unit;
})
}
// 接口json数据转换为本地
function formatApiProperty2Local(property: any, parent: Unit): Property {
const local = new Property(property.label, property.key, parent, property.type, property.value, property.data);
if (property.type === PropertyType.Select) {
local.options = (property.options || [])
} else if (property.type === PropertyType.Image) {
local.value = property.data
} else if (property.type === PropertyType.File) {
local.value = property.data
} else if (property.type === PropertyType.Video) {
local.value = property.data
}
return local;
}
export interface RootUnit { // 一级单元
key: string;
data: Array<TemplateProperty | TmplSelectProperty | UnitProperty>;
type?: number;
label:string
}
export enum PropertyType {
None = -1,
Input = 0, //文本输入
Image = 1, //图片
File = 2, //文件
Unit = 3, // 有下级
Select = 5, //选择
Date = 6, //时间戳
Editor = 7, //编辑器
Video = 8
}
//to showstatus
interface Property {
key: string;
type: PropertyType;
}
/**
* 普通字段
*/
export interface TemplateProperty extends Property {
type: PropertyType.Image;
value: string | Array<string>;
}
export interface TemInputProperty extends Property {
type: PropertyType.Input | PropertyType.Date ;
value: string;
data: object
}
/**
* 下拉选项字段(单选)
*/
export interface TmplSelectProperty extends Property {
type: PropertyType.Select;
options: string[];
value: string | Array<string>;
}
/**
* 单元字段
*/
export interface UnitProperty extends Property {
type: PropertyType.Unit;
// label:any;
value: Array<TemplateProperty | TmplSelectProperty>; // 包含的子字段数组
}
import { PropertyType } from "@/plugins/types";
import { getUuid } from "@/utils/tool";
export class Unit {
public id: string;
public title: string;
public children: Array<Property | Unit>;
public parent: Unit | null;
public type: PropertyType = PropertyType.Unit;
constructor(title: string, parent?: Unit) {
this.id = getUuid();
this.title = title;
this.children = [];
this.parent = parent || null;
}
/**
* 添加一个输入框子字段
*/
public addInputChildren(label: string) {
this.children.push(new Property(label, '', this));
}
/**
* 将子属性改为单元
*/
public changeChild2Unit(child: Property): Unit {
const index = this.children.indexOf(child);
const newUnit = new Unit(child.label, this);
this.children.splice(index, 1, newUnit);
return newUnit;
}
}
/**
* 属性
*/
export class Property {
public id: string;
public label: string;
public key: string;
public type: PropertyType;
public options: string[]; // todo 非下拉选项时冗余
public value: string | Array<string>;
public parent: Unit;
public data?: {
value: string
};
// public data: any
constructor(label: string, key: string, parent: Unit, type: PropertyType = PropertyType.Input, value: string | Array<string> = ``, data?: { value: string }) {
this.id = getUuid();
this.label = label;
this.key = key;
this.type = type;
this.options = [];
this.parent = parent;
this.value = ``;
if (Object.prototype.toString.call(value) === `[object Array]`) {
if (!(value.length !== 0 && Object.prototype.toString.call(value[0]) === `[object Object]`)) {
this.value = value;
}
} else {
if (data && data.value) {
this.value = data.value;
} else {
this.value = String(value);
}
}
}
}
export interface ResBase {
code: number;
data: any;
message: string;
}
export interface ResUploadFiles extends ResBase {
data: FileItem[];
}
export interface FileItem {
hash: string;
name: string;
type: string;
url: string;
update_time: number;
create_time: number
}
\ No newline at end of file
import { PropertyType } from "@/plugins/types";
export interface RootUnitItem { // 一级单元
id: string;
title: string;
children: Array<UnitItem | PropertyItem>;
}
export interface UnitItem { // 二级单元项
id: string;
type: PropertyType.Unit;
info: UnitInfo;
}
export interface UnitInfo {
title: string;
children: PropertyItem[];
}
export interface PropertyItem { // 属性项
id: string;
type: PropertyType;
info: AllProperty;
}
export type AllProperty = InputInfo | SelectInfo | DateInfo | ImageInfo;
export interface InputInfo extends PropertyItem {
label: string;
type: PropertyType.Input;
value: string;
}
export interface SelectInfo {
label: string;
value: string;
options: string[];
}
export interface Option {
id: string;
label: string;
}
export interface DateInfo {
label: string;
value: string;
}
export interface ImageInfo {
label: string;
imgList: ImageItem[];
}
export interface ImageItem {
url: string;
dataUrl: string;
file: File | null;
}
import QRCode from 'qrcode';
import { Notification } from 'element-ui';
import { Message } from 'element-ui';
import { CHAIN_BROWSER_URL } from "@/config/URLS";
function getChainBrowserUrl(hash: string): string {
......@@ -39,6 +39,7 @@ export async function downloadQrCode(hash: string) {
document.body.removeChild(a);
})
.catch(() => {
Notification.error('生成二维码失败');
// Notification.error('');
Message.error('生成二维码失败');
});
}
<template>
<router-view/>
</template>
<script>
export default {
name: 'templateManage'
}
</script>
This diff is collapsed.
This diff is collapsed.
<template>
<div class="body">
<div class="body-top">
<span class="body-top__left" @click="returnTemplate('Return')"
>返回模板</span
>
预览
<span class="body-top__right" @click="returnTemplate('Use')">使用</span>
</div>
<!-- 预览部分 -->
<div class="body-center">
<root-unit v-for="item in templateInfo" :unit="item" :key="item.id" />
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";
import { GO_URLS } from "@/config/URLS";
import { Unit } from "@/plugins/types2";
// 取本地数据转换函数
import { formatTemplateApi2Local } from "@/plugins/Template";
import RootUnit from "@/views/template/AddTemplate/RootUnit.vue";
@Component({
components: {
RootUnit,
},
})
export default class preview extends Vue {
@Prop({ type: Number, default: 0 }) systemTemplateId!: 0;
@Prop({ type: Boolean, default: true }) isActive!: boolean;
public templateInfo: Unit[] = [];
// 周期函数
public created() {
this.obtainTemplateInformation();
// if (this.systemTemplateId) {
// this.templateInfo = formatTemplateApi2Local(JSON.parse(this.detail));
// }
}
// 返回模板
public returnTemplate(val: string) {
this.$emit("returnTemplate", val);
}
// 查询模板
public async obtainTemplateInformation() {
// 获取个人模板||获取系统模板
// let url = "";
// if (this.isActive) {
// url = URLS.SYS_TMPL_GET;
// } else {
// url = URLS.TEMPLATE_DETAIL;
// }
const data = await this.$ajax({
type: "get",
params: {
id: this.systemTemplateId,
},
url: GO_URLS.getSystemTemplate,
});
if (data && data.data.detail) {
this.templateInfo = formatTemplateApi2Local(JSON.parse(data.data.detail));
}
}
}
</script>
<style lang="less" scoped>
/deep/.root_unit {
pointer-events: none;
.input-box {
input {
width: 500px;
}
}
.date-picker {
width: 500px;
}
}
.body {
width: 932px;
height: 640px;
background: rgba(255, 255, 255, 1);
border-radius: 10px;
// pointer-events: none;
.body-top {
height: 68px;
line-height: 68px;
text-align: center;
border-bottom: 1px solid #e9e9e9;
font-size: 22px;
font-weight: 500;
color: rgba(53, 53, 53, 1);
.body-top__right,
.body-top__left {
width: 90px;
height: 40px;
background: rgba(239, 239, 239, 1);
border-radius: 4px;
line-height: 40px;
font-size: 14px;
text-align: center;
font-weight: 400;
color: rgba(41, 41, 41, 1);
margin-top: 14px;
cursor: pointer;
}
.body-top__left {
float: left;
margin-left: 24px;
}
.body-top__right {
float: right;
margin-right: 24px;
}
}
.body-center {
height: 571px;
width: 100%;
// pointer-events: none;
border-radius: 0 0 10px 10px;
overflow-y: auto;
padding-left: 18px;
padding-top: 20px;
}
}
</style>
\ No newline at end of file
<template>
<div class="body">
<ul>
<li v-for="(item,index) in List" :key="index">
<!-- 一级标题 -->
<h1 class="title">{{item.label}}</h1>
<!-- 普通展示模式 -->
<div class="info" v-for="(item2,index2) in item.data" :key="index2">
<!-- 二级>子级 -->
<div class="info-title">{{item2.label}}</div>
<!-- 文本 -->
<div class="info-content" v-if="item2.type===0">{{item2.data.value}}</div>
<!-- 选择器 -->
<div class="info-content" v-if="item2.type===5">{{item2.data.value}}</div>
<!-- 显示时间 -->
<div class="info-content" v-if="item2.type===6">{{fmtTimeStamp2(item2.data.value)}}</div>
<!-- 显示视频 -->
<div class="info-content" v-if="item2.type===8">
<div class="info-content--video" v-for="(item,index) in item2.data" :key="index">
<video v-if="item.url" :src="item.url" controls="controls"></video>
</div>
</div>
<!-- pdf文件 -->
<div class="info-content info-content--pdf" v-if="item2.type===2">
<div class="show" v-for="(pdf1,pdfIndex1) in item2.data" :key="pdfIndex1">
<svg class="icon" aria-hidden="true">
<use xlink:href="#iconpdf-" />
</svg>
<p @click="openPDF(pdf1)">{{pdf1.name}}</p>
</div>
</div>
<!-- 编辑器 -->
<div
class="info-content info-content--bor"
v-if="item2.type==7"
v-html="item2.data.value"
></div>
<!-- 图片 -->
<div class="info-content" v-if="item2.type===1">
<div class="imgbox" v-for="(item3,index3) in item2.data" :key="index3">
<img :src="item3.value" />
<div class="ibox" @click="displayPicture(item3.value)">
<i class="iconfont iconfangda"></i>
</div>
</div>
</div>
</div>
</li>
</ul>
<!-- 图片放大镜 -->
<common-dialog
v-if="Magnifier"
@closePopup="Magnifier=false"
showMask
@ClickingBackground="Magnifier=false"
>
<div class="display-area">
<img :src="pcUrl" />
</div>
</common-dialog>
</div>
</template>
<script>
import CommonDialog from "@/components/CommonDialog.vue";
import { GO_URLS } from "@/config/URLS";
import { fmtTimeStamp } from "@/utils/tool/index";
export default {
// 引入组件
components: {
CommonDialog,
},
props: ["displayData"],
data() {
return {
Magnifier: false, // 图片放大器组件
List: [], // 展示用数据组
pcUrl: "",
};
},
computed: {},
watch: {
displayData: {
handler(newval, oldVal) {
if (newval.length > 0) {
this.List = JSON.parse(newval);
for (let index = 0; index < this.List.length; index++) {
const element = this.List[index];
if (element.label === "ext") {
this.List.splice(index, 1);
}
}
// this.List.pop();
this.replacementData(this.List);
} else {
this.List = [];
}
},
immediate: true,
},
},
created() {},
methods: {
// 获取增量的数据
// 时间转换
fmtTimeStamp2: function (stampStr) {
if (stampStr) {
return fmtTimeStamp("Y-M-D", parseInt(stampStr));
} else {
return " ";
}
},
// 显示图片放大器
displayPicture(item) {
this.pcUrl = item;
this.Magnifier = true;
},
// 替换图片
async requestPictures(string) {
const res = await this.$ajax({
type: "post",
async: true,
params: { hashes: [string] },
url: GO_URLS.getFiles,
});
if (res) {
return res.data.files[0].url;
} else {
return "";
}
},
// 数据处理
async replacementData(data) {
for (let index = 0; index < data.length; index++) {
const element = data[index];
// 有下级,跳过
if (element.type === 3) {
this.replacementData(element.data);
} else if (element.type === 1) {
// 图片
for (let index2 = 0; index2 < element.data.length; index2++) {
const img = element.data[index2].value;
element.data[index2].value = await this.requestPictures(img);
if (index2 === element.data.length - 1) this.$forceUpdate();
}
} else if (element.type === 8) {
//视频
for (let index2 = 0; index2 < element.data.length; index2++) {
const value = element.data[index2].value;
element.data[index2] = await this.requestVideos(value);
if (index2 === element.data.length - 1) this.$forceUpdate();
}
} else if (element.type === 2) {
for (let index2 = 0; index2 < element.data.length; index2++) {
const value = element.data[index2].value;
element.data[index2] = await this.requestFdf(value);
if (index2 === element.data.length - 1) this.$forceUpdate();
}
}
}
},
async requestVideos(value) {
if (!value) {
return false;
}
const res = await this.$ajax({
type: "post",
async: true,
params: { hashes: [value] },
url: GO_URLS.getFiles,
});
if (res) {
return res.data.files[0];
} else {
return "";
}
},
// pdf的替换
async requestFdf(item) {
const res = await this.$ajax({
type: "post",
async: true,
params: { hashes: [item] },
url: GO_URLS.getFiles,
});
if (res) {
return res.data.files[0];
} else {
return "";
}
},
// 打开pdf文件
openPDF(item) {
window.open(item.url);
},
},
};
</script>
<style scoped lang="less">
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
margin-bottom: 30px;
}
.show {
line-height: 1;
cursor: pointer;
padding-top: 20px;
padding-bottom: 4px;
&:hover {
i {
display: inline-block;
}
}
.icon {
font-size: 16px;
}
p {
font-size: 12px;
margin: 0;
display: inline-block;
padding: 0;
padding-left: 4px;
font-weight: 400;
color: rgba(63, 121, 254, 1);
}
}
.display-area {
// width: 819px;
// height: 564px;
img {
width: 100%;
// height: 100%;
}
}
.body {
padding-left: 46px;
padding-right: 40px;
.title {
font-size: 16px;
font-weight: 400;
color: rgba(41, 41, 41, 1);
padding-left: 16px;
line-height: 44px;
background: rgba(249, 249, 249, 1);
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.05);
}
.info {
padding-left: 20px;
margin-top: 16px;
margin-bottom: 24px;
line-height: 1;
display: flex;
.info-title {
font-size: 14px;
font-weight: 400;
width: 110px;
color: rgba(188, 188, 188, 1);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.info-content--pdf {
cursor: pointer;
color: rgba(63, 121, 254, 1);
}
.info-content {
font-size: 14px;
font-weight: 400;
flex-grow: 1;
overflow: hidden;
color: rgba(53, 53, 53, 1);
.info-content--video {
margin-bottom: 24px;
video {
// object-fit: fill;
width: 468px;
height: 334px;
}
}
.imgbox {
width: 93px;
height: 66px;
border: 1px solid rgba(235, 235, 235, 1);
float: left;
position: relative;
margin-bottom: 0;
margin-right: 6px;
&:hover {
.ibox {
display: block;
}
}
img {
width: 100%;
height: 100%;
}
.ibox {
position: absolute;
display: none;
width: 28px;
left: 50%;
background: rgba(0, 0, 0, 0.3);
top: 50%;
border-radius: 50%;
transform: translate(-50%, -50%);
margin-bottom: 0;
height: 28px;
text-align: center;
line-height: 28px;
cursor: pointer;
color: white;
}
}
}
.info-content--two {
background: rgba(249, 249, 249, 1);
}
.info-content--bor {
// border: 1px solid #000;
padding: 0 50px;
}
}
}
</style>
<template>
<div class="tinymce">
<textarea :id="Id"></textarea>
</div>
</template>
<script>
import "./zh_CN.js";
export default {
data() {
const Id = Date.now();
return {
Id: Id,
Editor: null,
DefaultConfig: {
// GLOBAL
height: 500,
theme: "modern",
// selector: "textarea",
// toolbar_drawer: "floating",
menubar: false,
// toolbar: 'undo redo | formatselect | bold italic backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help',
toolbar1: `styleselect | fontselect | formatselect | fontsizeselect | forecolor backcolor | bold italic underline strikethrough | table | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist | removeformat hr | code link | undo redo | fullscreen `,
// toolbar2: ` numlist bullist | preview removeformat hr | paste code link | undo redo | fullscreen `,
// paste preview
plugins: `
paste
importcss
table
advlist
fullscreen
link
media
lists
textcolor
colorpicker
hr
preview
wordcount
`,
// CONFIG
forced_root_block: "p",
force_p_newlines: true,
importcss_append: true,
// CONFIG: ContentStyle
content_style: `
* { padding:0; margin:0; }
html, body { height:100%; }
a { text-decoration: none; }
iframe { width: 100%; }
p { line-height:1.6; margin: 0px; }
table { word-wrap:break-word; word-break:break-all; max-width:100%; border:none; border-color:#999; }
.mce-object-iframe { width:100%; box-sizing:border-box; margin:0; padding:0; }
ul,ol { list-style-position:inside; }
`,
insert_button_items: "image link | inserttable",
// CONFIG: Paste
paste_retain_style_properties: "all",
paste_word_valid_elements: "*[*]", // word需要它
// paste_data_images: true, //
paste_convert_word_fake_lists: false, // 插入word文档需要该属性
paste_webkit_styles: "all",
paste_merge_formats: true,
nonbreaking_force_tab: false,
paste_auto_cleanup_on_paste: false,
// CONFIG: Font
fontsize_formats: "10px 11px 12px 14px 16px 18px 20px 24px",
// CONFIG: StyleSelect
style_formats: [
{
title: "首行缩进",
block: "p",
styles: { "text-indent": "2em" },
},
{
title: "行高",
items: [
{ title: "1", styles: { "line-height": "1" }, inline: "span" },
{
title: "1.5",
styles: { "line-height": "1.5" },
inline: "span",
},
{ title: "2", styles: { "line-height": "2" }, inline: "span" },
{
title: "2.5",
styles: { "line-height": "2.5" },
inline: "span",
},
{ title: "3", styles: { "line-height": "3" }, inline: "span" },
],
},
],
// FontSelect
font_formats: `
微软雅黑=微软雅黑;
宋体=宋体;
黑体=黑体;
仿宋=仿宋;
楷体=楷体;
隶书=隶书;
幼圆=幼圆;
Andale Mono=andale mono,times;
Arial=arial, helvetica,
sans-serif;
Arial Black=arial black, avant garde;
Book Antiqua=book antiqua,palatino;
Comic Sans MS=comic sans ms,sans-serif;
Courier New=courier new,courier;
Georgia=georgia,palatino;
Helvetica=helvetica;
Impact=impact,chicago;
Symbol=symbol;
Tahoma=tahoma,arial,helvetica,sans-serif;
Terminal=terminal,monaco;
Times New Roman=times new roman,times;
Trebuchet MS=trebuchet ms,geneva;
Verdana=verdana,geneva;
Webdings=webdings;
Wingdings=wingdings,zapf dingbats`,
// Tab
tabfocus_elements: ":prev,:next",
object_resizing: true,
},
};
},
props: {
value: {
default: "",
type: String,
},
config: {
type: Object,
default: () => {
return {
theme: "modern",
height: 300,
};
},
},
url: {
default: "",
type: String,
},
// accept: {
// default: "image/jpeg, image/png",
// type: String
// },
maxSize: {
default: 2097152,
type: Number,
},
withCredentials: {
default: false,
type: Boolean,
},
},
mounted() {
this.init();
},
// 实例销毁之前
beforeDestroy() {
// 销毁tinymce
this.$emit("on-destroy");
window.tinymce.remove(this);
},
methods: {
init() {
const self = this;
this.Editor = window.tinymce.init({
// 默认配置
...this.DefaultConfig,
// prop内传入的的config
...this.config,
// 挂载的DOM对象
selector: `#${this.Id}`,
setup: (editor) => {
// 抛出 'on-ready' 事件钩子
editor.on("init", () => {
self.loading = false;
self.$emit("on-ready");
editor.setContent(self.value);
});
editor.on("blur", () => {});
// 抛出 'input' 事件钩子,同步value数据
editor.on("input change undo redo", () => {
self.$emit("input", editor.getContent());
});
},
});
},
},
};
</script>
<style lang="less" scoped>
.tinymce {
width: 1200px;
margin: 0 auto;
&::-webkit-scrollbar {
width: 10px;
height: 10px;
}
&::-webkit-scrollbar-track {
background: red;
border-radius: 2px;
}
&::-webkit-scrollbar-thumb {
background: red;
border-radius: 10px;
}
&::-webkit-scrollbar-thumb:hover {
background: red;
}
&::-webkit-scrollbar-corner {
background: red;
}
/deep/.mce-flow-layout-item.mce-last {
display: none;
}
/deep/.mce-txt {
width: 58px;
}
}
</style>
\ No newline at end of file
This diff is collapsed.
import Vue from 'vue';
// import {GetParam, PostParam} from "@/plugins/axios-plugin";
export interface ResBase {
code: number;
data: any;
message: string;
}
// import {ResBase} from "@/types/api";
declare module 'vue/types/vue' {
interface Vue {
$ajax: (param: any) => Promise<ResBase | null>
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment