This commit is contained in:
wang_yp 2024-10-06 17:19:13 +08:00
parent acad2d3431
commit fa2023f223
29 changed files with 2691 additions and 876 deletions

449
org.html Normal file
View File

@ -0,0 +1,449 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Title</title>
</head>
<style>
@media screen and(-ms-high-contrast:active),(-ms-high-contrast:none) {
.ie_display{
display: flex;
flex-direction: column;
align-items: center;
}
.ie_margin{
margin-left: -10px!important;
}
}
</style>
<body style="overflow-y: scroll;">
<div id="depart" style="display: flex;justify-content: center;padding: 30px"></div>
</body>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
var isCompany = false;
//配置公司背景色,部门背景色,用户所在部门背景色
var comBackground = 'linear-gradient(#2196f3,#4c6cca)';
var depBackground = 'linear-gradient(#673ab7,#4c6cca)';
var userBackground = 'linear-gradient(#4CAF50,#4c6cca)';
//获取用户所在部门和id
var userDepName = '技术部';
var userDepId = '7';
var isHasTopCom = false;//是否需要另设顶层公司
var topCompany = 'XXX集团有限公司';//顶层公司名称
//1.接口返回原始数据结构
var depArr = [
{departmentname: 'CEO', subcompanyid1: '2', supdepid: '0', id: '1'},
{departmentname: '销售与市场', subcompanyid1: '3', supdepid: '1', id: '2'},
{departmentname: '生产', subcompanyid1: '2', supdepid: '1', id: '3'},
{departmentname: '人力资源部', subcompanyid1: '2', supdepid: '2', id: '4'},
{departmentname: '物流&客服部', subcompanyid1: '3', supdepid: '3', id: '5'},
{departmentname: '计划&采购部', subcompanyid1: '3', supdepid: '3', id: '6'},
{departmentname: '技术部', subcompanyid1: '2', supdepid: '4', id: '7'},
{departmentname: '采购部', subcompanyid1: '2', supdepid: '5', id: '8'},
{departmentname: '销售部', subcompanyid1: '2', supdepid: '6', id: '9'},
];
var comArr = [
{subcompanyname: 'XXX有限公司', supsubcomid: '0', id: '1'},
{subcompanyname: 'XXX有限公司华中分公司', supsubcomid: '1', id: '2'},
{subcompanyname: 'XXX有限公司华南分公司', supsubcomid: '1', id: '3'},
];
//2.将接口返回的数据拼接成链表结构
function findDep(depArr, str, arrNew) {
var arr = arrNew || [];
depArr.map(function(item, index){
if (item.departmentname == str) {
depArr.map(function(item1, index){
if (item1.id == item.supdepid) {
arr.push(item1);
if (item.supdepid == '0') {
return;
}
findDep(depArr, item1.departmentname, arr);
}
})
}
})
return arr;
}
var newComArr = [];
if(isHasTopCom){
newComArr.push({
departmentname: topCompany,
supdepid: '0',
id: '8888',
});
}
comArr.map(function(item, index){
if(isHasTopCom){
if (item.supsubcomid === '0') {
item.supsubcomid = '8888';
};
}
newComArr.push({
departmentname: item.subcompanyname,
supdepid: item.supsubcomid,
id: item.id,
});
});
function bibao(obj, s, m, str) {
var x1 = m || [];
for (var i = 0; i < obj.length; i++) {
if (obj[i].supdepid == s) {
x1.push(obj[i]);
x1.map(function (item, index) {
if (item.subcompanyid1 && isCompany) {
} else {
x1[index].child = [];
}
if (str) {
isCompany = true;
for (var i = 0; i < str.length; i++) {
if (item.id == str[i].subcompanyid1 && !item.subcompanyid1) {
x1[index].child.push(str[i]);
}
}
}
return bibao(obj, item.id, x1[index].child, str);
})
}
}
return x1;
};
var arr = bibao(depArr, '0');
var gData = bibao(newComArr,'0', [], arr);
//3.界面和样式的处理
function generate(obj, num, cb) {
if (obj && obj[0]) {
obj.map(function (item, index) {
var html = '';
var str = item.departmentname;
if (item.departmentname.indexOf(" ") > -1) {
item.departmentname = item.departmentname.replace(/\s*/g, "");
}
var str1 = '';
if (item.departmentname.indexOf('-') > -1) {
str1 = item.departmentname.replace(/-/g, '')
}else if (item.departmentname.indexOf('&') > -1) {
str1 = item.departmentname.replace(/&/g, '')
}else if (item.departmentname.indexOf('—') > -1) {
str1 = item.departmentname.replace(/—/g, '')
} else if (item.departmentname.indexOf('.') > -1) {
str1 = item.departmentname.replace(/./g, '')
} else if (item.departmentname.indexOf('') > -1) {
str1 = item.departmentname.replace(//g, '')
} else if (item.departmentname.indexOf('') > -1) {
str1 = item.departmentname.replace(//g, '')
} else if (item.departmentname.indexOf('') > -1 && item.departmentname.indexOf('') > -1) {
str1 = item.departmentname.replace(//g, '').replace(//g, '');
} else if (item.departmentname.indexOf('(') > -1 && item.departmentname.indexOf(')') > -1) {
str1 = item.departmentname.replace('(', '').replace(')', '');
} else if (item.departmentname.indexOf('-') > -1 && item.departmentname.indexOf('(') > -1 && item.departmentname.indexOf(')') > -1) {
str1 = item.departmentname.replace(/-/g, '').replace('(', '').replace(')', '');
} else if (item.departmentname.indexOf('-') > -1 && item.departmentname.indexOf('') > -1 && item.departmentname.indexOf('') > -1) {
str1 = item.departmentname.replace(/-/g, '').replace(//g, '').replace(//g, '');
} else {
str1 = item.departmentname;
}
var idStr = str1 + item.id;
var idStrSpan = item.departmentname + item.id + 'span';
var child = item.child;
var spanBar = num != 1 ? "<div style='background: #4c6cca;display: block;width: 3px;height: 20px;margin: auto;'></div>" : "<span></span>";
var background = item.subcompanyid1 ? depBackground : comBackground;
if (item.departmentname == userDepName && item.id== userDepId) {
background = userBackground;
}
var span = child && child.length > 0 ? "<div id=" + idStrSpan + " style='color:#fff;cursor:pointer;font-size: 25px;margin-top: -10px' onclick='display(" + JSON.stringify(item) + ",$(this)," + index + ")'>+</div>" : "<span></span>";
html += "<div class='ie_display' style='text-align: center;font-size:14px;color:#fff;width: 200px'><div style='display:flex;align-items: center'><div>" + spanBar + "<div style='background: " + background + ";box-shadow:5px 5px 5px #6A48D7;width: 150px;margin: auto;text-align: center;border-radius: 5px;display: flex;align-items:center;justify-content:space-between;height: 60px'><div style='width: 20px'></div><div>" + str + "</div><div style='display: flex;flex-direction: column;height: 100%;justify-content: space-between'>" + span + "<div style='align-self: flex-end;width: 20px;border-radius: 50%;background: #fff;color: #4c6cca'>" + child.length + "</div></div></div></div></div><div id=" + "'" + idStr + "'" + " style='display: flex;justify-content: center;'></div></div>";
if (cb) {
cb(html)
}
})
}
};
generate(gData, 1, function (html) {
$('#depart').append(html)
});
//4.点击触发generate方法挂载界面(点击右上角的+或-按钮)
function display(item, that, index) {
var str1 = '';
if (item.departmentname.indexOf('-') > -1) {
str1 = item.departmentname.replace(/-/g, '')
} else if (item.departmentname.indexOf('&') > -1) {
str1 = item.departmentname.replace(/&/g, '')
}else if (item.departmentname.indexOf('—') > -1) {
str1 = item.departmentname.replace(/—/g, '')
} else if (item.departmentname.indexOf('.') > -1) {
str1 = item.departmentname.replace(/./g, '')
} else if (item.departmentname.indexOf('') > -1) {
str1 = item.departmentname.replace(//g, '')
} else if (item.departmentname.indexOf('') > -1) {
str1 = item.departmentname.replace(//g, '')
} else if (item.departmentname.indexOf('') > -1 && item.departmentname.indexOf('') > -1) {
str1 = item.departmentname.replace(//g, '').replace(//g, '');
} else if (item.departmentname.indexOf('(') > -1 && item.departmentname.indexOf(')') > -1) {
str1 = item.departmentname.replace('(', '').replace(')', '');
} else if (item.departmentname.indexOf('-') > -1 && item.departmentname.indexOf('(') > -1 && item.departmentname.indexOf(')') > -1) {
str1 = item.departmentname.replace(/-/g, '').replace('(', '').replace(')', '');
} else if (item.departmentname.indexOf('-') > -1 && item.departmentname.indexOf('') > -1 && item.departmentname.indexOf('') > -1) {
str1 = item.departmentname.replace(/-/g, '').replace(//g, '').replace(//g, '');
} else {
str1 = item.departmentname;
}
var str = str1 + item.id;
var child = item.child;
var spanLeftImg = child[0].subcompanyid1 ? './leftDep.png' : './leftCom.png';
var spanRightImg = child[0].subcompanyid1 ? './rightDep.png' : './rightCom.png';
if(Number($('#depart')[0].style.left.replace('px',''))>0){
}else {
$('#depart').css({
'position': 'relative',
'left': "0px",
'transition-property': 'all',
'transition-duration': '1.5s'
});
}
if (child) {
if ($('#' + str).children('div').length > 0) {
that.html('+');
$('#' + str + '>div').remove();
if (child.length !== 1) {
$('#' + str).prev().remove();
}
} else {
var firstChild = 0;
var divLeft = 0;
var lineWidth = 0;
that.html('-');
$('#' + str).before('<div style="width: 150px"><div style="background: #4c6cca;display: block;width: 3px;height: 20px;margin: auto;"></div><div style="height: 3px;background: #4c6cca;margin-left: -26px"></div></div>');
generate(child, '', function (html) {
$('#' + str).append("<div style=''>" + html + "</div>");
$('#' + str).css('margin-bottom', '20px');
var childNum = $('#' + str).children('div').length;
var maxNum = parseInt((window.innerWidth-5)/200);
var siblings = ($('#' + str).parent().parent().siblings());
var windowWidth = window.innerWidth;
//右边越界
if ($('#' + str) && $('#' + str).children('div:first-child')[0] && ($('#' + str).children('div:last-child')[0].offsetLeft > windowWidth - 200) && child.length < maxNum) {
$('#depart').css({
position: 'relative',
'left': -($('#' + str).children('div:last-child')[0].offsetLeft + 200 - windowWidth) + 'px',
'transition-property': 'all',
'transition-duration': '1s'
});
}
for (var i = 0; i < siblings.length; i++) {
if ($(siblings[i])[0].childElementCount > 0 && $(siblings[i])[0].id!='span1'&& $(siblings[i])[0].id!='span2') {
if ($(siblings[i]).children().children('div:last-child').children().length > 0) {
if ($(siblings[i]).children().children('div:last-child').children().length > 1) {
$(siblings[i]).children().children('div:last-child').prev().remove();
}
$(siblings[i]).children().children('div:first-child').children('div:last-child').children('div:last-child').children('div:last-child').children('div:first-child').html('+');
$(siblings[i]).children().children('div:last-child').children().remove();
}
}
}
if (200 * (childNum + 1) - 197 >= window.innerWidth) {
if (isIE()) {
console.log(isIE())
$('#' + str).css({position: 'absolute', left: '-28px', right: 0});
} else {
$('#' + str).css({position: 'absolute', left: 0, right: 0});
}
$('#' + str).css({position: 'absolute', left: 0, right: 0});
$('#' + str).children("div:nth-child(" + childNum + ")").css('display', 'none');
if ($('#' + str).children("div:first-child")[0]&&$('#' + str).children("div:first-child")[0].id != 'span1') {
$('#' + str).children("div:first-child").before('<div id="span1" class="ie_positon_span1" style="margin-top: 23px;cursor: pointer" onclick="leftDir(' + str + ')"><img src=' + spanLeftImg + ' alt="" style="width:40px;height: 50px"/></div>');
}
$('#' + str).children('#span1').css('visibility', 'hidden');
if ($('#' + str).children('#span2').length == 0) {
$('#' + str).children("div:nth-child(" + Number(maxNum + 1) + ")").after('<div id="span2" class="ie_margin" style="margin-top: 23px;cursor: pointer;margin-left: -40px" onclick="rightDir(' + str + ')"><img src=' + spanRightImg + ' alt="" style="width:40px;height: 50px"/></div>');
}
divLeft = $('#' + str).children("div:nth-child(2)").children("div:first-child").children("div:first-child").children("div:first-child").children("div:first-child")[0].offsetLeft+1.5;
lineWidth = 200 * (maxNum - 1);
firstChild = $('#' + str).children('#span1')&&$('#' + str).children('#span1')[0].offsetLeft;
} else {
divLeft = $('#' + str).children("div:first-child").children("div:first-child").children("div:first-child").children("div:first-child").children("div:first-child")[0].offsetLeft;
lineWidth = 200 * (childNum - 1) + 3 ;
firstChild = $('#' + str).children("div:first-child")[0].offsetLeft;
}
//左边越界
if (firstChild+Number($('#depart')[0].offsetLeft)<=0) {
$('#depart').css({
'position': 'relative',
'left': -firstChild + 'px',
'transition-property': 'all',
'transition-duration': '1s'
});
}
$('#' + str).prev().children("div:last-child").css({
'width': lineWidth + 'px',
'margin-left': '0px',
'position': 'absolute',
'left': divLeft+ 'px',
});
if (child.length == 1) {
$('#' + str).prev().remove();
}
});
}
}
}
//5.创建用户所属的组织链条
var count = 0;
function findDep(depArr, str, id, arrNew) {
var arr = arrNew || [{child: []}];
count++;
for (var n = 0; n < depArr.length; n++) {
var item = depArr[n];
if (item.departmentname == str && item.id == id) {
for (var m = 0; m < depArr.length; m++) {
var item1 = depArr[m];
if (item1.id == item.supdepid) {
var itemStr = item1.child;
for (var i = 0; i < itemStr.length; i++) {
if (item.departmentname == itemStr[i].departmentname) {
if (count % 2 == 0) {
arr[0].name = item1.departmentname;
arr[0].no = i;
}
if (count % 2 != 0) {
arr[0].child.push({name: item1.departmentname, no: i});
}
}
}
var arrNew = arr;
if (arr[0].name != undefined && arr[0].child.length > 0) {
arrNew = [{child: arr}];
count--;
}
if (item1.supdepid == '0' && item1.subcompanyid1 == undefined) {
return arr;
} else if (item1.supdepid == '0') {
for (var i = 0; i < newComArr.length; i++) {
if (newComArr[i].id == item1.subcompanyid1) {
var itemStr1 = newComArr[i].child;
for (var j = 0; j < itemStr1.length; j++) {
if (item1.departmentname == itemStr1[j].departmentname) {
arrNew[0].name = newComArr[i].departmentname;
arrNew[0].no = j;
return findDep(newComArr, newComArr[i].departmentname, newComArr[i].id, [{child: arrNew}]);
break;
}
}
}
}
} else {
return findDep(depArr, item1.departmentname, item1.id, arrNew);
}
break;
}else if(item.supdepid == '0'){
var arrNew = arr;
if (arr[0].name != undefined && arr[0].child.length > 0) {
arrNew = [{child: arr}];
count--;
}
for (var i = 0; i < newComArr.length; i++) {
if (newComArr[i].id == item.subcompanyid1) {
var itemStr1 = newComArr[i].child;
for (var j = 0; j < itemStr1.length; j++) {
if (item.departmentname == itemStr1[j].departmentname) {
arrNew[0].name = newComArr[i].departmentname;
arrNew[0].no = j;
return findDep(newComArr, newComArr[i].departmentname, newComArr[i].id, [{child: arrNew}]);
break;
}
}
}
}
}
}
break;
}
}
}
var depChain = findDep(depArr, userDepName, userDepId);
function displayDep(obj, objN, index) {
var objM = obj[index];
var idStrSpan = objM.departmentname + objM.id + 'span';
display(objM, $('#' + idStrSpan));
if (objN && objN.length > 0) {
if (objM.departmentname == objN[0].name) {
if (objN[0].child && objN[0].child.length > 0) {
displayDep(objM.child, objN[0].child, objN[0].no);
}
}
}
}
;
displayDep(gData, depChain, 0);
//点击右边箭头
function rightDir(str) {
if ($(str).children('#span1')[0].style.visibility == 'hidden') {
$(str).children('#span1').css('visibility', 'visible');
}
$(str).children('#span1').next().css('display', 'none');
$(str).children('#span1').insertAfter($(str).children('#span1').next());
$(str).children('#span2').next().css('display', 'block');
$(str).children('#span2').insertAfter($(str).children('#span2').next());
if ($(str).children('#span2').next().length == 0) {
$(str).children('#span2').css('visibility', 'hidden');
}
removeChild(str);
}
//点击左边箭头
function leftDir(str) {
if ($(str).children('#span2')[0].style.visibility == 'hidden') {
$(str).children('#span2').css('visibility', 'visible');
}
$(str).children('#span1').prev().css('display', 'block');
$(str).children('#span1').insertBefore($(str).children('#span1').prev());
$(str).children('#span2').prev().css('display', 'none');
$(str).children('#span2').insertBefore($(str).children('#span2').prev());
if ($(str).children('#span1').prev().length == 0) {
$(str).children('#span1').css('visibility', 'hidden');
}
removeChild(str);
}
//公共方法-点击箭头之后删掉下面的所属机构
function removeChild(father) {
$('#depart').css({
position: 'relative',
'left': "0px",
'transition-property': 'all',
'transition-duration': '1.5s'
});
var siblings = $(father).children();
for (var i = 0; i < siblings.length; i++) {
if ($(siblings[i])[0].childElementCount > 0) {
if ($(siblings[i]).children().children('div:last-child').children().length > 0) {
if ($(siblings[i]).children().children('div:last-child').children().length > 1) {
$(siblings[i]).children().children('div:last-child').prev().remove();
}
$(siblings[i]).children().children('div:last-child').children().remove();
$(siblings[i]).children().children('div:first-child').children('div:last-child').children('div:last-child').children('div:last-child').children('div:first-child').html('+');
}
}
}
}
//判断是否是ie浏览器
function isIE() {
if (!!window.ActiveXObject || "ActiveXObject" in window) {
return true;
} else {
return false;
}
}
</script>
</html>

1229
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@
"@amap/amap-jsapi-loader": "^1.0.1",
"@babel/core": "^7.16.0",
"@craco/craco": "^6.4.5",
"@dabeng/react-orgchart": "^1.0.3",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
"@svgr/webpack": "^6.5.0",
"@testing-library/jest-dom": "^5.16.5",
@ -38,6 +39,7 @@
"eslint": "^8.3.0",
"eslint-config-react-app": "^7.0.1",
"eslint-webpack-plugin": "^3.1.1",
"expose-loader": "^5.0.0",
"file-loader": "^6.2.0",
"fs-extra": "^10.0.0",
"html-webpack-plugin": "^5.5.0",
@ -45,11 +47,13 @@
"jest": "^27.4.3",
"jest-resolve": "^27.4.2",
"jest-watch-typeahead": "^1.0.0",
"jquery": "^3.7.1",
"less": "^4.1.3",
"less-loader": "^11.1.0",
"mini-css-extract-plugin": "^2.4.5",
"mobx": "^6.6.2",
"mobx-react": "^7.5.3",
"orgchart": "^4.0.1",
"postcss": "^8.4.4",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-loader": "^6.2.1",
@ -70,6 +74,7 @@
"semver": "^7.3.5",
"source-map-loader": "^3.0.0",
"style-loader": "^3.3.1",
"styled-components": "^6.1.13",
"tailwindcss": "^3.0.2",
"terser-webpack-plugin": "^5.2.5",
"typescript": "^4.8.4",
@ -77,7 +82,6 @@
"webpack": "^5.64.4",
"webpack-dev-server": "^4.6.0",
"webpack-manifest-plugin": "^4.0.2",
"webrtc": "^1.14.1",
"workbox-webpack-plugin": "^6.4.1"
},
"scripts": {

View File

@ -39,6 +39,7 @@ export interface SimpleFormData {
formDatas: Array<FormDatas>,
createCallback?: Function
children?: React.ReactElement
childrenPosi?: boolean
}

View File

@ -29,7 +29,7 @@ const SimpleForm = (props: SimpleFormData) => {
onFinish={onFinish}
autoComplete="on"
>
{props.children ?? props.children}
{props.childrenPosi? null: props.children ?? props.children}
{props.formDatas.map((v) => {
switch (v.type) {
case FormType.input:
@ -205,6 +205,7 @@ const SimpleForm = (props: SimpleFormData) => {
);
}
})}
{props.childrenPosi? props.children ?? props.children: null}
</Form>
);
};

View File

@ -1,5 +1,27 @@
import "./org_chart.less";
const OrgChart = () => {
const getArrayDepth=(arr)=> {
let maxDepth = 0;
let maxUser =0;
function dfs(currentArr, currentDepth) {
currentDepth++;
for (let i = 0; i < currentArr.length; i++) {
if (Array.isArray(currentArr[i].children)) {
dfs(currentArr[i].children, currentDepth);
} else {
maxUser = Math.max(maxUser, currentArr[i].userList.length);
maxDepth = Math.max(maxDepth, currentDepth);
}
}
}
dfs(arr, 0);
return maxUser;
}
// 示例代码
// const arr = [[1, 2, [3, 4]], [[5], 6], 7];
// console.log(getArrayDepth(arr)); // 输出: 3
const data = [
{
depName: "镇武装部党委",
@ -31,37 +53,37 @@ const OrgChart = () => {
userList: [
{
position: "一小组长",
userName: "一小组长",
userName: "一小组长1",
userId: 6,
},
{
position: "二小组长",
userName: "二小组长",
position: "二小组长12",
userName: "二小组长2",
userId: 8,
},
{
position: "战士",
userName: "王小三",
userName: "王小三3",
userId: 11,
},
{
position: "战士",
userName: "王小四",
userName: "王小四4",
userId: 12,
},
{
position: "二小组长",
userName: "二小组长",
position: "二小组长34",
userName: "二小组长5",
userId: 8,
},
{
position: "战士",
userName: "王小三",
userName: "王小三6",
userId: 11,
},
{
position: "战士",
userName: "王小四",
userName: "王小四7",
userId: 13,
},
],
@ -71,18 +93,18 @@ const OrgChart = () => {
depId: 7,
userList: [
{
position: "二小组长",
userName: "二小组长",
position: "二小组长8",
userName: "二小组长9",
userId: 7,
},
{
position: "二小组长",
userName: "二小组长",
position: "二小组长10",
userName: "二小组长11",
userId: 8,
},
{
position: "战士",
userName: "王小三",
userName: "王小三14",
userId: 11,
},
{
@ -115,8 +137,8 @@ const OrgChart = () => {
userId: 7,
},
{
position: "二小组长",
userName: "二小组长",
position: "二小组长2",
userName: "二小组长11",
userId: 8,
},
{
@ -126,18 +148,18 @@ const OrgChart = () => {
},
{
position: "战士",
userName: "王小四",
userName: "王小四12",
userId: 12,
},
{
position: "二小组长",
position: "二小组长3",
userName: "二小组长",
userId: 8,
},
{
position: "战士",
userName: "王小四",
userName: "王小四32",
userId: 12,
},
],
@ -147,8 +169,8 @@ const OrgChart = () => {
depId: 8,
userList: [
{
position: "二小组长",
userName: "二小组长",
position: "二小组长4",
userName: "二小组长4",
userId: 8,
},
{
@ -158,7 +180,7 @@ const OrgChart = () => {
},
{
position: "战士",
userName: "王小四",
userName: "王小四12",
userId: 12,
},
{
@ -207,7 +229,7 @@ const OrgChart = () => {
depId: 9,
userList: [
{
position: "二小组长",
position: "二小组长5",
userName: "小组长",
userId: 9,
},
@ -223,7 +245,7 @@ const OrgChart = () => {
},
{
position: "战士",
userName: "王小四",
userName: "王小四3",
userId: 12,
},
{
@ -247,7 +269,25 @@ const OrgChart = () => {
],
},
];
const dc = (v)=>{
let max = getArrayDepth(data)
if (v.depId===1){
return 70*max-40
}
if (v.children.length>0){
return v.children.length*70-40
}
}
const lf = (v)=>{
let max = getArrayDepth(data)
if (v.depId===1){
return -30*max+20
}
if (v.children.length>0){
return -30*v.children.length+20
}
}
const renderTree = (list: Array<any>) => {
return (
<div className="orgsBox">
@ -268,7 +308,7 @@ const OrgChart = () => {
</span>
) : null}
{v.depId === 1 ? (
<div>
<div className="userNameCont">
{v.userList?.map((v1, _) => {
return (
<div key={v1.userName} className="userNmaeBox">
@ -297,14 +337,17 @@ const OrgChart = () => {
})
)}
{v.depId !== 2 ? (
<div className="line" style={{ width: 130 }}></div>
<div className="lineBox" style={{ width: 80 }}>
<div className="linLeft"></div>
<div className="linRight" style={{ width: dc(v),right:lf(v) }}></div>
</div>
) : null}
{renderTree(v.children)}
</div>
);
}
return (
<div key={v.depName} style={{ paddingLeft: 20, display: "flex" }}>
<div className="userNameCont node" key={v.depName} style={{ paddingLeft: 20, display: "flex" }}>
{v.userList?.map((v1, _) => {
return (
<div key={v1.userName} className="userNmaeBox">
@ -323,7 +366,7 @@ const OrgChart = () => {
</div>
);
};
return <div>{renderTree(data)}</div>;
return <div className="org_sc">{renderTree(data)}</div>;
};
export default OrgChart;

View File

@ -1,4 +1,13 @@
import { Button, Space, Modal, FormInstance } from "antd";
import {
Button,
Space,
Modal,
FormInstance,
Form,
InputNumber,
Select,
SelectProps,
} from "antd";
import { inject, observer } from "mobx-react";
import type { ColumnsType } from "antd/es/table";
import BTable from "@/components/b_table";
@ -9,6 +18,7 @@ import SimpleForm from "@/components/form/simple_form";
import React from "react";
import { FormType } from "@/components/form/interface";
import baseHttp from "@/service/base";
import MinusCircleOutlined from "@ant-design/icons/lib/icons/MinusCircleOutlined";
const Emergency = (props: Store) => {
const { emergencyStore } = props;
@ -18,6 +28,8 @@ const Emergency = (props: Store) => {
const [record, setRecord] = useState<any>(null);
const [tagId, setId] = useState<Number | null>(null);
const [userList, setUserList] = useState<Array<any>>([]);
const [data, setData] = useState<SelectProps["options"]>([]);
const columns: ColumnsType<UserDataType> = [
{ title: "应急处突名称", dataIndex: "emergency_name" },
{ title: "目标位置", dataIndex: "target_location" },
@ -27,8 +39,8 @@ const Emergency = (props: Store) => {
{
title: "完成状态",
dataIndex: "status",
render: (accomplish) =>
accomplish.status === 0 ? (
render: (status) =>
status === 0 ? (
<span style={{ color: "green" }}></span>
) : (
<span style={{ color: "red" }}></span>
@ -62,7 +74,7 @@ const Emergency = (props: Store) => {
danger
size="small"
onClick={() => {
dele(record)
dele(record);
}}
>
@ -71,12 +83,12 @@ const Emergency = (props: Store) => {
),
},
];
const dele = (record)=>{
const dele = (record) => {
emergencyStore.deleteItem(record.identity);
}
};
const edit = (record) => {
setProjectConfig(defaultConfig);
setIsModalOpen(true);
formRef.current?.setFieldsValue(record);
setRecord(record);
@ -130,7 +142,7 @@ const Emergency = (props: Store) => {
},
{
type: FormType.map,
label: "坐标信息",
label: "坐标信息",
name: "marker",
value: "",
rules: [{ required: true, message: "请输入任务描述!" }],
@ -145,6 +157,21 @@ const Emergency = (props: Store) => {
},
];
const onFinishFailed = () => {};
const handleSearch = (newValue: string) => {
if (newValue === "") return;
baseHttp.get("/supplies/list/serch", { name: newValue }).then((res) => {
let data = res.data?.record ?? [];
data.forEach((item) => {
item.text = item.name;
item.value = item.identity;
});
setData(data ?? []);
});
};
const handleChange = (newValue: string) => {
// setValue(newValue);
};
// 用户选择回调
return (
<div className="contentBox">
@ -173,7 +200,7 @@ const Emergency = (props: Store) => {
open={isModalOpen}
afterClose={() => formRef.current?.resetFields()}
onOk={() => formRef.current?.submit()}
okText="确定"
okText="确定"
cancelText="取消"
onCancel={() => {
setId(null);
@ -191,8 +218,63 @@ const Emergency = (props: Store) => {
formDatas={projectConfig}
onFinish={onFinish}
initialValues={true}
childrenPosi={true}
onFinishFailed={onFinishFailed}
/>
>
<Form.List name="supplies_list">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }) => (
<>
<Form.Item
{...restField}
label={"物资"}
name={[name, "supplies_identity"]}
rules={[{ required: true, message: "请选择物资" }]}
>
<Select
showSearch
placeholder={props.placeholder}
style={props.style}
defaultActiveFirstOption={false}
suffixIcon={null}
filterOption={false}
onSearch={handleSearch}
onChange={handleChange}
notFoundContent={null}
options={(data || []).map((d) => ({
value: d.value,
label: d.text,
}))}
/>
</Form.Item>
<Form.Item
{...restField}
name={[name, "num"]}
label={"数量"}
rules={[{ required: true, message: "请输入物资数量" }]}
>
<InputNumber placeholder="请输入物资数量" />
</Form.Item>
<MinusCircleOutlined onClick={() => remove(name)} />
</>
))}
<Form.Item>
<div style={{ textAlign: "center" }}>
<Button
style={{ width: 300 }}
type="dashed"
onClick={() => add()}
block
>
</Button>
</div>
</Form.Item>
</>
)}
</Form.List>
</SimpleForm>
</Modal>
</Space>
</div>

View File

@ -13,14 +13,14 @@ const Ec = (props: Store) => {
useEffect(() => {
usrStore.getlist().then(() => {
setUserList(usrStore.list);
webRTC.init();
});
}, [usrStore]);
const openDispatch = () => {
setIsModalOpen(true);
};
const callphone = (record: any) => {
webRTC.init();
webRTC.calls();
webRTC.calls(record.identity);
};
return (
<>
@ -52,7 +52,7 @@ const Ec = (props: Store) => {
<PhoneTwoTone
style={{ fontSize: "20px" }}
onClick={(item) => {
onClick={(items) => {
callphone(item);
}}
/>

View File

@ -5,25 +5,24 @@ import "./left.less";
import * as echarts from "echarts";
import Orgin from "./orgin";
import Pover from "./pover";
const HomeLeft = () => {
import { inject, observer } from "mobx-react";
import { Store } from "antd/es/form/interface";
const HomeLeft = (props: Store) => {
const { homeStore } = props;
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const initChart = () => {
const initChart = (data) => {
var myChart = echarts.init(document.getElementById("xunlian"));
var option = {
xAxis: {
type: "category",
data: ["应急抢险", "消防灭火", "水上救援", "民兵训练", "维稳处突"],
data: data.map((item) => item.name),
axisLabel: {
show: true,
interval: 0,
rotate: 30,
},
},
grid: {
top: "10%",
bottom: "45%",
right: "5%",
},
grid: {top: "10%",bottom: "45%",right: "5%"},
yAxis: {
type: "value",
splitLine: {
@ -32,7 +31,7 @@ const HomeLeft = () => {
},
series: [
{
data: [10, 15, 27, 10, 18],
data: data.map((item) => item.count),
type: "line",
smooth: true,
areaStyle: {
@ -55,8 +54,10 @@ const HomeLeft = () => {
};
useEffect(() => {
initChart();
}, []);
homeStore.getTr().then((res) => {
initChart(res.data.record);
});
}, [homeStore]);
// const openDispatch = () => {
// 位置移动
@ -108,5 +109,4 @@ const HomeLeft = () => {
</div>
);
};
export default HomeLeft;
export default inject("homeStore")(observer(HomeLeft));

View File

@ -3,6 +3,7 @@
color: #fff;
height: 100%;
display: flex;
overflow-y: hidden;
flex-direction: column;
.org{
flex:1;
@ -10,7 +11,6 @@
overflow-y: hidden;
text-align: center;
.org_head{
width: 100%;
background-image: url("../../../static/titie_secend@1x.png");
background-size: 100% 50px;
background-repeat: no-repeat;

View File

@ -2,9 +2,16 @@ import OrgChart from "@/pages/OrgChart";
import origin from "@/static/orgin.png";
import origin2 from "@/static/orgin2.png";
import { Modal } from "antd";
import { useState } from "react";
const Orgin = () => {
import { Store } from "antd/es/form/interface";
import { inject, observer } from "mobx-react";
import { useEffect, useState } from "react";
const Orgin = (props:Store) => {
const {homeStore} = props;
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
useEffect(()=>{
homeStore.getOgCount()
},[homeStore])
const showModal = () => {
setIsModalOpen(true);
};
@ -15,12 +22,12 @@ const Orgin = () => {
<>
<div className="orgin-content" onClick={showModal}>
<div className="po">
<span>234</span>
<span>{homeStore.ogMap?.count??0}</span>
<img src={origin} alt="" />
<p></p>
</div>
<div className="po">
<span>238</span>
<span>{homeStore.ogMap?.member_count??0}</span>
<img src={origin2} alt="" />
<p></p>
</div>
@ -41,4 +48,4 @@ const Orgin = () => {
);
};
export default Orgin;
export default inject("homeStore")(observer(Orgin));

View File

@ -1,16 +1,19 @@
import PoverPage from "@/pages/poverPage";
import { Modal } from "antd";
import { Store } from "antd/es/form/interface";
import * as echarts from "echarts";
import { inject, observer } from "mobx-react";
import { useEffect, useState } from "react";
const Pover = () => {
const Pover = (props: Store) => {
const { homeStore } = props;
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const initChart = () => {
const initChart = (data) => {
var myChart = echarts.init(document.getElementById("pover"));
var option = {
xAxis: {
type: "category",
data: ["基干民兵", "普通民兵", "Wed", "Thu", "Fri", "Sat", "Sun"],
data: data.map((item) => item.dep_name),
axisLabel: {
show: true,
interval: 0,
@ -31,7 +34,7 @@ const Pover = () => {
},
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
data: data.map((item) => item.count),
type: "bar",
barWidth: 10, // 设置柱子粗细
itemStyle: {
@ -42,9 +45,12 @@ const Pover = () => {
};
option && myChart.setOption(option);
};
useEffect(() => {
initChart();
}, []);
homeStore.getAf().then((res) => {
initChart(res?.data?.record);
});
}, [homeStore]);
const openPoverHander = () => {
setIsModalOpen(true);
};
@ -68,10 +74,9 @@ const Pover = () => {
}}
>
<PoverPage />
{/* <p>cascsa</p> */}
</Modal>
</>
);
};
export default Pover;
export default inject("homeStore")(observer(Pover));

View File

@ -0,0 +1,61 @@
import { Store } from "antd/es/form/interface";
import * as echarts from "echarts";
import { inject, observer } from "mobx-react";
import { useEffect } from "react";
const Ac = (props: Store) => {
const { homeStore } = props;
const initChart = (data) => {
var myChart = echarts.init(document.getElementById("rm"));
var option = {
legend: {
top: "5%",
right: "right",
textStyle: {
color: "#fff",
},
formatter: function (name) {
let v;
data.forEach((item) => {
if (item.name === name) {
v = item.value;
}
});
return name + "-" + v;
},
orient: "vertical", // 垂直排列
type: "scroll", //分页类型
pageIconColor: "#ff781f", //翻页箭头颜色
pageTextStyle: {
color: "#999", //翻页数字颜色
}, //翻页数字设置
pageIconSize: 10,
},
series: [
{
center: ["30%", "40%"],
name: "Access From",
type: "pie",
radius: ["40%", "60%"],
label: {
backgroundColor: "#F6F8FC",
borderColor: "#8C8D8E",
borderWidth: 0,
show: false,
borderRadius: 4,
},
data,
},
],
};
option && myChart.setOption(option);
};
useEffect(() => {
homeStore.getRm().then((res) => {
initChart(res.data?.record);
});
}, [homeStore]);
return <div style={{ width: "100%", height: "100%" }} id="rm"></div>;
};
export default inject("homeStore")(observer(Ac));

View File

@ -1,3 +1,5 @@
import Ac from "./ac";
import Pyzx from "./pyzx";
import "./right.less";
import Wz from "./wz";
const HomeRight = () => {
@ -13,11 +15,13 @@ const HomeRight = () => {
<div className="org_head">
<p></p>
</div>
<Ac />
</div>
<div className="org">
<div className="org_head">
<p></p>
</div>
<Pyzx />
</div>
</div>
);

View File

@ -0,0 +1,37 @@
import { inject, observer } from "mobx-react";
import "./right.less";
import { Store } from "antd/es/form/interface";
import { useEffect, useState } from "react";
const Pyzx = (props: Store) => {
const { homeStore } = props;
const [user, setUser] = useState<any>();
useEffect(() => {
homeStore.getAe().then((res) => {
setUser(res.data?.record);
});
}, [homeStore]);
return (
<div className="pyzx">
{user?.map((item) => {
return (
<div key={item.id} className="pyzx_title">
<img
height={80}
src="https://img0.baidu.com/it/u=2135939479,1633462316&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500"
alt=""
/>
<div className="content">
<div>:{item.user_name}</div>
<div>:{item.scores}</div>
<div>:{item.pos_held}</div>
<div>:{item.remark}</div>
</div>
</div>
);
})}
</div>
);
};
export default inject("homeStore")(observer(Pyzx));

View File

@ -10,7 +10,6 @@
overflow-y: hidden;
text-align: center;
.org_head {
width: 100%;
background-image: url("../../../static/titie_secend@1x.png");
background-size: 100% 50px;
background-repeat: no-repeat;
@ -21,3 +20,21 @@
}
}
}
.pyzx{
height: 100%;
padding: 10px;
.pyzx_title{
display: flex;
padding: 5px 4px;
align-items: start;
background: rgba(37, 52, 70, 0.4);
.content{
text-align: left;
font-size: 13px;
}
>img{
margin-right: 10px;
}
}
}

View File

@ -1,89 +1,56 @@
import { Store } from "antd/es/form/interface";
import * as echarts from "echarts";
import { inject, observer } from "mobx-react";
import { useEffect } from "react";
const Wz = () => {
const initChart = () => {
const Wz = (props: Store) => {
const { homeStore } = props;
const initChart = (data) => {
var myChart = echarts.init(document.getElementById("wz"));
var option = {
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b}: {c} ({d}%)",
legend: {
top: '5%',
right: 'right',
textStyle :{
color: "#fff"
},
formatter: function (name) {
let v;
data.forEach((item) => {
if (item.name === name) {
v = item.value;
}
});
return name + '-' + v;
},
},
series: [
{
center: ["50%", "40%"],
center: ["35%", "40%"],
name: "Access From",
type: "pie",
selectedMode: "single",
radius: [0, "30%"],
radius: ["40%", "60%"],
label: {
position: "inner",
fontSize: 10,
},
labelLine: {
show: false,
},
data: [
{ value: 1548, name: "Search Engine" },
{ value: 775, name: "Direct" },
{ value: 679, name: "Marketing", selected: true },
],
},
{
center: ["50%", "40%"],
name: "Access From",
type: "pie",
radius: ["45%", "60%"],
labelLine: {
length: 30,
show: false,
},
label: {
formatter: "{a|{a}}{abg|}\n{hr|}\n {b|{b}}{c} {per|{d}%} ",
backgroundColor: "#F6F8FC",
borderColor: "#8C8D8E",
borderWidth: 0,
show: false,
show: true,
borderRadius: 4,
rich: {
a: {
color: "#6E7079",
lineHeight: 22,
align: "center",
},
b: {
color: "#4C5058",
fontSize: 14,
fontWeight: "bold",
lineHeight: 33,
},
per: {
color: "#fff",
backgroundColor: "#4C5058",
padding: [3, 4],
borderRadius: 4,
},
},
},
data: [
{ value: 1048, name: "Baidu" },
{ value: 335, name: "Direct" },
{ value: 310, name: "Email" },
{ value: 251, name: "Google" },
{ value: 234, name: "Union Ads" },
{ value: 147, name: "Bing" },
{ value: 135, name: "Video Ads" },
{ value: 102, name: "Others" },
],
data
},
],
};
option && myChart.setOption(option);
};
useEffect(() => {
initChart();
}, []);
homeStore.getMm().then((res) => {
initChart(res.data?.record);
})
}, [homeStore]);
return <div style={{ width: "100%", height: "100%" }} id="wz"></div>;
};
export default Wz;
export default inject("homeStore")(observer(Wz));
// export default Wz;

View File

@ -1,4 +1,13 @@
import { Button, Space, Modal, FormInstance, Select } from "antd";
import {
Button,
Space,
Modal,
FormInstance,
Select,
Popconfirm,
PopconfirmProps,
message,
} from "antd";
import { inject, observer } from "mobx-react";
import BTable from "@/components/b_table";
import { useEffect, useState } from "react";
@ -56,16 +65,54 @@ const Material = (props: Store) => {
</Button>
<Button
{/* <Button
type="dashed"
danger
size="small"
onClick={() => {
materialStore.deleteItem(record.id);
}}
>
</Button>
</Button> */}
<Popconfirm
title="出库操作"
description="请确认是否出库该物资?"
onConfirm={() => {
try {
materialStore.deleteItem(record.id);
message.success("物资出库成功");
} catch (error) {
message.success("物资出库失败");
}
}}
onCancel={cancel}
okText="Yes"
cancelText="No"
>
<Button danger size="small">
</Button>
</Popconfirm>
<Popconfirm
title="删除操作"
description="请确认是否删除物资?"
onConfirm={() => {
try {
materialStore.deleteItem(record.id);
message.success("删除成功");
} catch (error) {
message.success("删除失败");
}
}}
onCancel={cancel}
okText="Yes"
cancelText="No"
>
<Button danger size="small">
</Button>
</Popconfirm>
</Space>
);
};
@ -74,6 +121,12 @@ const Material = (props: Store) => {
record.expiry_date = dayjs(record.expiry_date);
setRecord(record);
};
const cancel: PopconfirmProps["onCancel"] = (e) => {
console.log(e);
message.error("Click on No");
};
const onFinish = (values: any) => {
let data = {
...values,

View File

@ -1,63 +1,83 @@
.orgs {
margin-left: 10;
margin-bottom: 10;
margin-bottom: 10px;
display: flex;
align-items: center;
}
.orgsBox{
overflow: auto;
margin: 10px;
}
.line {
position: relative;
height: 3px; /* 线的高度 */
}
.line::after {
content: "";
.orgs::before{
position: absolute;
left: 0;
right: 0;
top: 0;
border-top: 1px solid #fff; /* 线的颜色和宽度 */
width: 80px;
left: -35px;
height: 1px;
background-color: black;
border-radius: 50%;
}
.line:before{
content: '';
position: absolute;
top: 50%;
left: 100%;
transform: translate(-50%, -50%);
width: 100%;
height: 50%;
background: #fff; /* 设置线的颜色 */
.orgsBox {
.userNameCont {
position: relative;
}
}
.line:after {
content: '';
position: absolute;
top: 50%;
left:50%;
transform: translate(-50%, -50%);
.userNmaeBox {
margin-left: 10px;
margin-bottom: 10px;
text-align: center;
.userNmae {
display: block;
padding: 5px 5px;
background: rgba(75, 176, 152, 0.2);
font-size: 13px;
}
}
.lineBox {
position: relative;
height: 100%;
width: 100%;
height: 50%;
background: #fff; /* 设置线的颜色 */
}
.line:before {
transform: translate(-50%, -50%) rotate(90deg);
}
.line:after {
width: 100%; /* 设置短线宽度 */
background: transparent; /* 设置短线透明 */
}
.userNmaeBox{
margin-left: 10px;
margin-bottom: 10px;
color: #fff;
text-align: center;
.userNmae{
display: block;
padding: 5px 5px;
background: rgba(75, 176, 152, 0.2);
font-size: 13px;
}
background-color: red;
top: -5px;
.linLeft {
position: absolute;
width: 50%;
border: 1px solid;
left: 0;
right: 50%;
}
.linRight {
position: absolute;
width: 100%;
border: 1px solid;
height: 100%;
right: -5px;
transform: rotate(-90deg) rotateY(180deg);
box-sizing: border-box;
}
.linRight:after {
position: absolute;
left: -40px;
top: 40px;
width: 80px;
height: 1px;
background-color: black;
border-radius: 50%;
transform: rotate(-90deg) rotateY(180deg);
}
.linRight::before {
position: absolute;
left: 410px;
top: 40px;
width: 80px;
height: 1px;
background-color: black;
border-radius: 50%;
transform: rotate(-90deg) rotateY(180deg);
}
}
.orgs:nth-of-type(1){
.orgs::before{
content: "";
width: 80px;
}
}

830
src/pages/org_chart2.less Normal file
View File

@ -0,0 +1,830 @@
.orgchart {
box-sizing: border-box;
display: inline-block;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background-image: linear-gradient(to top,rgba(200,0,0,.15) 5%,rgba(0,0,0,0) 5%),linear-gradient(to right,rgba(200,0,0,.15) 5%,rgba(0,0,0,0) 5%),linear-gradient(to bottom,rgba(200,0,0,.15) 5%,rgba(0,0,0,0) 5%),linear-gradient(to left,rgba(200,0,0,.15) 5%,rgba(0,0,0,0) 5%);
background-size: 10px 10px;
padding: 20px 20px 0 20px
}
.orgchart .hidden,.orgchart~.hidden {
display: none!important
}
.orgchart.b2t {
transform: rotate(180deg)
}
.orgchart.l2r {
position: absolute;
transform: rotate(-90deg) rotateY(180deg);
transform-origin: left top;
text-align: center
}
.orgchart.r2l {
position: absolute;
transform: rotate(90deg);
transform-origin: left top;
text-align: center
}
.orgchart~.mask {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 999;
text-align: center;
background-color: rgba(0,0,0,.3)
}
.orgchart~.mask .spinner {
position: absolute;
top: calc(50% - 50px);
left: calc(50% - 50px)
}
.orgchart>.spinner::before,.orgchart~.mask .spinner::before {
width: 100px;
height: 100px;
border-width: 10px;
border-radius: 50px;
border-top-color: rgba(68,157,68,.8);
border-bottom-color: rgba(68,157,68,.8);
border-left-color: rgba(68,157,68,.8)
}
.orgchart .nodes {
display: flex;
list-style: none;
padding-left: 0;
margin: 0
}
.orgchart .hierarchy {
position: relative
}
.orgchart .hierarchy::before {
content: "";
position: absolute;
top: -11px;
left: 0;
width: 100%;
border-top: 2px solid rgba(217,83,79,.8);
box-sizing: border-box
}
.orgchart .hierarchy.isSiblingsCollapsed.left-sibs::before,.orgchart .hierarchy:first-child::before {
left: calc(50% - 1px);
width: calc(50% + 1px);
}
.orgchart .hierarchy.isSiblingsCollapsed.right-sibs::before,.orgchart .hierarchy:last-child::before {
width: calc(50% + 1px)
}
.orgchart .hierarchy:not(.hidden):only-child::before {
width: 2px
}
.orgchart .isAncestorsCollapsed:only-child::before,.orgchart .isAncestorsCollapsed>.node::before,.orgchart .isChildrenCollapsed>.node:not(:only-child)::after,.orgchart .isCollapsedDescendant::before,.orgchart .isCollapsedDescendant>.node::after,.orgchart .isCollapsedDescendant>.node::before,.orgchart .isCollapsedSibling .hierarchy::before,.orgchart .isCollapsedSibling::before,.orgchart .isSiblingsCollapsed.left-sibs.right-sibs::before,.orgchart .isSiblingsCollapsed.left-sibs:last-child:before,.orgchart .isSiblingsCollapsed.right-sibs:first-child:before,.orgchart .isSiblingsCollapsed:not(.left-sibs):not(.right-sibs)::before,.orgchart>.nodes>.hierarchy::before {
content: none
}
.orgchart .node:not(:only-child)::after {
content: "";
position: absolute;
bottom: -12px;
left: calc(50% - 1px);
width: 2px;
height: 10px;
background-color: rgba(217,83,79,.8)
}
.orgchart ul li .node.allowedDrop {
border-color: rgba(68,157,68,.9)
}
.orgchart ul li .node.currentDropTarget {
background-color: rgba(68,157,68,.9)
}
.orgchart ul li .node.selected {
background-color: rgba(238,217,54,.5)
}
.orgchart ul li .node:hover {
background-color: rgba(238,217,54,.5)
}
.orgchart>ul>li>ul li>.node::before {
content: "";
position: absolute;
top: var(--top,-12px);
left: calc(50% - 1px);
width: 2px;
height: var(--height,10px);
background-color: rgba(217,83,79,.8)
}
.orgchart>ul>li>ul li.isSiblingsCollapsed>.node::before {
top: var(--top-cross-point,-12px);
height: var(--height-cross-point,10px)
}
.orgchart .node {
box-sizing: border-box;
display: inline-block;
position: relative;
margin: 0 0 20px 0;
padding: 3px;
border: 2px dashed transparent;
text-align: center
}
.orgchart.l2r .node,.orgchart.r2l .node {
width: 50px;
height: 140px
}
.orgchart .node:hover {
background-color: rgba(238,217,54,.5);
transition: .5s;
cursor: default;
z-index: 20
}
.orgchart .node.focused {
background-color: rgba(238,217,54,.5)
}
.orgchart .ghost-node {
position: fixed;
left: -10000px;
top: -10000px
}
.orgchart .ghost-node rect {
fill: #fff;
stroke: #bf0000
}
.orgchart .node.allowedDrop {
border-color: rgba(68,157,68,.9)
}
.orgchart .node>.spinner {
position: absolute;
top: calc(50% - 1rem);
left: calc(50% - 1rem)
}
.orgchart .node>.spinner::before {
width: 2rem;
height: 2rem;
border-width: .2rem;
border-radius: 1rem;
border-top-color: rgba(68,157,68,.8);
border-bottom-color: rgba(68,157,68,.8);
border-left-color: rgba(68,157,68,.8)
}
.orgchart .node .title {
box-sizing: border-box;
width: 130px;
text-align: center;
font-size: 12px;
font-weight: 700;
height: 20px;
line-height: 20px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
background-color: rgba(217,83,79,.8);
color: #fff;
border-radius: 4px 4px 0 0
}
.orgchart.b2t .node .title {
transform: rotate(-180deg);
transform-origin: center bottom
}
.orgchart.l2r .node .title {
transform: rotate(-90deg) translate(-45px,-45px) rotateY(180deg);
transform-origin: bottom center
}
.orgchart.r2l .node .title {
transform: rotate(-90deg) translate(-45px,-45px);
transform-origin: bottom center
}
.orgchart .node .title .parentNodeSymbol {
float: left
}
.orgchart .node .title .parentNodeSymbol::before {
color: #fff
}
.orgchart .node .title .parentNodeSymbol::after {
background-color: #fff
}
.orgchart .node .content {
box-sizing: border-box;
width: 130px;
height: 20px;
line-height: 20px;
font-size: 10px;
border: 1px solid rgba(217,83,79,.8);
border-width: 0 1px 1px 1px;
border-radius: 0 0 .25rem .25rem;
text-align: center;
background-color: #fff;
color: #333;
text-overflow: ellipsis;
white-space: nowrap
}
.orgchart.b2t .node .content {
transform: rotate(180deg);
transform-origin: center top
}
.orgchart.l2r .node .content {
transform: rotate(-90deg) translate(-45px,-45px) rotateY(180deg);
transform-origin: top center;
width: 130px
}
.orgchart.r2l .node .content {
transform: rotate(-90deg) translate(-45px,-45px);
transform-origin: top center;
width: 130px
}
.orgchart .node .edge {
position: absolute;
cursor: default;
transition: .2s
}
.orgchart .node .edge::before {
border-color: rgba(68,157,68,.5)
}
.orgchart.noncollapsable .node .edge {
display: none
}
.orgchart .node .edge:hover {
cursor: pointer
}
.orgchart .edge:hover::before {
border-color: #449d44
}
.orgchart .node .verticalEdge {
width: calc(100% - 6px);
height: 10px;
left: 3px
}
.orgchart .node .verticalEdge::before {
position: absolute;
left: calc(50% - 5px)
}
.orgchart .node .topEdge {
top: -2px
}
.orgchart .node .topEdge.oci-chevron-up::before {
top: 2px
}
.orgchart .node .topEdge.oci-chevron-down::before {
bottom: 3px
}
.orgchart .node .bottomEdge {
bottom: -2px
}
.orgchart .node .bottomEdge.oci-chevron-up::before {
bottom: -3px
}
.orgchart .node .bottomEdge.oci-chevron-down::before {
bottom: 1px
}
.orgchart .node .horizontalEdge {
width: 10px;
height: calc(100% - 6px);
top: 3px
}
.orgchart .node .rightEdge {
right: -2px
}
.orgchart .node .leftEdge {
left: -2px
}
.orgchart .node .horizontalEdge::before {
position: absolute;
top: calc(50% - 5px)
}
.orgchart .node .leftEdge.oci-chevron-right::before {
left: -3px
}
.orgchart .node .leftEdge.oci-chevron-left::before {
left: 1px
}
.orgchart .node .rightEdge.oci-chevron-left::before {
right: -3px
}
.orgchart .node .rightEdge.oci-chevron-right::before {
right: 1px
}
.orgchart .node .toggleBtn {
position: absolute;
left: -2px;
bottom: -2px;
width: 16px;
height: 16px
}
.orgchart .node .toggleBtn::before {
background-color: rgba(68,157,68,.6);
position: absolute;
left: 0;
bottom: 0
}
.orgchart .node .toggleBtn:hover::before {
background-color: #449d44
}
.oc-export-btn {
margin-left: .5rem;
padding: .5rem 1rem
}
.orgchart .node {
transition: transform .3s,opacity .3s
}
.orgchart .slide-down {
opacity: 0;
transform: translateY(40px)
}
.orgchart.l2r .node.slide-down,.orgchart.r2l .node.slide-down {
transform: translateY(130px)
}
.orgchart .slide-up {
opacity: 0;
transform: translateY(-40px)
}
.orgchart.l2r .node.slide-up,.orgchart.r2l .node.slide-up {
transform: translateY(-130px)
}
.orgchart .slide-right {
opacity: 0;
transform: translateX(130px)
}
.orgchart.l2r .node.slide-right,.orgchart.r2l .node.slide-right {
transform: translateX(40px)
}
.orgchart .slide-left {
opacity: 0;
transform: translateX(-130px)
}
.orgchart.l2r .node.slide-left,.orgchart.r2l .node.slide-left {
transform: translateX(-40px)
}
.orgchart .nodes.vertical {
display: block;
padding-left: 10px
}
.orgchart .nodes.vertical .nodes {
list-style: none;
display: block;
margin: 0;
padding-left: 10px;
text-align: left
}
.orgchart .nodes.vertical .node {
margin-bottom: 0
}
.orgchart .nodes.vertical .node::after,.orgchart .nodes.vertical .node::before {
content: none
}
.orgchart .nodes.vertical .hierarchy {
position: relative;
text-align: left
}
.orgchart .nodes.vertical .hierarchy::after,.orgchart .nodes.vertical .hierarchy::before {
box-sizing: border-box;
content: '';
position: absolute;
left: -6px;
border-color: rgba(217,83,79,.8);
border-style: solid;
border-width: 0 0 2px 2px
}
.orgchart .nodes.vertical .hierarchy::before {
top: 0;
height: 26px;
width: 11px
}
.orgchart .nodes.vertical .hierarchy::after {
bottom: 0;
height: calc(100% - 24px)
}
.orgchart .nodes.vertical .hierarchy:last-child::after {
border-width: 2px 0 0 0
}
.orgchart .nodes.vertical>.hierarchy:first-child::before {
box-sizing: border-box;
top: -11px;
height: 35px;
width: calc(50% + 2px);
border-width: 2px 0 0 2px
}
.orgchart .nodes.vertical>.hierarchy:first-child::after {
box-sizing: border-box;
top: 24px;
width: 11px;
border-width: 2px 0 0 2px
}
.orgchart .nodes.vertical>.hierarchy:first-child:last-child::after {
border-width: 2px 0 0 0
}
.orgchart .node.compact {
position: static;
display: grid;
width: 140px;
height: 50px;
background-color: #eee
}
.orgchart .node.compact.looseMode {
display: grid;
width: unset;
height: unset
}
.orgchart .node.compact>.node {
display: none
}
.orgchart .node.compact.looseMode>.node {
display: inline-block
}
.orgchart .node.compact>.node.compact {
position: relative
}
.orgchart .node.compact>.node.compact.looseMode {
display: grid
}
.orgchart .node.compact.even,.orgchart .node.compact.even:hover {
background-color: #eee
}
.orgchart .node.compact.odd,.orgchart .node.compact.odd:hover {
background-color: #fff
}
.orgchart .node.compact.even>.node.focused,.orgchart .node.compact.even>.node.selected,.orgchart .node.compact.even>.node:hover {
background-color: #fff
}
.orgchart .node.compact.odd>.node.focused,.orgchart .node.compact.odd>.node.selected,.orgchart .node.compact.odd>.node:hover {
background-color: #eee
}
.orgchart .node.compact::before {
top: var(--top-cross-point,-10px)
}
.orgchart .node.compact>.content {
position: absolute;
top: 25px;
left: 5px
}
.orgchart .node.compact.looseMode>.title {
margin-top: 5px;
margin-left: 5px
}
.orgchart .node.compact.looseMode>.content {
top: 30px;
left: 10px
}
.orgchart .node.compact>.node.compact.looseMode>.title {
margin-top: 5px;
margin-left: 5px
}
.orgchart .node.compact>.node.compact>.content {
position: absolute;
top: 23px;
left: 3px
}
.orgchart .node.compact>.node.compact.looseMode>.content {
top: 28px;
left: 8px
}
.orgchart .node.compact .node {
margin-bottom: 0
}
.orgchart .node.compact .node:not(:only-child)::after {
content: unset
}
.orgchart .backToCompactSymbol,.orgchart .backToLooseSymbol {
cursor: pointer
}
.orgchart .node.compact>.backToCompactSymbol {
position: absolute;
top: 5px;
left: 5px
}
.orgchart .node.compact.looseMode>.backToCompactSymbol {
top: 10px;
left: 10px
}
.orgchart .node.compact>.node.compact.looseMode>.backToCompactSymbol {
top: 8px;
left: 8px
}
.orgchart .node.compact>.node.compact>.backToCompactSymbol {
position: absolute;
top: 3px;
left: 3px
}
.orgchart .node.compact>.backToLooseSymbol {
position: absolute;
top: 25px;
right: 5px
}
.orgchart .node.compact>.node.compact>.backToLooseSymbol {
position: absolute;
top: 23px;
right: 3px
}
.orgchart .node.compact .backToCompactSymbol::before {
border-top-color: rgba(68,157,68,.6)
}
.orgchart .node.compact .backToLooseSymbol::before {
border-bottom-color: rgba(68,157,68,.6)
}
.orgchart .node.compact .backToCompactSymbol:hover::before {
border-top-color: #449d44
}
.orgchart .node.compact .backToLooseSymbol:hover::before {
border-bottom-color: #449d44
}
.oci {
display: inline-block;
position: relative;
font-style: normal;
font-family: Arial
}
.oci-menu::before {
content: "≡";
display: inline-block;
width: 1rem;
height: 1rem;
text-align: center;
line-height: 1rem;
color: #000;
font-size: 1rem
}
.oci-chevron-up::before {
content: "";
box-sizing: border-box;
width: 10px;
height: 10px;
display: inline-block;
border: 3px solid #000;
transform: rotate(45deg);
border-right: unset;
border-bottom: unset
}
.oci-chevron-down::before {
content: "";
box-sizing: border-box;
width: 10px;
height: 10px;
display: inline-block;
border: 3px solid #000;
transform: rotate(45deg);
border-top: unset;
border-left: unset
}
.oci-chevron-left::before {
content: "";
box-sizing: border-box;
width: 10px;
height: 10px;
display: inline-block;
border: 3px solid #000;
transform: rotate(45deg);
border-top: unset;
border-right: unset
}
.oci-chevron-right::before {
content: "";
box-sizing: border-box;
width: 10px;
height: 10px;
display: inline-block;
border: 3px solid #000;
transform: rotate(45deg);
border-left: unset;
border-bottom: unset
}
.oci-corner-top-left::before {
content: "";
display: inline-block;
border-top: 20px solid #000;
border-right: 20px solid transparent
}
.oci-corner-top-right::before {
content: "";
display: inline-block;
box-sizing: border-box;
width: 0;
height: 0;
border-top: 20px solid #000;
border-left: 20px solid transparent
}
.oci-corner-bottom-right::before {
content: "";
display: inline-block;
box-sizing: border-box;
width: 0;
height: 0;
border-bottom: 20px solid #000;
border-left: 20px solid transparent
}
.oci-corner-bottom-left::before {
content: "";
display: inline-block;
box-sizing: border-box;
width: 0;
height: 0;
border-bottom: 20px solid #000;
border-right: 20px solid transparent
}
.oci-plus-square::before {
content: "﹢";
display: inline-block;
width: 16px;
height: 16px;
text-align: center;
line-height: 16px;
background-color: #000;
color: #fff;
font-weight: 700
}
.oci-minus-square::before {
content: "﹣";
display: inline-block;
width: 16px;
height: 16px;
text-align: center;
line-height: 16px;
background-color: #000;
color: #fff;
font-weight: 700
}
.oci-arrow-square-up::before {
content: "⬆";
display: inline-block;
width: 1rem;
height: 1rem;
text-align: center;
line-height: 1rem;
background-color: #000;
color: #fff;
font-weight: 700
}
.oci-arrow-square-down::before {
content: "⬇";
display: inline-block;
width: 1rem;
height: 1rem;
text-align: center;
line-height: 1rem;
background-color: #000;
color: #fff;
font-weight: 700
}
.oci-info-circle::before {
content: "i";
display: inline-block;
width: 1rem;
height: 1rem;
border-radius: .5rem;
background-color: #000;
color: #fff;
text-align: center;
font-weight: 700
}
.oci-spinner::before {
content: "";
vertical-align: text-bottom;
display: inline-block;
box-sizing: border-box;
width: 1rem;
height: 1rem;
border: .1rem solid #000;
border-right-color: transparent;
border-radius: .625rem;
animation: oci-infinite-spinning .75s linear infinite
}
@keyframes oci-infinite-spinning {
from {
transform: rotate(0)
}
to {
transform: rotate(360deg)
}
}

View File

@ -1,4 +1,13 @@
import { Button, Space, Modal, FormInstance, Form, Select } from "antd";
import {
Button,
Space,
Modal,
FormInstance,
Form,
Select,
InputNumber,
SelectProps,
} from "antd";
import { inject, observer } from "mobx-react";
import type { ColumnsType } from "antd/es/table";
import BTable from "@/components/b_table";
@ -12,6 +21,8 @@ import dayjs from "dayjs";
import { traningConfig } from "./traning_config";
import { FormType } from "@/components/form/interface";
import TraningUser from "./traningUser";
import MinusCircleOutlined from "@ant-design/icons/lib/icons/MinusCircleOutlined";
const { Option } = Select;
const Trainings = (props: Store) => {
@ -24,6 +35,8 @@ const Trainings = (props: Store) => {
const [tagId, setId] = useState<Number | null>(null);
const [stashList, setStash] = useState<any>(null); // 仓库列表
const [userList, setUserList] = useState<Array<any>>([]);
const [data, setData] = useState<SelectProps["options"]>([]);
const columns: ColumnsType<UserDataType> = [
{ title: "任务标题", dataIndex: "title" },
{ title: "任务描述", dataIndex: "desc" },
@ -125,7 +138,21 @@ const Trainings = (props: Store) => {
}
setIsModalOpen(false);
};
const handleSearch = (newValue: string) => {
if (newValue === "") return;
baseHttp.get("/supplies/list/serch", { name: newValue }).then((res) => {
let data = res.data?.record ?? [];
data.forEach((item) => {
item.text = item.name;
item.value = item.identity;
});
setData(data ?? []);
});
};
const handleChange = (newValue: string) => {
// setValue(newValue);
};
// 任务发布handler
const fabu = () => {
setProjectConfig([
@ -198,6 +225,61 @@ const Trainings = (props: Store) => {
})}
</Select>
</Form.Item>
<Form.List name="supplies_list">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }) => (
<>
<Form.Item
{...restField}
label={"物资"}
name={[name, "supplies_identity"]}
rules={[{ required: true, message: "请选择物资" }]}
>
<Select
showSearch
placeholder={props.placeholder}
style={props.style}
defaultActiveFirstOption={false}
suffixIcon={null}
filterOption={false}
onSearch={handleSearch}
onChange={handleChange}
notFoundContent={null}
options={(data || []).map((d) => ({
value: d.value,
label: d.text,
}))}
/>
</Form.Item>
<Form.Item
{...restField}
name={[name, "num"]}
label={"数量"}
rules={[
{ required: true, message: "请输入物资数量" },
]}
>
<InputNumber placeholder="请输入物资数量" />
</Form.Item>
<MinusCircleOutlined onClick={() => remove(name)} />
</>
))}
<Form.Item>
<div style={{ textAlign: "center" }}>
<Button
style={{ width: 300 }}
type="dashed"
onClick={() => add()}
block
>
</Button>
</div>
</Form.Item>
</>
)}
</Form.List>
</>
</SimpleForm>
</Modal>

View File

@ -14,6 +14,8 @@ const User = (props: Store) => {
const [projectConfig, setProjectConfig] = useState<any>([]);
const formRef = React.useRef<FormInstance>(null);
const [record, setRecord] = useState<any>(null);
const [team, setTeam] = useState<any>(null);
const [per, setPer] = useState<any>(null);
const [userId, setId] = useState<Number | null>(null);
const actionWidget = (any, record) => {
return (
@ -47,7 +49,7 @@ const User = (props: Store) => {
...record,
imageUrl: [{ url: record.imageUrl }],
};
setProjectConfig(defaultConfig);
setProjectConfig(defaultConfig(team,per));
setIsModalOpen(true);
formRef.current?.setFieldsValue(record);
setRecord(record);
@ -57,19 +59,42 @@ const User = (props: Store) => {
let data = {
...values,
};
data.head_img = values.head_img[0].url;
if(values.head_img && values.head_img.length>0){
data.head_img = values.head_img[0].url;
}else{
data.head_img = "";
}
if (!userId) {
usrStore.add(values);
usrStore.add(data);
} else {
}
setIsModalOpen(false);
};
useEffect(() => {
usrStore.getlist();
usrStore.getTeam().then((res) => {
let data =res.data?.record??[]
for (let index = 0; index < data.length; index++) {
data[index].label = data[index].name;
data[index].value = data[index].identity;
}
console.log(data);
setTeam(data)
});
usrStore.getPer().then((res) => {
let data =res.data?.record??[]
for (let index = 0; index < data.length; index++) {
data[index].label = data[index].name;
data[index].value = data[index].identity;
}
setPer(data)
});
}, [usrStore]);
const addHandler = () => {
setProjectConfig(defaultConfig);
setProjectConfig(defaultConfig(team,per));
setId(null);
setIsModalOpen(true);
};
@ -79,7 +104,7 @@ const User = (props: Store) => {
<Space direction="vertical" size="middle" style={{ display: "flex" }}>
<Space direction="horizontal" size={"middle"}>
<Button type="default" onClick={() => addHandler()}>
</Button>
</Space>
<BTable
@ -97,7 +122,7 @@ const User = (props: Store) => {
dataSource={usrStore.list}
/>
<Modal
title={!userId ? "添加用户" : "编辑用户"}
title={!userId ? "添加民兵" : "编辑民兵"}
width={800}
open={isModalOpen}
afterClose={() => formRef.current?.resetFields()}

View File

@ -2,7 +2,8 @@ import { FormType } from "@/components/form/interface";
import { UserDataType } from "@/model/userModel";
import { ColumnsType } from "antd/lib/table";
import { Image } from "antd";
export const defaultConfig = [
export const defaultConfig =(team,per)=>
[
{
type: FormType.input,
label: "用户名",
@ -28,7 +29,7 @@ export const defaultConfig = [
rules: [{ required: true, message: "请选择性别" }],
},
{
type: FormType.input,
type: FormType.inputNumber,
label: "年龄",
name: "age",
value: "",
@ -119,6 +120,22 @@ export const defaultConfig = [
value: "",
rules: [{ required: true, message: "请输入民族" }],
},
{
type: FormType.cehckboxGroup,
label: "所属队伍",
name: "team_link_user",
checkboxData:team,
value: "",
rules: [{ required: true, message: "请输入民族" }],
},
{
type: FormType.cehckboxGroup,
label: "个人身份属性",
name: "pers_link_user",
checkboxData:per,
value: "",
rules: [{ required: true, message: "请输入民族" }],
},
{
type: FormType.radio,
label: "是否党员",
@ -162,7 +179,7 @@ export const defaultConfig = [
{
type: FormType.upload,
label: "头像",
name: "headImg",
name: "head_img",
value: [],
rules: [{ required: true, message: "请上传头像" }],
},
@ -172,96 +189,98 @@ export const columns: ColumnsType<UserDataType> = [
{
title: "用户名",
dataIndex: "user_name",
width:150,
fixed:"left"
width: 150,
fixed: "left",
},
{
title: "性别",
dataIndex: "sex",
width:150,
width: 150,
render: (sex) => <span>{sex === "0" ? "男" : "女"}</span>,
fixed:"left"
fixed: "left",
},
{
title: "年龄",
width:150,
width: 150,
dataIndex: "age",
},
{
title: "头像",
dataIndex: "head_img",
width:150,
width: 150,
render: (headImg) => <Image src={headImg}></Image>,
},
{
title: "登录账号",
width:150,
width: 150,
dataIndex: "account",
},
{
title: "家庭住址",
width:150,
width: 150,
dataIndex: "home_addr",
},
{
title: "身份证",
width:150,
width: 150,
dataIndex: "id_card",
},
{
title: "担任职务",
width:150,
width: 150,
dataIndex: "pos_held",
},
{
title: "通讯地址",
width:150,
width: 150,
dataIndex: "mail_addr",
},
{
title: "服役部队",
width:150,
width: 150,
dataIndex: "serv_unit",
},
{
title: "贯籍",
width:150,
width: 150,
dataIndex: "porig",
},
{
title: "专业特长",
width:150,
width: 150,
dataIndex: "spec",
},
{
title: "邮箱",
width:150,
width: 150,
dataIndex: "email",
},
{
title: "联系电话",
width:150,
width: 150,
dataIndex: "tel",
},
{
title: "民族",
width:150,
width: 150,
dataIndex: "eth",
},
{
title: "是否党员",
width:150,
width: 150,
dataIndex: "p_member",
render: (p_member) => <span>{p_member === 1 ? "是" : "否"}</span>,
},
{
title: "是否退役军人",
width:150,
width: 150,
dataIndex: "vet",
render: (vet) => <span>{vet === 1 ? "是" : "否"}</span>,
},
{
title: "备注",
width:150,
width: 150,
dataIndex: "remark",
},
];

View File

@ -16,10 +16,10 @@ import WhseMgmtRoute from "@/pages/whseMgmt/whseMgmt_route";
import Emergency from "@/pages/emergency";
import Patrol from "@/pages/patrol";
import Training from "@/pages/training";
import OrgChart from "@/pages/OrgChart";
import PoverPage from "@/pages/poverPage";
import PoverDetail from "@/pages/poverDetail";
import SystemPage from "@/pages/system";
import OrgChart from "@/pages/OrgChart";
export const homeRouter = [
{
path: "/",

52
src/store/home.ts Normal file
View File

@ -0,0 +1,52 @@
import { action, makeObservable, observable } from "mobx";
// 档案文件夹
import baseHttp from "@/service/base";
import BaseStore from "./baseStore";
import { TagDataType } from "@/model/userModel";
class HomeConfig {
static os: string = "public/os"
static tr: string = "public/tr"
static af: string = "public/af"
static mm: string = "public/mm"
static rm: string = "public/rm"
static ae: string = "public/ae"
}
class HomeStore extends BaseStore<TagDataType> {
constructor() {
super(HomeConfig)
makeObservable(this, {
getOgCount: action,
ogMap: observable,
alist: observable,
})
}
async getOgCount() {
let res = await baseHttp.get(HomeConfig.os, {});
this.ogMap = res.data.record
}
async getTr() {
return await baseHttp.get(HomeConfig.tr, {});
}
async getAf() {
return await baseHttp.get(HomeConfig.af, {});
}
async getMm() {
return await baseHttp.get(HomeConfig.mm, {});
}
async getRm() {
return await baseHttp.get(HomeConfig.rm, {});
}
async getAe() {
return await baseHttp.get(HomeConfig.ae, {});
}
ogMap!: Object;
alist!: Array<any>;
}
const homeStore = new HomeStore()
export default homeStore;

View File

@ -20,6 +20,7 @@ import { patrolStore } from './patrol';
import { trainingStore } from './training';
import { trainingCatStore } from './trainingCat';
import { sysStore } from './sys';
import homeStore from './home';
const store = {
usrStore,
@ -44,6 +45,7 @@ const store = {
trainingStore,
trainingCatStore,
sysStore,
homeStore
};
export default store;

View File

@ -9,6 +9,9 @@ class UserConfig {
static ADD: string = "user"
static DELETE: string = "user"
static EDIT: string = "user"
static team: string = "team/list"
static per: string = "persMgmt/list"
}
class UserStore extends BaseStore<UserDataType> {
_userinfo: UserInfos = {}; // 用户信息
@ -19,12 +22,20 @@ class UserStore extends BaseStore<UserDataType> {
makeObservable(this, {
logOut: action,
login: action,
getTeam:action,
getPer:action,
_userinfo: observable,
isNeedLogin: observable,
openLoginDilog: action,
userInfo: computed,
})
}
async getTeam(){
return await baseHttp.get(UserConfig.team, null)
}
async getPer(){
return await baseHttp.get(UserConfig.per, null)
}
get userInfo(): UserInfos {
if (!this._userinfo.token) {
let token = window.localStorage.getItem("token")

View File

@ -34,11 +34,11 @@
pc?.setLocalDescription(offer);
ws.send(JSON.stringify({
type: "offer", "data": {
"to": "467056",
"to": "01J8RT7YMKZNVWTYAECJ55S6W0",
"from": "31283192",
"description": offer,
"media": "video",
"session_id": "467056-31283192",
"session_id": "01J8RT7YMKZNVWTYAECJ55S6W0-31283192",
}
}))
// socketService.send({ type: 'offer', data: offer })
@ -49,7 +49,7 @@
}
// wss://rw.quwanya.cn/ws
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then(stream => {
const configuration = {
@ -126,14 +126,6 @@
pc.addIceCandidate(candidate)
case "answer":
pc?.setRemoteDescription(msg.data.description)
// let answer = JSON.parse(msg.content.body)
// if (!answer) {
// return console.log('failed to parse answer')
// }
// console.log(answer)
// this.setOffer(answer.data.description)
// break;
}
}

View File

@ -1,30 +1,38 @@
import SocketService from "./socket";
const socketService = SocketService.getInstance();
// const socketService = SocketService.getInstance();
class WebRtc {
private mediaStream: MediaStream | Blob | null = null;
private pee: RTCPeerConnection | null = null;
private ws: WebSocket | null = null;
private video: HTMLVideoElement | null = null;
private userToId: string = "";
open = () => {
this.ws?.send(JSON.stringify({
type: "new", "data": {
"name": "admin",
"id": "31283192",
"user_agent": "flutter-webrtc/js"
}
}))
}
async init() {
this.video = document.getElementById('rtcVideo') as HTMLVideoElement;
socketService.on("message", (e) => {
let msg = JSON.parse(e)
this.ws = new WebSocket("ws://rw.quwanya.cn:12217/ws")
this.ws.addEventListener('open', this.open);
let that = this;
this.createOffer()
this.ws.onmessage = function (evt) {
let msg = JSON.parse(evt.data)
if (!msg) {
return console.log('failed to parse msg')
}
switch (msg.type) {
case "answer":
let answer = JSON.parse(msg.content.body)
if (!answer) {
return console.log('failed to parse answer')
}
console.log(answer)
this.setOffer(answer.data.description)
break;
case "offer":
case 'offer':
let offer = msg.data.description
this.pee?.setRemoteDescription(offer)
this.pee?.createAnswer().then(answer => {
this.pee?.setLocalDescription(answer)
socketService.send(JSON.stringify({
that.pee?.setRemoteDescription(offer)
that.pee?.createAnswer().then(answer => {
that.pee?.setLocalDescription(answer)
that.ws?.send(JSON.stringify({
type: 'answer', data: {
'to': msg.data.from,
'from': "31283192",
@ -33,15 +41,24 @@ class WebRtc {
}
}))
})
break;
return
case 'candidate':
this.pee?.setRemoteDescription(msg.data.description)
let candidate = msg.data.candidate
if (!candidate) {
return console.log('failed to parse candidate')
}
that.pee?.addIceCandidate(candidate)
break;
default:
case "answer":
that.pee?.setRemoteDescription(msg.data.description)
break;
case "bye":
that.pee?.close()
that.close()
break;
}
});
this.createOffer();
}
}
async createOffer() {
try {
@ -50,6 +67,7 @@ class WebRtc {
};
const peerConnection = new RTCPeerConnection(configuration);
this.pee = peerConnection
// 获取远方流添加到页面播放
peerConnection.ontrack = event => {
const remoteVideo = document.querySelector('#remoteVideo') as HTMLVideoElement;
@ -61,28 +79,33 @@ class WebRtc {
}
};
await this.getMedia(peerConnection)
this.sendOffer()
peerConnection.onicecandidate = e => {
if (!e.candidate) {
return
}
socketService.send({ type: 'candidate', data: e.candidate })
this.ws?.send(JSON.stringify({ type: 'candidate', data: e }))
}
} catch (error) {
console.log(error);
}
}
sendOffer() {
sendOffer(userId) {
let that = this;
that.userToId = userId;
that.video = document.getElementById('rtcVideo') as HTMLVideoElement;
if (that.pee?.connectionState==="closed"){
that.createOffer()
}
that.pee?.createOffer().then(function (offer) {
that.pee?.setLocalDescription(offer);
socketService.send(JSON.stringify({
that.ws?.send(JSON.stringify({
type: "offer", "data": {
"to": "848401",
"to": userId,
"from": "31283192",
"description": offer,
"media": "video",
"session_id": "848401-31283192",
"session_id": userId + "-31283192",
}
}))
}).catch(function (error) {
@ -90,11 +113,7 @@ class WebRtc {
console.error(error);
});
}
setOffer(offer) {
this.pee?.setRemoteDescription(offer)
}
addIceCandidate(candidate) {
console.log('addIceCandidate');
this.pee?.addIceCandidate(candidate)
}
async getMedia(pee: RTCPeerConnection) {
@ -105,12 +124,12 @@ class WebRtc {
});
this.mediaStream = stream;
stream.getTracks().forEach(track => pee.addTrack(track, stream))
this.calls();
} catch (error) {
console.log(error);
}
}
calls() {
calls(userId) {
this.sendOffer(userId)
if (this.video) {
this.video.srcObject = this.mediaStream;
this.video.autoplay = true;
@ -120,6 +139,15 @@ class WebRtc {
close() {
this.video?.pause();
this.pee?.close();
this.ws?.send(JSON.stringify({
"type": "bye", "data": {
"session_id": this.userToId + "31283192",
"to": this.userToId
}
}
));
(this.mediaStream as MediaStream)?.getTracks().forEach(track => track.stop());
}
}