fix(amap):集成webrtc 到自有代码
This commit is contained in:
parent
08c8a91182
commit
210df9fa06
|
@ -1,17 +1,25 @@
|
|||
import React, { useMemo, useRef, useState } from 'react';
|
||||
import { Select, Spin } from 'antd';
|
||||
import type { SelectProps } from 'antd';
|
||||
import debounce from 'lodash/debounce';
|
||||
import React, { useMemo, useRef, useState } from "react";
|
||||
import { Select, Spin } from "antd";
|
||||
import type { SelectProps } from "antd";
|
||||
import debounce from "lodash/debounce";
|
||||
|
||||
export interface DebounceSelectProps<ValueType = any>
|
||||
extends Omit<SelectProps<ValueType | ValueType[]>, 'options' | 'children'> {
|
||||
extends Omit<SelectProps<ValueType | ValueType[]>, "options" | "children"> {
|
||||
fetchOptions: (search: string) => Promise<ValueType[]>;
|
||||
debounceTimeout?: number;
|
||||
}
|
||||
|
||||
const DebounceSelect = <
|
||||
ValueType extends { key?: string; label: React.ReactNode; value: string | number } = any,
|
||||
>({ fetchOptions, debounceTimeout = 800, ...props }: DebounceSelectProps<ValueType>) =>{
|
||||
ValueType extends {
|
||||
key?: string;
|
||||
label: React.ReactNode;
|
||||
value: string | number;
|
||||
} = any
|
||||
>({
|
||||
fetchOptions,
|
||||
debounceTimeout = 800,
|
||||
...props
|
||||
}: DebounceSelectProps<ValueType>) => {
|
||||
const [fetching, setFetching] = useState(false);
|
||||
const [options, setOptions] = useState<ValueType[]>([]);
|
||||
const fetchRef = useRef(0);
|
||||
|
@ -43,9 +51,10 @@ const DebounceSelect = <
|
|||
onSearch={debounceFetcher}
|
||||
notFoundContent={fetching ? <Spin size="small" /> : null}
|
||||
{...props}
|
||||
|
||||
options={options}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default DebounceSelect
|
||||
export default DebounceSelect;
|
||||
|
|
|
@ -7,107 +7,19 @@ import { HomeTwoTone } from "@ant-design/icons";
|
|||
import { inject, observer } from "mobx-react";
|
||||
import { Store } from "antd/es/form/interface";
|
||||
import { useEffect } from "react";
|
||||
import { items } from "./layout_config";
|
||||
const LayOut = (props: Store) => {
|
||||
const { usrStore } = props;
|
||||
const nav = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
useEffect(() => {
|
||||
console.log("layout ",usrStore.isNeedLogin);
|
||||
if (usrStore.isNeedLogin) {
|
||||
nav("/login");
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [usrStore.isNeedLogin]);
|
||||
const items = [
|
||||
{
|
||||
key: "/admin/user",
|
||||
label: `用户管理`,
|
||||
children: [
|
||||
{
|
||||
key: "/admin/dep",
|
||||
label: `部门管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/user",
|
||||
label: `用户管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/teamMgmt",
|
||||
label: `队伍属性管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/persMgmt",
|
||||
label: `个人身份管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/community",
|
||||
label: `社区管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/grid",
|
||||
label: `网格管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/patrolBrigade",
|
||||
label: `巡防大队`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "/admin/archives/box",
|
||||
label: `档案管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/material",
|
||||
label: `物资管理`,
|
||||
children: [
|
||||
{
|
||||
key: "/admin/whse/whseMgmt",
|
||||
label: `仓库管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/materialMgmt",
|
||||
label: `物资管理`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "/admin/leaveApproval",
|
||||
label: `请假审批`,
|
||||
},
|
||||
{
|
||||
key: "/admin/political",
|
||||
label: `政治法规`,
|
||||
children: [
|
||||
{
|
||||
key: "/admin/politicalStudy",
|
||||
label: `政治学习`,
|
||||
},
|
||||
{
|
||||
key: `/admin/polRegulations`,
|
||||
label: `政治法规管理`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "/admin/task",
|
||||
label: `任务管理`,
|
||||
children: [
|
||||
{ label: "处突任务", key: "/admin/emergency" },
|
||||
{ label: "巡逻任务", key: "/admin/patrol" },
|
||||
{ label: "训练任务", key: "/admin/training" },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "/admin/sys",
|
||||
label: `系统管理`,
|
||||
children: [
|
||||
{ label: "系统设置", key: "/admin/sys/setting" },
|
||||
{ label: "光荣牌审核", key: "/admin/sys/gp" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="layout">
|
||||
<Header
|
||||
|
@ -136,6 +48,8 @@ const LayOut = (props: Store) => {
|
|||
}}
|
||||
style={{ flex: 1, minWidth: 0 }}
|
||||
/>
|
||||
|
||||
<span style={{ color: "#fff" }}>退出登录</span>
|
||||
</Header>
|
||||
<Content style={{ padding: "0 20px" }}>
|
||||
<Outlet />
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
export const items = [
|
||||
{
|
||||
key: "/admin/user",
|
||||
label: `用户管理`,
|
||||
children: [
|
||||
{
|
||||
key: "/admin/user",
|
||||
label: `用户管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/teamMgmt",
|
||||
label: `队伍属性管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/persMgmt",
|
||||
label: `个人身份管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/community",
|
||||
label: `社区管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/grid",
|
||||
label: `网格管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/patrolBrigade",
|
||||
label: `巡防大队`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "/admin/archives/box",
|
||||
label: `档案管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/material",
|
||||
label: `物资管理`,
|
||||
children: [
|
||||
{
|
||||
key: "/admin/whse/whseMgmt",
|
||||
label: `仓库管理`,
|
||||
},
|
||||
{
|
||||
key: "/admin/materialMgmt",
|
||||
label: `物资管理`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "/admin/leaveApproval",
|
||||
label: `请假审批`,
|
||||
},
|
||||
{
|
||||
key: "/admin/political",
|
||||
label: `政治法规`,
|
||||
children: [
|
||||
{
|
||||
key: "/admin/politicalStudy",
|
||||
label: `政治学习`,
|
||||
},
|
||||
{
|
||||
key: `/admin/polRegulations`,
|
||||
label: `政治法规管理`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "/admin/task",
|
||||
label: `任务管理`,
|
||||
children: [
|
||||
{ label: "处突任务", key: "/admin/emergency" },
|
||||
{ label: "巡逻任务", key: "/admin/patrol" },
|
||||
{ label: "训练任务", key: "/admin/training" },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "/admin/sys",
|
||||
label: `系统管理`,
|
||||
children: [
|
||||
{ label: `部门管理`, key: "/admin/dep" },
|
||||
{ label: "系统设置", key: "/admin/sys/setting" },
|
||||
{ label: "光荣牌审核", key: "/admin/sys/gp" },
|
||||
{ label: "评优审核", key: "/admin/sys/gp" },
|
||||
],
|
||||
},
|
||||
];
|
|
@ -35,7 +35,7 @@ const Dep = (props: Store) => {
|
|||
setIsModalOpen(true);
|
||||
formRef.current?.setFieldsValue(data);
|
||||
setRecord(data);
|
||||
setId(record.id);
|
||||
setId(record.key);
|
||||
};
|
||||
const onFinish = (values: any) => {
|
||||
if (!tagId) {
|
||||
|
@ -95,11 +95,11 @@ const Dep = (props: Store) => {
|
|||
type DirectoryTreeProps = GetProps<typeof Tree.DirectoryTree>;
|
||||
|
||||
const onSelect: DirectoryTreeProps["onSelect"] = (keys, info) => {
|
||||
console.log("Trigger Select", keys, info);
|
||||
// console.log("Trigger Select", keys, info);
|
||||
};
|
||||
|
||||
const onExpand: DirectoryTreeProps["onExpand"] = (keys, info) => {
|
||||
console.log("Trigger Expand", keys, info);
|
||||
// console.log("Trigger Expand", keys, info);
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -126,11 +126,32 @@ const Dep = (props: Store) => {
|
|||
onExpand={onExpand}
|
||||
treeData={org}
|
||||
titleRender={(nodeData: DataNode) => {
|
||||
return <>{nodeData.title}<span style={{marginLeft:"10px",color:"blue"}} onClick={edit}>编辑</span></>
|
||||
return (
|
||||
<>
|
||||
{nodeData.title}
|
||||
<span
|
||||
style={{ marginLeft: "10px", color: "blue" }}
|
||||
onClick={() => {
|
||||
edit(nodeData);
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
</span>
|
||||
<span
|
||||
style={{ marginLeft: "10px", color: "blue" }}
|
||||
onClick={() => {
|
||||
depStore.deleteItem(nodeData.key);
|
||||
getOrg()
|
||||
}}
|
||||
>
|
||||
删除
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Modal
|
||||
title={!tagId ? "添加部门" : "编辑部门"}
|
||||
title={!record ? "添加部门" : "编辑部门"}
|
||||
width={800}
|
||||
open={isModalOpen}
|
||||
afterClose={() => formRef.current?.resetFields()}
|
||||
|
@ -139,6 +160,7 @@ const Dep = (props: Store) => {
|
|||
cancelText="取消"
|
||||
onCancel={() => {
|
||||
setId(null);
|
||||
setRecord(null);
|
||||
setIsModalOpen(false);
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -149,7 +149,7 @@ const Emergency = (props: Store) => {
|
|||
baseHttp.get("/user/list", null).then((res) => {
|
||||
let data = res.data?.record ?? [];
|
||||
data.forEach((item) => {
|
||||
item.label = item.account;
|
||||
item.label = item.user_name;
|
||||
item.value = item.identity;
|
||||
});
|
||||
setUserList(data ?? []);
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 2;
|
||||
flex: 5;
|
||||
.title_img {
|
||||
margin-left: 10px;
|
||||
width: 20px;
|
||||
|
@ -66,7 +66,7 @@
|
|||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
color: #fff;
|
||||
font-size: 30px;
|
||||
font-size:25px;
|
||||
font-weight: normal;
|
||||
line-height: normal;
|
||||
letter-spacing: 0.1em;
|
||||
|
@ -81,7 +81,7 @@
|
|||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
line-height: normal;
|
||||
letter-spacing: 0.1em;
|
||||
|
|
|
@ -21,7 +21,7 @@ const Home = observer(() => {
|
|||
</div>
|
||||
<div className="map_container_t_c">
|
||||
<img className="twp on_to" src={image2} alt="" />
|
||||
<span>黄水镇武装平台</span>
|
||||
<span>黄水镇微网实格应急处突综合指挥服务平台</span>
|
||||
<img className="twp" src={image2} alt="" />
|
||||
</div>
|
||||
<div className="map_container_t_r">
|
||||
|
|
|
@ -5,25 +5,33 @@ import { useState } from "react";
|
|||
import "./bot.less";
|
||||
import { PhoneTwoTone } from "@ant-design/icons";
|
||||
import { webRTC } from "@/util/webRtc";
|
||||
|
||||
import DebounceSelect from "@/components/form/featch_select";
|
||||
interface UserValue {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
const Ec = (props: Store) => {
|
||||
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
|
||||
const { usrStore } = props;
|
||||
const [userList, setUserList] = useState<any>([]);
|
||||
const openDispatch = () => {
|
||||
try {
|
||||
usrStore.getlist().then(() => {
|
||||
setUserList(usrStore.list);
|
||||
webRTC.init();
|
||||
setIsModalOpen(true);
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
const callphone = (record: any) => {
|
||||
webRTC.calls(record.identity);
|
||||
webRTC.calls(record.value);
|
||||
};
|
||||
const [value, setValue] = useState<UserValue[]>([]);
|
||||
async function fetchUserList(username: string): Promise<UserValue[]> {
|
||||
return usrStore.serchUser(username).then((res) => {
|
||||
return res.data.record.map((item) => ({
|
||||
label: item.user_name,
|
||||
value: item.identity,
|
||||
}));
|
||||
});
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<span onClick={openDispatch}> 应急连线</span>
|
||||
|
@ -45,16 +53,27 @@ const Ec = (props: Store) => {
|
|||
<h3>应急连线</h3>
|
||||
</div>
|
||||
<div className="u-item">
|
||||
{userList.map((item: any) => {
|
||||
return (
|
||||
<div key={item.account}>
|
||||
<div>姓名:{item.user_name} : 未在线</div>
|
||||
<DebounceSelect
|
||||
mode="multiple"
|
||||
value={value}
|
||||
placeholder="输入搜索"
|
||||
fetchOptions={fetchUserList}
|
||||
onChange={(newValue) => {
|
||||
setValue(newValue as UserValue[]);
|
||||
}}
|
||||
style={{ width: "100%" }}
|
||||
/>
|
||||
<p></p>
|
||||
{value.map((item: any) => {
|
||||
return (
|
||||
<div key={item.key}>
|
||||
<div>姓名:{item.label} : 未在线</div>
|
||||
<div>
|
||||
点击呼叫:
|
||||
<PhoneTwoTone
|
||||
style={{ fontSize: "20px" }}
|
||||
onClick={(items) => {
|
||||
webRTC.init();
|
||||
callphone(item);
|
||||
}}
|
||||
/>
|
||||
|
@ -75,7 +94,6 @@ const Ec = (props: Store) => {
|
|||
style={{ width: "300px", height: "300px" }}
|
||||
></video>
|
||||
</div>
|
||||
|
||||
<p
|
||||
className="ec_right_end"
|
||||
onClick={() => {
|
||||
|
|
|
@ -14,16 +14,33 @@ const Weather = () => {
|
|||
<div
|
||||
style={{
|
||||
flex: "1",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-around",
|
||||
color: "#fff",
|
||||
fontSize: "13px",
|
||||
padding:"10px"
|
||||
}}
|
||||
>
|
||||
<p>天气:{wechaer?.weather}</p>
|
||||
<p>风向:{wechaer?.windDirection}</p>
|
||||
<p>风级:{wechaer?.windPower}</p>
|
||||
<p>湿度:{wechaer?.humidity}</p>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<span>天气:{wechaer?.weather}</span>
|
||||
<span>风向:{wechaer?.windDirection}</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<span>风级:{wechaer?.windPower}</span>
|
||||
<span>湿度:{wechaer?.humidity}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ const videoJsOptions = {
|
|||
fluid: true,
|
||||
sources: [
|
||||
{
|
||||
src: "http://112.19.145.68:18000/hls/stream_1_0/playlist.m3u8",
|
||||
src: "http://183.221.86.205:18000/hls/stream_1_0/playlist.m3u8",
|
||||
type: "application/x-mpegURL",
|
||||
},
|
||||
],
|
||||
|
@ -19,7 +19,6 @@ const Video = (props: Store) => {
|
|||
const { homeStore, onReady } = props;
|
||||
const videoRef = useRef<HTMLDivElement>(null);
|
||||
const playerRef = useRef<any>(null); // 使用 any 类型
|
||||
|
||||
useEffect(() => {
|
||||
homeStore.getNewTask();
|
||||
}, [homeStore]);
|
||||
|
@ -44,7 +43,6 @@ const Video = (props: Store) => {
|
|||
}, [videoRef, onReady]);
|
||||
useEffect(() => {
|
||||
const player = playerRef.current;
|
||||
|
||||
return () => {
|
||||
if (player && !player.isDisposed()) {
|
||||
player.dispose();
|
||||
|
|
|
@ -64,7 +64,7 @@ const Regulations = (props: Store) => {
|
|||
const onFinish = (values: any) => {
|
||||
let data = {
|
||||
...values,
|
||||
file_url: values.file_url[0].name,
|
||||
file_url: (values.file_url.length>0)? values.file_url[0].name:'',
|
||||
};
|
||||
if (!record?.id) {
|
||||
regulationsStore.add(data);
|
||||
|
|
|
@ -37,7 +37,12 @@ export const defaultConfig = [
|
|||
label: "法规副标题",
|
||||
name: "sub_title",
|
||||
value: "",
|
||||
rules: [{ required: true, message: "请输入法规副标题!" }],
|
||||
},
|
||||
{
|
||||
type: FormType.inputNumber,
|
||||
label: "排序",
|
||||
name: "level",
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
type: "editor",
|
||||
|
|
|
@ -24,7 +24,6 @@ axios.interceptors.response.use((res: AxiosResponse) => {
|
|||
}
|
||||
return res;
|
||||
}, (err) => {
|
||||
|
||||
if (err.status === 401) {
|
||||
store.usrStore.openLoginDilog()
|
||||
store.usrStore.logOut()
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 362 KiB After Width: | Height: | Size: 101 KiB |
|
@ -2,7 +2,7 @@ class Config {
|
|||
static baseUrl = "https://rw.quwanya.cn/";
|
||||
static uploadUrl = "https://rw.quwanya.cn/";
|
||||
static ws = "wss://rw.quwanya.cn/wsadmin?id=admin";
|
||||
static rtc = "wss://rw.quwanya.cn/ws";
|
||||
// static rtc = "wss://rw.quwanya.cn/ws";
|
||||
static userStatic = "https://rw.quwanya.cn/uploads/user/";
|
||||
// https://rw.quwanya.cn/uploads/user/%E5%B4%94%E6%96%87%E8%8C%9C.jpg
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
import Config from "./config";
|
||||
import SocketService from "./socket";
|
||||
|
||||
class WebRtc {
|
||||
private mediaStream: MediaStream | Blob | null = null;
|
||||
private pee: RTCPeerConnection | null = null;
|
||||
private ws: WebSocket | null = null;
|
||||
private ws: SocketService | null = null;
|
||||
private video: HTMLVideoElement | null = null;
|
||||
private userToId: string = "";
|
||||
open = () => {
|
||||
|
@ -17,12 +17,13 @@ class WebRtc {
|
|||
}))
|
||||
}
|
||||
async init() {
|
||||
this.ws = new WebSocket(Config.rtc)
|
||||
this.ws.addEventListener('open', this.open);
|
||||
let that = this;
|
||||
this.ws = SocketService.getInstance();
|
||||
this.ws.on("message", this.onMessage);
|
||||
this.createOffer()
|
||||
this.ws.onmessage = function (evt) {
|
||||
let msg = JSON.parse(evt.data)
|
||||
}
|
||||
onMessage = (e: any) => {
|
||||
let that = this;
|
||||
let msg = JSON.parse(e.data)
|
||||
if (!msg) {
|
||||
return console.log('failed to parse msg')
|
||||
}
|
||||
|
@ -59,15 +60,12 @@ class WebRtc {
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
async createOffer() {
|
||||
|
||||
var url =
|
||||
'http://rw.quwanya.cn:12217/api/turn?service=turn&username=flutter-webrtc';
|
||||
fetch(url)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
|
||||
const configuration = {
|
||||
iceServers: [
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue