Browse Source

Merge pull request 'zq-0828-newMenu' (#120) from zq-0828-newMenu into master

Reviewed-on: #120
master
zhangqi 8 hours ago
parent
commit
9982d3edf0
  1. 251
      src/components/Tooltip.vue
  2. 18
      src/main.js
  3. 49
      src/utils/tooltip.js
  4. 57
      src/views/elementGroups.vue
  5. 18
      src/views/super/Ranking/RankBatchList.vue
  6. 2
      src/views/super/Ranking/RankList.vue

251
src/components/Tooltip.vue

@ -1,9 +1,8 @@
<template>
<template>
<transition name="fade">
<div v-if="visible" :class="['position-message', type, position]" id="qq" :style="positionStyle">
<!-- <i :class="iconClass"></i>/ -->
<div v-if="visible" :class="['position-message', type, position]" :style="positionStyle">
<img :src="defaultImages[type]" class="message-image" />
<span>{{ message }}</span>
<span>{{ currentMessage }}</span>
</div>
</transition>
</template>
@ -14,7 +13,7 @@ export default {
type: {
type: String,
default: 'info',
validator: val => ['info', 'success', 'error'].includes(val)
validator: val => ['info', 'success', 'error', 'warning'].includes(val)
},
position: {
type: String,
@ -22,22 +21,37 @@ export default {
validator: val => ['top', 'bottom'].includes(val)
},
message: String,
target: null, // /DOM
target: null,
offset: {
type: Number,
default: 10
},
duration: {
type: Number,
default: 2000
}
},
data() {
return {
visible: false,
positionStyle: {},
defaultImages:{
currentMessage: this.message, // 使message
defaultImages: {
success: require('@/assets/message_Success.png'),
info: require('@/assets/message_Warning.png'),
warning: require('@/assets/message_Warning.png'),
error: require('@/assets/message_error.png')
}
},
timer: null
}
},
watch: {
// propsmessage
message(newVal) {
this.currentMessage = newVal;
this.$nextTick(() => {
this.calculatePosition();
});
}
},
computed: {
@ -53,15 +67,67 @@ export default {
show() {
this.visible = true
this.$nextTick(() => {
this.calculatePosition(); // DOM
this.calculatePosition();
// duration0
if (this.duration > 0) {
this.clearTimer();
this.timer = setTimeout(() => {
this.hide();
}, this.duration);
}
});
console.log('zoulma???????', this.visible);
return this //
return this;
},
hide() {
this.visible = false
this.visible = false;
this.clearTimer();
return this;
},
updateMessage(newMessage) {
this.currentMessage = newMessage;
this.$nextTick(() => {
this.calculatePosition();
});
return this;
},
updateConfig(newConfig) {
//
if (newConfig.message !== undefined) {
this.currentMessage = newConfig.message;
}
if (newConfig.type) {
this.$emit('update:type', newConfig.type);
}
if (newConfig.position) {
this.$emit('update:position', newConfig.position);
}
this.$nextTick(() => {
this.calculatePosition();
});
return this;
},
destroy() {
this.hide();
// DOM
setTimeout(() => {
if (this.$el && this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el);
}
this.$destroy();
}, 300);
},
clearTimer() {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
},
calculatePosition() {
if (!this.$el || !this.visible) return;
const targetEl = typeof this.target === 'string'
? document.querySelector(this.target)
: this.target?.$el || this.target;
@ -75,28 +141,43 @@ export default {
const messageWidth = this.$el.offsetWidth;
const viewportWidth = window.innerWidth;
const messageHeight = this.$el.offsetHeight;
const scrollY = window.scrollY || window.pageYOffset;
//
let left = targetRect.left + targetRect.width / 2 - messageWidth / 2;
let top = 0;
//
if (left < 0) {
left = targetRect.left; //
} else if (left + messageWidth > viewportWidth) {
left = viewportWidth - messageWidth - (viewportWidth -targetRect.right); //
if (left < 5) {
left = 5; //
} else if (left + messageWidth > viewportWidth - 5) {
left = viewportWidth - messageWidth - 5; //
}
if(this.position == 'top'){
top =`${targetRect.top + window.scrollY - this.offset - messageHeight}px`
}else{
top = `${targetRect.top + window.scrollY + this.offset + messageHeight}px`
if (this.position === 'top') {
top = targetRect.top + scrollY - this.offset - messageHeight;
//
if (top < scrollY) {
top = targetRect.bottom + scrollY + this.offset;
}
} else {
top = targetRect.bottom + scrollY + this.offset;
//
if (top + messageHeight > scrollY + window.innerHeight) {
top = targetRect.top + scrollY - this.offset - messageHeight;
}
}
this.positionStyle = {
top,
top: `${top}px`,
left: `${left}px`,
right: 'auto', // right
right: 'auto'
};
},
},
beforeDestroy() {
this.clearTimer();
}
}
</script>
@ -112,133 +193,29 @@ export default {
background: #FFFFFF;
box-sizing: border-box;
box-shadow: 0px 3px 8px 0px rgba(0, 0, 0, 0.16);
span{
pointer-events: none;
span {
letter-spacing: 0.08em;
color: #626573;
white-space: nowrap;
}
}
.message-image {
width: 18px;
height: 18px;
margin-right: 10px;
}
.position-message i {
margin-right: 6px;
font-size: 16px;
}
.position-message.info {
/* background-color: #f4f4f5;
color: #909399;
border: 1px solid #e9e9eb; */
}
.position-message.success {
/* background-color: #f0f9eb;
color: #67c23a;
border: 1px solid #e1f3d8; */
}
.position-message.error {
/* background-color: #fef0f0;
color: #f56c6c;
border: 1px solid #fde2e2; */
width: 18px;
height: 18px;
margin-right: 10px;
flex-shrink: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s;
transition: opacity 0.3s, transform 0.3s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
transform: translateY(-10px);
}
</style>
<!-- <template>
<transition name="fade">
<div
v-if="visible"
:class="['position-message', type]"
:style="positionStyle"
>
<i :class="iconClass"></i>
<span>{{ message }}</span>
</div>
</transition>
</template>
<script>
export default {
computed: {
iconClass() {
return {
info: 'el-icon-info',
success: 'el-icon-success',
error: 'el-icon-error'
}[this.type]
}
},
props: {
type: {
type: String,
default: 'info',
validator: val => ['info', 'success', 'error'].includes(val)
},
position: {
type: String,
default: 'top',
validator: val => ['top', 'bottom'].includes(val)
},
message: String,
target: null, // /DOM
offset: {
type: Number,
default: 5
}
},
data() {
return {
visible: false,
positionStyle: {}
}
},
methods: {
hide() {
this.visible = false
},
calculatePosition() {
const targetEl = typeof this.target === 'string'
? document.querySelector(this.target)
: this.target?.$el || this.target;
if (!targetEl?.getBoundingClientRect) {
console.error('Invalid target:', this.target);
return;
}
const targetRect = targetEl.getBoundingClientRect();
const messageWidth = this.$el.offsetWidth;
if (this.position === 'bottom') {
this.positionStyle = {
top: `${targetRect.bottom + window.scrollY + this.offset}px`,
left: `${targetRect.left + targetRect.width / 2 - messageWidth / 2}px`,
};
} else {
//
this.positionStyle = {
top: `${targetRect.top + window.scrollY - this.offset - this.$el.offsetHeight}px`,
left: `${targetRect.left + targetRect.width / 2 - messageWidth / 2}px`,
};
}
},
show() {
this.visible = true;
this.$nextTick(this.calculatePosition);
return this;
},
},
};
</script> -->
</style>

18
src/main.js

@ -46,10 +46,28 @@ function filterByPermission(data, targetPermission) {
return newItem;
});
}
//金额千分符 会在整数后添加两个0 --适用于直接显示的
function stateFormat(row, column, cellValue) {
if (cellValue) {
return Number(cellValue)
.toFixed(2)
.replace(/(\d)(?=(\d{3})+\.)/g, ($0, $1) => {
return $1 + ",";
})
.replace(/\.$/, "");
}
}
//金额千分符 自定义渲染表格内容情况下,调用此方法
function formatNumber(value) {
if (value === null || value === undefined) return '';
return Number(value).toLocaleString();
}
Vue.prototype.$routerBaseApi = 'http://admin.pengda.checkcopy.com';
// 复制
Vue.prototype.$copy = modernCopyToClipboard;
Vue.prototype.$filterByPermission = filterByPermission;
Vue.prototype.$stateFormat = stateFormat;
Vue.prototype.$formatNumber = formatNumber;
Vue.prototype.$loadingFn = LoadingService;
Vue.config.productionTip = false;
// 请求

49
src/utils/tooltip.js

@ -3,31 +3,56 @@ import Tooltip from '@/components/Tooltip.vue'
const PositionMessageConstructor = Vue.extend(Tooltip)
// 自动隐藏功能扩展
// 存储实例引用,便于全局控制
const instances = []
function showMessage(options) {
const instance = new PositionMessageConstructor({
propsData: options
propsData: options
}).$mount()
document.body.appendChild(instance.$el)
instances.push(instance)
const showInstance = instance.show()
// 添加自动隐藏
// 添加自动隐藏(duration为0表示一直显示)
if (options.duration !== 0) {
setTimeout(() => {
showInstance.hide()
const duration = options.duration || 2000
setTimeout(() => {
document.body.removeChild(instance.$el)
}, 300) // 等待动画结束
}, options.duration || 2000)
instance.hide()
setTimeout(() => {
if (instance.$el && instance.$el.parentNode) {
instance.$el.parentNode.removeChild(instance.$el)
}
// 从实例数组中移除
const index = instances.indexOf(instance)
if (index > -1) {
instances.splice(index, 1)
}
}, 300) // 等待动画结束
}, duration)
}
return showInstance
}
}
// 隐藏所有tooltip
function hideAll() {
instances.forEach(instance => {
instance.hide()
setTimeout(() => {
if (instance.$el && instance.$el.parentNode) {
instance.$el.parentNode.removeChild(instance.$el)
}
}, 300)
})
instances.length = 0
}
export default {
install(Vue) {
Vue.prototype.$positionMessage = showMessage
}
install(Vue) {
Vue.prototype.$positionMessage = showMessage
Vue.prototype.$hideAllPositionMessages = hideAll
}
}

