fix(api):task crud

This commit is contained in:
wang_yp 2024-09-28 15:01:02 +08:00
parent 35ec46e38c
commit c1c33e3b29
42 changed files with 2052 additions and 448 deletions

View File

@ -1,10 +1,11 @@
import { Outlet } from "react-router";
import MyComponent from "./components/errorComp";
import MapUtl from "./components/map/mapUtil";
// import MapUtl from "./components/map/mapUtil";
import { useEffect } from "react";
const { socket } = require("./util/socket");
socket.init();
socket.onmessage((e) => {
const data = JSON.parse(e.data);
// const data = JSON.parse(e.data);
// if (data.type === "heartbeat") {
// MapUtl.makerList[0].setPosition([103.55, 30.342]);
// var m = MapUtl.amap;
@ -17,6 +18,9 @@ socket.onmessage((e) => {
// }
});
const App = () => {
useEffect(() => {
console.log("app mounted");
}, []);
return (
<>
<MyComponent>

View File

@ -28,6 +28,7 @@ const BTable = (props: any) => {
<Table
style={{ height: "100%", overflow: "auto" }}
pagination={false}
scroll={{ x: 'max-content' }}
loading={store.listStatus}
rowSelection={rowSelection}
columns={props.columns}

View File

@ -2,6 +2,7 @@ import { FormInstance } from "antd"
import React from "react"
export enum FormType {
input = "input",
inputNumber = "inputNumber",
select = "select",
editor = "editor",
date = "date",
@ -22,6 +23,7 @@ export interface FormDatas {
selectUrl?: string,
selectList?: Array<selectItem>
checkboxData?: Array<any>,
radioData?: Array<any>,
rules: Array<rules>
}

View File

@ -1,4 +1,4 @@
import { Checkbox, DatePicker, Form, Input, Radio } from "antd";
import { Checkbox, DatePicker, Form, Input, InputNumber, Radio } from "antd";
import { useEffect } from "react";
import { FormType, SimpleFormData } from "./interface";
import { FormSelect } from "./select";
@ -43,6 +43,17 @@ const SimpleForm = (props: SimpleFormData) => {
<Input defaultValue={v.value} value={v.value} />
</Form.Item>
);
case FormType.inputNumber:
return (
<Form.Item
key={v.label}
label={v.label}
name={v.name}
rules={v.rules}
>
<InputNumber defaultValue={v.value} value={v.value} />
</Form.Item>
);
case "password":
return (
<Form.Item
@ -149,8 +160,9 @@ const SimpleForm = (props: SimpleFormData) => {
rules={v.rules}
>
<Radio.Group>
<Radio value={1}></Radio>
<Radio value={2}></Radio>
{v.radioData?.map((item) => (
<Radio key={item.val} value={item.val}>{item.key}</Radio>
))}
</Radio.Group>
</Form.Item>
);
@ -173,9 +185,11 @@ const SimpleForm = (props: SimpleFormData) => {
name={v.name}
rules={v.rules}
>
<MapFrom onChange={(m)=>{
form.setFieldValue(v.name, m);
}}/>
<MapFrom
onChange={(m) => {
form.setFieldValue(v.name, m);
}}
/>
</Form.Item>
);
default:

View File

@ -1,17 +1,17 @@
html{
html {
width: 100%;
height: 100%;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
height: 100%;
}
#root{
#root {
height: 100%;
}
.projectContent {
@ -23,10 +23,10 @@ body {
overflow: hidden;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
.layout{
.layout {
height: 100%;
}
@ -70,37 +70,39 @@ code {
}
}
.btn-dp {
color: #00EF97 !important;
border-color: #00EF97 !important;
color: #00ef97 !important;
border-color: #00ef97 !important;
}
.owner_model{
.owner_model {
padding-bottom: 0px !important;
.ant-modal-content{
background: url("static/frame_s@1x.png") ;
.ant-modal-content {
background: url("static/frame_s@1x.png");
background-size: 100% 100%;
background-position: center center; /* 可选,确保图片在容器中居中 */
background-repeat: no-repeat; /* 确保图片不会重复 */
padding-bottom: 0px;
.ant-modal-close{
display: none;
}
.ant-modal-header{
.ant-modal-header {
padding: 30px 30px;
color: rgba(0, 0, 0, 0.85);
background: none;
border-bottom: 0px solid #f0f0f0;
min-height: 80px;
display: flex;
align-items: center;
padding-left:40px ;
.ant-modal-title{
padding-left: 40px;
position: relative;
top: -38px;
left: -30px;
.ant-modal-title {
color: #fff;
}
}
.ant-modal-body{
min-height: 300px;
.ant-modal-close{
color: #fff;
}
.ant-modal-footer{
.ant-modal-body {
min-height: 300px;
overflow: auto;
}
.ant-modal-footer {
padding: 30px 30px;
text-align: center;
background: transparent;
@ -108,4 +110,4 @@ code {
background: none;
}
}
}
}

329
src/pages/OrgChart.tsx Normal file
View File

@ -0,0 +1,329 @@
import "./org_chart.less";
const OrgChart = () => {
const data = [
{
depName: "镇武装部党委",
depId: 1,
userList: [
{
position: "武装部长",
userName: "李部长",
userId: 1,
},
{
position: "教导员",
userName: "王教导",
userId: 2,
},
],
children: [
{
depName: " 武装力量党支部",
depId: 2,
children: [
{
depName: " 文武社区支部",
depId: 3,
children: [
{
depName: " 一小组",
depId: 6,
userList: [
{
position: "一小组长",
userName: "一小组长",
userId: 6,
},
{
position: "二小组长",
userName: "二小组长",
userId: 8,
},
{
position: "战士",
userName: "王小三",
userId: 11,
},
{
position: "战士",
userName: "王小四",
userId: 12,
},
{
position: "二小组长",
userName: "二小组长",
userId: 8,
},
{
position: "战士",
userName: "王小三",
userId: 11,
},
{
position: "战士",
userName: "王小四",
userId: 13,
},
],
},
{
depName: " 二小组",
depId: 7,
userList: [
{
position: "二小组长",
userName: "二小组长",
userId: 7,
},
{
position: "二小组长",
userName: "二小组长",
userId: 8,
},
{
position: "战士",
userName: "王小三",
userId: 11,
},
{
position: "战士",
userName: "王小四",
userId: 12,
},
],
},
],
userList: [
{
position: "文武社区支部书记",
userName: "书记名称",
userId: 3,
},
],
},
{
depName: " 花龙村支部",
depId: 4,
children: [
{
depName: " 一小组",
depId: 7,
userList: [
{
position: "一小组长",
userName: "一小组长",
userId: 7,
},
{
position: "二小组长",
userName: "二小组长",
userId: 8,
},
{
position: "战士",
userName: "王小三",
userId: 11,
},
{
position: "战士",
userName: "王小四",
userId: 12,
},
{
position: "二小组长",
userName: "二小组长",
userId: 8,
},
{
position: "战士",
userName: "王小四",
userId: 12,
},
],
},
{
depName: " 二小组",
depId: 8,
userList: [
{
position: "二小组长",
userName: "二小组长",
userId: 8,
},
{
position: "战士",
userName: "王小三",
userId: 11,
},
{
position: "战士",
userName: "王小四",
userId: 12,
},
{
position: "战士",
userName: "王小五",
userId: 13,
},
],
},
],
userList: [
{
position: "花龙村支部书记",
userName: "书记名称",
userId: 4,
},
],
},
{
depName: " 云华社区支部",
depId: 5,
children: [
{
depName: " 一小组",
depId: 8,
userList: [
{
position: "一小组长",
userName: "小组长",
userId: 8,
},
{
position: "战士",
userName: "王喜哦",
userId: 12,
},
{
position: "战士",
userName: "王喜吃",
userId: 13,
},
],
},
{
depName: " 二小组",
depId: 9,
userList: [
{
position: "二小组长",
userName: "小组长",
userId: 9,
},
{
position: "战士",
userName: "王小二",
userId: 10,
},
{
position: "战士",
userName: "王小三",
userId: 11,
},
{
position: "战士",
userName: "王小四",
userId: 12,
},
{
position: "战士",
userName: "王小五",
userId: 13,
},
],
},
],
userList: [
{
position: "云华社区支部书记",
userName: "书记名称",
userId: 5,
},
],
},
],
},
],
},
];
const renderTree = (list: Array<any>) => {
return (
<div className="orgsBox">
{list?.map((v, _) => {
if (v.children) {
return (
<div key={v.depName} className="orgs">
{v.depId !== 2 ? (
<span
style={{
display: "inline-block",
width: "20px",
marginLeft: 15,
color: "#fff",
}}
>
{v.depName}
</span>
) : null}
{v.depId === 1 ? (
<div>
{v.userList?.map((v1, _) => {
return (
<div key={v1.userName} className="userNmaeBox">
<img
height={60}
src="https://img0.baidu.com/it/u=2135939479,1633462316&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500"
alt=""
/>
<span className="userNmae">{v1.userName}</span>
</div>
);
})}
</div>
) : (
v.userList?.map((v1, _) => {
return (
<div key={v1.userName} className="userNmaeBox">
<img
height={60}
src="https://img0.baidu.com/it/u=2135939479,1633462316&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500"
alt=""
/>
<span className="userNmae">{v1.userName}</span>
</div>
);
})
)}
{v.depId !== 2 ? (
<div className="line" style={{ width: 130 }}></div>
) : null}
{renderTree(v.children)}
</div>
);
}
return (
<div key={v.depName} style={{ paddingLeft: 20, display: "flex" }}>
{v.userList?.map((v1, _) => {
return (
<div key={v1.userName} className="userNmaeBox">
<img
height={60}
src="https://img1.baidu.com/it/u=1746619441,3368766734&fm=253&fmt=auto&app=138&f=JPEG?w=400&h=400"
alt=""
/>
<span className="userNmae">{v1.userName}</span>
</div>
);
})}
</div>
);
})}
</div>
);
};
return <div>{renderTree(data)}</div>;
};
export default OrgChart;

View File

@ -24,21 +24,22 @@ export const defaultConfig = [
{
type: FormType.input,
label: "档案名称",
name: "category_name",
name: "archives_name",
value: "",
rules: [{ required: true, message: "请输入分类名称!" }],
},
{
type: FormType.input,
label: "档案描述",
name: "category_desc",
name: "archives_desc",
value: "",
},
{
type: FormType.upload,
label: "档案文件",
name: "file_url",
value: "",
rules: [{ required: true, message: "请输入分类名称!" }],
value: [],
},
];

View File

@ -1,16 +1,22 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import "./preview.less";
import Config from "@/util/config";
const Preview = (props: any) => {
const { list } = props;
const [selectIndex, setSelectIndex] = useState<number>(0);
useEffect(() => {
return () => {
setSelectIndex(0);
};
}, []);
return (
<div className="preview_container">
<div className="preview_left">
{list.map((item: any, index: number) => (
{list?.map((item: any, index: number) => (
<span
className={selectIndex === index ? "select" : ""}
onClick={() => setSelectIndex(index)}
key={item}
key={item.archives_name}
>
{item.archives_name}
</span>
@ -18,7 +24,13 @@ const Preview = (props: any) => {
</div>
<div className="preview_center"></div>
<div className="preview_right">
<p></p>
{list && list.length > 0 ? (
<img
style={{ width: "100%", minHeight: "200px" }}
src={Config.uploadUrl + "uploads/" + list[selectIndex].file_url}
alt={list[selectIndex].file_url}
/>
) : null}
</div>
</div>
);

View File

@ -1,4 +1,4 @@
import { Button, Space, Modal, FormInstance } from "antd";
import { Button, Space, Modal, FormInstance, Form, Select } from "antd";
import { inject, observer } from "mobx-react";
import type { ColumnsType } from "antd/es/table";
import BTable from "@/components/b_table";
@ -7,7 +7,8 @@ import { UserDataType } from "@/model/userModel";
import { Store } from "antd/lib/form/interface";
import SimpleForm from "@/components/form/simple_form";
import React from "react";
import { FormType } from "@/components/form/interface";
const { Option } = Select;
const Dep = (props: Store) => {
const { depStore } = props;
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
@ -15,6 +16,7 @@ const Dep = (props: Store) => {
const formRef = React.useRef<FormInstance>(null);
const [record, setRecord] = useState<any>(null);
const [tagId, setId] = useState<Number | null>(null);
const [stoList, setStolist] = useState<any>([]);
const columns: ColumnsType<UserDataType> = [
{ title: "部门名称", dataIndex: "dep_name" },
{ title: "部门描述", dataIndex: "remark" },
@ -23,47 +25,46 @@ const Dep = (props: Store) => {
dataIndex: "id",
render: (any, record) => (
<div>
<Space direction="vertical">
<Space wrap>
<Button
type="dashed"
size="small"
onClick={() => {
edit(record);
}}
>
</Button>
<Button
type="dashed"
danger
size="small"
onClick={() => {
depStore.deleteItem(record.id);
}}
>
</Button>
</Space>
<Space wrap>
<Button
type="dashed"
size="small"
onClick={() => {
edit(record);
}}
>
</Button>
<Button
type="dashed"
danger
size="small"
onClick={() => {
depStore.deleteItem(record.id);
}}
>
</Button>
</Space>
</div>
),
},
];
const edit = (record) => {
record = {
let data = {
...record,
imageUrl: [{ url: record.imageUrl }],
head_img: [{ url: record.head_img }],
};
setProjectConfig(defaultConfig);
setIsModalOpen(true);
formRef.current?.setFieldsValue(record);
setRecord(record);
formRef.current?.setFieldsValue(data);
setRecord(data);
setId(record.id);
};
const onFinish = (values: any) => {
let data = values
data.head_img = values.head_img[0].url
let data = values;
data.head_img = values.head_img[0].url;
if (!tagId) {
depStore.add(data);
} else {
@ -72,17 +73,11 @@ const Dep = (props: Store) => {
setIsModalOpen(false);
};
useEffect(() => {
depStore.getlist();
depStore.getlist().then(() => {
setStolist(depStore.list);
});
}, [depStore]);
const defaultConfig = [
{
type: "select",
label: "上级部门名称",
name: "pdep_id",
value: "",
selectUrl: "dep/list",
rules: [{ required: false, message: "请输入上级部门!" }],
},
{
type: "input",
label: "部门名称",
@ -97,6 +92,23 @@ const Dep = (props: Store) => {
value: "",
rules: [{ required: true, message: "请输入部门描述" }],
},
{
type: FormType.radio,
label: "第三方机构",
name: "other",
radioData: [
{
key: "是",
val: 1,
},
{
key: "否",
val: 2,
},
],
value: "",
rules: [{ required: true, message: "请输入部门描述" }],
},
{
type: "upload",
label: "头像",
@ -146,7 +158,25 @@ const Dep = (props: Store) => {
onFinish={onFinish}
initialValues={true}
onFinishFailed={onFinishFailed}
/>
>
<>
<Form.Item
key="pdep_id"
label="上级部门"
name="pdep_id"
>
<Select placeholder="">
{stoList?.map((v: any) => {
return (
<Option key={v.id} value={v.id}>
{v.dep_name}
</Option>
);
})}
</Select>
</Form.Item>
</>
</SimpleForm>
</Modal>
</Space>
</div>

View File

@ -1,83 +1,127 @@
.contents_center {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
.map_container_t{
position: absolute;
height: 80px;
top: 0;
width: 100%;
background-image: url("../../static/head.png");
background-repeat: no-repeat;
left: 0;
right: 0;
z-index: 1;
display: flex;
align-items: center;
.title_img{
margin-left: 10px;
width: 20px;
height: 20px;
}
.twp{
width: 160px;
height: 30px;
}
>span{
margin-left: 15px;
margin-right: 15px;
color: #fff;
font-size: 38px;
font-weight: normal;
line-height: normal;
letter-spacing: 0.1em;
font-variation-settings: "opsz" auto;
color: #FFFFFF;
text-shadow: 0px 0px 10px #29ECB4;
}
}
.map_container_l{
position: absolute;
left: 0px;
top: 80px;
width: 20%;
bottom: 0px;
z-index: 2;
opacity: 1;
background: rgba(37, 52, 70, 0.4);
backdrop-filter: blur(10px);
}
.map_container_r{
position: absolute;
right: 0px;
top: 80px;
bottom: 0px;
width: 20%;
z-index: 2;
opacity: 1;
background: rgba(37, 52, 70, 0.4);
backdrop-filter: blur(10px);
}
.map_container_b{
position: absolute;
bottom: 0px;
background: rgba(37, 52, 70, 0.4);
height: 80px;
width: 100%;
z-index: 1;
text-align: center;
.bottom_content{
display: inline-block;
padding-top: 15px;
>span{
background: linear-gradient(180deg, rgba(0, 193, 153, 0.1) 0%, rgba(0, 239, 151, 0.8) 100%);
padding: 5px 10px ;
color: #fff;
margin: 0 10px;
cursor: pointer;
font-size: 18px;
}
}
}
@keyframes scroll {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(-100%);
}
}
.contents_center {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
.map_container_t {
position: absolute;
height: 60px;
top: 0;
width: 100%;
background-image: url("../../static/head.png");
background-repeat: no-repeat;
backdrop-filter: blur(10px);
left: 0;
right: 0;
z-index: 1;
display: flex;
align-items: center;
justify-content: space-between;
.map_container_t_l {
display: flex;
align-items: center;
flex: 1;
.title_img {
margin-left: 10px;
width: 20px;
height: 20px;
}
.twp {
width: 160px;
height: 30px;
}
> span {
margin-left: 15px;
margin-right: 15px;
color: #fff;
font-size: 30px;
font-weight: normal;
line-height: normal;
letter-spacing: 0.1em;
font-variation-settings: "opsz" auto;
color: #ffffff;
text-shadow: 0px 0px 10px #29ecb4;
}
}
.scr {
flex: 1;
overflow: hidden;
.scrolling-text {
white-space: nowrap;
display: block;
animation: scroll 10s linear infinite;
color: #fff;
> span {
display: inline-block;
animation: scrollText 10s linear infinite; /* 动画 */
}
:hover >span{
animation-play-state: paused;
}
}
}
.map_container_t_r {
flex: 1;
text-align: right;
padding-right: 10px;
}
}
.map_container_l {
position: absolute;
left: 0px;
top: 60px;
width: 20%;
bottom: 0px;
z-index: 2;
opacity: 1;
background: rgba(37, 52, 70, 0.4);
backdrop-filter: blur(10px);
}
.map_container_r {
position: absolute;
right: 0px;
top: 60px;
bottom: 0px;
width: 20%;
z-index: 2;
opacity: 1;
background: rgba(37, 52, 70, 0.4);
backdrop-filter: blur(10px);
}
.map_container_b {
position: absolute;
bottom: 0px;
backdrop-filter: blur(10px);
background: rgba(37, 52, 70, 0.4);
height: 80px;
width: 100%;
z-index: 1;
text-align: center;
.bottom_content {
display: inline-block;
padding-top: 15px;
> span {
background: linear-gradient(
180deg,
rgba(0, 193, 153, 0.1) 0%,
rgba(0, 239, 151, 0.8) 100%
);
padding: 5px 10px;
color: #fff;
margin: 0 10px;
cursor: pointer;
font-size: 18px;
}
}
}
}

View File

@ -4,15 +4,35 @@ import MapContainer from "@/components/map/MapComponent";
import HomeLeft from "@/pages/home/homeLeft/home_left";
import HomeRight from "@/pages/home/homeRigrt/home_right";
import HomeBottom from "@/pages/home/homeBottom/home_bottom";
import image1 from "@/static/title_jiantou@1x.png"
import image2 from "@/static/title_line@1x.png"
import image1 from "@/static/title_jiantou@1x.png";
import image2 from "@/static/title_line@1x.png";
import { SettingOutlined } from "@ant-design/icons";
import { useNavigate } from "react-router";
const Home = observer(() => {
const navigate = useNavigate();
return (
<div className="contents_center">
<div className="map_container_t">
<div className="map_container_t_l">
<img className="title_img" src={image1} alt="" />
<span></span>
<img className="twp" src={image2} alt=""/>
<img className="twp" src={image2} alt="" />
</div>
<div className="scr">
<div className="scrolling-text">
<span>
32,
41,
23,
</span>
</div>
</div>
<div className="map_container_t_r">
<SettingOutlined
onClick={() => {navigate("admin/user");}}
style={{ fontSize: "20px", color: "#f9f9f9", cursor: "pointer" }}
/>
</div>
</div>
<div className="map_container_l">
<HomeLeft />

View File

@ -0,0 +1,101 @@
.bottom_container {
width: 100%;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.owner_model {
background-color: #000;
}
.disPatch {
#card_basic {
.ant-form-item {
color: #fff;
.ant-row {
color: #fff;
.ant-col {
color: #fff;
> label {
color: #fff;
}
.ant-form-item-control-input {
background: rgba(37, 52, 70, 0.4);
color: #fff;
.ant-select-selector {
background: rgba(37, 52, 70, 0.4);
color: #fff;
}
.ant-input {
background: rgba(37, 52, 70, 0.4);
color: #fff;
}
.ant-picker {
background: rgba(37, 52, 70, 0.4);
.ant-picker-input {
color: #fff;
::placeholder {
color: #fff; /* 设置为灰色 */
}
}
}
.ant-form-item-control-input-content {
color: #fff; /* 设置为灰色 */
.ant-checkbox-group {
color: #fff; /* 设置为灰色 */
.ant-checkbox-wrapper {
color: #fff;
}
}
}
}
}
}
}
}
}
.ec_container {
display: flex;
align-items: start;
justify-content: space-around;
width: 100%;
height: 600px;
overflow: hidden;
.ec_left {
width: 25%;
height: 90%;
overflow-y: auto;
padding: 10px;
background: rgba(37, 52, 70, 0.4);
color: #fff;
text-align: start;
.ec_left_title {
color: #fff;
}
.u-item{
cursor: pointer;
}
}
.ec_right {
width: 75%;
height: 100%;
position: relative;
#rtcVideo{
height: 90%;
width: 100%;
}
.ec_right_end{
position: absolute;
left: 0;
right: 0;
bottom: 20px;
color: #fff;
text-align: center;
}
}
}

View File

@ -0,0 +1,128 @@
import SimpleForm from "@/components/form/simple_form";
import { TrainingConfig } from "@/pages/training/traning_config";
import { Button, Form, FormInstance, Modal, Select } from "antd";
import React, { useEffect } from "react";
import { useState } from "react";
import baseHttp from "@/service/base";
import "./bot.less";
import { Store } from "antd/es/form/interface";
import { inject, observer } from "mobx-react";
import { FormType } from "@/components/form/interface";
const { Option } = Select;
const Dispath = (props: Store) => {
const { trainingStore, trainingCatStore } = props;
const openDispatch = () => {
setIsModalOpen(true);
setProjectConfig([
...TrainingConfig,
{
type: FormType.cehckboxGroup,
label: "参与人员选择",
name: "user_id",
value: [],
checkboxData: userList,
rules: [{ required: true, message: "请选择参与人员!" }],
},
]);
};
const handleCancle = () => {
setIsModalOpen(false);
};
const handleSubmit = () => {
setIsModalOpen(false);
};
const formRef = React.useRef<FormInstance>(null);
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const [projectConfig, setProjectConfig] = useState<any>([]);
const [stashList, setStashList] = useState<any>([]);
const [userList, setUserList] = useState<any>([]);
useEffect(() => {
trainingCatStore.getlist().then(() => {
setStashList(trainingCatStore.list);
});
baseHttp.get("/user/list", null).then((res) => {
let data = res.data?.record ?? [];
data.forEach((item) => {
item.label = item.account;
item.value = item.identity;
});
setUserList(data ?? []);
});
}, [trainingCatStore]);
const onFinish = (values: any) => {
let data = {
...values,
score: Number(values.score),
count: Number(values.count),
};
trainingStore.add(data);
setIsModalOpen(false);
};
return (
<>
<span onClick={openDispatch}></span>
<Modal
title={"发布调度任务"}
className="owner_model"
width={800}
open={isModalOpen}
afterClose={() => {}}
onOk={() => {}}
footer={[
<Button key="return" ghost onClick={handleCancle}>
</Button>,
<Button
className="btn-dp"
key="submit"
type="primary"
ghost
onClick={handleSubmit}
>
</Button>,
]}
onCancel={() => {
setIsModalOpen(false);
}}
>
<div className="disPatch" style={{ fontSize: "#fff" }}>
<SimpleForm
formRef={formRef}
createCallback={() => {}}
formName="card_basic"
colProps={25}
subBtnName="提交"
formDatas={projectConfig}
onFinish={onFinish}
initialValues={true}
onFinishFailed={() => {}}
>
<>
<Form.Item
key="category_identity"
label="训练类别"
name="category_identity"
rules={[{ required: true, message: "请选择训练类别!" }]}
>
<Select placeholder="">
{stashList?.map((v: any) => {
return (
<Option key={v.identity} value={v.identity}>
{v.name}
</Option>
);
})}
</Select>
</Form.Item>
</>
</SimpleForm>
</div>
</Modal>
</>
);
};
export default inject("trainingStore", "trainingCatStore")(observer(Dispath));

View File

@ -0,0 +1,71 @@
import { Modal } from "antd";
import { Store } from "antd/es/form/interface";
import { inject, observer } from "mobx-react";
import { useEffect, useState } from "react";
import "./bot.less";
import { PhoneTwoTone } from "@ant-design/icons";
import { webRTC } from "@/util/webRtc";
const Ec = (props: Store) => {
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const { usrStore } = props;
const [userList, setUserList] = useState<any>([]);
useEffect(() => {
usrStore.getlist().then(() => {
setUserList(usrStore.list);
});
}, [usrStore]);
const openDispatch = () => {
setIsModalOpen(true);
};
const callphone=(record:any)=>{
webRTC.init()
webRTC.calls()
}
return (
<>
<span onClick={openDispatch}> 线</span>
<Modal
title={"应急连线"}
className="owner_model"
width={800}
open={isModalOpen}
afterClose={() => {}}
onOk={() => {}}
footer={null}
onCancel={() => {
setIsModalOpen(false);
}}
>
<div className="ec_container">
<div className="ec_left">
<div className="ec_left_title">
<h3>线</h3>
</div>
<div className="u-item">
{userList.map((item: any) => {
return (
<div key={item.account}>
<div>{item.account} : 线</div>
<p></p>
<div>
<PhoneTwoTone style={{ fontSize: "20px" }} onClick={(item)=>{callphone(item)}} />
</div>
</div>
);
})}
</div>
</div>
<div className="ec_right">
<video id="rtcVideo"></video>
<p className="ec_right_end" onClick={()=>{
webRTC.close()
}}></p>
</div>
</div>
</Modal>
</>
);
};
export default inject("usrStore")(observer(Ec));

View File

@ -0,0 +1,28 @@
import { Modal } from "antd";
import { useState } from "react";
const Emr = () => {
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const openDispatch = () => {
setIsModalOpen(true);
};
return (
<>
<span onClick={openDispatch}> </span>
<Modal
title={"应急处突"}
className="owner_model"
width={800}
open={isModalOpen}
afterClose={() => {}}
onOk={() => {}}
footer={null}
onCancel={() => {
setIsModalOpen(false);
}}
></Modal>
</>
);
};
export default Emr;

View File

@ -1,56 +1,17 @@
import { useState } from "react";
import { Button, Modal } from "antd";
import "./right.less";
import { webRTC } from "@/util/webRtc";
import Dispath from "./dispath";
import WhichVideo from "./which_video";
import Ec from "./ec";
import Emr from "./emr";
import "./bot.less";
const HomeBottom = () => {
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const openDispatch = () => {
setIsModalOpen(true);
webRTC.init();
};
const handleCancle = () => {
setIsModalOpen(false);
};
const handleSubmit = () => {
setIsModalOpen(false);
};
return (
<div className="bottom_container">
<div className="bottom_content">
<span onClick={openDispatch}></span>
<span onClick={openDispatch}></span>
<span onClick={openDispatch}>线</span>
<span onClick={openDispatch}></span>
<Dispath />
<Emr />
<Ec />
<WhichVideo />
</div>
<Modal
title={"添加用户"}
className="owner_model"
width={800}
open={isModalOpen}
afterClose={() => {}}
onOk={() => {}}
footer={[
<Button key="return" ghost onClick={handleCancle}>
</Button>,
<Button
className="btn-dp"
key="submit"
type="primary"
ghost
onClick={handleSubmit}
>
</Button>,
]}
onCancel={() => {
setIsModalOpen(false);
}}
>
<div>
<video id="localVideo" width={300} height={300} src=""></video>
</div>
</Modal>
</div>
);
};

View File

@ -1,13 +0,0 @@
.bottom_container{
width: 100%;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.owner_model{
background-color: #000;
}

View File

@ -0,0 +1,28 @@
import { Modal } from "antd";
import { useState } from "react";
const WhichVideo = () => {
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const openDispatch = () => {
setIsModalOpen(true);
};
return (
<>
<span onClick={openDispatch}> </span>
<Modal
title={"视频查看"}
className="owner_model"
width={800}
open={isModalOpen}
afterClose={() => {}}
onOk={() => {}}
footer={null}
onCancel={() => {
setIsModalOpen(false);
}}
></Modal>
</>
);
};
export default WhichVideo;

View File

@ -1,13 +1,12 @@
import { useEffect, useState } from "react";
import { Modal } from "antd";
import "./left.less";
import { useNavigate } from "react-router";
import MapUtl from "@/components/map/mapUtil";
import * as echarts from "echarts";
import Orgin from "./orgin";
import Pover from "./pover";
const HomeLeft = () => {
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const navigate = useNavigate();
const initChart = () => {
var myChart = echarts.init(document.getElementById("xunlian"));
var option = {
@ -55,46 +54,11 @@ const HomeLeft = () => {
option && myChart.setOption(option);
};
const initChart2 = () => {
var myChart = echarts.init(document.getElementById("orgin1"));
var option = {
xAxis: {
type: 'category',
data: ['基干民兵', '普通民兵', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisLabel: {
show: true,
interval: 0,
rotate: 30,
},
},
grid: {
top: "10%",
bottom: "45%",
right: "5%",
},
yAxis: {
type: 'value',
splitLine: {
show: false, // 去除网格线
},
},
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar'
}
]
};
option && myChart.setOption(option);
};
useEffect(() => {
initChart();
}, []);
useEffect(() => {
initChart2();
}, []);
const openDispatch = () => {
// const openDispatch = () => {
// 位置移动
// MapUtl.makerList[0].setPosition([103.55, 30.342]);
// var m = MapUtl.amap;
@ -104,26 +68,23 @@ const HomeLeft = () => {
// anchor: new m.Pixel(12, 32), // 图标锚点
// });
// MapUtl.makerList[0].setIcon(newIcon);
};
const jumpToUser = () => {
navigate("admin/user");
};
// };
return (
<div className="left_container">
<div onClick={openDispatch} className="org">
<div className="org">
<div className="org_head">
<p></p>
</div>
<Orgin />
</div>
<div onClick={jumpToUser} className="org">
<div className="org">
<div className="org_head">
<p></p>
</div>
<div style={{ width: "100%", height: "100%" }} id="orgin1"></div>
<Pover />
</div>
<div onClick={openDispatch} className="org">
<div className="org">
<div className="org_head">
<p></p>
</div>

View File

@ -3,7 +3,7 @@
color: #fff;
height: 100%;
display: flex;
flex-direction: column;
flex-direction: column;
.org{
flex:1;
width: 100%;
@ -36,6 +36,11 @@
>img{
width: 100%;
}
>p{
font-size: 13px;
padding-bottom: 0px;
margin-bottom: 0px;
}
}
}
}

View File

@ -1,17 +1,41 @@
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 = () => {
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const showModal = () => {
setIsModalOpen(true);
};
const handleCancel = () => {
setIsModalOpen(false);
};
return (
<div className="orgin-content">
<div className="po">
<span>234</span>
<img src={origin} alt="" />
<>
<div className="orgin-content" onClick={showModal}>
<div className="po">
<span>234</span>
<img src={origin} alt="" />
<p></p>
</div>
<div className="po">
<span>238</span>
<img src={origin2} alt="" />
<p></p>
</div>
</div>
<div className="po">
<span>238</span>
<img src={origin2} alt="" />
</div>
</div>
<Modal
title={"组织架构"}
className="owner_model"
width={"80%"}
open={isModalOpen}
onCancel={handleCancel}
footer={null}
>
<OrgChart />
</Modal>
</>
);
};

View File

@ -0,0 +1,79 @@
import PoverPage from "@/pages/poverPage";
import { Modal } from "antd";
import * as echarts from "echarts";
import { useEffect, useState } from "react";
const Pover = () => {
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const initChart = () => {
var myChart = echarts.init(document.getElementById("pover"));
var option = {
xAxis: {
type: "category",
data: ["基干民兵", "普通民兵", "Wed", "Thu", "Fri", "Sat", "Sun"],
axisLabel: {
show: true,
interval: 0,
rotate: 30,
},
},
grid: {
top: "10%",
bottom: "45%",
right: "5%",
left: "12%",
},
yAxis: {
type: "value",
splitLine: {
show: false, // 去除网格线
},
},
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: "bar",
barWidth: 10, // 设置柱子粗细
itemStyle: {
normal: {
barBorderRadius: [5, 5, 0, 0],
},
},
},
],
};
option && myChart.setOption(option);
};
useEffect(() => {
initChart();
}, []);
const openPoverHander = () => {
setIsModalOpen(true);
};
return (
<>
<div
onClick={openPoverHander}
style={{ width: "100%", height: "100%" }}
id="pover"
></div>
<Modal
title="力量汇总"
className="owner_model"
width={"80%"}
open={isModalOpen}
afterClose={() => {}}
onOk={() => {}}
footer={null}
onCancel={() => {
setIsModalOpen(false);
}}
>
<PoverPage />
{/* <p>cascsa</p> */}
</Modal>
</>
);
};
export default Pover;

View File

@ -1,4 +1,5 @@
import "./right.less";
import Wz from "./wz";
const HomeRight = () => {
return (
<div className="right_container">
@ -6,6 +7,7 @@ const HomeRight = () => {
<div className="org_head">
<p></p>
</div>
<Wz />
</div>
<div className="org">
<div className="org_head">

View File

@ -1,13 +1,13 @@
.right_container {
width: 100%;
color: #fff;
height: 100%;
width: 100%;
color: #fff;
height: auto;
color: #fff;
height: 100%;
display: flex;
flex-direction: column;
.org {
flex:1;
width: 100%;
min-height: 200px;
overflow-y: hidden;
text-align: center;
.org_head {
width: 100%;

View File

@ -0,0 +1,89 @@
import * as echarts from "echarts";
import { useEffect } from "react";
const Wz = () => {
const initChart = () => {
var myChart = echarts.init(document.getElementById("wz"));
var option = {
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b}: {c} ({d}%)",
},
series: [
{
center: ["50%", "40%"],
name: "Access From",
type: "pie",
selectedMode: "single",
radius: [0, "30%"],
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,
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" },
],
},
],
};
option && myChart.setOption(option);
};
useEffect(() => {
initChart();
}, []);
return <div style={{ width: "100%", height: "100%" }} id="wz"></div>;
};
export default Wz;

View File

@ -8,6 +8,7 @@ export const columns: ColumnsType<UserDataType> = [
},
];
export const leaveColumns: ColumnsType<UserDataType> = [
{
title: "请假人",
@ -59,6 +60,16 @@ export const defaultConfig = [
value: "",
rules: [{ required: true, message: "请输入驳回原因!" }],
},
];
export const defaultCatConfig = [
{
type: FormType.input,
label: "分类名称",
name: "name",
value: "",
rules: [{ required: true, message: "请输入分类名称!" }],
},
];

View File

@ -5,7 +5,7 @@ import { useEffect, useState } from "react";
import { Store } from "antd/lib/form/interface";
import SimpleForm from "@/components/form/simple_form";
import React from "react";
import { columns, defaultConfig } from "./levcat_column";
import { columns, defaultCatConfig } from "./levcat_column";
const LeaveCat = (props: Store) => {
const { leaveCategoryStore } = props;
@ -15,7 +15,7 @@ const LeaveCat = (props: Store) => {
const [record, setRecord] = useState<any>(null);
useEffect(() => {
leaveCategoryStore.getlist();
setProjectConfig(defaultConfig);
setProjectConfig(defaultCatConfig);
}, [leaveCategoryStore]);
const column_widget = (any, record) => {
return (
@ -69,7 +69,7 @@ const LeaveCat = (props: Store) => {
type="default"
onClick={() => {
setRecord(null);
setProjectConfig(defaultConfig);
setProjectConfig(defaultCatConfig);
setIsModalOpen(true);
}}
>

View File

@ -26,6 +26,10 @@ export const columns: ColumnsType<UserDataType> = [
title: "所属仓库",
dataIndex: "stash_name",
},
{
title: "数量",
dataIndex: "num",
},
];
export const defaultConfig = [
@ -52,6 +56,13 @@ export const defaultConfig = [
value: "",
rules: [{ required: true, message: "请输入物资描述!" }],
},
{
type: FormType.inputNumber,
label: "物资数量",
name: "num",
value: "",
rules: [{ required: true, message: "请输入物资数量!" }],
},
{
type: FormType.date,
label: "过期时间",

63
src/pages/org_chart.less Normal file
View File

@ -0,0 +1,63 @@
.orgs {
margin-left: 10;
margin-bottom: 10;
display: flex;
align-items: center;
}
.orgsBox{
overflow: auto;
margin: 10px;
}
.line {
position: relative;
height: 3px; /* 线的高度 */
}
.line::after {
content: "";
position: absolute;
left: 0;
right: 0;
top: 0;
border-top: 1px solid #fff; /* 线的颜色和宽度 */
}
.line:before{
content: '';
position: absolute;
top: 50%;
left: 100%;
transform: translate(-50%, -50%);
width: 100%;
height: 50%;
background: #fff; /* 设置线的颜色 */
}
.line:after {
content: '';
position: absolute;
top: 50%;
left:50%;
transform: translate(-50%, -50%);
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;
}
}

View File

@ -0,0 +1,68 @@
import "./pvd.less";
const PoverDetail = () => {
return (
<div className="pvd_table">
<table className="table" border={1}>
<thead>
<tr>
<td ></td>
<td ></td>
<td ></td>
<td ></td>
<td rowSpan={4} colSpan={2}></td>
</tr>
<tr>
<td ></td>
<td >2024-09-12</td>
<td ></td>
<td >广</td>
</tr>
<tr>
<td ></td>
<td ></td>
<td ></td>
<td ></td>
</tr>
<tr>
<td ></td>
<td colSpan={3}></td>
</tr>
<tr>
<td ></td>
<td >13208266337</td>
<td ></td>
<td colSpan={2}>wang_yp2023@qq.com</td>
</tr>
<tr>
<td ></td>
<td ></td>
<td ></td>
<td colSpan={2}></td>
</tr>
<tr>
<td ></td>
<td colSpan={4}></td>
</tr>
<tr>
<td ></td>
<td colSpan={4}></td>
</tr>
<tr>
<td ></td>
<td colSpan={4}></td>
</tr>
<tr>
<td ></td>
<td colSpan={4}></td>
</tr>
<tr>
<td ></td>
<td colSpan={4}></td>
</tr>
</thead>
</table>
</div>
);
};
export default PoverDetail;

View File

@ -0,0 +1,17 @@
.pvd_table {
.table {
width: 100%;
border-collapse: collapse;
overflow-x: auto;
> thead {
> tr {
box-sizing: border-box;
> td {
min-width: 70px;
padding: 10px 10px;
}
}
}
}
}

View File

@ -0,0 +1,134 @@
import { useEffect } from "react";
import * as echarts from "echarts";
import "./pv.less";
import { SnippetsTwoTone } from "@ant-design/icons";
import { inject, observer } from "mobx-react";
import { Store } from "antd/es/form/interface";
import PvTable from "./pvTable";
const PoverPage = (props:Store) => {
const initChart = (id: string) => {
var myChart = echarts.init(document.getElementById(id));
var option = {
title: {
text: "10%",
left: "center",
top: "center",
textStyle: {
color: "#fff",
fontSize: "18px",
},
},
series: [
{
type: "pie",
radius: ["70%", "100%"],
center: ["50%", "50%"],
color: "#000",
data: [
// itemSyle是单项的背景颜色设置。
{
value: 30,
itemStyle: { color: "#254e99", borderRadius: 100 },
emphasis: { scale: false },
},
{
value: 100,
itemStyle: { color: "#f5f5f5" },
emphasis: { scale: false },
},
],
label: {
show: false,
},
animationDelay: function (idx) {
return Math.random() * 200;
},
},
],
};
option && myChart.setOption(option);
};
useEffect(() => {
initChart("pover_jg");
initChart("pover_jgs");
initChart("pover1");
initChart("pover2");
}, []);
return (
<div style={{ width: "100%", height: "100%" }}>
<div className="nav-header">
<div style={{ textAlign: "center" }}>
<div style={{ width: "150px", height: "100px" }} id="pover_jgs"></div>
<span style={{ color: "#fff" }}></span>
</div>
<div className="pv-head-item">
<SnippetsTwoTone style={{ fontSize: 30 }} />
<div>
<div>120</div>
<span></span>
</div>
</div>
<div className="pv-head-item">
<SnippetsTwoTone style={{ fontSize: 30 }} />
<div>
<div>120</div>
<span></span>
</div>
</div>
<div className="pv-head-item">
<SnippetsTwoTone style={{ fontSize: 30 }} />
<div>
<div>120</div>
<span></span>
</div>
</div>
<div className="pv-head-item">
<SnippetsTwoTone style={{ fontSize: 30 }} />
<div>
<div>120</div>
<span>退</span>
</div>
</div>
<div className="pv-head-item">
<SnippetsTwoTone style={{ fontSize: 30 }} />
<div>
<div>120</div>
<span></span>
</div>
</div>
<div className="pv-head-item">
<SnippetsTwoTone style={{ fontSize: 30 }} />
<div>
<div>120</div>
<span></span>
</div>
</div>
</div>
<div className="nav-content">
<div className="content-left">
<div style={{ textAlign: "center" }}>
<div style={{ width: "100%", height: "100%" }} id="pover_jg"></div>
<span style={{ color: "#fff" }}></span>
</div>
<p></p>
<div style={{ textAlign: "center" }}>
<div style={{ width: "100%", height: "100%" }} id="pover1"></div>
<span style={{ color: "#fff" }}></span>
</div>
<p></p>
<div style={{ textAlign: "center" }}>
<div style={{ width: "100%", height: "100%" }} id="pover2"></div>
<span style={{ color: "#fff" }}></span>
</div>
</div>
<div className="content-right">
<p style={{margin:0,fontSize:"20px",marginBottom:"10px"}}></p>
<PvTable />
</div>
</div>
</div>
);
};
export default inject("usrStore")(observer(PoverPage));

View File

@ -0,0 +1,63 @@
.nav-header {
min-height: 50px;
padding: 10px;
display: flex;
}
.nav-content {
width: 100%;
height: 100%;
min-height: 500px;
display: flex;
align-items: start;
justify-content: space-around;
.content-left {
width: 15%;
height: 100%;
}
.content-right {
width: 85%;
height: 100%;
text-align: center;
color: #fff;
}
}
.pv-head-item {
display: flex;
width: 120px;
height: 80px;
align-items: center;
background: rgba(37, 52, 70, 0.4);
color: #fff;
border: 1px solid #000;
border-radius: 10px;
border-bottom-left-radius: 0px;
border-top-left-radius: 20px;
border-bottom-right-radius: 40px;
border-top-right-radius: 0px;
margin-right: 10px;
padding: 5px;
> div {
margin-left: 10px;
}
}
.pv_table {
.table {
width: 100%;
overflow-x: auto;
background: rgba(37, 52, 70, 0.4);
border: 0.5px solid rgba(37, 52, 70, 0.4);
> thead {
background: rgba(37, 52, 70, 0.4);
> tr {
background: #000;
box-sizing: border-box;
> td {
background: rgba(37, 52, 70, 0.4);
min-width: 70px;
padding: 0px 10px;
}
}
}
}
}

View File

@ -0,0 +1,45 @@
const PvTable = () => {
return (
<div className="pv_table">
<table className="table">
<thead>
<tr>
<td rowSpan={2}></td>
<td rowSpan={2}></td>
<td rowSpan={2}></td>
<td rowSpan={2}></td>
<td colSpan={4}></td>
<td colSpan={4}></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>退</td>
</tr>
</thead>
<tbody>
<tr onClick={(e) => console.log(e)}>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
</tbody>
</table>
</div>
);
};
export default PvTable;

View File

@ -12,8 +12,6 @@ import baseHttp from "@/service/base";
import dayjs from "dayjs";
const { Option } = Select;
const Trainings = (props: Store) => {
const { trainingStore, trainingCatStore } = props;
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
@ -92,6 +90,7 @@ const Trainings = (props: Store) => {
let data = {
...values,
score: Number(values.score),
count: Number(values.count),
};
if (!tagId) {
trainingStore.add(data);
@ -146,6 +145,13 @@ const Trainings = (props: Store) => {
value: "",
rules: [{ required: true, message: "请输入任务积分设置!" }],
},
{
type: FormType.input,
label: "训练次数",
name: "count",
value: 0,
rules: [{ required: true, message: "请输入训练次数!" }],
},
{
type: FormType.cehckboxGroup,
label: "参与人员选择",

View File

@ -0,0 +1,54 @@
import { FormType } from "@/components/form/interface";
export const TrainingConfig = [
{
type: FormType.input,
label: "任务标题",
name: "title",
value: "",
rules: [{ required: true, message: "请输入任务标题!" }],
},
{
type: FormType.input,
label: "任务描述",
name: "desc",
value: "",
rules: [{ required: true, message: "请输入任务描述!" }],
},
{
type: FormType.input,
label: "任务地点",
name: "address",
value: "",
rules: [{ required: true, message: "请输入任务地点!" }],
},
{
type: FormType.date,
label: "任务开始时间",
name: "start_time",
value: "",
rules: [{ required: true, message: "请输入任务开始时间!" }],
},
{
type: FormType.date,
label: "任务结束时间",
name: "end_time",
value: "",
rules: [{ required: true, message: "请输入任务结束时间!" }],
},
{
type: FormType.input,
label: "任务积分设置",
name: "score",
value: "",
rules: [{ required: true, message: "请输入任务积分设置!" }],
},
{
type: FormType.input,
label: "训练次数",
name: "count",
value: 0,
rules: [{ required: true, message: "请输入训练次数!" }],
},
]

View File

@ -1,14 +1,12 @@
import { Button, Image, Space, Modal, FormInstance } from "antd";
import { Button, Space, Modal, FormInstance } from "antd";
import { inject, observer } from "mobx-react";
import type { ColumnsType } from "antd/es/table";
import BTable from "@/components/b_table";
import { useEffect, useState } from "react";
import { UserDataType } from "@/model/userModel";
import { Store } from "antd/lib/form/interface";
import "./user.less";
import SimpleForm from "@/components/form/simple_form";
import React from "react";
import { FormType } from "@/components/form/interface";
import { columns, defaultConfig } from "./user_config";
import "./user.less";
const User = (props: Store) => {
const { usrStore } = props;
@ -17,69 +15,33 @@ const User = (props: Store) => {
const formRef = React.useRef<FormInstance>(null);
const [record, setRecord] = useState<any>(null);
const [userId, setId] = useState<Number | null>(null);
const columns: ColumnsType<UserDataType> = [
{
title: "用户名",
dataIndex: "user_name",
},
{
title: "年龄",
dataIndex: "age",
},
{
title: "性别",
dataIndex: "sex",
render: (sex) => <span>{sex === "0" ? "男" : "女"}</span>,
},
{
title: "头像",
dataIndex: "head_img",
render: (headImg) => <Image src={headImg}></Image>,
},
{
title: "职位",
dataIndex: "position",
},
{
title: "备注",
dataIndex: "remark",
},
{
title: "操作",
dataIndex: "id",
ellipsis: {
showTitle: false,
},
render: (any, record) => (
<div>
<Space direction="vertical">
<Space wrap>
<Button
type="dashed"
size="small"
onClick={() => {
edit(record);
}}
>
</Button>
const actionWidget = (any, record) => {
return (
<Space wrap>
<Button
type="dashed"
size="small"
onClick={() => {
edit(record);
}}
>
</Button>
<Button
type="dashed"
danger
size="small"
onClick={() => {
usrStore.deleteItem(record.id);
}}
>
</Button>
</Space>
);
};
<Button
type="dashed"
danger
size="small"
onClick={() => {
usrStore.deleteItem(record.id);
}}
>
</Button>
</Space>
</Space>
</div>
),
},
];
const edit = (record) => {
record = {
...record,
@ -105,61 +67,35 @@ const User = (props: Store) => {
useEffect(() => {
usrStore.getlist();
}, [usrStore]);
const defaultConfig = [
{
type: FormType.input,
label: "用户名",
name: "acount",
value: "",
rules: [{ required: true, message: "请输入人物名称!" }],
},
{
type: FormType.input,
label: "年龄",
name: "age",
value: "",
rules: [{ required: true, message: "请输入卡片内容" }],
},
{
type: FormType.input,
label: "居住地",
name: "address",
value: "",
rules: [{ required: true, message: "请输入卡片内容" }],
},
{
type: FormType.radio,
label: "性别",
name: "sex",
value: 0,
rules: [{ required: true, message: "请输入卡片内容" }],
},
{
type: FormType.upload,
label: "头像",
name: "headImg",
value: [],
rules: [{ required: true, message: "请上传头像" }],
},
];
const addHandler = () => {
setProjectConfig(defaultConfig);
setId(null);
setIsModalOpen(true);
};
const onFinishFailed = () => {};
return (
<div className="contentBox">
<Space direction="vertical" size="middle" style={{ display: "flex" }}>
<Space direction="horizontal" size={"middle"}>
<Button
type="default"
onClick={() => {
setProjectConfig(defaultConfig);
setId(null);
setIsModalOpen(true);
}}
>
<Button type="default" onClick={() => addHandler()}>
</Button>
</Space>
<BTable store={usrStore} columns={columns} dataSource={usrStore.list} />
<BTable
store={usrStore}
columns={[
...columns,
{
title: "操作",
dataIndex: "id",
fixed: 'right',
ellipsis: { showTitle: false },
render: (any, record)=>actionWidget(any, record),
},
]}
dataSource={usrStore.list}
/>
<Modal
title={!userId ? "添加用户" : "编辑用户"}
width={800}

View File

@ -0,0 +1,267 @@
import { FormType } from "@/components/form/interface";
import { UserDataType } from "@/model/userModel";
import { ColumnsType } from "antd/lib/table";
import { Image } from "antd";
export const defaultConfig = [
{
type: FormType.input,
label: "用户名",
name: "user_name",
value: "",
rules: [{ required: true, message: "请输入用户名称!" }],
},
{
type: FormType.radio,
label: "性别",
name: "sex",
radioData: [
{
key: "男",
val: 1,
},
{
key: "女",
val: 2,
},
],
value: 0,
rules: [{ required: true, message: "请选择性别" }],
},
{
type: FormType.input,
label: "年龄",
name: "age",
value: "",
rules: [{ required: true, message: "请输入年龄" }],
},
{
type: FormType.input,
label: "登录账号",
name: "account",
value: "",
rules: [{ required: true, message: "请输入登录账号" }],
},
{
type: FormType.input,
label: "初始密码",
name: "password",
value: "",
rules: [{ required: true, message: "请输入初始密码" }],
},
{
type: FormType.input,
label: "家庭住址",
name: "home_addr",
value: "",
rules: [{ required: true, message: "请输入家庭住址" }],
},
{
type: FormType.input,
label: "身份证",
name: "id_card",
value: "",
rules: [{ required: true, message: "请输入身份证" }],
},
{
type: FormType.input,
label: "担任职务",
name: "pos_held",
value: "",
rules: [{ required: true, message: "请输入担任职务" }],
},
{
type: FormType.input,
label: "通讯地址",
name: "mail_addr",
value: "",
rules: [{ required: true, message: "请输入通讯地址" }],
},
{
type: FormType.input,
label: "服役部队",
name: "serv_unit",
value: "",
rules: [{ required: true, message: "请输入服役部队" }],
},
{
type: FormType.input,
label: "贯籍",
name: "porig",
value: "",
rules: [{ required: true, message: "请输入贯籍" }],
},
{
type: FormType.input,
label: "专业特长",
name: "spec",
value: "",
rules: [{ required: true, message: "请输入专业特长" }],
},
{
type: FormType.input,
label: "邮箱",
name: "email",
value: "",
rules: [{ required: true, message: "请输入邮箱" }],
},
{
type: FormType.input,
label: "联系电话",
name: "tel",
value: "",
rules: [{ required: true, message: "请输入联系电话" }],
},
{
type: FormType.input,
label: "民族",
name: "eth",
value: "",
rules: [{ required: true, message: "请输入民族" }],
},
{
type: FormType.radio,
label: "是否党员",
name: "p_member",
value: 1,
radioData: [
{
key: "是",
val: 1,
},
{
key: "否",
val: 2,
},
],
rules: [{ required: true, message: "请输入民族" }],
},
{
type: FormType.radio,
label: "是否退役军人",
name: "vet",
value: 0,
radioData: [
{
key: "是",
val: 1,
},
{
key: "否",
val: 2,
},
],
rules: [{ required: true, message: "请输入退役军人" }],
},
{
type: FormType.textarea,
label: "描述",
name: "remark",
value: "",
},
{
type: FormType.upload,
label: "头像",
name: "headImg",
value: [],
rules: [{ required: true, message: "请上传头像" }],
},
];
export const columns: ColumnsType<UserDataType> = [
{
title: "用户名",
dataIndex: "user_name",
width:150,
fixed:"left"
},
{
title: "性别",
dataIndex: "sex",
width:150,
render: (sex) => <span>{sex === "0" ? "男" : "女"}</span>,
fixed:"left"
},
{
title: "年龄",
width:150,
dataIndex: "age",
},
{
title: "头像",
dataIndex: "head_img",
width:150,
render: (headImg) => <Image src={headImg}></Image>,
},
{
title: "登录账号",
width:150,
dataIndex: "account",
},
{
title: "家庭住址",
width:150,
dataIndex: "home_addr",
},
{
title: "身份证",
width:150,
dataIndex: "id_card",
},
{
title: "担任职务",
width:150,
dataIndex: "pos_held",
},
{
title: "通讯地址",
width:150,
dataIndex: "mail_addr",
},
{
title: "服役部队",
width:150,
dataIndex: "serv_unit",
},
{
title: "贯籍",
width:150,
dataIndex: "porig",
},
{
title: "专业特长",
width:150,
dataIndex: "spec",
},
{
title: "邮箱",
width:150,
dataIndex: "email",
},
{
title: "联系电话",
width:150,
dataIndex: "tel",
},
{
title: "民族",
width:150,
dataIndex: "eth",
},
{
title: "是否党员",
width:150,
dataIndex: "p_member",
},
{
title: "是否退役军人",
width:150,
dataIndex: "vet",
},
{
title: "备注",
width:150,
dataIndex: "remark",
},
];

View File

@ -55,16 +55,27 @@ export const defaultConfig = [
value: "",
rules: [{ required: true, message: "请输入仓库描述" }],
},
{
type: FormType.input,
label: "监控链接",
name: "monitoring_url",
value: "",
},
{
type: FormType.radio,
label: "是否为第三方仓库",
name: "is_other",
value: 1,
radioData: [
{
key: "是",
val: 1,
},
{
key: "否",
val: 2,
},
],
rules: [{ required: true, message: "请选择是否为第三方仓库" }],
},
{
type: FormType.input,
label: "监控链接",
name: "monitoring_url",
value: "",
},
{

View File

@ -16,6 +16,9 @@ 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";
export const homeRouter = [
{
path: "/",
@ -31,6 +34,21 @@ export const homeRouter = [
path: "/admin",
element: <LayOut />,
children: [
{
path: "/admin/orgChart",
index: true,
element: <OrgChart />,
},
{
path: "/admin/poverDetail",
index: true,
element: <PoverDetail />,
},
{
path: "/admin/pover",
index: true,
element: <PoverPage />,
},
{
path: "/admin/user",
index: true,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 142 KiB

View File

@ -1,46 +1,23 @@
import { message } from 'antd/lib';
import WebRTC from 'webrtc';
class WebRtc {
private rtc: WebRTC
private mediaStream: MediaStream | Blob | null = null;
private video: HTMLVideoElement | null = null;
async init() {
this.rtc = new WebRTC({debug: true});
try {
let strem = await navigator.mediaDevices.getUserMedia({ audio: true, video: true })
var localVideo = document.getElementById('localVideo') as HTMLVideoElement;
localVideo.srcObject = strem;
console.log('localVideo', this.rtc?.addStream);
// this.rtc?.addStream(strem);
} catch (error) {
console.log(error);
// message.error(`error ${JSON.stringify(message)}`)
}
let constraints = { audio: false, video: true };
this.video = document.getElementById('rtcVideo') as HTMLVideoElement;
this.mediaStream = await navigator.mediaDevices.getUserMedia(constraints) as MediaStream | Blob
}
calls() {
this.rtc.createOffer()
.then((offer) => {
// ...
})
.catch((error) => {
console.log('Error creating offer: ', error);
});
// 接听呼叫
this.rtc.createAnswer()
.then((answer) => {
// 发送answer信令等操作
// ...
})
.catch((error) => {
console.log('Error creating answer: ', error);
});
if (this.video) {
this.video.srcObject = this.mediaStream;
this.video.autoplay = true;
}
}
close() {
this.rtc.close();
this.video?.pause();
(this.mediaStream as MediaStream)?.getTracks().forEach(track => track.stop());
}
}