Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2eba5f0140 | ||
|
|
1dacb5a705 | ||
| 99b2cc369d | |||
|
|
0e48245381 | ||
|
|
83a8974dc5 | ||
|
|
76443e343c | ||
| c5fdbd6a27 | |||
| ace17a95dd | |||
| 2125269c6c | |||
|
|
1373b56b94 | ||
|
|
23f4390a9b | ||
|
|
1f08afd8d3 | ||
|
|
c64012e4ea | ||
|
|
cffdd0f7ba | ||
| 1ba1186ee2 | |||
| a869e62351 | |||
| 458ac46ca4 | |||
|
|
8ec6582ffc | ||
|
|
7110ba358c | ||
| b6fcf5c32b | |||
|
|
5cce73902d | ||
|
|
25db88333d | ||
|
|
ddb542d89b | ||
|
|
01e9657d49 | ||
| 01f15d8352 | |||
|
|
da7d02474f | ||
|
|
9fbbd17e1f | ||
|
|
f1b3cb854f | ||
|
|
5b39799d01 | ||
| 291ab91c99 | |||
| 4c68830fb7 | |||
|
|
996d0a5ba5 | ||
|
|
56be3971e4 | ||
|
|
1ed8a1e76d | ||
|
|
45f85ee6e8 | ||
|
|
13e436bbb5 |
@@ -5,5 +5,7 @@ const prodEnv = require('./prod.env')
|
||||
module.exports = merge(prodEnv, {
|
||||
NODE_ENV: '"development"',
|
||||
BASE_API: '"http://127.0.0.1:48090"'
|
||||
|
||||
// BASE_API: '"http://192.168.1.241:8080/prod-api"'
|
||||
|
||||
})
|
||||
|
||||
@@ -8,6 +8,14 @@ export function login (data) {
|
||||
})
|
||||
}
|
||||
|
||||
export function logincas (data) {
|
||||
return request({
|
||||
url: 'accessUser/logincas',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function logout () {
|
||||
return request({
|
||||
url: 'accessUser/logout',
|
||||
@@ -15,6 +23,18 @@ export function logout () {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export function outlogcas (data) {
|
||||
console.log(data)
|
||||
return request({
|
||||
url: 'accessUser/outlogcas',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 登录之后 根据旧修改密码
|
||||
export function reqUpdatePassword (data) {
|
||||
return request({
|
||||
|
||||
@@ -271,7 +271,6 @@ export default {
|
||||
return { top: top, left: left }
|
||||
},
|
||||
objToOne(obj) {
|
||||
console.log(obj)
|
||||
let tmpData = {}
|
||||
for (let index in obj) {
|
||||
if (typeof obj[index] == 'object' && !this.isArrayFn(obj[index])) {
|
||||
|
||||
@@ -6,7 +6,6 @@ export default router
|
||||
const whiteList = ['/login', '/aj/**', '/el/**', '/bigscreen/viewer', '/excelreport/viewer']
|
||||
// 判断是否需要登录权限 以及是否登录
|
||||
router.beforeEach((to, from, next) => {
|
||||
|
||||
NProgress.start()
|
||||
let token = getToken();
|
||||
let lideeUser = getAccessUser();
|
||||
@@ -18,6 +17,7 @@ router.beforeEach((to, from, next) => {
|
||||
next()
|
||||
}
|
||||
}else {
|
||||
|
||||
if (whiteList.includes(to.path)) {
|
||||
next()
|
||||
}else {
|
||||
|
||||
@@ -250,7 +250,8 @@ export const constantRouterMap = [
|
||||
component: () => import('@/views/bigscreenDesigner/viewer'),
|
||||
hidden: true,
|
||||
meta: {
|
||||
requireAuth: true
|
||||
requireAuth: true,
|
||||
keepAlive: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -32,6 +32,7 @@ const user = {
|
||||
const repCode = response.repCode
|
||||
const repData = response.repData
|
||||
if (repCode === '0000') {
|
||||
|
||||
commit('SET_TOKEN', repData.token)
|
||||
commit('SET_ACCESSUSER', repData.accessUser)
|
||||
resolve(response)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import axios from 'axios'
|
||||
import { Message, MessageBox } from 'element-ui'
|
||||
import router from '../router'
|
||||
import store from '../store'
|
||||
import { getToken } from '@/utils/auth'
|
||||
// 创建axios实例
|
||||
@@ -41,7 +42,13 @@ service.interceptors.response.use(
|
||||
// sessionStorage.clear()
|
||||
// localStorage.clear()
|
||||
localStorage.removeItem('AJReportToken')
|
||||
window.location.href = "/";
|
||||
router.push({
|
||||
path: '/login',
|
||||
query: {
|
||||
redirect: location.hash.substring(1)
|
||||
}
|
||||
})
|
||||
// window.location.href = "/index?redirect=" + location.hash.substring(1);
|
||||
})
|
||||
}
|
||||
else if (res.code !== '200') {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,8 +13,10 @@
|
||||
<el-form-item
|
||||
v-if="
|
||||
inputShow[item.name] &&
|
||||
item.type != 'el-collapse'&&
|
||||
item.type != 'dycustComponents' &&
|
||||
item.type != 'dynamic-add-table'
|
||||
item.type != 'dynamic-add-table'&&
|
||||
(item.name != 'is_drill_drown' || hideDrill === false)
|
||||
"
|
||||
:label="item.label"
|
||||
:prop="item.name"
|
||||
@@ -155,7 +157,7 @@
|
||||
<el-button type="primary" @click="saveData">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
|
||||
<el-dialog
|
||||
title="代码编辑"
|
||||
:visible.sync="methodsVisible"
|
||||
@@ -173,6 +175,15 @@
|
||||
</span>
|
||||
</el-dialog>
|
||||
</el-form-item>
|
||||
<el-collapse v-if="inputShow[item.name] && item.type === 'el-collapse'">
|
||||
<el-collapse-item
|
||||
class="collapseItem1"
|
||||
:title="item.label"
|
||||
@click.prevent.native="handleCollapse"
|
||||
:name="item.label"
|
||||
>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
<dynamicComponents
|
||||
v-if="item.type == 'dycustComponents' && inputShow[item.name]"
|
||||
v-model="formData[item.name]"
|
||||
@@ -336,6 +347,7 @@
|
||||
<script>
|
||||
import ColorPicker from "./colorPicker.vue";
|
||||
import vueJsonEditor from "vue-json-editor";
|
||||
|
||||
import "codemirror/lib/codemirror.css"; // 核心样式
|
||||
import "codemirror/theme/cobalt.css"; // 引入主题后还需要在 options 中指定主题才会生效
|
||||
// language
|
||||
@@ -354,7 +366,7 @@ import componentLinkage from './componentLinkage';
|
||||
import imageSelect from './imageSelect';
|
||||
import multiIframeManager from './multiIframeManager.vue';
|
||||
export default {
|
||||
name: "DynamicForm",
|
||||
name: "dynamic-form",
|
||||
components: {
|
||||
imageSelect,
|
||||
ColorPicker,
|
||||
@@ -390,6 +402,10 @@ export default {
|
||||
widgetIndex: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
hideDrill:{
|
||||
type: Boolean,
|
||||
default:false,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -399,6 +415,8 @@ export default {
|
||||
dialogVisibleStaticData: false,
|
||||
methodsVisible: false,
|
||||
validationRules: "",
|
||||
|
||||
|
||||
optionsJavascript: {
|
||||
mode: "text/javascript",
|
||||
tabSize: 2, // 缩进格式
|
||||
@@ -416,6 +434,7 @@ export default {
|
||||
value(newValue, oldValue) {
|
||||
this.formData = newValue || {};
|
||||
},
|
||||
|
||||
options(val) {
|
||||
this.setDefaultValue();
|
||||
this.isShowData();
|
||||
@@ -427,6 +446,12 @@ export default {
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
handleCollapse(){
|
||||
this.$emit('handleCollapse',this.formData)
|
||||
},
|
||||
changeDrillData(val){
|
||||
this.changed(val, 'drill_drown_setting')
|
||||
},
|
||||
onJsonChange(val) {
|
||||
console.log(val);
|
||||
},
|
||||
@@ -442,7 +467,6 @@ export default {
|
||||
} else {
|
||||
this.$set(this.formData, key, val);
|
||||
}
|
||||
|
||||
this.$emit("onChanged", this.formData);
|
||||
// key为当前用户操作的表单组件
|
||||
for (let i = 0; i < this.options.length; i++) {
|
||||
@@ -465,6 +489,7 @@ export default {
|
||||
handleClose() {
|
||||
this.dialogVisibleStaticData = false;
|
||||
this.methodsVisible = false;
|
||||
|
||||
},
|
||||
// 组件属性 数据是否展示动态还是静态数据
|
||||
isShowData() {
|
||||
@@ -480,8 +505,10 @@ export default {
|
||||
}
|
||||
}
|
||||
data.forEach((el) => {
|
||||
if (el.relactiveDomValue != currentData.value) {
|
||||
if (el.relactiveDomValue != currentData.value&&el.name!=='drill_drown_setting') {
|
||||
this.inputShow[el.name] = false;
|
||||
}else if(el.name==='drill_drown_setting'){
|
||||
this.inputShow[el.name] = el.relactiveDomValue == this.formData[el.relactiveDom];
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -494,6 +521,7 @@ export default {
|
||||
this.formData[this.options[i].name] = this.deepClone(
|
||||
this.options[i].value
|
||||
);
|
||||
|
||||
} else if (Object.prototype.toString.call(obj) == "[object Array]") {
|
||||
for (let j = 0; j < obj.length; j++) {
|
||||
const list = obj[j].list;
|
||||
@@ -515,6 +543,12 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.dialogDrillDrown.el-dialog__wrapper .el-dialog{
|
||||
.el-dialog__body{
|
||||
max-height:calc(100vh - 60px) !important;
|
||||
overflow-y:hidden !important;
|
||||
}
|
||||
}
|
||||
.el-form-item {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
@@ -547,4 +581,9 @@ export default {
|
||||
background: transparent;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.collapseItem1 .el-collapse-item__arrow.is-active{
|
||||
cursor:pointer;
|
||||
color: #bcc9d4;
|
||||
transform:rotate(0)
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -259,7 +259,7 @@ export default {
|
||||
},
|
||||
// 列表查询
|
||||
async handleQueryPageList() {
|
||||
debugger
|
||||
|
||||
// 将特殊参数值urlcode处理
|
||||
// 默认的排序
|
||||
if (
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
v-for="(it, idx) in item.list"
|
||||
:key="idx"
|
||||
draggable="true"
|
||||
@dragstart="dragStart(it.code)"
|
||||
@dragstart="dragStart(it.code, $event)"
|
||||
@dragend="dragEnd()"
|
||||
>
|
||||
<div class="tools-item">
|
||||
@@ -290,6 +290,8 @@
|
||||
:type="widget.type"
|
||||
:bigscreen="{ bigscreenWidth, bigscreenHeight }"
|
||||
@onActivated="setOptionsOnClickWidget"
|
||||
@onChildActivated="setOptionsOnClickInnerWidget"
|
||||
@onTabsHeaderMouseDown="onTabsHeaderMouseDown($event)"
|
||||
@contextmenu.prevent.native="rightClick($event, index)"
|
||||
@mousedown.prevent.native="widgetsClick($event, index)"
|
||||
@mouseup.prevent.native="grade = false"
|
||||
@@ -310,13 +312,34 @@
|
||||
label="配置"
|
||||
>
|
||||
<dynamicForm
|
||||
ref="formData"
|
||||
ref="formData1"
|
||||
:options="widgetOptions.setup"
|
||||
:layer-widget="layerWidget"
|
||||
:widget-index="widgetIndex"
|
||||
:widget-params-config="widgetParamsConfig"
|
||||
@handleCollapse="handleCollapse"
|
||||
@onChanged="(val) => widgetValueChanged('setup', val)"
|
||||
/>
|
||||
<!-- 如果当前选中的是 Tabs 内部子组件,在配置表单底部显示删除按钮 -->
|
||||
<div
|
||||
v-if="innerWidgetSelected"
|
||||
style="text-align: right; margin-top: 12px;"
|
||||
>
|
||||
<el-popconfirm
|
||||
title="确定删除该子组件吗?"
|
||||
@onConfirm="deleteInnerWidget"
|
||||
@confirm="deleteInnerWidget"
|
||||
>
|
||||
<el-button
|
||||
slot="reference"
|
||||
type="danger"
|
||||
size="mini"
|
||||
plain
|
||||
>
|
||||
删除该子组件
|
||||
</el-button>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane
|
||||
v-if="isNotNull(widgetOptions.data)"
|
||||
@@ -342,7 +365,15 @@
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
title="下钻配置"
|
||||
:visible.sync="dialogVisibleDrillDrown"
|
||||
width="100%"
|
||||
class="dialogDrillDrown"
|
||||
>
|
||||
|
||||
<drill-drown-setting @submitDrillDrownData="submitDrillDrownData" :screenData="screenData"></drill-drown-setting>
|
||||
</el-dialog>
|
||||
<content-menu
|
||||
:visible.sync="visibleContentMenu"
|
||||
:style-obj="styleObj"
|
||||
@@ -367,7 +398,7 @@ import dynamicForm from "./components/dynamicForm.vue";
|
||||
import draggable from "vuedraggable";
|
||||
import VueRulerTool from "vue-ruler-tool"; // 大屏设计页面的标尺插件
|
||||
import contentMenu from "./components/contentMenu";
|
||||
|
||||
import DrillDrownSetting from "./components/drillDrownSetting";
|
||||
export default {
|
||||
name: "Login",
|
||||
components: {
|
||||
@@ -376,11 +407,13 @@ export default {
|
||||
widget,
|
||||
dynamicForm,
|
||||
contentMenu,
|
||||
DrillDrownSetting
|
||||
},
|
||||
mixins: [mixin],
|
||||
data() {
|
||||
return {
|
||||
grade: false,
|
||||
dialogVisibleDrillDrown:false,
|
||||
layerWidget: [],
|
||||
widgetTools: widgetTools, // 左侧工具栏的组件图标,将js变量加入到当前作用域
|
||||
widthLeftForTools: 200, // 左侧工具栏宽度
|
||||
@@ -388,7 +421,10 @@ export default {
|
||||
widthLeftForOptions: 300, // 右侧属性配置区
|
||||
widthPaddingTools: 18,
|
||||
toolIsShow: true, // 左侧工具栏是否显示
|
||||
|
||||
screenData:{
|
||||
dashboard: { },
|
||||
widgets: []
|
||||
},
|
||||
bigscreenWidth: 1920, // 大屏设计的大小
|
||||
bigscreenHeight: 1080,
|
||||
|
||||
@@ -432,6 +468,8 @@ export default {
|
||||
rect : null, //框选矩形对象
|
||||
openMulDrag: false, //批量拖拽开关
|
||||
moveWidgets:{}, //记录移动的组件的起始left和top属性
|
||||
// 记录当前是否选中了 Tabs 内部子组件,如果为 null 则表示选中的是顶层组件或大屏
|
||||
innerWidgetSelected: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -494,6 +532,17 @@ export default {
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
submitDrillDrownData(data){
|
||||
this.dialogVisibleDrillDrown=false
|
||||
this.$refs.formData1.changeDrillData(data)
|
||||
},
|
||||
handleCollapse(val){
|
||||
this.dialogVisibleDrillDrown=true
|
||||
this.screenData=val.drill_drown_setting?val.drill_drown_setting:{
|
||||
dashboard: { },
|
||||
widgets: []
|
||||
}
|
||||
},
|
||||
// 获取图层数据
|
||||
getLayerData(val) {
|
||||
const layerWidgetArr = [];
|
||||
@@ -506,6 +555,7 @@ export default {
|
||||
if (val[i].value.paramsKeys) {
|
||||
obj.paramsKeys = val[i].value.paramsKeys;
|
||||
}
|
||||
|
||||
const options = val[i].options["setup"];
|
||||
options.forEach((el) => {
|
||||
if (el.name == "layerName") {
|
||||
@@ -526,9 +576,14 @@ export default {
|
||||
getPXUnderScale(px) {
|
||||
return this.bigscreenScaleInWorkbench * px;
|
||||
},
|
||||
dragStart(widgetCode) {
|
||||
dragStart(widgetCode, evt) {
|
||||
this.dragWidgetCode = widgetCode;
|
||||
this.currentWidgetTotal = this.widgets.length; // 当前操作面板上有多少各组件
|
||||
// 通过 dataTransfer 传递组件 code,便于 Tabs 等嵌套容器在 drop 时读取(不依赖父组件链)
|
||||
if (evt && evt.dataTransfer) {
|
||||
evt.dataTransfer.setData("application/x-widget-code", widgetCode);
|
||||
evt.dataTransfer.effectAllowed = "copy";
|
||||
}
|
||||
},
|
||||
dragEnd() {
|
||||
/**
|
||||
@@ -555,12 +610,48 @@ export default {
|
||||
});
|
||||
},
|
||||
dragOver(evt) {
|
||||
// 鼠标在 Tabs 标签内容区内时不处理,让 tab 内容区成为 drop 目标,避免工作台抢走
|
||||
if (evt.target && evt.target.closest && (evt.target.closest(".tab-content") || evt.target.closest("[data-tab-content]"))) {
|
||||
return;
|
||||
}
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
evt.dataTransfer.dropEffect = "copy";
|
||||
},
|
||||
// 拖动一个组件放到工作区中去,在拖动结束时,放到工作区对应的坐标点上去
|
||||
widgetOnDragged(evt) {
|
||||
// 若落在 Tabs 标签内容区内,由 widgetTabs 自己处理,不在此处添加到主画布
|
||||
if (evt.target && evt.target.closest && (evt.target.closest(".tab-content") || evt.target.closest("[data-tab-content]"))) {
|
||||
return;
|
||||
}
|
||||
// 若落在 Tabs 组件的外层容器上(如 avue-draggable),委托给对应 Tabs 加入当前激活的 tab
|
||||
const widgetsRef = this.$refs.widgets;
|
||||
const widgetList = Array.isArray(widgetsRef) ? widgetsRef : (widgetsRef ? [widgetsRef] : []);
|
||||
if (evt.target && widgetList.length) {
|
||||
for (let i = 0; i < widgetList.length; i++) {
|
||||
const w = widgetList[i];
|
||||
if (!w || !w.$el || !w.$el.contains(evt.target)) continue;
|
||||
if (this.widgets[i] && this.widgets[i].type === "widget-tabs") {
|
||||
const findTabs = (comp) => {
|
||||
if (!comp) return null;
|
||||
if (typeof comp.addWidgetFromDrop === "function") return comp;
|
||||
if (comp.$children && comp.$children.length) {
|
||||
for (let j = 0; j < comp.$children.length; j++) {
|
||||
const found = findTabs(comp.$children[j]);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
const tabsComp = findTabs(w);
|
||||
if (tabsComp) {
|
||||
tabsComp.addWidgetFromDrop(evt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
let widgetType = this.dragWidgetCode;
|
||||
|
||||
// 获取结束坐标和列名
|
||||
@@ -596,6 +687,7 @@ export default {
|
||||
options: tool.options,
|
||||
};
|
||||
// 处理默认值
|
||||
console.log(widgetType)
|
||||
const widgetJsonValue = this.getWidgetConfigValue(widgetJson);
|
||||
|
||||
widgetJsonValue.value.position.left =
|
||||
@@ -618,7 +710,6 @@ export default {
|
||||
widgetJson.value.position
|
||||
);
|
||||
this.setWidgetConfigValue(widgetJson.options.data, widgetJson.value.data);
|
||||
|
||||
return widgetJson;
|
||||
},
|
||||
setWidgetConfigValue(config, configValue) {
|
||||
@@ -642,6 +733,50 @@ export default {
|
||||
this.widgetIndex = index;
|
||||
this.widgetsClick(event,index);
|
||||
},
|
||||
/**
|
||||
* Tabs 标题栏按下:启动整块 Tabs 的拖动(因 Tabs 外层 avue-draggable 已禁用)
|
||||
*/
|
||||
onTabsHeaderMouseDown(payload) {
|
||||
if (!payload || !payload.event || typeof payload.rootWidgetIndex !== 'number') return;
|
||||
const rootIndex = payload.rootWidgetIndex;
|
||||
const widget = this.widgets[rootIndex];
|
||||
if (!widget || !widget.value || !widget.value.position) return;
|
||||
// 选中 Tabs 组件本身,触发蓝色点框和右侧配置
|
||||
this.innerWidgetSelected = null;
|
||||
this.widgetsClickFocus(rootIndex);
|
||||
const evt = payload.event;
|
||||
const workbenchRect = document.getElementById('workbench') && document.getElementById('workbench').getBoundingClientRect();
|
||||
if (!workbenchRect) return;
|
||||
const scale = this.currentSizeRangeIndex === this.defaultSize.index
|
||||
? this.bigscreenScaleInWorkbench
|
||||
: this.sizeRange[this.currentSizeRangeIndex] / 100;
|
||||
const startX = evt.clientX;
|
||||
const startY = evt.clientY;
|
||||
const startLeft = widget.value.position.left;
|
||||
const startTop = widget.value.position.top;
|
||||
const onMove = (e) => {
|
||||
const dx = (e.clientX - startX) / scale;
|
||||
const dy = (e.clientY - startY) / scale;
|
||||
let newLeft = startLeft + dx;
|
||||
let newTop = startTop + dy;
|
||||
if (newLeft < 0) newLeft = 0;
|
||||
if (newTop < 0) newTop = 0;
|
||||
if (newLeft + widget.value.position.width > this.bigscreenWidth) {
|
||||
newLeft = this.bigscreenWidth - widget.value.position.width;
|
||||
}
|
||||
if (newTop + widget.value.position.height > this.bigscreenHeight) {
|
||||
newTop = this.bigscreenHeight - widget.value.position.height;
|
||||
}
|
||||
this.$set(widget.value.position, 'left', newLeft);
|
||||
this.$set(widget.value.position, 'top', newTop);
|
||||
};
|
||||
const onUp = () => {
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onUp);
|
||||
};
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onUp);
|
||||
},
|
||||
// 如果是点击大屏设计器中的底层,加载大屏底层属性
|
||||
setOptionsOnClickScreen() {
|
||||
console.log("setOptionsOnClickScreen");
|
||||
@@ -660,6 +795,8 @@ export default {
|
||||
// 如果是点击某个组件,获取该组件的配置项
|
||||
setOptionsOnClickWidget(obj) {
|
||||
this.screenCode = "";
|
||||
// 选中顶层组件时清空内部子组件的选中状态
|
||||
this.innerWidgetSelected = null;
|
||||
if (typeof obj == "number") {
|
||||
this.widgetOptions = this.deepClone(this.widgets[obj]["options"]);
|
||||
return;
|
||||
@@ -678,8 +815,120 @@ export default {
|
||||
});
|
||||
this.widgetOptions = this.deepClone(this.widgets[obj.index]["options"]);
|
||||
},
|
||||
/**
|
||||
* 选中 Tabs 组件内部的子组件,展示该子组件的右侧配置
|
||||
*/
|
||||
setOptionsOnClickInnerWidget(payload) {
|
||||
if (!payload) return;
|
||||
console.log('setOptionsOnClickInnerWidget payload:', payload);
|
||||
|
||||
const { rootWidgetIndex, tabIndex, childIndex } = payload;
|
||||
const rootIndex = typeof rootWidgetIndex === "number" ? rootWidgetIndex : 0;
|
||||
const rootWidget = this.widgets[rootIndex];
|
||||
if (!rootWidget || !rootWidget.value) return;
|
||||
|
||||
// 1. 兼容两种存储位置:value.setup.tabsList / options.setup 里的 tabsList
|
||||
const setupObj = rootWidget.value.setup || {};
|
||||
let tabsList = setupObj.tabsList;
|
||||
if (!tabsList || !tabsList.length) {
|
||||
const setupArr = rootWidget.options && rootWidget.options.setup ? rootWidget.options.setup : [];
|
||||
const tabsItem = setupArr.find(it => it.name === "tabsList");
|
||||
if (tabsItem && Array.isArray(tabsItem.value)) {
|
||||
tabsList = tabsItem.value;
|
||||
}
|
||||
}
|
||||
tabsList = tabsList || [];
|
||||
|
||||
const targetTab = tabsList[tabIndex];
|
||||
if (!targetTab || !targetTab.children || !targetTab.children[childIndex]) {
|
||||
console.warn("Tabs 子组件未找到:", { rootIndex, tabIndex, childIndex, tabsList });
|
||||
return;
|
||||
}
|
||||
|
||||
let childWidget = targetTab.children[childIndex];
|
||||
|
||||
// 2. 确保子组件有 options(老数据里可能只有 type + value)
|
||||
if (!childWidget.options) {
|
||||
try {
|
||||
const tool = getToolByCode(childWidget.type);
|
||||
if (tool && tool.options) {
|
||||
childWidget.options = this.deepClone(tool.options);
|
||||
} else {
|
||||
console.warn("未找到子组件 options 配置:", childWidget.type);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("为子组件补全 options 失败:", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 用实际 position 回填到 options.position 中,保证坐标表单显示正确
|
||||
if (childWidget.options && Array.isArray(childWidget.options.position)) {
|
||||
const pos = (childWidget.value && childWidget.value.position) ? childWidget.value.position : {};
|
||||
childWidget.options.position.forEach((el) => {
|
||||
if (pos.hasOwnProperty(el.name)) {
|
||||
el.value = pos[el.name];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 4. 记录当前选中的内部子组件路径 & 切换右侧到子组件配置
|
||||
this.innerWidgetSelected = {
|
||||
rootWidgetIndex: rootIndex,
|
||||
tabIndex,
|
||||
childIndex,
|
||||
};
|
||||
this.screenCode = "";
|
||||
this.widgetIndex = rootIndex;
|
||||
this.activeName = "first";
|
||||
|
||||
this.widgetOptions = this.deepClone(childWidget.options || {});
|
||||
},
|
||||
/**
|
||||
* 删除当前选中的 Tabs 内部子组件
|
||||
*/
|
||||
deleteInnerWidget() {
|
||||
if (!this.innerWidgetSelected) return;
|
||||
const { rootWidgetIndex, tabIndex, childIndex } = this.innerWidgetSelected;
|
||||
const rootWidget = this.widgets[rootWidgetIndex];
|
||||
if (!rootWidget || !rootWidget.value) return;
|
||||
|
||||
// 永远只操作“真实绑定”的数据:rootWidget.value.setup.tabsList
|
||||
if (!rootWidget.value.setup) {
|
||||
this.$set(rootWidget.value, "setup", {});
|
||||
}
|
||||
if (!Array.isArray(rootWidget.value.setup.tabsList)) {
|
||||
this.$set(rootWidget.value.setup, "tabsList", []);
|
||||
}
|
||||
const tabsList = rootWidget.value.setup.tabsList;
|
||||
|
||||
const targetTab = tabsList[tabIndex];
|
||||
if (!targetTab || !targetTab.children || !targetTab.children.length) return;
|
||||
|
||||
targetTab.children.splice(childIndex, 1);
|
||||
|
||||
// 同步回 rootWidget 的 setup / options
|
||||
rootWidget.value.setup.tabsList = tabsList;
|
||||
const setupArr = rootWidget.options && rootWidget.options.setup ? rootWidget.options.setup : [];
|
||||
setupArr.forEach((item) => {
|
||||
if (item.name === "tabsList") {
|
||||
item.value = tabsList;
|
||||
}
|
||||
});
|
||||
|
||||
// 清空内部选中状态,并回到 Tabs 本身配置
|
||||
this.innerWidgetSelected = null;
|
||||
this.widgetIndex = rootWidgetIndex;
|
||||
this.widgetOptions = this.deepClone(rootWidget.options || {});
|
||||
this.activeName = "first";
|
||||
},
|
||||
widgetsClick(event,index) {
|
||||
console.log("widgetsClick");
|
||||
// 如果是 Tabs 组件,内部点击由 widgetTabs 自己处理,这里只负责选中 Tabs 整体
|
||||
const rootWidget = this.widgets[index];
|
||||
if (rootWidget && rootWidget.type === "widget-tabs") {
|
||||
this.widgetsClickFocus(index);
|
||||
return;
|
||||
}
|
||||
//判断是否按住了Ctrl按钮,表示Ctrl多选
|
||||
let _this = this;
|
||||
let eventWidget = null;
|
||||
@@ -777,10 +1026,40 @@ export default {
|
||||
console.log(newSetup);
|
||||
this.widgetOptions.setup = newSetup;
|
||||
} else {
|
||||
for (let i = 0; i < this.widgets.length; i++) {
|
||||
if (this.widgetIndex == i) {
|
||||
this.widgets[i].value[key] = this.deepClone(val);
|
||||
this.setDefaultValue(this.widgets[i].options[key], val);
|
||||
// 如果当前选中的是 Tabs 内部子组件,优先更新内部子组件的配置
|
||||
if (this.innerWidgetSelected) {
|
||||
const { rootWidgetIndex, tabIndex, childIndex } = this.innerWidgetSelected;
|
||||
const rootWidget = this.widgets[rootWidgetIndex];
|
||||
if (rootWidget && rootWidget.value && rootWidget.value.setup) {
|
||||
const tabsList = rootWidget.value.setup.tabsList || [];
|
||||
const targetTab = tabsList[tabIndex];
|
||||
if (targetTab && targetTab.children && targetTab.children[childIndex]) {
|
||||
const childWidget = targetTab.children[childIndex];
|
||||
// 更新子组件的 value 和 options
|
||||
if (!childWidget.value) {
|
||||
this.$set(childWidget, "value", {});
|
||||
}
|
||||
childWidget.value[key] = this.deepClone(val);
|
||||
if (childWidget.options && childWidget.options[key]) {
|
||||
this.setDefaultValue(childWidget.options[key], val);
|
||||
}
|
||||
// 回写到 rootWidget 的 setup 中,保证 Tabs 组件保存时能带上最新配置
|
||||
rootWidget.value.setup.tabsList = tabsList;
|
||||
const setupArr = rootWidget.options && rootWidget.options.setup ? rootWidget.options.setup : [];
|
||||
setupArr.forEach((item) => {
|
||||
if (item.name === "tabsList") {
|
||||
item.value = tabsList;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 普通顶层组件的配置更新逻辑保持不变
|
||||
for (let i = 0; i < this.widgets.length; i++) {
|
||||
if (this.widgetIndex == i) {
|
||||
this.widgets[i].value[key] = this.deepClone(val);
|
||||
this.setDefaultValue(this.widgets[i].options[key], val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* @Descripttion: Tabs标签组件
|
||||
* @version:
|
||||
* @Author: Devli
|
||||
* @Date: 2024-01-01 00:00:00
|
||||
* @LastEditors: Devli
|
||||
* @LastEditTime: 2024-01-01 00:00:00
|
||||
*/
|
||||
export const widgetTabs = {
|
||||
code: 'widget-tabs',
|
||||
type: 'form',
|
||||
tabName: '表单',
|
||||
label: 'Tabs标签',
|
||||
icon: 'iconkuangjia',
|
||||
options: {
|
||||
// 配置
|
||||
setup: [
|
||||
{
|
||||
type: 'el-input-text',
|
||||
label: '图层名称',
|
||||
name: 'layerName',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: 'Tabs标签',
|
||||
},
|
||||
{
|
||||
type: 'el-select',
|
||||
label: '标签位置',
|
||||
name: 'tabPosition',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
selectOptions: [
|
||||
{ code: 'top', name: '顶部' },
|
||||
{ code: 'right', name: '右侧' },
|
||||
{ code: 'bottom', name: '底部' },
|
||||
{ code: 'left', name: '左侧' },
|
||||
],
|
||||
value: 'top',
|
||||
},
|
||||
{
|
||||
type: 'el-select',
|
||||
label: '标签类型',
|
||||
name: 'type',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
selectOptions: [
|
||||
{ code: '', name: '默认' },
|
||||
{ code: 'border-card', name: '边框卡片' },
|
||||
{ code: 'card', name: '卡片' },
|
||||
],
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
type: 'el-switch',
|
||||
label: '可关闭',
|
||||
name: 'closable',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
type: 'el-switch',
|
||||
label: '可添加',
|
||||
name: 'addable',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
type: 'el-switch',
|
||||
label: '可拉伸',
|
||||
name: 'stretch',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
type: 'vue-color',
|
||||
label: '标签字体颜色',
|
||||
name: 'labelColor',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: '#303133',
|
||||
},
|
||||
{
|
||||
type: 'vue-color',
|
||||
label: '激活标签颜色',
|
||||
name: 'activeColor',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: '#409EFF',
|
||||
},
|
||||
{
|
||||
type: 'el-input-number',
|
||||
label: '字体字号',
|
||||
name: 'fontSize',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: 14,
|
||||
},
|
||||
{
|
||||
type: 'el-button',
|
||||
label: '标签列表',
|
||||
name: 'tabsList',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: [
|
||||
{ label: '标签一', name: 'tab1', content: '标签一的内容', children: [] },
|
||||
{ label: '标签二', name: 'tab2', content: '标签二的内容', children: [] },
|
||||
{ label: '标签三', name: 'tab3', content: '标签三的内容', children: [] },
|
||||
],
|
||||
},
|
||||
[
|
||||
{
|
||||
name: '组件联动',
|
||||
list: [
|
||||
{
|
||||
type: 'componentLinkage',
|
||||
label: '',
|
||||
name: 'componentLinkage',
|
||||
required: false,
|
||||
value: []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
// 数据
|
||||
data: [
|
||||
{
|
||||
type: 'el-radio-group',
|
||||
label: '数据类型',
|
||||
name: 'dataType',
|
||||
require: false,
|
||||
placeholder: '',
|
||||
selectValue: true,
|
||||
selectOptions: [
|
||||
{
|
||||
code: 'staticData',
|
||||
name: '静态数据',
|
||||
},
|
||||
{
|
||||
code: 'dynamicData',
|
||||
name: '动态数据',
|
||||
},
|
||||
],
|
||||
value: 'staticData',
|
||||
},
|
||||
{
|
||||
type: 'el-input-number',
|
||||
label: '刷新时间(毫秒)',
|
||||
name: 'refreshTime',
|
||||
relactiveDom: 'dataType',
|
||||
relactiveDomValue: 'dynamicData',
|
||||
value: 30000
|
||||
},
|
||||
{
|
||||
type: 'el-button',
|
||||
label: '静态数据',
|
||||
name: 'staticData',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
relactiveDom: 'dataType',
|
||||
relactiveDomValue: 'staticData',
|
||||
value: [
|
||||
{ label: '标签一', name: 'tab1', content: '标签一的内容', children: [] },
|
||||
{ label: '标签二', name: 'tab2', content: '标签二的内容', children: [] },
|
||||
{ label: '标签三', name: 'tab3', content: '标签三的内容', children: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'dycustComponents',
|
||||
label: '',
|
||||
name: 'dynamicData',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
relactiveDom: 'dataType',
|
||||
relactiveDomValue: 'dynamicData',
|
||||
chartType: 'widget-tabs',
|
||||
dictKey: 'TABS_PROPERTIES',
|
||||
value: '',
|
||||
},
|
||||
],
|
||||
// 坐标
|
||||
position: [
|
||||
{
|
||||
type: 'el-input-number',
|
||||
label: '左边距',
|
||||
name: 'left',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
type: 'el-input-number',
|
||||
label: '上边距',
|
||||
name: 'top',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
type: 'el-input-number',
|
||||
label: '宽度',
|
||||
name: 'width',
|
||||
required: false,
|
||||
placeholder: '该容器在1920px大屏中的宽度',
|
||||
value: 400,
|
||||
},
|
||||
{
|
||||
type: 'el-input-number',
|
||||
label: '高度',
|
||||
name: 'height',
|
||||
required: false,
|
||||
placeholder: '该容器在1080px大屏中的高度',
|
||||
value: 300,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,24 @@ export const widgetImage = {
|
||||
required: false,
|
||||
placeholder: '',
|
||||
},
|
||||
{
|
||||
type: 'el-switch',
|
||||
label: '开启下钻',
|
||||
name: 'is_drill_drown',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
type: 'el-collapse',
|
||||
label: '下钻配置',
|
||||
name: 'drill_drown_setting',
|
||||
relactiveDom:'is_drill_drown',
|
||||
relactiveDomValue:true,
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value:''
|
||||
},
|
||||
],
|
||||
// 数据
|
||||
data: [],
|
||||
|
||||
@@ -66,6 +66,14 @@ export const widgetTable = {
|
||||
placeholder: '',
|
||||
value: false
|
||||
},
|
||||
{
|
||||
type: 'el-switch',
|
||||
label: '序号',
|
||||
name: 'isIndex',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: false
|
||||
},
|
||||
{
|
||||
type: 'el-input-number',
|
||||
label: '边框宽度',
|
||||
@@ -314,8 +322,44 @@ export const widgetTable = {
|
||||
value: 1
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
],
|
||||
{
|
||||
type: 'el-switch',
|
||||
label: '开启下钻',
|
||||
name: 'is_drill_drown',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
type: 'el-collapse',
|
||||
label: '下钻配置',
|
||||
name: 'drill_drown_setting',
|
||||
relactiveDom:'is_drill_drown',
|
||||
relactiveDomValue:true,
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value:''
|
||||
},
|
||||
{
|
||||
type: 'el-switch',
|
||||
label: '阅读模式',
|
||||
name: 'is_read_mode',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
type: 'vue-color',
|
||||
label: '阅读模式颜色',
|
||||
name: 'read_color',
|
||||
relactiveDom:'is_read_mode',
|
||||
relactiveDomValue:true,
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value:''
|
||||
},
|
||||
{
|
||||
type: 'dynamic-add-table',
|
||||
label: '',
|
||||
|
||||
@@ -150,6 +150,24 @@ export const widgetText = {
|
||||
placeholder: '',
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
type: 'el-switch',
|
||||
label: '开启下钻',
|
||||
name: 'is_drill_drown',
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
type: 'el-collapse',
|
||||
label: '下钻配置',
|
||||
name: 'drill_drown_setting',
|
||||
relactiveDom:'is_drill_drown',
|
||||
relactiveDomValue:true,
|
||||
required: false,
|
||||
placeholder: '',
|
||||
value:''
|
||||
},
|
||||
[
|
||||
{
|
||||
name: '自定义样式设置',
|
||||
|
||||
@@ -13,6 +13,7 @@ import {widgetHref} from "./configure/texts/widget-href"
|
||||
import {widgetTime} from "./configure/texts/widget-time"
|
||||
import {widgetImage} from "./configure/texts/widget-image"
|
||||
import {widgetButton} from "./configure/form/widget-button"
|
||||
import {widgetTabs} from "./configure/form/widget-tabs"
|
||||
import {widgetSliders} from "./configure/texts/widget-slider"
|
||||
import {widgetVideo} from "./configure/texts/widget-video"
|
||||
import {widgetVideoMonitor} from "./configure/texts/widget-videoMonitor"
|
||||
@@ -68,6 +69,7 @@ export const widgetTool = [
|
||||
widgetTime,
|
||||
widgetImage,
|
||||
widgetButton,
|
||||
widgetTabs,
|
||||
// widgetSliders,
|
||||
widgetVideo,
|
||||
widgetVideoMonitor,
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
<!--
|
||||
* @Author: qianlishi qianlishi@anji-plus.com
|
||||
* @Date: 2023-03-06 15:38:10
|
||||
* @LastEditors: qianlishi qianlishi@anji-plus.com
|
||||
* @LastEditTime: 2023-04-20 13:54:57
|
||||
-->
|
||||
<template>
|
||||
<el-date-picker
|
||||
:style="styleObj"
|
||||
v-model="timeValue"
|
||||
:value-format="valueFormat"
|
||||
:picker-options="datetimeRangePickerOptions"
|
||||
:type="dateType"
|
||||
@[eventChange]="change"
|
||||
/>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
originWidgetLinkageLogic,
|
||||
targetWidgetLinkageLogic,
|
||||
} from "@/views/bigscreenDesigner/designer/linkageLogic";
|
||||
import miment from 'miment'
|
||||
|
||||
export default {
|
||||
name: "WidgetFormTime",
|
||||
props: {
|
||||
value: Object,
|
||||
ispreview: Boolean,
|
||||
widgetIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
timeValue: "",
|
||||
optionsStyle: {},
|
||||
optionsData: {},
|
||||
optionsSetup: {},
|
||||
//日期时间快捷选项
|
||||
datetimeRangePickerOptions: {
|
||||
shortcuts: [{
|
||||
text: '今天',
|
||||
onClick(picker) {
|
||||
const start = new Date(new Date(new Date().getTime()).setHours(0, 0, 0, 0));
|
||||
const end = new Date(new Date(new Date().getTime()).setHours(23, 59, 59, 999));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '昨天',
|
||||
onClick(picker) {
|
||||
const start = new Date(new Date(new Date().getTime() - 24 * 60 * 60 * 1000).setHours(0, 0, 0, 0));
|
||||
const end = new Date(new Date(new Date().getTime() - 24 * 60 * 60 * 1000).setHours(23, 59, 59, 999));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近一周',
|
||||
onClick(picker) {
|
||||
const end = new Date(new Date(new Date().getTime()).setHours(23, 59, 59, 999));
|
||||
const start = new Date(new Date(new Date().getTime() + 24 * 60 * 60 * 1000));
|
||||
start.setTime(miment().add(-6, 'DD').stamp());
|
||||
new Date(start.setHours(0, 0, 0, 0));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近一个月',
|
||||
onClick(picker) {
|
||||
const end = new Date(new Date(new Date().getTime()).setHours(23, 59, 59, 999));
|
||||
const start = new Date();
|
||||
start.setTime(miment().add(-1, 'MM').stamp());
|
||||
new Date(start.setHours(0, 0, 0, 0));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近三个月',
|
||||
onClick(picker) {
|
||||
const end = new Date(new Date(new Date().getTime()).setHours(23, 59, 59, 999));
|
||||
const start = new Date();
|
||||
start.setTime(miment().add(-3, 'MM').stamp());
|
||||
new Date(start.setHours(0, 0, 0, 0));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近半年',
|
||||
onClick(picker) {
|
||||
const end = new Date(new Date(new Date().getTime()).setHours(23, 59, 59, 999));
|
||||
const start = new Date();
|
||||
start.setTime(miment().add(-6, 'MM').stamp());
|
||||
new Date(start.setHours(0, 0, 0, 0));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近一年',
|
||||
onClick(picker) {
|
||||
const end = new Date(new Date(new Date().getTime()).setHours(23, 59, 59, 999));
|
||||
const start = new Date();
|
||||
start.setTime(miment().add(-1, 'YY').stamp());
|
||||
new Date(start.setHours(0, 0, 0, 0));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}],
|
||||
// disabledDate(time){
|
||||
// return time.getTime() > Date.now()
|
||||
// }
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
styleObj() {
|
||||
return {
|
||||
position: this.ispreview ? "absolute" : "static",
|
||||
width: this.optionsStyle.width + "px",
|
||||
height: this.optionsStyle.height + "px",
|
||||
left: this.optionsStyle.left + "px",
|
||||
top: this.optionsStyle.top + "px",
|
||||
background: this.optionsSetup.select_background,
|
||||
};
|
||||
},
|
||||
eventChange() {
|
||||
return "change";
|
||||
},
|
||||
dateType() {
|
||||
return this.optionsSetup.dateType || 'datetimerange';
|
||||
},
|
||||
valueFormat() {
|
||||
return this.dateType === 'daterange' ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss';
|
||||
},
|
||||
allComponentLinkage() {
|
||||
return this.$store.state.designer.allComponentLinkage;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler(val) {
|
||||
this.optionsSetup = val.setup;
|
||||
this.optionsData = val.data;
|
||||
this.optionsStyle = val.position;
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.optionsSetup = this.value.setup;
|
||||
this.optionsData = this.value.data;
|
||||
this.optionsStyle = this.value.position;
|
||||
|
||||
targetWidgetLinkageLogic(this); // 联动-目标组件逻辑
|
||||
},
|
||||
methods: {
|
||||
change(event) {
|
||||
const formTimeData = {}
|
||||
formTimeData['startTime'] = event[0] //startTime
|
||||
formTimeData['endTime'] = event[1] //endTime
|
||||
originWidgetLinkageLogic(this, true, {
|
||||
currentData: formTimeData,
|
||||
}); // 联动-源组件逻辑
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.el-select {
|
||||
height: 100%;
|
||||
|
||||
.el-input {
|
||||
height: 100%;
|
||||
|
||||
.el-input__inner {
|
||||
height: 100%;
|
||||
background: inherit;
|
||||
color: inherit;
|
||||
|
||||
&::placeholder {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -5,14 +5,26 @@
|
||||
* @LastEditTime: 2023-04-20 13:54:57
|
||||
-->
|
||||
<template>
|
||||
<div class="pickWrap">
|
||||
|
||||
<el-date-picker
|
||||
:style="styleObj"
|
||||
v-model="timeValue"
|
||||
:value-format="valueFormat"
|
||||
:picker-options="datetimeRangePickerOptions"
|
||||
:type="dateType"
|
||||
@[eventChange]="change"
|
||||
class="start-picker date-picker"
|
||||
:style="styleObj"
|
||||
v-model="startTime"
|
||||
:value-format="valueFormat"
|
||||
:type="dateType=='datetimerange'?'datetime':'date'"
|
||||
@[eventChange]="change"
|
||||
/>
|
||||
|
||||
<el-date-picker
|
||||
class="date-picker"
|
||||
:style="{...styleObj,left:styleObj.leftEnd,width:styleObj.widthEnd}"
|
||||
v-model="endTime"
|
||||
:value-format="valueFormat"
|
||||
:type="dateType=='datetimerange'?'datetime':'date'"
|
||||
@[eventChange]="change"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
@@ -33,85 +45,23 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
timeValue: "",
|
||||
optionsStyle: {},
|
||||
optionsData: {},
|
||||
optionsSetup: {},
|
||||
//日期时间快捷选项
|
||||
datetimeRangePickerOptions: {
|
||||
shortcuts: [{
|
||||
text: '今天',
|
||||
onClick(picker) {
|
||||
const start = new Date(new Date(new Date().getTime()).setHours(0, 0, 0, 0));
|
||||
const end = new Date(new Date(new Date().getTime()).setHours(23, 59, 59, 999));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '昨天',
|
||||
onClick(picker) {
|
||||
const start = new Date(new Date(new Date().getTime() - 24 * 60 * 60 * 1000).setHours(0, 0, 0, 0));
|
||||
const end = new Date(new Date(new Date().getTime() - 24 * 60 * 60 * 1000).setHours(23, 59, 59, 999));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近一周',
|
||||
onClick(picker) {
|
||||
const end = new Date(new Date(new Date().getTime()).setHours(23, 59, 59, 999));
|
||||
const start = new Date(new Date(new Date().getTime() + 24 * 60 * 60 * 1000));
|
||||
start.setTime(miment().add(-6, 'DD').stamp());
|
||||
new Date(start.setHours(0, 0, 0, 0));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近一个月',
|
||||
onClick(picker) {
|
||||
const end = new Date(new Date(new Date().getTime()).setHours(23, 59, 59, 999));
|
||||
const start = new Date();
|
||||
start.setTime(miment().add(-1, 'MM').stamp());
|
||||
new Date(start.setHours(0, 0, 0, 0));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近三个月',
|
||||
onClick(picker) {
|
||||
const end = new Date(new Date(new Date().getTime()).setHours(23, 59, 59, 999));
|
||||
const start = new Date();
|
||||
start.setTime(miment().add(-3, 'MM').stamp());
|
||||
new Date(start.setHours(0, 0, 0, 0));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近半年',
|
||||
onClick(picker) {
|
||||
const end = new Date(new Date(new Date().getTime()).setHours(23, 59, 59, 999));
|
||||
const start = new Date();
|
||||
start.setTime(miment().add(-6, 'MM').stamp());
|
||||
new Date(start.setHours(0, 0, 0, 0));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近一年',
|
||||
onClick(picker) {
|
||||
const end = new Date(new Date(new Date().getTime()).setHours(23, 59, 59, 999));
|
||||
const start = new Date();
|
||||
start.setTime(miment().add(-1, 'YY').stamp());
|
||||
new Date(start.setHours(0, 0, 0, 0));
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}],
|
||||
// disabledDate(time){
|
||||
// return time.getTime() > Date.now()
|
||||
// }
|
||||
}
|
||||
endTime:null,
|
||||
startTime:null,
|
||||
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
styleObj() {
|
||||
return {
|
||||
position: this.ispreview ? "absolute" : "static",
|
||||
width: this.optionsStyle.width + "px",
|
||||
width: this.optionsStyle.width/2+12 + "px",
|
||||
widthEnd: this.optionsStyle.width/2-12 + "px",
|
||||
height: this.optionsStyle.height + "px",
|
||||
left: this.optionsStyle.left + "px",
|
||||
leftEnd: this.optionsStyle.left+this.optionsStyle.width/2+12 + "px",
|
||||
top: this.optionsStyle.top + "px",
|
||||
background: this.optionsSetup.select_background,
|
||||
};
|
||||
@@ -149,8 +99,8 @@ export default {
|
||||
methods: {
|
||||
change(event) {
|
||||
const formTimeData = {}
|
||||
formTimeData['startTime'] = event[0] //startTime
|
||||
formTimeData['endTime'] = event[1] //endTime
|
||||
formTimeData['startTime'] = this.startTime //event[0] //startTime
|
||||
formTimeData['endTime'] = this.endTime //event[1] //endTime
|
||||
originWidgetLinkageLogic(this, true, {
|
||||
currentData: formTimeData,
|
||||
}); // 联动-源组件逻辑
|
||||
@@ -159,21 +109,20 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.el-select {
|
||||
height: 100%;
|
||||
|
||||
.el-input {
|
||||
height: 100%;
|
||||
|
||||
.el-input__inner {
|
||||
height: 100%;
|
||||
background: inherit;
|
||||
color: inherit;
|
||||
|
||||
&::placeholder {
|
||||
color: inherit;
|
||||
}
|
||||
.start-picker{
|
||||
display:flex;
|
||||
&:after{
|
||||
content:'-';
|
||||
width:24px;
|
||||
transform:translate(7px,5px)
|
||||
}
|
||||
}
|
||||
}
|
||||
.pickWrap{
|
||||
display:flex;
|
||||
&::v-deep() {
|
||||
.el-input__prefix{
|
||||
height:28px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
845
src/views/bigscreenDesigner/designer/widget/form/widgetTabs.vue
Normal file
845
src/views/bigscreenDesigner/designer/widget/form/widgetTabs.vue
Normal file
@@ -0,0 +1,845 @@
|
||||
<!--
|
||||
* @Author: Devli
|
||||
* @Date: 2024-01-01 00:00:00
|
||||
* @Last Modified by: Devli
|
||||
* @Last Modified time: 2024-01-01 00:00:00
|
||||
!-->
|
||||
<template>
|
||||
<div class="widget-tabs" @mousedown.capture="onTabsRootCapture">
|
||||
<el-tabs
|
||||
:style="styleObj"
|
||||
:tab-position="tabPosition"
|
||||
:type="tabsType"
|
||||
:closable="closable"
|
||||
:addable="addable"
|
||||
:stretch="stretch"
|
||||
v-model="activeTab"
|
||||
@tab-click="handleTabClick"
|
||||
@tab-remove="handleTabRemove"
|
||||
@tab-add="handleTabAdd"
|
||||
>
|
||||
<el-tab-pane
|
||||
v-for="(tab, index) in tabsList"
|
||||
:key="tab.name || index"
|
||||
:label="tab.label"
|
||||
:name="tab.name || `tab${index}`"
|
||||
:closable="closable"
|
||||
>
|
||||
<div
|
||||
class="tab-content"
|
||||
data-tab-content
|
||||
:style="contentStyle"
|
||||
@click.capture="onTabContentClick($event, index)"
|
||||
@drop="handleTabDrop($event, tab, index)"
|
||||
@dragover.capture.prevent="handleTabDragOver($event)"
|
||||
@dragover.prevent="handleTabDragOver($event)"
|
||||
@dragenter.capture.prevent="handleTabDragEnter($event)"
|
||||
@dragenter.prevent="handleTabDragEnter($event)"
|
||||
>
|
||||
<!-- 渲染子组件(支持在标签内部拖动、删除) -->
|
||||
<template v-if="tab.children && tab.children.length > 0">
|
||||
<div
|
||||
v-for="(childWidget, childIndex) in tab.children"
|
||||
:key="childWidget.value.widgetId || `child-${index}-${childIndex}`"
|
||||
class="tab-child-draggable"
|
||||
:style="{
|
||||
marginLeft: (childWidget.value.position && typeof childWidget.value.position.left === 'number') ? childWidget.value.position.left + 'px' : '0px',
|
||||
marginTop: (childWidget.value.position && typeof childWidget.value.position.top === 'number') ? childWidget.value.position.top + 'px' : '0px',
|
||||
width: (childWidget.value.position && childWidget.value.position.width) ? childWidget.value.position.width + 'px' : '100px',
|
||||
height: (childWidget.value.position && childWidget.value.position.height) ? childWidget.value.position.height + 'px' : '50px',
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="tab-child-wrapper"
|
||||
:data-tab-index="index"
|
||||
:data-child-index="childIndex"
|
||||
>
|
||||
<!-- 选中子组件的小手柄:点击后触发右侧显示该子组件配置 -->
|
||||
<span
|
||||
class="tab-child-select-handle"
|
||||
title="选中并配置该组件"
|
||||
@mousedown.stop.prevent="onTabChildHandleDown(index, childIndex)"
|
||||
>
|
||||
<i class="el-icon-setting tab-child-select-icon"></i>
|
||||
</span>
|
||||
<component
|
||||
:is="getComponentName(childWidget.type)"
|
||||
:value="childWidget.value"
|
||||
:widget-index="childIndex"
|
||||
:ispreview="ispreview"
|
||||
class="tab-child-component"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="tab-content-empty">
|
||||
拖拽组件到这里
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
originWidgetLinkageLogic,
|
||||
targetWidgetLinkageLogic,
|
||||
} from "@/views/bigscreenDesigner/designer/linkageLogic";
|
||||
import { getToolByCode } from "@/views/bigscreenDesigner/designer/tools/index";
|
||||
// 与主画布 widget.vue 保持一致:注册所有可拖入的组件,否则图表、下拉等会报 Unknown custom element
|
||||
import widgetHref from "../texts/widgetHref.vue";
|
||||
import widgetText from "../texts/widgetText.vue";
|
||||
import widgetButton from "./widgetButton.vue";
|
||||
import widgetImage from "../texts/widgetImage.vue";
|
||||
import widgetTable from "../texts/widgetTable.vue";
|
||||
import WidgetMarquee from "../texts/widgetMarquee.vue";
|
||||
import widgetTime from "../texts/widgetTime.vue";
|
||||
import widgetSlider from "../texts/widgetSlider.vue";
|
||||
import widgetVideo from "../texts/widgetVideo.vue";
|
||||
import widgetVideoMonitor from "../texts/widgetVideoMonitor.vue";
|
||||
import WidgetIframe from "../texts/widgetIframe.vue";
|
||||
import widgetCalendar from "../texts/widgetCalendar.vue";
|
||||
import widgetBarchart from "../bar/widgetBarchart.vue";
|
||||
import widgetScatter from "../scatter/widgetScatter.vue";
|
||||
import widgetGradientColorBarchart from "../bar/widgetGradientColorBarchart.vue";
|
||||
import widgetLinechart from "../line/widgetLinechart.vue";
|
||||
import widgetBarlinechart from "../barline/widgetBarlinechart";
|
||||
import WidgetPiechart from "../pie/widgetPiechart.vue";
|
||||
import WidgetFunnel from "../funnel/widgetFunnel.vue";
|
||||
import WidgetGauge from "../percent/widgetGauge.vue";
|
||||
import WidgetPieNightingaleRoseArea from "../pie/widgetPieNightingaleRose";
|
||||
import widgetLineMap from "../map/widgetLineMap.vue";
|
||||
import widgetPiePercentageChart from "../percent/widgetPiePercentageChart";
|
||||
import widgetAirBubbleMap from "../map/widgetAirBubbleMap.vue";
|
||||
import widgetBarStackChart from "../bar/widgetBarStackChart.vue";
|
||||
import widgetLineStackChart from "../line/widgetLineStackChart.vue";
|
||||
import widgetBarCompareChart from "../bar/widgetBarCompareChart.vue";
|
||||
import widgetLineCompareChart from "../line/widgetLineCompareChart.vue";
|
||||
import widgetDecoratePieChart from "../styleWidget/widgetDecoratePieChart.vue";
|
||||
import widgetMoreBarLineChart from "../barline/widgetMoreBarLineChart";
|
||||
import widgetWordCloud from "../wordcloud/widgetWordCloud.vue";
|
||||
import widgetHeatmap from "../heatmap/widgetHeatmap.vue";
|
||||
import widgetRadar from "../radar/widgetRadar.vue";
|
||||
import widgetBarLineStackChart from "../barline/widgetBarLineStackChart";
|
||||
import widgetSelect from "./widgetSelect.vue";
|
||||
import widgetFormTime from "./widgetFormTime.vue";
|
||||
import widgetScaleVertical from "../scale/widgetScaleVertical.vue";
|
||||
import widgetScaleHorizontal from "../scale/widgetScaleHorizontal.vue";
|
||||
import widgetBarDoubleYaxisChart from "../bar/widgetBarDoubleYaxisChart.vue";
|
||||
import widgetBorder from "../styleWidget/widgetBorder.vue";
|
||||
import widgetDecorateFlowLine from "../styleWidget/widgetDecorateFlowLine.vue";
|
||||
import widgetDecoration from "../styleWidget/widgetDecoration.vue";
|
||||
import widgetBarMap from "../map/widgetBarMap.vue";
|
||||
import widgetChinaMap from "../map/widgetChinaMap.vue";
|
||||
import widgetGlobalMap from "../map/widgetGlobalMap.vue";
|
||||
import widgetBarStackMoreShowChart from "../bar/widgetBarStackMoreShowChart.vue";
|
||||
import widgetBarLineSingleChart from "../barline/widgetBarLineSingleChart.vue";
|
||||
|
||||
export default {
|
||||
name: "WidgetTabs",
|
||||
components: {
|
||||
widgetHref,
|
||||
widgetText,
|
||||
widgetButton,
|
||||
widgetImage,
|
||||
widgetTable,
|
||||
WidgetMarquee,
|
||||
widgetTime,
|
||||
widgetSlider,
|
||||
widgetVideo,
|
||||
widgetVideoMonitor,
|
||||
WidgetIframe,
|
||||
widgetCalendar,
|
||||
widgetBarchart,
|
||||
widgetGradientColorBarchart,
|
||||
widgetLinechart,
|
||||
widgetBarlinechart,
|
||||
WidgetPiechart,
|
||||
WidgetFunnel,
|
||||
WidgetGauge,
|
||||
WidgetPieNightingaleRoseArea,
|
||||
widgetLineMap,
|
||||
widgetPiePercentageChart,
|
||||
widgetAirBubbleMap,
|
||||
widgetBarStackChart,
|
||||
widgetLineStackChart,
|
||||
widgetBarCompareChart,
|
||||
widgetLineCompareChart,
|
||||
widgetDecoratePieChart,
|
||||
widgetMoreBarLineChart,
|
||||
widgetWordCloud,
|
||||
widgetHeatmap,
|
||||
widgetRadar,
|
||||
widgetBarLineStackChart,
|
||||
widgetScaleVertical,
|
||||
widgetScaleHorizontal,
|
||||
widgetSelect,
|
||||
widgetFormTime,
|
||||
widgetBarDoubleYaxisChart,
|
||||
widgetBorder,
|
||||
widgetDecorateFlowLine,
|
||||
widgetDecoration,
|
||||
widgetBarMap,
|
||||
widgetChinaMap,
|
||||
widgetGlobalMap,
|
||||
widgetScatter,
|
||||
widgetBarStackMoreShowChart,
|
||||
widgetBarLineSingleChart,
|
||||
},
|
||||
props: {
|
||||
value: Object,
|
||||
ispreview: Boolean,
|
||||
widgetIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: {},
|
||||
optionsSetup: {},
|
||||
optionsData: {},
|
||||
optionsStyle: {},
|
||||
activeTab: '',
|
||||
dynamicTabsList: [],
|
||||
flagInter: null,
|
||||
grade: false,
|
||||
draggingChild: null,
|
||||
childDragMoveHandler: null,
|
||||
childDragUpHandler: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
transStyle() {
|
||||
return this.objToOne(this.options);
|
||||
},
|
||||
styleObj() {
|
||||
return {
|
||||
position: this.ispreview ? "relative" : "static",
|
||||
width: this.optionsStyle.width + "px",
|
||||
height: this.optionsStyle.height + "px",
|
||||
left: this.optionsStyle.left + "px",
|
||||
top: this.optionsStyle.top + "px",
|
||||
display:
|
||||
this.transStyle.hideLayer === undefined
|
||||
? "block"
|
||||
: this.transStyle.hideLayer ? "none" : "block",
|
||||
};
|
||||
},
|
||||
contentStyle() {
|
||||
return {
|
||||
color: this.transStyle.labelColor || '#303133',
|
||||
'font-size': (this.transStyle.fontSize || 14) + 'px',
|
||||
padding: '20px',
|
||||
height: '100%',
|
||||
'box-sizing': 'border-box',
|
||||
};
|
||||
},
|
||||
tabPosition() {
|
||||
return this.transStyle.tabPosition || 'top';
|
||||
},
|
||||
tabsType() {
|
||||
return this.transStyle.type || '';
|
||||
},
|
||||
closable() {
|
||||
return this.transStyle.closable || false;
|
||||
},
|
||||
addable() {
|
||||
return this.transStyle.addable || false;
|
||||
},
|
||||
stretch() {
|
||||
return this.transStyle.stretch || false;
|
||||
},
|
||||
tabsList() {
|
||||
if (this.optionsData && this.optionsData.dataType === 'dynamicData' && this.optionsData.dynamicData && this.dynamicTabsList.length > 0) {
|
||||
// 动态数据
|
||||
return this.dynamicTabsList;
|
||||
} else {
|
||||
// 静态数据 - 优先使用setup中的tabsList,确保children数据不丢失
|
||||
const tabsList = this.optionsSetup.tabsList || this.transStyle.tabsList || [];
|
||||
// 确保每个tab都有children数组
|
||||
tabsList.forEach(tab => {
|
||||
if (!tab.children) {
|
||||
this.$set(tab, 'children', []);
|
||||
}
|
||||
});
|
||||
return tabsList;
|
||||
}
|
||||
},
|
||||
allComponentLinkage() {
|
||||
return this.$store.state.designer.allComponentLinkage;
|
||||
},
|
||||
tabBigscreen() {
|
||||
// 子组件的bigscreen应该是相对于tab容器的
|
||||
return {
|
||||
bigscreenWidth: this.optionsStyle.width,
|
||||
bigscreenHeight: this.optionsStyle.height,
|
||||
};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler(val) {
|
||||
this.options = val;
|
||||
this.optionsSetup = val.setup || {};
|
||||
this.optionsData = val.data || {};
|
||||
this.optionsStyle = val.position || {};
|
||||
this.setActiveTab();
|
||||
},
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.options = this.value;
|
||||
this.optionsSetup = this.value.setup;
|
||||
this.optionsData = this.value.data;
|
||||
this.optionsStyle = this.value.position;
|
||||
this.setActiveTab();
|
||||
targetWidgetLinkageLogic(this); // 联动-目标组件逻辑
|
||||
|
||||
// 设置动态数据
|
||||
if (this.optionsData && this.optionsData.dataType === 'dynamicData') {
|
||||
this.dynamicDataFn(this.optionsData.dynamicData, this.optionsData.refreshTime);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 触发 Tabs 内部子组件选中事件,让设计器右侧展示该子组件的配置
|
||||
*/
|
||||
emitChildActivated(tabIndex, childIndex) {
|
||||
if (this.ispreview) return;
|
||||
const currentTabsList = this.tabsList;
|
||||
const targetTab = currentTabsList[tabIndex];
|
||||
if (!targetTab || !targetTab.children || !targetTab.children[childIndex]) return;
|
||||
const childWidget = targetTab.children[childIndex];
|
||||
this.$emit("childActivated", {
|
||||
rootWidgetIndex: this.widgetIndex,
|
||||
tabIndex,
|
||||
childIndex,
|
||||
widget: childWidget,
|
||||
});
|
||||
},
|
||||
/**
|
||||
* tab 内容区域点击:单击子组件 => 选中子组件;双击空白 => 选中整个 Tabs
|
||||
*/
|
||||
onTabContentClick(evt, tabIndex) {
|
||||
if (this.ispreview || !evt.target || !evt.target.closest) return;
|
||||
// 1)如果点在某个子组件包装层上,优先选中该子组件
|
||||
const wrapper = evt.target.closest(".tab-child-wrapper");
|
||||
if (wrapper) {
|
||||
const childIndexAttr = wrapper.getAttribute("data-child-index");
|
||||
const childIndex = Number(childIndexAttr);
|
||||
if (!isNaN(childIndex)) {
|
||||
this.emitChildActivated(tabIndex, childIndex);
|
||||
}
|
||||
evt.stopPropagation();
|
||||
return;
|
||||
}
|
||||
// 2)双击内容区空白,通知外层选中整个 Tabs
|
||||
const contentEl = evt.currentTarget;
|
||||
const hasChildWrapper = contentEl.querySelector(".tab-child-wrapper");
|
||||
if (!hasChildWrapper && evt.detail === 2) {
|
||||
this.$emit("tabsContentDblClick", { tabIndex, event: evt });
|
||||
evt.stopPropagation();
|
||||
return;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 点击左上角选择手柄:只做“选中内部子组件”的动作
|
||||
*/
|
||||
onTabChildHandleDown(tabIndex, childIndex) {
|
||||
if (this.ispreview) return;
|
||||
this.emitChildActivated(tabIndex, childIndex);
|
||||
},
|
||||
setActiveTab() {
|
||||
const tabs = this.tabsList;
|
||||
if (!tabs || tabs.length === 0) return;
|
||||
|
||||
// 如果当前 activeTab 还在 tabs 中,则保持不变,避免每次数据变化都跳回第一个标签
|
||||
if (this.activeTab) {
|
||||
const exist = tabs.some((t, i) => (t.name || `tab${i}`) === this.activeTab);
|
||||
if (exist) return;
|
||||
}
|
||||
|
||||
// 当前没有选中标签,或原选中标签已被删除时,才默认选中第一个
|
||||
this.activeTab = tabs[0].name || 'tab0';
|
||||
},
|
||||
handleTabClick(tab) {
|
||||
const currentTab = this.tabsList.find(t => (t.name || `tab${this.tabsList.indexOf(t)}`) === tab.name);
|
||||
if (currentTab) {
|
||||
originWidgetLinkageLogic(this, true, {
|
||||
currentData: currentTab,
|
||||
}); // 联动-源组件逻辑
|
||||
}
|
||||
},
|
||||
handleTabRemove(name) {
|
||||
// 处理标签页移除
|
||||
console.log('移除标签页:', name);
|
||||
},
|
||||
handleTabAdd() {
|
||||
// 处理标签页添加
|
||||
console.log('添加标签页');
|
||||
},
|
||||
//动态数据字典解析
|
||||
dynamicDataFn(val, refreshTime) {
|
||||
if (!val) return;
|
||||
clearInterval(this.flagInter); // 清除之前的定时器
|
||||
if (this.ispreview) {
|
||||
this.getEchartData(val);
|
||||
this.flagInter = setInterval(() => {
|
||||
this.getEchartData(val);
|
||||
}, refreshTime);
|
||||
} else {
|
||||
this.getEchartData(val);
|
||||
}
|
||||
},
|
||||
getEchartData(val) {
|
||||
const data = this.queryEchartsData(val);
|
||||
data.then((res) => {
|
||||
this.renderingFn(res);
|
||||
}).catch((err) => {
|
||||
console.error('获取tabs数据失败:', err);
|
||||
});
|
||||
},
|
||||
renderingFn(val) {
|
||||
// 将动态数据转换为tabs格式
|
||||
this.dynamicTabsList = Array.isArray(val) ? val.map((item, index) => ({
|
||||
label: item.label || item.name || `标签${index + 1}`,
|
||||
name: item.name || item.value || `tab${index}`,
|
||||
content: item.content || item.label || item.name || '',
|
||||
children: item.children || [],
|
||||
})) : [];
|
||||
this.$nextTick(() => {
|
||||
this.setActiveTab();
|
||||
});
|
||||
},
|
||||
// 处理tab内容区域的拖拽
|
||||
handleTabDragOver(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
evt.stopImmediatePropagation();
|
||||
evt.dataTransfer.dropEffect = "copy";
|
||||
return false;
|
||||
},
|
||||
handleTabDragEnter(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
evt.stopImmediatePropagation();
|
||||
return false;
|
||||
},
|
||||
handleTabDrop(evt, tab, tabIndex) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
evt.stopImmediatePropagation();
|
||||
|
||||
console.log('Tabs drop事件触发', tab, tabIndex);
|
||||
|
||||
// 优先从 dataTransfer 读取(index 在 dragStart 时已写入),否则再沿父组件查找
|
||||
let dragWidgetCode = null;
|
||||
if (evt.dataTransfer && evt.dataTransfer.types && evt.dataTransfer.types.indexOf('application/x-widget-code') !== -1) {
|
||||
dragWidgetCode = evt.dataTransfer.getData('application/x-widget-code');
|
||||
}
|
||||
if (!dragWidgetCode) {
|
||||
dragWidgetCode = this.getDragWidgetCode();
|
||||
}
|
||||
console.log('拖拽的组件类型:', dragWidgetCode);
|
||||
|
||||
if (!dragWidgetCode) {
|
||||
console.warn('未获取到拖拽组件类型');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取相对于tab内容区域的坐标
|
||||
const tabContentEl = evt.currentTarget;
|
||||
const tabContentRect = tabContentEl.getBoundingClientRect();
|
||||
const x = evt.clientX - tabContentRect.left;
|
||||
const y = evt.clientY - tabContentRect.top;
|
||||
|
||||
// 创建新组件
|
||||
const tool = getToolByCode(dragWidgetCode);
|
||||
if (!tool) {
|
||||
console.warn('未找到组件配置:', dragWidgetCode);
|
||||
return;
|
||||
}
|
||||
|
||||
const widgetJson = {
|
||||
type: dragWidgetCode,
|
||||
value: {
|
||||
setup: {},
|
||||
data: {},
|
||||
position: {
|
||||
width: 0,
|
||||
height: 0,
|
||||
left: 0,
|
||||
top: 0,
|
||||
zIndex: 0,
|
||||
},
|
||||
},
|
||||
options: this.deepClone(tool.options),
|
||||
};
|
||||
|
||||
// 处理默认值
|
||||
const widgetJsonValue = this.getWidgetConfigValue(widgetJson);
|
||||
// Tabs 内部子组件:默认边距统一从 0 开始,由右侧“坐标”面板控制间距
|
||||
widgetJsonValue.value.position.left = 0;
|
||||
widgetJsonValue.value.position.top = 0;
|
||||
|
||||
// 生成唯一ID
|
||||
const uuid = Number(Math.random().toString().substr(2)).toString(36);
|
||||
widgetJsonValue.value.widgetId = uuid;
|
||||
widgetJsonValue.value.widgetCode = dragWidgetCode;
|
||||
|
||||
// 获取当前的tabsList(确保使用正确的数据源)
|
||||
let currentTabsList = this.tabsList;
|
||||
|
||||
// 找到对应的tab并添加子组件
|
||||
const targetTab = currentTabsList[tabIndex];
|
||||
if (!targetTab) {
|
||||
console.warn('未找到目标tab');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!targetTab.children) {
|
||||
this.$set(targetTab, 'children', []);
|
||||
}
|
||||
targetTab.children.push(this.deepClone(widgetJsonValue));
|
||||
|
||||
// 更新到setup中
|
||||
this.optionsSetup.tabsList = currentTabsList;
|
||||
|
||||
// 更新value.setup
|
||||
if (!this.value.setup) {
|
||||
this.$set(this.value, 'setup', {});
|
||||
}
|
||||
this.value.setup.tabsList = currentTabsList;
|
||||
|
||||
// 触发更新
|
||||
this.$emit('input', this.value);
|
||||
|
||||
console.log('子组件已添加:', targetTab.children);
|
||||
|
||||
this.grade = false;
|
||||
},
|
||||
/**
|
||||
* 当 drop 落在 Tabs 外层容器(如 avue-draggable)时由设计器调用,将组件加入当前激活的 tab
|
||||
*/
|
||||
addWidgetFromDrop(evt) {
|
||||
if (!evt || !evt.dataTransfer) return;
|
||||
let dragWidgetCode = null;
|
||||
if (evt.dataTransfer.types && evt.dataTransfer.types.indexOf("application/x-widget-code") !== -1) {
|
||||
dragWidgetCode = evt.dataTransfer.getData("application/x-widget-code");
|
||||
}
|
||||
if (!dragWidgetCode) dragWidgetCode = this.getDragWidgetCode();
|
||||
if (!dragWidgetCode) return;
|
||||
|
||||
const tabIndex = this.tabsList.findIndex(
|
||||
(t, i) => (t.name || `tab${i}`) === this.activeTab
|
||||
);
|
||||
const tab = tabIndex >= 0 ? this.tabsList[tabIndex] : this.tabsList[0];
|
||||
const actualIndex = tabIndex >= 0 ? tabIndex : 0;
|
||||
|
||||
const contentEls = this.$el.querySelectorAll("[data-tab-content]");
|
||||
const contentEl = contentEls[actualIndex] || contentEls[0];
|
||||
const rect = contentEl ? contentEl.getBoundingClientRect() : this.$el.getBoundingClientRect();
|
||||
const x = evt.clientX - rect.left;
|
||||
const y = evt.clientY - rect.top;
|
||||
|
||||
const tool = getToolByCode(dragWidgetCode);
|
||||
if (!tool) return;
|
||||
|
||||
const widgetJson = {
|
||||
type: dragWidgetCode,
|
||||
value: {
|
||||
setup: {},
|
||||
data: {},
|
||||
position: { width: 0, height: 0, left: 0, top: 0, zIndex: 0 },
|
||||
},
|
||||
options: this.deepClone(tool.options),
|
||||
};
|
||||
const widgetJsonValue = this.getWidgetConfigValue(widgetJson);
|
||||
// 同样,外层 drop 到 Tabs 上时,内部子组件也从 0 边距起步
|
||||
widgetJsonValue.value.position.left = 0;
|
||||
widgetJsonValue.value.position.top = 0;
|
||||
const uuid = Number(Math.random().toString().substr(2)).toString(36);
|
||||
widgetJsonValue.value.widgetId = uuid;
|
||||
widgetJsonValue.value.widgetCode = dragWidgetCode;
|
||||
|
||||
const currentTabsList = this.tabsList;
|
||||
const targetTab = currentTabsList[actualIndex];
|
||||
if (!targetTab) return;
|
||||
if (!targetTab.children) this.$set(targetTab, "children", []);
|
||||
targetTab.children.push(this.deepClone(widgetJsonValue));
|
||||
|
||||
this.optionsSetup.tabsList = currentTabsList;
|
||||
if (!this.value.setup) this.$set(this.value, "setup", {});
|
||||
this.value.setup.tabsList = currentTabsList;
|
||||
this.$emit("input", this.value);
|
||||
},
|
||||
getDragWidgetCode() {
|
||||
// 尝试从父组件获取dragWidgetCode
|
||||
let parent = this.$parent;
|
||||
while (parent) {
|
||||
if (parent.dragWidgetCode !== undefined) {
|
||||
return parent.dragWidgetCode;
|
||||
}
|
||||
parent = parent.$parent;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
getWidgetConfigValue(widgetJson) {
|
||||
this.setWidgetConfigValue(
|
||||
widgetJson.options.setup,
|
||||
widgetJson.value.setup
|
||||
);
|
||||
this.setWidgetConfigValue(
|
||||
widgetJson.options.position,
|
||||
widgetJson.value.position
|
||||
);
|
||||
this.setWidgetConfigValue(widgetJson.options.data, widgetJson.value.data);
|
||||
return widgetJson;
|
||||
},
|
||||
setWidgetConfigValue(config, configValue) {
|
||||
if (config) {
|
||||
config.forEach((item) => {
|
||||
if (this.isObjectFn(item)) {
|
||||
configValue[item.name] = item.value;
|
||||
}
|
||||
if (this.isArrayFn(item)) {
|
||||
item.forEach((itemChild) => {
|
||||
itemChild.list.forEach((ev) => {
|
||||
configValue[ev.name] = ev.value;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
handleChildWidgetActivated(data) {
|
||||
// 处理子组件激活事件(预留)
|
||||
console.log('子组件激活:', data);
|
||||
},
|
||||
/**
|
||||
* 捕获阶段处理内部子区域 mousedown:先于 avue-draggable 拦截,避免整块 Tabs 被拖动
|
||||
* 点击删除按钮时不拦截,让删除能正常触发
|
||||
*/
|
||||
/**
|
||||
* 根节点捕获:仅当点击在标题栏时发出事件,让设计器拖动整块 Tabs(外层 avue-draggable 已禁用)
|
||||
*/
|
||||
onTabsRootCapture(evt) {
|
||||
if (this.ispreview || !evt.target || !evt.target.closest) return;
|
||||
const headerEl = evt.target.closest(".el-tabs__header");
|
||||
if (headerEl) {
|
||||
// 点击在 Tabs 头部:阻止事件冒泡到外层 draggable,并通知外层开始拖动整块 Tabs
|
||||
evt.stopPropagation();
|
||||
this.$emit("tabsHeaderMouseDown", evt);
|
||||
}
|
||||
},
|
||||
onTabChildMouseDown(event, tabIndex, childIndex) {
|
||||
if (event.target && event.target.closest && event.target.closest('.tab-child-delete')) {
|
||||
return; // 点在删除按钮上,不拦截,删除按钮的 @mousedown.stop 会阻止冒泡到外层
|
||||
}
|
||||
console.log('onTabChildMouseDown:', tabIndex, childIndex);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
// 选中内部组件并通知外层暂时禁用拖拽
|
||||
this.emitChildActivated(tabIndex, childIndex);
|
||||
this.$emit('innerDragStart');
|
||||
this.startChildDrag(event, childIndex, tabIndex);
|
||||
},
|
||||
/**
|
||||
* 开始拖拽标签内子组件(可由 onTabChildMouseDown 或 workbench 捕获层调用)
|
||||
*/
|
||||
startChildDrag(event, childIndex, tabIndex) {
|
||||
this.$emit('innerDragStart');
|
||||
const currentTabsList = this.tabsList;
|
||||
const targetTab = currentTabsList[tabIndex];
|
||||
if (!targetTab || !targetTab.children || !targetTab.children[childIndex]) return;
|
||||
|
||||
const child = targetTab.children[childIndex];
|
||||
if (!child.value.position) {
|
||||
this.$set(child.value, 'position', {});
|
||||
}
|
||||
const pos = child.value.position;
|
||||
|
||||
const startLeft = typeof pos.left === 'number' ? pos.left : 0;
|
||||
const startTop = typeof pos.top === 'number' ? pos.top : 0;
|
||||
|
||||
this.draggingChild = {
|
||||
tabIndex,
|
||||
childIndex,
|
||||
startX: event.clientX,
|
||||
startY: event.clientY,
|
||||
startLeft,
|
||||
startTop,
|
||||
};
|
||||
|
||||
// 选中效果
|
||||
this.grade = true;
|
||||
|
||||
// 绑定全局鼠标事件
|
||||
this.childDragMoveHandler = (e) => this.onChildDragMove(e);
|
||||
this.childDragUpHandler = (e) => this.onChildDragEnd(e);
|
||||
document.addEventListener('mousemove', this.childDragMoveHandler);
|
||||
document.addEventListener('mouseup', this.childDragUpHandler);
|
||||
},
|
||||
/**
|
||||
* 拖拽过程中移动子组件
|
||||
*/
|
||||
onChildDragMove(event) {
|
||||
if (!this.draggingChild) return;
|
||||
|
||||
const { tabIndex, childIndex, startX, startY, startLeft, startTop } = this.draggingChild;
|
||||
const dx = event.clientX - startX;
|
||||
const dy = event.clientY - startY;
|
||||
|
||||
const currentTabsList = this.tabsList;
|
||||
const targetTab = currentTabsList[tabIndex];
|
||||
if (!targetTab || !targetTab.children || !targetTab.children[childIndex]) return;
|
||||
|
||||
const child = targetTab.children[childIndex];
|
||||
if (!child.value.position) {
|
||||
this.$set(child.value, 'position', {});
|
||||
}
|
||||
const pos = child.value.position;
|
||||
const width = pos.width || 100;
|
||||
const height = pos.height || 50;
|
||||
|
||||
let newLeft = startLeft + dx;
|
||||
let newTop = startTop + dy;
|
||||
|
||||
// 约束在 tab 内容区域内部
|
||||
if (newLeft < 0) newLeft = 0;
|
||||
if (newTop < 0) newTop = 0;
|
||||
if (newLeft + width > this.optionsStyle.width) {
|
||||
newLeft = this.optionsStyle.width - width;
|
||||
}
|
||||
if (newTop + height > this.optionsStyle.height) {
|
||||
newTop = this.optionsStyle.height - height;
|
||||
}
|
||||
|
||||
this.$set(pos, 'left', newLeft);
|
||||
this.$set(pos, 'top', newTop);
|
||||
|
||||
// 实时同步到配置,保证保存后位置不丢
|
||||
this.optionsSetup.tabsList = currentTabsList;
|
||||
if (!this.value.setup) {
|
||||
this.$set(this.value, 'setup', {});
|
||||
}
|
||||
this.value.setup.tabsList = currentTabsList;
|
||||
this.$emit('input', this.value);
|
||||
},
|
||||
/**
|
||||
* 结束拖拽
|
||||
*/
|
||||
onChildDragEnd() {
|
||||
if (this.childDragMoveHandler) {
|
||||
document.removeEventListener('mousemove', this.childDragMoveHandler);
|
||||
this.childDragMoveHandler = null;
|
||||
}
|
||||
if (this.childDragUpHandler) {
|
||||
document.removeEventListener('mouseup', this.childDragUpHandler);
|
||||
this.childDragUpHandler = null;
|
||||
}
|
||||
this.draggingChild = null;
|
||||
// 通知外层 Widget:内部拖拽结束,恢复外层 avue-draggable
|
||||
this.$emit("innerDragEnd");
|
||||
},
|
||||
// 将组件类型字符串转换为组件名称
|
||||
getComponentName(type) {
|
||||
// 将 widget-text 转换为 widgetText
|
||||
if (!type) return '';
|
||||
return type.split('-').map((part, index) => {
|
||||
if (index === 0) return part;
|
||||
return part.charAt(0).toUpperCase() + part.slice(1);
|
||||
}).join('');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.widget-tabs {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
::v-deep .el-tabs {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.el-tabs__header {
|
||||
margin: 0;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.el-tabs__content {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.el-tab-pane {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.tab-child-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tab-child-select-handle {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -2px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
z-index: 30;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tab-child-select-handle:hover {
|
||||
background: rgba(64, 158, 255, 0.9);
|
||||
}
|
||||
|
||||
.tab-child-select-icon {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.tab-child-component {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tab-content-empty {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
border: 2px dashed #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
:value="value"
|
||||
:ispreview="true"
|
||||
:widget-index="index"
|
||||
@oepnTheDrillView="$emit('oepnTheDrillView',$event)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -58,7 +59,6 @@ import widgetChinaMap from "./map/widgetChinaMap.vue";
|
||||
import widgetGlobalMap from "./map/widgetGlobalMap.vue";
|
||||
import widgetBarStackMoreShowChart from "./bar/widgetBarStackMoreShowChart.vue";
|
||||
import widgetBarLineSingleChart from "./barline/widgetBarLineSingleChart.vue";
|
||||
|
||||
export default {
|
||||
name: "WidgetTemp",
|
||||
components: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="imagebox" :style="styleColor">
|
||||
<div class="imagebox" :style="styleColor" @click="handleClick" >
|
||||
<img
|
||||
:class="transStyle.startRotate ? 'startImg' : ''"
|
||||
:style="imgStyle"
|
||||
@@ -18,7 +18,8 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: {}
|
||||
options: {},
|
||||
optionsSetup:{}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -50,15 +51,26 @@ export default {
|
||||
value: {
|
||||
handler(val) {
|
||||
this.options = val;
|
||||
this.optionsSetup = val.setup;
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.options = this.value;
|
||||
this.optionsSetup = this.value.setup;
|
||||
},
|
||||
mounted() {},
|
||||
methods: {}
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
handleClick(){
|
||||
console.log(this.optionsSetup)
|
||||
if(!!this.optionsSetup.is_drill_drown){
|
||||
this.$emit('oepnTheDrillView',this.optionsSetup.drill_drown_setting)
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -3,26 +3,45 @@
|
||||
<superslide v-if="hackReset" :options="options" class="txtScroll-top" ref="superslide">
|
||||
<!--表头-->
|
||||
<div class="title">
|
||||
<div
|
||||
v-if="isIndex"
|
||||
:style="[headerTableStyle,{width:'50px',flexShrink: 0}, tableRowHeight()]">
|
||||
序号
|
||||
</div>
|
||||
<div v-for="(item, index) in header" :key="index"
|
||||
:style="[headerTableStyle, tableFiledWidth(index), tableRowHeight()]">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
<!--数据-->
|
||||
<div class="bd">
|
||||
<div class="bd" @click="handleClick">
|
||||
<ul class="infoList">
|
||||
<li v-for="(item, index) in list" :key="index" :style="tableRowHeight()">
|
||||
<div v-for="(itemChild, idx) in header"
|
||||
<li v-for="(item, index) in list" :key="index" :style="tableRowHeight()">
|
||||
<div
|
||||
@mouseenter="handleMouseSeen(index, -1)" @mouseleave="handleMouseLeave"
|
||||
v-if="isIndex"
|
||||
:style="[
|
||||
bodyTableStyle,
|
||||
tableReadColor(index, -1),{width:'50px',flexShrink: 0},
|
||||
bodyTable(index),
|
||||
tableRowHeight()
|
||||
]"
|
||||
>
|
||||
{{ index + 1 }}
|
||||
</div>
|
||||
<div @mouseenter="handleMouseSeen(index, idx)" @mouseleave="handleMouseLeave" v-for="(itemChild, idx) in header"
|
||||
:key="idx"
|
||||
:style="[
|
||||
bodyTableStyle,
|
||||
bodyTable(index),
|
||||
tableFiledWidth(idx),
|
||||
tableReadColor(index, idx),
|
||||
tableRowHeight()
|
||||
]"
|
||||
>
|
||||
{{ item[itemChild.key] }}
|
||||
</div>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -98,10 +117,12 @@ export default {
|
||||
},
|
||||
header: [],
|
||||
list: [],
|
||||
hoverIndex: {},
|
||||
optionsSetUp: {},
|
||||
optionsPosition: {},
|
||||
optionsData: {},
|
||||
flagInter: null,
|
||||
isIndex: false,
|
||||
// 新增导出对话框相关数据
|
||||
exportDialogVisible: false,
|
||||
exporting: false,
|
||||
@@ -131,6 +152,7 @@ export default {
|
||||
},
|
||||
headerTableStyle() {
|
||||
const headStyle = this.optionsSetUp;
|
||||
this.isIndex=headStyle.isIndex
|
||||
return {
|
||||
"text-align": headStyle.textAlignHeader,
|
||||
"font-size": headStyle.fontSizeHeader + "px",
|
||||
@@ -216,6 +238,7 @@ export default {
|
||||
value: {
|
||||
handler(val) {
|
||||
this.optionsSetUp = val.setup;
|
||||
|
||||
this.optionsPosition = val.position;
|
||||
this.optionsData = val.data;
|
||||
this.initData();
|
||||
@@ -238,6 +261,17 @@ export default {
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
},
|
||||
methods: {
|
||||
handleMouseSeen(index, idx){
|
||||
this.hoverIndex = {index, idx}
|
||||
},
|
||||
handleMouseLeave(){
|
||||
this.hoverIndex = {}
|
||||
},
|
||||
handleClick(){
|
||||
if(!!this.optionsSetUp.is_drill_drown){
|
||||
this.$emit('oepnTheDrillView',this.optionsSetUp.drill_drown_setting)
|
||||
}
|
||||
},
|
||||
initData() {
|
||||
this.handlerRollFn();
|
||||
this.handlerHead();
|
||||
@@ -341,6 +375,14 @@ export default {
|
||||
}
|
||||
return styleJson;
|
||||
},
|
||||
tableReadColor(index, idx){
|
||||
let styleJson = {};
|
||||
if (this.optionsSetUp.is_read_mode && (this.hoverIndex.index === index || this.hoverIndex.idx === idx)) {
|
||||
styleJson["background-color"] = this.optionsSetUp.read_color;console.log(styleJson["background-color"],this.hoverIndex,1231231)
|
||||
}
|
||||
|
||||
return styleJson;
|
||||
},
|
||||
// 添加的方法 - 设备类型检测
|
||||
checkDeviceType() {
|
||||
this.screenWidth = window.innerWidth;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @Last Modified time: 2022-3-14 14:04:24
|
||||
!-->
|
||||
<template>
|
||||
<div class="text" :style="computedStyleColor">{{ styleColor.text }}</div>
|
||||
<div class="text" @click="handleClick" :style="computedStyleColor">{{ styleColor.text }}</div>
|
||||
</template>
|
||||
<script>
|
||||
import {targetWidgetLinkageLogic} from "@/views/bigscreenDesigner/designer/linkageLogic";
|
||||
@@ -84,6 +84,11 @@ export default {
|
||||
this.setOptionsData();
|
||||
},
|
||||
methods: {
|
||||
handleClick(){
|
||||
if(!!this.optionsSetup.is_drill_drown){
|
||||
this.$emit('oepnTheDrillView',this.optionsSetup.drill_drown_setting)
|
||||
}
|
||||
},
|
||||
// 根据条件应用样式
|
||||
getConditionalStyle() {
|
||||
const setup = this.optionsSetup || {};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<avue-draggable
|
||||
:data-widget-index="index"
|
||||
:step="step"
|
||||
:width="widgetsWidth"
|
||||
:height="widgetsHeight"
|
||||
@@ -12,7 +13,16 @@
|
||||
@blur="handleBlur"
|
||||
>
|
||||
<!-- :z-index="-1" -->
|
||||
<component :is="type" :widget-index="index" :value="value"/>
|
||||
<component
|
||||
:is="type"
|
||||
:widget-index="index"
|
||||
:value="value"
|
||||
@childActivated="handleChildActivated"
|
||||
@innerDragStart="handleInnerDragStart"
|
||||
@innerDragEnd="handleInnerDragEnd"
|
||||
@tabsHeaderMouseDown="handleTabsHeaderMouseDown"
|
||||
@tabsContentDblClick="handleTabsContentDblClick"
|
||||
/>
|
||||
</avue-draggable>
|
||||
</template>
|
||||
|
||||
@@ -20,6 +30,7 @@
|
||||
import widgetHref from "./texts/widgetHref.vue";
|
||||
import widgetText from "./texts/widgetText.vue";
|
||||
import widgetButton from './form/widgetButton.vue';
|
||||
import widgetTabs from './form/widgetTabs.vue';
|
||||
import WidgetMarquee from "./texts/widgetMarquee.vue";
|
||||
import widgetTime from "./texts/widgetTime.vue";
|
||||
import widgetImage from "./texts/widgetImage.vue";
|
||||
@@ -72,6 +83,7 @@ export default {
|
||||
widgetHref,
|
||||
widgetText,
|
||||
widgetButton,
|
||||
widgetTabs,
|
||||
widgetBorder,
|
||||
widgetDecorateFlowLine,
|
||||
widgetDecoration,
|
||||
@@ -146,6 +158,8 @@ export default {
|
||||
/* leftMargin: null,
|
||||
topMargin: null*/
|
||||
},
|
||||
// 当 Tabs 内部拖拽子组件时,暂时禁用外层 avue-draggable,防止整个 Tabs 被拖动
|
||||
innerDragging: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -165,7 +179,10 @@ export default {
|
||||
return this.value.position.zIndex || 1;
|
||||
},
|
||||
widgetDisabled() {
|
||||
return this.value.position.disabled || false;
|
||||
// 统一走一套逻辑:
|
||||
// - 当内部子组件正在拖拽时禁用外层拖拽,避免误拖整块组件
|
||||
// - 其余情况按组件自身的 disabled 控制
|
||||
return this.value.position.disabled || this.innerDragging || false;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
@@ -218,6 +235,32 @@ export default {
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 接收 Tabs 内部子组件发出的激活事件,并转发给设计器主页面
|
||||
*/
|
||||
handleChildActivated(payload) {
|
||||
console.log('handleChildActivated in widget.vue:', payload);
|
||||
const info = Object.assign({}, payload || {});
|
||||
if (info.rootWidgetIndex === undefined || info.rootWidgetIndex === null) {
|
||||
info.rootWidgetIndex = this.index;
|
||||
}
|
||||
this.$emit("onChildActivated", info);
|
||||
},
|
||||
// Tabs 内部开始拖拽/点击子组件时,暂时禁用外层拖拽
|
||||
handleInnerDragStart() {
|
||||
this.innerDragging = true;
|
||||
},
|
||||
handleInnerDragEnd() {
|
||||
this.innerDragging = false;
|
||||
},
|
||||
handleTabsHeaderMouseDown(evt) {
|
||||
this.$emit('onTabsHeaderMouseDown', { event: evt, rootWidgetIndex: this.index });
|
||||
},
|
||||
// Tabs 内容区双击空白时,也视为选中整个 Tabs
|
||||
handleTabsContentDblClick(payload) {
|
||||
if (!payload || !payload.event) return;
|
||||
this.$emit('onTabsHeaderMouseDown', { event: payload.event, rootWidgetIndex: this.index });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
159
src/views/bigscreenDesigner/viewer/drillDrownView.vue
Normal file
159
src/views/bigscreenDesigner/viewer/drillDrownView.vue
Normal file
@@ -0,0 +1,159 @@
|
||||
<!--
|
||||
* @Descripttion: 大屏设计器 -- 预览
|
||||
* @Author: Devli
|
||||
* @Date: 2021-3-13 11:04:24
|
||||
* @Last Modified by: Raod
|
||||
* @Last Modified time: 2022-5-6 11:04:24
|
||||
!-->
|
||||
<template>
|
||||
<div class="layout drillDrownViewLayout">
|
||||
<div :style="bigScreenStyle">
|
||||
<widget
|
||||
v-for="(widget, index) in widgets"
|
||||
:key="index"
|
||||
v-model="widget.value"
|
||||
:index="index"
|
||||
:type="widget.type"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import widget from "../designer/widget/temp";
|
||||
import { detailDashboard } from "@/api/bigscreen";
|
||||
export default {
|
||||
name: "Login",
|
||||
components: {
|
||||
widget
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
bigScreenStyle: {},
|
||||
dashboard:{},
|
||||
widgets: [],
|
||||
viewData:{}
|
||||
};
|
||||
},
|
||||
props:{
|
||||
screenData:{
|
||||
type:Object,
|
||||
default:()=>{
|
||||
return {
|
||||
dashboard: { },
|
||||
widgets: []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
screenData: {
|
||||
handler(val) {
|
||||
this.viewData=val
|
||||
this.getData();
|
||||
},
|
||||
deep: true,
|
||||
immediate:true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.viewData=this.screenData
|
||||
this.getData();
|
||||
window.onresize=this.Debounce(this.setScale,500);
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
const data = {dashboard:{...this.viewData.dashboard,...this.viewData},widgets:null};
|
||||
this.dashboard=data.dashboard||{};
|
||||
const equipment = document.body.clientWidth;
|
||||
const ratioEquipment = equipment / data.dashboard.width;
|
||||
this.bigScreenStyle = {
|
||||
width: data.dashboard.width + "px",
|
||||
height: data.dashboard.height + "px",
|
||||
"background-color": data.dashboard.backgroundColor,
|
||||
"background-image": "url(" + data.dashboard.backgroundImage + ")",
|
||||
"background-position": "0% 0%",
|
||||
"background-size": "100% 100%",
|
||||
"background-repeat": "initial",
|
||||
"background-attachment": "initial",
|
||||
"background-origin": "initial",
|
||||
"background-clip": "initial",
|
||||
transform: `scale(${ratioEquipment}, ${ratioEquipment})`,
|
||||
"transform-origin": "0 0"
|
||||
};
|
||||
data.dashboard.widgets.forEach((item, index) => {
|
||||
item.value.widgetId = item.value.setup.widgetId
|
||||
item.value.widgetCode = item.value.setup.widgetCode
|
||||
if (item.value.setup.componentLinkage && item.value.setup.componentLinkage.length) {
|
||||
this.$store.commit('SET_ALL_COMPONENT_LINKAGE', {
|
||||
index,
|
||||
widgetId: item.value.widgetId,
|
||||
linkageArr: item.value.setup.componentLinkage
|
||||
})
|
||||
}
|
||||
})
|
||||
this.widgets = data.dashboard.widgets;
|
||||
|
||||
// 定时刷新
|
||||
if(data.dashboard.refreshSeconds>0) {
|
||||
setTimeout(function(){ window.location.reload(); }, data.dashboard.refreshSeconds*1000);
|
||||
}
|
||||
},
|
||||
Debounce:(fn,t)=>{
|
||||
const delay=t||500;
|
||||
let timer=null;
|
||||
return(...args)=>{
|
||||
if(timer){
|
||||
clearTimeout(timer);
|
||||
}
|
||||
const context=this
|
||||
timer=setTimeout(()=>{
|
||||
fn.apply(context,args);
|
||||
},delay);
|
||||
}
|
||||
},
|
||||
setScale(){
|
||||
const scale=this.getScale();
|
||||
this.bigScreenStyle.transform='scale('+scale.scalex+','+scale.scaley+')'
|
||||
},
|
||||
getScale(){
|
||||
let width = this.dashboard.width
|
||||
let height = this.dashboard.height
|
||||
// 固定宽度比例
|
||||
const scalex = window.innerWidth / width
|
||||
// 高度按相同比例缩放,但允许超出屏幕高度
|
||||
const scaley = scalex
|
||||
return {
|
||||
scalex,
|
||||
scaley
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.layout {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.drillDrownViewLayout{
|
||||
min-height: calc(100vh - 34px) !important;
|
||||
overflow-y:auto !important;
|
||||
&::-webkit-scrollbar {
|
||||
display: none; /* 隐藏滚动条 */
|
||||
}
|
||||
}
|
||||
.bottom-text {
|
||||
width: 100%;
|
||||
color: #a0a0a0;
|
||||
position: fixed;
|
||||
bottom: 16px;
|
||||
z-index: 9999;
|
||||
}
|
||||
.drillDrownViewLayout{
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -14,24 +14,39 @@
|
||||
v-model="widget.value"
|
||||
:index="index"
|
||||
:type="widget.type"
|
||||
@oepnTheDrillView="oepnTheDrillView"
|
||||
/>
|
||||
</div>
|
||||
<el-dialog
|
||||
:title="''"
|
||||
class="dialogDrillDrown dialogDrillDrownView" :visible.sync="visiableDrillView">
|
||||
<drill-drown-view :screenData="screenData"></drill-drown-view>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import widget from "../designer/widget/temp";
|
||||
import DrillDrownView from "./drillDrownView";
|
||||
|
||||
import { detailDashboard } from "@/api/bigscreen";
|
||||
export default {
|
||||
name: "Login",
|
||||
components: {
|
||||
widget
|
||||
widget,
|
||||
DrillDrownView
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bigScreenStyle: {},
|
||||
dashboard:{},
|
||||
widgets: []
|
||||
widgets: [],
|
||||
screenData:{
|
||||
dashboard: { },
|
||||
widgets: []
|
||||
},
|
||||
visiableDrillView:false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
@@ -39,6 +54,10 @@ export default {
|
||||
window.onresize=this.Debounce(this.setScale,500);
|
||||
},
|
||||
methods: {
|
||||
oepnTheDrillView(val){
|
||||
this.screenData=val
|
||||
this.visiableDrillView=true
|
||||
},
|
||||
async getData() {
|
||||
const reportCode = this.$route.query.reportCode;
|
||||
const { code, data } = await detailDashboard(reportCode);
|
||||
@@ -114,8 +133,24 @@ export default {
|
||||
<style lang="scss">
|
||||
.layout {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
.dialogDrillDrownView .el-dialog{
|
||||
width:auto;
|
||||
margin-top:0 !important;
|
||||
.el-dialog__body{
|
||||
padding:0;
|
||||
max-height:calc(100vh - 34px);
|
||||
overflow:auto;
|
||||
&::-webkit-scrollbar {
|
||||
display: none; /* 隐藏滚动条 */
|
||||
}
|
||||
}
|
||||
.el-dialog__header .el-dialog__headerbtn{
|
||||
top: 6px;
|
||||
}
|
||||
}
|
||||
.bottom-text {
|
||||
width: 100%;
|
||||
|
||||
@@ -82,6 +82,8 @@ import Hamburger from "@/components/Hamburger";
|
||||
import { getStorageItem } from "@/utils/storage";
|
||||
import { reqUpdatePassword } from "@/api/login";
|
||||
import { transPsw } from "@/utils/encrypted";
|
||||
import {getAccessUser} from "@/utils/auth";
|
||||
import {outlogcas} from "@/api/login";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -156,11 +158,34 @@ export default {
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
sessionStorage.clear();
|
||||
localStorage.clear();
|
||||
this.$router.push("/login");
|
||||
debugger
|
||||
//获取登录人
|
||||
let user = getAccessUser()
|
||||
console.log(user.loginName)
|
||||
debugger
|
||||
|
||||
|
||||
this.outlogincasapi();
|
||||
debugger
|
||||
console.log(user.loginName)
|
||||
// sessionStorage.clear();
|
||||
// localStorage.clear();
|
||||
// this.$router.push("/login");
|
||||
});
|
||||
},
|
||||
async outlogincasapi() {
|
||||
debugger
|
||||
const obj = {
|
||||
loginName: "admin",
|
||||
password: "demo",
|
||||
verifyCode: "",
|
||||
};
|
||||
const { code, data } = await outlogcas(obj);
|
||||
sessionStorage.clear();
|
||||
localStorage.clear();
|
||||
this.$router.push("/login");
|
||||
|
||||
},
|
||||
// 修改密码
|
||||
updatePassword() {
|
||||
this.wordVisible = true;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
|
||||
<template>
|
||||
<div class="login_container">
|
||||
|
||||
<div class="login_contant">
|
||||
<img src="@/assets/images/login.jpg" alt="image" class="login_img" />
|
||||
<el-form
|
||||
@@ -13,28 +11,25 @@
|
||||
label-position="left"
|
||||
@keyup.enter.native="handleLogin"
|
||||
>
|
||||
<div class="title_container">
|
||||
智慧大屏
|
||||
</div>
|
||||
<div style="height: 30px;"></div>
|
||||
<div class="title_container">国瑞药业驾驶舱平台</div>
|
||||
<div style="height: 30px"></div>
|
||||
<div class="form_fields">
|
||||
|
||||
<el-form-item prop="loginName">
|
||||
<el-input
|
||||
ref="loginName"
|
||||
v-model="loginForm.loginName"
|
||||
placeholder="用户名"
|
||||
name="loginName"
|
||||
type="text"
|
||||
tabindex="1"
|
||||
autocomplete="on"
|
||||
@focus="setTop('0')"
|
||||
@change="getPsw"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="loginName">
|
||||
<el-input
|
||||
ref="loginName"
|
||||
v-model="loginForm.loginName"
|
||||
placeholder="用户名"
|
||||
name="loginName"
|
||||
type="text"
|
||||
tabindex="1"
|
||||
autocomplete="on"
|
||||
@focus="setTop('0')"
|
||||
@change="getPsw"
|
||||
/>
|
||||
</el-form-item>
|
||||
<div>
|
||||
<div style="height: 20px;"></div>
|
||||
|
||||
<div style="height: 20px"></div>
|
||||
|
||||
<input
|
||||
name="password"
|
||||
type="password"
|
||||
@@ -62,7 +57,7 @@
|
||||
@keyup.native="checkCapslock"
|
||||
/>
|
||||
<span class="show_pwd" @click="showPwd">
|
||||
<div style="height: 10px;"></div>
|
||||
<div style="height: 10px"></div>
|
||||
<i class="el-icon-view" />
|
||||
</span>
|
||||
</el-form-item>
|
||||
@@ -75,13 +70,13 @@
|
||||
<p>记住密码</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 30px;"></div>
|
||||
<div style="height: 30px"></div>
|
||||
<el-button
|
||||
:loading="loading"
|
||||
type="primary"
|
||||
class="login_btn"
|
||||
@click.native.prevent="handleLogin"
|
||||
>登 录</el-button
|
||||
>登 录</el-button
|
||||
>
|
||||
</el-form>
|
||||
</div>
|
||||
@@ -100,13 +95,14 @@
|
||||
import Verify from "@/components/verifition/Verify";
|
||||
import cookies from "js-cookie";
|
||||
import { Decrypt, Encrypt } from "@/utils/index";
|
||||
import { login } from "@/api/login";
|
||||
import { login, logincas } from "@/api/login";
|
||||
import { transPsw } from "@/utils/encrypted";
|
||||
import { setToken, setAccessUser } from "@/utils/auth";
|
||||
import { setToken, getToken, setAccessUser } from "@/utils/auth";
|
||||
|
||||
export default {
|
||||
name: "Login",
|
||||
components: {
|
||||
Verify
|
||||
Verify,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -115,11 +111,13 @@ export default {
|
||||
loginForm: {
|
||||
loginName: "",
|
||||
password: "",
|
||||
verifyCode: ""
|
||||
verifyCode: "",
|
||||
},
|
||||
loginRules: {
|
||||
loginName: [{ required: true, message: "用户名必填", trigger: "blur" }],
|
||||
password: [{ required: true, message: "用户密码必填", trigger: "blur" }]
|
||||
password: [
|
||||
{ required: true, message: "用户密码必填", trigger: "blur" },
|
||||
],
|
||||
},
|
||||
passwordType: "password",
|
||||
capsTooltip: false,
|
||||
@@ -127,25 +125,45 @@ export default {
|
||||
redirect: undefined,
|
||||
otherQuery: {},
|
||||
needCaptcha: false,
|
||||
centerDialogVisible: false
|
||||
centerDialogVisible: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
// 监听路由获取上个路由(from)的地址和参数
|
||||
handler: function(route) {
|
||||
handler: function (route) {
|
||||
const query = route.query;
|
||||
if (query) {
|
||||
this.redirect = query.redirect;
|
||||
this.otherQuery = this.getOtherQuery(query);
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.handleLoginFocus();
|
||||
//获取url传参 ticket url
|
||||
const ticket = this.$route.query.ticket;
|
||||
let token = getToken();
|
||||
console.log(ticket);
|
||||
console.log(token);
|
||||
if (ticket == undefined && token == null) {
|
||||
//跳转统一身份认证
|
||||
var isTs = true;
|
||||
if (isTs) {
|
||||
window.location.href = 'http://192.168.1.241/login?redirect=/lig/oauth2/oauth2/application&appid=330b4ecb60c9a6802b957fe1e5a5ecd3&url=http%3A%2F%2F192.168.1.241%3A8080%2F%23%2Flogin'+(this.redirect?'&ssUrl='+this.redirect:'');
|
||||
// window.location.href = 'http://localhost/login?redirect=/lig/oauth2/oauth2/application&appid=330b4ecb60c9a6802b957fe1e5a5ecd3&url=http%3A%2F%2Flocalhost%3A9528%2F%23%2Flogin'+(this.redirect?'&ssUrl='+this.redirect:'');
|
||||
|
||||
}
|
||||
} else if (ticket != undefined && token == null) {
|
||||
//请求登录
|
||||
this.logincasapi();
|
||||
} else {
|
||||
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
methods: {
|
||||
handleLoginFocus() {
|
||||
if (this.loginForm.loginName === "") {
|
||||
@@ -181,7 +199,7 @@ export default {
|
||||
},
|
||||
// 滑动验证码
|
||||
useVerify() {
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
this.$refs.loginForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$refs.verify.show();
|
||||
} else {
|
||||
@@ -198,7 +216,7 @@ export default {
|
||||
},
|
||||
// 登录操作
|
||||
handleLogin() {
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
this.$refs.loginForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.loading = true;
|
||||
// 登录失败次数过多需要展示滑动验证码
|
||||
@@ -212,11 +230,41 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
async logincasapi() {
|
||||
const ticket = this.$route.query.ticket;
|
||||
const obj = {
|
||||
loginName: ticket,
|
||||
password: "demo",
|
||||
verifyCode: "",
|
||||
};
|
||||
const { code, data } = await logincas(obj);
|
||||
this.loading = false;
|
||||
if (code != "200") return;
|
||||
setToken(data.token);
|
||||
setAccessUser(data);
|
||||
debugger
|
||||
// 选中记住密码时 把密码存到cookie里,时效15天
|
||||
this.rememberPsw &&
|
||||
cookies.set(
|
||||
`u_${this.loginForm.loginName}`,
|
||||
Encrypt(this.loginForm.password),
|
||||
{ expires: 15 }
|
||||
);
|
||||
if (data && data.captcha) {
|
||||
this.needCaptcha = true;
|
||||
} else {
|
||||
this.needCaptcha = false;
|
||||
this.$router.push({
|
||||
path: this.redirect || "/index",
|
||||
query: this.otherQuery,
|
||||
});
|
||||
}
|
||||
},
|
||||
async loginApi() {
|
||||
const obj = {
|
||||
loginName: this.loginForm.loginName,
|
||||
password: transPsw(this.loginForm.password),
|
||||
verifyCode: ""
|
||||
verifyCode: "",
|
||||
};
|
||||
const { code, data } = await login(obj);
|
||||
this.loading = false;
|
||||
@@ -236,7 +284,7 @@ export default {
|
||||
this.needCaptcha = false;
|
||||
this.$router.push({
|
||||
path: this.redirect || "/index",
|
||||
query: this.otherQuery
|
||||
query: this.otherQuery,
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -247,8 +295,8 @@ export default {
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -260,15 +308,14 @@ export default {
|
||||
opacity: 10;
|
||||
background: #fff;
|
||||
}
|
||||
.delete {
|
||||
color: #fff;
|
||||
}
|
||||
.delete {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.login_container {
|
||||
.el-input {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
@@ -345,7 +392,7 @@ export default {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
//height: calc(100% - 60px);
|
||||
height: 100%;
|
||||
height: 100%;
|
||||
.login_img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
@@ -359,22 +406,21 @@ export default {
|
||||
min-width: 460px;
|
||||
width: 22%;
|
||||
height: 400px;
|
||||
background-color: #006DD9;
|
||||
background-color: #006dd9;
|
||||
opacity: 0.6;
|
||||
padding: 30px;
|
||||
overflow: hidden;
|
||||
.title_container {
|
||||
position: relative;
|
||||
font-size: 22px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
.form_fields {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
|
||||
|
||||
.show_pwd {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
@@ -427,7 +473,7 @@ export default {
|
||||
.login_btn {
|
||||
min-width: 400px;
|
||||
height: 40px;
|
||||
background: #0BA1F8;
|
||||
background: #0ba1f8;
|
||||
border: none;
|
||||
// border-radius: 10px;
|
||||
font-size: 20px;
|
||||
|
||||
Reference in New Issue
Block a user