Commit d3631b1e by 郁子恒

新增json导出功能

parent d172cacb
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -29,6 +29,7 @@
},
"dependencies": {
"element-ui": "^2.5.4",
"file-saver": "^2.0.5",
"jquery": "^3.7.1",
"less": "^3.9.0",
"less-loader": "^4.1.0",
......
......@@ -2,8 +2,7 @@
<!-- <router-view></router-view>
-->
<div id="realcontent">
<div id="EasySpiderResizer"
style="width: 10px; height: 10px; position: absolute; left: 0; top: 0; cursor: nw-resize;"> </div>
<div id="EasySpiderResizer" style="width: 10px; height: 10px; position: absolute; left: 0; top: 0; cursor: nw-resize;"> </div>
<div>
<!-- 页头信息 -->
<div class="tooldrag">
......@@ -23,8 +22,7 @@
</div>
</div>
<div style="display: flex;flex-direction: column;">
<el-button size="mini" style="width: 60px;height: 25px;margin-bottom: 5px;margin-left: 10px;"
@click="submitPlan">保存任务</el-button>
<el-button size="mini" style="width: 60px;height: 25px;margin-bottom: 5px;margin-left: 10px;" @click="submitPlan">保存任务</el-button>
<el-button size="mini" style="width: 60px;height: 25px;" @click="newAction">新建动作</el-button>
</div>
</div>
......@@ -39,32 +37,25 @@
</div>
</div>
<!-- 动作标签 -->
<div
style="margin-bottom: 5px;margin-left: 15px;margin-right: 15px;width: 470px;overflow: auto;white-space: nowrap;display: flex;padding-top: 5px;">
<div style="margin-bottom: 5px;margin-left: 15px;margin-right: 15px;width: 470px;overflow: auto;white-space: nowrap;display: flex;padding-top: 5px;">
<!-- <el-button @click="goback">返回</el-button> -->
<draggable v-model="treeNode" chosenClass="chosen" forceFallback="true" group="people" animation="1000"
@start="onStart" @end="onEnd" v-if="isChildrenTree == false">
<draggable v-model="treeNode" chosenClass="chosen" forceFallback="true" group="people" animation="1000" @start="onStart" @end="onEnd" v-if="isChildrenTree == false">
<transition-group>
<!-- <div class="item" v-for="element in myArray" :key="element.id">{{ element.name }}</div> -->
<el-tag class="boxtags" :key="tag.tagId" v-for="(tag, index) in treeNode" @click="selectTag(tag)">
<el-tag class="boxtags" :key="tag.tagId" v-for="tag in treeNode" @click="selectTag(tag)">
<div style="display: flex;align-items: center;height: 30px;position: relative;">
<span style="margin-left: 3px;min-width: 20px;">{{ 1+tag.actionName }}</span>
<img id="closeimg" @click="handleClose(tag)"
style="width: 20px;position: absolute;top: -8px;right: -18px;" src="./assets/close.png">
<span style="margin-left: 3px;min-width: 20px;">{{ 1 + tag.actionName }}</span>
<img id="closeimg" @click="handleClose(tag)" style="width: 20px;position: absolute;top: -8px;right: -18px;" src="./assets/close.png">
</div>
</el-tag>
</transition-group>
</draggable>
<draggable v-model="childrenTreeNode" chosenClass="chosen" forceFallback="true" group="people"
animation="1000" @start="onStart" @end="onEnd" v-if="isChildrenTree == true">
<draggable v-model="childrenTreeNode" chosenClass="chosen" forceFallback="true" group="people" animation="1000" @start="onStart" @end="onEnd" v-if="isChildrenTree == true">
<transition-group>
<el-tag class="boxtags" :key="item.tagId" v-for="(item, index) in childrenTreeNode"
@click="selectTag(item)">
<el-tag class="boxtags" :key="item.tagId" v-for="item in childrenTreeNode" @click="selectTag(item)">
<div style="display: flex;align-items: center;height: 30px;position: relative;">
<span style="margin-left: 3px;">{{2+ item.actionName }}</span>
<img id="closeimg" @click="handleClose(item)"
style="width: 20px;position: absolute;top: -8px;right: -18px;" src="./assets/close.png">
<span style="margin-left: 3px;">{{ 2 + item.actionName }}</span>
<img id="closeimg" @click="handleClose(item)" style="width: 20px;position: absolute;top: -8px;right: -18px;" src="./assets/close.png">
</div>
</el-tag>
</transition-group>
......@@ -83,8 +74,7 @@
</div>
<div style="margin-right: 5px;">
<span style="width: 90px;">动作类型:</span>
<el-select id="eventType" name="eventType" v-model="actionType" placeholder="请选择类型"
@change="handleChange" filterable remote>
<el-select id="eventType" name="eventType" v-model="actionType" placeholder="请选择类型" @change="handleChange" filterable remote>
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
......@@ -93,23 +83,22 @@
<el-button @click="toActions">进入容器</el-button>
</div>
</div>
<component :is="dynamicComponent" :actionName="actionName" :actionType="actionType"
@dataChanged="handleDataChange" v-if="actionType !== ''"></component>
<component :is="dynamicComponent" :actionName="actionName" :actionType="actionType" @dataChanged="handleDataChange" v-if="actionType !== ''"></component>
</el-card>
</div>
</div>
</template>
<script>
// 导出json文件使用的库
import { saveAs } from 'file-saver';
import draggable from 'vuedraggable'
import { onSelect, elClick, wait, loopClick, onInput, collectSingleElements, pageClose, mouseMove, pageJavascipt, collectionTable, submit, actions } from './components/index.js'
import { onSelect, elRightClick, wait, loopClick, onInput, collectSingleElements, pageClose, mouseMove, pageJavascipt, collectionTable, submit, actions } from './components/index.js'
export default {
name: 'App',
components: { draggable, onSelect, elClick, wait, loopClick, onInput, collectSingleElements, pageClose, mouseMove, pageJavascipt, collectionTable, submit, actions },
components: { draggable, onSelect, elRightClick, wait, loopClick, onInput, collectSingleElements, pageClose, mouseMove, pageJavascipt, collectionTable, submit, actions },
props: {},
data () {
data() {
return {
dynamicComponent: null,
taskName: '',
......@@ -119,12 +108,12 @@ export default {
dynamicTags: [],
isShowAction: false,
options: [{
value: 'elRightClick',
label: '右击'
}, {
value: 'select',
label: '选择'
}, {
value: 'elClick',
label: '点击'
}, {
value: 'wait',
label: '等待'
}, {
......@@ -174,9 +163,8 @@ export default {
}
},
created () { },
mounted () {
created() { },
mounted() {
this.$nextTick(() => {
window.addEventListener('resize', this.onResize);
});
......@@ -187,13 +175,12 @@ export default {
},
watch: {
actionName (newVal, oldVal) {
actionName(newVal, oldVal) {
// 在输入值发生变化时触发
if (newVal !== oldVal) {
// console.log(newVal)
// console.log(this.dynamicTags)
const targetObject = this.dynamicTags.find(obj => obj.tagId === this.dynamicTagObj.tagId);
if (targetObject) {
if (newVal == undefined) return
// 找到匹配的对象
......@@ -208,7 +195,7 @@ export default {
// 可以在这里执行自定义逻辑
},
treeNode: {
handler (newVal, oldVal) {
handler(newVal, oldVal) {
console.log('数组变化了', newVal);
},
deep: true
......@@ -217,14 +204,14 @@ export default {
computed: {},
methods: {
// 组件配置
loadComponent (componentName) {
loadComponent(componentName) {
switch (componentName) {
case 'elRightClick':
this.dynamicComponent = elRightClick
break;
case 'select':
this.dynamicComponent = onSelect
break;
case 'elClick':
this.dynamicComponent = elClick
break;
case 'wait':
this.dynamicComponent = wait
break;
......@@ -255,13 +242,12 @@ export default {
case 'actions':
this.dynamicComponent = actions
break;
default:
this.dynamicComponent = null;
}
},
// 接收子组件信息
handleDataChange (newData) {
handleDataChange(newData) {
console.log('接收到的数据:', newData);
const targetObject = this.dynamicTags.find(obj => obj.Kvid === this.dynamicTagObj.Kvid);
console.log(targetObject)
......@@ -278,7 +264,7 @@ export default {
console.log(this.treeNode)
},
// 新建动作
newAction () {
newAction() {
this.isShowAction = true;
this.dynamicTagObj = {}
this.actionName = "新建动作"
......@@ -311,10 +297,9 @@ export default {
}
this.isChildrenTree = false
}
},
// 进入容器
toActions () {
toActions() {
this.isShowAction = false
if (this.actionType == 'actions') {
// this.actionType = ''
......@@ -336,11 +321,9 @@ export default {
console.log(this.treeNode)
for (let i = 0; i < this.treeNode.length; i++) {
this.actionAll[0].children.push(this.treeNode[i])
}
this.actionAll.push(obj)
this.findOrPushObject(this.actionAll[0].children, obj)
} else {
// this.actionType = ''
// this.actionName = ''
......@@ -350,20 +333,17 @@ export default {
obj.children = []
for (let i = 0; i < activeItem.children.length; i++) {
obj.children.push(activeItem.children[i])
}
this.childrenTreeNode = obj.children
this.findOrPushObject(this.actionAll, obj)
// console.log(this.actionAll)
}
} else {
this.parentKvid = null
}
},
// 动作下拉框
handleChange (val) {
handleChange(val) {
this.actionType == val
let _this = this
// 在输入值发生变化时触发
......@@ -381,19 +361,17 @@ export default {
}
},
// 导航标签
onBreadcrumb (item) {
onBreadcrumb(item) {
this.actionName = item.actionName
this.actionType = item.actionType
this.deleteObjectsAfterKvid(this.actionAll, item.Kvid)
let activeItem = this.findObjectByKvid(this.treeNode, item.Kvid);
if (activeItem == null) {
this.childrenTreeNode = this.treeNode
this.isChildrenTree = false
this.parentKvid = null
// console.log(this.treeNode)
} else {
this.childrenTreeNode = []
this.childrenTreeNode = activeItem.children
this.isChildrenTree = true
......@@ -402,7 +380,7 @@ export default {
}
},
// 单击标签
selectTag (item) {
selectTag(item) {
// this.parentTree = item
let _this = this
if (item.actionType == 'actions') {
......@@ -416,13 +394,11 @@ export default {
obj.children = []
for (let i = 0; i < _this.treeNode.length; i++) {
_this.actionAll[0].children.push(_this.treeNode[i])
}
_this.actionAll.push(obj)
_this.findOrPushObject(_this.actionAll[0].children, obj)
_this.childrenTreeNode = []
_this.isChildrenTree = true
} else {
_this.parentKvid = item.Kvid
_this.childrenTreeNode = []
......@@ -431,7 +407,6 @@ export default {
obj.name = item.actionName
obj.Kvid = item.Kvid
obj.children = []
for (let i = 0; i < item.children.length; i++) {
obj.children.push(item.children[i])
_this.childrenTreeNode.push(item.children[i])
......@@ -439,13 +414,10 @@ export default {
_this.findOrPushObject(_this.actionAll, obj)
_this.isChildrenTree = true
}
} else {
_this.actionName = item.actionName
_this.actionType = item.actionType
_this.isShowAction = true
}
_this.Kvid = item.Kvid
if (item.children != undefined && item.children.length > 0) {
......@@ -460,7 +432,7 @@ export default {
_this.loadComponent(item.actionType)
},
// 删除标签
handleClose (tag) {
handleClose(tag) {
let _this = this
if (_this.childrenTreeNode.length > 0 && _this.isChildrenTree == true) {
let filteredArray = _this.childrenTreeNode.filter(item => item.Kvid !== tag.Kvid);
......@@ -491,7 +463,6 @@ export default {
activeParentItem.children = []
for (let i = 0; i < filteredArray.length; i++) {
activeParentItem.children.push(filteredArray[i])
}
}
} else if (_this.treeNode.length > 0 && _this.isChildrenTree == false) {
......@@ -512,7 +483,7 @@ export default {
_this.isShowAction = false
},
// 根据 Kvid 找到对应的对象,并将匹配到的对象后面的所有对象数据删除
deleteObjectsAfterKvid (dataArray, targetKvid) {
deleteObjectsAfterKvid(dataArray, targetKvid) {
const index = dataArray.findIndex(obj => obj.Kvid === targetKvid);
if (index !== -1) {
// 找到匹配的对象
......@@ -522,11 +493,11 @@ export default {
}
},
// 树结构添加数据
addDataToParent (tree, parentKvid, newData, childTree) {
addDataToParent(tree, parentKvid, newData, childTree) {
let _this = this
_this.childrenTreeNode = []
// 递归函数,用于在树的每一级中查找合适的父节点并添加数据
function addToNode (node, parentKvid, newData, childTree) {
function addToNode(node, parentKvid, newData, childTree) {
if (node.children == undefined) {
node.children = []
}
......@@ -558,7 +529,7 @@ export default {
tree.push(newData);
},
// 返回上一级目录
goback () {
goback() {
this.parentKvid = null
this.childrenTreeNode = []
let activeItem = this.findObjectByKvid(this.treeNode, this.Kvid);
......@@ -569,17 +540,23 @@ export default {
} else {
for (let i = 0; i < activeParentsItem.children.length; i++) {
this.childrenTreeNode.push(activeParentsItem.children[i])
}
this.Kvid = activeParentItem.Kvid
}
},
// 计划任务提交
submitPlan (formName) {
// 保存任务
submitPlan(formName) {
this.isShowAction = true
console.log(this.treeNode)
// 将JSON对象转换为JSON字符串
const jsonString = JSON.stringify(this.treeNode, null, 2);
// 创建一个Blob对象
const blob = new Blob([jsonString], { type: 'application/json' });
// 使用file-saver库保存文件
saveAs(blob, 'exported_data.json');
},
// 根据parentKvid找当前节点
findHierarchyByParentKvid (tree, parentKvid) {
findHierarchyByParentKvid(tree, parentKvid) {
let _this = this
for (var i = 0; i < tree.length; i++) {
var node = tree[i];
......@@ -593,11 +570,10 @@ export default {
}
}
}
return []; // 未找到匹配的节点,返回空数组
},
// 根据Kvid找节点
findObjectByKvid (array, kvid) {
findObjectByKvid(array, kvid) {
let _this = this
for (var i = 0; i < array.length; i++) {
var obj = array[i];
......@@ -611,11 +587,10 @@ export default {
}
}
}
return null; // 如果没有找到目标对象,返回 null
},
// 根据 Kvid 匹配,如果有相同的就返回,没有就 push
findOrPushObject (dataArray, newObj) {
findOrPushObject(dataArray, newObj) {
const existingObj = dataArray.find(obj => obj.Kvid === newObj.Kvid);
if (existingObj) {
// 已经存在相同的 Kvid,返回该对象
......@@ -627,12 +602,12 @@ export default {
}
},
//开始拖拽事件-标签拖拽
onStart () {
onStart() {
this.drag = true;
this.isShowAction = false
},
//拖拽结束事件
onEnd () {
onEnd() {
this.drag = false;
// console.log(this.treeNode)
// console.log(this.childrenTreeNode)
......@@ -641,9 +616,7 @@ export default {
activeParentItem.children = []
for (let i = 0; i < this.childrenTreeNode.length; i++) {
activeParentItem.children.push(this.childrenTreeNode[i])
}
}
// 拖拽完最终结果
console.log(this.treeNode)
......@@ -686,6 +659,7 @@ export default {
font-weight: normal !important;
border: solid #3384FF 3px;
border-radius: 10px;
user-select: none;
-webkit-user-select: none;
/* 文字不可被选中 */
}
......@@ -769,19 +743,12 @@ export default {
width: 100px;
height: 30px;
cursor: pointer;
/* margin-left: 15px !important; */
padding: 0 !important;
}
/* 输入框样式 */
.tooltips input[type=text] {
/* display: block; */
/* margin-top: 3px !important; */
/* padding-left: 5px !important; */
/* margin-bottom: 7px !important; */
font-size: 13px;
/* border-radius: 5px; */
/* border: solid 1px #DCDFE6; */
width: 145px;
height: 20px;
}
......@@ -857,8 +824,6 @@ export default {
font-size: 15px;
font-weight: bold;
cursor: pointer;
/*position: absolute;*/
/*position: ;*/
margin-right: 10px;
vertical-align: text-bottom !important;
}
......
<template>
<div class="elClick">
<div class="elRightClick">
<div style="height: 35px;margin-left: 15px;text-align: left;">
<el-button size="small" class="button-new-tag" @click="selectElement">选择元素</el-button>
<el-button size="small" class="button-new-tag" @click="cancelSelect">取消选择</el-button>
<span style="margin-left: 3px;">元素信息如下:</span>
</div>
<el-form label-position="right" label-width="80px" :model="actionConfig">
<el-form-item label="查找方式">
<el-select id="eventType" name="eventType" v-model="actionConfig.Type" :placeholder="selectDisabled?'请先选择元素':'请选择'"
@change="handleChange" filterable remote :disabled="selectDisabled">
<el-select id="eventType" name="eventType" v-model="actionConfig.Type" :placeholder="selectDisabled ? '请先右击选择元素' : '请选择'" @change="handleChange" filterable remote :disabled="selectDisabled">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
......@@ -28,12 +28,12 @@
<script>
export default {
name: 'elClick',
name: 'elRightClick',
components: {},
props: ['actionName', 'actionType'],
data () {
data() {
return {
elementInfo:{},
elementInfo: {},
actionConfig:
{
"Target": {//点击的目标元素配置信息
......@@ -69,16 +69,23 @@ export default {
value: 'Css',
label: 'Css'
}],
selectDisabled:true
selectDisabled: true
}
},
created () { },
mounted () { },
created() { },
mounted() {
// 在组件挂载后调用selectElement来添加事件监听器
this.selectElement();
},
beforeDestroy() {
// 在组件销毁前移除事件监听器
document.removeEventListener('contextmenu', this.contextMenuHandler);
},
watch: {},
computed: {},
methods: {
submit () {
submit() {
console.log(this.actionConfig)
// 防止父级改变,子级未改变重新赋值
this.actionConfig.Name = this.actionName
......@@ -86,42 +93,70 @@ export default {
this.$emit('dataChanged', this.actionConfig);
// console.log(this.actionName)
},
// 获取页面元素
selectElement () {
let _this = this
// 定义事件处理函数
function contextMenuHandler (event) {
// 获取页面元素方法
contextMenuHandler(event) {
event.preventDefault(); // 阻止默认的右击菜单
let element = event.target;
let elementInfo = {
Id: element.id || '无',
Xpath: _this.getElementXPath(element),
Xpath: this.getElementXPath(element),
Link: element.href || '无',
Name: element.name || '无',
Class: element.className || '无',
PartialLink: element.textContent.trim() || '无',
Tag: element.tagName.toLowerCase(),
Css: _this.getElementCssSelector(element)
Css: this.getElementCssSelector(element),
};
_this.elementInfo =elementInfo
_this.selectDisabled = false
this.elementInfo = elementInfo;
this.selectDisabled = false;
// 移除事件监听器
document.removeEventListener('contextmenu', contextMenuHandler);
}
document.removeEventListener('contextmenu', this.contextMenuHandler);
},
// 选择元素按钮调用
selectElement() {
// 添加事件监听器
document.addEventListener('contextmenu', contextMenuHandler, false);
document.addEventListener('contextmenu', this.contextMenuHandler, false);
},
handleChange (val) {
// 取消按钮调用
cancelSelect() {
// 在取消按钮点击时移除事件监听器
document.removeEventListener('contextmenu', this.contextMenuHandler);
},
// // 获取页面元素
// selectElement() {
// let _this = this
// // 定义事件处理函数
// function contextMenuHandler(event) {
// event.preventDefault(); // 阻止默认的右击菜单
// let element = event.target;
// let elementInfo = {
// Id: element.id || '无',
// Xpath: _this.getElementXPath(element),
// Link: element.href || '无',
// Name: element.name || '无',
// Class: element.className || '无',
// PartialLink: element.textContent.trim() || '无',
// Tag: element.tagName.toLowerCase(),
// Css: _this.getElementCssSelector(element)
// };
// _this.elementInfo = elementInfo
// _this.selectDisabled = false
// // 移除事件监听器
// document.removeEventListener('contextmenu', contextMenuHandler);
// }
// // 添加事件监听器
// document.addEventListener('contextmenu', contextMenuHandler, false);
// },
// 改变选择框提示内容
handleChange(val) {
// this.actionType == val
let _this = this
console.log(_this.elementInfo)
console.log(_this.elementInfo[val])
_this.actionConfig.Target.Selector = _this.elementInfo[val]
},
// 获取xpath
getElementXPath (element) {
getElementXPath(element) {
let _this = this
if (element.tagName === 'BODY') {
return '/HTML/' + element.tagName;
......@@ -138,7 +173,7 @@ export default {
}
},
// 获取元素css
getElementCssSelector (element) {
getElementCssSelector(element) {
let selector = element.tagName.toLowerCase();
if (element.id) {
selector += '#' + element.id;
......
import elRightClick from './elRightClick.vue';
import onSelect from './onSelect.vue';
import elClick from './elClick.vue';
import wait from './wait.vue';
import loopClick from './loopClick.vue'
import collectSingleElements from './collectSingleElements.vue';
......@@ -12,4 +12,4 @@ import actions from './actions.vue';
import onInput from './onInput.vue'
// import ComponentC from './ComponentC.vue';
export { onSelect, elClick, wait, onInput,loopClick, collectSingleElements, pageClose, mouseMove, pageJavascipt, collectionTable, submit, actions };
\ No newline at end of file
export { elRightClick, onSelect, wait, onInput, loopClick, collectSingleElements, pageClose, mouseMove, pageJavascipt, collectionTable, submit, actions };
\ No newline at end of file
......@@ -4,19 +4,18 @@
<script>
export default {
name:'onSelect',
components:{},
props:{},
data(){
name: 'onSelect',
components: {},
props: {},
data() {
return {
}
},
created(){},
mounted(){},
watch:{},
computed:{},
methods:{},
created() { },
mounted() { },
watch: {},
computed: {},
methods: {},
}
</script>
<style lang="scss" scoped>
</style>
\ No newline at end of file
<style lang="scss" scoped></style>
\ No newline at end of file
<template>
<div class="wait">等待</div>
<div class="wait">
<el-form label-position="right" label-width="80px" :model="actionConfig">
<el-form-item label="等待时间">
<el-input
v-model="actionConfig.Target.PauseMilliseconds"
></el-input>
</el-form-item>
</el-form>
<div style="width: 100%;text-align: right;">
<el-button size="small" class="button-new-tag" @click="submit" style="margin-right: 5px;">提交信息</el-button>
</div>
</div>
</template>
<script>
export default {
name:'wait',
components:{},
props:{},
data(){
name: 'wait',
components: {},
props: ['actionName', 'actionType'],
data() {
return {
selectDisabled: true,
elementInfo: {},
actionConfig:
{
"PauseMilliseconds": 2000,
"Name": this.actionName,//动作名称
"Alias": this.actionType//动作类型
},
}
},
created(){},
mounted(){},
watch:{},
computed:{},
methods:{},
created() { },
mounted() { },
watch: {},
computed: {},
methods: {
// 提交信息
submit() {
console.log(this.actionConfig)
// 防止父级改变,子级未改变重新赋值
this.actionConfig.Name = this.actionName
this.actionConfig.Alias = this.actionType
this.$emit('dataChanged', this.actionConfig);
// console.log(this.actionName)
},
},
}
</script>
<style lang="scss" scoped>
</style>
\ No newline at end of file
<!-- <style lang="scss" scoped></style> -->
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment