Merge branch 'test' of https://git.code.tencent.com/lian-cbtc/jl-client into test
This commit is contained in:
commit
76ba1caf8a
@ -354,7 +354,7 @@ export function Jl3dpassflow(dom) {
|
||||
}
|
||||
}
|
||||
}
|
||||
},3000);
|
||||
},1000);
|
||||
};
|
||||
},1000);
|
||||
|
||||
@ -390,7 +390,7 @@ export function Jl3dpassflow(dom) {
|
||||
}
|
||||
moveanimateupdate();
|
||||
|
||||
scope.anime = requestAnimationFrame(animate);
|
||||
requestAnimationFrame(animate);
|
||||
|
||||
}
|
||||
|
||||
@ -468,7 +468,7 @@ export function Jl3dpassflow(dom) {
|
||||
}
|
||||
|
||||
if(humans[i].stage == 0){
|
||||
console.log(humans[i].doors);
|
||||
// console.log(humans[i].doors);
|
||||
zhajiin[humans[i].doors].waiting = 0;
|
||||
humans[i].stage = 1;
|
||||
}
|
||||
@ -805,8 +805,7 @@ export function Jl3dpassflow(dom) {
|
||||
}
|
||||
|
||||
function zhajicontrol(type,door){
|
||||
console.log(door);
|
||||
console.log(zhajiin);
|
||||
|
||||
let devicenum = door-1;
|
||||
if(type == "in"){
|
||||
deviceaction[zhajiin[devicenum].id].action.reset();
|
||||
|
1102
src/jlmap3d/jl3dpassflow/jl3dpassflownew.js
Normal file
1102
src/jlmap3d/jl3dpassflow/jl3dpassflownew.js
Normal file
File diff suppressed because it is too large
Load Diff
0
src/jlmap3d/jl3dpassflow/model/humanmanager.js
Normal file
0
src/jlmap3d/jl3dpassflow/model/humanmanager.js
Normal file
0
src/jlmap3d/jl3dpassflow/model/humanmodel.js
Normal file
0
src/jlmap3d/jl3dpassflow/model/humanmodel.js
Normal file
136
src/jlmap3d/jl3dpassflow/model/zonemanager.js
Normal file
136
src/jlmap3d/jl3dpassflow/model/zonemanager.js
Normal file
@ -0,0 +1,136 @@
|
||||
import { ZoneModel } from '@/jlmap3d/jl3dpassflow/model/zonemodel.js';
|
||||
|
||||
let enter1 = {
|
||||
code : '001',
|
||||
name : "enter1",
|
||||
type : "normal",
|
||||
stage : "0",
|
||||
railpoints : [
|
||||
new THREE.Vector3(34,9.8,-6),
|
||||
new THREE.Vector3(32,9.8,-6)
|
||||
]
|
||||
};
|
||||
|
||||
let enter2 = {
|
||||
code : '002',
|
||||
name : "enter2",
|
||||
type : "normal",
|
||||
stage : "0",
|
||||
railpoints : [
|
||||
new THREE.Vector3(35,9.8,31.5),
|
||||
new THREE.Vector3(31,9.8,31.5)
|
||||
]
|
||||
};
|
||||
|
||||
let security = {
|
||||
code : '003',
|
||||
name : "security",
|
||||
type : "device",
|
||||
stage : "1",
|
||||
railpoints : [
|
||||
new THREE.Vector3(20.5,9.8,18),
|
||||
new THREE.Vector3(21,9.8,21)
|
||||
]
|
||||
};
|
||||
|
||||
let entergate = {
|
||||
code : '004',
|
||||
name : "entergate",
|
||||
type : "device",
|
||||
stage : "2",
|
||||
railpoints : [
|
||||
new THREE.Vector3(6.3,9.8,17.4),
|
||||
new THREE.Vector3(4.8,9.8,17.4),
|
||||
new THREE.Vector3(3.4,9.8,17.4),
|
||||
new THREE.Vector3(2.1,9.8,17.4),
|
||||
new THREE.Vector3(0.7,9.8,17.4)
|
||||
]
|
||||
};
|
||||
|
||||
let standtop = {
|
||||
code : '005',
|
||||
name : "standtop",
|
||||
type : "stand",
|
||||
stage : "3",
|
||||
railpoints : [
|
||||
new THREE.Vector3(52.1,1.77,-1.8),
|
||||
new THREE.Vector3(-63.5,1.77,-1.8)
|
||||
]
|
||||
};
|
||||
|
||||
let standdown = {
|
||||
code : '006',
|
||||
name : "standdown",
|
||||
type : "stand",
|
||||
stage : "3",
|
||||
railpoints : [
|
||||
new THREE.Vector3(52.1,1.77,24),
|
||||
new THREE.Vector3(-64,1.77,24)
|
||||
]
|
||||
};
|
||||
//4是刚下车状态
|
||||
let exitgate = {
|
||||
code : '007',
|
||||
name : "exitgate",
|
||||
type : "device",
|
||||
stage : "5",
|
||||
railpoints : [
|
||||
new THREE.Vector3(18.8,9.8,-0.27),
|
||||
new THREE.Vector3(18.8,9.8,1.18),
|
||||
new THREE.Vector3(18.8,9.8,2.64),
|
||||
new THREE.Vector3(18.8,9.8,4.1),
|
||||
new THREE.Vector3(18.8,9.8,5.4)
|
||||
]
|
||||
};
|
||||
|
||||
let exit1 = {
|
||||
code : '008',
|
||||
name : "exit1",
|
||||
type : "normal",
|
||||
stage : "6",
|
||||
railpoints : [
|
||||
new THREE.Vector3(28.2,9.8,-7),
|
||||
new THREE.Vector3(30.5,9.8,-7.4)
|
||||
]
|
||||
};
|
||||
|
||||
let exit2 = {
|
||||
code : '009',
|
||||
name : "exit2",
|
||||
type : "normal",
|
||||
stage : "6",
|
||||
railpoints : [
|
||||
new THREE.Vector3(28.3,9.8,28.8),
|
||||
new THREE.Vector3(31.2,9.8,28.8)
|
||||
]
|
||||
};
|
||||
|
||||
export function ZoneManager() {
|
||||
|
||||
var scope = this;
|
||||
|
||||
this.name = "test";
|
||||
|
||||
this.list = [];
|
||||
|
||||
initzone();
|
||||
|
||||
function initzone(){
|
||||
scope.list[enter1.name] = new ZoneModel(enter1);
|
||||
scope.list[enter2.name] = new ZoneModel(enter2);
|
||||
scope.list[security.name] = new ZoneModel(security);
|
||||
scope.list[entergate.name] = new ZoneModel(entergate);
|
||||
scope.list[standtop.name] = new ZoneModel(standtop);
|
||||
scope.list[standdown.name] = new ZoneModel(standdown);
|
||||
scope.list[exitgate.name] = new ZoneModel(exitgate);
|
||||
scope.list[exit1.name] = new ZoneModel(exit1);
|
||||
scope.list[exit2.name] = new ZoneModel(exit2);
|
||||
}
|
||||
|
||||
this.getzoneposition = function(name){
|
||||
// let random = Math.random();
|
||||
let position = scope.list[name].railline.getPointAt(Math.random());
|
||||
return position;
|
||||
}
|
||||
|
||||
}
|
15
src/jlmap3d/jl3dpassflow/model/zonemodel.js
Normal file
15
src/jlmap3d/jl3dpassflow/model/zonemodel.js
Normal file
@ -0,0 +1,15 @@
|
||||
export function ZoneModel(data) {
|
||||
var scope = this;
|
||||
//code
|
||||
this.code = data.code;
|
||||
//命名
|
||||
this.name = data.name;
|
||||
this.type = data.type;
|
||||
this.stage = data.stage;
|
||||
this.status = 0;
|
||||
//轨迹点
|
||||
this.railpoints = data.railpoints;
|
||||
|
||||
this.railline = new THREE.CatmullRomCurve3(data.railpoints);
|
||||
|
||||
}
|
123
src/jlmap3d/jl3dpassflow/utils/AStar.js
Normal file
123
src/jlmap3d/jl3dpassflow/utils/AStar.js
Normal file
@ -0,0 +1,123 @@
|
||||
import { BinaryHeap } from './BinaryHeap';
|
||||
import { Utils } from './Utils.js';
|
||||
|
||||
class AStar {
|
||||
static init (graph) {
|
||||
for (let x = 0; x < graph.length; x++) {
|
||||
//for(var x in graph) {
|
||||
const node = graph[x];
|
||||
node.f = 0;
|
||||
node.g = 0;
|
||||
node.h = 0;
|
||||
node.cost = 1.0;
|
||||
node.visited = false;
|
||||
node.closed = false;
|
||||
node.parent = null;
|
||||
}
|
||||
}
|
||||
|
||||
static cleanUp (graph) {
|
||||
for (let x = 0; x < graph.length; x++) {
|
||||
const node = graph[x];
|
||||
delete node.f;
|
||||
delete node.g;
|
||||
delete node.h;
|
||||
delete node.cost;
|
||||
delete node.visited;
|
||||
delete node.closed;
|
||||
delete node.parent;
|
||||
}
|
||||
}
|
||||
|
||||
static heap () {
|
||||
return new BinaryHeap(function (node) {
|
||||
return node.f;
|
||||
});
|
||||
}
|
||||
|
||||
static search (graph, start, end) {
|
||||
this.init(graph);
|
||||
//heuristic = heuristic || astar.manhattan;
|
||||
|
||||
|
||||
const openHeap = this.heap();
|
||||
|
||||
openHeap.push(start);
|
||||
|
||||
while (openHeap.size() > 0) {
|
||||
|
||||
// Grab the lowest f(x) to process next. Heap keeps this sorted for us.
|
||||
const currentNode = openHeap.pop();
|
||||
|
||||
// End case -- result has been found, return the traced path.
|
||||
if (currentNode === end) {
|
||||
let curr = currentNode;
|
||||
const ret = [];
|
||||
while (curr.parent) {
|
||||
ret.push(curr);
|
||||
curr = curr.parent;
|
||||
}
|
||||
this.cleanUp(ret);
|
||||
return ret.reverse();
|
||||
}
|
||||
|
||||
// Normal case -- move currentNode from open to closed, process each of its neighbours.
|
||||
currentNode.closed = true;
|
||||
|
||||
// Find all neighbours for the current node. Optionally find diagonal neighbours as well (false by default).
|
||||
const neighbours = this.neighbours(graph, currentNode);
|
||||
|
||||
for (let i = 0, il = neighbours.length; i < il; i++) {
|
||||
const neighbour = neighbours[i];
|
||||
|
||||
if (neighbour.closed) {
|
||||
// Not a valid node to process, skip to next neighbour.
|
||||
continue;
|
||||
}
|
||||
|
||||
// The g score is the shortest distance from start to current node.
|
||||
// We need to check if the path we have arrived at this neighbour is the shortest one we have seen yet.
|
||||
const gScore = currentNode.g + neighbour.cost;
|
||||
const beenVisited = neighbour.visited;
|
||||
|
||||
if (!beenVisited || gScore < neighbour.g) {
|
||||
|
||||
// Found an optimal (so far) path to this node. Take score for node to see how good it is.
|
||||
neighbour.visited = true;
|
||||
neighbour.parent = currentNode;
|
||||
if (!neighbour.centroid || !end.centroid) throw new Error('Unexpected state');
|
||||
neighbour.h = neighbour.h || this.heuristic(neighbour.centroid, end.centroid);
|
||||
neighbour.g = gScore;
|
||||
neighbour.f = neighbour.g + neighbour.h;
|
||||
|
||||
if (!beenVisited) {
|
||||
// Pushing to heap will put it in proper place based on the 'f' value.
|
||||
openHeap.push(neighbour);
|
||||
} else {
|
||||
// Already seen the node, but since it has been rescored we need to reorder it in the heap
|
||||
openHeap.rescoreElement(neighbour);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No result was found - empty array signifies failure to find path.
|
||||
return [];
|
||||
}
|
||||
|
||||
static heuristic (pos1, pos2) {
|
||||
return Utils.distanceToSquared(pos1, pos2);
|
||||
}
|
||||
|
||||
static neighbours (graph, node) {
|
||||
const ret = [];
|
||||
|
||||
for (let e = 0; e < node.neighbours.length; e++) {
|
||||
ret.push(graph[node.neighbours[e]]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
export { AStar };
|
134
src/jlmap3d/jl3dpassflow/utils/BinaryHeap.js
Normal file
134
src/jlmap3d/jl3dpassflow/utils/BinaryHeap.js
Normal file
@ -0,0 +1,134 @@
|
||||
// javascript-astar
|
||||
// http://github.com/bgrins/javascript-astar
|
||||
// Freely distributable under the MIT License.
|
||||
// Implements the astar search algorithm in javascript using a binary heap.
|
||||
|
||||
class BinaryHeap {
|
||||
constructor (scoreFunction) {
|
||||
this.content = [];
|
||||
this.scoreFunction = scoreFunction;
|
||||
}
|
||||
|
||||
push (element) {
|
||||
// Add the new element to the end of the array.
|
||||
this.content.push(element);
|
||||
|
||||
// Allow it to sink down.
|
||||
this.sinkDown(this.content.length - 1);
|
||||
}
|
||||
|
||||
pop () {
|
||||
// Store the first element so we can return it later.
|
||||
const result = this.content[0];
|
||||
// Get the element at the end of the array.
|
||||
const end = this.content.pop();
|
||||
// If there are any elements left, put the end element at the
|
||||
// start, and let it bubble up.
|
||||
if (this.content.length > 0) {
|
||||
this.content[0] = end;
|
||||
this.bubbleUp(0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
remove (node) {
|
||||
const i = this.content.indexOf(node);
|
||||
|
||||
// When it is found, the process seen in 'pop' is repeated
|
||||
// to fill up the hole.
|
||||
const end = this.content.pop();
|
||||
|
||||
if (i !== this.content.length - 1) {
|
||||
this.content[i] = end;
|
||||
|
||||
if (this.scoreFunction(end) < this.scoreFunction(node)) {
|
||||
this.sinkDown(i);
|
||||
} else {
|
||||
this.bubbleUp(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size () {
|
||||
return this.content.length;
|
||||
}
|
||||
|
||||
rescoreElement (node) {
|
||||
this.sinkDown(this.content.indexOf(node));
|
||||
}
|
||||
|
||||
sinkDown (n) {
|
||||
// Fetch the element that has to be sunk.
|
||||
const element = this.content[n];
|
||||
|
||||
// When at 0, an element can not sink any further.
|
||||
while (n > 0) {
|
||||
// Compute the parent element's index, and fetch it.
|
||||
const parentN = ((n + 1) >> 1) - 1;
|
||||
const parent = this.content[parentN];
|
||||
|
||||
if (this.scoreFunction(element) < this.scoreFunction(parent)) {
|
||||
// Swap the elements if the parent is greater.
|
||||
this.content[parentN] = element;
|
||||
this.content[n] = parent;
|
||||
// Update 'n' to continue at the new position.
|
||||
n = parentN;
|
||||
} else {
|
||||
// Found a parent that is less, no need to sink any further.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bubbleUp (n) {
|
||||
// Look up the target element and its score.
|
||||
const length = this.content.length,
|
||||
element = this.content[n],
|
||||
elemScore = this.scoreFunction(element);
|
||||
|
||||
while (true) {
|
||||
// Compute the indices of the child elements.
|
||||
const child2N = (n + 1) << 1,
|
||||
child1N = child2N - 1;
|
||||
// This is used to store the new position of the element,
|
||||
// if any.
|
||||
let swap = null;
|
||||
let child1Score;
|
||||
// If the first child exists (is inside the array)...
|
||||
if (child1N < length) {
|
||||
// Look it up and compute its score.
|
||||
const child1 = this.content[child1N];
|
||||
child1Score = this.scoreFunction(child1);
|
||||
|
||||
// If the score is less than our element's, we need to swap.
|
||||
if (child1Score < elemScore) {
|
||||
swap = child1N;
|
||||
}
|
||||
}
|
||||
|
||||
// Do the same checks for the other child.
|
||||
if (child2N < length) {
|
||||
const child2 = this.content[child2N],
|
||||
child2Score = this.scoreFunction(child2);
|
||||
if (child2Score < (swap === null ? elemScore : child1Score)) {
|
||||
swap = child2N;
|
||||
}
|
||||
}
|
||||
|
||||
// If the element needs to be moved, swap it, and continue.
|
||||
if (swap !== null) {
|
||||
this.content[n] = this.content[swap];
|
||||
this.content[swap] = element;
|
||||
n = swap;
|
||||
}
|
||||
|
||||
// Otherwise, we are done.
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { BinaryHeap };
|
200
src/jlmap3d/jl3dpassflow/utils/Builder.js
Normal file
200
src/jlmap3d/jl3dpassflow/utils/Builder.js
Normal file
@ -0,0 +1,200 @@
|
||||
import {
|
||||
Vector3,
|
||||
} from 'three';
|
||||
|
||||
import { Utils } from './Utils';
|
||||
|
||||
class Builder {
|
||||
/**
|
||||
* Constructs groups from the given navigation mesh.
|
||||
* @param {Geometry} geometry
|
||||
* @return {Zone}
|
||||
*/
|
||||
static buildZone (geometry) {
|
||||
|
||||
const navMesh = this._buildNavigationMesh(geometry);
|
||||
|
||||
const zone = {};
|
||||
|
||||
navMesh.vertices.forEach((v) => {
|
||||
v.x = Utils.roundNumber(v.x, 2);
|
||||
v.y = Utils.roundNumber(v.y, 2);
|
||||
v.z = Utils.roundNumber(v.z, 2);
|
||||
});
|
||||
|
||||
zone.vertices = navMesh.vertices;
|
||||
|
||||
const groups = this._buildPolygonGroups(navMesh);
|
||||
|
||||
// TODO: This block represents a large portion of navigation mesh construction time
|
||||
// and could probably be optimized. For example, construct portals while
|
||||
// determining the neighbor graph.
|
||||
zone.groups = new Array(groups.length);
|
||||
groups.forEach((group, groupIndex) => {
|
||||
|
||||
const indexByPolygon = new Map(); // { polygon: index in group }
|
||||
group.forEach((poly, polyIndex) => { indexByPolygon.set(poly, polyIndex); });
|
||||
|
||||
const newGroup = new Array(group.length);
|
||||
group.forEach((poly, polyIndex) => {
|
||||
|
||||
const neighbourIndices = [];
|
||||
poly.neighbours.forEach((n) => neighbourIndices.push(indexByPolygon.get(n)));
|
||||
|
||||
// Build a portal list to each neighbour
|
||||
const portals = [];
|
||||
poly.neighbours.forEach((n) => portals.push(this._getSharedVerticesInOrder(poly, n)));
|
||||
|
||||
const centroid = new Vector3( 0, 0, 0 );
|
||||
centroid.add( zone.vertices[ poly.vertexIds[0] ] );
|
||||
centroid.add( zone.vertices[ poly.vertexIds[1] ] );
|
||||
centroid.add( zone.vertices[ poly.vertexIds[2] ] );
|
||||
centroid.divideScalar( 3 );
|
||||
centroid.x = Utils.roundNumber(centroid.x, 2);
|
||||
centroid.y = Utils.roundNumber(centroid.y, 2);
|
||||
centroid.z = Utils.roundNumber(centroid.z, 2);
|
||||
|
||||
newGroup[polyIndex] = {
|
||||
id: polyIndex,
|
||||
neighbours: neighbourIndices,
|
||||
vertexIds: poly.vertexIds,
|
||||
centroid: centroid,
|
||||
portals: portals
|
||||
};
|
||||
});
|
||||
|
||||
zone.groups[groupIndex] = newGroup;
|
||||
});
|
||||
|
||||
return zone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a navigation mesh from the given geometry.
|
||||
* @param {Geometry} geometry
|
||||
* @return {Object}
|
||||
*/
|
||||
static _buildNavigationMesh (geometry) {
|
||||
geometry.mergeVertices();
|
||||
return this._buildPolygonsFromGeometry(geometry);
|
||||
}
|
||||
|
||||
static _buildPolygonGroups (navigationMesh) {
|
||||
|
||||
const polygons = navigationMesh.polygons;
|
||||
|
||||
const polygonGroups = [];
|
||||
|
||||
const spreadGroupId = function (polygon) {
|
||||
polygon.neighbours.forEach((neighbour) => {
|
||||
if (neighbour.group === undefined) {
|
||||
neighbour.group = polygon.group;
|
||||
spreadGroupId(neighbour);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
polygons.forEach((polygon) => {
|
||||
if (polygon.group !== undefined) {
|
||||
// this polygon is already part of a group
|
||||
polygonGroups[polygon.group].push(polygon);
|
||||
} else {
|
||||
// we need to make a new group and spread its ID to neighbors
|
||||
polygon.group = polygonGroups.length;
|
||||
spreadGroupId(polygon);
|
||||
polygonGroups.push([polygon]);
|
||||
}
|
||||
});
|
||||
|
||||
return polygonGroups;
|
||||
}
|
||||
|
||||
static _buildPolygonNeighbours (polygon, vertexPolygonMap) {
|
||||
const neighbours = new Set();
|
||||
|
||||
const groupA = vertexPolygonMap[polygon.vertexIds[0]];
|
||||
const groupB = vertexPolygonMap[polygon.vertexIds[1]];
|
||||
const groupC = vertexPolygonMap[polygon.vertexIds[2]];
|
||||
|
||||
// It's only necessary to iterate groups A and B. Polygons contained only
|
||||
// in group C cannot share a >1 vertex with this polygon.
|
||||
// IMPORTANT: Bublé cannot compile for-of loops.
|
||||
groupA.forEach((candidate) => {
|
||||
if (candidate === polygon) return;
|
||||
if (groupB.includes(candidate) || groupC.includes(candidate)) {
|
||||
neighbours.add(candidate);
|
||||
}
|
||||
});
|
||||
groupB.forEach((candidate) => {
|
||||
if (candidate === polygon) return;
|
||||
if (groupC.includes(candidate)) {
|
||||
neighbours.add(candidate);
|
||||
}
|
||||
});
|
||||
|
||||
return neighbours;
|
||||
}
|
||||
|
||||
static _buildPolygonsFromGeometry (geometry) {
|
||||
|
||||
const polygons = [];
|
||||
const vertices = geometry.vertices;
|
||||
|
||||
// Constructing the neighbor graph brute force is O(n²). To avoid that,
|
||||
// create a map from vertices to the polygons that contain them, and use it
|
||||
// while connecting polygons. This reduces complexity to O(n*m), where 'm'
|
||||
// is related to connectivity of the mesh.
|
||||
const vertexPolygonMap = new Array(vertices.length); // array of polygon objects by vertex index
|
||||
for (let i = 0; i < vertices.length; i++) {
|
||||
vertexPolygonMap[i] = [];
|
||||
}
|
||||
|
||||
// Convert the faces into a custom format that supports more than 3 vertices
|
||||
geometry.faces.forEach((face) => {
|
||||
const poly = { vertexIds: [face.a, face.b, face.c], neighbours: null };
|
||||
polygons.push(poly);
|
||||
vertexPolygonMap[face.a].push(poly);
|
||||
vertexPolygonMap[face.b].push(poly);
|
||||
vertexPolygonMap[face.c].push(poly);
|
||||
});
|
||||
|
||||
// Build a list of adjacent polygons
|
||||
polygons.forEach((polygon) => {
|
||||
polygon.neighbours = this._buildPolygonNeighbours(polygon, vertexPolygonMap);
|
||||
});
|
||||
|
||||
return {
|
||||
polygons: polygons,
|
||||
vertices: vertices
|
||||
};
|
||||
}
|
||||
|
||||
static _getSharedVerticesInOrder (a, b) {
|
||||
|
||||
const aList = a.vertexIds;
|
||||
const a0 = aList[0], a1 = aList[1], a2 = aList[2];
|
||||
|
||||
const bList = b.vertexIds;
|
||||
const shared0 = bList.includes(a0);
|
||||
const shared1 = bList.includes(a1);
|
||||
const shared2 = bList.includes(a2);
|
||||
|
||||
// it seems that we shouldn't have an a and b with <2 shared vertices here unless there's a bug
|
||||
// in the neighbor identification code, or perhaps a malformed input geometry; 3 shared vertices
|
||||
// is a kind of embarrassing but possible geometry we should handle
|
||||
if (shared0 && shared1 && shared2) {
|
||||
return Array.from(aList);
|
||||
} else if (shared0 && shared1) {
|
||||
return [a0, a1];
|
||||
} else if (shared1 && shared2) {
|
||||
return [a1, a2];
|
||||
} else if (shared0 && shared2) {
|
||||
return [a2, a0]; // this ordering will affect the string pull algorithm later, not clear if significant
|
||||
} else {
|
||||
console.warn("Error processing navigation mesh neighbors; neighbors with <2 shared vertices found.");
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { Builder };
|
93
src/jlmap3d/jl3dpassflow/utils/Channel.js
Normal file
93
src/jlmap3d/jl3dpassflow/utils/Channel.js
Normal file
@ -0,0 +1,93 @@
|
||||
import { Utils } from './Utils';
|
||||
|
||||
class Channel {
|
||||
constructor () {
|
||||
this.portals = [];
|
||||
}
|
||||
|
||||
push (p1, p2) {
|
||||
if (p2 === undefined) p2 = p1;
|
||||
this.portals.push({
|
||||
left: p1,
|
||||
right: p2
|
||||
});
|
||||
}
|
||||
|
||||
stringPull () {
|
||||
const portals = this.portals;
|
||||
const pts = [];
|
||||
// Init scan state
|
||||
let portalApex, portalLeft, portalRight;
|
||||
let apexIndex = 0,
|
||||
leftIndex = 0,
|
||||
rightIndex = 0;
|
||||
|
||||
portalApex = portals[0].left;
|
||||
portalLeft = portals[0].left;
|
||||
portalRight = portals[0].right;
|
||||
|
||||
// Add start point.
|
||||
pts.push(portalApex);
|
||||
|
||||
for (let i = 1; i < portals.length; i++) {
|
||||
const left = portals[i].left;
|
||||
const right = portals[i].right;
|
||||
|
||||
// Update right vertex.
|
||||
if (Utils.triarea2(portalApex, portalRight, right) <= 0.0) {
|
||||
if (Utils.vequal(portalApex, portalRight) || Utils.triarea2(portalApex, portalLeft, right) > 0.0) {
|
||||
// Tighten the funnel.
|
||||
portalRight = right;
|
||||
rightIndex = i;
|
||||
} else {
|
||||
// Right over left, insert left to path and restart scan from portal left point.
|
||||
pts.push(portalLeft);
|
||||
// Make current left the new apex.
|
||||
portalApex = portalLeft;
|
||||
apexIndex = leftIndex;
|
||||
// Reset portal
|
||||
portalLeft = portalApex;
|
||||
portalRight = portalApex;
|
||||
leftIndex = apexIndex;
|
||||
rightIndex = apexIndex;
|
||||
// Restart scan
|
||||
i = apexIndex;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Update left vertex.
|
||||
if (Utils.triarea2(portalApex, portalLeft, left) >= 0.0) {
|
||||
if (Utils.vequal(portalApex, portalLeft) || Utils.triarea2(portalApex, portalRight, left) < 0.0) {
|
||||
// Tighten the funnel.
|
||||
portalLeft = left;
|
||||
leftIndex = i;
|
||||
} else {
|
||||
// Left over right, insert right to path and restart scan from portal right point.
|
||||
pts.push(portalRight);
|
||||
// Make current right the new apex.
|
||||
portalApex = portalRight;
|
||||
apexIndex = rightIndex;
|
||||
// Reset portal
|
||||
portalLeft = portalApex;
|
||||
portalRight = portalApex;
|
||||
leftIndex = apexIndex;
|
||||
rightIndex = apexIndex;
|
||||
// Restart scan
|
||||
i = apexIndex;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((pts.length === 0) || (!Utils.vequal(pts[pts.length - 1], portals[portals.length - 1].left))) {
|
||||
// Append last point to path.
|
||||
pts.push(portals[portals.length - 1].left);
|
||||
}
|
||||
|
||||
this.path = pts;
|
||||
return pts;
|
||||
}
|
||||
}
|
||||
|
||||
export { Channel };
|
315
src/jlmap3d/jl3dpassflow/utils/Pathfinding.js
Normal file
315
src/jlmap3d/jl3dpassflow/utils/Pathfinding.js
Normal file
@ -0,0 +1,315 @@
|
||||
import {
|
||||
Vector3,
|
||||
Plane,
|
||||
Geometry,
|
||||
Triangle,
|
||||
} from 'three';
|
||||
|
||||
import { Utils } from './Utils';
|
||||
import { AStar } from './AStar';
|
||||
import { Builder } from './Builder';
|
||||
import { Channel } from './Channel';
|
||||
|
||||
/**
|
||||
* Defines an instance of the pathfinding module, with one or more zones.
|
||||
*/
|
||||
class Pathfinding {
|
||||
constructor () {
|
||||
this.zones = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* (Static) Builds a zone/node set from navigation mesh geometry.
|
||||
* @param {BufferGeometry} geometry
|
||||
* @return {Zone}
|
||||
*/
|
||||
static createZone (geometry) {
|
||||
if ( geometry.isGeometry ) {
|
||||
// Haven't actually implemented support for BufferGeometry yet, but Geometry is somewhat
|
||||
// not-recommended these days, so go ahead and start warning.
|
||||
console.warn('[three-pathfinding]: Use BufferGeometry, not Geometry, to create zone.');
|
||||
} else {
|
||||
geometry = new Geometry().fromBufferGeometry(geometry);
|
||||
}
|
||||
|
||||
return Builder.buildZone(geometry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets data for the given zone.
|
||||
* @param {string} zoneID
|
||||
* @param {Zone} zone
|
||||
*/
|
||||
setZoneData (zoneID, zone) {
|
||||
this.zones[zoneID] = zone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random node within a given range of a given position.
|
||||
* @param {string} zoneID
|
||||
* @param {number} groupID
|
||||
* @param {Vector3} nearPosition
|
||||
* @param {number} nearRange
|
||||
* @return {Node}
|
||||
*/
|
||||
getRandomNode (zoneID, groupID, nearPosition, nearRange) {
|
||||
|
||||
if (!this.zones[zoneID]) return new Vector3();
|
||||
|
||||
nearPosition = nearPosition || null;
|
||||
nearRange = nearRange || 0;
|
||||
|
||||
const candidates = [];
|
||||
const polygons = this.zones[zoneID].groups[groupID];
|
||||
|
||||
polygons.forEach((p) => {
|
||||
if (nearPosition && nearRange) {
|
||||
if (Utils.distanceToSquared(nearPosition, p.centroid) < nearRange * nearRange) {
|
||||
candidates.push(p.centroid);
|
||||
}
|
||||
} else {
|
||||
candidates.push(p.centroid);
|
||||
}
|
||||
});
|
||||
|
||||
return Utils.sample(candidates) || new Vector3();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the closest node to the target position.
|
||||
* @param {Vector3} position
|
||||
* @param {string} zoneID
|
||||
* @param {number} groupID
|
||||
* @param {boolean} checkPolygon
|
||||
* @return {Node}
|
||||
*/
|
||||
getClosestNode (position, zoneID, groupID, checkPolygon = false) {
|
||||
const nodes = this.zones[zoneID].groups[groupID];
|
||||
const vertices = this.zones[zoneID].vertices;
|
||||
let closestNode = null;
|
||||
let closestDistance = Infinity;
|
||||
|
||||
nodes.forEach((node) => {
|
||||
const distance = Utils.distanceToSquared(node.centroid, position);
|
||||
if (distance < closestDistance
|
||||
&& (!checkPolygon || Utils.isVectorInPolygon(position, node, vertices))) {
|
||||
closestNode = node;
|
||||
closestDistance = distance;
|
||||
}
|
||||
});
|
||||
|
||||
return closestNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a path between given start and end points. If a complete path
|
||||
* cannot be found, will return the nearest endpoint available.
|
||||
*
|
||||
* @param {Vector3} startPosition Start position.
|
||||
* @param {Vector3} targetPosition Destination.
|
||||
* @param {string} zoneID ID of current zone.
|
||||
* @param {number} groupID Current group ID.
|
||||
* @return {Array<Vector3>} Array of points defining the path.
|
||||
*/
|
||||
findPath (startPosition, targetPosition, zoneID, groupID) {
|
||||
const nodes = this.zones[zoneID].groups[groupID];
|
||||
const vertices = this.zones[zoneID].vertices;
|
||||
|
||||
const closestNode = this.getClosestNode(startPosition, zoneID, groupID, true);
|
||||
const farthestNode = this.getClosestNode(targetPosition, zoneID, groupID, true);
|
||||
|
||||
// If we can't find any node, just go straight to the target
|
||||
if (!closestNode || !farthestNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const paths = AStar.search(nodes, closestNode, farthestNode);
|
||||
|
||||
const getPortalFromTo = function (a, b) {
|
||||
for (var i = 0; i < a.neighbours.length; i++) {
|
||||
if (a.neighbours[i] === b.id) {
|
||||
return a.portals[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// We have the corridor, now pull the rope.
|
||||
const channel = new Channel();
|
||||
channel.push(startPosition);
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
const polygon = paths[i];
|
||||
const nextPolygon = paths[i + 1];
|
||||
|
||||
if (nextPolygon) {
|
||||
const portals = getPortalFromTo(polygon, nextPolygon);
|
||||
channel.push(
|
||||
vertices[portals[0]],
|
||||
vertices[portals[1]]
|
||||
);
|
||||
}
|
||||
}
|
||||
channel.push(targetPosition);
|
||||
channel.stringPull();
|
||||
|
||||
// Return the path, omitting first position (which is already known).
|
||||
const path = channel.path.map((c) => new Vector3(c.x, c.y, c.z));
|
||||
path.shift();
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns closest node group ID for given position.
|
||||
* @param {string} zoneID
|
||||
* @param {Vector3} position
|
||||
* @return {number}
|
||||
*/
|
||||
Pathfinding.prototype.getGroup = (function() {
|
||||
const plane = new Plane();
|
||||
return function (zoneID, position, checkPolygon = false) {
|
||||
if (!this.zones[zoneID]) return null;
|
||||
|
||||
let closestNodeGroup = null;
|
||||
let distance = Math.pow(50, 2);
|
||||
const zone = this.zones[zoneID];
|
||||
|
||||
for (let i = 0; i < zone.groups.length; i++) {
|
||||
const group = zone.groups[i];
|
||||
for (const node of group) {
|
||||
if (checkPolygon) {
|
||||
plane.setFromCoplanarPoints(
|
||||
zone.vertices[node.vertexIds[0]],
|
||||
zone.vertices[node.vertexIds[1]],
|
||||
zone.vertices[node.vertexIds[2]]
|
||||
);
|
||||
if (Math.abs(plane.distanceToPoint(position)) < 0.01) {
|
||||
const poly = [
|
||||
zone.vertices[node.vertexIds[0]],
|
||||
zone.vertices[node.vertexIds[1]],
|
||||
zone.vertices[node.vertexIds[2]]
|
||||
];
|
||||
if(Utils.isPointInPoly(poly, position)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
const measuredDistance = Utils.distanceToSquared(node.centroid, position);
|
||||
if (measuredDistance < distance) {
|
||||
closestNodeGroup = i;
|
||||
distance = measuredDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closestNodeGroup;
|
||||
};
|
||||
}());
|
||||
|
||||
/**
|
||||
* Clamps a step along the navmesh, given start and desired endpoint. May be
|
||||
* used to constrain first-person / WASD controls.
|
||||
*
|
||||
* @param {Vector3} start
|
||||
* @param {Vector3} end Desired endpoint.
|
||||
* @param {Node} node
|
||||
* @param {string} zoneID
|
||||
* @param {number} groupID
|
||||
* @param {Vector3} endTarget Updated endpoint.
|
||||
* @return {Node} Updated node.
|
||||
*/
|
||||
Pathfinding.prototype.clampStep = (function () {
|
||||
const point = new Vector3();
|
||||
const plane = new Plane();
|
||||
const triangle = new Triangle();
|
||||
|
||||
const endPoint = new Vector3();
|
||||
|
||||
let closestNode;
|
||||
let closestPoint = new Vector3();
|
||||
let closestDistance;
|
||||
|
||||
return function (startRef, endRef, node, zoneID, groupID, endTarget) {
|
||||
const vertices = this.zones[zoneID].vertices;
|
||||
const nodes = this.zones[zoneID].groups[groupID];
|
||||
|
||||
const nodeQueue = [node];
|
||||
const nodeDepth = {};
|
||||
nodeDepth[node.id] = 0;
|
||||
|
||||
closestNode = undefined;
|
||||
closestPoint.set(0, 0, 0);
|
||||
closestDistance = Infinity;
|
||||
|
||||
// Project the step along the current node.
|
||||
plane.setFromCoplanarPoints(
|
||||
vertices[node.vertexIds[0]],
|
||||
vertices[node.vertexIds[1]],
|
||||
vertices[node.vertexIds[2]]
|
||||
);
|
||||
plane.projectPoint(endRef, point);
|
||||
endPoint.copy(point);
|
||||
|
||||
for (let currentNode = nodeQueue.pop(); currentNode; currentNode = nodeQueue.pop()) {
|
||||
|
||||
triangle.set(
|
||||
vertices[currentNode.vertexIds[0]],
|
||||
vertices[currentNode.vertexIds[1]],
|
||||
vertices[currentNode.vertexIds[2]]
|
||||
);
|
||||
|
||||
triangle.closestPointToPoint(endPoint, point);
|
||||
|
||||
if (point.distanceToSquared(endPoint) < closestDistance) {
|
||||
closestNode = currentNode;
|
||||
closestPoint.copy(point);
|
||||
closestDistance = point.distanceToSquared(endPoint);
|
||||
}
|
||||
|
||||
const depth = nodeDepth[currentNode.id];
|
||||
if (depth > 2) continue;
|
||||
|
||||
for (let i = 0; i < currentNode.neighbours.length; i++) {
|
||||
const neighbour = nodes[currentNode.neighbours[i]];
|
||||
if (neighbour.id in nodeDepth) continue;
|
||||
|
||||
nodeQueue.push(neighbour);
|
||||
nodeDepth[neighbour.id] = depth + 1;
|
||||
}
|
||||
}
|
||||
|
||||
endTarget.copy(closestPoint);
|
||||
return closestNode;
|
||||
};
|
||||
}());
|
||||
|
||||
/**
|
||||
* Defines a zone of interconnected groups on a navigation mesh.
|
||||
*
|
||||
* @type {Object}
|
||||
* @property {Array<Group>} groups
|
||||
* @property {Array<Vector3>} vertices
|
||||
*/
|
||||
const Zone = {}; // jshint ignore:line
|
||||
|
||||
/**
|
||||
* Defines a group within a navigation mesh.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const Group = {}; // jshint ignore:line
|
||||
|
||||
/**
|
||||
* Defines a node (or polygon) within a group.
|
||||
*
|
||||
* @type {Object}
|
||||
* @property {number} id
|
||||
* @property {Array<number>} neighbours IDs of neighboring nodes.
|
||||
* @property {Array<number>} vertexIds
|
||||
* @property {Vector3} centroid
|
||||
* @property {Array<Array<number>>} portals Array of portals, each defined by two vertex IDs.
|
||||
* @property {boolean} closed
|
||||
* @property {number} cost
|
||||
*/
|
||||
const Node = {}; // jshint ignore:line
|
||||
|
||||
export { Pathfinding };
|
53
src/jlmap3d/jl3dpassflow/utils/PathfindingHelper.js
Normal file
53
src/jlmap3d/jl3dpassflow/utils/PathfindingHelper.js
Normal file
@ -0,0 +1,53 @@
|
||||
import {
|
||||
Color,
|
||||
Object3D,
|
||||
LineBasicMaterial,
|
||||
MeshBasicMaterial,
|
||||
SphereBufferGeometry,
|
||||
BoxGeometry,
|
||||
Mesh,
|
||||
SphereGeometry,
|
||||
Geometry,
|
||||
Vector3,
|
||||
Line,
|
||||
} from 'three';
|
||||
|
||||
const OFFSET = 0.2;
|
||||
|
||||
/**
|
||||
* Helper for debugging pathfinding behavior.
|
||||
*/
|
||||
class PathfindingHelper extends Object3D {
|
||||
constructor () {
|
||||
super();
|
||||
|
||||
this._playerMarker = null;
|
||||
|
||||
this._markers = [
|
||||
this._playerMarker,
|
||||
];
|
||||
|
||||
this._markers.forEach( ( marker ) => {
|
||||
this.add( marker );
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param {Vector3} position
|
||||
* @return {this}
|
||||
*/
|
||||
setPlayerPosition( position ) {
|
||||
// this._playerMarker.lookAt(position);
|
||||
this._playerMarker.position.copy( position );
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export { PathfindingHelper };
|
66
src/jlmap3d/jl3dpassflow/utils/Utils.js
Normal file
66
src/jlmap3d/jl3dpassflow/utils/Utils.js
Normal file
@ -0,0 +1,66 @@
|
||||
class Utils {
|
||||
|
||||
static roundNumber (value, decimals) {
|
||||
const factor = Math.pow(10, decimals);
|
||||
return Math.round(value * factor) / factor;
|
||||
}
|
||||
|
||||
static sample (list) {
|
||||
return list[Math.floor(Math.random() * list.length)];
|
||||
}
|
||||
|
||||
static distanceToSquared (a, b) {
|
||||
|
||||
var dx = a.x - b.x;
|
||||
var dy = a.y - b.y;
|
||||
var dz = a.z - b.z;
|
||||
|
||||
return dx * dx + dy * dy + dz * dz;
|
||||
|
||||
}
|
||||
|
||||
//+ Jonas Raoni Soares Silva
|
||||
//@ http://jsfromhell.com/math/is-point-in-poly [rev. #0]
|
||||
static isPointInPoly (poly, pt) {
|
||||
for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
|
||||
((poly[i].z <= pt.z && pt.z < poly[j].z) || (poly[j].z <= pt.z && pt.z < poly[i].z)) && (pt.x < (poly[j].x - poly[i].x) * (pt.z - poly[i].z) / (poly[j].z - poly[i].z) + poly[i].x) && (c = !c);
|
||||
return c;
|
||||
}
|
||||
|
||||
static isVectorInPolygon (vector, polygon, vertices) {
|
||||
|
||||
// reference point will be the centroid of the polygon
|
||||
// We need to rotate the vector as well as all the points which the polygon uses
|
||||
|
||||
var lowestPoint = 100000;
|
||||
var highestPoint = -100000;
|
||||
|
||||
var polygonVertices = [];
|
||||
|
||||
polygon.vertexIds.forEach((vId) => {
|
||||
lowestPoint = Math.min(vertices[vId].y, lowestPoint);
|
||||
highestPoint = Math.max(vertices[vId].y, highestPoint);
|
||||
polygonVertices.push(vertices[vId]);
|
||||
});
|
||||
|
||||
if (vector.y < highestPoint + 0.5 && vector.y > lowestPoint - 0.5 &&
|
||||
this.isPointInPoly(polygonVertices, vector)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static triarea2 (a, b, c) {
|
||||
var ax = b.x - a.x;
|
||||
var az = b.z - a.z;
|
||||
var bx = c.x - a.x;
|
||||
var bz = c.z - a.z;
|
||||
return bx * az - ax * bz;
|
||||
}
|
||||
|
||||
static vequal (a, b) {
|
||||
return this.distanceToSquared(a, b) < 0.00001;
|
||||
}
|
||||
}
|
||||
|
||||
export { Utils };
|
4
src/jlmap3d/jl3dpassflow/utils/index.js
Normal file
4
src/jlmap3d/jl3dpassflow/utils/index.js
Normal file
@ -0,0 +1,4 @@
|
||||
import { Pathfinding } from './Pathfinding';
|
||||
import { PathfindingHelper } from './PathfindingHelper';
|
||||
|
||||
export { Pathfinding, PathfindingHelper };
|
@ -53,12 +53,12 @@ export function Jlmap3dSubscribeNew(jlmap3d,routegroup,jsonwebwork) {
|
||||
jsonwebwork.onmessage = function (event) {
|
||||
|
||||
|
||||
|
||||
// console.log(event.data);
|
||||
// if(event.data.deviceType == "TRAIN"){
|
||||
// // console.log(event.data);
|
||||
//
|
||||
// }
|
||||
console.log(event.data);
|
||||
// console.log(event.data);
|
||||
if(event.data.type == "Device_Load_Destroy_3D"){
|
||||
DeviceDestroy(event.data);
|
||||
return;
|
||||
@ -150,7 +150,6 @@ export function Jlmap3dSubscribeNew(jlmap3d,routegroup,jsonwebwork) {
|
||||
let code = data.code;
|
||||
|
||||
if(trainlisttest.list[code].right != data.right){
|
||||
|
||||
if(data.right == "0"){
|
||||
trainlisttest.list[code].right = "0";
|
||||
trainlisttest.list[code].rotation.y = Math.PI;
|
||||
@ -442,27 +441,28 @@ export function Jlmap3dSubscribeNew(jlmap3d,routegroup,jsonwebwork) {
|
||||
for(let i=0,leni=data.length;i<leni;i++){
|
||||
if(data[i].deviceType == "SWITCH"){
|
||||
initswitch(data[i]);
|
||||
}
|
||||
if(data[i].deviceType == "PSD"){
|
||||
}else if(data[i].deviceType == "PSD"){
|
||||
initstand(data[i]);
|
||||
}else{
|
||||
console.log(data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function DeviceDestroy(data){
|
||||
for(let i=0,leni=data.body.length;i<leni;i++){
|
||||
for(let i=0,leni=data.body.deviceList.length;i<leni;i++){
|
||||
|
||||
if(data.body[i].type == "TRAIN"){
|
||||
code =data.body[i].code;
|
||||
if (trainlisttest.list[code].dispose != data.body[i].dispose && data.body[i].dispose == "0") {
|
||||
if(data.body.deviceList[i].type == "TRAIN"){
|
||||
code =data.body.deviceList[i].code;
|
||||
if (trainlisttest.list[code].dispose != data.body.deviceList[i].dispose && data.body.deviceList[i].dispose == "0") {
|
||||
|
||||
if (rails.sectionrail[data.body[i].section]) {
|
||||
if (rails.sectionrail[data.body.deviceList[i].section]) {
|
||||
|
||||
trainlisttest.group.add(trainlisttest.list[code]);
|
||||
trainlisttest.list[code].position.y = 0;
|
||||
// trainlisttest.list[code].progress = 0;
|
||||
trainlisttest.list[code].dispose = "0";
|
||||
trainlisttest.list[code].nowcode = data.body[i].section;
|
||||
trainlisttest.list[code].nowcode = data.body.deviceList[i].section;
|
||||
trainlisttest.list[code].nextcode = null;
|
||||
trainlisttest.list[code].curve = null;
|
||||
trainlisttest.list[code].nextcurve = null;
|
||||
@ -476,7 +476,7 @@ export function Jlmap3dSubscribeNew(jlmap3d,routegroup,jsonwebwork) {
|
||||
trainlisttest.list[code].mixerpush = true;
|
||||
}
|
||||
}
|
||||
} else if (trainlisttest.list[code].dispose != data.body[i].dispose && data.body[i].dispose == "1") {
|
||||
} else if (trainlisttest.list[code].dispose != data.body.deviceList[i].dispose && data.body.deviceList[i].dispose == "1") {
|
||||
trainlisttest.list[code].status = 1;
|
||||
trainlisttest.group.remove(trainlisttest.list[code]);
|
||||
trainlisttest.list[code].progress = null;
|
||||
@ -493,17 +493,17 @@ export function Jlmap3dSubscribeNew(jlmap3d,routegroup,jsonwebwork) {
|
||||
|
||||
}
|
||||
}
|
||||
if(data.body[i].type == "SIGNAL"){
|
||||
signalupdate(data.body[i]);
|
||||
if(data.body.deviceList[i].type == "SIGNAL"){
|
||||
signalupdate(data.body.deviceList[i]);
|
||||
}
|
||||
if(data.body[i].type == "SWITCH"){
|
||||
switchupdate(data.body[i]);
|
||||
if(data.body.deviceList[i].type == "SWITCH"){
|
||||
switchupdate(data.body.deviceList[i]);
|
||||
}
|
||||
if(data.body[i].type == "PSD"){
|
||||
standupdate(data.body[i]);
|
||||
if(data.body.deviceList[i].type == "PSD"){
|
||||
standupdate(data.body.deviceList[i]);
|
||||
}
|
||||
if(data.body[i].type == "TRAIN_DOOR"){
|
||||
traindoorupdate(data.body[i]);
|
||||
if(data.body.deviceList[i].type == "TRAIN_DOOR"){
|
||||
traindoorupdate(data.body.deviceList[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -250,6 +250,13 @@ class SkinCode extends defaultStyle {
|
||||
}
|
||||
};
|
||||
|
||||
// 供电线路
|
||||
this[deviceType.Power] = {
|
||||
lineColor: '#FFFFFF', // 线条颜色
|
||||
strokeColor: '#ccc', // 线条颜色
|
||||
extendLength: 10 // 延伸长度
|
||||
};
|
||||
|
||||
this[deviceType.StationStand] = {
|
||||
common: { // 通用属性
|
||||
textFontSize: 8, // 站台默认字体大小
|
||||
|
@ -363,6 +363,13 @@ class SkinCode extends defaultStyle {
|
||||
}
|
||||
};
|
||||
|
||||
// 供电线路
|
||||
this[deviceType.Power] = {
|
||||
lineColor: '#FFFFFF', // 线条颜色
|
||||
strokeColor: '#ccc', // 线条颜色
|
||||
extendLength: 10 // 延伸长度
|
||||
};
|
||||
|
||||
this[deviceType.Switch] = {
|
||||
text: {
|
||||
show: true, // 道岔名称显示
|
||||
|
@ -200,6 +200,13 @@ class SkinCode extends defaultStyle {
|
||||
}
|
||||
};
|
||||
|
||||
// 供电线路
|
||||
this[deviceType.Power] = {
|
||||
lineColor: '#FFFFFF', // 线条颜色
|
||||
strokeColor: '#ccc', // 线条颜色
|
||||
extendLength: 10 // 延伸长度
|
||||
};
|
||||
|
||||
this[deviceType.StationStand] = {
|
||||
common: { // 通用属性
|
||||
textFontSize: 10, // 站台默认字体大小
|
||||
|
@ -383,6 +383,13 @@ class SkinCode extends defaultStyle {
|
||||
}
|
||||
};
|
||||
|
||||
// 供电线路
|
||||
this[deviceType.Power] = {
|
||||
lineColor: '#FFFFFF', // 线条颜色
|
||||
strokeColor: '#ccc', // 线条颜色
|
||||
extendLength: 10 // 延伸长度
|
||||
};
|
||||
|
||||
this[deviceType.Switch] = {
|
||||
text: {
|
||||
show: true, // 道岔名称显示
|
||||
|
@ -329,8 +329,8 @@ class SkinCode extends defaultStyle {
|
||||
},
|
||||
StationControl:{
|
||||
text: {
|
||||
distance: 2, // 灯和文字之间的距离
|
||||
fontSize: 11, // 字体大小
|
||||
distance: 10, // 灯和文字之间的距离
|
||||
fontSize: 14, // 字体大小
|
||||
fontFormat: 'consolas', // 字体格式
|
||||
fontColor: '#ffffff', // 字体颜色
|
||||
fontWeight: 'normal', // 字体粗细
|
||||
@ -345,9 +345,9 @@ class SkinCode extends defaultStyle {
|
||||
},
|
||||
lamp: {
|
||||
count: 2, // 控制模式灯个数
|
||||
offset: {x: 0, y: 0}, // 控制模式灯偏移量
|
||||
radiusR: 4, // 控制模式灯的半径
|
||||
distance: 36, // 控制模式之间灯之间的距离
|
||||
offset: {x: 0, y: 3}, // 控制模式灯偏移量
|
||||
radiusR: 7, // 控制模式灯的半径
|
||||
distance: 42, // 控制模式之间灯之间的距离
|
||||
grayColor: '#7F7F7F', // 控制模式灰色
|
||||
greenColor: '#00FF00', // 控制模式绿色
|
||||
redColor: '#FF0000', // 控制模式红色
|
||||
@ -418,6 +418,12 @@ class SkinCode extends defaultStyle {
|
||||
this[deviceType.Line] = {
|
||||
lineColor: '#FFFFFF' // 线条颜色
|
||||
};
|
||||
// 供电线路
|
||||
this[deviceType.Power] = {
|
||||
lineColor: '#FFFFFF', // 线条颜色
|
||||
strokeColor: '#ccc', // 线条颜色
|
||||
extendLength: 8 // 延伸长度
|
||||
};
|
||||
|
||||
this[deviceType.LcControl] = {
|
||||
text: {
|
||||
|
@ -392,6 +392,13 @@ class SkinCode extends defaultStyle {
|
||||
}
|
||||
};
|
||||
|
||||
// 供电线路
|
||||
this[deviceType.Power] = {
|
||||
lineColor: '#FFFFFF', // 线条颜色
|
||||
strokeColor: '#ccc', // 线条颜色
|
||||
extendLength: 10 // 延伸长度
|
||||
};
|
||||
|
||||
this[deviceType.Switch] = {
|
||||
text: {
|
||||
show: true, // 道岔名称显示
|
||||
|
@ -411,6 +411,13 @@ class SkinCode extends defaultStyle {
|
||||
}
|
||||
};
|
||||
|
||||
// 供电线路
|
||||
this[deviceType.Power] = {
|
||||
lineColor: '#FFFFFF', // 线条颜色
|
||||
strokeColor: '#ccc', // 线条颜色
|
||||
extendLength: 10 // 延伸长度
|
||||
};
|
||||
|
||||
this[deviceType.StationDelayUnlock] = {
|
||||
text: {
|
||||
distance: 3, // 延迟解锁和设备之间的距离
|
||||
|
@ -387,6 +387,13 @@ class SkinCode extends defaultStyle {
|
||||
}
|
||||
};
|
||||
|
||||
// 供电线路
|
||||
this[deviceType.Power] = {
|
||||
lineColor: '#FFFFFF', // 线条颜色
|
||||
strokeColor: '#ccc', // 线条颜色
|
||||
extendLength: 10 // 延伸长度
|
||||
};
|
||||
|
||||
this[deviceType.Switch] = {
|
||||
text: {
|
||||
show: true, // 道岔名称显示
|
||||
|
@ -509,6 +509,14 @@ class SkinCode extends defaultStyle {
|
||||
lineColor: '#FFFFFF', // 线条颜色
|
||||
lineDash: [8, 4]
|
||||
};
|
||||
|
||||
// 供电线路
|
||||
this[deviceType.Power] = {
|
||||
lineColor: '#FFFFFF', // 线条颜色
|
||||
strokeColor: '#ccc', // 线条颜色
|
||||
extendLength: 10 // 延伸长度
|
||||
};
|
||||
|
||||
this[deviceType.AutomaticRoute] = {
|
||||
// 是否显示
|
||||
displayCondition: '03', // 显示条件 prdType
|
||||
|
@ -245,4 +245,9 @@ deviceRender[deviceType.Arrow] = {
|
||||
_type: deviceType.Arrow,
|
||||
zlevel: 1
|
||||
};
|
||||
/** 供电线路 */
|
||||
deviceRender[deviceType.Power] = {
|
||||
_type: deviceType.Power,
|
||||
zlevel: 1
|
||||
};
|
||||
export default deviceRender;
|
||||
|
@ -42,7 +42,8 @@ const deviceType = {
|
||||
Axle: 'Axle',
|
||||
SplitStation:'SplitStation',
|
||||
SwitchFault: 'SwitchFault',
|
||||
Arrow: 'Arrow'
|
||||
Arrow: 'Arrow',
|
||||
Power: 'Power'
|
||||
};
|
||||
|
||||
export default deviceType;
|
||||
|
47
src/jmapNew/shape/Power/ESeparator.js
Normal file
47
src/jmapNew/shape/Power/ESeparator.js
Normal file
@ -0,0 +1,47 @@
|
||||
import Group from 'zrender/src/container/Group';
|
||||
import Polyline from 'zrender/src/graphic/shape/Polyline';
|
||||
|
||||
/** 分隔符*/
|
||||
export default class ESeparator extends Group {
|
||||
constructor(model) {
|
||||
super();
|
||||
this.model = model;
|
||||
this.zlevel = model.zlevel;
|
||||
this.z = model.z || 6;
|
||||
this.style = model.style;
|
||||
this.setType();
|
||||
}
|
||||
|
||||
createModel(points) {
|
||||
const model = this.model;
|
||||
this.partition = new Polyline({
|
||||
zlevel: this.zlevel,
|
||||
progressive: model.progressive,
|
||||
z: this.z,
|
||||
shape: {
|
||||
points: points
|
||||
},
|
||||
style: {
|
||||
lineWidth: model.width,
|
||||
stroke: model.stroke
|
||||
}
|
||||
});
|
||||
this.add(this.partition);
|
||||
}
|
||||
|
||||
setType() {
|
||||
const model = this.model;
|
||||
if (model && model.traingle) {
|
||||
const points = [
|
||||
[model.point.x, model.point.y - (this.style.Power.extendLength)],
|
||||
[model.point.x, model.point.y + (this.style.Power.extendLength)]
|
||||
];
|
||||
this.createModel(points);
|
||||
}
|
||||
if (model.traingle) {
|
||||
this.origin = [model.point.x, model.point.y];
|
||||
this.rotation = Math.PI * 2 - Math.atan2(model.traingle.absy, model.traingle.absx) * model.traingle.drictx * model.traingle.dricty;
|
||||
this.dirty(); // 可以无需调用
|
||||
}
|
||||
}
|
||||
}
|
131
src/jmapNew/shape/Power/index.js
Normal file
131
src/jmapNew/shape/Power/index.js
Normal file
@ -0,0 +1,131 @@
|
||||
import Polyline from 'zrender/src/graphic/shape/Polyline';
|
||||
import Group from 'zrender/src/container/Group';
|
||||
import JTriangle from '../../utils/JTriangle';
|
||||
import ESeparator from './ESeparator';
|
||||
import {isShowThePrdType} from '../../utils/handlePath';
|
||||
|
||||
export default class Line2 extends Group {
|
||||
constructor(model, style) {
|
||||
super();
|
||||
this._code = model.code;
|
||||
this._type = model._type;
|
||||
this.zlevel = model.zlevel;
|
||||
this.z = 0;
|
||||
this.model = model;
|
||||
this.style = style;
|
||||
this.isShowShape = true;
|
||||
if (isShowThePrdType(model.prdType, model.showConditions) || model.previewOrMapDraw) {
|
||||
this.create();
|
||||
this.createTerminal();
|
||||
this.setState(model);
|
||||
}
|
||||
if (model.previewOrMapDraw) {
|
||||
this.setShowMode();
|
||||
}
|
||||
}
|
||||
|
||||
create() {
|
||||
const model = this.model;
|
||||
const style = this.style;
|
||||
if (model && model.points.length > 1) {
|
||||
const points = [];
|
||||
for (let i = 0; i < model.points.length; i++) {
|
||||
points.push([model.points[i].x, model.points[i].y]);
|
||||
}
|
||||
this.line = new Polyline({
|
||||
zlevel: this.zlevel,
|
||||
progressive: model.progressive,
|
||||
z: this.z,
|
||||
shape: {
|
||||
points: points
|
||||
},
|
||||
style: {
|
||||
lineWidth: model.width,
|
||||
stroke: style.Power.strokeColor
|
||||
}
|
||||
});
|
||||
this.add(this.line);
|
||||
}
|
||||
}
|
||||
|
||||
createTerminal() { // 创建左右端点
|
||||
const model = this.model;
|
||||
const style = this.style;
|
||||
if (model && model.leftTerminal) { // 左端点
|
||||
const traingle = new JTriangle(model.points[0], model.points[1]);
|
||||
this.leftTerminal = new ESeparator({
|
||||
style: style,
|
||||
zlevel: this.zlevel,
|
||||
z: this.z + 3,
|
||||
traingle: traingle,
|
||||
width: model.width,
|
||||
stroke: style.Power.strokeColor,
|
||||
point: {
|
||||
x: model.points[0].x,
|
||||
y: model.points[0].y
|
||||
}
|
||||
});
|
||||
this.add(this.leftTerminal);
|
||||
}
|
||||
if (model && model.rightTerminal) { // 右端点
|
||||
const traingle = new JTriangle(model.points[model.points.length - 2], model.points[model.points.length - 1]);
|
||||
this.rightTerminal = new ESeparator({
|
||||
style: style,
|
||||
zlevel: this.zlevel,
|
||||
z: this.z + 3,
|
||||
traingle: traingle,
|
||||
width: model.width,
|
||||
stroke: style.Power.strokeColor,
|
||||
point: {
|
||||
x: model.points[model.points.length - 1].x,
|
||||
y: model.points[model.points.length - 1].y
|
||||
}
|
||||
});
|
||||
this.add(this.rightTerminal);
|
||||
}
|
||||
}
|
||||
|
||||
setLineType(type) {
|
||||
switch (type) {
|
||||
case '01': break;
|
||||
case '02':
|
||||
this.eachChild((child) => {
|
||||
child.setStyle('lineDash', this.style.Line.lineDash || [4]);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setState(model) {
|
||||
if (!this.isShowShape) return;
|
||||
this.setLineType(model.type);
|
||||
}
|
||||
// 设置显示模式
|
||||
setShowMode() {
|
||||
const showMode = this.model.showMode;
|
||||
const showConditions = this.model.showConditions;
|
||||
if (!showConditions || showConditions === '01' || showMode === showConditions) {
|
||||
this.eachChild((child) => {
|
||||
child.show();
|
||||
});
|
||||
} else {
|
||||
this.eachChild((child) => {
|
||||
child.hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
setShowStation(stationCode) {
|
||||
if (!stationCode || this.model.stationCode === stationCode) {
|
||||
this.eachChild((child) => {
|
||||
child.show();
|
||||
});
|
||||
this.isShowShape = true;
|
||||
this.setState(this.model);
|
||||
} else {
|
||||
this.eachChild((child) => {
|
||||
child.hide();
|
||||
});
|
||||
this.isShowShape = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -70,6 +70,12 @@ export default class ESingleControl extends Group {
|
||||
this.control.setStyle('fill', color);
|
||||
}
|
||||
}
|
||||
|
||||
setTextColor(color) {
|
||||
if (color) {
|
||||
this.text.setStyle('textFill', color);
|
||||
}
|
||||
}
|
||||
getArcBoundingRect() {
|
||||
const rect = this.control.getBoundingRect().clone();
|
||||
const scale = this.control.scale[0];
|
||||
|
@ -291,12 +291,15 @@ export default class Station extends Group {
|
||||
this.emergencyControl && this.emergencyControl.setColor(this.style.Station.StationControl.lamp.grayColor);
|
||||
this.substationControl && this.substationControl.setColor(this.style.Station.StationControl.lamp.grayColor);
|
||||
this.centerControl && this.centerControl.setColor(this.style.Station.StationControl.lamp.greenColor);
|
||||
this.centerControl && this.centerControl.setTextColor(this.style.Station.StationControl.lamp.greenColor); // 文字颜色
|
||||
}
|
||||
|
||||
handleLocal() { // 站控
|
||||
this.emergencyControl && this.emergencyControl.setColor(this.style.Station.StationControl.lamp.grayColor);
|
||||
this.substationControl && this.substationControl.setColor(this.style.Station.StationControl.lamp.yellowColor);
|
||||
this.substationControl && this.substationControl.setTextColor(this.style.Station.StationControl.lamp.yellowColor); // 文字颜色
|
||||
this.centerControl && this.centerControl.setColor(this.style.Station.StationControl.lamp.grayColor);
|
||||
this.arrowsControl && this.arrowsControl.setColor(this.style.Station.StationControl.lamp.greenColor);
|
||||
}
|
||||
|
||||
handleEmergency() { // 紧急站控
|
||||
@ -315,7 +318,8 @@ export default class Station extends Group {
|
||||
setState(model) {
|
||||
if (!this.isShowShape) return;
|
||||
this.recover();
|
||||
model.controlMode && this['handle' + model.controlMode]();
|
||||
// model.controlMode && this['handle' + model.controlMode]();
|
||||
this.handleLocal();
|
||||
}
|
||||
|
||||
getShapeTipPoint(opts) {
|
||||
|
@ -24,6 +24,7 @@ import AutomaticRoute from './AutomacticRoute/index.js';
|
||||
import SaidLamp from './SaidLamp/index.js';
|
||||
import SplitStation from './SplitStation/index';
|
||||
import Arrow from './Arrow/index';
|
||||
import Power from './Power/index';
|
||||
|
||||
/** 图库*/
|
||||
const mapShape = {};
|
||||
@ -69,6 +70,7 @@ mapShape[deviceType.Axle] = SaidLamp;
|
||||
mapShape[deviceType.SwitchFault] = SaidLamp;
|
||||
mapShape[deviceType.SplitStation] = SplitStation;
|
||||
mapShape[deviceType.Arrow] = Arrow;
|
||||
mapShape[deviceType.Power] = Power;
|
||||
|
||||
function shapefactory(device, jmap) {
|
||||
const type = device._type;
|
||||
|
@ -302,7 +302,7 @@ export default {
|
||||
'$store.state.menuOperation.selectedCount': function (val) {
|
||||
this.selectedChange();
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.resetPosition();
|
||||
},
|
||||
|
@ -144,9 +144,12 @@ export function parser(data, skinCode, showConfig) {
|
||||
zrUtil.each(data.splitStationList || [], elem => {
|
||||
mapDevice[elem.code] = createDevice(deviceType.SplitStation, elem, propConvert, showConfig);
|
||||
}, this);
|
||||
zrUtil.each( data.arrowList || [], elem => {
|
||||
zrUtil.each(data.arrowList || [], elem => {
|
||||
mapDevice[elem.code] = createDevice(deviceType.Arrow, elem, propConvert, showConfig);
|
||||
}, this);
|
||||
zrUtil.each(data.powerList || [], elem => {
|
||||
mapDevice[elem.code] = createDevice(deviceType.Power, elem, propConvert, showConfig);
|
||||
}, this);
|
||||
zrUtil.each(data.indicatorLightList || [], elem => {
|
||||
switch (elem.type) {
|
||||
case 'AtsControl':
|
||||
@ -326,6 +329,7 @@ export function updateMapData(state, model) {
|
||||
case deviceType.SplitStation: updateForList(model, state, 'splitStationList'); break;
|
||||
case deviceType.SwitchFault: updateForList(model, state, 'indicatorLightList'); break;
|
||||
case deviceType.Arrow: updateForList(model, state, 'arrowList'); break;
|
||||
case deviceType.Power: updateForList(model, state, 'powerList'); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -342,6 +342,13 @@ const map = {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
powerList: (state) => {
|
||||
if (state.map) {
|
||||
return state.map.powerList || [];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
tempSpeedLimitList: (state) => {
|
||||
if (state.map) {
|
||||
return state.map.tempSpeedLimitList;
|
||||
|
@ -30,7 +30,7 @@ export default {
|
||||
return {
|
||||
jl3d: null,
|
||||
rendermode:'监控视角',
|
||||
renderswitch:true
|
||||
renderswitch:false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -182,7 +182,7 @@ export default {
|
||||
} else {
|
||||
getPracticalQuestion(this.$route.query.raceId).then((responese)=>{
|
||||
if (responese.data) {
|
||||
participantCreatTrainingRoom(this.$route.query.raceId, {mapId: 41, prdType: '02'}).then(resp => {
|
||||
participantCreatTrainingRoom(this.$route.query.raceId, {mapId: 41, prdType: '03'}).then(resp => {
|
||||
const query = { lineCode: '11', mapId: '41', group: resp.data, raceId: this.$route.query.raceId};
|
||||
this.$router.replace({ path: `/jointTrainingNew`, query: query});
|
||||
});
|
||||
|
@ -2,7 +2,7 @@
|
||||
<!-- v-quickMenuDrag -->
|
||||
<div class="chatBox">
|
||||
<div v-if="!minimize" class="chat-box">
|
||||
<chat-member-list ref="chatMemberList" :group="group" @addCoversition="addCoversition" />
|
||||
<chat-member-list ref="chatMemberList" :group="group" :current-coversition="currentCoversition" @addCoversition="addCoversition" />
|
||||
<div class="chat-box-main">
|
||||
<chat-coversition-list ref="chatCoversitionList" @setCurrentCoversition="setCurrentCoversition" @setHeadTitle="setHeadTitle" />
|
||||
<div class="chat-window">
|
||||
@ -11,8 +11,8 @@
|
||||
<div class="minimality" @click="handleMinimality('min')">
|
||||
<i class="el-icon-remove" />
|
||||
</div>
|
||||
<div v-show="currentCoversition.group==undefined?true:currentCoversition.group" class="showMembers" @click="handleMembers()">
|
||||
<i class="el-icon-user-solid" />
|
||||
<div v-show="currentCoversition.all==undefined?true&&isShow:currentCoversition.all&&isShow" class="chat-createGroup" @click="handleCreateGroup()">
|
||||
<i class="el-icon-plus" style="font-weight: bolder;" />
|
||||
</div>
|
||||
<div class="chat-setting" @click="handleSetting()">
|
||||
<i class="el-icon-s-tools" />
|
||||
@ -43,12 +43,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<chat-setting ref="chatSetting" :form="form" @setSetting="setSetting" />
|
||||
<chat-create-group ref="createGroup" :group="group" @addCoversition="addCoversition" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import CMD from '@/scripts/cmdPlugin/CommandEnum';
|
||||
import ChatSetting from './chatSetting';
|
||||
import ChatContent from './chatContent';
|
||||
import ChatCreateGroup from './chatCreateGroup';
|
||||
import ChatMemberList from './chatMemberList';
|
||||
import ChatCoversitionList from './chatCoversitionList';
|
||||
import RecordRTC from 'recordrtc';
|
||||
@ -59,12 +61,17 @@ export default {
|
||||
ChatSetting,
|
||||
ChatContent,
|
||||
ChatMemberList,
|
||||
ChatCoversitionList
|
||||
ChatCoversitionList,
|
||||
ChatCreateGroup
|
||||
},
|
||||
props: {
|
||||
group: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
userRole: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@ -84,15 +91,12 @@ export default {
|
||||
headerTitle:''
|
||||
};
|
||||
},
|
||||
computed:{
|
||||
isShow() {
|
||||
return this.userRole != 'ADMIN' && this.userRole != 'AUDIENCE';
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$store.state.socket.simulationRoleList': function (val) {
|
||||
if (val && val.length) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.chatMemberList && this.$refs.chatMemberList.setMemberStatus(val);
|
||||
this.$refs.chatCoversitionList && this.$refs.chatCoversitionList.setCoversitionStatus(val);
|
||||
});
|
||||
}
|
||||
},
|
||||
'$store.state.socket.simulationScriptTip':function(val, old) {
|
||||
if (val) {
|
||||
if (val.type == 'Conversation') {
|
||||
@ -134,7 +138,7 @@ export default {
|
||||
},
|
||||
setCurrentCoversition(coversition) {
|
||||
this.currentCoversition = coversition;
|
||||
if (coversition.group) {
|
||||
if (coversition.all) {
|
||||
this.headerTitle = coversition.name;
|
||||
}
|
||||
if (this.recordSending) {
|
||||
@ -147,7 +151,7 @@ export default {
|
||||
},
|
||||
addCoversition({data, headerTitle}) {
|
||||
this.$refs.chatCoversitionList.addCoversition(data, headerTitle);
|
||||
this.currentCoversition = {id:data.id, group:data.group};
|
||||
this.currentCoversition = {id:data.id, all:data.all};
|
||||
this.headerTitle = headerTitle;
|
||||
},
|
||||
changeCoversition(data) {
|
||||
@ -259,12 +263,11 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
handleCreateGroup() {
|
||||
this.$refs.createGroup.doShow();
|
||||
},
|
||||
handleSetting() {
|
||||
this.$refs.chatSetting.doShow();
|
||||
},
|
||||
handleMembers() {
|
||||
this.$refs.chatSetting.doClose();
|
||||
this.$refs.chatMemberList.doShow();
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -293,6 +296,10 @@ export default {
|
||||
margin-left: 15px;
|
||||
display: inline-block;
|
||||
margin-top: 10px;
|
||||
width: 70%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.chat-box-content{
|
||||
width: 100%;
|
||||
@ -312,6 +319,14 @@ export default {
|
||||
display: inline-block;
|
||||
width: 400px;
|
||||
}
|
||||
.chat-createGroup{
|
||||
float: right;
|
||||
line-height: 40px;
|
||||
margin-right: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
}
|
||||
.chat-setting{
|
||||
float: right;
|
||||
line-height: 40px;
|
||||
|
@ -4,13 +4,13 @@
|
||||
<div v-for="(chatContent,index) in chatContentList" :key="index" class="chatContentInClass">
|
||||
<div :class="chatContent.self?'rightUser':'leftUser'">
|
||||
<div class="userHeader">
|
||||
<div v-if="chatContent.group&& !chatContent.self" class="userName">{{ covertName(chatContent.member) }}</div>
|
||||
<div v-if="chatContent.all&& !chatContent.self" class="userName">{{ covertName(chatContent.member) }}</div>
|
||||
<div :class="chatContent.self?'userChatTime textRight':'userChatTime'">{{ formatTime(chatContent.chatTime) }}</div>
|
||||
</div>
|
||||
<div class="userBubble" @click="playAudio('audio'+index)">
|
||||
<div class="userMessage">
|
||||
<!-- &&!(chatContent.self) -->
|
||||
<span v-if="chatContent.group">@{{ covertName(chatContent.targetName) }}</span>
|
||||
<span v-if="chatContent.all">@{{ covertName(chatContent.targetName) }}</span>
|
||||
<span class="el-icon-video-play playicon" />
|
||||
<span class="messageText">{{ chatContent.message }}</span>
|
||||
<audio :id="'audio'+index" :src="baseUrl+chatContent.src" style="display:none" />
|
||||
@ -46,7 +46,7 @@ export default {
|
||||
this.chatContentList.push(simulationText);
|
||||
this.scrollTop();
|
||||
} else {
|
||||
if (!simulationText.group) {
|
||||
if (!simulationText.all) {
|
||||
this.$emit('changeCoversition', simulationText);
|
||||
// this.$emit('addCoversition', {data:simulationText, headerTitle:''});
|
||||
this.chatContentList.push(simulationText);
|
||||
|
@ -32,9 +32,14 @@ export default {
|
||||
if (resp.data) {
|
||||
const data = resp.data;
|
||||
data.map(coversition=>{
|
||||
const objectCover = this.handleMemberName(coversition);
|
||||
coversition.coverName = objectCover.coversitionName;
|
||||
coversition.isOnline = objectCover.isOnline;
|
||||
if (coversition.name) {
|
||||
coversition.coverName = coversition.name;
|
||||
coversition.isOnline = true;
|
||||
} else {
|
||||
const objectCover = this.handleMemberName(coversition);
|
||||
coversition.coverName = objectCover.coversitionName;
|
||||
coversition.isOnline = objectCover.isOnline;
|
||||
}
|
||||
return coversition;
|
||||
});
|
||||
this.coversitionList = data;
|
||||
@ -49,8 +54,13 @@ export default {
|
||||
const index = this.coversitionList.findIndex(item=>{ return item.id == data.id; });
|
||||
if (index < 0) {
|
||||
const objectCover = this.handleMemberName(data);
|
||||
data.coverName = objectCover.coversitionName;
|
||||
data.isOnline = objectCover.isOnline;
|
||||
if (data.name) {
|
||||
data.coverName = data.name;
|
||||
data.isOnline = true;
|
||||
} else {
|
||||
data.coverName = objectCover.coversitionName;
|
||||
data.isOnline = objectCover.isOnline;
|
||||
}
|
||||
this.coversitionList.push(data);
|
||||
if (headerTitle) {
|
||||
this.currentCoversition = data;
|
||||
@ -58,8 +68,8 @@ export default {
|
||||
}
|
||||
},
|
||||
changeCoversition(coversition) {
|
||||
this.$emit('setHeadTitle', !coversition.isOnline ? coversition.coverName + ' (离线)' : coversition.coverName);
|
||||
this.currentCoversition = {id:coversition.id, group:coversition.group};
|
||||
this.$emit('setHeadTitle', coversition.coverName);
|
||||
this.currentCoversition = {id:coversition.id, all:coversition.all};
|
||||
this.$emit('setCurrentCoversition', coversition);
|
||||
// this.$refs.chatContent.reloadData(this.currentCoversition);
|
||||
},
|
||||
@ -74,7 +84,7 @@ export default {
|
||||
this.changeCoversition(coversition);
|
||||
},
|
||||
handleMemberName(conversition) {
|
||||
if (conversition.group) {
|
||||
if (conversition.all) {
|
||||
return {coversitionName:conversition.name, isOnline:true};
|
||||
} else {
|
||||
let coversitionName = '';
|
||||
@ -119,11 +129,6 @@ export default {
|
||||
}
|
||||
return {coversitionName:coversitionName, isOnline:isOnline};
|
||||
}
|
||||
},
|
||||
setCoversitionStatus(data) {
|
||||
this.initPage(false);
|
||||
this.$emit('setHeadTitle', !this.currentCoversition.isOnline ? this.currentCoversition.coverName + ' (离线)' : this.currentCoversition.coverName);
|
||||
// this.changeCoversition(this.currentCoversition);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
224
src/views/newMap/displayNew/chatView/chatCreateGroup.vue
Normal file
224
src/views/newMap/displayNew/chatView/chatCreateGroup.vue
Normal file
@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<div v-show="dialogVisible" class="chat-create-group">
|
||||
<div class="create-group-header">
|
||||
<div class="create-group-title">添加会话对象</div>
|
||||
<div class="create-group-close">
|
||||
<i class="el-icon-close" @click="dialogVisible=false" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="create-group-content">
|
||||
<div class="chat-member-list">
|
||||
<el-checkbox-group v-model="checkList">
|
||||
<el-checkbox
|
||||
v-for="member in memberList"
|
||||
:key="member.id"
|
||||
class="each-chat-member"
|
||||
:label="member"
|
||||
:disabled="member.userId === userId"
|
||||
>{{ member.memberName }}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
<div class="currentSelectList">
|
||||
<div
|
||||
v-for="member in checkList"
|
||||
:key="member.id"
|
||||
class="eachSelect"
|
||||
>
|
||||
{{ member.memberName }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- :style="member.userId === userId ?'color:red':''" -->
|
||||
</div>
|
||||
<div class="create-group-bottom">
|
||||
<el-button :loading="loading" size="small" type="primary" @click="doCreate">创建会话</el-button>
|
||||
<el-button size="small" @click="doClose">取消</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {getSimulationMembersNew, getSimulationConversationIdNew} from '@/api/chat';
|
||||
import ConstConfig from '@/scripts/ConstConfig';
|
||||
import Cookies from 'js-cookie';
|
||||
export default {
|
||||
name:'ChatCreateGroup',
|
||||
props: {
|
||||
group: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible:false,
|
||||
loading:false,
|
||||
memberList:[],
|
||||
checkList:[]
|
||||
};
|
||||
},
|
||||
computed:{
|
||||
userId() {
|
||||
return this.$store.state.user.id;
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
doShow() {
|
||||
this.getSimulationMembers();
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
getSimulationMembers() {
|
||||
getSimulationMembersNew(this.$route.query.group).then(resp => {
|
||||
let lastData = JSON.stringify(resp.data);
|
||||
const roleTypeList = ConstConfig.ConstSelect.roleTypeNew;
|
||||
roleTypeList.forEach(function(element) {
|
||||
const rolename = element.value;
|
||||
if (Cookies.get('user_lang') == 'en') {
|
||||
lastData = lastData.replace(new RegExp(rolename, 'g'), element.enLabel);
|
||||
} else {
|
||||
lastData = lastData.replace(new RegExp(rolename, 'g'), element.label);
|
||||
}
|
||||
});
|
||||
lastData = JSON.parse(lastData);
|
||||
lastData = lastData.filter(memberIn=>{ return memberIn.role != '观众'; });
|
||||
lastData.map(member=>{
|
||||
const deviceName = member.deviceName ? '-' + member.deviceName : '';
|
||||
const memberName = member.name ? '-' + member.name : '';
|
||||
member.memberName = member.role + deviceName + memberName;
|
||||
return member;
|
||||
});
|
||||
this.memberList = lastData;
|
||||
});
|
||||
},
|
||||
doCreate() {
|
||||
if (this.checkList.length > 0) {
|
||||
this.loading = true;
|
||||
const checkList = this.checkList.map(function(check) { return check.id; });
|
||||
getSimulationConversationIdNew(checkList, this.group).then(resp => {
|
||||
if (resp.data) {
|
||||
const data = resp.data;
|
||||
this.loading = false;
|
||||
this.$emit('addCoversition', {data:data, headerTitle:resp.data.name});
|
||||
this.dialogVisible = false;
|
||||
this.checkList = [];
|
||||
}
|
||||
}).catch(error=>{
|
||||
this.$messageBox('创建会话失败: ' + error.messagfe);
|
||||
this.loading = false;
|
||||
this.dialogVisible = false;
|
||||
this.checkList = [];
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
doClose() {
|
||||
this.checkList = [];
|
||||
this.dialogVisible = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.chat-create-group{
|
||||
position: absolute;
|
||||
width: 70%;
|
||||
height: 300px;
|
||||
border: 1px #dedede solid;
|
||||
left: 26%;
|
||||
top: 8%;
|
||||
z-index: 7;
|
||||
border-radius: 8px;
|
||||
box-shadow: #b5aeae 0 0 10px;
|
||||
background: #fff;
|
||||
}
|
||||
.create-group-header{
|
||||
padding-left: 10px;
|
||||
padding-top: 6px;
|
||||
font-size: 14px;
|
||||
border-bottom: 1px #dedede solid;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
.create-group-title{
|
||||
display: inline-block;
|
||||
}
|
||||
.create-group-close{
|
||||
float: right;
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.chat-member-list{
|
||||
width: 54%;
|
||||
height: 216px;
|
||||
overflow-y: auto;
|
||||
padding: 5px 10px;
|
||||
font-size: 14px;
|
||||
overflow-x: hidden;
|
||||
border-right: 1px #ccc solid;
|
||||
display:inline-block;
|
||||
}
|
||||
.create-group-content{
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px #dedede solid;
|
||||
}
|
||||
.create-group-bottom{
|
||||
text-align: center;
|
||||
margin-top:8px;
|
||||
}
|
||||
.each-chat-member{
|
||||
display:block;
|
||||
margin-top:5px;
|
||||
}
|
||||
.currentSelectList{
|
||||
display: inline-block;
|
||||
width: 44%;
|
||||
font-size: 14px;
|
||||
vertical-align: top;
|
||||
padding: 5px 10px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
height: 216px;
|
||||
}
|
||||
.eachSelect{
|
||||
display:block;
|
||||
margin-top:5px;
|
||||
}
|
||||
// 谷歌、safari、qq浏览器、360浏览器滚动条样式
|
||||
// 定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸
|
||||
.chat-member-list::-webkit-scrollbar,.currentSelectList::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
// height: 110px;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
/*定义滚动条轨道 内阴影+圆角*/
|
||||
.chat-member-list::-webkit-scrollbar-track,.currentSelectList::-webkit-scrollbar-track{
|
||||
// box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
||||
border-radius: 10px;
|
||||
background-color: #FFFFFF;;
|
||||
}
|
||||
/*定义滑块 内阴影+圆角*/
|
||||
.chat-member-list::-webkit-scrollbar-thumb,.currentSelectList::-webkit-scrollbar-thumb{
|
||||
border-radius: 10px;
|
||||
// box-shadow: inset 0 0 6px rgba(0,0,0,.3);
|
||||
background-color: #cacaca;
|
||||
}
|
||||
/*滑块效果*/
|
||||
.chat-member-list::-webkit-scrollbar-thumb:hover,.currentSelectList::-webkit-scrollbar-thumb:hover {
|
||||
border-radius: 5px;
|
||||
// box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
|
||||
background: rgba(0,0,0,0.4);
|
||||
}
|
||||
/*IE滚动条颜色*/
|
||||
html {
|
||||
scrollbar-face-color:#bfbfbf;/*滚动条颜色*/
|
||||
scrollbar-highlight-color:#000;
|
||||
scrollbar-3dlight-color:#000;
|
||||
scrollbar-darkshadow-color:#000;
|
||||
scrollbar-Shadow-color:#adadad;/*滑块边色*/
|
||||
scrollbar-arrow-color:rgba(0,0,0,0.4);/*箭头颜色*/
|
||||
scrollbar-track-color:#eeeeee;/*背景颜色*/
|
||||
}
|
||||
</style>
|
@ -5,14 +5,16 @@
|
||||
<div
|
||||
v-for="member in memberList"
|
||||
:key="member.id"
|
||||
:class="member.online?'each-chat-member':'each-chat-member each-chat-member-outline'"
|
||||
@click="createConversition(member)"
|
||||
:style="member.userId === userId ?'color:red':''"
|
||||
class="each-chat-member"
|
||||
:title="member.memberName"
|
||||
>{{ member.memberName }}</div>
|
||||
<!-- :class="member.online?'each-chat-member':'each-chat-member each-chat-member-outline'" -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {getSimulationMembersNew, getSimulationConversationIdNew} from '@/api/chat';
|
||||
import {getSimulationChatMemberNew} from '@/api/chat';
|
||||
import ConstConfig from '@/scripts/ConstConfig';
|
||||
import Cookies from 'js-cookie';
|
||||
export default {
|
||||
@ -21,43 +23,35 @@ export default {
|
||||
group: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
currentCoversition:{
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showMembers:false,
|
||||
showMembers:true,
|
||||
memberList:[]
|
||||
};
|
||||
},
|
||||
computed:{
|
||||
userId() {
|
||||
return this.$store.state.user.id;
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
currentCoversition:function (val, old) {
|
||||
if (val) {
|
||||
this.getSimulationMembers();
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getSimulationMembers();
|
||||
},
|
||||
methods:{
|
||||
createConversition(member) {
|
||||
if (member.userId != this.$store.state.user.id && member.online) {
|
||||
getSimulationConversationIdNew({ memberId: member.id }, this.group).then(resp => {
|
||||
if (resp.data) {
|
||||
const data = resp.data;
|
||||
this.$emit('addCoversition', {data:data, headerTitle:member.memberName});
|
||||
this.showMembers = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
setMemberStatus(memberInfo) {
|
||||
this.getSimulationMembers();
|
||||
// memberInfo.forEach(member=>{
|
||||
// if (this.coversitionList) {
|
||||
// this.coversitionList.forEach(item=>{
|
||||
// if (item.id == member.id) {
|
||||
// item.online = member.online;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
},
|
||||
getSimulationMembers() {
|
||||
getSimulationMembersNew(this.$route.query.group).then(resp => {
|
||||
getSimulationChatMemberNew(this.$route.query.group, this.currentCoversition.id).then(resp => {
|
||||
let lastData = JSON.stringify(resp.data);
|
||||
const roleTypeList = ConstConfig.ConstSelect.roleTypeNew;
|
||||
roleTypeList.forEach(function(element) {
|
||||
@ -82,14 +76,6 @@ export default {
|
||||
return this.memberList.filter(member=>{
|
||||
return member.id == memberId;
|
||||
});
|
||||
},
|
||||
doShow() {
|
||||
if (this.showMembers) {
|
||||
this.showMembers = false;
|
||||
} else {
|
||||
this.showMembers = true;
|
||||
this.getSimulationMembers();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -41,6 +41,7 @@
|
||||
:group="group"
|
||||
:quest-id="questId"
|
||||
:show-station="showStation"
|
||||
:user-role="userRole"
|
||||
@tryTime="tryTime"
|
||||
@hidepanel="hidepanel"
|
||||
@passflow="passflow"
|
||||
@ -253,6 +254,17 @@ export default {
|
||||
},
|
||||
project() {
|
||||
return getSessionStorage('project');
|
||||
},
|
||||
userRole() {
|
||||
if (this.$route.query.prdType == '02') {
|
||||
return 'DISPATCHER';
|
||||
} else if (this.$route.query.prdType == '01') {
|
||||
return 'STATION_SUPERVISOR';
|
||||
} else if (this.$route.query.prdType == '04') {
|
||||
return 'DRIVER';
|
||||
} else {
|
||||
return 'AUDIENCE';
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<chat-box ref="chatbox" :group="group" />
|
||||
<chat-box ref="chatbox" :group="group" :user-role="userRole" />
|
||||
<div class="display-card" :style="{top: offset+'px'}">
|
||||
<el-row>
|
||||
<span v-if="countTime" class="display-score">{{ $t('display.demon.trialTime') }} {{ countTime }}</span>
|
||||
@ -77,6 +77,10 @@ export default {
|
||||
default() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
userRole: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
@ -38,6 +38,7 @@ export default {
|
||||
chatContentList:[],
|
||||
coversition:{},
|
||||
currentAudioList:[],
|
||||
currentAudioIndex:0,
|
||||
isPlay:false,
|
||||
baseUrl:process.env.VUE_APP_VOICE_API
|
||||
};
|
||||
@ -122,17 +123,18 @@ export default {
|
||||
return /\d{2}:\d{2}:\d{2}/.exec(time)[0] || time;
|
||||
},
|
||||
playAllAudio() {
|
||||
// this.playEachAudio(this.currentAudioList[this.currentAudioIndex]);
|
||||
this.playEachAudio(this.currentAudioList[this.currentAudioIndex]);
|
||||
},
|
||||
playEachAudio(index) {
|
||||
playEachAudio(audioUrl) {
|
||||
this.$nextTick(function() {
|
||||
document.querySelector('#audio' + index).play();
|
||||
document.querySelector('#audioPlay').src = audioUrl;
|
||||
document.querySelector('#audioPlay').play();
|
||||
const that = this;
|
||||
document.querySelector('#audio' + index).onended = function() {
|
||||
document.querySelector('#audioPlay').onended = function() {
|
||||
that.currentAudioList.shift();
|
||||
if (that.currentAudioList.length > 0) {
|
||||
// that.currentAudioIndex++;
|
||||
// that.playEachAudio(that.currentAudioList[that.currentAudioIndex]);
|
||||
that.currentAudioIndex++;
|
||||
that.playEachAudio(that.currentAudioList[that.currentAudioIndex]);
|
||||
} else {
|
||||
that.isPlay = false;
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ export default {
|
||||
}
|
||||
},
|
||||
changeCoversition(coversition) {
|
||||
this.$emit('setHeadTitle', !coversition.isOnline ? coversition.coverName + ' (离线)' : coversition.coverName);
|
||||
this.$emit('setHeadTitle', coversition.coverName);
|
||||
this.currentCoversition = {id:coversition.id, all:coversition.all};
|
||||
this.$emit('setCurrentCoversition', coversition);
|
||||
// this.$refs.chatContent.reloadData(this.currentCoversition);
|
||||
|
@ -133,6 +133,14 @@
|
||||
@setCenter="setCenter"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="供电线" class="tab_pane_box" name="Power" :lazy="lazy">
|
||||
<power-draft
|
||||
ref="Power"
|
||||
:selected="selected"
|
||||
@updateMapModel="updateMapModel"
|
||||
@setCenter="setCenter"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('map.text')" class="tab_pane_box" name="Text" :lazy="lazy">
|
||||
<text-draft
|
||||
ref="Text"
|
||||
@ -211,6 +219,7 @@ import PsdDraft from './psdDraft';
|
||||
import EspDraft from './espDraft';
|
||||
import TrainDraft from './train/index';
|
||||
import LineDraft from './line';
|
||||
import PowerDraft from './power';
|
||||
import TextDraft from './text';
|
||||
import ControlDraft from './ControlDraft';
|
||||
import TrainWindowDraft from './trainwindow';
|
||||
@ -242,6 +251,7 @@ export default {
|
||||
TrainWindowDraft,
|
||||
TrainDraft,
|
||||
LineDraft,
|
||||
PowerDraft,
|
||||
TextDraft,
|
||||
ZcControlDraft,
|
||||
OutFrameDraft,
|
||||
|
@ -225,7 +225,7 @@ export default {
|
||||
this.editModel.points.splice(index + 1, 0, data);
|
||||
},
|
||||
delPoint(index) {
|
||||
this.editModel.points.splice(index + 1, 0);
|
||||
this.editModel.points.splice(index, 1);
|
||||
},
|
||||
addPointAddModel(index) {
|
||||
const data = { x: 0, y: 0};
|
||||
|
315
src/views/newMap/newMapdraft/mapoperate/power.vue
Normal file
315
src/views/newMap/newMapdraft/mapoperate/power.vue
Normal file
@ -0,0 +1,315 @@
|
||||
<template>
|
||||
<el-tabs v-model="activeName" class="card">
|
||||
<el-tab-pane class="view-control" :label="$t('map.property')" name="first" :lazy="lazy">
|
||||
<div style="height: calc(100% - 46px);">
|
||||
<el-scrollbar wrap-class="scrollbar-wrapper">
|
||||
<config-list ref="form" :form="form" :form-model="editModel" :rules="rules" />
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<el-button-group class="map-draft-group">
|
||||
<el-button type="primary" size="small" @click="edit">{{ $t('map.updateObj') }}</el-button>
|
||||
<el-button type="danger" size="small" @click="deleteObj">{{ $t('map.deleteObj') }}</el-button>
|
||||
</el-button-group>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane class="view-control" :label="$t('map.newConstruction')" name="second" :lazy="lazy">
|
||||
<div style="height: calc(100% - 46px);">
|
||||
<el-scrollbar wrap-class="scrollbar-wrapper">
|
||||
<el-form ref="make" label-width="120px" :model="addModel" size="mini" :rules="makeRules">
|
||||
<el-form-item :label="$t('map.lineWidth')" prop="width">
|
||||
<el-input-number v-model="addModel.width" :min="1" />px
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('map.showConditions')" prop="showConditions">
|
||||
<el-radio-group v-model="addModel.showConditions">
|
||||
<el-radio label="01">{{ $t('map.localCenter') }}</el-radio>
|
||||
<el-radio label="02">{{ $t('map.center') }}</el-radio>
|
||||
<el-radio label="03">{{ $t('map.local') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<div class="coordinate">
|
||||
<span class="title">{{ $t('map.linePoint') }}</span>
|
||||
<div class="point-section">
|
||||
<template v-for="(point, index) in addModel.points">
|
||||
<div :key="index" style="overflow: hidden;">
|
||||
<el-form-item
|
||||
label=""
|
||||
:prop="'points[' + index + '].x'"
|
||||
style="display: table; float: left;"
|
||||
label-width="0px"
|
||||
>
|
||||
<el-input-number v-model="point.x" />
|
||||
</el-form-item>
|
||||
<span style="display: table; margin-left: 8px; float: left; line-height: 28px;">
|
||||
, </span>
|
||||
<el-form-item
|
||||
label=""
|
||||
:prop="'points[' + index + '].y'"
|
||||
style="display: table; float: left; margin-right: 5px;"
|
||||
label-width="10px"
|
||||
>
|
||||
<el-input-number v-model="point.y" />
|
||||
</el-form-item>
|
||||
<el-button
|
||||
icon="el-icon-plus"
|
||||
circle
|
||||
class="point-button"
|
||||
@click="addPointAddModel(index)"
|
||||
/>
|
||||
<el-button
|
||||
icon="el-icon-minus"
|
||||
:disabled="index == 0 || index == addModel.points.length - 1"
|
||||
circle
|
||||
class="point-button"
|
||||
@click="delPointAddModel(index)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<el-button-group class="map-draft-group">
|
||||
<el-button type="primary" size="small" @click="create">{{ $t('map.create') }}</el-button>
|
||||
</el-button-group>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { getUID } from '@/jmapNew/utils/Uid';
|
||||
import ConfigList from './config/list';
|
||||
import { deepAssign } from '@/utils/index';
|
||||
|
||||
export default {
|
||||
name: 'StationStandDraft',
|
||||
components: {
|
||||
ConfigList
|
||||
},
|
||||
props: {
|
||||
selected: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: 'first',
|
||||
lazy: true,
|
||||
showConditionsList: [
|
||||
{ label: this.$t('map.localCenter'), value: '01'},
|
||||
{ label: this.$t('map.center'), value: '02' },
|
||||
{ label: this.$t('map.local'), value: '03'}
|
||||
],
|
||||
terminalList: [
|
||||
{ label: '显示', value: true},
|
||||
{ label: '隐藏', value: false }
|
||||
],
|
||||
editModel: {
|
||||
code: '',
|
||||
width: 1,
|
||||
leftTerminal: true,
|
||||
rightTerminal: true,
|
||||
showConditions: '01', // 显示条件
|
||||
points: []
|
||||
},
|
||||
addModel: {
|
||||
width: 1,
|
||||
showConditions: '01',
|
||||
points: [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 100, y: 100 }
|
||||
]
|
||||
},
|
||||
rules: {
|
||||
code: [
|
||||
{ required: true, message: this.$t('rules.pleaseSelectLine'), trigger: 'blur' }
|
||||
],
|
||||
width: [
|
||||
{ required: true, message: this.$t('rules.pleaseSelectLineWidth'), trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
makeRules: {
|
||||
code: [
|
||||
{ required: true, message: this.$t('rules.pleaseSelectLine'), trigger: 'blur' }
|
||||
],
|
||||
width: [
|
||||
{ required: true, message: this.$t('rules.pleaseSelectLineWidth'), trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('map', [
|
||||
'powerList'
|
||||
]),
|
||||
form() {
|
||||
const form = {
|
||||
labelWidth: '120px',
|
||||
items: {
|
||||
code: {
|
||||
name: '',
|
||||
item: []
|
||||
},
|
||||
draw: {
|
||||
name: this.$t('map.drawData'),
|
||||
item: [
|
||||
{ prop: 'code', label: '供电线路', type: 'select', optionLabel: 'code', optionValue: 'code', options: this.powerList, change: true, deviceChange: this.deviceChange },
|
||||
{ prop: 'width', label: '供电线路宽度', type: 'number', min: 1, placeholder: 'px' },
|
||||
{ prop: 'showConditions', label: this.$t('map.showConditions'), type: 'radio', optionLabel: 'label', optionValue:'value', radioList: this.showConditionsList},
|
||||
{ prop: 'leftTerminal', label: '左侧端点:', type: 'select', optionLabel: 'label', optionValue:'value', options: this.terminalList},
|
||||
{ prop: 'rightTerminal', label: '右侧端点:', type: 'select', optionLabel: 'label', optionValue:'value', options: this.terminalList},
|
||||
{ prop: 'points', label: this.$t('map.segmentCoordinates'), type: 'points', width: '100px', isHidden: !this.isPointsShow, addPoint: this.addPoint, delPoint: this.delPoint }
|
||||
]
|
||||
},
|
||||
map: {
|
||||
name: this.$t('map.mapData'),
|
||||
item: [
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
return form;
|
||||
},
|
||||
isPointsShow() {
|
||||
return this.editModel.points.length > 0;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
deviceChange(code) {
|
||||
this.$emit('setCenter', code);
|
||||
this.deviceSelect(this.$store.getters['map/getDeviceByCode'](code));
|
||||
},
|
||||
deviceSelect(selected) {
|
||||
if (selected && selected._type.toUpperCase() === 'Power'.toUpperCase()) {
|
||||
this.$refs.form && this.$refs.form.resetFields();
|
||||
this.$refs.make && this.$refs.make.resetFields();
|
||||
this.activeName = 'first';
|
||||
this.editModel = deepAssign(this.editModel, selected);
|
||||
}
|
||||
},
|
||||
addPoint(index) {
|
||||
const data = { x: 0, y: 0 };
|
||||
this.editModel.points.splice(index + 1, 0, data);
|
||||
},
|
||||
delPoint(index) {
|
||||
this.editModel.points.splice(index, 1);
|
||||
},
|
||||
addPointAddModel(index) {
|
||||
const data = { x: 0, y: 0};
|
||||
this.addModel.points.splice(index + 1, 0, data);
|
||||
},
|
||||
delPointAddModel(index) {
|
||||
this.addModel.points.splice(index, 1);
|
||||
},
|
||||
create() {
|
||||
this.$refs['make'].validate((valid) => {
|
||||
if (valid) {
|
||||
if (JSON.stringify(this.addModel.points[0]) !== JSON.stringify(this.addModel.points[this.addModel.points.length - 1])) {
|
||||
const pointArr = JSON.stringify(this.addModel.points);
|
||||
const model = {
|
||||
_type: 'Power',
|
||||
code: getUID('Power', this.powerList),
|
||||
width: this.addModel.width,
|
||||
leftTerminal: true,
|
||||
rightTerminal: true,
|
||||
showConditions: this.addModel.showConditions,
|
||||
points: JSON.parse(pointArr)
|
||||
};
|
||||
this.$emit('updateMapModel', model);
|
||||
this.$refs.make && this.$refs.make.resetFields();
|
||||
} else {
|
||||
this.$message.console.error(this.$t('tip.cannotCoincide'));
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// 修改对象
|
||||
edit() {
|
||||
this.$refs['form'].validate((valid) => {
|
||||
if (valid) {
|
||||
const data = Object.assign({_type: 'Line'}, this.editModel);
|
||||
this.$emit('updateMapModel', data);
|
||||
}
|
||||
});
|
||||
},
|
||||
// 删除对象
|
||||
deleteObj() {
|
||||
const selected = this.$store.getters['map/getDeviceByCode'](this.editModel.code);
|
||||
if (selected && selected._type.toUpperCase() === 'Line'.toUpperCase()) {
|
||||
this.$confirm(this.$t('tip.confirmDeletion'), this.$t('tip.hint'), {
|
||||
confirmButtonText: this.$t('tip.confirm'),
|
||||
cancelButtonText: this.$t('tip.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$emit('updateMapModel', {...selected, _dispose: true});
|
||||
this.$refs.form && this.$refs.form.resetFields();
|
||||
}).catch(() => {
|
||||
this.$message.info(this.$t('tip.cancelledDelete'));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
@import "src/styles/mixin.scss";
|
||||
.view-control{
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.card {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.coordinate {
|
||||
overflow: hidden;
|
||||
|
||||
.title {
|
||||
text-align: right;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
line-height: 40px;
|
||||
padding: 0 12px 0 0;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
line-height: 28px;
|
||||
width: 120px;
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
.point-section {
|
||||
/*float: left;*/
|
||||
position: absolute;
|
||||
left: 120px;
|
||||
width: calc(100% - 120px);
|
||||
}
|
||||
|
||||
.point-button {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
float: left;
|
||||
|
||||
/deep/ {
|
||||
.el-icon-plus,
|
||||
.el-icon-minus {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-input-number--mini {
|
||||
width: 110px;
|
||||
}
|
||||
</style>
|
2339
static/model/path/path.obj
Normal file
2339
static/model/path/path.obj
Normal file
File diff suppressed because it is too large
Load Diff
25
static/workertest/passsimulation/passer.js
Normal file
25
static/workertest/passsimulation/passer.js
Normal file
@ -0,0 +1,25 @@
|
||||
var i=0;
|
||||
var update = null;
|
||||
function timedCount(){
|
||||
|
||||
onmessage = (e) => {
|
||||
|
||||
|
||||
if(e.data == "on"){
|
||||
|
||||
update = setInterval("passerupdate()", 50);
|
||||
}
|
||||
|
||||
if(e.data == "off"){
|
||||
clearInterval(update);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
function passerupdate(){
|
||||
|
||||
postMessage("up");
|
||||
}
|
||||
|
||||
timedCount();
|
25
static/workertest/passsimulation/station.js
Normal file
25
static/workertest/passsimulation/station.js
Normal file
@ -0,0 +1,25 @@
|
||||
var i=0;
|
||||
var update = null;
|
||||
function timedCount(){
|
||||
|
||||
onmessage = (e) => {
|
||||
|
||||
|
||||
if(e.data == "on"){
|
||||
console.log("on");
|
||||
update = setInterval("stationupdate()", 3000);
|
||||
}
|
||||
|
||||
if(e.data == "off"){
|
||||
clearInterval(update);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
function stationupdate(){
|
||||
|
||||
postMessage("up");
|
||||
}
|
||||
|
||||
timedCount();
|
Loading…
Reference in New Issue
Block a user