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

View File

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

View File

@ -2,6 +2,7 @@ import { FormInstance } from "antd"
import React from "react" import React from "react"
export enum FormType { export enum FormType {
input = "input", input = "input",
inputNumber = "inputNumber",
select = "select", select = "select",
editor = "editor", editor = "editor",
date = "date", date = "date",
@ -22,6 +23,7 @@ export interface FormDatas {
selectUrl?: string, selectUrl?: string,
selectList?: Array<selectItem> selectList?: Array<selectItem>
checkboxData?: Array<any>, checkboxData?: Array<any>,
radioData?: Array<any>,
rules: Array<rules> 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 { useEffect } from "react";
import { FormType, SimpleFormData } from "./interface"; import { FormType, SimpleFormData } from "./interface";
import { FormSelect } from "./select"; import { FormSelect } from "./select";
@ -43,6 +43,17 @@ const SimpleForm = (props: SimpleFormData) => {
<Input defaultValue={v.value} value={v.value} /> <Input defaultValue={v.value} value={v.value} />
</Form.Item> </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": case "password":
return ( return (
<Form.Item <Form.Item
@ -149,8 +160,9 @@ const SimpleForm = (props: SimpleFormData) => {
rules={v.rules} rules={v.rules}
> >
<Radio.Group> <Radio.Group>
<Radio value={1}></Radio> {v.radioData?.map((item) => (
<Radio value={2}></Radio> <Radio key={item.val} value={item.val}>{item.key}</Radio>
))}
</Radio.Group> </Radio.Group>
</Form.Item> </Form.Item>
); );
@ -173,9 +185,11 @@ const SimpleForm = (props: SimpleFormData) => {
name={v.name} name={v.name}
rules={v.rules} rules={v.rules}
> >
<MapFrom onChange={(m)=>{ <MapFrom
form.setFieldValue(v.name, m); onChange={(m) => {
}}/> form.setFieldValue(v.name, m);
}}
/>
</Form.Item> </Form.Item>
); );
default: default:

View File

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

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

View File

@ -1,83 +1,127 @@
.contents_center { @keyframes scroll {
width: 100%; 0% {
height: 100%; transform: translateX(100%);
overflow: hidden; }
position: relative; 100% {
.map_container_t{ transform: translateX(-100%);
position: absolute; }
height: 80px; }
top: 0; .contents_center {
width: 100%; width: 100%;
background-image: url("../../static/head.png"); height: 100%;
background-repeat: no-repeat; overflow: hidden;
left: 0; position: relative;
right: 0; .map_container_t {
z-index: 1; position: absolute;
display: flex; height: 60px;
align-items: center; top: 0;
.title_img{ width: 100%;
margin-left: 10px; background-image: url("../../static/head.png");
width: 20px; background-repeat: no-repeat;
height: 20px; backdrop-filter: blur(10px);
} left: 0;
.twp{ right: 0;
width: 160px; z-index: 1;
height: 30px; display: flex;
} align-items: center;
>span{ justify-content: space-between;
margin-left: 15px; .map_container_t_l {
margin-right: 15px; display: flex;
color: #fff; align-items: center;
font-size: 38px; flex: 1;
font-weight: normal; .title_img {
line-height: normal; margin-left: 10px;
letter-spacing: 0.1em; width: 20px;
font-variation-settings: "opsz" auto; height: 20px;
color: #FFFFFF; }
text-shadow: 0px 0px 10px #29ECB4; .twp {
} width: 160px;
} height: 30px;
.map_container_l{ }
position: absolute; > span {
left: 0px; margin-left: 15px;
top: 80px; margin-right: 15px;
width: 20%; color: #fff;
bottom: 0px; font-size: 30px;
z-index: 2; font-weight: normal;
opacity: 1; line-height: normal;
background: rgba(37, 52, 70, 0.4); letter-spacing: 0.1em;
backdrop-filter: blur(10px); font-variation-settings: "opsz" auto;
} color: #ffffff;
.map_container_r{ text-shadow: 0px 0px 10px #29ecb4;
position: absolute; }
right: 0px; }
top: 80px;
bottom: 0px; .scr {
width: 20%; flex: 1;
z-index: 2; overflow: hidden;
opacity: 1; .scrolling-text {
background: rgba(37, 52, 70, 0.4); white-space: nowrap;
backdrop-filter: blur(10px); display: block;
} animation: scroll 10s linear infinite;
.map_container_b{ color: #fff;
position: absolute; > span {
bottom: 0px; display: inline-block;
background: rgba(37, 52, 70, 0.4); animation: scrollText 10s linear infinite; /* 动画 */
height: 80px; }
width: 100%; :hover >span{
z-index: 1; animation-play-state: paused;
text-align: center; }
.bottom_content{ }
display: inline-block; }
padding-top: 15px;
>span{ .map_container_t_r {
background: linear-gradient(180deg, rgba(0, 193, 153, 0.1) 0%, rgba(0, 239, 151, 0.8) 100%); flex: 1;
padding: 5px 10px ; text-align: right;
color: #fff; padding-right: 10px;
margin: 0 10px; }
cursor: pointer; }
font-size: 18px; .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 HomeLeft from "@/pages/home/homeLeft/home_left";
import HomeRight from "@/pages/home/homeRigrt/home_right"; import HomeRight from "@/pages/home/homeRigrt/home_right";
import HomeBottom from "@/pages/home/homeBottom/home_bottom"; import HomeBottom from "@/pages/home/homeBottom/home_bottom";
import image1 from "@/static/title_jiantou@1x.png" import image1 from "@/static/title_jiantou@1x.png";
import image2 from "@/static/title_line@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 Home = observer(() => {
const navigate = useNavigate();
return ( return (
<div className="contents_center"> <div className="contents_center">
<div className="map_container_t"> <div className="map_container_t">
<div className="map_container_t_l">
<img className="title_img" src={image1} alt="" /> <img className="title_img" src={image1} alt="" />
<span></span> <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>
<div className="map_container_l"> <div className="map_container_l">
<HomeLeft /> <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 Dispath from "./dispath";
import { Button, Modal } from "antd"; import WhichVideo from "./which_video";
import "./right.less"; import Ec from "./ec";
import { webRTC } from "@/util/webRtc"; import Emr from "./emr";
import "./bot.less";
const HomeBottom = () => { const HomeBottom = () => {
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const openDispatch = () => {
setIsModalOpen(true);
webRTC.init();
};
const handleCancle = () => {
setIsModalOpen(false);
};
const handleSubmit = () => {
setIsModalOpen(false);
};
return ( return (
<div className="bottom_container"> <div className="bottom_container">
<div className="bottom_content"> <div className="bottom_content">
<span onClick={openDispatch}></span> <Dispath />
<span onClick={openDispatch}></span> <Emr />
<span onClick={openDispatch}>线</span> <Ec />
<span onClick={openDispatch}></span> <WhichVideo />
</div> </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> </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 { useEffect, useState } from "react";
import { Modal } from "antd"; import { Modal } from "antd";
import "./left.less"; import "./left.less";
import { useNavigate } from "react-router";
import MapUtl from "@/components/map/mapUtil";
import * as echarts from "echarts"; import * as echarts from "echarts";
import Orgin from "./orgin"; import Orgin from "./orgin";
import Pover from "./pover";
const HomeLeft = () => { const HomeLeft = () => {
const [isModalOpen, setIsModalOpen] = useState<boolean>(false); const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const navigate = useNavigate();
const initChart = () => { const initChart = () => {
var myChart = echarts.init(document.getElementById("xunlian")); var myChart = echarts.init(document.getElementById("xunlian"));
var option = { var option = {
@ -55,46 +54,11 @@ const HomeLeft = () => {
option && myChart.setOption(option); 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(() => { useEffect(() => {
initChart(); initChart();
}, []); }, []);
useEffect(() => { // const openDispatch = () => {
initChart2();
}, []);
const openDispatch = () => {
// 位置移动 // 位置移动
// MapUtl.makerList[0].setPosition([103.55, 30.342]); // MapUtl.makerList[0].setPosition([103.55, 30.342]);
// var m = MapUtl.amap; // var m = MapUtl.amap;
@ -104,26 +68,23 @@ const HomeLeft = () => {
// anchor: new m.Pixel(12, 32), // 图标锚点 // anchor: new m.Pixel(12, 32), // 图标锚点
// }); // });
// MapUtl.makerList[0].setIcon(newIcon); // MapUtl.makerList[0].setIcon(newIcon);
}; // };
const jumpToUser = () => {
navigate("admin/user");
};
return ( return (
<div className="left_container"> <div className="left_container">
<div onClick={openDispatch} className="org"> <div className="org">
<div className="org_head"> <div className="org_head">
<p></p> <p></p>
</div> </div>
<Orgin /> <Orgin />
</div> </div>
<div onClick={jumpToUser} className="org"> <div className="org">
<div className="org_head"> <div className="org_head">
<p></p> <p></p>
</div> </div>
<div style={{ width: "100%", height: "100%" }} id="orgin1"></div> <Pover />
</div> </div>
<div onClick={openDispatch} className="org"> <div className="org">
<div className="org_head"> <div className="org_head">
<p></p> <p></p>
</div> </div>

View File

@ -36,6 +36,11 @@
>img{ >img{
width: 100%; 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 origin from "@/static/orgin.png";
import origin2 from "@/static/orgin2.png"; import origin2 from "@/static/orgin2.png";
import { Modal } from "antd";
import { useState } from "react";
const Orgin = () => { const Orgin = () => {
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const showModal = () => {
setIsModalOpen(true);
};
const handleCancel = () => {
setIsModalOpen(false);
};
return ( return (
<div className="orgin-content"> <>
<div className="po"> <div className="orgin-content" onClick={showModal}>
<span>234</span> <div className="po">
<img src={origin} alt="" /> <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>
<div className="po"> <Modal
<span>238</span> title={"组织架构"}
<img src={origin2} alt="" /> className="owner_model"
</div> width={"80%"}
</div> 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 "./right.less";
import Wz from "./wz";
const HomeRight = () => { const HomeRight = () => {
return ( return (
<div className="right_container"> <div className="right_container">
@ -6,6 +7,7 @@ const HomeRight = () => {
<div className="org_head"> <div className="org_head">
<p></p> <p></p>
</div> </div>
<Wz />
</div> </div>
<div className="org"> <div className="org">
<div className="org_head"> <div className="org_head">

View File

@ -1,13 +1,13 @@
.right_container { .right_container {
width: 100%; width: 100%;
color: #fff; color: #fff;
height: 100%; height: 100%;
width: 100%; display: flex;
color: #fff; flex-direction: column;
height: auto;
.org { .org {
flex:1;
width: 100%; width: 100%;
min-height: 200px; overflow-y: hidden;
text-align: center; text-align: center;
.org_head { .org_head {
width: 100%; 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> = [ export const leaveColumns: ColumnsType<UserDataType> = [
{ {
title: "请假人", title: "请假人",
@ -59,6 +60,16 @@ export const defaultConfig = [
value: "", value: "",
rules: [{ required: true, message: "请输入驳回原因!" }], 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 { Store } from "antd/lib/form/interface";
import SimpleForm from "@/components/form/simple_form"; import SimpleForm from "@/components/form/simple_form";
import React from "react"; import React from "react";
import { columns, defaultConfig } from "./levcat_column"; import { columns, defaultCatConfig } from "./levcat_column";
const LeaveCat = (props: Store) => { const LeaveCat = (props: Store) => {
const { leaveCategoryStore } = props; const { leaveCategoryStore } = props;
@ -15,7 +15,7 @@ const LeaveCat = (props: Store) => {
const [record, setRecord] = useState<any>(null); const [record, setRecord] = useState<any>(null);
useEffect(() => { useEffect(() => {
leaveCategoryStore.getlist(); leaveCategoryStore.getlist();
setProjectConfig(defaultConfig); setProjectConfig(defaultCatConfig);
}, [leaveCategoryStore]); }, [leaveCategoryStore]);
const column_widget = (any, record) => { const column_widget = (any, record) => {
return ( return (
@ -69,7 +69,7 @@ const LeaveCat = (props: Store) => {
type="default" type="default"
onClick={() => { onClick={() => {
setRecord(null); setRecord(null);
setProjectConfig(defaultConfig); setProjectConfig(defaultCatConfig);
setIsModalOpen(true); setIsModalOpen(true);
}} }}
> >

View File

@ -26,6 +26,10 @@ export const columns: ColumnsType<UserDataType> = [
title: "所属仓库", title: "所属仓库",
dataIndex: "stash_name", dataIndex: "stash_name",
}, },
{
title: "数量",
dataIndex: "num",
},
]; ];
export const defaultConfig = [ export const defaultConfig = [
@ -52,6 +56,13 @@ export const defaultConfig = [
value: "", value: "",
rules: [{ required: true, message: "请输入物资描述!" }], rules: [{ required: true, message: "请输入物资描述!" }],
}, },
{
type: FormType.inputNumber,
label: "物资数量",
name: "num",
value: "",
rules: [{ required: true, message: "请输入物资数量!" }],
},
{ {
type: FormType.date, type: FormType.date,
label: "过期时间", 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"; import dayjs from "dayjs";
const { Option } = Select; const { Option } = Select;
const Trainings = (props: Store) => { const Trainings = (props: Store) => {
const { trainingStore, trainingCatStore } = props; const { trainingStore, trainingCatStore } = props;
const [isModalOpen, setIsModalOpen] = useState<boolean>(false); const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
@ -92,6 +90,7 @@ const Trainings = (props: Store) => {
let data = { let data = {
...values, ...values,
score: Number(values.score), score: Number(values.score),
count: Number(values.count),
}; };
if (!tagId) { if (!tagId) {
trainingStore.add(data); trainingStore.add(data);
@ -146,6 +145,13 @@ const Trainings = (props: Store) => {
value: "", value: "",
rules: [{ required: true, message: "请输入任务积分设置!" }], rules: [{ required: true, message: "请输入任务积分设置!" }],
}, },
{
type: FormType.input,
label: "训练次数",
name: "count",
value: 0,
rules: [{ required: true, message: "请输入训练次数!" }],
},
{ {
type: FormType.cehckboxGroup, type: FormType.cehckboxGroup,
label: "参与人员选择", 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 { inject, observer } from "mobx-react";
import type { ColumnsType } from "antd/es/table";
import BTable from "@/components/b_table"; import BTable from "@/components/b_table";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { UserDataType } from "@/model/userModel";
import { Store } from "antd/lib/form/interface"; import { Store } from "antd/lib/form/interface";
import "./user.less";
import SimpleForm from "@/components/form/simple_form"; import SimpleForm from "@/components/form/simple_form";
import React from "react"; import React from "react";
import { FormType } from "@/components/form/interface"; import { columns, defaultConfig } from "./user_config";
import "./user.less";
const User = (props: Store) => { const User = (props: Store) => {
const { usrStore } = props; const { usrStore } = props;
@ -17,69 +15,33 @@ const User = (props: Store) => {
const formRef = React.useRef<FormInstance>(null); const formRef = React.useRef<FormInstance>(null);
const [record, setRecord] = useState<any>(null); const [record, setRecord] = useState<any>(null);
const [userId, setId] = useState<Number | null>(null); const [userId, setId] = useState<Number | null>(null);
const columns: ColumnsType<UserDataType> = [ const actionWidget = (any, record) => {
{ return (
title: "用户名", <Space wrap>
dataIndex: "user_name", <Button
}, type="dashed"
{ size="small"
title: "年龄", onClick={() => {
dataIndex: "age", edit(record);
}, }}
{ >
title: "性别",
dataIndex: "sex", </Button>
render: (sex) => <span>{sex === "0" ? "男" : "女"}</span>,
}, <Button
{ type="dashed"
title: "头像", danger
dataIndex: "head_img", size="small"
render: (headImg) => <Image src={headImg}></Image>, onClick={() => {
}, usrStore.deleteItem(record.id);
{ }}
title: "职位", >
dataIndex: "position",
}, </Button>
{ </Space>
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>
<Button
type="dashed"
danger
size="small"
onClick={() => {
usrStore.deleteItem(record.id);
}}
>
</Button>
</Space>
</Space>
</div>
),
},
];
const edit = (record) => { const edit = (record) => {
record = { record = {
...record, ...record,
@ -105,61 +67,35 @@ const User = (props: Store) => {
useEffect(() => { useEffect(() => {
usrStore.getlist(); usrStore.getlist();
}, [usrStore]); }, [usrStore]);
const defaultConfig = [
{ const addHandler = () => {
type: FormType.input, setProjectConfig(defaultConfig);
label: "用户名", setId(null);
name: "acount", setIsModalOpen(true);
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 onFinishFailed = () => {}; const onFinishFailed = () => {};
return ( return (
<div className="contentBox"> <div className="contentBox">
<Space direction="vertical" size="middle" style={{ display: "flex" }}> <Space direction="vertical" size="middle" style={{ display: "flex" }}>
<Space direction="horizontal" size={"middle"}> <Space direction="horizontal" size={"middle"}>
<Button <Button type="default" onClick={() => addHandler()}>
type="default"
onClick={() => {
setProjectConfig(defaultConfig);
setId(null);
setIsModalOpen(true);
}}
>
</Button> </Button>
</Space> </Space>
<BTable
<BTable store={usrStore} columns={columns} dataSource={usrStore.list} /> store={usrStore}
columns={[
...columns,
{
title: "操作",
dataIndex: "id",
fixed: 'right',
ellipsis: { showTitle: false },
render: (any, record)=>actionWidget(any, record),
},
]}
dataSource={usrStore.list}
/>
<Modal <Modal
title={!userId ? "添加用户" : "编辑用户"} title={!userId ? "添加用户" : "编辑用户"}
width={800} 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: "", value: "",
rules: [{ required: true, message: "请输入仓库描述" }], rules: [{ required: true, message: "请输入仓库描述" }],
}, },
{
type: FormType.input,
label: "监控链接",
name: "monitoring_url",
value: "",
},
{ {
type: FormType.radio, type: FormType.radio,
label: "是否为第三方仓库", label: "是否为第三方仓库",
name: "is_other", name: "is_other",
value: 1,
radioData: [
{
key: "是",
val: 1,
},
{
key: "否",
val: 2,
},
],
rules: [{ required: true, message: "请选择是否为第三方仓库" }],
},
{
type: FormType.input,
label: "监控链接",
name: "monitoring_url",
value: "", value: "",
}, },
{ {

View File

@ -16,6 +16,9 @@ import WhseMgmtRoute from "@/pages/whseMgmt/whseMgmt_route";
import Emergency from "@/pages/emergency"; import Emergency from "@/pages/emergency";
import Patrol from "@/pages/patrol"; import Patrol from "@/pages/patrol";
import Training from "@/pages/training"; import Training from "@/pages/training";
import OrgChart from "@/pages/OrgChart";
import PoverPage from "@/pages/poverPage";
import PoverDetail from "@/pages/poverDetail";
export const homeRouter = [ export const homeRouter = [
{ {
path: "/", path: "/",
@ -31,6 +34,21 @@ export const homeRouter = [
path: "/admin", path: "/admin",
element: <LayOut />, element: <LayOut />,
children: [ 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", path: "/admin/user",
index: true, 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 { class WebRtc {
private rtc: WebRTC private mediaStream: MediaStream | Blob | null = null;
private video: HTMLVideoElement | null = null;
async init() { async init() {
this.rtc = new WebRTC({debug: true}); let constraints = { audio: false, video: true };
try { this.video = document.getElementById('rtcVideo') as HTMLVideoElement;
let strem = await navigator.mediaDevices.getUserMedia({ audio: true, video: true }) this.mediaStream = await navigator.mediaDevices.getUserMedia(constraints) as MediaStream | Blob
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)}`)
}
} }
calls() { calls() {
this.rtc.createOffer() if (this.video) {
.then((offer) => { this.video.srcObject = this.mediaStream;
// ... this.video.autoplay = true;
}) }
.catch((error) => {
console.log('Error creating offer: ', error);
});
// 接听呼叫
this.rtc.createAnswer()
.then((answer) => {
// 发送answer信令等操作
// ...
})
.catch((error) => {
console.log('Error creating answer: ', error);
});
} }
close() { close() {
this.rtc.close(); this.video?.pause();
(this.mediaStream as MediaStream)?.getTracks().forEach(track => track.stop());
} }
} }