Commit 4d9b3a90 authored by 白舜's avatar 白舜 🎱

update bg-ui with 'apaas-portal-ui'

parent 6ae0af1a
...@@ -15,24 +15,21 @@ ...@@ -15,24 +15,21 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { import { reactive, ref,onBeforeMount,toRefs } from 'vue'
name: "BgBtns", const props = defineProps({
props: { modelValue: {
modelValue: { type: [String, Number],
type: [String, Number], default: []
default: "",
},
options: {
type: Array,
default: () => [],
},
}, },
emits: ["update:modelValue"], options: {
methods: { type: Array,
selectBtn({ value }) { default: () => [],
this.$emit("update:modelValue", value); }
}, })
}, const emit = defineEmits(['update:modelValue'])
};
const selectBtn = ({value})=>{
emit("update:modelValue", value);
}
</script> </script>
<template> <template>
<div class="bg-card"> <div class="bg-card">
<h3 class="card-title text-clip"> <div class="card-header">
<span class="title-icon" v-if="icon"> <slot name="title">
<bg-icon :icon="icon" /> <h3 class="card-title text-clip">
</span> <span class="title-icon" v-if="icon">
<span class="title-text">{{ title }}</span> <bg-icon :icon="icon" />
</h3> </span>
<span class="easy-icon" v-if="easyIcon"></span>
<span class="title-text">{{ title }}</span>
<span class="subtitle-text" v-if="subTitle">{{ subTitle }}</span>
</h3>
</slot>
<slot name="title-extra"></slot>
</div>
<div class="card-content" ref="content"> <div class="card-content" ref="content">
<slot /> <slot />
</div> </div>
</div> </div>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
name: "BgCard", title: {
props: { type: String,
title: { default: "",
type: String, },
default: "", subTitle:{
}, type: String,
icon: { default: "",
type: String,
default: "",
},
}, },
}; icon: {
type: String,
default: "",
},
easyIcon:{
type:Boolean,
default:false,
}
})
</script> </script>
<style scoped>
.easy-icon{
width: 4px;
height: 14px;
background-color: #3759be;
border-radius: 2px;
margin-right: 8px;
}
.subtitle-text{
font-size: 14px;
color: #909bb6;
font-weight: 400;
line-height: 5px;
margin-top: 4px;
}
</style>
\ No newline at end of file
<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"
<template v-if="item.slot"> v-for="(item, index) in data"
<span> :key="'data' + index">
<slot v-bind:item="item" :name="item.slot"></slot> <span>{{ item.title }}</span>
</span> <!-- 拓展功能 -->
</template> <template v-if="item.slot">
<!-- 原有下载功能 --> <span>
<template v-else> <slot v-bind:item="item" :name="item.slot"></slot>
<span v-if="!item.urls" :title="item.info" @click="down_file(item.url)" :style="item.url?{color:'#515fe7',cursor:'pointer'}:''">{{item.info}}</span> </span>
<span v-else :title="item.info"> </template>
<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> <template v-else>
</template> <span
</div> v-if="!item.urls"
<div class="bg" :style="{top:(2*index+1)*42+'px'}" v-for="(item,index) in bg_num" :key="'bg'+index"></div> :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-for="(it, idx) in item.urls"
@click="down_file(it)"
style="color: #515fe7; cursor: pointer"
:key="'urls' + idx"
>{{ helper.downloadFileFormatNew(it) }}</span
>
</span>
</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>
</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,
last_width:0,
bg_num:0,
};
},
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){//计算最后一个格子的宽度
this.last_width = {width:(this.layout.line_num-(n.length%this.layout.line_num)+1)/this.layout.line_num*100+'%'}
}else{
this.last_width = {width:100/this.layout.line_num +'%'}
}
if(n.length<this.layout.line_num){
return
}else{
this.bg_num = Math.floor((Math.ceil(n.length/this.layout.line_num))/2)
}
},
immediate: true
}
},
computed: {
},
created() {
},
mounted() {
}, watch(
methods: { () => props.data,
down_file(url){ (n, o) => {
if(url){ if (props.layout.line_num) {
console.log(url); unit_width.value = { width: 100 / props.layout.line_num + "%" };
const a = document.createElement("a"); // 创建a标签 }
a.setAttribute("download", ""); // download属性 if (props.layout.line_num && n.length % props.layout.line_num !== 0) {
a.setAttribute("href", url); // href链接 //计算最后一个格子的宽度
a.click(); // 自执行点击事件 last_width.value = {
} 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 < props.layout.line_num) {
return;
} else {
bg_num.value = Math.floor(Math.ceil(n.length / props.layout.line_num) / 2);
}
}
);
const down_file = (url) => {
if (url) {
console.log(url);
const a = document.createElement("a"); // 创建a标签
a.setAttribute("download", ""); // download属性
a.setAttribute("href", url); // href链接
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,16 +110,16 @@ export default { ...@@ -107,16 +110,16 @@ 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;
} }
</style> </style>
<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>
</p> </p>
<template v-else> <template v-else>
<slot :name="item.slot" :data="item"></slot> <slot :name="item.slot" :data="item"></slot>
</template> </template>
</div>
</div> </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;
flex-wrap: wrap; flex-wrap: wrap;
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;
border-left: solid 1px #dadee7; border-left: solid 1px #dadee7;
border-top: solid 1px #dadee7; border-top: solid 1px #dadee7;
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>
<template> <template>
<div class="bg-detail bg-form"> <div class="bg-detail bg-form" ref="bgDetail">
<!-- 固定导航 --> <!-- 固定导航 -->
<div class="bg-tabs-nav--fixed" v-show="showFixedBars"> <div class="bg-tabs-nav--fixed" v-show="showFixedBars">
<ul v-if="calcTabs().length"> <ul v-if="calcTabs().length">
...@@ -60,32 +60,30 @@ ...@@ -60,32 +60,30 @@
</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: () => {
return false; provide('getActiveName',activeName.value)
},
}; provide('getIsTabs',false)
},
data() { const showFixedBars = ref(false)
return {
activeName: "", const state = reactive({
showFixedBars: false, scrollCallback:null
scrollCallback: null, })
};
}, const calcTabs=()=> {
methods: {
calcTabs() {
let tabSlots = []; let tabSlots = [];
if (this.$slots.default) { if (slots.default()) {
tabSlots = this.$slots.default tabSlots = slots.default()
.filter( .filter(
(vnode) => (vnode) =>
vnode.tag && vnode.tag &&
...@@ -96,48 +94,47 @@ export default { ...@@ -96,48 +94,47 @@ export default {
} }
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() { onMounted(()=>{
this.$nextTick(() => { nextTick().then(() => {
let tabs = this.calcTabs(); let tabs = calcTabs();
this.activeName = tabs[0] && tabs[0].name; activeName.value = tabs[0] && tabs[0].name;
scrollAction();
this.scrollAction(); window.addEventListener("scroll", scrollAction, true);
window.addEventListener("scroll", this.scrollAction, true); });
}); })
},
destroyed() { onUnmounted(()=>{
window.removeEventListener("scroll", this.scrollAction, true); 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,31 @@ ...@@ -15,31 +15,31 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { import { reactive, ref, onBeforeMount, toRefs, computed, watch } from "vue";
name: "BgFilterDate", const props = defineProps({
model: { name: {
prop: "time", type: String,
event: "change", default: "",
}, },
props: { time: {
name: { type: String,
type: String, default: "",
default: "",
},
}, },
data() { });
return {
value: "" const emit = defineEmits(["update:time"]);
}
}, // const change=(event)=> {
computed: { // emit("update:time", event);
// }
const useTime = computed({
get() {
return props.time;
}, },
methods: { set(value) {
change(event) { emit("update:time", value);
this.$emit("change", event);
},
}, },
}; });
</script> </script>
\ No newline at end of file
<template> <template>
<div class="bg-filter-group" :style="{'border-bottom': showFlag? 'none' : '','padding-bottom': showFlag? '8px':'16px'}"> <div
class="bg-filter-group"
:style="
showFlag
? { 'border-bottom': 'none', 'padding-bottom': '8px' }
: { 'border-bottom': '', 'padding-bottom': '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 :placeholder="placeholder" @keydown.enter="search" @clear="search" clearable v-model.trim="modelValue"> <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" ref="filterGroup" 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, nextTick } from "vue";
const state = reactive({ const state = reactive({
showFlag: false, showFlag: true,
modelValue: "" modelValue: "",
}) });
// const filterGroup = ref(null);
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
type: String, type: String,
default: '', default: "",
}, },
placeholder: { placeholder: {
type: String, type: String,
default: "请输入关键词" default: "请输入关键词",
} },
}) showSearch: {
type: Boolean,
default: true,
},
});
watch(props,(n,o) => { watch(props, (n, o) => {
state.modelValue = n.modelValue state.modelValue = n.modelValue;
}) });
watch(() => state.modelValue,(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",
// "changeHeight"
]);
const search = () => { const search = () => {
emit('search',state.modelValue) emit("search", state.modelValue);
} };
const moreFilter = () => { const moreFilter = () => {
state.showFlag = !state.showFlag state.showFlag = !state.showFlag;
} // nextTick().then(() => {
// console.dir(filterGroup.value)
// let height = filterGroup.value.offsetHeight
// // console.log(height)
// emit("changeHeight",height)
// })
};
onMounted(() => { onMounted(() => {
state.modelValue = props.modelValue state.modelValue = props.modelValue;
}) });
const { modelValue,showFlag } = toRefs(state) const { modelValue, showFlag } = toRefs(state);
</script> </script>
\ No newline at end of file
...@@ -15,22 +15,17 @@ ...@@ -15,22 +15,17 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { import {computed} from "vue";
name: "BgFilter", const props = defineProps({
model: { modelValue: {
prop: "value", type: [Number, String],
event: "change", default: '',
}, },
props: { isCalc:{
isCalc:{
type:Boolean, type:Boolean,
default:false, default:false,
}, },
value: {
type: [Number, String],
default: "",
},
name: { name: {
type: String, type: String,
default: "", default: "",
...@@ -51,34 +46,34 @@ export default { ...@@ -51,34 +46,34 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}, });
computed: {
fullOptions() { const emit = defineEmits(['update:modelValue'])
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() { const selection = computed(()=> {
let value = this.value + ""; 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 +82,9 @@ export default { ...@@ -87,11 +82,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,85 +6,83 @@ ...@@ -6,85 +6,83 @@
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: "BgFiltrate",
model: { const props = defineProps({
prop: "value", modelValue: {
event: "change", type: [Number, String],
default: "",
}, },
props: { isCalc: {
value: { type: Boolean,
type: [Number, String], default: false,
default: "",
},
name: {
type: String,
default: "",
},
options: {
type: Array,
default: () => [],
},
optionName: {
type: String,
default: "name",
},
optionValue: {
type: String,
default: "value",
},
multiple: {
type: Boolean,
default: false,
},
}, },
computed: { name: {
fullOptions() { type: String,
return [ default: "",
{
name: "全部",
value: "",
},
...this.options.map((item) => {
return {
name: item[this.optionName],
value: item[this.optionValue] + "",
};
}),
];
},
selection() {
let value = this.value + "";
return value.split(",");
},
}, },
methods: { options: {
selectAction({ value, name }) { type: Array,
if (value && this.multiple) { default: () => [],
let selection = [...this.selection].filter((v) => v !== ""); },
let index = selection.findIndex((v) => v === value); optionName: {
type: String,
default: "name",
},
optionValue: {
type: String,
default: "value",
},
multiple: {
type: Boolean,
default: false,
},
});
if (index > -1) { const emit = defineEmits(["update:modelValue"]);
selection.splice(index, 1);
} else {
selection.push(value);
}
this.$emit("change", selection.join(",")); const fullOptions = computed(() => {
} else { return [
this.$emit("change", value, name); {
} name: "全部",
value: "",
}, },
}, ...props.options.map((item) => {
return {
name: item[props.optionName],
value: item[props.optionValue] + "",
};
}),
];
});
const selection = computed(() => {
let value = props.modelValue + "";
return value.split(",");
});
const selectAction = ({ value, name, sub_cate }) => {
if (value && props.multiple) {
let selection = [...props.selection].filter((v) => v !== "");
let index = selection.findIndex((v) => v === value);
if (index > -1) {
selection.splice(index, 1);
} else {
selection.push(value);
}
emit("update:modelValue", selection.join(","));
} else {
emit("update:modelValue", value, name);
}
}; };
</script> </script>
\ No newline at end of file
...@@ -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_220.40af3ff1115b250314027a7e199e042a.js"; import "https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/svg_19654_229.cab419d7be9fcc68760c67d9dcb0cb4a.js";
export default { const props = defineProps({
props: { icon: {
icon: { type: String,
type: String, default: "",
default: "",
},
}, },
}; })
</script> </script>
\ No newline at end of file
...@@ -6,115 +6,109 @@ ...@@ -6,115 +6,109 @@
: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',
}" }">
>{{ item.value }}</span> <span v-if="item.callback" @click.stop="item.callback && item.callback()" class="can_click_text" style="text-decoration:underline">{{
<a item.value
}}</span>
<span v-else>{{ item.value }}</span>
</span>
<a class="copy-btn" @click="copyText(item.value, $event)" v-if="item.copy"> 复制 </a>
<bg-icon
class="copy-btn" class="copy-btn"
@click="copyText(item.value, $event)" :class="item.url.indexOf('/') == -1 ? 'copy-btn-dis' : ''"
v-if="item.copy" style="font-size: 14px; cursor: pointer"
> icon="#bg-ic-download"
复制
</a>
<bg-icon
class="copy-btn"
style="font-size: 14px;cursor: pointer;"
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;cursor: pointer;" style="font-size: 14px; 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 { reactive, ref, onBeforeMount, toRefs } from "vue";
import Clipboard from "clipboard"; import Clipboard from "clipboard";
import { ElMessage } from "element-plus";
export default { const props = defineProps({
name: "BgInfo", data: {
props: { type: Array,
data: { default: () => [],
type: Array,
default: () => [],
},
col: {
type: Number,
default: 2,
},
}, },
data() { col: {
return { type: Number,
show: false default: 2,
}
}, },
methods: { });
clipboardSuccess() {
this.$message({
type: "success",
message: "复制成功",
duration: 1500,
});
},
clipboardError() {
this.$message({
message: "浏览器不支持自动复制",
type: "warning",
});
},
copyText(text, e) {
const clipboard = new Clipboard(e.target, {
text: () => text,
});
clipboard.on("success", () => { const show = ref(false);
this.clipboardSuccess();
// 释放内存
clipboard.destroy();
});
clipboard.on("error", () => { const clipboardSuccess = () => {
// 不支持复制 ElMessage({
this.clipboardError(); type: "success",
// 释放内存 message: "复制成功",
clipboard.destroy(); duration: 1500,
}); });
};
// 解决第一次点击不生效的问题,如果没有,第一次点击会不生效 const clipboardError = () => {
clipboard.onClick(e); ElMessage({
}, message: "浏览器不支持自动复制",
download(url) { type: "warning",
const a = document.createElement("a"); // 创建a标签 });
a.setAttribute("download", ""); // download属性 };
a.setAttribute("href", url); // href链接 const copyText = (text, e) => {
a.click(); // 自执行点击事件 const clipboard = new Clipboard(e.target, {
}, text: () => text,
changeView(item) { });
if (!this.show) {
item.value = item.realValue clipboard.on("success", () => {
}else { clipboardSuccess();
item.value = "***************" // 释放内存
} clipboard.destroy();
this.show = !this.show });
}
}, clipboard.on("error", () => {
// 不支持复制
clipboardError();
// 释放内存
clipboard.destroy();
});
// 解决第一次点击不生效的问题,如果没有,第一次点击会不生效
clipboard.onClick(e);
};
const download = (url) => {
if (url.indexOf("/") == -1) {
return;
}
const a = document.createElement("a"); // 创建a标签
a.setAttribute("download", ""); // download属性
a.setAttribute("href", url); // href链接
a.click(); // 自执行点击事件
};
const changeView = (item) => {
if (!show.value) {
item.value = item.realValue;
} else {
item.value = "***************";
}
show.value = !show.value;
}; };
</script> </script>
...@@ -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,87 +26,81 @@ ...@@ -28,87 +26,81 @@
</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", title: {
props: { type: String,
title: { default: "",
type: String,
default: "",
},
width: {
type: String,
default: "25%",
},
height: {
type: String,
default: "278px",
},
btn: {
type: Number,
default: 0,
},
btns: {
type: Array,
default: () => [],
},
download: {
type: Boolean,
default: false,
},
}, },
computed: { width: {
style() { type: String,
return { default: "25%",
width: `calc(${this.width} - 20px)`,
height: this.height,
};
},
}, },
data() { height: {
return { type: String,
downloading: false, default: "278px",
};
}, },
methods: { btn: {
getScrollTop() { type: Number,
let scrollTop = 0; default: 0,
},
btns: {
type: Array,
default: () => [],
},
download: {
type: Boolean,
default: false,
},
});
if (document.documentElement && document.documentElement.scrollTop) { const style = computed(() => {
scrollTop = document.documentElement.scrollTop; return {
} else if (document.body) { width: `calc(${props.width} - 20px)`,
scrollTop = document.body.scrollTop; height: props.height,
} };
});
return scrollTop; const downloading = ref(false);
},
downloadAction() {
if (this.downloading) {
return;
}
let content = this.$refs.content; const content = ref(null);
let { top, left } = content.getBoundingClientRect();
let scrollTop = this.getScrollTop();
this.downloading = true; const getScrollTop = () => {
let scrollTop = 0;
html2canvas(content, { x: left, y: top + scrollTop }).then((canvas) => { if (document.documentElement && document.documentElement.scrollTop) {
let imgUrl = canvas.toDataURL("image/png"); scrollTop = document.documentElement.scrollTop;
let a = document.createElement("a"); // 生成一个a元素 } else if (document.body) {
let event = new MouseEvent("click"); // 创建一个单击事件 scrollTop = document.body.scrollTop;
}
this.$nextTick(() => { return scrollTop;
a.download = this.title; // 设置图片名称 };
a.href = imgUrl; // 将生成的URL设置为a.href属性 const downloadAction = () => {
a.dispatchEvent(event); // 触发a的单击事件 if (downloading.value) {
return;
}
this.downloading = false; let { top, left } = content.value.getBoundingClientRect();
}); let scrollTop = getScrollTop();
});
}, downloading.value = true;
},
html2canvas(content.value, { x: left, y: top + scrollTop }).then((canvas) => {
let imgUrl = canvas.toDataURL("image/png");
let a = document.createElement("a"); // 生成一个a元素
let event = new MouseEvent("click"); // 创建一个单击事件
nextTick().then(() => {
a.download = props.title; // 设置图片名称
a.href = imgUrl; // 将生成的URL设置为a.href属性
a.dispatchEvent(event); // 触发a的单击事件
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,22 +66,19 @@ ...@@ -73,22 +66,19 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
name: "BgList", visible: {
props: { type: Boolean,
visible: { default: false,
type: Boolean, },
default: false, noMoreFilters: {
}, type: Boolean,
noMoreFilters: { default: false,
type: Boolean, },
default: false, inlineFilters: {
}, type: Boolean,
inlineFilters: { default: false,
type: Boolean,
default: false,
},
}, },
}; });
</script> </script>
<template> <template>
<ul class="nav-list" v-if="list&&list.length"> <ul class="nav-list bg-no-scroll" 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>
...@@ -41,51 +48,68 @@ ...@@ -41,51 +48,68 @@
</ul> </ul>
</template> </template>
<script> <script>
export default { export default {
name: "NavList", name: "NavList",
props: { };
list: { </script>
type: Array, <script setup>
required: true, import { reactive, ref, onBeforeMount, toRefs, onMounted } from "vue";
}, // 导航列表 [ { name: "xxx", path: "xxx" } ] const props = defineProps({
deep: { list: {
type: Number, type: Array,
default: 0, required: true,
}, }, // 导航列表 [ { name: "xxx", path: "xxx" } ]
highlightParentRule: { deep: {
type: Function, type: Number,
}, default: 0,
}, },
data() { highlightParentRule: {
return { type: Function,
showMore: {},
};
}, },
methods: { });
showMoreAction(index) {
let flag = this.showMore[index];
if (flag === undefined) { const showMore = reactive({});
flag = true;
}
this.showMore[index] = !flag const showMoreAction = (index) => {
}, let flag = showMore[index];
getChildrenPath(arr,temp=[]){
arr.forEach(e => { if (flag === undefined) {
temp.push(e.path) flag = true;
if(e.children&&e.children.length){ }
this.getChildrenPath(e.children,temp)
} showMore[index] = !flag;
}); };
return temp const getChildrenPath = (arr, temp = []) => {
}, arr.forEach((e) => {
isCurrent(path) { temp.push(e.path);
return ( if (e.children && e.children.length) {
(this.highlightParentRule && this.highlightParentRule(path)) || false getChildrenPath(e.children, temp);
); }
}, });
}, return temp;
};
const isCurrent = (path) => {
return (props.highlightParentRule && props.highlightParentRule(path)) || false;
}; };
/**
* @description 菜单高度过长,对于不在视野中的元素需要scrollIntoView
*/
const setCurrentIntoView = ()=>{
let current = document.querySelector(".current")
if(!current){
return
}
let screenHeight = document.body.clientHeight
let currentClient = current.getBoundingClientRect()
if(currentClient.top+currentClient.height>screenHeight-10){
current.scrollIntoView()
}
}
onMounted(()=>{
setCurrentIntoView()
})
</script> </script>
...@@ -3,36 +3,30 @@ ...@@ -3,36 +3,30 @@
<div class="bg-nav-title" v-if="title"> <div class="bg-nav-title" v-if="title">
<h3 class="text-clip">{{ title }}</h3> <h3 class="text-clip">{{ title }}</h3>
</div> </div>
<div class="bg-nav-list bg-scroll"> <div class="bg-nav-list">
<NavList :list="list" :highlight-parent-rule="highlightParentRule" /> <NavList :list="list" :highlight-parent-rule="highlightParentRule" />
</div> </div>
</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", title: {
components: { type: String,
NavList, default: "",
}, },
props: { width: {
title: { type: String,
type: String, default: "184px",
default: "", }, // 宽度
}, list: {
width: { type: Array,
type: String, required: true,
default: "184px", }, // 导航列表 [ { name: "xxx", path: "xxx" } ]
}, // 宽度 highlightParentRule: {
list: { type: Function,
type: Array,
required: true,
}, // 导航列表 [ { name: "xxx", path: "xxx" } ]
highlightParentRule: {
type: Function,
},
}, },
}; });
</script> </script>
<template> <template>
<div class="bg-pagination"> <div class="bg-pagination">
<el-pagination <el-pagination
:currentPage="page" :small="small"
:page-size="size" :currentPage="numberOfPage"
:page-size="numberOfPageSize"
:page-sizes="pageSizes" :page-sizes="pageSizes"
:layout="layout" :layout="layout"
:total="total" :total="total"
@size-change="changeSize" @size-change="changeSize"
@current-change="changePage" @current-change="changePage"
:background="background" :background="background"
:disabled="disabled" :disabled="disabled" />
/>
</div> </div>
</template> </template>
<script> <script setup>
export default { import { computed } from 'vue';
name: "pagination", const props = defineProps({
props: { small: {
page: { type: Boolean,
type: Number, default: () => false,
default: 1 },
}, page: {
size: { type: [String, Number],
type: Number, default: 1,
default: 10, },
}, size: {
pageSizes: { type: [String, Number],
type: Array, default: 10,
default: [10,50,100] },
}, pageSizes: {
total: { type: Array,
type: Number, default: [10, 50, 100],
default: 0 },
}, total: {
layout: { type: Number,
type: String, default: 0,
default: "total, sizes, prev, pager, next, jumper" },
}, layout: {
background: { type: String,
type: Boolean, default: "total, sizes, prev, pager, next, jumper",
default: false },
}, background: {
disabled: { type: Boolean,
type: Boolean, default: false,
default: false },
} disabled: {
}, type: Boolean,
setup(props, context) { default: false,
const changePage = (val) => { },
context.emit("change-page",val) });
} const emit = defineEmits(["change-page", "change-size"]);
const changeSize = (val) => { const numberOfPage = computed(() => Number(props.page))
context.emit("change-size",val) const numberOfPageSize = computed(() => Number(props.size))
} const changePage = (val) => {
return { emit("change-page", val);
changePage, };
changeSize
} const changeSize = (val) => {
}, emit("change-size", val);
} };
</script> </script>
\ No newline at end of file
<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> <script setup>
import '@wangeditor/editor/dist/css/style.css' // 引入 css import "@wangeditor/editor/dist/css/style.css"; // 引入 css
import { onBeforeUnmount, ref, shallowRef, onMounted, reactive, toRefs } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { import { onBeforeUnmount, ref, shallowRef, onMounted } from "vue";
useFormItem, import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
} from 'element-plus'
import { useFormItem } from "element-plus";
export default { const props = defineProps({
components: { Editor, Toolbar },
props: {
modelValue: { modelValue: {
type: String, type: String,
default: '', default: "",
}, },
disabled:{ disabled: {
type:Boolean, type: Boolean,
default:false default: false,
} },
}, mode: {
emits: ['update:modelValue','change','blur'], type: String,
watch:{ default: "default",
modelValue(n,o){ },
this.valueHtml = n });
}
}, const emit = defineEmits(["update:modelValue", "change", "blur"]);
setup(props,{ emit }) {
//引入form-item const valueHtml = ref("");
const { formItem } = useFormItem() // change次数
// 编辑器实例,必须用 shallowRef let changeNum = ref(0);
const editorRef = shallowRef()
const { formItem } = useFormItem();
// 内容 HTML
const valueHtml = ref('') const editorRef = shallowRef();
// change次数 onMounted(() => {
let changeNum = ref(0) setTimeout(() => {
valueHtml.value = props.modelValue;
// 模拟 ajax 异步获取内容 });
onMounted(() => { });
setTimeout(()=>{
valueHtml.value = props.modelValue const toolbarConfig = {};
// console.log(valueHtml.value); const editorConfig = {
}) placeholder: "请输入内容...",
}) MENU_CONF: {
uploadImage: {
const toolbarConfig = {} server: "/apaas/common/image/upload", // 服务器地址
const editorConfig = { fieldName: "file", // 上传的文件的字段名称
placeholder: '请输入内容...', meta: {
MENU_CONF: { directory: "image",
uploadImage: { }, // 上传图片必须携带的参数
server: '/apaas/common/image/upload', // 服务器地址 maxFileSize: 2 * 1024 * 1024, // 图片最大2M
fieldName: "file", // 上传的文件的字段名称 timeout: 3 * 60 * 1000, // 超时时间3分钟
meta: { allowedFileTypes: ["image/jpg", "image/png", "image/gif", "image/jpeg"],
directory: 'image', customInsert(res, insertFn) {
}, // 上传图片必须携带的参数 // res 即服务端的返回结果
maxFileSize: 2 * 1024 * 1024, // 图片最大2M // 从 res 中找到 url alt href ,然后插图图片 url是必须,href和alt可以为""
timeout: 3 * 60 * 1000, // 超时时间3分钟 let url = res.data;
allowedFileTypes: ['image/jpg','image/png','image/gif','image/jpeg',], let alt = "";
customInsert(res, insertFn) { let href = res.data;
// res 即服务端的返回结果 insertFn(url, alt, href);
// 从 res 中找到 url alt href ,然后插图图片 url是必须,href和alt可以为"" },
let url = res.data onBeforeUpload(file) {
let alt = "" // 可以 return
let href = res.data // 1. return file 或者 new 一个 file ,接下来将上传
insertFn(url, alt, href) // 2. return false ,不上传这个 file
}, let allowedType = ["jpg", "png", "jpeg", "gif", "bmp", "tiff"]; // 常见的图片格式
onBeforeUpload(file) { let data = Object.values(file)[0];
// 可以 return if (allowedType.indexOf(data.extension) == -1) {
// 1. return file 或者 new 一个 file ,接下来将上传 alert(`图片验证未通过,【${data.name}】不是图片`);
// 2. return false ,不上传这个 file return false;
let allowedType = ["jpg","png","jpeg","gif","bmp","tiff"] // 常见的图片格式 } else {
let data = Object.values(file)[0] return file;
if (allowedType.indexOf(data.extension) == -1) { }
alert(`图片验证未通过,【${data.name}】不是图片`) },
return false onError(file, err, res) {
}else { console.log(`${file.name} 上传出错`, err, res);
return file },
} },
}, },
onError(file, err, res) { };
console.log(`${file.name} 上传出错`, err, res)
}, onBeforeUnmount(() => {
} const editor = editorRef.value;
} if (editor == null) return;
} editor.destroy();
});
// watch( const handleCreated = (editor) => {
// props,modelValue, editorRef.value = editor; // 记录 editor 实例,重要!
// (n,o) => { if (props.disabled) {
editor.disable();
// }
// )
// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null) return
editor.destroy()
})
const handleCreated = (editor) => {
editorRef.value = editor // 记录 editor 实例,重要!
if(props.disabled){
editor.disable()
}
}
const handleChange = ()=>{
//初始化会默认赋值<p><br></p>
//会对原有数据造成影响,return掉
changeNum.value++
if(changeNum.value==1){
return
}
emit("update:modelValue", valueHtml.value);
// formItem?.validate?.('change').catch((err) => debugWarn(err))
} }
};
const handleBlur = ()=>{ const handleChange = () => {
formItem?.validate?.('blur').catch((err) => console.warn(err)) //初始化会默认赋值<p><br></p>
//会对原有数据造成影响,return掉
changeNum.value++;
if (changeNum.value == 1) {
return;
} }
emit("update:modelValue", valueHtml.value);
return { };
editorRef, const handleBlur = () => {
valueHtml, formItem?.validate?.("blur").catch((err) => console.warn(err));
mode: 'default', // 或 'simple' };
toolbarConfig,
editorConfig,
handleCreated,
handleChange,
handleBlur,
};
}
}
</script> </script>
<style>
.w-e-toolbar p, .w-e-text-container p, .w-e-menu-panel p {
font-size: 14px !important;
color: #202531!important;
}
.w-e-text-container{
word-break: break-all;
}
</style>
\ No newline at end of file
...@@ -3,52 +3,45 @@ ...@@ -3,52 +3,45 @@
<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: { type: [String, Number],
prop: "value", default: "",
event: "change",
}, },
props: { types: {
value: { type: Array,
type: [Number, String], default: () => [
default: "", {
}, name: "综合排序",
types: { value: 0,
type: Array, },
default: () => [ {
{ name: "最近更新",
name: "综合排序", value: 1,
value: 0, },
}, {
{ name: "最高人气",
name: "最近更新", value: 2,
value: 1, },
}, {
{ name: "最好评价",
name: "最高人气", value: 3,
value: 2, },
}, ],
{
name: "最好评价",
value: 3,
},
],
},
},
methods: {
selectAction({ value }) {
this.$emit("change", value);
},
}, },
});
const emit = defineEmits(["update:modelValue"]);
const selectAction = ({ value }) => {
emit("update:modelValue", value);
}; };
</script> </script>
\ No newline at end of file
<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>
<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,87 +9,84 @@ ...@@ -15,87 +9,84 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { import { reactive, ref, onBeforeMount, toRefs, computed, onMounted } from "vue";
name: "BgSwitch", const props = defineProps({
props: { modelValue: {
modelValue: { type: [Boolean, Number, String],
type: [Boolean, Number, String], default: 0,
default: 0,
},
labels: {
type: Array,
default: () => ["停用", "启用"],
},
values: {
type: Array,
default: () => [0, 1],
},
colors: {
type: Array,
default: () => ["#c1c7d7", "#275a9d"],
},
disabled: {
type: Boolean,
default: false,
},
}, },
emits: ['update:modelValue'], labels: {
data() { type: Array,
return { default: () => ["停用", "启用"],
gap: 0,
box_height: 0,
circle_height: 0,
};
}, },
computed: { values: {
now_index() { type: Array,
if (this.values[0] == this.modelValue) { default: () => [0, 1],
return 0;
} else {
return 1;
}
},
now_style() {
return {
color: this.colors[this.now_index],
borderColor: this.colors[this.now_index],
};
},
now_label_style() {
return this.now_index == 0
? { left: this.circle_height + this.gap + 5 + "px" }
: { left: "10px" };
},
now_circle_style() {
return this.now_index == 0
? {
left: this.gap + "px",
backgroundColor: this.colors[this.now_index],
}
: {
right: this.gap + "px",
backgroundColor: this.colors[this.now_index],
};
},
}, },
methods: { colors: {
switch_data() { type: Array,
if (this.disabled) { default: () => ["#c1c7d7", "#275a9d"],
return;
}
if (this.values[0] == this.modelValue) {
this.$emit("update:modelValue", this.values[1]);
} else {
this.$emit("update:modelValue", this.values[0]);
}
},
}, },
mounted() { disabled: {
this.box_height = this.$refs.bg_switch.offsetHeight; type: Boolean,
this.circle_height = this.$refs.circle.offsetHeight; default: false,
this.gap = (this.box_height - this.circle_height - 4) / 2;
}, },
});
const emit = defineEmits(["update:modelValue"]);
const gap = ref(0);
const box_height = ref(0);
const circle_height = ref(0);
const now_index = computed(() => {
if (props.values[0] == props.modelValue) {
return 0;
} else {
return 1;
}
});
const now_style = computed(() => {
return {
color: props.colors[now_index.value],
borderColor: props.colors[now_index.value],
};
});
const now_label_style = computed(() => {
return now_index.value == 0 ? { left: circle_height.value + gap.value + 5 + "px" } : { left: "10px" };
});
const now_circle_style = computed(() => {
return now_index.value == 0
? {
left: gap.value + "px",
backgroundColor: props.colors[now_index.value],
}
: {
right: gap.value + "px",
backgroundColor: props.colors[now_index.value],
};
});
const switch_data = () => {
if (props.disabled) {
return;
}
if (props.values[0] == props.modelValue) {
emit("update:modelValue", props.values[1]);
} else {
emit("update:modelValue", props.values[0]);
}
}; };
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,51 +9,47 @@ ...@@ -9,51 +9,47 @@
</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;
},
},
getIsTabs: {
type: Function,
default: () => {
return false;
},
},
}, },
props: { false
label: { );
type: String, const getIsTabs = inject(
required: true, "isTabs",
}, false
name: { );
type: String,
required: true, const props = defineProps({
}, label: {
type: String,
required: true,
}, },
computed: { name: {
activeName() { type: String,
return this.getActiveName(); required: true,
},
isTabs() {
return this.getIsTabs();
},
showTab() {
if (this.isTabs) {
if (this.activeName === this.name) {
return true;
} else {
return false;
}
} else {
return true;
}
},
}, },
}; });
const activeName = computed(() => {
return getActiveName();
});
const isTabs = computed(() => {
return getIsTabs;
});
const showTab = computed(() => {
if (isTabs.value) {
if (activeName.value === props.name) {
return true;
} else {
return false;
}
} else {
return true;
}
});
</script> </script>
...@@ -4,30 +4,27 @@ ...@@ -4,30 +4,27 @@
</a> </a>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
name: "BgTableBtn", disabled: {
props: { type: Boolean,
disabled: { default: false,
type: Boolean,
default: false,
},
click: {
type: Function,
default: () => null,
},
}, },
emits: ["click"], click: {
methods: { type: Function,
clickAction() { default: () => null,
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>
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
</bg-table-btn> </bg-table-btn>
<a <a
class="bg-table-btn" class="bg-table-btn"
@mouseenter="showMOreBtns" @mouseenter="showMoreBtns"
@mouseleave="hideMoreBtns" @mouseleave="hideMoreBtns"
v-if="otherOperations.length > 0" v-if="otherOperations.length > 0"
> >
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
<bg-icon style="font-size: 12px; color: #2b4695;" icon="#bg-ic-s-more" /> <bg-icon style="font-size: 12px; color: #2b4695;" icon="#bg-ic-s-more" />
<bg-table-btns-more <bg-table-btns-more
:operations="otherOperations" :operations="otherOperations"
@mouseenter="showMOreBtns" @mouseenter="showMoreBtns"
@mouseleave="hideMoreBtns" @mouseleave="hideMoreBtns"
v-if="showMore" v-if="showMore"
/> />
...@@ -78,7 +78,7 @@ export default { ...@@ -78,7 +78,7 @@ export default {
return name; return name;
} }
}, },
showMOreBtns() { showMoreBtns() {
if (this.timer) clearTimeout(this.timer); if (this.timer) clearTimeout(this.timer);
this.showMore = true; this.showMore = true;
......
<template>
<div class="bg-table-btns" ref="bgTableBtnsRef">
<slot></slot>
<span
class="bg-table-btn more"
id="more_btn"
v-if="state.children.length > limit"
ref="lastEl"
@mouseenter="showMoreBtns"
@mouseleave="hideMoreBtns">
<bg-icon style="font-size: 12px; color: #2b4695" icon="#bg-ic-s-more" />
<teleport to="body">
<div
class="more-box"
:style="state.style"
v-if="state.showMore"
@mouseenter="showMoreBtns"
@mouseleave="hideMoreBtns">
<span
v-for="(item, index) in state.lastChildren"
:key="'as' + index"
@click="action(item.onClick, item.disabled)"
:class="item.disabled ? 'disabled' : ''"
>{{ item.name }}</span
>
</div>
</teleport>
</span>
</div>
</template>
<script setup>
import { reactive, ref, onBeforeMount, onMounted, toRefs, provide, useSlots, h, render, nextTick } from "vue";
const slots = useSlots();
const props = defineProps({
limit: {
type: Number,
default: 3,
},
});
const bgTableBtnsRef = ref(null);
const lastEl = ref(null);
const state = reactive({
children: [],
index: 0,
lastChildren: [],
style: {},
timer: null,
showMore: false,
});
const action = (event, disable) => {
if (disable) {
return;
}
event();
state.showMore = false
};
const calcTabs = () => {
let tabSlots = slots.default() || [];
state.lastChildren = [];
if (tabSlots) {
tabSlots.forEach((e, idx) => {
if (idx + 2 > props.limit && tabSlots.length > props.limit && e.props) {
// console.log(e);
// console.log(e.props);
state.lastChildren.push(e.props);
}
});
}
};
const showMoreBtns = () => {
calcTabs();
dealData();
nextTick(() => {
updateSytle();
if (state.timer) clearTimeout(state.timer);
state.showMore = true;
});
};
const hideMoreBtns = () => {
if (state.timer) clearTimeout(state.timer);
state.timer = setTimeout(() => {
state.showMore = false;
}, 50);
};
const updateSytle = () => {
let { top, right } = lastEl.value.getBoundingClientRect();
let { width } = window.document.body.getBoundingClientRect();
state.style = {
top: `${top + 16}px`,
right: `${width - right - 16}px`,
};
};
const dealData = () => {
let children = bgTableBtnsRef.value.children || [];
state.children = children;
if (children.length > props.limit) {
children[props.limit - 1].style.display = "none";
children[props.limit - 1].style.width = "0px";
state.index = props.limit - 2;
state.lastChildren[0].name = children[props.limit - 1].innerText;
}
for (let index = 0; index < children.length; index++) {
const e = children[index];
if (index + 1 > props.limit && e.tagName == "A" && e.className.indexOf("bg-table-btn") !== -1) {
e.style.display = "none";
e.style.width = "0px";
state.lastChildren[index - props.limit + 1].name = e.innerText;
}
}
};
onMounted(() => {
calcTabs();
dealData();
});
</script>
<style scoped>
.more {
position: relative;
z-index: 200;
}
.more-box {
position: fixed;
padding: 4px 0;
background-color: #ffffff;
box-shadow: 0px 4px 12px 0px rgba(18, 30, 63, 0.1);
border-radius: 4px;
border: solid 1px #e6e9ef;
width: 88px;
z-index: 300;
}
.more-box span {
display: block;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
white-space: nowrap;
padding: 10px 16px;
color: #404a62;
line-height: 1;
font-size: 14px;
cursor: pointer;
}
.more-box span:hover {
background-color: #f2f3f7;
}
.more-box .disabled {
color: #a9b1c7;
cursor: not-allowed;
}
.more-box .disabled:hover {
background-color: #f2f3f7;
color: #a9b1c7;
}
.more-box span::before {
display: none;
}
</style>
...@@ -3,14 +3,13 @@ ...@@ -3,14 +3,13 @@
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"
tooltip-effect="light" tooltip-effect="light"
> :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>
...@@ -19,13 +18,7 @@ ...@@ -19,13 +18,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}`"
...@@ -33,8 +26,7 @@ ...@@ -33,8 +26,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,135 +55,132 @@ ...@@ -63,135 +55,132 @@
</el-table-column> </el-table-column>
</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();
headers: {
type: Array, const props = defineProps({
require: true, headers: {
}, type: Array,
data: { require: true,
type: Array,
},
rowKey: {
type: String,
},
treeProps: {
type: Object,
},
showIndex: {
type: Boolean,
default: false,
},
selectable: {
type: Function,
},
defaultExpandAll: {
type: Boolean,
default: false,
},
}, },
data() { data: {
return { type: Array,
allSelection: [], // 所有页面上的选中的数据
};
}, },
computed: { rowKey: {
showSelctColumn() { type: String,
return (
this.$attrs &&
(this.$attrs["selection-change"] || this.$attrs["select"])
);
}, // 是否显示选中列
addSelectEvent() {
return this.$attrs && this.$attrs["select"];
}, // 是否监听select事件 select事件会记录所有页面上的选中的数据
}, },
watch: { treeProps: {
data: { type: Object,
handler() {
this.recoverSelection();
},
deep: true,
},
}, },
methods: { showIndex: {
recoverSelection() { type: Boolean,
let selectionIds = this.allSelection.map((v) => v[this.rowKey]); default: false,
},
this.data.forEach((v) => { selectable: {
if (selectionIds.indexOf(v[this.rowKey]) > -1) { type: Function,
this.$nextTick(() => { },
console.log({ ...v }); defaultExpandAll: {
this.$refs.table.toggleRowSelection(v, true); type: Boolean,
}); default: false,
}
});
}, // 恢复选中
selectionChange(selection) {
if (!this.addSelectEvent) return; // 如果用户未监听select事件,则不执行
if (!this.rowKey) throw Error("监听select事件时,row-key必须传入!");
this.upAllSelection(selection);
this.$emit("select", this.allSelection);
}, // select事件
upAllSelection(selection) {
let rowIds = this.data.map((v) => v[this.rowKey]);
let allSelection = [...this.allSelection];
let selectionIds = allSelection.map((v) => v[this.rowKey]);
// 首先把当前页的选中全部移除
selectionIds = selectionIds.filter((v) => rowIds.indexOf(v) === -1);
// allSelection仅保留selectionIds存在的
allSelection = allSelection.filter(
(v) => selectionIds.indexOf(v[this.rowKey]) > -1
);
// 然后再加入当前页的选中
allSelection.push(...selection);
this.allSelection = allSelection;
}, // 更新当前全部被选中的数据
clearSelection() {
this.$refs.table.clearSelection();
this.allSelection = [];
}, // 清空选中
getRowInfo(row, key) {
let currentIndex = -1;
let parentRows = null;
let propPath = "";
let childrenKey = this.treeProps.children;
let recursionItems = (items, prop) => {
for (let i = 0; i < items.length; i++) {
let item = items[i];
propPath += `${i}.`;
if (item[prop] === row[prop]) {
currentIndex = i;
parentRows = items;
break;
} else if (item[childrenKey] && item[childrenKey].length > 0) {
propPath += `${childrenKey}.`;
recursionItems(item[childrenKey], prop);
}
}
};
recursionItems(this.data, key, "");
return {
index: currentIndex,
rows: parentRows,
$_prop_path: propPath,
};
},
}, },
});
const emit = defineEmits(["select"]);
const allSelection = ref([]);
const showSelectColumn = computed(() => {
return attrs && (attrs["selection-change"] || attrs["select"]);
}); // 是否显示选中列
const addSelectEvent = computed(() => {
return attrs && attrs["select"];
});
watch(
() => props.data,
() => {
recoverSelection();
}
);
const table = ref(null);
const recoverSelection = () => {
let selectionIds = allSelection.value.map((v) => v[props.rowKey]);
props.data.forEach((v) => {
if (selectionIds.indexOf(v[props.rowKey]) > -1) {
nextTick(() => {
table.value.toggleRowSelection(v, true);
});
}
});
}; // 恢复选中
const selectionChange = (selection) => {
if (!addSelectEvent.value) return; // 如果用户未监听select事件,则不执行
if (!props.rowKey) throw Error("监听select事件时,row-key必须传入!");
upAllSelection(selection);
emit("select", allSelection.value);
}; // select事件
const upAllSelection = (selection) => {
let rowIds = props.data.map((v) => v[props.rowKey]);
let allSelection1 = [...allSelection.value];
let selectionIds = allSelection1.map((v) => v[props.rowKey]);
// 首先把当前页的选中全部移除
selectionIds = selectionIds.filter((v) => rowIds.indexOf(v) === -1);
// allSelection仅保留selectionIds存在的
allSelection1 = allSelection1.filter((v) => selectionIds.indexOf(v[props.rowKey]) > -1);
// 然后再加入当前页的选中
allSelection1.push(...selection);
allSelection.value = allSelection1;
}; // 更新当前全部被选中的数据
const clearSelection = () => {
table.value.clearSelection();
allSelection.value = [];
}; // 清空选中
const getRowInfo = (row, key) => {
let currentIndex = -1;
let parentRows = null;
let propPath = "";
let childrenKey = props.treeProps.children;
let recursionItems = (items, prop) => {
for (let i = 0; i < items.length; i++) {
let item = items[i];
propPath += `${i}.`;
if (item[prop] === row[prop]) {
currentIndex = i;
parentRows = items;
break;
} else if (item[childrenKey] && item[childrenKey].length > 0) {
propPath += `${childrenKey}.`;
recursionItems(item[childrenKey], prop);
}
}
};
recursionItems(props.data, key, "");
return {
index: currentIndex,
rows: parentRows,
$_prop_path: propPath,
};
}; };
defineExpose({
getRowInfo,
})
</script> </script>
\ No newline at end of file
<template> <template>
<el-table <el-table
:height="height"
ref="table" ref="table"
class="bg-table" class="bg-table"
:data="rows" :data="rows"
...@@ -8,38 +9,33 @@ ...@@ -8,38 +9,33 @@
@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"
align="center"
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="indexWidth" align="left">
v-if="isIndex"
type="index"
:label="indexLabel"
width="54"
align="left"
>
<!-- 序号 --> <!-- 序号 -->
</el-table-column> </el-table-column>
<el-table-column v-if="sort" width="54" align="center">
<template v-slot:header>
<p style="width: 100%; text-align: center">排名</p>
</template>
<template v-slot:default="{ row,$index }">
<p style="width: 100%; text-align: center;display: flex;align-items: center;">
<bg-icon style="font-size: 12px; color: #429e8a;margin-right: 9px;" icon="#bg-ic-arrow-up-2" v-if="row.sort == 1" />
<bg-icon style="font-size: 12px; color: #d75138;margin-right: 9px;" icon="#bg-ic-arrow-down-2" v-else-if="row.sort == 2" />
<bg-icon style="font-size: 12px; color: #909bb6;margin-right: 9px;" icon="#bg-ic-minus" v-else />
<span>{{ $index + 1 }}</span>
</p>
</template>
</el-table-column>
<el-table-column <el-table-column
v-for="(header, index) in headers" v-for="(header, index) in headers"
:width="header.width" :width="header.width"
...@@ -47,8 +43,7 @@ ...@@ -47,8 +43,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}`" />
...@@ -59,137 +54,166 @@ ...@@ -59,137 +54,166 @@
<slot v-if="$slots[header.prop]" :name="header.prop" :row="row" /> <slot v-if="$slots[header.prop]" :name="header.prop" :row="row" />
<template v-else> <template v-else>
<col-node :val="row[header.prop]" :emptyColPlaceholder="emptyColPlaceholder"></col-node>
<!-- {{ row[header.prop] | ellipsis(header.max) }} --> <!-- {{ row[header.prop] | ellipsis(header.max) }} -->
{{ row[header.prop] }}
</template> </template>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</template> </template>
<script> <script setup>
import { selectTableMixin } from './hook/mixin-select-table' import { h, watch, ref } from "vue";
export default { import { selectTableMixin } from "./hook/mixin-select-table";
name: "BgTable", let { nowSelectData, allSelectData, selectData, initSelectTableData, runPage, dealSelectData } = selectTableMixin();
setup() {
const {
nowSelectData,
allSelectData,
selectData,
initSelectTableData,
runPage,
dealSelectData
} = selectTableMixin()
return { const props = defineProps({
nowSelectData, height: {
allSelectData, type: [Number, String],
selectData, default: "auto",
initSelectTableData,
runPage,
dealSelectData
}
}, },
props: { headers: {
headers: { type: Array,
type: Array, require: true,
require: true,
},
rows: {
type: Array,
default: () => [],
},
select: {
type: Boolean,
default: false,
},
selectable: {
type: Function,
},
isIndex: {
type: Boolean,
default: false
},
indexLabel: {
type: String,
default: "序号"
},
stripe: {
type: Boolean,
default: false
},
paddingLeft: {
type: [Number, String],
default: () => 33,
},
}, },
/* filters: { rows: {
ellipsis(value, max) { type: Array,
if (!value) { default: () => [],
return "";
} else if (max && value.length > max) {
return value.slice(0, max - 1) + "...";
} else {
return value;
}
},
}, */
watch:{
rows(n,o){
if(n.length&&this.select){
this.runPage()
this.initSelectTableData(n).then((selectData)=>{
if(selectData.length){
setTimeout(()=>{
this.toggleRowArrSelection(selectData)
})
}
})
}
}
}, },
created(){ select: {
console.log(this.$attrs) type: Boolean,
default: false,
}, },
methods: { // selectable: {
toggleRowSelection(row, flag = true) { // type: Function,
this.$refs.table.toggleRowSelection(row, flag); // },
}, isIndex: {
selectAction(selection) { type: Boolean,
this.$emit("selectAc", {allLength:Object.keys(this.allSelectData).length+this.nowSelectData.length,selection}); default: false,
}, },
clearSelection() { indexLabel: {
this.$refs.table.clearSelection(); type: String,
this.$emit("select", {allLength:Object.keys(this.allSelectData).length+this.nowSelectData.length,selection:[]}); default: "序号",
}, },
setSelectedRow(row) { stripe: {
this.$refs.table.toggleRowSelection(row); type: Boolean,
}, default: false,
toggleRowArrSelection(arr, flag = true){
arr.forEach(e => {
this.$refs.table.toggleRowSelection(e, flag);
});
},
selectActionRow(selection,row){
this.selectData(selection)
this.$emit("select", {allLength:Object.keys(this.allSelectData).length+this.nowSelectData.length,selection});
},
selectActionAll(selection){
this.selectData(selection)
this.$emit("select", {allLength:Object.keys(this.allSelectData).length+this.nowSelectData.length,selection});
},
clearTable(){//清除选中数据,在页面状态更新时使用
this.allSelectData={}
this.nowSelectData=[]
this.clearSelection();
},
tableRowClassName({ row, rowIndex }) {
if (rowIndex % 2 == 0) {
return "white-row";
} else {
return "stripe-row";
}
},
}, },
paddingLeft: {
type: [Number, String],
default: () => 12,
},
canEdit: {
type: Boolean,
default: false,
}, // 多选框是否禁用
canEditFlag: {
type: Boolean,
default: "",
}, // 决定多选框是否禁用的字段
sort: {
type: Boolean,
default: false,
}, // 排名
emptyColPlaceholder: {
type: [String, Function],
default: "-",
}, // 后端行数据某列为空时显示的占位符号
indexWidth: {
type: Number,
default: 54
}
});
const table = ref(null);
const emit = defineEmits(["selectAc", "select"]);
watch(
() => props.rows,
(n, o) => {
if (n.length && props.select) {
runPage();
initSelectTableData(n).then((selectData) => {
if (selectData.length) {
setTimeout(() => {
toggleRowArrSelection(selectData);
});
}
});
}
}
);
const toggleRowSelection = (row, flag = true) => {
table.value.toggleRowSelection(row, flag);
};
const selectAction = (selection) => {
emit("selectAc", { allLength: Object.keys(allSelectData).length + nowSelectData.length, selection });
};
const clearSelection = () => {
table.value.clearSelection();
emit("select", { allLength: Object.keys(allSelectData).length + nowSelectData.length, selection: [] });
};
const setSelectedRow = (row) => {
toggleRowSelection(row);
};
const toggleRowArrSelection = (arr, flag = true) => {
arr.forEach((e) => {
toggleRowSelection(e, flag);
});
};
const selectActionRow = (selection, row) => {
selectData(selection);
emit("select", { allLength: Object.keys(allSelectData).length + nowSelectData.length, selection });
};
const selectActionAll = (selection) => {
selectData(selection);
emit("select", { allLength: Object.keys(allSelectData).length + nowSelectData.length, selection });
}; };
const clearTable = () => {
//清除选中数据,在页面状态更新时使用
allSelectData = {};
nowSelectData = [];
clearSelection();
};
const tableRowClassName = ({ row, rowIndex }) => {
if (rowIndex % 2 == 0) {
return "white-row";
} else {
return "stripe-row";
}
};
const selectable = (row, index) => {
if (props.canEdit) {
if (row[props.canEditFlag] && row[props.canEditFlag] == 1) {
return false;
} else {
return true;
}
} else {
return true;
}
};
/**
* 该功能用于表格数据某行的列数据后端未处理返回空字符串的情况,前端展示需要灵活处理的解决方案;
* 改内部组件val参数为默认的原始数据,emptyColPlaceholder是自定义的类型
* 一般情况下默认空则渲染为占位符 "-"
* 当然也可以写渲染函数特殊处理此处,以满足特别需求,但是父组件传递的函数必须是渲染函数!
*/
const colNode = (props) => {
if (props.val === "") {
if (typeof props.emptyColPlaceholder === 'string') {
return h("span", props.emptyColPlaceholder);
}
if (typeof props.emptyColPlaceholder === 'function') {
return props.emptyColPlaceholder()
}
}
return h("span", props.val);
}
defineExpose({
clearTable,
toggleRowSelection,
});
</script> </script>
...@@ -26,51 +26,39 @@ ...@@ -26,51 +26,39 @@
</div> </div>
</template> </template>
<script> <script setup>
export default { import { reactive, ref, onBeforeMount, toRefs, provide, useSlots } from "vue";
name: "BgTabs",
provide() {
return {
getActiveName: () => {
return this.modelValue;
},
getIsTabs: () => {
return true;
},
};
},
props: {
modelValue: {
type: String,
default: '',
},
},
emits: ['update:modelValue'],
data() {
return {
isTabs: true,
};
},
methods: {
calcTabs() {
let tabSlots = [];
if (this.$slots.default) { const slots = useSlots();
tabSlots = this.$slots.default
.filter(
(vnode) =>
vnode.tag &&
vnode.componentOptions &&
vnode.componentOptions.Ctor.options.name === "BgTab"
)
.map((vnode) => vnode.componentOptions.propsData);
}
return tabSlots; const props = defineProps({
}, modelValue: {
changeActiveName({ name }) { type: String,
this.$emit("update:modelValue", name); default: "",
},
}, },
});
const getActiveName = provide("activeName", ()=>{return props.modelValue});
const getIsTabs = provide("isTabs", true);
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);
}
console.log(tabSlots)
return tabSlots;
};
const changeActiveName = ({ name }) => {
emit("update:modelValue", name);
}; };
</script> </script>
...@@ -10,67 +10,51 @@ ...@@ -10,67 +10,51 @@
</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"
size="mini"
@click="showInput = true"
v-if="!showInput"
>
新增
</el-button>
<el-input v-model.trim="newTag" @blur="addTag" v-else /> <el-input v-model.trim="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", type: String,
event: "change", default: "",
}, },
props: { disabled: {
value: { type: Boolean,
type: String, default: false,
default: "",
},
disabled: {
type: Boolean,
default: false,
},
}, },
data() { });
return {
newTag: "",
showInput: false,
};
},
computed: {
tags() {
return (this.value && this.value.split(",")) || [];
},
},
methods: {
deleteTag(index) {
let tags = [...this.tags];
tags.splice(index, 1); const emit = defineEmits(["update:modelValue"]);
this.$emit("change", tags.join(",")); const newTag = ref("");
}, const showInput = ref(false);
addTag() {
let tags = [...this.tags];
if (this.newTag) { const tags = computed(() => {
tags.push(this.newTag); return (props.modelValue && props.modelValue.split(",")) || [];
} });
this.$emit("change", tags.join(",")); const deleteTag = (index) => {
this.newTag = ""; let tags = [...tags.value];
this.showInput = false;
}, tags.splice(index, 1);
},
emit("update:modelValue", tags.join(","));
};
const addTag = () => {
let tags = [...tags.value];
if (newTag.value) {
tags.push(newTag.value);
}
emit("update:modelValue", tags.join(","));
newTag.value = "";
showInput.value = false;
}; };
</script> </script>
This diff is collapsed.
<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="{
...@@ -18,8 +15,7 @@ ...@@ -18,8 +15,7 @@
:disabled="actionDisabled" :disabled="actionDisabled"
style="max-width: 600px" style="max-width: 600px"
drag drag
multiple multiple>
>
<!-- <el-button type="primary"> <!-- <el-button type="primary">
上传附件 上传附件
</el-button> </el-button>
...@@ -28,11 +24,7 @@ ...@@ -28,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>
...@@ -50,7 +42,7 @@ ...@@ -50,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;line-height: 18px;"> <div class="el-upload__tip" style="color: #909bb6; line-height: 18px">
{{ otherInfo }} {{ otherInfo }}
</div> </div>
</template> </template>
...@@ -58,165 +50,138 @@ ...@@ -58,165 +50,138 @@
</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", modelValue: {
// }, type: Array,
props: { default: () => [],
modelValue: {
type: Array,
default: () => [],
},
fileTypes: {
type: Array,
default: () => [
"doc",
"docx",
"xls",
"xlsx",
"pdf",
"jpg",
"jpeg",
"png",
],
},
fileMaxSize: {
type: Number,
default: 20, // 单位:M
},
disabled: {
type: Boolean,
default: false,
},
refresh: {
type: Boolean,
default: false,
}, // 是否重新初始化附件(手动刷新组件的附件列表)
customTips: {
type: Boolean,
default: false,
}, // 是否自定义提示
isEasy: {
type: Boolean,
default: false,
},
triggerText: {
type: String,
default: "请上传",
},
triggerIcon: {
type: String,
default: "bg-ic-file",
},
otherInfo: {
type: String,
default: "",
},
limit: {
type: Number,
default: 9999,
},
}, },
emits: ["update:modelValue","change"], fileTypes: {
data() { type: Array,
return { default: () => ["doc", "docx", "xls", "xlsx", "pdf", "jpg", "jpeg", "png"],
fileList: [], },
}; fileMaxSize: {
type: Number,
default: 20, // 单位:M
}, },
computed: { disabled: {
actionDisabled() { type: Boolean,
return this.disabled default: false,
},
}, },
watch: { refresh: {
modelValue() { type: Boolean,
let newStr = this.modelValue.map((v) => v.url).join(","); default: false,
let oldStr = this.fileList }, // 是否重新初始化附件(手动刷新组件的附件列表)
.map((v) => (v.response && v.response.data) || v.url) customTips: {
.join(","); type: Boolean,
default: false,
if (newStr !== oldStr) { }, // 是否自定义提示
this.fileList = [...this.modelValue]; isEasy: {
} type: Boolean,
}, default: false,
}, },
methods: { triggerText: {
initFileList() { type: String,
let urls = (this.value && this.value.split(",")) || []; default: "请上传",
this.fileList = urls.map((url, index) => {
let temp = url.split("/");
let name = temp[temp.length - 1] || `附件_${index + 1}`;
return { name, url };
});
this.$emit("update:refresh", false);
},
handleBeforeUpload(file) {
if (this.fileList && this.fileList.length >= this.limit) {
this.$message.error(`只允许上传${this.limit}个文件`)
return false
}
let temp = file.name.split(".");
let type = temp[temp.length - 1].toLocaleLowerCase();
let fileTypesOk = this.fileTypes.indexOf(type) > -1||this.fileTypes.length==0;
let fileMaxSizeOk = file.size / 1024 / 1024 <= this.fileMaxSize;
if (!fileTypesOk) {
this.$message.error(
`上传文件只能是${this.fileTypes.join("")}这些格式!`
);
}
if (!fileMaxSizeOk) {
this.$message.error(`上传文件大小不能超过${this.fileMaxSize}M!`);
}
return fileTypesOk && fileMaxSizeOk;
},
handleExceed(file, fileList) {
console.log(file, fileList);
},
handlePreview(val) {
let a = document.createElement("a"); // 生成一个a元素
let event = new MouseEvent("click"); // 创建一个单击事件
a.download = val.name; // 设置图片名称
a.href = val.url || val.response.data; // 将生成的URL设置为a.href属性
a.dispatchEvent(event); // 触发a的单击事件
},
handleRemove(file, fileList) {
this.updateFileList(fileList);
},
handleSuccess(response, file, fileList) {
this.updateFileList(fileList);
},
updateFileList(fileList) {
let values = fileList.map((v) => {
return {
name: v.name,
url: (v.response && v.response.data) || v.url,
};
});
this.fileList = fileList;
this.$emit("update:modelValue", values);
this.$emit("change",values);
},
}, },
mounted() { triggerIcon: {
this.fileList = [...this.modelValue]; type: String,
default: "bg-ic-file",
}, },
otherInfo: {
type: String,
default: "",
},
limit: {
type: Number,
default: 9999,
},
});
const emit = defineEmits(["update:modelValue", "change"]);
const state = reactive({
fileList: [],
});
const actionDisabled = computed(() => {
return props.disabled;
});
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];
}
}
);
const handleBeforeUpload = (file) => {
if (state.fileList && state.fileList.length >= props.limit) {
ElMessage.error(`只允许上传${props.limit}个文件`);
return false;
}
let temp = file.name.split(".");
let type = temp[temp.length - 1].toLocaleLowerCase();
let fileTypesOk = props.fileTypes.indexOf(type) > -1 || props.fileTypes.length == 0;
let fileMaxSizeOk = file.size / 1024 / 1024 <= props.fileMaxSize;
if (!fileTypesOk) {
ElMessage.error(`上传文件只能是${props.fileTypes.join("")}这些格式!`);
}
if (!fileMaxSizeOk) {
ElMessage.error(`上传文件大小不能超过${props.fileMaxSize}M!`);
}
return fileTypesOk && fileMaxSizeOk;
};
const handleExceed = (file, fileList) => {
console.log(file, fileList);
};
const handlePreview = (val) => {
let a = document.createElement("a"); // 生成一个a元素
let event = new MouseEvent("click"); // 创建一个单击事件
a.download = val.name; // 设置图片名称
a.href = val.url || val.response.data; // 将生成的URL设置为a.href属性
a.dispatchEvent(event); // 触发a的单击事件
}; };
const handleRemove = (file, fileList) => {
updateFileList(fileList);
};
const handleSuccess = (response, file, fileList) => {
updateFileList(fileList);
};
const updateFileList = (fileList) => {
let values = fileList.map((v) => {
return {
name: v.name,
url: (v.response && v.response.data) || v.url,
};
});
state.fileList = fileList;
emit("update:modelValue", values);
emit("change", values);
};
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: {
modelValue: { const props = defineProps({
type: String, modelValue: {
default: "", type: String,
}, default: "",
disabled:{
type:Boolean,
default:false
}
}, },
emits: ['update:modelValue'], disabled: {
data(){ type: Boolean,
return{ default: false,
fileList:[]
}
}, },
created(){ });
}, const emit = defineEmits(["update:modelValue"]);
methods: {
handleAvatarSuccess({ data }) {
this.$emit("update:modelValue", data.visitURL);
},
beforeAvatarUpload(file) {
const isJPG = file.type === "image/jpeg" || file.type === "image/png";
const isLt1M = file.size / 1024 / 1024 < 1;
if (!isJPG) { const state = reactive({
this.$message.error("上传的图片只能是 JPG、PNG 格式!"); fileList: [],
} });
if (!isLt1M) {
this.$message.error("上传的图片大小不能超过 1MB!");
}
return isJPG && isLt1M; const handleAvatarSuccess = ({ data }) => {
}, emit("update:modelValue", data.visitURL);
onChangeFile(file, fileList){ };
console.log(file, fileList); const beforeAvatarUpload = (file) => {
if(!this.beforeAvatarUpload(file.raw)){ const isJPG = file.type === "image/jpeg" || file.type === "image/png";
return const isLt1M = file.size / 1024 / 1024 < 1;
}
var reader = new FileReader(); if (!isJPG) {
reader.readAsDataURL(file.raw); // 一定要传入file格式 ElMessage.error("上传的图片只能是 JPG、PNG 格式!");
reader.onload = () => { }
this.$emit("update:modelValue", reader.result); if (!isLt1M) {
}; ElMessage.error("上传的图片大小不能超过 1MB!");
} }
},
return isJPG && isLt1M;
}; };
const onChangeFile = (file, fileList) => {
console.log(file, fileList);
if (!beforeAvatarUpload(file.raw)) {
return;
}
var reader = new FileReader();
reader.readAsDataURL(file.raw); // 一定要传入file格式
reader.onload = () => {
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'
...@@ -34,6 +32,7 @@ ...@@ -34,6 +32,7 @@
import BgInnerTabs from './bg-inner-tabs.vue' import BgInnerTabs from './bg-inner-tabs.vue'
import BgFilterGroup from './bg-filter-group.vue' import BgFilterGroup from './bg-filter-group.vue'
import BgTableBtns from './bg-table-btns.vue' import BgTableBtns from './bg-table-btns.vue'
import BgTableBtns2 from './bg-table-btns2.vue'
const components = { const components = {
BgIcon,//字体图标 BgIcon,//字体图标
...@@ -49,8 +48,6 @@ const components = { ...@@ -49,8 +48,6 @@ const components = {
BgLayoutCard, // 带标题的卡片 BgLayoutCard, // 带标题的卡片
BgCard, // 详情卡片 BgCard, // 详情卡片
BgInfo, // 表格信息 BgInfo, // 表格信息
BgSteps, // 步骤条
BgStep, // 步骤条
BgBtns, // 按钮组 BgBtns, // 按钮组
BgUpload, // 上传附件 BgUpload, // 上传附件
BgUploadImage, // 上传单张图片 BgUploadImage, // 上传单张图片
...@@ -69,6 +66,7 @@ const components = { ...@@ -69,6 +66,7 @@ const components = {
BgInnerTabs,//内部tab BgInnerTabs,//内部tab
BgFilterGroup,//列表按钮及筛选 BgFilterGroup,//列表按钮及筛选
BgTableBtns,// 表格按钮组 BgTableBtns,// 表格按钮组
BgTableBtns2,
}; };
const install = (Vue) => { const install = (Vue) => {
......
...@@ -265,17 +265,17 @@ a { ...@@ -265,17 +265,17 @@ a {
padding: 0 10px; padding: 0 10px;
> * { > * {
height: 36px !important; height: 32px !important;
background-color: transparent !important; background-color: transparent !important;
font-size: 14px; font-size: 14px;
line-height: 36px !important; line-height: 32px !important;
color: #404a62; color: #404a62;
} }
> .el-pager > li { > .el-pager > li {
height: 36px !important; height: 32px !important;
background-color: transparent !important; background-color: transparent !important;
line-height: 36px !important; line-height: 32px !important;
color: #404a62 !important; color: #404a62 !important;
&.active { &.active {
...@@ -522,7 +522,7 @@ a { ...@@ -522,7 +522,7 @@ a {
} }
> .bg-nav-list { > .bg-nav-list {
height: calc(100% - 135px); height: calc(100% - 10px);
box-sizing: border-box; box-sizing: border-box;
ul.nav-list { ul.nav-list {
...@@ -644,17 +644,20 @@ a { ...@@ -644,17 +644,20 @@ a {
&::before { &::before {
display: none; display: none;
} }
.empty_container { .el-table__empty-block {
height: 500px; height: 500px!important;
padding-top: 247px; .empty_container {
img { height: 500px;
width: 257px; padding-top: 247px;
height: 145px; img {
} width: 257px;
.text { height: 145px;
font-size: 16px; }
color: #616f94; .text {
line-height: 1; font-size: 16px;
color: #616f94;
line-height: 1;
}
} }
} }
th, th,
...@@ -746,7 +749,7 @@ a { ...@@ -746,7 +749,7 @@ a {
max-width: 388px; max-width: 388px;
padding: 15px 12px; padding: 15px 12px;
color: #202531; color: #202531;
box-shadow: 0px 4px 12px 0px box-shadow: 0px 4px 12px 0px
rgba(18, 30, 63, 0.1); rgba(18, 30, 63, 0.1);
border: solid 1px #e6e9ef; border: solid 1px #e6e9ef;
font-size: 14px; font-size: 14px;
...@@ -760,12 +763,26 @@ a { ...@@ -760,12 +763,26 @@ a {
> .cell { > .cell {
padding: 0 10px !important; padding: 0 10px !important;
overflow: unset; overflow: unset;
display: flex; display: flex!important;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
} }
} }
.el-table-column--selection{
border-left: 1px solid #e6e9ef;
> .cell {
justify-content: center
}
}
th.el-table-column--selection{
> .cell {
display: flex;
justify-content: center
}
}
&.el-table--border { &.el-table--border {
...@@ -804,7 +821,12 @@ a { ...@@ -804,7 +821,12 @@ a {
display: inline; display: inline;
color: #3759be; color: #3759be;
cursor: pointer; cursor: pointer;
&:hover {
color: #738bd2
}
&:active {
color: #2c4798;
}
&.disabled { &.disabled {
cursor: not-allowed; cursor: not-allowed;
color: #a9b1c7; color: #a9b1c7;
...@@ -1495,7 +1517,7 @@ a { ...@@ -1495,7 +1517,7 @@ a {
border-left: 1px solid #e3e5ef; border-left: 1px solid #e3e5ef;
color: #404a62; color: #404a62;
position: relative; position: relative;
> .copy-btn { > .copy-btn {
position: absolute; position: absolute;
top: 50%; top: 50%;
...@@ -1512,6 +1534,16 @@ a { ...@@ -1512,6 +1534,16 @@ a {
color: #2b4695; color: #2b4695;
} }
} }
> .copy-btn-dis {
color: #dce0e8;
cursor: not-allowed!important;
&:hover {
color: #dce0e8;
}
&:active {
color: #dce0e8;
}
}
} }
} }
...@@ -1819,7 +1851,7 @@ a { ...@@ -1819,7 +1851,7 @@ a {
> .el-upload-list { > .el-upload-list {
margin: 0 0 0 16px; margin: 0 0 0 16px;
> .el-upload-list__item { > .el-upload-list__item {
margin: 0; margin: 0;
...@@ -2337,6 +2369,9 @@ a { ...@@ -2337,6 +2369,9 @@ a {
height: 32px; height: 32px;
margin-top: 16px; margin-top: 16px;
float: right; float: right;
.el-input {
--el-input-height: 32px;
}
.el-pagination { .el-pagination {
text-align: center; text-align: center;
margin: 0 auto; margin: 0 auto;
...@@ -2356,7 +2391,7 @@ a { ...@@ -2356,7 +2391,7 @@ a {
li:hover { li:hover {
color: #3759be; color: #3759be;
} }
} }
.el-input__wrapper { .el-input__wrapper {
background-color: #fff; background-color: #fff;
} }
...@@ -2373,14 +2408,20 @@ a { ...@@ -2373,14 +2408,20 @@ a {
.bg-card { .bg-card {
background-color: #ffffff; background-color: #ffffff;
box-shadow: 0px 1px 4px 0px box-shadow: 0px 1px 4px 0px
rgba(0, 7, 101, 0.15); rgba(0, 7, 101, 0.15);
border-radius: 6px; border-radius: 6px;
margin-bottom: 16px; margin-bottom: 16px;
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #ebedf2;
}
.card-title { .card-title {
padding: 16px 16px; padding: 16px 16px;
border-bottom: 1px solid #ebedf2;
font-weight: bold; font-weight: bold;
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
...@@ -2517,7 +2558,7 @@ a { ...@@ -2517,7 +2558,7 @@ a {
background-color: #f2f3f7; background-color: #f2f3f7;
color: #202531; color: #202531;
} }
&.disabled { &.disabled {
color: #a9b1c7; color: #a9b1c7;
} }
...@@ -2534,4 +2575,4 @@ a { ...@@ -2534,4 +2575,4 @@ a {
height: 10px; height: 10px;
width: 100%; width: 100%;
} }
} }
\ No newline at end of file
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