57
src/views/elementGroups.vue

@ -74,11 +74,17 @@
@change="radioChange" :rules="rules.language" label-key="name" :disabledKeys="['1']"
value-key="id" />
</div>
<div class="ele-item">
<label for="">数组套对象类型下拉框</label>
<!-- :extraItem="{label:'全部',value:'99999'}" 传入必须是 labelvalue 组件内会自动改为自定义的 labelKeyvalueKey-->
<div class="flex">
<GuipSelect width="150px" v-model="form.card" clearable label="卡片" :default-value="form.card" @change="selectChangeTest"
prop="card" :options="options" valueKey="id1" labelKey="id2" :extraItem="{label:'全部',value:'99999'}"/>
<p>j卢卡斯就到啦</p>
<GuipInput ref="GuipInput" v-model="form.input2" :maxlength="100" @change="handleInput"
@blur="handleInput" prop="input2" @input="handleInput" @focus="handleInput" placeholder="这是自定义默认提示语" />
</div>
</div>
<div class="ele-item">
<label for="">纯数组[1,2]下拉框</label>
@ -90,12 +96,12 @@
<GuipSelect width="150px" v-model="form.card1" clearable label="卡片" :default-value="form.card" @change="selectChangeTest"
prop="card" :options="languageOptions"/>
</div>
<el-button type="primary" @click="submitForm">Submit</el-button>
<div>
<h3 for="">表格(表头自定义自定义渲染固定列)</h3>
<GuipButton type="primary" @click="toggleAllSelection">全选按钮</GuipButton>
<GuipTable :tableData="[{payment:0}]" ref="multipleTable" @selectChange="handleSelectionChange"
<GuipTable :tableData="[{payment:0,name2:10008.9}]" ref="multipleTable" @selectChange="handleSelectionChange"
:multiple="true" autoColumn="true" :loading="tableLoading">
<!-- <template slot="header"> -->
<el-table-column width="180" fixed="left" label="名称(固定左)"></el-table-column>
@ -132,7 +138,7 @@
</template>
</el-table-column>
<el-table-column prop="name2" label="姓名" width="150"></el-table-column>
<el-table-column prop="name2" label="姓名" width="150" :formatter="$stateFormat"></el-table-column>
<el-table-column prop="statu" label="价格" width="150">
<template slot-scope="scope">
<GuipSwitch v-model="scope.row.statu" activeText="默认类型boolean" inactiveText="关闭" :active-value="1" :inactive-value="0"
@ -237,6 +243,7 @@
</GuipInput>
<!-- <el-input placeholder="oieuwroieuwi" style="width:400px;height:60px"></el-input> -->
</div>
<div class="ele-item">
<label for="">单选框</label>
<el-radio v-model="radio1" :label="1">选项一</el-radio>
@ -494,7 +501,6 @@
</CustomDropdown>
</div>
<el-button type="primary" @click="submitForm">Submit</el-button>
</el-form>
<div style="width: 100%;margin: 20px 0;height: 20px;background-color: antiquewhite;">
@ -523,12 +529,18 @@
<el-button @click="save" type="primary">保存</el-button>
</div> -->
</div>
<div class="flex ele-item">
<div class="flex ele-item gap10" style="flex-wrap: wrap;">
<label for="">一些功能集合</label>
<GuipButton type="primary" ref="button1" :btnstyle="{ width: '300px' }" @click="openDialog3('button1','bottom')">下方弹出消息提示
</GuipButton>
<GuipButton type="primary" ref="button2" :btnstyle="{ width: '300px' }" @click="openDialog3('button2','top')">上方弹出消息提示
</GuipButton>
<GuipButton type="primary" ref="button3" :btnstyle="{ width: '300px' }" @click="openDialog4('button3','top')">一直显示消息提示
</GuipButton>
<GuipButton type="primary" ref="button5" :btnstyle="{ width: '300px' }" @click="openDialog5">动态更改提示文案
</GuipButton>
<GuipButton type="primary" :btnstyle="{ width: '300px' }" @click="openDialog6">主动隐藏消息提示
</GuipButton>
<GuipButton type="primary" :btnstyle="{ width: '300px' }" @click="openDialog">打开弹框标题巨左按钮居右
</GuipButton>
<GuipButton type="primary" :btnstyle="{ width: '300px' }" @click="openDialog1">打开弹框标题巨中按钮居中
@ -744,9 +756,12 @@ export default {
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' }
],
input2: [
{ required: true, message: '请输入手机号', trigger: 'blur' }
],
age: [
{ required: true, message: '请输入年龄', trigger: 'blur' }
]
],
},
usernameRules: [{ required: true, message: 'Username is required', trigger: 'blur' }],//rules
msg: "测试",
@ -940,7 +955,6 @@ export default {
height: '50px'
},
plain: false,
options: [{
value: '选项1',
label1: '黄金hhhhhh',
@ -972,6 +986,8 @@ export default {
label1: '双皮奶hhhhhhhhh',
label: '北京烤鸭'
}],
tooltip:null
}
},
mounted() {
@ -1162,15 +1178,40 @@ export default {
openDialog2() {
this.dialogVisible2 = true;
// // tooltip
// this.tooltip.destroy()
// // tooltip
// this.$hideAllPositionMessages()
},
openDialog6(){
this.tooltip.hide()
},
openDialog3(el,pos){
// type
this.$positionMessage({
duration:3000,
type: 'success',
message: '操作成功',
target: this.$refs[el], // DOM
position: pos // 'bottom'
}) // 3
console.log(this.tooltip,'tooltip',el,pos);
},
openDialog4(el){
//
this.tooltip = this.$positionMessage({
type: 'info',
message: '这个提示会一直显示',
target: this.$refs[el],
duration: 0 // 0
})
},
openDialog5(){
this.tooltip.updateMessage('更新后的文本内容----')
},
//
handleConfirm() {

18
src/views/super/Ranking/RankBatchList.vue

@ -26,7 +26,7 @@
<GuipTable :tableData="tableData" style="width: 100%" :border="true" @sort-change="handleSortChange"
:loading="loading" @cell-mouse-enter="handleRowHover">
<el-table-column fixed="left" prop="sort" label="排序" width="70"></el-table-column>
<el-table-column
<el-table-column fixed="left"
v-if="(dataRank == 1 || dataRank == 2) && (dataType == 'ver_type' || dataType == 'check_type')"
prop="name" :key="selectedType" :label="type_select[selectedType]" min-width="120">
@ -44,7 +44,7 @@
</template>
</el-table-column>
<el-table-column v-else prop="name" :label="type_desc[dataType]" width="150"></el-table-column>
<el-table-column v-else fixed="left" prop="name" :label="type_desc[dataType]" width="150"></el-table-column>
<el-table-column v-for="(field, index) in valueFields" :key="field" :label="labels[index]"
:prop="String(index + 1)"
@ -53,9 +53,6 @@
<!--产品利润排行展示查看更多-->
<template v-if="index == 3 && dataRank == 1" v-slot="{ row, $index }">
<!-- <el-popover v-model="row.id_popover" placement="top" trigger="manual"
:ref="`popover-${$index}`" :append-to-body="false" :visible-arrow="true"
popper-class="custom-popover" @show="popshow"> -->
<el-popover v-model="row.id_popover" :ref="`popover-${row.id}`"
placement="bottom" trigger="manual" :append-to-body="false" :visible-arrow="true"
popper-class="custom-popover" @show="popshow" >
@ -116,7 +113,8 @@
</div>
<div class="flex" slot="reference">
{{ row[field] }}
<!-- {{ row[field] }} -->
{{ $formatNumber(row[field]) }}
<svg-icon :size="14" v-if="row[field] *100 != 0"
:path="require('@/assets/super/list-detail.svg')" :color="'#8A9099'"
:hoverColor="'#006AFF'" @click="handleClick(row, $index, 'id')" />
@ -126,7 +124,7 @@
</template>
<template v-else slot-scope="scope">
<div class="flex">
{{ scope.row[field] }}
{{ $formatNumber(scope.row[field]) }}
</div>
</template>
</el-table-column>
@ -134,7 +132,7 @@
<!--产品利润排行展示代理商排行-->
<el-table-column v-if="dataRank == 1 && (dataType == 'ver_type' || dataType == 'check_type')"
:render-header=" (h, scope) => renderHeaderWithIcon(h, scope, require('@/assets/require.svg')) "
key="top" prop="top" label="代理商排行" width="250" fixed="right">
key="top" prop="top" label="代理商排行" width="250">
<template v-slot="{ row, $index }">
<!-- :fallback-placements="['bottom','top','left']" -->
<el-popover v-model="row.id_popover_2" :ref="`popover_2-${$index}`"
@ -233,7 +231,7 @@ export default {
'ver_type': '按品牌名称',
'check_type': '按服务名称',
},
selectedType: 'check_type',
selectedType: 'ver_type',
view: 'month',
labels: ['', '', '', ''],
current_month: '',
@ -609,6 +607,7 @@ export default {
</script>
<style scoped lang="scss">
.pagetitle {
margin-bottom: 12px;
h4 {
margin-bottom: 0;
}
@ -628,7 +627,6 @@ export default {
}
.beforeNotice {
margin-top: 12px;
border-radius: 4px;
background: #F2F7FF;
border: 1px solid #BFDAFF;

2
src/views/super/Ranking/RankList.vue

@ -268,7 +268,7 @@ export default {
'ver_type': '按品牌名称',
'check_type': '按服务名称',
},
selectedType: 'check_type',
selectedType: 'ver_type',
viewDesc: {
'month': '月份',
'monthTwo': '月份',

Loading…
Cancel
Save