diff --git a/README.md b/README.md index 88ab3e2..3708155 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,6 @@ To learn React, check out the [React documentation](https://reactjs.org/). 2、武装力量 根据队伍统计 3、年度训练 按照年度统计类别,次数 (任务发布时,可选择多个类别) - 4、物资管理 5、档案管理 diff --git a/src/App.tsx b/src/App.tsx index cd0815b..d41109d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,21 @@ import { Outlet } from "react-router"; import MyComponent from "./components/errorComp"; +import MapUtl from "./components/map/mapUtil"; +const { socket } = require("./util/socket"); +socket.init(); +socket.onmessage((e) => { + const data = JSON.parse(e.data); + // if (data.type === "heartbeat") { + // MapUtl.makerList[0].setPosition([103.55, 30.342]); + // var m = MapUtl.amap; + // var newIcon = new m.Icon({ + // image: "//a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png", //Icon 的图像 + // size: new m.Size(25, 34), // 图标大小 + // anchor: new m.Pixel(12, 32), // 图标锚点 + // }); + // MapUtl.makerList[0].setIcon(newIcon); + // } +}); const App = () => { return ( <> diff --git a/src/components/layout/layout.tsx b/src/components/layout/layout.tsx index a5fe1a7..6b90ae6 100644 --- a/src/components/layout/layout.tsx +++ b/src/components/layout/layout.tsx @@ -11,54 +11,80 @@ const LayOut = (props: Store) => { const { usrStore } = props; const nav = useNavigate(); const location = useLocation(); - + useEffect(() => { if (usrStore.isNeedLogin) { nav("/login"); } - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, [usrStore.isNeedLogin]); const items = [ { key: "/admin/user", label: `用户管理`, - }, - { - key: "/admin/dep", - label: `部门管理`, + children: [ + { + key: "/admin/dep", + label: `部门管理`, + }, + { + key: "/admin/user", + label: `用户管理`, + }, + { + key: "/admin/teamMgmt", + label: `队伍属性管理`, + }, + { + key: "/admin/persMgmt", + label: `个人身份管理`, + }, + ], }, { key: "/admin/archives", label: `档案管理`, }, { - key: "/admin/whse/whseMgmt", - label: `仓库管理`, - }, - { - key: "/admin/materialMgmt", + key: "/admin/material", label: `物资管理`, + children: [ + { + key: "/admin/whse/whseMgmt", + label: `仓库管理`, + }, + { + key: "/admin/materialMgmt", + label: `物资管理`, + }, + ], }, { key: "/admin/leaveApproval", label: `请假审批`, }, { - key: "/admin/politicalStudy", - label: `政治学习`, + key: "/admin/political", + label: `政治法规`, + children: [ + { + key: "/admin/politicalStudy", + label: `政治学习`, + }, + { + key: `/admin/polRegulations`, + label: `政治法规管理`, + }, + ], }, { - key: `/admin/polRegulations`, - label: `政治法规管理`, - }, - - { - key: "/admin/teamMgmt", - label: `队伍属性管理`, - }, - { - key: "/admin/persMgmt", - label: `个人身份管理`, + key: "/admin/task", + label: `任务管理`, + children: [ + { label: "处突任务", key: "/admin/emergency" }, + { label: "巡逻任务", key: "/admin/patrol" }, + { label: "训练任务", key: "/admin/training" }, + ], }, ]; return ( @@ -72,7 +98,7 @@ const LayOut = (props: Store) => { display: "flex", alignItems: "center", padding: "0 10px", - boxSizing: "border-box" + boxSizing: "border-box", }} > { -// const { folderStore,archivesStore } = props; -// const [isModalOpen, setIsModalOpen] = useState(false); -// const [isModalOpenArchives, setIsModalOpenArchives] = -// useState(false); - -// const [projectConfig, setProjectConfig] = useState([]); -// const formRef = React.useRef(null); -// const [tagId, setId] = useState(null); -// const [folderList, setfolderList] = useState(null); // 仓库列表 -// const onFinish = (values: any) => { -// let data = values; -// if (!tagId) { -// folderStore.add(data); -// } else { -// folderStore.putItem(tagId, data); -// } -// setIsModalOpen(false); -// }; -// useEffect(() => { -// folderStore.getlist().then(()=>{ -// setfolderList(folderStore.list); -// }); - -// }, [folderStore]); - -// // 添加事件 -// const addHandler = () => { -// setProjectConfig(folderConfig); -// setIsModalOpen(true); -// }; - -// // 取消 -// const cancelHandler = () => { -// setId(null); -// setIsModalOpen(false); -// }; - -// const cancelHandlerArch = () => { -// setIsModalOpenArchives(false); -// }; - -// // 文件夹点击 -// const folderHandle = () => { -// setIsModalOpenArchives(true); -// }; -// const onFinishFailed = () => {}; -// return ( -//
-// -// -// -// -// column_widget(any, record), -// }, -// ]} -// dataSource={archivesStore.list} -// /> -// cancelHandlerArch} -// onCancel={cancelHandlerArch} -// > -// -// formRef.current?.resetFields()} -// onOk={() => formRef.current?.submit()} -// onCancel={cancelHandler} -// > -// {}} -// formName="card_basic" -// colProps={12} -// span={6} -// subBtnName="提交" -// formDatas={projectConfig} -// onFinish={onFinish} -// initialValues={true} -// onFinishFailed={onFinishFailed} -// > -// -// -// -// -// -// -//
-// ); -// }; - -// export default inject(...["archivesStore", "folderStore"])( -// observer(Archive) -// ); - - import { Button, Space, Modal, FormInstance, Select } from "antd"; import { inject, observer } from "mobx-react"; import BTable from "@/components/b_table"; diff --git a/src/pages/archives/archivesCat_clumn.tsx b/src/pages/archives/archivesCat_clumn.tsx index f52a4b6..f9e86d4 100644 --- a/src/pages/archives/archivesCat_clumn.tsx +++ b/src/pages/archives/archivesCat_clumn.tsx @@ -24,14 +24,14 @@ export const defaultConfig = [ { type: FormType.input, label: "档案名称", - name: "archives_name", + name: "category_name", value: "", rules: [{ required: true, message: "请输入分类名称!" }], }, { type: FormType.input, label: "档案描述", - name: "archives_desc", + name: "category_desc", value: "", }, { diff --git a/src/pages/home/home.less b/src/pages/home/home.less index 684b6ed..e90e9a7 100644 --- a/src/pages/home/home.less +++ b/src/pages/home/home.less @@ -41,10 +41,9 @@ position: absolute; left: 0px; top: 80px; - bottom: 10px; - width: 15%; - bottom: 80px; - z-index: 1; + width: 20%; + bottom: 0px; + z-index: 2; opacity: 1; background: rgba(37, 52, 70, 0.4); backdrop-filter: blur(10px); @@ -53,21 +52,19 @@ position: absolute; right: 0px; top: 80px; - bottom: 80px; - width: 15%; - z-index: 1; + 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; - right: 0px; bottom: 0px; background: rgba(37, 52, 70, 0.4); height: 80px; width: 100%; - left: 0; z-index: 1; text-align: center; .bottom_content{ diff --git a/src/pages/home/homeLeft/home_left.tsx b/src/pages/home/homeLeft/home_left.tsx index 7db6377..d7f895f 100644 --- a/src/pages/home/homeLeft/home_left.tsx +++ b/src/pages/home/homeLeft/home_left.tsx @@ -1,21 +1,109 @@ -import { useState } from "react"; +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"; const HomeLeft = () => { const [isModalOpen, setIsModalOpen] = useState(false); const navigate = useNavigate(); + const initChart = () => { + var myChart = echarts.init(document.getElementById("xunlian")); + var option = { + xAxis: { + type: "category", + data: ["应急抢险", "消防灭火", "水上救援", "民兵训练", "维稳处突"], + axisLabel: { + show: true, + interval: 0, + rotate: 30, + }, + }, + grid: { + top: "10%", + bottom: "45%", + right: "5%", + }, + yAxis: { + type: "value", + splitLine: { + show: false, // 去除网格线 + }, + }, + series: [ + { + data: [10, 15, 27, 10, 18], + type: "line", + smooth: true, + areaStyle: { + opacity: 0.1, + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: "rgb(128, 255, 165)", + }, + { + offset: 1, + color: "rgb(1, 191, 236)", + }, + ]), + }, + }, + ], + }; + 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 = () => { // 位置移动 - MapUtl.makerList[0].setPosition([103.55, 30.342]); - var m = MapUtl.amap; - var newIcon = new m.Icon({ - image: "//a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png", //Icon 的图像 - size: new m.Size(25, 34), // 图标大小 - anchor: new m.Pixel(12, 32), // 图标锚点 - }); - MapUtl.makerList[0].setIcon(newIcon); + // MapUtl.makerList[0].setPosition([103.55, 30.342]); + // var m = MapUtl.amap; + // var newIcon = new m.Icon({ + // image: "//a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png", //Icon 的图像 + // size: new m.Size(25, 34), // 图标大小 + // anchor: new m.Pixel(12, 32), // 图标锚点 + // }); + // MapUtl.makerList[0].setIcon(newIcon); }; const jumpToUser = () => { navigate("admin/user"); @@ -27,16 +115,19 @@ const HomeLeft = () => {

组织架构

+

武装力量

+

年度训练

+
span{ + position: absolute; + left: 0; + right: 0; + } + >img{ + width: 100%; + } + } + } } } \ No newline at end of file diff --git a/src/pages/home/homeLeft/orgin.tsx b/src/pages/home/homeLeft/orgin.tsx new file mode 100644 index 0000000..5707e8f --- /dev/null +++ b/src/pages/home/homeLeft/orgin.tsx @@ -0,0 +1,18 @@ +import origin from "@/static/orgin.png"; +import origin2 from "@/static/orgin2.png"; +const Orgin = () => { + return ( +
+
+ 234 + +
+
+ 238 + +
+
+ ); +}; + +export default Orgin; diff --git a/src/pages/leaveApproval/index.tsx b/src/pages/leaveApproval/index.tsx index a63572e..63c2d41 100644 --- a/src/pages/leaveApproval/index.tsx +++ b/src/pages/leaveApproval/index.tsx @@ -1,7 +1,23 @@ +import { Tabs, TabsProps } from "antd"; +import Leave from "./level"; +import LeaveCat from "./levelCat"; + const LeaveApproval = () => { + const items: TabsProps["items"] = [ + { + key: "1", + label: "请假分类管理", + children: , + }, + { + key: "2", + label: "请假管理", + children: , + }, + ]; return ( <> -

leaveApproval

+ ); }; diff --git a/src/pages/leaveApproval/levcat_column.tsx b/src/pages/leaveApproval/levcat_column.tsx new file mode 100644 index 0000000..ebab0f7 --- /dev/null +++ b/src/pages/leaveApproval/levcat_column.tsx @@ -0,0 +1,64 @@ +import { FormType } from "@/components/form/interface"; +import { UserDataType } from "@/model/userModel"; +import { ColumnsType } from "antd/lib/table"; +export const columns: ColumnsType = [ + { + title: "分类名称", + dataIndex: "name", + }, +]; + +export const leaveColumns: ColumnsType = [ + { + title: "请假人", + dataIndex: "user_name", + }, + { + title: "请假开始时间", + dataIndex: "leave_start_time", + }, + { + title: "请假结束时间", + dataIndex: "leave_end_time", + }, + { + title: "请假备注", + dataIndex: "leave_remark", + }, + { + title: "驳回原因", + dataIndex: "reject", + }, + { + title: "审批人", + dataIndex: "audit_name", + }, + { + title: "假期类别", + dataIndex: "name", + }, + { + title: "审核状态", + dataIndex: "status", + render(value, record, index) { + return record.status === 1 + ? "已通过" + : record.status === 2 + ? "已驳回" + : "待审批"; + }, + }, +]; + +export const defaultConfig = [ + + { + type: FormType.input, + label: "驳回原因", + name: "reject", + value: "", + rules: [{ required: true, message: "请输入驳回原因!" }], + }, + +]; + diff --git a/src/pages/leaveApproval/level.tsx b/src/pages/leaveApproval/level.tsx new file mode 100644 index 0000000..3914f02 --- /dev/null +++ b/src/pages/leaveApproval/level.tsx @@ -0,0 +1,106 @@ +import BTable from "@/components/b_table"; +import { inject, observer } from "mobx-react"; +import { Store } from "antd/lib/form/interface"; +import { Button, FormInstance, Modal, Space } from "antd"; +import { defaultConfig, leaveColumns } from "./levcat_column"; +import { useEffect, useState } from "react"; +import SimpleForm from "@/components/form/simple_form"; +import React from "react"; +const Leave = (props: Store) => { + const { leaveStore } = props; + const formRef = React.useRef(null); + const [record, setRecord] = useState(null); + const [isModalOpen, setIsModalOpen] = useState(false); + const [projectConfig, setProjectConfig] = useState([]); + useEffect(() => { + leaveStore.getlist(); + setProjectConfig(defaultConfig); + }, [leaveStore]); + const onFinish = (values: any) => { + let data = { + ...values, + status: 2, + }; + leaveStore.access(record.id, data); + setIsModalOpen(false); + }; + const onFinishFailed = () => {}; + const edit = (record) => { + setIsModalOpen(true); + setRecord(record); + }; + const access = (record) => { + leaveStore.access(record.id, { status: 1 }); + }; + const column_widget = (any, record) => { + if (record.status===0){ + return ( + + + + + ); + } + return
; + + }; + return ( + <> + column_widget(any, record) + }, + ]} + dataSource={leaveStore.list} + /> + formRef.current?.resetFields()} + onOk={() => formRef.current?.submit()} + onCancel={() => { + setIsModalOpen(false); + }} + > + + + + ); +}; + +// export default Leave; +export default inject("leaveStore")(observer(Leave)); diff --git a/src/pages/leaveApproval/levelCat.tsx b/src/pages/leaveApproval/levelCat.tsx new file mode 100644 index 0000000..adba966 --- /dev/null +++ b/src/pages/leaveApproval/levelCat.tsx @@ -0,0 +1,127 @@ +import { Button, Space, Modal, FormInstance } from "antd"; +import { inject, observer } from "mobx-react"; +import BTable from "@/components/b_table"; +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"; + +const LeaveCat = (props: Store) => { + const { leaveCategoryStore } = props; + const [isModalOpen, setIsModalOpen] = useState(false); + const [projectConfig, setProjectConfig] = useState([]); + const formRef = React.useRef(null); + const [record, setRecord] = useState(null); + useEffect(() => { + leaveCategoryStore.getlist(); + setProjectConfig(defaultConfig); + }, [leaveCategoryStore]); + const column_widget = (any, record) => { + return ( + + + + + + ); + }; + const edit = (record) => { + setIsModalOpen(true); + setRecord(record); + }; + const onFinish = (values: any) => { + let data = { + ...values, + pid:values.pid??0 + }; + if (!record?.id) { + leaveCategoryStore.add(data); + } else { + leaveCategoryStore.putItem(record.id, data); + } + setIsModalOpen(false); + }; + + const onFinishFailed = () => {}; + return ( +
+ + + + + column_widget(any, record), + }, + ]} + dataSource={leaveCategoryStore.list} + /> + formRef.current?.resetFields()} + onOk={() => formRef.current?.submit()} + onCancel={() => { + setIsModalOpen(false); + }} + > + { + if (record?.id) { + formRef.current?.setFieldsValue(record); + } else { + formRef.current?.setFieldsValue(null); + } + }} + formName="card_basic" + colProps={25} + subBtnName="提交" + formDatas={projectConfig} + onFinish={onFinish} + initialValues={true} + onFinishFailed={onFinishFailed} + /> + + +
+ ); +}; + +export default inject("leaveCategoryStore")(observer(LeaveCat)); diff --git a/src/static/orgin.png b/src/static/orgin.png new file mode 100644 index 0000000..20653f8 Binary files /dev/null and b/src/static/orgin.png differ diff --git a/src/static/orgin2.png b/src/static/orgin2.png new file mode 100644 index 0000000..955f03a Binary files /dev/null and b/src/static/orgin2.png differ diff --git a/src/store/index.ts b/src/store/index.ts index a005b8f..0a1c2e0 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -13,6 +13,8 @@ import { materialCatStore } from './materialCat'; import { materialStore } from './materialStore'; import { regulationsCatStore } from './regulationsCat'; import { regulationsStore } from './regulations'; +import { leaveCategoryStore } from './leave_cat'; +import { leaveStore } from './leave'; const store = { usrStore, @@ -29,7 +31,9 @@ const store = { materialCatStore, materialStore, regulationsCatStore, - regulationsStore + regulationsStore, + leaveCategoryStore, + leaveStore }; export default store; \ No newline at end of file diff --git a/src/store/leave.ts b/src/store/leave.ts new file mode 100644 index 0000000..5e92804 --- /dev/null +++ b/src/store/leave.ts @@ -0,0 +1,28 @@ +import { action, makeObservable } from "mobx"; +// 档案分类 +import BaseStore from "./baseStore"; +import { TagDataType } from "@/model/userModel"; +import baseHttp from "@/service/base"; + + +class LeaveConfig { + static LIST: string = "leave/list" + static ADD: string = "leave" + static DELETE: string = "leave" + static EDIT: string = "leave" + static ACCESS: string = "leave/access" +} +class LeaveStore extends BaseStore { + constructor() { + super(LeaveConfig) + makeObservable(this, { + access: action + }) + } + async access(id: number, param: any) { + await baseHttp.put(LeaveConfig.ACCESS + "/" + id, param) + this.getlist() + } +} +export const leaveStore = new LeaveStore() + diff --git a/src/store/leave_cat.ts b/src/store/leave_cat.ts new file mode 100644 index 0000000..b42fbcb --- /dev/null +++ b/src/store/leave_cat.ts @@ -0,0 +1,20 @@ +import { makeObservable } from "mobx"; +// 档案分类 +import BaseStore from "./baseStore"; +import { TagDataType } from "@/model/userModel"; + + +class LeaveCategoryConfig { + static LIST: string = "leave/category/list" + static ADD: string = "leave/category" + static DELETE: string = "leave/category" + static EDIT: string = "leave/category" +} +class LeaveCategoryStore extends BaseStore { + constructor() { + super(LeaveCategoryConfig) + makeObservable(this, {}) + } +} +export const leaveCategoryStore = new LeaveCategoryStore() + diff --git a/src/util/socket.ts b/src/util/socket.ts new file mode 100644 index 0000000..2d4ac45 --- /dev/null +++ b/src/util/socket.ts @@ -0,0 +1,38 @@ +class Socket { + static socketUrl = "ws://localhost:12214/ws"; + static ws: WebSocket; + init() { + try { + Socket.ws = new WebSocket(Socket.socketUrl); + this.heartbeat(); + } catch (error) { + console.log(error); + } + } + send(data: any) { + Socket.ws.send(data); + } + onmessage(callback: any) { + Socket.ws.onmessage = callback; + } + onclose(callback: any) { + Socket.ws.onclose = callback; + } + onopen(callback: any) { + Socket.ws.onopen = callback; + } + onerror(callback: any) { + Socket.ws.onerror = callback; + } + close() { + Socket.ws.close(); + } + // 心跳 + heartbeat() { + setInterval(() => { + Socket.ws.send(`{"type":"heartbeat"}`); + }, 1000*60); + } +} + +export const socket = new Socket(); \ No newline at end of file