Commit 4c101843 authored by 赵伟庚's avatar 赵伟庚

update:bg-ui改写为vue3

parent 4ff6f918
...@@ -7,18 +7,15 @@ ...@@ -7,18 +7,15 @@
'is-active': modelValue === btn.value, 'is-active': modelValue === btn.value,
}" }"
:key="btn.value" :key="btn.value"
@click="selectBtn(btn)" @click="selectBtn(btn)">
>
{{ btn.name }} {{ btn.name }}
</li> </li>
</ul> </ul>
</div> </div>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
name: "BgBtns",
props: {
modelValue: { modelValue: {
type: [String, Number], type: [String, Number],
default: "", default: "",
...@@ -27,12 +24,10 @@ export default { ...@@ -27,12 +24,10 @@ export default {
type: Array, type: Array,
default: () => [], default: () => [],
}, },
}, });
emits: ["update:modelValue"], const emit = defineEmits(["update:modelValue"]);
methods: {
selectBtn({ value }) { const selectBtn = ({ value }) => {
this.$emit("update:modelValue", value); emit("update:modelValue", value);
},
},
}; };
</script> </script>
...@@ -12,10 +12,8 @@ ...@@ -12,10 +12,8 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
name: "BgCard",
props: {
title: { title: {
type: String, type: String,
default: "", default: "",
...@@ -24,6 +22,5 @@ export default { ...@@ -24,6 +22,5 @@ export default {
type: String, type: String,
default: "", default: "",
}, },
}, });
};
</script> </script>
...@@ -2,50 +2,48 @@ ...@@ -2,50 +2,48 @@
<VAceEditor <VAceEditor
v-model:value="states.content" v-model:value="states.content"
class="vue-ace-editor" class="vue-ace-editor"
:class="{'vue-ace-editor-disable':props.disabled}" :class="{ 'vue-ace-editor-disable': props.disabled }"
@input="codeChange" @input="codeChange"
:lang="props.lang" :lang="props.lang"
:theme="props.theme" :theme="props.theme"
:options="{ :options="{
useWorker: true, useWorker: true,
readOnly: props.disabled, readOnly: props.disabled,
wrap: true wrap: true,
}" }" />
/>
</template> </template>
<script setup> <script setup>
import { reactive, toRefs, watch,onMounted } from "vue"; import { reactive, toRefs, watch, onMounted } from "vue";
import { VAceEditor } from "vue3-ace-editor"; import { VAceEditor } from "vue3-ace-editor";
import ace from 'ace-builds'; import ace from "ace-builds";
import modeJsonUrl from 'ace-builds/src-noconflict/mode-json?url'; import modeJsonUrl from "ace-builds/src-noconflict/mode-json?url";
import modeJavascriptUrl from 'ace-builds/src-noconflict/mode-javascript?url'; import modeJavascriptUrl from "ace-builds/src-noconflict/mode-javascript?url";
import modeHtmlUrl from 'ace-builds/src-noconflict/mode-html?url'; import modeHtmlUrl from "ace-builds/src-noconflict/mode-html?url";
import themeGithubUrl from 'ace-builds/src-noconflict/theme-github?url'; import themeGithubUrl from "ace-builds/src-noconflict/theme-github?url";
import themeChromeUrl from 'ace-builds/src-noconflict/theme-chrome?url'; import themeChromeUrl from "ace-builds/src-noconflict/theme-chrome?url";
import themeMonokaiUrl from 'ace-builds/src-noconflict/theme-monokai?url'; import themeMonokaiUrl from "ace-builds/src-noconflict/theme-monokai?url";
import workerBaseUrl from 'ace-builds/src-noconflict/worker-base?url'; import workerBaseUrl from "ace-builds/src-noconflict/worker-base?url";
import workerJsonUrl from 'ace-builds/src-noconflict/worker-json?url'; import workerJsonUrl from "ace-builds/src-noconflict/worker-json?url";
import workerJavascriptUrl from 'ace-builds/src-noconflict/worker-javascript?url'; import workerJavascriptUrl from "ace-builds/src-noconflict/worker-javascript?url";
import workerHtmlUrl from 'ace-builds/src-noconflict/worker-html?url'; import workerHtmlUrl from "ace-builds/src-noconflict/worker-html?url";
ace.config.setModuleUrl('ace/mode/json', modeJsonUrl); ace.config.setModuleUrl("ace/mode/json", modeJsonUrl);
ace.config.setModuleUrl('ace/mode/javascript', modeJavascriptUrl); ace.config.setModuleUrl("ace/mode/javascript", modeJavascriptUrl);
ace.config.setModuleUrl('ace/mode/html', modeHtmlUrl); ace.config.setModuleUrl("ace/mode/html", modeHtmlUrl);
ace.config.setModuleUrl('ace/theme/github', themeGithubUrl); ace.config.setModuleUrl("ace/theme/github", themeGithubUrl);
ace.config.setModuleUrl('ace/theme/chrome', themeChromeUrl); ace.config.setModuleUrl("ace/theme/chrome", themeChromeUrl);
ace.config.setModuleUrl('ace/theme/monokai', themeMonokaiUrl); ace.config.setModuleUrl("ace/theme/monokai", themeMonokaiUrl);
ace.config.setModuleUrl('ace/mode/base', workerBaseUrl); ace.config.setModuleUrl("ace/mode/base", workerBaseUrl);
ace.config.setModuleUrl('ace/mode/json_worker', workerJsonUrl); ace.config.setModuleUrl("ace/mode/json_worker", workerJsonUrl);
ace.config.setModuleUrl('ace/mode/javascript_worker', workerJavascriptUrl); ace.config.setModuleUrl("ace/mode/javascript_worker", workerJavascriptUrl);
ace.config.setModuleUrl('ace/mode/html_worker', workerHtmlUrl); ace.config.setModuleUrl("ace/mode/html_worker", workerHtmlUrl);
const props = defineProps( const props = defineProps({
{
modelValue: { modelValue: {
type:String, type: String,
default:"", default: "",
}, },
disabled:{ disabled: {
type:Boolean, type: Boolean,
default:false default: false,
}, },
// lang:{ // lang:{
// type:String, // type:String,
...@@ -55,19 +53,18 @@ const props = defineProps( ...@@ -55,19 +53,18 @@ const props = defineProps(
// type:String, // type:String,
// default:"themeChromeUrl" // default:"themeChromeUrl"
// }, // },
width:{ width: {
type:String, type: String,
default:"100%" default: "100%",
}, },
} });
) const emit = defineEmits(["update:modelValue"]);
const emit = defineEmits(['update:modelValue']) // watch(
watch( // props.modelValue,
props.modelValue, // (n,o) => {
(n,o) => { // states.content = n
states.content = n // }
} // )
)
const states = reactive({ const states = reactive({
lang: "json", lang: "json",
...@@ -75,16 +72,16 @@ const states = reactive({ ...@@ -75,16 +72,16 @@ const states = reactive({
content: "", content: "",
}); });
watch( // watch(
states.content, // states.content,
(n,o) => { // (n,o) => {
emit("update:modelValue", n); // emit("update:modelValue", n);
} // }
) // )
const codeChange = (val,val1,val2)=>{ const codeChange = () => {
emit("update:modelValue", states.content); emit("update:modelValue", states.content);
} };
onMounted(() => { onMounted(() => {
let obj = ""; let obj = "";
...@@ -92,15 +89,16 @@ onMounted(() => { ...@@ -92,15 +89,16 @@ onMounted(() => {
try { try {
if (typeof JSON.parse(props.modelValue) == "object") { if (typeof JSON.parse(props.modelValue) == "object") {
obj = JSON.stringify(JSON.parse(props.modelValue), null, "\t"); obj = JSON.stringify(JSON.parse(props.modelValue), null, "\t");
} else {
obj = props.modelValue;
} }
} catch (e) { } catch (e) {
obj = props.modelValue; obj = props.modelValue;
} }
states.content = obj states.content = obj;
}) });
const {content} = toRefs(states)
const { content } = toRefs(states);
</script> </script>
<style scoped> <style scoped>
...@@ -114,48 +112,48 @@ const {content} = toRefs(states) ...@@ -114,48 +112,48 @@ const {content} = toRefs(states)
border-radius: 4px; border-radius: 4px;
overflow: hidden; overflow: hidden;
} }
.vue-ace-editor :deep() .ace_scrollbar-v{ .vue-ace-editor :deep() .ace_scrollbar-v {
width: 0px!important; width: 0px !important;
} }
.vue-ace-editor :deep() .ace_gutter{ .vue-ace-editor :deep() .ace_gutter {
font-size: 14px; font-size: 14px;
color: #ffffff; color: #ffffff;
background-color: #262626; background-color: #262626;
} }
.vue-ace-editor :deep() .ace_gutter-cell{ .vue-ace-editor :deep() .ace_gutter-cell {
line-height: 22px; line-height: 22px;
background-color: #262626; background-color: #262626;
} }
.vue-ace-editor :deep() .ace_print-margin{ .vue-ace-editor :deep() .ace_print-margin {
width: 0; width: 0;
} }
.vue-ace-editor :deep() .ace_scroller{ .vue-ace-editor :deep() .ace_scroller {
background-color: #1a1a1a; background-color: #1a1a1a;
color: #fff; color: #fff;
caret-color:#fff; caret-color: #fff;
} }
/* 光标颜色 */ /* 光标颜色 */
.vue-ace-editor :deep() .ace_cursor{ .vue-ace-editor :deep() .ace_cursor {
color: #fff; color: #fff;
} }
.vue-ace-editor-disable :deep() .ace_scrollbar-v{ .vue-ace-editor-disable :deep() .ace_scrollbar-v {
width: 6px!important; width: 6px !important;
} }
.vue-ace-editor-disable :deep() .ace_gutter{ .vue-ace-editor-disable :deep() .ace_gutter {
background-color: #202531; background-color: #202531;
} }
.vue-ace-editor-disable :deep() .ace_gutter-cell{ .vue-ace-editor-disable :deep() .ace_gutter-cell {
background-color: #202531; background-color: #202531;
} }
.vue-ace-editor-disable :deep() .ace_scroller{ .vue-ace-editor-disable :deep() .ace_scroller {
background-color: #fff; background-color: #fff;
color: #202531; color: #202531;
} }
/* 光标颜色 */ /* 光标颜色 */
.vue-ace-editor-disable :deep() .ace_cursor{ .vue-ace-editor-disable :deep() .ace_cursor {
color: #000; color: #000;
} }
</style> </style>
<template> <template>
<div class="detail_box"> <div class="detail_box">
<div class="detail_text text_clip" :style="index==data.length-1?last_width:unit_width" v-for="(item,index) in data" :key="'data'+index"> <div
<span>{{item.title}}</span> class="detail_text text_clip"
:style="index == data.length - 1 ? last_width : unit_width"
v-for="(item, index) in data"
:key="'data' + index">
<span>{{ item.title }}</span>
<!-- 拓展功能 --> <!-- 拓展功能 -->
<template v-if="item.slot"> <template v-if="item.slot">
<span> <span>
...@@ -10,93 +14,92 @@ ...@@ -10,93 +14,92 @@
</template> </template>
<!-- 原有下载功能 --> <!-- 原有下载功能 -->
<template v-else> <template v-else>
<span v-if="!item.urls" :title="item.info" @click="down_file(item.url)" :style="item.url?{color:'#515fe7',cursor:'pointer'}:''">{{item.info}}</span> <span
v-if="!item.urls"
:title="item.info"
@click="down_file(item.url)"
:style="item.url ? { color: '#515fe7', cursor: 'pointer' } : ''"
>{{ item.info }}</span
>
<span v-else :title="item.info"> <span v-else :title="item.info">
<span v-for="(it,idx) in item.urls" @click="down_file(it)" style="color:#515fe7;cursor:pointer;" :key="'urls'+idx">{{helper.downloadFileFormatNew(it)}}</span> <span
v-for="(it, idx) in item.urls"
@click="down_file(it)"
style="color: #515fe7; cursor: pointer"
:key="'urls' + idx"
>{{ helper.downloadFileFormatNew(it) }}</span
>
</span> </span>
</template> </template>
</div> </div>
<div class="bg" :style="{top:(2*index+1)*42+'px'}" v-for="(item,index) in bg_num" :key="'bg'+index"></div> <div
class="bg"
:style="{ top: (2 * index + 1) * 42 + 'px' }"
v-for="(item, index) in bg_num"
:key="'bg' + index"></div>
</div> </div>
</template> </template>
<script> <script setup>
import helper from './utils/index.js' import { reactive, ref, onBeforeMount, toRefs, watch } from "vue";
import helper from "./utils/index.js";
console.log(helper); console.log(helper);
export default { const props = defineProps({
props: { data: {
data:{
type: Array, type: Array,
default: () => [], default: () => [],
}, },
layout:{ layout: {
line_num:4 line_num: 4,
}
}, },
components: { });
}, const unit_width = ref(0);
data() { const last_width = ref(0);
return { const bg_num = ref(0);
helper,
unit_width:0, watch(
last_width:0, () => props.data,
bg_num:0, (n, o) => {
}; if (props.layout.line_num) {
}, unit_width.value = { width: 100 / props.layout.line_num + "%" };
watch: {
data:{
handler: function(n, o) {
if(this.layout.line_num){
this.unit_width = {width:100/this.layout.line_num +'%'}
} }
if(this.layout.line_num&&n.length%this.layout.line_num!==0){//计算最后一个格子的宽度 if (props.layout.line_num && n.length % props.layout.line_num !== 0) {
this.last_width = {width:(this.layout.line_num-(n.length%this.layout.line_num)+1)/this.layout.line_num*100+'%'} //计算最后一个格子的宽度
}else{ last_width.value = {
this.last_width = {width:100/this.layout.line_num +'%'} width: ((props.layout.line_num - (n.length % this.layout.line_num) + 1) / this.layout.line_num) * 100 + "%",
};
} else {
last_width.value = { width: 100 / props.layout.line_num + "%" };
} }
if(n.length<this.layout.line_num){ if (n.length < props.layout.line_num) {
return return;
}else{ } else {
this.bg_num = Math.floor((Math.ceil(n.length/this.layout.line_num))/2) bg_num.value = Math.floor(Math.ceil(n.length / props.layout.line_num) / 2);
} }
},
immediate: true
} }
);
}, const down_file = (url) => {
computed: { if (url) {
},
created() {
},
mounted() {
},
methods: {
down_file(url){
if(url){
console.log(url); console.log(url);
const a = document.createElement("a"); // 创建a标签 const a = document.createElement("a"); // 创建a标签
a.setAttribute("download", ""); // download属性 a.setAttribute("download", ""); // download属性
a.setAttribute("href", url); // href链接 a.setAttribute("href", url); // href链接
a.click(); // 自执行点击事件 a.click(); // 自执行点击事件
} }
}
},
}; };
</script> </script>
<style scoped> <style scoped>
.detail_box{ .detail_box {
width: 100%; width: 100%;
border-bottom: 1px solid #e3e5ef; border-bottom: 1px solid #e3e5ef;
border-right: 1px solid #e3e5ef; border-right: 1px solid #e3e5ef;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
} }
.detail_box .detail_text{ .detail_box .detail_text {
width: 25%; width: 25%;
height: 42px; height: 42px;
line-height: 42px; line-height: 42px;
...@@ -107,14 +110,14 @@ export default { ...@@ -107,14 +110,14 @@ export default {
position: relative; position: relative;
z-index: 1; z-index: 1;
} }
.detail_box .detail_text span:nth-of-type(1){ .detail_box .detail_text span:nth-of-type(1) {
color: #616f94; color: #616f94;
} }
.detail_box .detail_text span:nth-of-type(2){ .detail_box .detail_text span:nth-of-type(2) {
color: #404a62; color: #404a62;
} }
.bg{ .bg {
background-color:#f7f8f9; background-color: #f7f8f9;
width: 100%; width: 100%;
height: 42px; height: 42px;
position: absolute; position: absolute;
......
<template> <template>
<div class="out-detail"> <div class="out-detail">
<div class="row-box" v-for="(item,index) in list" :style="{width:item.width}" :key="'row-box'+index"> <div class="row-box" v-for="(item, index) in list" :style="{ width: item.width }" :key="'row-box' + index">
<p class="detail-module" v-if="!item.slot"> <p class="detail-module" v-if="!item.slot">
<span :style="{width:itemWidth}">{{item.label}}</span> <span :style="{ width: itemWidth }">{{ item.label }}</span>
<span class="text_clip" :title="item.value" v-if="!item.childSlot">{{item.value}}</span> <span class="text_clip" :title="item.value" v-if="!item.childSlot">{{ item.value }}</span>
<span v-else> <span v-else>
<slot :name="item.childSlot" :data="item"></slot> <slot :name="item.childSlot" :data="item"></slot>
</span> </span>
...@@ -15,46 +15,21 @@ ...@@ -15,46 +15,21 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
props: { list: {
list:{ type: Array,
type:Array, default: () => [],
default:()=>[]
}, },
itemWidth:{ itemWidth: {
type:String, type: String,
default:'' default: "",
}
}, },
components: { });
},
data() {
return {
};
},
watch: {
},
computed: {
},
created() {
},
mounted() {
},
methods: {
},
};
</script> </script>
<style scoped> <style scoped>
.out-detail{ .out-detail {
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
display: flex; display: flex;
...@@ -62,9 +37,9 @@ export default { ...@@ -62,9 +37,9 @@ export default {
border-right: solid 1px #dadee7; border-right: solid 1px #dadee7;
border-bottom: solid 1px #dadee7; border-bottom: solid 1px #dadee7;
} }
.row-box{ .row-box {
width: 50%; width: 50%;
flex-grow:1; flex-grow: 1;
text-align: left; text-align: left;
line-height: 48px; line-height: 48px;
min-height: 48px; min-height: 48px;
...@@ -73,22 +48,22 @@ export default { ...@@ -73,22 +48,22 @@ export default {
font-size: 14px; font-size: 14px;
color: #404a62; color: #404a62;
} }
.row-box .detail-module{ .row-box .detail-module {
height: 100%; height: 100%;
display: flex; display: flex;
} }
.row-box .detail-module span{ .row-box .detail-module span {
height: 100%; height: 100%;
display: inline-block; display: inline-block;
padding-left: 15px; padding-left: 15px;
box-sizing: border-box; box-sizing: border-box;
} }
.row-box .detail-module span:nth-of-type(1){ .row-box .detail-module span:nth-of-type(1) {
background-color: #f7f7f9; background-color: #f7f7f9;
min-width: 114px; min-width: 114px;
border-right: solid 1px #dadee7; border-right: solid 1px #dadee7;
} }
.row-box .detail-module span:nth-of-type(2){ .row-box .detail-module span:nth-of-type(2) {
flex-grow:1; flex-grow: 1;
} }
</style> </style>
...@@ -9,8 +9,7 @@ ...@@ -9,8 +9,7 @@
:class="{ :class="{
current: activeName === item.name, current: activeName === item.name,
}" }"
@click="changeActiveName(item, index)" @click="changeActiveName(item, index)">
>
{{ item.label }} {{ item.label }}
</li> </li>
<li> <li>
...@@ -44,8 +43,7 @@ ...@@ -44,8 +43,7 @@
:class="{ :class="{
current: activeName === item.name, current: activeName === item.name,
}" }"
@click="changeActiveName(item, index)" @click="changeActiveName(item, index)">
>
{{ item.label }} {{ item.label }}
</li> </li>
<li> <li>
...@@ -60,84 +58,76 @@ ...@@ -60,84 +58,76 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { import { ref, provide, reactive, onBeforeMount, onMounted, onUnmounted, nextTick, toRefs, useSlots } from "vue";
name: "BgDetail",
provide() { const slots = useSlots();
return {
getActiveName: () => { const activeName = ref("");
return this.activeName;
}, const bgDetail = ref(null);
getIsTabs: () => { provide("getActiveName", activeName.value);
return false;
}, provide("getIsTabs", false);
};
}, const showFixedBars = ref(false);
data() {
return { const state = reactive({
activeName: "",
showFixedBars: false,
scrollCallback: null, scrollCallback: null,
}; });
},
methods: { const calcTabs = () => {
calcTabs() {
let tabSlots = []; let tabSlots = [];
if (this.$slots.default) { if (slots.default()) {
tabSlots = this.$slots.default tabSlots = slots
.filter( .default()
(vnode) => .filter((vnode) => vnode.tag && vnode.componentOptions && vnode.componentOptions.Ctor.options.name === "BgTab")
vnode.tag &&
vnode.componentOptions &&
vnode.componentOptions.Ctor.options.name === "BgTab"
)
.map((vnode) => vnode.componentOptions.propsData); .map((vnode) => vnode.componentOptions.propsData);
} }
return tabSlots; return tabSlots;
}, };
changeActiveName({ name }, index) { const changeActiveName = ({ name }, index) => {
let targetEl = this.$el.querySelectorAll(`.bg-tab`)[index]; let targetEl = bgDetail.value.querySelectorAll(`.bg-tab`)[index];
let targetCtx = document.querySelector(`.bg-main`); let targetCtx = document.querySelector(`.bg-main`);
targetCtx.scrollTop = targetEl && targetEl.offsetTop - 165; targetCtx.scrollTop = targetEl && targetEl.offsetTop - 165;
this.activeName = name; activeName.value = name;
this.scrollCallback = () => { state.scrollCallback = () => {
this.activeName = name; activeName.value = name;
}; };
}, };
scrollAction() { const scrollAction = () => {
let targetCtx = document.querySelector(`.bg-main`); let targetCtx = document.querySelector(`.bg-main`);
let ctxScrollTop = targetCtx.scrollTop || 0; let ctxScrollTop = targetCtx.scrollTop || 0;
let targetEls = this.$el.querySelectorAll(`.bg-tab`); let targetEls = bgDetail.value.querySelectorAll(`.bg-tab`);
let tabs = this.calcTabs(); let tabs = calcTabs();
for (let i = 0; i < targetEls.length; i++) { for (let i = 0; i < targetEls.length; i++) {
let targetEl = targetEls[i]; let targetEl = targetEls[i];
if (ctxScrollTop >= targetEl.offsetTop) { if (ctxScrollTop >= targetEl.offsetTop) {
this.activeName = tabs[i].name; activeName.value = tabs[i].name;
} }
} }
this.showFixedBars = ctxScrollTop > 222; showFixedBars.value = ctxScrollTop > 222;
this.scrollCallback && this.scrollCallback(); state.scrollCallback && state.scrollCallback();
this.scrollCallback = null; state.scrollCallback = null;
},
},
mounted() {
this.$nextTick(() => {
let tabs = this.calcTabs();
this.activeName = tabs[0] && tabs[0].name;
this.scrollAction();
window.addEventListener("scroll", this.scrollAction, true);
});
},
destroyed() {
window.removeEventListener("scroll", this.scrollAction, true);
},
}; };
onMounted(() => {
nextTick().then(() => {
let tabs = calcTabs();
activeName.value = tabs[0] && tabs[0].name;
scrollAction();
window.addEventListener("scroll", scrollAction, true);
});
});
onUnmounted(() => {
window.removeEventListener("scroll", scrollAction, true);
});
</script> </script>
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<span class="bg-filtrate-text">{{ name }}</span> <span class="bg-filtrate-text">{{ name }}</span>
<div class="bg-filtrate-list"> <div class="bg-filtrate-list">
<el-date-picker <el-date-picker
v-model="value" v-model="useTime"
type="daterange" type="daterange"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
range-separator="~" range-separator="~"
...@@ -15,31 +15,27 @@ ...@@ -15,31 +15,27 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { import { reactive, ref, onBeforeMount, toRefs, computed, watch } from "vue";
name: "BgFilterDate", const props = defineProps({
model: {
prop: "time",
event: "change",
},
props: {
name: { name: {
type: String, type: String,
default: "", default: "",
}, },
time: {
type: String,
default: "",
}, },
data() { });
return {
value: ""
}
},
computed: {
const emit = defineEmits(["update:time"]);
const useTime = computed({
get() {
return props.time;
}, },
methods: { set(value) {
change(event) { emit("update:time", value);
this.$emit("change", event);
},
}, },
}; });
</script> </script>
<template> <template>
<div class="bg-filter-group" :style="{'border-bottom': showFlag? 'none' : '','padding-bottom': showFlag? '8px':'16px'}"> <div
class="bg-filter-group"
:style="{ 'border-bottom': showFlag ? 'none' : '', 'padding-bottom': showFlag ? '8px' : '16px' }">
<div class="top-filter"> <div class="top-filter">
<div class="left-slot"> <div class="left-slot">
<slot name="left_action"></slot> <slot name="left_action"></slot>
</div> </div>
<div class="right-filter"> <div class="right-filter">
<el-input v-if="showSearch" :placeholder="placeholder" @keydown.enter="search" @clear="search" clearable v-model.trim="value"> <el-input
v-if="showSearch"
:placeholder="placeholder"
@keydown.enter="search"
@clear="search"
clearable
v-model.trim="modelValue">
<template #append> <template #append>
<div class="append-btn" @click="search"> <div class="append-btn" @click="search">
<bg-icon style="font-size: 12px; color: #404a62; " icon="#bg-ic-search"></bg-icon> <bg-icon style="font-size: 12px; color: #404a62" icon="#bg-ic-search"></bg-icon>
</div> </div>
</template> </template>
</el-input> </el-input>
<div class="more-btn" :class="showFlag ? 'more-btn1': ''" v-if="$slots.filter_group"> <div class="more-btn" :class="showFlag ? 'more-btn1' : ''" v-if="$slots.filter_group">
<el-button type="default" class="more-filter" @click="moreFilter"> <el-button type="default" class="more-filter" @click="moreFilter">
高级搜索 高级搜索
<bg-icon style="font-size: 8px; color: #404a62; margin-left: 8px" icon="#bg-ic-arrow-down" v-if="!showFlag"></bg-icon> <bg-icon
style="font-size: 8px; color: #404a62; margin-left: 8px"
icon="#bg-ic-arrow-down"
v-if="!showFlag"></bg-icon>
<bg-icon style="font-size: 8px; color: #404a62; margin-left: 8px" icon="#bg-ic-arrow-up" v-else></bg-icon> <bg-icon style="font-size: 8px; color: #404a62; margin-left: 8px" icon="#bg-ic-arrow-up" v-else></bg-icon>
</el-button> </el-button>
</div> </div>
</div> </div>
</div> </div>
<div class="filter-group" v-if="showFlag"> <div class="filter-group" v-show="showFlag">
<slot name="filter_group"></slot> <slot name="filter_group"></slot>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { computed, onMounted, reactive, toRefs, watch,ref } from "vue" import { computed, onMounted, reactive, toRefs, watch, ref } from "vue";
const state = reactive({ const state = reactive({
showFlag: false, showFlag: false,
value: "" modelValue: "",
}) });
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
type: String, type: String,
default: '', default: "",
}, },
placeholder: { placeholder: {
type: String, type: String,
default: "请输入关键词" default: "请输入关键词",
}, },
showSearch: { showSearch: {
type: Boolean, type: Boolean,
default: true default: true,
} },
}) });
watch(props,(n,o) => { watch(props, (n, o) => {
state.value = n.modelValue state.modelValue = n.modelValue;
}) });
watch(() => state.value,(n,o) => { watch(
emit('update:modelValue',n) () => state.modelValue,
}) (n, o) => {
const emit = defineEmits(['search','update:modelValue']) emit("update:modelValue", n);
}
);
const emit = defineEmits(["search", "update:modelValue"]);
const search = () => { const search = () => {
emit('search',state.value) emit("search", state.modelValue);
} };
const moreFilter = () => { const moreFilter = () => {
state.showFlag = !state.showFlag state.showFlag = !state.showFlag;
} };
onMounted(() => { onMounted(() => {
state.value = props.modelValue state.modelValue = props.modelValue;
}) });
const { value,showFlag } = toRefs(state) const { modelValue, showFlag } = toRefs(state);
</script> </script>
...@@ -7,30 +7,24 @@ ...@@ -7,30 +7,24 @@
v-for="(item, index) in fullOptions" v-for="(item, index) in fullOptions"
:class="{ current: selection.indexOf(item.value) > -1 }" :class="{ current: selection.indexOf(item.value) > -1 }"
:key="'li_' + index" :key="'li_' + index"
@click="selectAction(item)" @click="selectAction(item)">
>
{{ item.name }} {{ item.name }}
</li> </li>
</ul> </ul>
</div> </div>
</template> </template>
<script> <script setup>
export default { import { computed } from "vue";
name: "BgFilter", const props = defineProps({
model: { modelValue: {
prop: "value",
event: "change",
},
props: {
isCalc:{
type:Boolean,
default:false,
},
value: {
type: [Number, String], type: [Number, String],
default: "", default: "",
}, },
isCalc: {
type: Boolean,
default: false,
},
name: { name: {
type: String, type: String,
default: "", default: "",
...@@ -51,34 +45,33 @@ export default { ...@@ -51,34 +45,33 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}, });
computed: { const emit = defineEmits(["update:modelValue"]);
fullOptions() { const fullOptions = computed(() => {
return [ return [
{ {
name: "全部", name: "全部",
value: "", value: "",
}, },
...this.options.map((item) => { ...props.options.map((item) => {
return { return {
name: item[this.optionName], name: item[props.optionName],
value: item[this.optionValue] + "", value: item[props.optionValue] + "",
sub_cate: item.sub_cate ? item.sub_cate : "", sub_cate: item.sub_cate ? item.sub_cate : "",
}; };
}), }),
]; ];
}, });
selection() {
let value = this.value + ""; const selection = computed(() => {
let value = props.modelValue + "";
return value.split(","); return value.split(",");
}, });
}, const selectAction = ({ value, name, sub_cate }) => {
methods: { if (value && props.multiple) {
selectAction({ value, name, sub_cate }) { let selection = [...props.selection].filter((v) => v !== "");
if (value && this.multiple) {
let selection = [...this.selection].filter((v) => v !== "");
let index = selection.findIndex((v) => v === value); let index = selection.findIndex((v) => v === value);
if (index > -1) { if (index > -1) {
...@@ -87,11 +80,9 @@ export default { ...@@ -87,11 +80,9 @@ export default {
selection.push(value); selection.push(value);
} }
this.$emit("change", selection.join(",")); emit("update:modelValue", selection.join(","));
} else { } else {
this.$emit("change", value, name, sub_cate ? sub_cate : ""); emit("update:modelValue", value, name, sub_cate ? sub_cate : "");
} }
},
},
}; };
</script> </script>
...@@ -6,23 +6,17 @@ ...@@ -6,23 +6,17 @@
v-for="(item, index) in fullOptions" v-for="(item, index) in fullOptions"
:class="{ current: selection.indexOf(item.value) > -1 }" :class="{ current: selection.indexOf(item.value) > -1 }"
:key="'li_' + index" :key="'li_' + index"
@click="selectAction(item)" @click="selectAction(item)">
>
{{ item.name }} {{ item.name }}
</li> </li>
</ul> </ul>
</div> </div>
</template> </template>
<script> <script setup>
export default { import { computed } from "vue-demi";
name: "BgFiltrate", const props = defineProps({
model: { modelValue: {
prop: "value",
event: "change",
},
props: {
value: {
type: [Number, String], type: [Number, String],
default: "", default: "",
}, },
...@@ -46,32 +40,30 @@ export default { ...@@ -46,32 +40,30 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}, });
computed: { const fullOptions = computed(() => {
fullOptions() {
return [ return [
{ {
name: "全部", name: "全部",
value: "", value: "",
}, },
...this.options.map((item) => { ...props.options.map((item) => {
return { return {
name: item[this.optionName], name: item[props.optionName],
value: item[this.optionValue] + "", value: item[props.optionValue] + "",
}; };
}), }),
]; ];
}, });
selection() { const selection = computed(() => {
let value = this.value + ""; let value = props.modelValue + "";
return value.split(","); return value.split(",");
}, });
},
methods: { const selectAction = ({ value, name }) => {
selectAction({ value, name }) { if (value && props.multiple) {
if (value && this.multiple) { let selection = [...props.selection].filter((v) => v !== "");
let selection = [...this.selection].filter((v) => v !== "");
let index = selection.findIndex((v) => v === value); let index = selection.findIndex((v) => v === value);
if (index > -1) { if (index > -1) {
...@@ -80,11 +72,9 @@ export default { ...@@ -80,11 +72,9 @@ export default {
selection.push(value); selection.push(value);
} }
this.$emit("change", selection.join(",")); emit("update:modelValue", selection.join(","));
} else { } else {
this.$emit("change", value, name); emit("update:modelValue", value, name);
} }
},
},
}; };
</script> </script>
...@@ -4,15 +4,13 @@ ...@@ -4,15 +4,13 @@
</svg> </svg>
</template> </template>
<script> <script setup>
import "https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/svg_19654_219.e913701ac6c36991a671b81b5a7654f2.js"; import "https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/svg_19654_226.2578d57f3d5174aa1f23c90c15983cb6.js";
export default { const props = defineProps({
props: {
icon: { icon: {
type: String, type: String,
default: "", default: "",
}, },
}, });
};
</script> </script>
...@@ -6,60 +6,63 @@ ...@@ -6,60 +6,63 @@
:key="'li_' + index" :key="'li_' + index"
:style="{ :style="{
width: item.full ? `100%` : `calc(100% / ${col})`, width: item.full ? `100%` : `calc(100% / ${col})`,
}" }">
> <span :style="{ width: item.nameWidth ? item.nameWidth + 'px' : '50%' }">
<span :style="{ width: item.nameWidth ? item.nameWidth + 'px' : '50%'}">
{{ item.name }} {{ item.name }}
</span> </span>
<span :style="{ width: item.nameWidth ? `calc( 100% - ${item.nameWidth + 'px'})` : '50%'}"> <span :style="{ width: item.nameWidth ? `calc( 100% - ${item.nameWidth + 'px'})` : '50%' }">
<span <span
style="display: inline-block;width: 100%;white-space: normal;word-break: break-all" style="display: inline-block; width: 100%; white-space: normal; word-break: break-all"
:style="{ :style="{
width: item.copy ? 'calc(100% - 36px)' : item.download || item.password ? 'calc(100% - 22px)': '100%', width: item.copy ? 'calc(100% - 36px)' : item.download || item.password ? 'calc(100% - 22px)' : '100%',
color: item.download ? '#3759be' : '#404a62' color: item.download ? '#3759be' : '#404a62',
}" }">
<span v-if="item.state" :style="{ color: stateColor[item.state] }">
<span class="state-dot" :style="{ backgroundColor: stateColor[item.state] }"></span>{{ item.value }}</span
> >
<span v-if="item.state" :style="{color: stateColor[item.state]}"> <span class="state-dot" :style="{backgroundColor: stateColor[item.state]}"></span>{{item.value}}</span> <span v-else-if="item.secret">{{ secret(item.value) }}</span>
<span v-else-if="item.secret">{{secret(item.value)}}</span> <span v-else-if="item.idCard">{{ idCardShow ? item.value : idcard(item.value) }}</span>
<span v-else-if="item.idCard">{{idCardShow ? item.value : idcard(item.value)}}</span> <span v-else-if="item.callback" @click.stop="item.callback && item.callback()" class="can_click_text">{{
<span v-else-if="item.callback" @click.stop="item.callback && item.callback()" class="can_click_text">{{item.value}}</span> item.value
}}</span>
<span v-else>{{ item.value }}</span> <span v-else>{{ item.value }}</span>
</span> </span>
<a <a class="copy-btn" @click="copyText(item.value, $event)" v-if="item.copy"> 复制 </a>
<bg-icon
v-if="item.copy_icon"
@click="copyIcon(item.value)"
class="copy-btn" class="copy-btn"
@click="copyText(item.value, $event)" style="font-size: 14px; color: #a9b1c7; cursor: pointer"
v-if="item.copy" icon="#bg-ic-copy"></bg-icon>
> <bg-icon
复制 v-if="item.idCard"
</a> @click="idCardShow = !idCardShow"
<bg-icon v-if="item.copy_icon" @click="copyIcon(item.value)" class="copy-btn" style="font-size: 14px; color: #a9b1c7;cursor: pointer;" icon="#bg-ic-copy"></bg-icon> class="copy-btn"
<bg-icon v-if="item.idCard" @click="idCardShow = !idCardShow" class="copy-btn" style="font-size: 14px; color: #a9b1c7;cursor: pointer;" icon="#bg-ic-eye"></bg-icon> style="font-size: 14px; color: #a9b1c7; cursor: pointer"
icon="#bg-ic-eye"></bg-icon>
<bg-icon <bg-icon
class="copy-btn" class="copy-btn"
style="font-size: 14px; color: #a9b1c7;cursor: pointer;" style="font-size: 14px; color: #a9b1c7; cursor: pointer"
icon="#bg-ic-download" icon="#bg-ic-download"
v-if="item.download" v-if="item.download"
@click="download(item.url)" @click="download(item.url)"></bg-icon>
></bg-icon>
<bg-icon <bg-icon
class="copy-btn" class="copy-btn"
style="font-size: 14px; color: #a9b1c7;cursor: pointer;" style="font-size: 14px; color: #a9b1c7; cursor: pointer"
:icon="show ? '#bg-ic-eye-close' : '#bg-ic-eye'" :icon="show ? '#bg-ic-eye-close' : '#bg-ic-eye'"
v-if="item.password" v-if="item.password"
@click="changeView(item)" @click="changeView(item)"></bg-icon>
></bg-icon>
</span> </span>
</li> </li>
</ul> </ul>
</div> </div>
</template> </template>
<script> <script setup>
import Clipboard from "clipboard"; import Clipboard from "clipboard";
import { reactive, toRefs } from "vue";
export default { import { ElMessage } from "element-plus";
name: "BgInfo", const props = defineProps({
props: {
data: { data: {
type: Array, type: Array,
default: () => [], default: () => [],
...@@ -68,99 +71,97 @@ export default { ...@@ -68,99 +71,97 @@ export default {
type: Number, type: Number,
default: 2, default: 2,
}, },
}, });
model: { const state = reactive({
prop: 'data',
event: 'newValue'
},
data() {
return {
show: false, show: false,
idCardShow: false, idCardShow: false,
stateColor: { stateColor: {
success: '#48ad97', success: "#48ad97",
danger: '#d75138', danger: "#d75138",
default: '#787878' default: "#787878",
}
}
}, },
methods: { });
clipboardSuccess() {
this.$message({ const clipboardSuccess = () => {
ElMessage({
type: "success", type: "success",
message: "复制成功", message: "复制成功",
duration: 1500, duration: 1500,
}); });
}, };
clipboardError() {
this.$message({ const clipboardError = () => {
message: "浏览器不支持自动复制", ElMessage({
type: "warning", type: "warning",
message: "浏览器不支持自动复制",
}); });
}, };
copyText(text, e) {
console.log(text) const copyText = (text, e) => {
console.log(e)
const clipboard = new Clipboard(e.target, { const clipboard = new Clipboard(e.target, {
text: () => text, text: () => text,
}); });
clipboard.on("success", () => { clipboard.on("success", () => {
this.clipboardSuccess(); clipboardSuccess();
// 释放内存 // 释放内存
clipboard.destroy(); clipboard.destroy();
}); });
clipboard.on("error", () => { clipboard.on("error", () => {
// 不支持复制 // 不支持复制
this.clipboardError(); clipboardError();
// 释放内存 // 释放内存
clipboard.destroy(); clipboard.destroy();
}); });
// 解决第一次点击不生效的问题,如果没有,第一次点击会不生效 // 解决第一次点击不生效的问题,如果没有,第一次点击会不生效
clipboard.onClick(e); clipboard.onClick(e);
}, };
copyIcon(data) {
navigator.clipboard.writeText(data).then(
function () {
},
function () {
} const copyIcon = (data) => {
navigator.clipboard.writeText(data).then(
function () {},
function () {}
); );
}, };
download(url) {
const download = (url) => {
const a = document.createElement("a"); // 创建a标签 const a = document.createElement("a"); // 创建a标签
a.setAttribute("download", ""); // download属性 a.setAttribute("download", ""); // download属性
a.setAttribute("href", url); // href链接 a.setAttribute("href", url); // href链接
a.click(); // 自执行点击事件 a.click(); // 自执行点击事件
}, };
changeView(item) { const changeView = (item) => {
if (!this.show) { if (!state.show) {
item.value = item.realValue item.value = item.realValue;
}else { } else {
item.value = "***************" item.value = "***************";
} }
this.show = !this.show state.show = !state.show;
}, };
secret(value) {
const secret = (value) => {
const len = value.length; const len = value.length;
const str1 = value.substring(0,3); const str1 = value.substring(0, 3);
const str2 = value.substring(value.length-6,value.length); const str2 = value.substring(value.length - 6, value.length);
const passwordStr = value.substring(3,value.length-6).split('').map(item => '*').join(''); const passwordStr = value
return str1+passwordStr+str2 .substring(3, value.length - 6)
}, .split("")
idcard(value) { .map((item) => "*")
.join("");
return str1 + passwordStr + str2;
};
const idcard = (value) => {
const len = value.length; const len = value.length;
const str1 = value.substring(0,3); const str1 = value.substring(0, 3);
const str2 = value.substring(value.length-4,value.length); const str2 = value.substring(value.length - 4, value.length);
const passwordStr = value.substring(3,value.length-4).split('').map(item => '*').join(''); const passwordStr = value
return str1+passwordStr+str2 .substring(3, value.length - 4)
}, .split("")
viewIdCard() { .map((item) => "*")
.join("");
} return str1 + passwordStr + str2;
},
}; };
const { show, idCardShow, stateColor } = toRefs(state);
</script> </script>
<template> <template>
<div class="inner-container" :style="{height:height[0]+'px',fontSize:height[2]+'px'}"> <div class="inner-container" :style="{ height: height[0] + 'px', fontSize: height[2] + 'px' }">
<div :style="{height:height[1]+'px',lineHeight:height[1]-2+'px'}" :class="{'now-inner':nowIndex==index}" @click="changeInner(index)" v-for="(item,index) in data" :key="'inner'+index">{{item}}</div> <div
:style="{ height: height[1] + 'px', lineHeight: height[1] - 2 + 'px' }"
:class="{ 'now-inner': nowIndex == index }"
@click="changeInner(index)"
v-for="(item, index) in data"
:key="'inner' + index">
{{ item }}
</div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { reactive, ref,onBeforeMount,toRefs } from 'vue' import { reactive, ref, onBeforeMount, toRefs } from "vue";
const props = defineProps({ const props = defineProps({
modelValue:{ modelValue: {
type: [String,Number], type: [String, Number],
default: 0, default: 0,
}, },
data: { data: {
type: Array, type: Array,
default: [], default: [],
}, },
default:{ default: {
type: [String,Number], type: [String, Number],
default: 0 default: 0,
}, },
height:{ height: {
type:Array, type: Array,
default:[36,32,16] default: [36, 32, 16],
} },
}) });
const emit = defineEmits(['update:modelValue','change']) const emit = defineEmits(["update:modelValue", "change"]);
const nowIndex = ref('') const nowIndex = ref("");
const changeInner = (val)=>{ const changeInner = (val) => {
nowIndex.value = val nowIndex.value = val;
emit('update:modelValue',val) emit("update:modelValue", val);
emit('change',val) emit("change", val);
} };
onBeforeMount(()=>{ onBeforeMount(() => {
nowIndex.value = props.default nowIndex.value = props.default;
}) });
</script> </script>
<style scoped> <style scoped>
.inner-container{ .inner-container {
height: 36px; height: 36px;
background-color: #edeef0; background-color: #edeef0;
border-radius: 4px; border-radius: 4px;
...@@ -48,16 +55,16 @@ onBeforeMount(()=>{ ...@@ -48,16 +55,16 @@ onBeforeMount(()=>{
display: inline-block; display: inline-block;
overflow: hidden; overflow: hidden;
} }
.inner-container div{ .inner-container div {
height: 32px; height: 32px;
line-height: 30px; line-height: 30px;
border-radius: 4px; border-radius: 4px;
padding:0 15px; padding: 0 15px;
float: left; float: left;
color: #404a62; color: #404a62;
cursor: pointer; cursor: pointer;
} }
.inner-container .now-inner{ .inner-container .now-inner {
background-color: #2b4695; background-color: #2b4695;
color: #ffffff; color: #ffffff;
} }
......
...@@ -7,8 +7,7 @@ ...@@ -7,8 +7,7 @@
v-for="(item, index) in btns" v-for="(item, index) in btns"
:key="item" :key="item"
:class="{ current: index === btn }" :class="{ current: index === btn }"
@click="$emit('update:btn', index)" @click="$emit('update:btn', index)">
>
{{ item }} {{ item }}
</li> </li>
</ul> </ul>
...@@ -17,8 +16,7 @@ ...@@ -17,8 +16,7 @@
@click="downloadAction" @click="downloadAction"
v-loading="downloading" v-loading="downloading"
element-loading-spinner="el-icon-loading" element-loading-spinner="el-icon-loading"
v-if="download" v-if="download">
>
<img src="./imgs/btn_daochu.png" /> <img src="./imgs/btn_daochu.png" />
</div> </div>
</div> </div>
...@@ -28,12 +26,11 @@ ...@@ -28,12 +26,11 @@
</div> </div>
</template> </template>
<script> <script setup>
import { reactive, ref, onBeforeMount, toRefs, computed, nextTick } from "vue";
import html2canvas from "html2canvas"; import html2canvas from "html2canvas";
export default { const props = defineProps({
name: "BgLayoutCard",
props: {
title: { title: {
type: String, type: String,
default: "", default: "",
...@@ -58,22 +55,20 @@ export default { ...@@ -58,22 +55,20 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}, });
computed: {
style() { const style = computed(() => {
return {
width: `calc(${this.width} - 20px)`,
height: this.height,
};
},
},
data() {
return { return {
downloading: false, width: `calc(${props.width} - 20px)`,
height: props.height,
}; };
}, });
methods: {
getScrollTop() { const downloading = ref(false);
const content = ref(null);
const getScrollTop = () => {
let scrollTop = 0; let scrollTop = 0;
if (document.documentElement && document.documentElement.scrollTop) { if (document.documentElement && document.documentElement.scrollTop) {
...@@ -83,32 +78,30 @@ export default { ...@@ -83,32 +78,30 @@ export default {
} }
return scrollTop; return scrollTop;
}, };
downloadAction() {
if (this.downloading) { const downloadAction = () => {
if (downloading.value) {
return; return;
} }
let content = this.$refs.content; let { top, left } = content.value.getBoundingClientRect();
let { top, left } = content.getBoundingClientRect(); let scrollTop = getScrollTop();
let scrollTop = this.getScrollTop();
this.downloading = true; downloading.value = true;
html2canvas(content, { x: left, y: top + scrollTop }).then((canvas) => { html2canvas(content.value, { x: left, y: top + scrollTop }).then((canvas) => {
let imgUrl = canvas.toDataURL("image/png"); let imgUrl = canvas.toDataURL("image/png");
let a = document.createElement("a"); // 生成一个a元素 let a = document.createElement("a"); // 生成一个a元素
let event = new MouseEvent("click"); // 创建一个单击事件 let event = new MouseEvent("click"); // 创建一个单击事件
this.$nextTick(() => { nextTick().then(() => {
a.download = this.title; // 设置图片名称 a.download = props.title; // 设置图片名称
a.href = imgUrl; // 将生成的URL设置为a.href属性 a.href = imgUrl; // 将生成的URL设置为a.href属性
a.dispatchEvent(event); // 触发a的单击事件 a.dispatchEvent(event); // 触发a的单击事件
this.downloading = false; downloading.value = false;
}); });
}); });
},
},
}; };
</script> </script>
...@@ -30,10 +30,7 @@ ...@@ -30,10 +30,7 @@
<slot name="filter" /> <slot name="filter" />
</div> </div>
</div> </div>
<div <div class="filter-content" :class="{ 'inline-filters': inlineFilters, 'show-more': visible }">
class="filter-content"
:class="{ 'inline-filters': inlineFilters, 'show-more': visible }"
>
<div class="filter-list"> <div class="filter-list">
<slot name="filters" /> <slot name="filters" />
</div> </div>
...@@ -41,12 +38,8 @@ ...@@ -41,12 +38,8 @@
<div class="filters-right" v-if="$slots['filters-right']"> <div class="filters-right" v-if="$slots['filters-right']">
<slot name="filters-right" /> <slot name="filters-right" />
</div> </div>
<el-button type="primary2" @click="$emit('search-action')"> <el-button type="primary2" @click="$emit('search-action')"> 查询 </el-button>
查询 <el-button type="default2" @click="$emit('search-reset')"> 重置 </el-button>
</el-button>
<el-button type="default2" @click="$emit('search-reset')">
重置
</el-button>
</div> </div>
</div> </div>
</div> </div>
...@@ -73,10 +66,8 @@ ...@@ -73,10 +66,8 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
name: "BgList",
props: {
visible: { visible: {
type: Boolean, type: Boolean,
default: false, default: false,
...@@ -89,6 +80,5 @@ export default { ...@@ -89,6 +80,5 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}, });
};
</script> </script>
<template> <template>
<ul class="nav-list" v-if="list&&list.length"> <ul class="nav-list" v-if="list && list.length">
<li v-for="(item, index) in list" v-show="item.menuType!==2" :key="'nav_' + index"> <li v-for="(item, index) in list" v-show="item.menuType !== 2" :key="'nav_' + index">
<template v-if="item.children && item.children.length&&item.menuType==0"> <template v-if="item.children && item.children.length && item.menuType == 0">
<div <div
class="nav-item nav-more text-clip" class="nav-item nav-more text-clip"
:class="{ current: isCurrent([item.path]) }" :class="{ current: isCurrent([item.path]) }"
@click="showMoreAction(index)" @click="showMoreAction(index)">
> <span :style="{ paddingLeft: `${deep * 2}em` }">
<span :style="{ paddingLeft: `${deep*2}em` }">
<!-- <img v-if="item.icon" :src="item.icon" alt=""> --> <!-- <img v-if="item.icon" :src="item.icon" alt=""> -->
<bg-icon v-if="item.icon" style="color:#7c8292;" :icon="'#'+item.icon"></bg-icon> <bg-icon v-if="item.icon" style="color: #7c8292" :icon="'#' + item.icon"></bg-icon>
{{ item.menuName }} {{ item.menuName }}
<bg-icon v-show="showMore[index] !== false" style="font-size:8px;position: absolute;right: 10px;top: 20px;" icon="#bg-ic-arrow-up"></bg-icon> <bg-icon
<bg-icon v-show="showMore[index] == false" style="font-size:8px;position: absolute;right: 10px;top: 20px;" icon="#bg-ic-arrow-down"></bg-icon> v-show="showMore[index] !== false"
style="font-size: 8px; position: absolute; right: 10px; top: 20px"
icon="#bg-ic-arrow-up"></bg-icon>
<bg-icon
v-show="showMore[index] == false"
style="font-size: 8px; position: absolute; right: 10px; top: 20px"
icon="#bg-ic-arrow-down"></bg-icon>
</span> </span>
&ensp; &ensp;
</div> </div>
...@@ -21,18 +26,20 @@ ...@@ -21,18 +26,20 @@
:list="item.children" :list="item.children"
:deep="deep + 1" :deep="deep + 1"
:highlight-parent-rule="highlightParentRule" :highlight-parent-rule="highlightParentRule"
v-if="showMore[index] !== false" v-if="showMore[index] !== false" />
/>
</transition> </transition>
</template> </template>
<template v-else> <template v-else>
<div <div
class="nav-item text-clip" class="nav-item text-clip"
:class="{current:isCurrent(item.children&&item.children.length?[...getChildrenPath(item.children),item.path]:[item.path])}" :class="{
@click="$router.push(item.path)" current: isCurrent(
> item.children && item.children.length ? [...getChildrenPath(item.children), item.path] : [item.path]
<span :style="{ paddingLeft: item.icon ? `${deep*2 - 1.37}em` :`${deep*2}em` }"> ),
<bg-icon v-if="item.icon" style="color:#7c8292;" :icon="'#'+item.icon"></bg-icon> }"
@click="$router.push(item.path)">
<span :style="{ paddingLeft: item.icon ? `${deep * 2 - 1.37}em` : `${deep * 2}em` }">
<bg-icon v-if="item.icon" style="color: #7c8292" :icon="'#' + item.icon"></bg-icon>
{{ item.menuName }} {{ item.menuName }}
</span> </span>
</div> </div>
...@@ -44,7 +51,11 @@ ...@@ -44,7 +51,11 @@
<script> <script>
export default { export default {
name: "NavList", name: "NavList",
props: { };
</script>
<script setup>
import { reactive } from "vue";
const props = defineProps({
list: { list: {
type: Array, type: Array,
required: true, required: true,
...@@ -56,36 +67,30 @@ export default { ...@@ -56,36 +67,30 @@ export default {
highlightParentRule: { highlightParentRule: {
type: Function, type: Function,
}, },
}, });
data() {
return {
showMore: {},
};
},
methods: {
showMoreAction(index) {
let flag = this.showMore[index];
const showMore = reactive({});
const showMoreAction = (index) => {
let flag = showMore[index];
if (flag === undefined) { if (flag === undefined) {
flag = true; flag = true;
} }
this.showMore[index] = !flag showMore[index] = !flag;
}, };
getChildrenPath(arr,temp=[]){
arr.forEach(e => { const getChildrenPath = (arr, temp = []) => {
temp.push(e.path) arr.forEach((e) => {
if(e.children&&e.children.length){ temp.push(e);
this.getChildrenPath(e.children,temp) if (e.children && e.children.length) {
getChildrenPath(e.children, temp);
} }
}); });
return temp return temp;
}, };
isCurrent(path) {
return ( const isCurrent = (path) => {
(this.highlightParentRule && this.highlightParentRule(path)) || false return (props.highlightParentRule && props.highlightParentRule(path)) || false;
);
},
},
}; };
</script> </script>
...@@ -9,15 +9,10 @@ ...@@ -9,15 +9,10 @@
</div> </div>
</template> </template>
<script> <script setup>
import NavList from "./bg-nav-list.vue"; import NavList from "./bg-nav-list.vue";
export default { const props = defineProps({
name: "BgNav",
components: {
NavList,
},
props: {
title: { title: {
type: String, type: String,
default: "", default: "",
...@@ -33,6 +28,5 @@ export default { ...@@ -33,6 +28,5 @@ export default {
highlightParentRule: { highlightParentRule: {
type: Function, type: Function,
}, },
}, });
};
</script> </script>
...@@ -10,8 +10,7 @@ ...@@ -10,8 +10,7 @@
@size-change="changeSize" @size-change="changeSize"
@current-change="changePage" @current-change="changePage"
:background="background" :background="background"
:disabled="disabled" :disabled="disabled" />
/>
</div> </div>
</template> </template>
...@@ -19,11 +18,11 @@ ...@@ -19,11 +18,11 @@
const props = defineProps({ const props = defineProps({
small: { small: {
type: Boolean, type: Boolean,
default: () => false default: () => false,
}, },
page: { page: {
type: Number, type: Number,
default: 1 default: 1,
}, },
size: { size: {
type: Number, type: Number,
...@@ -31,32 +30,32 @@ const props = defineProps({ ...@@ -31,32 +30,32 @@ const props = defineProps({
}, },
pageSizes: { pageSizes: {
type: Array, type: Array,
default: [10,50,100] default: [10, 50, 100],
}, },
total: { total: {
type: Number, type: Number,
default: 0 default: 0,
}, },
layout: { layout: {
type: String, type: String,
default: "total, sizes, prev, pager, next, jumper" default: "total, sizes, prev, pager, next, jumper",
}, },
background: { background: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
disabled: { disabled: {
type: Boolean, type: Boolean,
default: false default: false,
} },
}) });
const emit = defineEmits(['change-page','change-size']) const emit = defineEmits(["change-page", "change-size"]);
const changePage = (val) => { const changePage = (val) => {
emit("change-page",val) emit("change-page", val);
} };
const changeSize = (val) => { const changeSize = (val) => {
emit("change-size",val) emit("change-size", val);
} };
</script> </script>
...@@ -4,24 +4,18 @@ ...@@ -4,24 +4,18 @@
class="bg-permission-option--self" class="bg-permission-option--self"
:class="{ :class="{
'full-option': !(option.children && option.children.length > 0), 'full-option': !(option.children && option.children.length > 0),
}" }">
> <el-checkbox v-model="option.isSelected" :indeterminate="option.isIndeterminate" @change="changeSelf">
<el-checkbox
v-model="option.isSelected"
:indeterminate="option.isIndeterminate"
@change="changeSelf"
>
<span :title="option.name + (option.remark ? `(${option.remark})` : '')"> <span :title="option.name + (option.remark ? `(${option.remark})` : '')">
{{ option.name }} {{ option.name }}
{{option.remark ? `(${option.remark})` : ""}} {{ option.remark ? `(${option.remark})` : "" }}
</span> </span>
</el-checkbox> </el-checkbox>
</div> </div>
<div <div
class="bg-permission-option--list" class="bg-permission-option--list"
:class="{ 'flex-wrap': deep === depth - 1 }" :class="{ 'flex-wrap': deep === depth - 1 }"
v-if="option.children && option.children.length > 0" v-if="option.children && option.children.length > 0">
>
<BgPermissionOption <BgPermissionOption
v-for="(item, index) in option.children" v-for="(item, index) in option.children"
:ref="`child${index}`" :ref="`child${index}`"
...@@ -29,16 +23,14 @@ ...@@ -29,16 +23,14 @@
:key="`opt_${index}`" :key="`opt_${index}`"
:deep="deep + 1" :deep="deep + 1"
:depth="depth" :depth="depth"
@change="changeChild" @change="changeChild" />
/>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup>
export default { import { nextTick } from "vue";
name: "BgPermissionOption", const props = defineProps({
props: {
option: { option: {
type: Object, type: Object,
require: true, require: true,
...@@ -51,49 +43,46 @@ export default { ...@@ -51,49 +43,46 @@ export default {
type: Number, type: Number,
default: 1, default: 1,
}, },
}, });
methods: {
changeSelf() { const dealData = (arr, flag) => {
let isSelected = this.option.isSelected; arr.forEach((e) => {
let children = this.option.children || []; e.isSelected = flag;
if (e.children && e.children.length) {
dealData(e.children, flag);
}
});
};
const emit = defineEmits(["change"]);
const changeSelf = () => {
let isSelected = props.option.isSelected;
let children = props.option.children || [];
// 将自己的选中状态赋值给子级 // 将自己的选中状态赋值给子级
if (children.length > 0) { if (children.length > 0) {
children.forEach((v, i) => { dealData(children, isSelected);
v.isSelected = isSelected;
this.$nextTick(() => {
this.$refs[`child${i}`][0].changeSelf();
});
});
} }
// 关于自己选中都是全选和不选,所以不存在半选状态 // 关于自己选中都是全选和不选,所以不存在半选状态
this.option.isIndeterminate = false; props.option.isIndeterminate = false;
// 修改完自己和自己子级,告诉父级更新 // 修改完自己和自己子级,告诉父级更新
this.$emit("change"); emit("change");
}, // 本级选中状态发生变化 };
changeChild() {
const changeChild = () => {
let isSelected = true; let isSelected = true;
let isIndeterminate = false; let isIndeterminate = false;
let children = this.option.children; let children = props.option.children;
children.forEach((v, i) => { children.forEach((v, i) => {
isSelected = isSelected && v.isSelected; // 所有子级都为选中时,自己才为选中状态 isSelected = isSelected && v.isSelected; // 所有子级都为选中时,自己才为选中状态
isIndeterminate = isIndeterminate || v.isIndeterminate || v.isSelected; // 只要有下级为半选状态或选中状态,自己就为半选状态 isIndeterminate = isIndeterminate || v.isIndeterminate || v.isSelected; // 只要有下级为半选状态或选中状态,自己就为半选状态
}); });
// 自己为全选状态时,半选不生效 // 自己为全选状态时,半选不生效
isIndeterminate = isSelected ? false : isIndeterminate; isIndeterminate = isSelected ? false : isIndeterminate;
// 赋值 // 赋值
this.option.isSelected = isSelected; props.option.isSelected = isSelected;
this.option.isIndeterminate = isIndeterminate; props.option.isIndeterminate = isIndeterminate;
// 修改完自己和自己子级,告诉父级更新 // 修改完自己和自己子级,告诉父级更新
this.$emit("change"); emit("change");
}, // 下级选中状态发生变化
},
}; };
</script> </script>
<template> <template>
<div class="bg-permission"> <div class="bg-permission">
<div class="permission-header" v-if="selectAll"> <div class="permission-header" v-if="selectAll">
<el-checkbox <el-checkbox v-model="isSelected" :indeterminate="isIndeterminate" @change="changeSelf"> 全选 </el-checkbox>
v-model="isSelected"
:indeterminate="isIndeterminate"
@change="changeSelf"
>
全选
</el-checkbox>
</div> </div>
<div class="permission-null" v-if="permissionData.length === 0"> <div class="permission-null" v-if="permissionData.length === 0">
<p>暂无数据</p> <p>暂无数据</p>
...@@ -20,26 +14,16 @@ ...@@ -20,26 +14,16 @@
:key="`opt_${index}`" :key="`opt_${index}`"
:props="props" :props="props"
:depth="depth" :depth="depth"
@change="changeChild" @change="changeChild" />
/>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup>
import { val } from "dom7"; import { computed, reactive, toRefs, watch, nextTick, onMounted } from "vue";
import BgPermissionOption from "./bg-permission-option.vue"; import BgPermissionOption from "./bg-permission-option.vue";
export default { const props = defineProps({
name: "BgPermission",
components: {
BgPermissionOption,
},
model: {
prop: "values",
event: "change",
},
props: {
values: { values: {
type: Array, type: Array,
default: () => [], default: () => [],
...@@ -60,175 +44,154 @@ export default { ...@@ -60,175 +44,154 @@ export default {
type: Boolean, type: Boolean,
default: true, default: true,
}, // 是否在顶部显示全选按钮 }, // 是否在顶部显示全选按钮
}, });
data() {
return { const state = reactive({
initFlag: true, // 是否需要初始化 initFlag: true, // 是否需要初始化
permissionData: [], // 数据项 permissionData: [], // 数据项
isSelected: false, // 是否全选 isSelected: false, // 是否全选
isIndeterminate: false, // 是否半选 isIndeterminate: false, // 是否半选
}; });
},
computed: { const emit = defineEmits(["changeMenu"]);
depth() {
return this.getDepth({ children: this.permissionData }); const depth = computed(() => {
}, // 数据层级深度 return getDepth({ children: state.permissionData });
}, });
watch: {
values: { watch(
handler() { () => props.values,
if (this.initFlag) { () => {
this.initPermissionData(); if (state.initFlag) {
initPermissionData();
} }
state.initFlag = true;
}
);
this.initFlag = true; watch(
}, () => props.options,
deep: true, () => {
}, initPermissionData();
options: { }
handler() { );
this.initPermissionData();
}, const getDepth = (node) => {
deep: true, if (!node.children || node.children.length === 0) {
}, return 1;
}, }
methods: {
initPermissionData() { let maxChildrenDepth = [...node.children].map((v) => getDepth(v));
let {
name: nameProp, return Math.max(...maxChildrenDepth) + 1;
value: valueProp, }; // 获取JsonTree深度
children: childrenProp,
remark: remarkProp, const initPermissionData = () => {
} = this.props; let { name: nameProp, value: valueProp, children: childrenProp, remark: remarkProp } = props.props;
let permissionData = []; let permissionData = [];
let traverseOptions = (item) => { let traverseOptions = (item) => {
let result = {}; let result = {};
let name = item[nameProp]; let name = item[nameProp];
let value = item[valueProp]; let value = item[valueProp];
let children = item[childrenProp]; let children = item[childrenProp];
let isSelected = this.values.indexOf(value) > -1; let isSelected = props.values.indexOf(value) > -1;
let isIndeterminate = false; let isIndeterminate = false;
let remark = item[remarkProp]; let remark = item[remarkProp];
result.name = name; result.name = name;
result.value = value; result.value = value;
result.remark = remark; result.remark = remark;
if (children && children.length > 0) { if (children && children.length > 0) {
result.children = []; result.children = [];
isSelected = true; // 如果存在子节点,则根据子节点反推当前节点选中状态 isSelected = true; // 如果存在子节点,则根据子节点反推当前节点选中状态
isIndeterminate = false; // 当前节点半选状态 isIndeterminate = false; // 当前节点半选状态
children.forEach((v) => { children.forEach((v) => {
result.children.push(traverseOptions(v)); result.children.push(traverseOptions(v));
}); });
result.children.forEach((v) => { result.children.forEach((v) => {
isSelected = isSelected && v.isSelected; // 所有子节点都为选中状态,则当前节点选中状态为真 isSelected = isSelected && v.isSelected; // 所有子节点都为选中状态,则当前节点选中状态为真
isIndeterminate = isIndeterminate || v.isSelected || v.isIndeterminate; // 所有下级节点只要存在一个选中状态,则当前节点半选状态为真 isIndeterminate = isIndeterminate || v.isSelected || v.isIndeterminate; // 所有下级节点只要存在一个选中状态,则当前节点半选状态为真
}); });
} }
result.isSelected = isSelected; result.isSelected = isSelected;
result.isIndeterminate = isSelected ? false : isIndeterminate; // 当前节点选中状态为真时,半选为假 result.isIndeterminate = isSelected ? false : isIndeterminate; // 当前节点选中状态为真时,半选为假
return result; return result;
}; };
props.options.forEach((v) => {
this.options.forEach((v) => {
permissionData.push(traverseOptions(v)); permissionData.push(traverseOptions(v));
}); });
this.permissionData = permissionData; state.permissionData = permissionData;
// 初始化完数据项后要更新一下全选半选状态 // 初始化完数据项后要更新一下全选半选状态
if (permissionData.length > 0) { if (permissionData.length > 0) {
this.$nextTick(() => { nextTick(() => {
this.changeChild(); changeChild();
}); });
} }
}, // 初始化数据项 }; // 初始化数据项
getDepth(node) {
if (!node.children || node.children.length === 0) {
return 1;
}
let maxChildrenDepth = [...node.children].map((v) => this.getDepth(v)); const dealData = (arr, flag) => {
arr.forEach((e) => {
return Math.max(...maxChildrenDepth) + 1; e.isSelected = !!flag;
}, // 获取JsonTree深度 if (e.children && e.children.length) {
changeSelf() { dealData(e.children, flag);
let isSelected = this.isSelected; }
let children = this.permissionData || []; });
};
const changeSelf = () => {
let isSelected = state.isSelected;
let children = state.permissionData || [];
// 将自己的选中状态赋值给子级 // 将自己的选中状态赋值给子级
if (children.length > 0) { if (children.length > 0) {
children.forEach((v, i) => { dealData(children, isSelected);
v.isSelected = isSelected;
this.$nextTick(() => {
this.$refs[`child${i}`][0].changeSelf();
});
});
} }
// 关于自己选中都是全选和不选,所以不存在半选状态 // 关于自己选中都是全选和不选,所以不存在半选状态
this.isIndeterminate = false; state.isIndeterminate = false;
// 出发双向绑定事件 // 出发双向绑定事件
this.changeValues(); changeValues();
}, // 改变全选状态 }; // 改变全选状态
changeChild() { const changeChild = () => {
let isSelected = true; let isSelected = true;
let isIndeterminate = false; let isIndeterminate = false;
let children = this.permissionData; let children = state.permissionData;
children.forEach((v, i) => { children.forEach((v, i) => {
isSelected = isSelected && v.isSelected; // 所有子级都为选中时,自己才为选中状态 isSelected = isSelected && v.isSelected; // 所有子级都为选中时,自己才为选中状态
isIndeterminate = isIndeterminate || v.isIndeterminate || v.isSelected; // 只要有下级为半选状态,自己就为半选状态 isIndeterminate = isIndeterminate || v.isIndeterminate || v.isSelected; // 只要有下级为半选状态,自己就为半选状态
}); });
// 自己为全选状态时,半选不生效 // 自己为全选状态时,半选不生效
isIndeterminate = isSelected ? false : isIndeterminate; isIndeterminate = isSelected ? false : isIndeterminate;
// 赋值 // 赋值
this.isSelected = isSelected; state.isSelected = isSelected;
this.isIndeterminate = isIndeterminate; state.isIndeterminate = isIndeterminate;
// 出发双向绑定事件 // 出发双向绑定事件
this.changeValues(); changeValues();
}, // 下级选中状态发生变化 }; // 下级选中状态发生变化
changeValues() {
const changeValues = () => {
let values = []; let values = [];
let traverseOptions = ({ let i = 1;
isSelected, let traverseOptions = ({ isSelected, isIndeterminate, value, children, name }) => {
isIndeterminate,
value,
children,
}) => {
if (isSelected) { if (isSelected) {
values.push(value); values.push(value);
} }
if (isIndeterminate) { if (isIndeterminate) {
values.push(value); values.push(value);
} }
if (children && children.length > 0) { if (children && children.length > 0) {
children.forEach((v) => { children.forEach((v) => {
traverseOptions(v); traverseOptions(v);
}); });
} }
}; };
state.permissionData.forEach((v) => {
this.permissionData.forEach((v) => {
traverseOptions(v); traverseOptions(v);
}); });
this.initFlag = false; // 防止在watch中出发重新初始化 state.initFlag = false; // 防止在watch中出发重新初始化
this.$emit("changeMenu", values); emit("changeMenu", values);
}, // 双向绑定的处理 }; // 双向绑定的处理
},
mounted() { onMounted(() => {
this.initPermissionData(); initPermissionData();
}, });
};
const { permissionData, isSelected, isIndeterminate } = toRefs(state);
</script> </script>
<template> <template>
<div style="border: 1px solid #ccc;z-index: 100;"> <div style="border: 1px solid #ccc; z-index: 100">
<Toolbar <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
style="border-bottom: 1px solid #ccc"
:editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="mode"
/>
<Editor <Editor
style="height: 500px; overflow-y: hidden;" style="height: 500px; overflow-y: hidden"
v-model="valueHtml" v-model="valueHtml"
@onChange="handleChange" @onChange="handleChange"
@onBlur="handleBlur" @onBlur="handleBlur"
:defaultConfig="editorConfig" :defaultConfig="editorConfig"
:mode="mode" :mode="mode"
@onCreated="handleCreated" @onCreated="handleCreated" />
/>
</div> </div>
</template> </template>
<script setup> <script setup>
import '@wangeditor/editor/dist/css/style.css' // 引入 css import "@wangeditor/editor/dist/css/style.css"; // 引入 css
import { onBeforeUnmount, ref, shallowRef, onMounted, watch } from 'vue' import { onBeforeUnmount, ref, shallowRef, onMounted } from "vue";
import { Editor, Toolbar } from '@wangeditor/editor-for-vue' import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { import { useFormItem } from "element-plus";
useFormItem,
} from 'element-plus'
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
type: String, type: String,
default: '', default: "",
}, },
disabled:{ disabled: {
type:Boolean, type: Boolean,
default:false default: false,
}, },
mode: { mode: {
type: String, type: String,
default: 'default' default: "default",
} },
}) });
const emit = defineEmits(['update:modelValue','change','blur']) const emit = defineEmits(["update:modelValue", "change", "blur"]);
const valueHtml = ref('') const valueHtml = ref("");
// change次数
let changeNum = ref(0);
const { formItem } = useFormItem() const { formItem } = useFormItem();
const editorRef = shallowRef() const editorRef = shallowRef();
onMounted(() => { onMounted(() => {
setTimeout(()=>{ setTimeout(() => {
valueHtml.value = props.modelValue valueHtml.value = props.modelValue;
}) });
}) });
const toolbarConfig = {} const toolbarConfig = {};
const editorConfig = { placeholder: '请输入内容...' } const editorConfig = {
placeholder: "请输入内容...",
MENU_CONF: {
uploadImage: {
server: "/apaas/common/image/upload", // 服务器地址
fieldName: "file", // 上传的文件的字段名称
meta: {
directory: "image",
}, // 上传图片必须携带的参数
maxFileSize: 2 * 1024 * 1024, // 图片最大2M
timeout: 3 * 60 * 1000, // 超时时间3分钟
allowedFileTypes: ["image/jpg", "image/png", "image/gif", "image/jpeg"],
customInsert(res, insertFn) {
// res 即服务端的返回结果
// 从 res 中找到 url alt href ,然后插图图片 url是必须,href和alt可以为""
let url = res.data;
let alt = "";
let href = res.data;
insertFn(url, alt, href);
},
onBeforeUpload(file) {
// 可以 return
// 1. return file 或者 new 一个 file ,接下来将上传
// 2. return false ,不上传这个 file
let allowedType = ["jpg", "png", "jpeg", "gif", "bmp", "tiff"]; // 常见的图片格式
let data = Object.values(file)[0];
if (allowedType.indexOf(data.extension) == -1) {
alert(`图片验证未通过,【${data.name}】不是图片`);
return false;
} else {
return file;
}
},
onError(file, err, res) {
console.log(`${file.name} 上传出错`, err, res);
},
},
},
};
onBeforeUnmount(() => { onBeforeUnmount(() => {
const editor = editorRef.value const editor = editorRef.value;
if (editor == null) return if (editor == null) return;
editor.destroy() editor.destroy();
}) });
const handleCreated = (editor) => { const handleCreated = (editor) => {
editorRef.value = editor // 记录 editor 实例,重要! editorRef.value = editor; // 记录 editor 实例,重要!
if(props.disabled){ if (props.disabled) {
editor.disable() editor.disable();
} }
} };
const handleChange = ()=>{ const handleChange = () => {
emit("update:modelValue", valueHtml.value); //初始化会默认赋值<p><br></p>
} //会对原有数据造成影响,return掉
const handleBlur = ()=>{ changeNum.value++;
formItem?.validate?.('blur').catch((err) => console.warn(err)) if (changeNum.value == 1) {
} return;
watch(
() => props.modelValue,
(n,o) => {
valueHtml.value = n
} }
) emit("update:modelValue", valueHtml.value);
};
const handleBlur = () => {
formItem?.validate?.("blur").catch((err) => console.warn(err));
};
</script> </script>
...@@ -3,23 +3,16 @@ ...@@ -3,23 +3,16 @@
<a <a
v-for="(item, index) in types" v-for="(item, index) in types"
:key="'name_' + index" :key="'name_' + index"
:class="{ current: item.value === value }" :class="{ current: item.value === modelValue }"
@click="selectAction(item)" @click="selectAction(item)">
>
{{ item.name }} {{ item.name }}
</a> </a>
</div> </div>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
name: "BgSort", modelValue: {
model: {
prop: "value",
event: "change",
},
props: {
value: {
type: [Number, String], type: [Number, String],
default: "", default: "",
}, },
...@@ -44,11 +37,9 @@ export default { ...@@ -44,11 +37,9 @@ export default {
}, },
], ],
}, },
}, });
methods: { const emit = defineEmits(["update:modelValue"]);
selectAction({ value }) { const selectAction = ({ value }) => {
this.$emit("change", value); emit("update:modelValue", value);
},
},
}; };
</script> </script>
<template>
<div class="bg-step" v-show="active === step">
<div class="step-content">
<slot />
</div>
<div class="step-action bg-form">
<slot name="action" />
</div>
</div>
</template>
<script>
export default {
name: "BgStep",
inject: {
getActive: {
type: Function,
default: () => {
return this.$parent.getActive;
},
},
},
props: {
title: {
type: String,
default: "",
},
step: {
type: Number,
required: true,
},
icon: {
required: true,
},
},
computed: {
active() {
return this.getActive();
},
},
};
</script>
<template>
<div class="bg-steps">
<div class="bg-steps-container">
<div class="steps-nav">
<ul>
<template v-for="(item, index) in calcSteps()" :key="'tab_' + index">
<li
class="step-line"
:class="{
done: active > index,
current: active === index,
}"
v-if="index > 0"
></li>
<li
class="step-item"
:class="{
done: active > index,
current: active === index,
}"
>
<div class="step-icon">
<!-- -->
</div>
<div class="step-hightlight-icon">
<img :src="item.icon" />
</div>
<div class="step-title">
<p>
{{ item.title || "完成" }}
</p>
<p v-if="item.title">
<template v-if="active > index">
已完成
</template>
<template v-else-if="active === index">
进行中
</template>
<template v-else>
未进行
</template>
</p>
</div>
</li>
<li
class="step-line"
:class="{
done: active > index,
current: active === index,
}"
v-if="index < calcSteps().length - 1"
></li>
</template>
</ul>
</div>
<div class="steps-content">
<slot />
</div>
</div>
</div>
</template>
<script>
export default {
name: "BgDetail",
provide() {
return {
getActive: () => {
return this.active;
},
};
},
props: {
active: {
type: Number,
default: 0,
},
},
data() {
return {
showFixedBars: false,
scrollCallback: null,
};
},
methods: {
calcSteps() {
let stepSlots = [];
if (this.$slots.default) {
stepSlots = this.$slots.default
.filter(
(vnode) =>
vnode.tag &&
vnode.componentOptions &&
vnode.componentOptions.Ctor.options.name === "BgStep"
)
.map((vnode) => {
return vnode.componentOptions.propsData;
});
}
return stepSlots;
},
},
};
</script>
...@@ -7,17 +7,16 @@ ...@@ -7,17 +7,16 @@
inline-prompt inline-prompt
:active-text="activeText" :active-text="activeText"
:inactive-text="inactiveText" :inactive-text="inactiveText"
@change="changeState" @change="changeState" />
/>
</template> </template>
<script setup> <script setup>
import { onMounted, reactive, toRefs, watch } from "vue" import { onMounted, reactive, toRefs, watch } from "vue";
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
type: Number, type: Number,
default: 0 default: 0,
}, },
activeText: { activeText: {
type: String, type: String,
...@@ -25,30 +24,30 @@ const props = defineProps({ ...@@ -25,30 +24,30 @@ const props = defineProps({
}, },
inactiveText: { inactiveText: {
type: String, type: String,
default: "" default: "",
}, },
rowId: { rowId: {
type: Number, type: Number,
default: null default: null,
} },
}) });
const state = reactive({ const state = reactive({
value: 1 value: 1,
}) });
const emit = defineEmits(['changeState']) const emit = defineEmits(["changeState"]);
const changeState = () => { const changeState = () => {
if (props.rowId) { if (props.rowId) {
let params = { let params = {
state: state.value, state: state.value,
id: props.rowId id: props.rowId,
} };
emit('changeState',params) emit("changeState", params);
}else { } else {
emit('changeState',state.value) emit("changeState", state.value);
} }
} };
onMounted(()=> { onMounted(() => {
state.value = props.modelValue state.value = props.modelValue;
}) });
const { value } = toRefs(state) const { value } = toRefs(state);
</script> </script>
<template> <template>
<div <div ref="bgSwitch" class="bg-switch" :class="{ disabled: disabled }" :style="now_style" @click="switch_data">
ref="bg_switch"
class="bg-switch"
:class="{ disabled: disabled }"
:style="now_style"
@click="switch_data"
>
<span class="label" :style="now_label_style"> <span class="label" :style="now_label_style">
{{ labels[now_index] }} {{ labels[now_index] }}
</span> </span>
...@@ -15,10 +9,9 @@ ...@@ -15,10 +9,9 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { import { ref, computed, onMounted } from "vue";
name: "BgSwitch", const props = defineProps({
props: {
modelValue: { modelValue: {
type: [Boolean, Number, String], type: [Boolean, Number, String],
default: 0, default: 0,
...@@ -39,62 +32,63 @@ export default { ...@@ -39,62 +32,63 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}, });
emits: ['update:modelValue'],
data() { const emit = defineEmits(["update:modelValue"]);
return {
gap: 0, const gap = ref(0);
box_height: 0,
circle_height: 0, const box_height = ref(0);
};
}, const circle_height = ref(0);
computed: {
now_index() { const now_index = computed(() => {
if (this.values[0] == this.modelValue) { if (props.values[0] == props.modelValue) {
return 0; return 0;
} else { } else {
return 1; return 1;
} }
}, });
now_style() {
const now_style = computed(() => {
return { return {
borderColor: this.colors[this.now_index], borderColor: props.colors[now_index.value],
backgroundColor: this.colors[this.now_index], backgroundColor: props.colors[now_index.value],
}; };
}, });
now_label_style() {
return this.now_index == 0 const now_label_style = computed(() => {
? { left: this.circle_height + this.gap + 5 + "px" } return now_index.value == 0 ? { left: circle_height.value + gap.value + 5 + "px" } : { left: "6px" };
: { left: "6px" }; });
},
now_circle_style() {
return this.now_index == 0
? {
left: this.gap + "px",
const now_circle_style = computed(() => {
return now_index.value == 0
? {
left: gap.value + "px",
} }
: { : {
left: 'calc(100% - 15px)', left: "calc(100% - 16px)",
}; };
}, });
},
methods: { const switch_data = () => {
switch_data() { if (props.disabled) {
if (this.disabled) {
return; return;
} }
if (this.values[0] == this.modelValue) { if (props.values[0] == props.modelValue) {
this.$emit("update:modelValue", this.values[1]); emit("update:modelValue", props.values[1]);
} else { } else {
this.$emit("update:modelValue", this.values[0]); emit("update:modelValue", props.values[0]);
} }
},
},
mounted() {
this.box_height = this.$refs.bg_switch.offsetHeight;
this.circle_height = this.$refs.circle.offsetHeight;
this.gap = (this.box_height - this.circle_height - 4) / 2;
},
}; };
const bgSwitch = ref(null);
const circle = ref(null);
onMounted(() => {
box_height.value = bgSwitch.value.offsetHeight;
circle_height.value = circle.value.offsetHeight;
gap.value = (box_height.value - circle_height.value - 4) / 2;
});
</script> </script>
...@@ -9,24 +9,19 @@ ...@@ -9,24 +9,19 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { import { reactive, ref, onBeforeMount, toRefs, computed, inject } from "vue";
name: "BgTab",
inject: { const getActiveName = inject(
getActiveName: { "activeName",
type: Function, () => {
default: () => { return "";
return this.$parent.activeName; },
}, false
}, );
getIsTabs: { const getIsTabs = inject("isTabs", false);
type: Function,
default: () => { const props = defineProps({
return false;
},
},
},
props: {
label: { label: {
type: String, type: String,
required: true, required: true,
...@@ -35,17 +30,17 @@ export default { ...@@ -35,17 +30,17 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
}, });
computed: {
activeName() { const activeName = computed(() => {
return this.getActiveName(); return getActiveName();
}, });
isTabs() { const isTabs = computed(() => {
return this.getIsTabs(); return getIsTabs;
}, });
showTab() { const showTab = computed(() => {
if (this.isTabs) { if (isTabs.value) {
if (this.activeName === this.name) { if (activeName.value === props.name) {
return true; return true;
} else { } else {
return false; return false;
...@@ -53,7 +48,5 @@ export default { ...@@ -53,7 +48,5 @@ export default {
} else { } else {
return true; return true;
} }
}, });
},
};
</script> </script>
...@@ -4,10 +4,8 @@ ...@@ -4,10 +4,8 @@
</a> </a>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
name: "BgTableBtn",
props: {
disabled: { disabled: {
type: Boolean, type: Boolean,
default: false, default: false,
...@@ -16,18 +14,15 @@ export default { ...@@ -16,18 +14,15 @@ export default {
type: Function, type: Function,
default: () => null, default: () => null,
}, },
}, });
emits: ["click"],
methods: {
clickAction() {
if (this.disabled) {
return;
}
this.$emit("click"); const emit = defineEmits(["click"]);
this.click && this.click(); const clickAction = () => {
}, if (props.disabled) {
}, return;
}
emit("click");
props.click && props.click();
}; };
</script> </script>
...@@ -3,13 +3,12 @@ ...@@ -3,13 +3,12 @@
ref="table" ref="table"
class="bg-table bg-table-pro" class="bg-table bg-table-pro"
:class="{ 'bg-table-tree': !!rowKey }" :class="{ 'bg-table-tree': !!rowKey }"
v-bind="$attrs" v-bind="attrs"
:data="data" :data="data"
:row-key="rowKey" :row-key="rowKey"
:tree-props="treeProps" :tree-props="treeProps"
@selection-change="selectionChange" @selection-change="selectionChange"
:default-expand-all="defaultExpandAll" :default-expand-all="defaultExpandAll">
>
<el-table-column width="60" v-if="showIndex"> <el-table-column width="60" v-if="showIndex">
<template v-slot:header> <template v-slot:header>
<p style="width: 100%; text-align: center">序号</p> <p style="width: 100%; text-align: center">序号</p>
...@@ -18,13 +17,7 @@ ...@@ -18,13 +17,7 @@
<p style="width: 100%; text-align: center">{{ $index + 1 }}</p> <p style="width: 100%; text-align: center">{{ $index + 1 }}</p>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column type="selection" :selectable="selectable" width="60" align="center" v-if="showSelectColumn" />
type="selection"
:selectable="selectable"
width="60"
align="center"
v-if="showSelctColumn"
/>
<el-table-column <el-table-column
v-for="(header, index) in headers" v-for="(header, index) in headers"
:key="`col_${index}`" :key="`col_${index}`"
...@@ -32,8 +25,7 @@ ...@@ -32,8 +25,7 @@
:label="header.label" :label="header.label"
:align="header.align" :align="header.align"
:show-overflow-tooltip="!$slots[header.prop]" :show-overflow-tooltip="!$slots[header.prop]"
:fixed="header.fixed" :fixed="header.fixed">
>
<template v-slot:header> <template v-slot:header>
<template v-if="$slots[`header-${header.prop}`]"> <template v-if="$slots[`header-${header.prop}`]">
<slot :name="`header-${header.prop}`" /> <slot :name="`header-${header.prop}`" />
...@@ -63,10 +55,12 @@ ...@@ -63,10 +55,12 @@
</el-table> </el-table>
</template> </template>
<script> <script setup>
export default { import { useAttrs, ref, computed, watch, nextTick } from "vue";
name: "BgTablePro",
props: { const attrs = useAttrs();
const props = defineProps({
headers: { headers: {
type: Array, type: Array,
require: true, require: true,
...@@ -91,80 +85,74 @@ export default { ...@@ -91,80 +85,74 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}, });
data() {
return { const emit = defineEmits(["select"]);
allSelection: [], // 所有页面上的选中的数据
}; const allSelection = ref([]);
},
computed: { const showSelectColumn = computed(() => {
showSelctColumn() { return attrs && (attrs["selection-change"] || attrs["select"]);
return ( }); // 是否显示选中列
this.$attrs &&
(this.$attrs["selection-change"] || this.$attrs["select"]) const addSelectEvent = computed(() => {
); return attrs && attrs["select"];
}, // 是否显示选中列 });
addSelectEvent() {
return this.$attrs && this.$attrs["select"]; watch(
}, // 是否监听select事件 select事件会记录所有页面上的选中的数据 () => props.data,
}, () => {
watch: { recoverSelection();
data: { }
handler() { );
this.recoverSelection();
}, const table = ref(null);
deep: true,
}, const recoverSelection = () => {
}, let selectionIds = allSelection.value.map((v) => v[props.rowKey]);
methods: { props.data.forEach((v) => {
recoverSelection() { if (selectionIds.indexOf(v[props.rowKey]) > -1) {
let selectionIds = this.allSelection.map((v) => v[this.rowKey]); nextTick(() => {
table.value.toggleRowSelection(v, true);
this.data.forEach((v) => {
if (selectionIds.indexOf(v[this.rowKey]) > -1) {
this.$nextTick(() => {
console.log({ ...v });
this.$refs.table.toggleRowSelection(v, true);
}); });
} }
}); });
}, // 恢复选中 }; // 恢复选中
selectionChange(selection) {
if (!this.addSelectEvent) return; // 如果用户未监听select事件,则不执行 const selectionChange = (selection) => {
if (!addSelectEvent.value) return; // 如果用户未监听select事件,则不执行
if (!this.rowKey) throw Error("监听select事件时,row-key必须传入!"); if (!props.rowKey) throw Error("监听select事件时,row-key必须传入!");
this.upAllSelection(selection); upAllSelection(selection);
this.$emit("select", this.allSelection); emit("select", allSelection.value);
}, // select事件 }; // select事件
upAllSelection(selection) { const upAllSelection = (selection) => {
let rowIds = this.data.map((v) => v[this.rowKey]); let rowIds = props.data.map((v) => v[props.rowKey]);
let allSelection = [...this.allSelection]; let allSelection1 = [...allSelection.value];
let selectionIds = allSelection.map((v) => v[this.rowKey]); let selectionIds = allSelection1.map((v) => v[props.rowKey]);
// 首先把当前页的选中全部移除 // 首先把当前页的选中全部移除
selectionIds = selectionIds.filter((v) => rowIds.indexOf(v) === -1); selectionIds = selectionIds.filter((v) => rowIds.indexOf(v) === -1);
// allSelection仅保留selectionIds存在的 // allSelection仅保留selectionIds存在的
allSelection = allSelection.filter( allSelection1 = allSelection1.filter((v) => selectionIds.indexOf(v[props.rowKey]) > -1);
(v) => selectionIds.indexOf(v[this.rowKey]) > -1
);
// 然后再加入当前页的选中 // 然后再加入当前页的选中
allSelection.push(...selection); allSelection1.push(...selection);
this.allSelection = allSelection; allSelection.value = allSelection1;
}, // 更新当前全部被选中的数据 }; // 更新当前全部被选中的数据
clearSelection() { const clearSelection = () => {
this.$refs.table.clearSelection(); table.value.clearSelection();
this.allSelectio = []; allSelection.value = [];
}, // 清空选中 }; // 清空选中
getRowInfo(row, key) { const getRowInfo = (row, key) => {
let currentIndex = -1; let currentIndex = -1;
let parentRows = null; let parentRows = null;
let propPath = ""; let propPath = "";
let childrenKey = this.treeProps.children; let childrenKey = props.treeProps.children;
let recursionItems = (items, prop) => { let recursionItems = (items, prop) => {
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
let item = items[i]; let item = items[i];
...@@ -182,15 +170,12 @@ export default { ...@@ -182,15 +170,12 @@ export default {
} }
}; };
recursionItems(this.data, key, ""); recursionItems(props.data, key, "");
return { return {
index: currentIndex, index: currentIndex,
rows: parentRows, rows: parentRows,
$_prop_path: propPath, $_prop_path: propPath,
}; };
},
},
}; };
</script> </script>
\ No newline at end of file
...@@ -9,35 +9,18 @@ ...@@ -9,35 +9,18 @@
@select-all="selectActionAll" @select-all="selectActionAll"
:stripe="stripe" :stripe="stripe"
:row-class-name="stripe ? tableRowClassName : ''" :row-class-name="stripe ? tableRowClassName : ''"
tooltip-effect="light" tooltip-effect="light">
>
<template v-slot:empty> <template v-slot:empty>
<div class="empty_container"> <div class="empty_container">
<img src="../assets/imgs/img-no-data.png" alt=""> <img src="../assets/imgs/img-no-data.png" alt="" />
<div class="text"> <div class="text">暂无数据</div>
暂无数据
</div>
</div> </div>
</template> </template>
<el-table-column <el-table-column v-if="paddingLeft > 10" :width="paddingLeft - 10"></el-table-column>
v-if="paddingLeft > 10" <el-table-column type="selection" :selectable="selectable" width="38" v-if="select">
:width="paddingLeft - 10"
></el-table-column>
<el-table-column
type="selection"
:selectable="selectable"
width="38"
v-if="select"
>
<!-- checkbox --> <!-- checkbox -->
</el-table-column> </el-table-column>
<el-table-column <el-table-column v-if="isIndex" type="index" :label="indexLabel" width="54" align="left">
v-if="isIndex"
type="index"
:label="indexLabel"
width="54"
align="left"
>
<!-- 序号 --> <!-- 序号 -->
</el-table-column> </el-table-column>
<el-table-column <el-table-column
...@@ -47,8 +30,7 @@ ...@@ -47,8 +30,7 @@
:align="header.align" :align="header.align"
:key="'col_' + index" :key="'col_' + index"
:fixed="header.fixed" :fixed="header.fixed"
show-overflow-tooltip show-overflow-tooltip>
>
<template v-slot:header> <template v-slot:header>
<template v-if="$slots[`header-${header.prop}`]"> <template v-if="$slots[`header-${header.prop}`]">
<slot :name="`header-${header.prop}`" /> <slot :name="`header-${header.prop}`" />
...@@ -68,21 +50,14 @@ ...@@ -68,21 +50,14 @@
</template> </template>
<script setup> <script setup>
import { watch, ref, } from 'vue' import { watch, ref } from "vue";
import { selectTableMixin } from './hook/mixin-select-table' import { selectTableMixin } from "./hook/mixin-select-table";
let { let { nowSelectData, allSelectData, selectData, initSelectTableData, runPage, dealSelectData } = selectTableMixin();
nowSelectData,
allSelectData,
selectData,
initSelectTableData,
runPage,
dealSelectData
} = selectTableMixin()
const props = defineProps({ const props = defineProps({
height: { height: {
type: [Number, String], type: [Number, String],
default: 'auto' default: "auto",
}, },
headers: { headers: {
type: Array, type: Array,
...@@ -101,15 +76,15 @@ const props = defineProps({ ...@@ -101,15 +76,15 @@ const props = defineProps({
// }, // },
isIndex: { isIndex: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
indexLabel: { indexLabel: {
type: String, type: String,
default: "序号" default: "序号",
}, },
stripe: { stripe: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
paddingLeft: { paddingLeft: {
type: [Number, String], type: [Number, String],
...@@ -117,84 +92,85 @@ const props = defineProps({ ...@@ -117,84 +92,85 @@ const props = defineProps({
}, },
canEdit: { canEdit: {
type: Boolean, type: Boolean,
default: false default: false,
}, // 多选框是否禁用 }, // 多选框是否禁用
canEditFlag: { canEditFlag: {
typr : Boolean, typr: Boolean,
default: "" default: "",
}, // 决定多选框是否禁用的字段 }, // 决定多选框是否禁用的字段
}) });
const table = ref(null) const table = ref(null);
const emit = defineEmits(['selectAc','select']) const emit = defineEmits(["selectAc", "select"]);
watch( watch(
() => props.rows, () => props.rows,
(n,o) => { (n, o) => {
if (n.length && props.select) { if (n.length && props.select) {
runPage() runPage();
initSelectTableData(n).then((selectData)=>{ initSelectTableData(n).then((selectData) => {
if(selectData.length){ if (selectData.length) {
setTimeout(()=>{ setTimeout(() => {
toggleRowArrSelection(selectData) toggleRowArrSelection(selectData);
}) });
} }
}) });
} }
} }
) );
const toggleRowSelection = (row, flag = true) => { const toggleRowSelection = (row, flag = true) => {
table.value.toggleRowSelection(row, flag); table.value.toggleRowSelection(row, flag);
} };
const selectAction = (selection) => { const selectAction = (selection) => {
emit("selectAc", {allLength:Object.keys(allSelectData).length+nowSelectData.length,selection}); emit("selectAc", { allLength: Object.keys(allSelectData).length + nowSelectData.length, selection });
} };
const clearSelection = () => { const clearSelection = () => {
table.value.clearSelection(); table.value.clearSelection();
emit("select", {allLength:Object.keys(allSelectData).length+nowSelectData.length,selection:[]}); emit("select", { allLength: Object.keys(allSelectData).length + nowSelectData.length, selection: [] });
} };
const setSelectedRow = (row) => { const setSelectedRow = (row) => {
toggleRowSelection(row); toggleRowSelection(row);
} };
const toggleRowArrSelection = (arr, flag = true) => { const toggleRowArrSelection = (arr, flag = true) => {
arr.forEach(e => { arr.forEach((e) => {
toggleRowSelection(e, flag); toggleRowSelection(e, flag);
}); });
} };
const selectActionRow = (selection,row) => { const selectActionRow = (selection, row) => {
selectData(selection) selectData(selection);
emit("select", {allLength:Object.keys(allSelectData).length+nowSelectData.length,selection}); emit("select", { allLength: Object.keys(allSelectData).length + nowSelectData.length, selection });
} };
const selectActionAll = (selection) => { const selectActionAll = (selection) => {
selectData(selection) selectData(selection);
emit("select", {allLength:Object.keys(allSelectData).length+nowSelectData.length,selection}); emit("select", { allLength: Object.keys(allSelectData).length + nowSelectData.length, selection });
} };
const clearTable = () => {//清除选中数据,在页面状态更新时使用 const clearTable = () => {
allSelectData={} //清除选中数据,在页面状态更新时使用
nowSelectData=[] allSelectData = {};
nowSelectData = [];
clearSelection(); clearSelection();
} };
const tableRowClassName = ({ row, rowIndex }) => { const tableRowClassName = ({ row, rowIndex }) => {
if (rowIndex % 2 == 0) { if (rowIndex % 2 == 0) {
return "white-row"; return "white-row";
} else { } else {
return "stripe-row"; return "stripe-row";
} }
} };
const selectable = (row,index) => { const selectable = (row, index) => {
if (props.canEdit) { if (props.canEdit) {
if (row[props.canEditFlag] && row[props.canEditFlag] == 1) { if (row[props.canEditFlag] && row[props.canEditFlag] == 1) {
return false return false;
}else { } else {
return true return true;
} }
}else { } else {
return true return true;
} }
} };
defineExpose({ defineExpose({
clearTable, clearTable,
toggleRowSelection, toggleRowSelection,
}) });
</script> </script>
...@@ -8,8 +8,7 @@ ...@@ -8,8 +8,7 @@
:class="{ :class="{
current: modelValue === item.name, current: modelValue === item.name,
}" }"
@click="changeActiveName(item, index)" @click="changeActiveName(item, index)">
>
{{ item.label }} {{ item.label }}
</li> </li>
<li> <li>
...@@ -26,50 +25,39 @@ ...@@ -26,50 +25,39 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { import { reactive, ref, onBeforeMount, toRefs, provide, useSlots } from "vue";
name: "BgTabs",
provide() { const slots = useSlots();
return {
getActiveName: () => { const props = defineProps({
return this.modelValue;
},
getIsTabs: () => {
return true;
},
};
},
props: {
modelValue: { modelValue: {
type: String, type: String,
default: '', default: "",
},
}, },
emits: ['update:modelValue'], });
data() {
return {
isTabs: true,
};
},
methods: {
calcTabs() {
let tabSlots = [];
if (this.$slots.default()) { const getActiveName = provide("activeName", () => {
tabSlots = this.$slots.default() return props.modelValue;
.filter( });
(vnode) => const getIsTabs = provide("isTabs", true);
vnode.type &&
vnode.type.name === "BgTab" const emit = defineEmits(["update:modelValue"]);
)
const isTabs = ref(true);
const calcTabs = () => {
let tabSlots = [];
if (slots.default()) {
tabSlots = slots
.default()
.filter((vnode) => vnode.type && vnode.type.__name === "bg-tab")
.map((vnode) => vnode.props); .map((vnode) => vnode.props);
} }
return tabSlots; return tabSlots;
}, };
changeActiveName({ name }) { const changeActiveName = ({ name }) => {
this.$emit("update:modelValue", name); emit("update:modelValue", name);
},
},
}; };
</script> </script>
...@@ -10,29 +10,17 @@ ...@@ -10,29 +10,17 @@
</a> </a>
</li> </li>
<li v-if="!disabled"> <li v-if="!disabled">
<el-button <el-button type="primary2" size="mini" @click="showInput = true" v-if="!showInput"> 新增 </el-button>
type="primary2" <el-input v-model.trim="newTag" @blur="addTag" v-else />
size="mini"
@click="showInput = true"
v-if="!showInput"
>
新增
</el-button>
<el-input v-model="newTag" @blur="addTag" v-else />
</li> </li>
</ul> </ul>
</div> </div>
</template> </template>
<script> <script setup>
export default { import { reactive, ref, onBeforeMount, toRefs, computed, useSlots } from "vue";
name: "BgTags", const props = defineProps({
model: { modelValue: {
prop: "value",
event: "change",
},
props: {
value: {
type: String, type: String,
default: "", default: "",
}, },
...@@ -40,37 +28,33 @@ export default { ...@@ -40,37 +28,33 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}, });
data() {
return { const emit = defineEmits(["update:modelValue"]);
newTag: "",
showInput: false, const newTag = ref("");
}; const showInput = ref(false);
},
computed: { const tags = computed(() => {
tags() { return (props.modelValue && props.modelValue.split(",")) || [];
return (this.value && this.value.split(",")) || []; });
},
}, const deleteTag = (index) => {
methods: { let tags = [...tags.value];
deleteTag(index) {
let tags = [...this.tags];
tags.splice(index, 1); tags.splice(index, 1);
this.$emit("change", tags.join(",")); emit("update:modelValue", tags.join(","));
}, };
addTag() { const addTag = () => {
let tags = [...this.tags]; let tags = [...tags.value];
if (this.newTag) { if (newTag.value) {
tags.push(this.newTag); tags.push(newTag.value);
} }
this.$emit("change", tags.join(",")); emit("update:modelValue", tags.join(","));
this.newTag = ""; newTag.value = "";
this.showInput = false; showInput.value = false;
},
},
}; };
</script> </script>
<template> <template>
<el-upload <el-upload
ref="upload" ref="uploadRef"
class="bg-upload" class="bg-upload"
v-bind="$attrs" v-bind="$attrs"
:file-list="fileList" :file-list="fileList"
...@@ -44,11 +44,12 @@ ...@@ -44,11 +44,12 @@
</el-dialog> </el-dialog>
</template> </template>
<script> <script setup>
import { UploadFilled } from "@element-plus/icons-vue"; import { UploadFilled } from "@element-plus/icons-vue";
export default { import { computed, watch, nextTick, onMounted, reactive, ref, toRefs } from "vue";
name: "BgUploadImage", import { ElMessage } from "element-plus";
props: {
const props = defineProps({
modelValue: { modelValue: {
type: Array, type: Array,
default: () => [], default: () => [],
...@@ -95,70 +96,53 @@ export default { ...@@ -95,70 +96,53 @@ export default {
type: String, type: String,
default: "", default: "",
}, // 自定义提示内容 }, // 自定义提示内容
}, });
emits: ["update:modelValue", "change"],
computed: {
acceptTypes() {
if (Array.isArray(this.accept)) {
return this.accept.join(",");
} else {
return this.accept;
}
},
types() {
return this.acceptTypes.split(",").filter((v) => v !== "");
},
tips() {
let str = "";
if (this.types.length > 0) { const emit = defineEmits(["update:modelValue", "change"]);
str += `后缀为 ${this.types.join("")} `;
}
if (this.fileSize) { const uploadRef = ref(null);
if (str) str += "";
str += `大小不超过 ${this.fileSize}${this.fileSizeUnit}`; const state = reactive({
fileList: [],
dialogImageUrl: "",
dialogVisible: false,
});
const acceptTypes = computed(() => {
if (Array.isArray(props.accept)) {
return props.accept.join(",");
} else {
return props.accept;
} }
});
if (str) str += "的文件"; const types = computed(() => {
return acceptTypes.value.split(",").filter((v) => v !== "");
});
if (this.limit) { const tips = computed(() => {
str += `,最多上传 ${this.limit} 个文件`; let str = "";
if (types.value.length > 0) {
str += `后缀为${types.value.join("")}`;
}
if (props.fileSize) {
if (str) str += "";
str += `大小不超过${props.fileSize}${props.fileSizeUnit}`;
} }
if (str) str += "的文件";
if (props.limit) {
str += `,最多上传 ${props.limit} 个文件`;
}
if (str) { if (str) {
str = "支持" + str; str = "支持" + str;
} }
return str; return str;
}, });
},
data() {
return {
fileList: [],
UploadFilled,
dialogImageUrl: "",
dialogVisible: false,
};
},
watch: {
modelValue() {
let newStr = this.modelValue.map((v) => v.url).join(",");
let oldStr = this.fileList.map((v) => (v.response && v.response.data) || v.url).join(",");
if (newStr !== oldStr) { const checkLimit = (filelist) => {
this.fileList = [...this.modelValue]; const limit = props.limit;
} const uploadDom = uploadRef.value;
this.$nextTick().then(() => {
this.checkLimit(this.modelValue);
});
},
},
methods: {
checkLimit(filelist) {
const limit = this.limit;
const uploadDom = this.$refs["upload"];
const length = uploadDom.$el.children[0].children.length; const length = uploadDom.$el.children[0].children.length;
if (filelist.length === limit) { if (filelist.length === limit) {
uploadDom.$el.children[0].children[length - 1].style.display = "none"; uploadDom.$el.children[0].children[length - 1].style.display = "none";
...@@ -167,8 +151,23 @@ export default { ...@@ -167,8 +151,23 @@ export default {
? (uploadDom.$el.children[0].children[length - 1].style.display = "") ? (uploadDom.$el.children[0].children[length - 1].style.display = "")
: ""; : "";
} }
}, };
handleBeforeUpload(file) {
watch(
() => props.modelValue,
() => {
let newStr = props.modelValue.map((v) => v.url).join(",");
let oldStr = state.fileList.map((v) => (v.response && v.response.data) || v.url).join(",");
if (newStr !== oldStr) {
state.fileList = [...props.modelValue];
}
nextTick().then(() => {
checkLimit(props.modelValue);
});
}
);
const handleBeforeUpload = (file) => {
let units = { let units = {
KB: 1024, KB: 1024,
MB: 1024 * 1024, MB: 1024 * 1024,
...@@ -176,36 +175,35 @@ export default { ...@@ -176,36 +175,35 @@ export default {
}; };
let temp = file.name.split("."); let temp = file.name.split(".");
let type = "." + temp[temp.length - 1].toLocaleLowerCase(); let type = "." + temp[temp.length - 1].toLocaleLowerCase();
let fileTypeIsOk = this.types.length === 0 || this.types.indexOf(type) > -1; let fileTypeIsOk = types.value.length === 0 || types.value.indexOf(type) > -1;
let fileSizeIsOk = let fileSizeIsOk =
this.fileSize === 0 || this.fileSize === undefined || file.size / units[this.fileSizeUnit] <= this.fileSize; props.fileSize === 0 || props.fileSize === undefined || file.size / units[props.fileSizeUnit] <= props.fileSize;
let checked = fileTypeIsOk && fileSizeIsOk; let checked = fileTypeIsOk && fileSizeIsOk;
if (!checked) { if (!checked) {
this.$message.error(this.tips); ElMessage.error(tips.value);
} }
return checked; return checked;
}, };
handleSuccess(response, file, fileList) { const handleSuccess = (response, file, fileList) => {
this.updateFileList(fileList); updateFileList(fileList);
this.checkLimit(fileList); checkLimit(fileList);
}, };
handleRemove(file, fileList) { const handleRemove = (file, fileList) => {
this.updateFileList(fileList); updateFileList(fileList);
this.checkLimit(fileList); checkLimit(fileList);
}, };
handlePreview({ name, url }) { const handlePreview = ({ name, url }) => {
this.dialogImageUrl = url; state.dialogImageUrl = url;
this.dialogVisible = true; state.dialogVisible = true;
// let a = document.createElement("a"); // 生成一个a元素 // let a = document.createElement("a"); // 生成一个a元素
// let event = new MouseEvent("click"); // 创建一个单击事件 // let event = new MouseEvent("click"); // 创建一个单击事件
// a.download = name; // 设置图片名称 // a.download = name; // 设置图片名称
// a.href = url; // 将生成的URL设置为a.href属性 // a.href = url; // 将生成的URL设置为a.href属性
// a.dispatchEvent(event); // 触发a的单击事件 // a.dispatchEvent(event); // 触发a的单击事件
}, };
updateFileList(fileList) { const updateFileList = (fileList) => {
let values = fileList.map((v) => { let values = fileList.map((v) => {
return { return {
name: v.name, name: v.name,
...@@ -213,19 +211,21 @@ export default { ...@@ -213,19 +211,21 @@ export default {
}; };
}); });
this.fileList = fileList; state.fileList = fileList;
console.log(values); console.log(values);
this.$emit("update:modelValue", values); emit("update:modelValue", values);
this.$emit("change", values); emit("change", values);
}, };
submitUpload() { const submitUpload = () => {
this.$refs.upload.submit(); uploadRef.value.submit();
},
},
mounted() {
this.fileList = [...this.modelValue];
},
}; };
onMounted(() => {
state.fileList = [...props.modelValue];
nextTick().then(() => {
checkLimit(props.modelValue);
});
});
const { fileList, dialogImageUrl, dialogVisible } = toRefs(state);
</script> </script>
<template> <template>
<div <div class="bg-upload" :class="{ 'is-disabled': actionDisabled, 'is-easy': isEasy }">
class="bg-upload"
:class="{ 'is-disabled': actionDisabled, 'is-easy': isEasy }"
>
<el-upload <el-upload
action="/apaas/common/file/upload" action="/apaas/common/file/upload"
:data="{ :data="{
...@@ -15,12 +12,10 @@ ...@@ -15,12 +12,10 @@
:on-preview="handlePreview" :on-preview="handlePreview"
:on-remove="handleRemove" :on-remove="handleRemove"
:file-list="fileList" :file-list="fileList"
:limit="limit"
:disabled="actionDisabled" :disabled="actionDisabled"
style="max-width: 600px" style="max-width: 600px"
multiple
drag drag
> multiple>
<!-- <el-button type="primary"> <!-- <el-button type="primary">
上传附件 上传附件
</el-button> </el-button>
...@@ -29,11 +24,7 @@ ...@@ -29,11 +24,7 @@
</div> --> </div> -->
<template v-if="isEasy"> <template v-if="isEasy">
<el-button type="primary" size="mini"> <el-button type="primary" size="mini">
<bg-icon <bg-icon :icon="`#${triggerIcon}`" v-if="triggerIcon" style="margin-right: 8px" />
:icon="`#${triggerIcon}`"
v-if="triggerIcon"
style="margin-right: 8px"
/>
{{ triggerText }} {{ triggerText }}
</el-button> </el-button>
</template> </template>
...@@ -51,7 +42,7 @@ ...@@ -51,7 +42,7 @@
</p> </p>
</div> </div>
<template v-slot:tip v-if="otherInfo != ''"> <template v-slot:tip v-if="otherInfo != ''">
<div class="el-upload__tip" style="color: #909bb6"> <div class="el-upload__tip" style="color: #909bb6; line-height: 18px">
{{ otherInfo }} {{ otherInfo }}
</div> </div>
</template> </template>
...@@ -59,33 +50,18 @@ ...@@ -59,33 +50,18 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { import { computed, watch, onMounted, reactive, ref, nextTick, toRefs } from "vue";
name: "BgUpload", import { ElMessage } from "element-plus";
// model: {
// prop: "value", const props = defineProps({
// event: "change",
// },
props: {
modelValue: { modelValue: {
type: Array, type: Array,
default: () => [], default: () => [],
}, },
limit: {
type: Number,
},
fileTypes: { fileTypes: {
type: Array, type: Array,
default: () => [ default: () => ["doc", "docx", "xls", "xlsx", "pdf", "jpg", "jpeg", "png"],
"doc",
"docx",
"xls",
"xlsx",
"pdf",
"jpg",
"jpeg",
"png",
],
}, },
fileMaxSize: { fileMaxSize: {
type: Number, type: Number,
...@@ -119,83 +95,71 @@ export default { ...@@ -119,83 +95,71 @@ export default {
type: String, type: String,
default: "", default: "",
}, },
limit: {
type: Number,
default: 9999,
}, },
emits: ["update:modelValue"], });
data() {
return {
fileList: [],
};
},
computed: {
actionDisabled() {
return this.disabled ;//|| this.fileList.length === this.limit; 文件数量 === limit 会导致无法删除已上传文件
},
},
watch: {
modelValue() {
let newStr = this.modelValue.map((v) => v.url).join(",");
let oldStr = this.fileList
.map((v) => (v.response && v.response.data) || v.url)
.join(",");
if (newStr !== oldStr) { const emit = defineEmits(["update:modelValue", "change"]);
this.fileList = [...this.modelValue];
}
},
},
methods: {
initFileList() {
let urls = (this.value && this.value.split(",")) || [];
this.fileList = urls.map((url, index) => { const state = reactive({
let temp = url.split("/"); fileList: [],
let name = temp[temp.length - 1] || `附件_${index + 1}`; });
return { name, url }; const actionDisabled = computed(() => {
}); return props.disabled;
});
this.$emit("update:refresh", false); watch(
}, () => props.modelValue,
handleBeforeUpload(file) { () => {
let newStr = props.modelValue.map((v) => v.url).join(",");
let oldStr = state.fileList.map((v) => (v.response && v.response.data) || v.url).join(",");
if (newStr !== oldStr) {
state.fileList = [...props.modelValue];
}
}
);
const handleBeforeUpload = (file) => {
if (state.fileList && state.fileList.length >= props.limit) {
ElMessage.error(`只允许上传${props.limit}个文件`);
return false;
}
let temp = file.name.split("."); let temp = file.name.split(".");
let type = temp[temp.length - 1].toLocaleLowerCase(); let type = temp[temp.length - 1].toLocaleLowerCase();
let fileTypesOk = this.fileTypes.indexOf(type) > -1; let fileTypesOk = props.fileTypes.indexOf(type) > -1 || props.fileTypes.length == 0;
let fileMaxSizeOk = file.size / 1024 / 1024 <= this.fileMaxSize; let fileMaxSizeOk = file.size / 1024 / 1024 <= props.fileMaxSize;
if (!fileTypesOk) { if (!fileTypesOk) {
this.$message.error( ElMessage.error(`上传文件只能是${props.fileTypes.join("")}这些格式!`);
`上传文件只能是${this.fileTypes.join("")}这些格式!`
);
} }
if (!fileMaxSizeOk) { if (!fileMaxSizeOk) {
this.$message.error(`上传文件大小不能超过${this.fileMaxSize}M!`); ElMessage.error(`上传文件大小不能超过${props.fileMaxSize}M!`);
} }
return fileTypesOk && fileMaxSizeOk; return fileTypesOk && fileMaxSizeOk;
}, };
handleExceed(file, fileList) { const handleExceed = (file, fileList) => {
console.log(file, fileList); console.log(file, fileList);
if (fileList && fileList.length == this.limit) { };
this.$message.error(`最多只允许上传${this.limit}个文件`) const handlePreview = (val) => {
return false
}
},
handlePreview(val) {
let a = document.createElement("a"); // 生成一个a元素 let a = document.createElement("a"); // 生成一个a元素
let event = new MouseEvent("click"); // 创建一个单击事件 let event = new MouseEvent("click"); // 创建一个单击事件
a.download = val.name; // 设置图片名称 a.download = val.name; // 设置图片名称
a.href = val.url || val.response.data; // 将生成的URL设置为a.href属性 a.href = val.url || val.response.data; // 将生成的URL设置为a.href属性
a.dispatchEvent(event); // 触发a的单击事件 a.dispatchEvent(event); // 触发a的单击事件
}, };
handleRemove(file, fileList) { const handleRemove = (file, fileList) => {
this.updateFileList(fileList); updateFileList(fileList);
}, };
handleSuccess(response, file, fileList) { const handleSuccess = (response, file, fileList) => {
this.updateFileList(fileList); updateFileList(fileList);
}, };
updateFileList(fileList) { const updateFileList = (fileList) => {
let values = fileList.map((v) => { let values = fileList.map((v) => {
return { return {
name: v.name, name: v.name,
...@@ -203,19 +167,21 @@ export default { ...@@ -203,19 +167,21 @@ export default {
}; };
}); });
this.fileList = fileList; state.fileList = fileList;
this.$emit("update:modelValue", values); emit("update:modelValue", values);
this.$emit("change"); emit("change", values);
},
},
mounted() {
this.fileList = [...this.modelValue];
},
}; };
onMounted(() => {
state.fileList = [...props.modelValue];
});
const { fileList } = toRefs(state);
</script> </script>
<style> <style>
.bg-upload .el-upload-dragger{ .bg-upload .el-upload-dragger {
padding: 0; padding: 0;
border: 0; border: 0;
} }
......
...@@ -6,8 +6,7 @@ ...@@ -6,8 +6,7 @@
:auto-upload="false" :auto-upload="false"
:on-change="onChangeFile" :on-change="onChangeFile"
:file-list="fileList" :file-list="fileList"
:disabled="disabled" :disabled="disabled">
>
<template v-slot:trigger> <template v-slot:trigger>
<div class="trigger-content"> <div class="trigger-content">
<div class="image-trigger" v-if="modelValue"> <div class="image-trigger" v-if="modelValue">
...@@ -25,62 +24,60 @@ ...@@ -25,62 +24,60 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { import { computed, watch, onMounted, reactive, ref, nextTick, toRefs } from "vue";
name: "BgUploadImage", import { ElMessage } from "element-plus";
props: {
const props = defineProps({
modelValue: { modelValue: {
type: String, type: String,
default: "", default: "",
}, },
disabled:{ disabled: {
type:Boolean, type: Boolean,
default:false default: false,
}
},
emits: ['update:modelValue'],
data(){
return{
fileList:[]
}
}, },
created(){ });
}, const emit = defineEmits(["update:modelValue"]);
methods: {
handleAvatarSuccess({ data }) { const state = reactive({
this.$emit("update:modelValue", data.visitURL); fileList: [],
}, });
beforeAvatarUpload(file) {
const handleAvatarSuccess = ({ data }) => {
emit("update:modelValue", data.visitURL);
};
const beforeAvatarUpload = (file) => {
const isJPG = file.type === "image/jpeg" || file.type === "image/png"; const isJPG = file.type === "image/jpeg" || file.type === "image/png";
const isLt1M = file.size / 1024 / 1024 < 1; const isLt1M = file.size / 1024 / 1024 < 1;
if (!isJPG) { if (!isJPG) {
this.$message.error("上传的图片只能是 JPG、PNG 格式!"); ElMessage.error("上传的图片只能是 JPG、PNG 格式!");
} }
if (!isLt1M) { if (!isLt1M) {
this.$message.error("上传的图片大小不能超过 1MB!"); ElMessage.error("上传的图片大小不能超过 1MB!");
} }
return isJPG && isLt1M; return isJPG && isLt1M;
}, };
onChangeFile(file, fileList){ const onChangeFile = (file, fileList) => {
console.log(file, fileList); console.log(file, fileList);
if(!this.beforeAvatarUpload(file.raw)){ if (!beforeAvatarUpload(file.raw)) {
return return;
} }
var reader = new FileReader(); var reader = new FileReader();
reader.readAsDataURL(file.raw); // 一定要传入file格式 reader.readAsDataURL(file.raw); // 一定要传入file格式
reader.onload = () => { reader.onload = () => {
this.$emit("update:modelValue", reader.result); emit("update:modelValue", reader.result);
}; };
}
},
}; };
const { fileList } = toRefs(state);
</script> </script>
<style scoped> <style scoped>
.user-upload-image :deep() .el-upload-list{ .user-upload-image :deep() .el-upload-list {
display: none; display: none;
} }
</style> </style>
...@@ -14,8 +14,6 @@ ...@@ -14,8 +14,6 @@
import BgLayoutCard from './bg-layout-card.vue' import BgLayoutCard from './bg-layout-card.vue'
import BgCard from './bg-card.vue' import BgCard from './bg-card.vue'
import BgInfo from './bg-info.vue' import BgInfo from './bg-info.vue'
import BgSteps from './bg-steps.vue'
import BgStep from './bg-step.vue'
import BgBtns from './bg-btns.vue' import BgBtns from './bg-btns.vue'
import BgUpload from './bg-upload.vue' import BgUpload from './bg-upload.vue'
import BgUploadImage from './bg-upload-image.vue' import BgUploadImage from './bg-upload-image.vue'
...@@ -52,8 +50,6 @@ const components = { ...@@ -52,8 +50,6 @@ const components = {
BgLayoutCard, // 带标题的卡片 BgLayoutCard, // 带标题的卡片
BgCard, // 详情卡片 BgCard, // 详情卡片
BgInfo, // 表格信息 BgInfo, // 表格信息
BgSteps, // 步骤条
BgStep, // 步骤条
BgBtns, // 按钮组 BgBtns, // 按钮组
BgUpload, // 上传附件 BgUpload, // 上传附件
BgUploadImage, // 上传单张图片 BgUploadImage, // 上传单张图片
......
...@@ -1529,176 +1529,6 @@ a { ...@@ -1529,176 +1529,6 @@ a {
} }
} }
.bg-steps {
background-color: #ffffff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.1);
border-radius: 6px;
padding: 14px;
> .bg-steps-container {
.steps-nav {
padding: 18px 16px 31px;
border-bottom: 1px solid #f4f7fc;
> ul {
display: flex;
justify-content: space-between;
align-items: center;
> .step-item {
display: flex;
justify-content: flex-start;
align-items: center;
margin: 0 16px;
> .step-icon {
position: relative;
width: 30px;
height: 30px;
border-radius: 50%;
background-color: #e3e5ef;
&::before {
content: "";
width: 16px;
height: 16px;
border-radius: 50%;
background-color: #bcc1d0;
position: absolute;
top: 7px;
left: 7px;
}
}
> .step-hightlight-icon {
position: relative;
width: 70px;
height: 70px;
border-radius: 50%;
background-color: #2d96c9;
display: flex;
justify-content: center;
align-items: center;
display: none;
&::before {
content: "";
width: 60px;
height: 60px;
border: solid 3px #84bfdc;
box-sizing: border-box;
border-radius: 50%;
position: absolute;
top: 5px;
left: 5px;
}
}
> .step-title {
margin-left: 15px;
> p {
line-height: 1;
color: #bcc1d0;
&:nth-child(1) {
font-weight: bolder;
font-size: 18px;
}
&:nth-child(2) {
font-size: 14px;
margin-top: 12px;
}
}
}
&.done,
&.current {
> .step-icon {
display: none;
}
> .step-hightlight-icon {
display: flex;
}
}
> .step-title {
margin-left: 15px;
> p {
&:nth-child(1) {
color: #242c43;
}
&:nth-child(2) {
color: #8890a7;
}
}
}
}
> .step-line {
width: 100px;
flex: 1 1 auto;
height: 4px;
background-color: #e3e5ef;
border-radius: 2px 0px 0px 2px;
&.done,
&.current {
background-color: #2d96c9;
}
}
}
}
.steps-content {
margin-top: 20px;
}
}
}
.bg-step {
.step-done {
display: flex;
justify-self: center;
align-items: center;
> .done-icon {
margin-right: 15px;
}
> .done-info {
> p {
line-height: 1.5;
&:nth-child(1) {
font-weight: bolder;
font-size: 18px;
color: #242c43;
}
&:nth-child(2) {
font-size: 14px;
color: #8890a7;
margin-top: 5px;
}
}
}
}
> .step-action {
overflow: hidden;
margin-top: 20px;
> .fr {
float: right;
}
}
}
.bg-btns { .bg-btns {
display: inline-block; display: inline-block;
......
<template> <template>
<div class="item_card" :style="{'height':props.flag ? '242px' : '206px'}"> <div class="item_card" :style="{ height: props.flag ? '242px' : '206px' }">
<div class="action_box" v-if="props.flag"> <div class="action_box" v-if="props.flag">
<div class="can_click_text" @click="deleteItem(props.item)">删除</div> <div class="can_click_text" @click="deleteItem(props.item)">删除</div>
<div class="can_click_text" @click="move(1)" :class="props.item.canDown ? '' : 'disabled'">下移</div> <div class="can_click_text" @click="move(1)" :class="props.item.canDown ? '' : 'disabled'">下移</div>
<div class="can_click_text" @click="move(2)" :class="props.item.canUp ? '' : 'disabled'">上移</div> <div class="can_click_text" @click="move(2)" :class="props.item.canUp ? '' : 'disabled'">上移</div>
</div> </div>
<div class="top_info" :style="{'padding-left': !props.flag ? '8px' : '24px'}"> <div class="top_info" :style="{ 'padding-left': !props.flag ? '8px' : '24px' }">
<el-checkbox <el-checkbox
v-if="!props.flag" v-if="!props.flag"
class="select_box" class="select_box"
v-model="props.item.checked" v-model="props.item.checked"
@change="change_check" @change="change_check"></el-checkbox>
></el-checkbox>
<div class="logo"> <div class="logo">
<img v-if="props.item.ability_logo" :src="props.item.ability_logo" alt=""> <img v-if="props.item.ability_logo" :src="props.item.ability_logo" alt="" />
<img v-else src="../assets/imgs/img_cover_ability.png" alt=""> <img v-else src="../assets/imgs/img_cover_ability.png" alt="" />
</div> </div>
<div class="info"> <div class="info">
<div class="name"> <div class="name">
<span class="ability_name">{{props.item.ability_name}}</span> <span class="ability_name">{{ props.item.ability_name }}</span>
<span class="icon_box openness" :class="openClassObj[props.item.openness_id]">{{props.item.openness}}</span> <span class="icon_box openness" :class="openClassObj[props.item.openness_id]">{{ props.item.openness }}</span>
<span class="icon_box mock" v-if="props.item.include_mock_service">mock</span> <span class="icon_box mock" v-if="props.item.include_mock_service">mock</span>
</div> </div>
<div class="count"> <div class="count">
<div class="box1"> <div class="box1">
<div class="score_box"> <div class="score_box">
<el-rate <el-rate v-model="props.item.score" disabled />
v-model="props.item.score"
disabled
/>
</div> </div>
<span class="score">{{props.item.score}}</span> <span class="score">{{ props.item.score }}</span>
</div> </div>
<div class="line"></div> <div class="line"></div>
<div class="box2"> <div class="box2">
...@@ -38,8 +34,8 @@ ...@@ -38,8 +34,8 @@
props.item.browse_count == 0 || (props.item.browse_count && props.item.browse_count < 10000) props.item.browse_count == 0 || (props.item.browse_count && props.item.browse_count < 10000)
? props.item.browse_count ? props.item.browse_count
: props.item.browse_count < 10000000 : props.item.browse_count < 10000000
? Math.floor(props.item.browse_count/10000) + '万+' ? Math.floor(props.item.browse_count / 10000) + "万+"
: '999万+' : "999万+"
}} }}
</div> </div>
<div class="line"></div> <div class="line"></div>
...@@ -48,21 +44,21 @@ ...@@ -48,21 +44,21 @@
props.item.call_count == 0 || (props.item.call_count && props.item.call_count < 10000) props.item.call_count == 0 || (props.item.call_count && props.item.call_count < 10000)
? props.item.call_count ? props.item.call_count
: props.item.call_count < 10000000 : props.item.call_count < 10000000
? Math.floor(props.item.call_count/10000) + '万+' ? Math.floor(props.item.call_count / 10000) + "万+"
: '999万+' : "999万+"
}} }}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="bottom_info" :style="{'height':props.flag ? 'calc(100% - 128px)' : 'calc(100% - 92px)'}"> <div class="bottom_info" :style="{ height: props.flag ? 'calc(100% - 128px)' : 'calc(100% - 92px)' }">
<div class="desc" :title="props.item.synopsis"> <div class="desc" :title="props.item.synopsis">
{{props.item.synopsis}} {{ props.item.synopsis }}
</div> </div>
<div class="action"> <div class="action">
<span class="fws" :title="props.item.develop"> <span class="fws" :title="props.item.develop">
<bg-icon style="font-size: 14px; color: #909bb6;" icon="#bg-ic-shop" /> <bg-icon style="font-size: 14px; color: #909bb6" icon="#bg-ic-shop" />
{{props.item.develop}} {{ props.item.develop }}
</span> </span>
</div> </div>
</div> </div>
...@@ -70,56 +66,54 @@ ...@@ -70,56 +66,54 @@
</template> </template>
<script setup> <script setup>
import { useRouter } from "vue-router" import { useRouter } from "vue-router";
const router = useRouter() const router = useRouter();
const props = defineProps({ const props = defineProps({
item: { item: {
type: Object, type: Object,
default: {} default: {},
}, },
flag: { flag: {
type: Boolean, type: Boolean,
default: false default: false,
} },
}) });
const emit = defineEmits(["change_check","deleteItem","move"]) const emit = defineEmits(["change_check", "deleteItem", "move"]);
const openClassObj = { const openClassObj = {
'9de06ba6-6ee2-4449-91d9-31a1c7554311':'open', "9de06ba6-6ee2-4449-91d9-31a1c7554311": "open",
'4e8b4c37-e565-4195-8303-3b1ccd48dd13':'share', "4e8b4c37-e565-4195-8303-3b1ccd48dd13": "share",
'4e8b4c37-e565-4195-8303-3b1ccd48dd12':'limit', "4e8b4c37-e565-4195-8303-3b1ccd48dd12": "limit",
'4e8b4c37-e565-4195-8303-3b1ccd48dd16':'sensitive' "4e8b4c37-e565-4195-8303-3b1ccd48dd16": "sensitive",
} };
const change_check = () => { const change_check = () => {
console.log(props.item) console.log(props.item);
emit("change_check",props.item) emit("change_check", props.item);
} };
const deleteItem = (item) => { const deleteItem = (item) => {
emit("deleteItem",item) emit("deleteItem", item);
} };
const move = (type) => { const move = (type) => {
if ((type == 1 && !props.item.canDown) || (type == 2 && !props.item.canUp)) { if ((type == 1 && !props.item.canDown) || (type == 2 && !props.item.canUp)) {
return return;
} }
let temp = { let temp = {
item: props.item, item: props.item,
type: type type: type,
} };
emit("move",temp) emit("move", temp);
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.item_card { .item_card {
width: 384px; width: 384px;
// margin-right: 16px; // margin-right: 16px;
margin-bottom: 16px; margin-bottom: 16px;
height: 206px; height: 206px;
background-color: #ffffff; background-color: #ffffff;
box-shadow: 0px 4px 16px 0px box-shadow: 0px 4px 16px 0px rgba(18, 30, 63, 0.08);
rgba(18, 30, 63, 0.08);
border-radius: 6px; border-radius: 6px;
&:nth-child(3n) { &:nth-child(3n) {
margin-right: 0; margin-right: 0;
...@@ -194,20 +188,19 @@ const move = (type) => { ...@@ -194,20 +188,19 @@ const move = (type) => {
border-color: #a1cfc5; border-color: #a1cfc5;
} }
.open{ .open {
background-color: #f0f5eb; background-color: #f0f5eb;
border-color:#bbd19e; border-color: #bbd19e;
color: #78a33d; color: #78a33d;
} }
.share{ .share {
} }
.limit{ .limit {
background-color: #fcf0e6; background-color: #fcf0e6;
border-color: #f2b380; border-color: #f2b380;
color: #e56600; color: #e56600;
} }
.sensitive{ .sensitive {
background-color: #fbeeeb; background-color: #fbeeeb;
border-color: #eba89c; border-color: #eba89c;
color: #d75138; color: #d75138;
......
<template> <template>
<div class="card_list"> <div class="card_list">
<div v-for="(e,i) in props.list" :key="'card' + i" class="item"> <div v-for="(e, i) in props.list" :key="'card' + i" class="item">
<ability-card v-if="e.id" :item="e" @change_check="changeCheck" :flag="props.flag" @deleteItem="deleteItem" @move="move"/> <ability-card
v-if="e.id"
:item="e"
@change_check="changeCheck"
:flag="props.flag"
@deleteItem="deleteItem"
@move="move" />
<div v-else class="empty_card" @click="open"> <div v-else class="empty_card" @click="open">
<span>+</span> <span>+</span>
</div> </div>
...@@ -10,31 +16,31 @@ ...@@ -10,31 +16,31 @@
</template> </template>
<script setup> <script setup>
import abilityCard from "./ability-card.vue" import abilityCard from "./ability-card.vue";
const props = defineProps({ const props = defineProps({
list: { list: {
type: Array, type: Array,
default: [] default: [],
}, },
flag: { flag: {
type: Boolean, type: Boolean,
default: false default: false,
} },
}) });
const emit = defineEmits(["changeCheck","openBox","deleteItem","move"]) const emit = defineEmits(["changeCheck", "openBox", "deleteItem", "move"]);
const changeCheck = (item) => { const changeCheck = (item) => {
emit("changeCheck",item) emit("changeCheck", item);
} };
const open = () => { const open = () => {
console.log(3333) console.log(3333);
emit("openBox") emit("openBox");
} };
const deleteItem = (item) => { const deleteItem = (item) => {
emit("deleteItem",item) emit("deleteItem", item);
} };
const move = (temp) => { const move = (temp) => {
emit("move",temp) emit("move", temp);
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
<template> <template>
<el-form <el-form ref="ruleFormRef" class="ruleForm" :model="tableRows" :size="formSize" :rules="formRules">
ref="ruleFormRef" <bg-table-pro :headers="headers" :data="tableRows" ref="input-table" :border="true" :stripe="false">
class="ruleForm" <template v-slot:name="{ row, index }">
:model="tableRows" <el-form-item :prop="`[${index}].name`" :rules="formRules.name" style="width: 100%">
:size="formSize" <el-input @change="changeName" :disabled="disabled || acDisable" v-model.trim="row.name" />
:rules="formRules"
>
<bg-table-pro
:headers="headers"
:data="tableRows"
ref="input-table"
:border="true"
:stripe="false"
>
<template v-slot:name="{ row,index }">
<el-form-item
:prop="`[${index}].name`"
:rules="formRules.name"
>
<el-input @change="changeName" :disabled="disabled||acDisable" v-model="row.name" />
</el-form-item> </el-form-item>
</template> </template>
<template v-slot:value="{ row,index }"> <template v-slot:value="{ row, index }">
<el-form-item <el-form-item :prop="`[${index}].value`" :rules="formRules.value" style="width: 100%">
:prop="`[${index}].value`" <el-input @change="changeValue" :disabled="disabled" v-model.trim="row.value" />
:rules="formRules.value"
>
<el-input @change="changeValue" :disabled="disabled" v-model="row.value" />
</el-form-item> </el-form-item>
</template> </template>
<template v-slot:desc="{ row,index }"> <template v-slot:desc="{ row, index }">
<el-form-item <el-form-item :prop="`[${index}].desc`" :rules="formRules.desc" style="width: 100%">
:prop="`[${index}].desc`" <el-input @change="changeDesc" :disabled="disabled" v-model.trim="row.desc" />
:rules="formRules.desc"
>
<el-input :disabled="disabled" v-model="row.desc" />
</el-form-item> </el-form-item>
</template> </template>
<template v-slot:action="{ row,index }"> <template v-slot:action="{ row, index }">
<bg-table-btn :disabled="disabled||acDisable" :click="()=>{addParam(index)}">增加</bg-table-btn> <bg-table-btn
<bg-table-btn :disabled="disabled||acDisable" :click="()=>{removeParam(row, index)}"> :disabled="disabled || acDisable"
:click="
() => {
addParam(index);
}
"
>增加</bg-table-btn
>
<bg-table-btn
:disabled="disabled || acDisable"
:click="
() => {
removeParam(row, index);
}
">
删除 删除
</bg-table-btn> </bg-table-btn>
</template> </template>
...@@ -49,67 +42,60 @@ ...@@ -49,67 +42,60 @@
</template> </template>
<script setup> <script setup>
import { import { reactive, toRefs, onBeforeMount, onMounted, ref, getCurrentInstance } from "vue";
reactive,
toRefs,
onBeforeMount,
onMounted,
ref,
getCurrentInstance,
} from "vue";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
const props = defineProps({ const props = defineProps({
data: { data: {
type: Array, type: Array,
default:()=>[] default: () => [],
}, },
disabled:{ disabled: {
type:Boolean, type: Boolean,
default:false default: false,
}, },
acDisable:{ acDisable: {
type:Boolean, type: Boolean,
default:false default: false,
} },
}) });
const emit = defineEmits(['change']) const emit = defineEmits(["change"]);
const formSize = ref("default"); const formSize = ref("default");
const ruleFormRef = ref(null); const ruleFormRef = ref(null);
const formRules = reactive({ const formRules = reactive({
name:[ name: [
{ {
required: true, required: true,
message: '请输入键', message: "请输入键",
trigger: 'blur' trigger: "blur",
}, },
{ {
max: 30, max: 50,
message: '最多30个字符', message: "最多50个字符",
trigger: 'blur' trigger: "blur",
} },
], ],
value:[ value: [
{ {
required: true, required: true,
message: '请输入值', message: "请输入值",
trigger: 'blur' trigger: "blur",
}, },
{ {
min: 0, min: 0,
max: 50, max: 500,
message: '最多50个字符', message: "最多500个字符",
trigger: 'blur' trigger: "blur",
} },
], ],
desc:[ desc: [
{ {
max: 50, max: 500,
message: '最多50个字符', message: "最多500个字符",
trigger: 'blur' trigger: "blur",
} },
] ],
}); });
const headers = reactive([ const headers = reactive([
...@@ -133,76 +119,84 @@ const headers = reactive([ ...@@ -133,76 +119,84 @@ const headers = reactive([
]); ]);
const state = reactive({ const state = reactive({
tableRows:[] tableRows: [],
}); });
onBeforeMount(()=>{ onBeforeMount(() => {
initTable() initTable();
}) });
var initTable = ()=>{ var initTable = () => {
if(props.data&&props.data.length>=1){ if (props.data && props.data.length >= 1) {
state.tableRows = props.data state.tableRows = props.data;
}else{ } else {
addParam(0) state.tableRows = [];
} addParam(0);
}
var createRow = ()=>{
return{
id:uuidv4(),
name:'',
value:'',
desc:''
} }
} };
var addParam = (index)=>{changeName var createRow = () => {
return {
id: uuidv4(),
name: "",
value: "",
desc: "",
};
};
var addParam = (index) => {
state.tableRows.splice(index + 1, 0, createRow()); state.tableRows.splice(index + 1, 0, createRow());
} };
var removeParam = (row, index)=>{ var removeParam = (row, index) => {
state.tableRows.splice(index, 1); state.tableRows.splice(index, 1);
if (state.tableRows.length === 0) { if (state.tableRows.length === 0) {
addParam(0); addParam(0);
} }
} };
const changeName = ()=>{ const changeName = () => {
emit('change',{ emit("change", {
type:'name', type: "name",
data:state.tableRows data: state.tableRows,
}) });
} };
const changeValue= ()=>{ const changeValue = () => {
emit('change',{ emit("change", {
type:'value', type: "value",
data:state.tableRows data: state.tableRows,
}) });
} };
var getInputData = ()=>{ const changeDesc = () => {
let lastData = [] emit("change", {
let tempObj = {} type: "desc",
state.tableRows.forEach(e => { data: state.tableRows,
tempObj[e.name] = e });
};
var getInputData = () => {
let lastData = [];
let tempObj = {};
state.tableRows.forEach((e) => {
tempObj[e.name] = e;
}); });
for (const key in tempObj) { for (const key in tempObj) {
if(key&&tempObj[key].value){ if (key && tempObj[key].value) {
lastData.push(tempObj[key]) lastData.push(tempObj[key]);
} }
} }
return lastData return lastData;
} };
const {tableRows} = toRefs(state) const { tableRows } = toRefs(state);
//暴露获取数据方法 //暴露获取数据方法
defineExpose({ defineExpose({
getInputData, getInputData,
initTable initTable,
}) });
</script> </script>
<style scoped></style> <style scoped></style>
<template> <template>
<el-table-column :label="coloumnHeader.label" header-align="center"> <el-table-column :label="coloumnHeader.label" header-align="center">
<template v-for="(item,index) in coloumnHeader.children" :key="'header' + index"> <template v-for="(item, index) in coloumnHeader.children" :key="'header' + index">
<MyTableColumn <MyTableColumn v-if="item.children && item.children.length" :coloumnHeader="item"></MyTableColumn>
v-if="item.children && item.children.length"
:coloumnHeader="item"
></MyTableColumn>
<el-table-column <el-table-column
v-else v-else
:label="item.label" :label="item.label"
:prop="item.prop" :prop="item.prop"
header-align="center" header-align="center"
:align="item.align" :align="item.align"
:width="item.width" :width="item.width"></el-table-column>
></el-table-column>
</template> </template>
</el-table-column> </el-table-column>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
name: "MyTableColumn",
props: {
coloumnHeader: { coloumnHeader: {
type: Object, type: Object,
default: {} default: {},
} },
} });
}
</script> </script>
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