diff --git a/apps/web/src/app/main/sport/context/EditableContext.tsx b/apps/web/src/app/main/sport/context/EditableContext.tsx new file mode 100644 index 0000000..327c96f --- /dev/null +++ b/apps/web/src/app/main/sport/context/EditableContext.tsx @@ -0,0 +1,64 @@ +import React, { useContext, useEffect, useState } from "react"; +import { Form,Input } from "antd"; + + + +// 创建可编辑单元格组件 +export const EditableContext = React.createContext(null); +export const EditableRow = ({ index, ...props }) => { + const [form] = Form.useForm(); + return ( +
+ + + +
+ ); +}; +export const EditableCell = ({ + title, + editable, + children, + dataIndex, + record, + handleSave, + ...restProps + }) => { + const form = useContext(EditableContext); + + useEffect(() => { + if (editable) { + form.setFieldsValue({ [dataIndex]: record[dataIndex] }); + } + }, [form, dataIndex, record, editable]); + + const save = async () => { + try { + const values = await form.validateFields(); + handleSave({ ...record, ...values }); + } catch (errInfo) { + console.log('保存失败:', errInfo); + } + }; + + let childNode = children; + + if (editable) { + childNode = ( + + + + ); + } + + return {childNode}; + }; \ No newline at end of file diff --git a/apps/web/src/app/main/sport/page.tsx b/apps/web/src/app/main/sport/page.tsx new file mode 100644 index 0000000..3d07979 --- /dev/null +++ b/apps/web/src/app/main/sport/page.tsx @@ -0,0 +1,375 @@ +import { Button, Select, Table, Modal, Form, Input, InputNumber } from "antd"; +import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; +import { useEffect, useState, useCallback, useContext } from "react"; +import toast from "react-hot-toast"; +import React from "react"; +import _ from "lodash"; +import { useMainContext } from "../layout/MainProvider"; +import { EditableRow, EditableContext, EditableCell } from '../sport/context/EditableContext'; +export default function SportPage() { + const { form, setVisible, searchValue, setSearchValue } = useMainContext(); + const { editingRecord, setEditingRecord } = useMainContext(); + // 模拟数据,实际使用时应替换为API调用 + const [isLoading, setIsLoading] = useState(false); + const [sportsData, setSportsData] = useState([ + { + id: 1, + name: "张三", + gender: "男", + age: 25, + unit: "信息部", + threeKm: "85", + pullUp: 72, + shuttle: "65", + sitUp: 90, + bodyType: "标准", + totalScore: 85 + }, + { + id: 2, + name: "李四", + gender: "女", + age: 22, + unit: "市场部", + threeKm: "79", + pullUp: 58, + shuttle: "81", + sitUp: 63, + bodyType: "偏瘦", + totalScore: 78 + }, + { + id: 3, + name: "王五", + gender: "男", + age: 28, + unit: "技术部", + threeKm: "92", + pullUp: 85, + shuttle: "77", + sitUp: 88, + bodyType: "标准", + totalScore: 90 + }, + { + id: 4, + name: "赵六", + gender: "女", + age: 24, + unit: "人力资源部", + threeKm: "75", + pullUp: 56, + shuttle: "71", + sitUp: 67, + bodyType: "偏瘦", + totalScore: 75 + }, + { + id: 5, + name: "钱七", + gender: "男", + age: 30, + unit: "财务部", + threeKm: "68", + pullUp: 77, + shuttle: "59", + sitUp: 82, + bodyType: "偏胖", + totalScore: 82 + }, + { + id: 6, + name: "孙八", + gender: "男", + age: 26, + unit: "销售部", + threeKm: "93", + pullUp: 88, + shuttle: "84", + sitUp: 95, + bodyType: "标准", + totalScore: 92 + }, + { + id: 7, + name: "周九", + gender: "女", + age: 23, + unit: "客服部", + threeKm: "73", + pullUp: 60, + shuttle: "65", + sitUp: 75, + bodyType: "标准", + totalScore: 79 + }, + { + id: 8, + name: "吴十", + gender: "男", + age: 32, + unit: "研发部", + threeKm: "82", + pullUp: 70, + shuttle: "68", + sitUp: 79, + bodyType: "偏胖", + totalScore: 80 + }, + { + id: 9, + name: "郑十一", + gender: "女", + age: 27, + unit: "市场营销部", + threeKm: "62", + pullUp: 53, + shuttle: "69", + sitUp: 71, + bodyType: "偏瘦", + totalScore: 76 + }, + { + id: 10, + name: "刘十二", + gender: "男", + age: 29, + unit: "产品部", + threeKm: "87", + pullUp: 82, + shuttle: "78", + sitUp: 86, + bodyType: "标准", + totalScore: 88 + } + ]); + // 新增搜索功能 + const filteredData = sportsData.filter(item => + item.name.toLowerCase().includes(searchValue.toLowerCase()) || + item.unit.toLowerCase().includes(searchValue.toLowerCase()) + ); + const handleNew = () => { + form.resetFields(); + setEditingRecord(null); + setVisible(true); + }; + + // 计算总成绩的函数 + const calculateTotalScore = (record) => { + // 确保所有值都转为数字 + const threeKmScore = parseInt(record.threeKm, 10) || 0; + const pullUpScore = parseInt(record.pullUp, 10) || 0; + const shuttleScore = parseInt(record.shuttle, 10) || 0; + const sitUpScore = parseInt(record.sitUp, 10) || 0; + + // 计算总分 + return threeKmScore + pullUpScore + shuttleScore + sitUpScore; + }; + + // 初始化时计算所有记录的总成绩 + useEffect(() => { + const updatedData = sportsData.map(record => ({ + ...record, + totalScore: calculateTotalScore(record) + })); + setSportsData(updatedData); + }, []); + + const handleSave = (row) => { + const newData = [...sportsData]; + const index = newData.findIndex(item => row.id === item.id); + const item = newData[index]; + + // 创建更新后的记录 + const updatedRecord = { ...item, ...row }; + + // 重新计算总成绩 + updatedRecord.totalScore = calculateTotalScore(updatedRecord); + + // 更新数据 + newData.splice(index, 1, updatedRecord); + setSportsData(newData); + toast.success("保存成功"); + }; + + const columns = [ + { + title: "姓名", + dataIndex: "name", + key: "name", + }, + { + title: "性别", + dataIndex: "gender", + key: "gender", + }, + { + title: "年龄", + dataIndex: "age", + key: "age", + }, + { + title: "单位", + dataIndex: "unit", + key: "unit", + }, + { + title: "三公里", + dataIndex: "threeKm", + key: "threeKm", + editable: true, + }, + { + title: "单杠", + dataIndex: "pullUp", + key: "pullUp", + editable: true, + }, + { + title: "30x2折返跑", + dataIndex: "shuttle", + key: "shuttle", + editable: true, + }, + { + title: "仰卧卷腹", + dataIndex: "sitUp", + key: "sitUp", + editable: true, + }, + { + title: "BMI", + dataIndex: "bodyType", + key: "bodyType", + editable: true, + }, + { + title: "总成绩", + dataIndex: "totalScore", + key: "totalScore", + editable: true, + }, + { + title: "操作", + key: "action", + render: (_, record) => ( +
+ + +
+ ), + } + ]; + + const mergedColumns = columns.map(col => { + if (!col.editable) { + return col; + } + return { + ...col, + onCell: record => ({ + record, + editable: col.editable, + dataIndex: col.dataIndex, + title: col.title, + handleSave, + }), + }; + }); + + useEffect(() => { + if (editingRecord) { + form.setFieldsValue(editingRecord); + } + }, [editingRecord, form]); + + const handleEdit = (record) => { + setEditingRecord(record); + form.setFieldsValue(record); + setVisible(true); + }; + + const handleDelete = (id) => { + Modal.confirm({ + title: '确认删除', + content: '确定要删除该记录吗?', + okText: '确定', + cancelText: '取消', + onOk: async () => { + try { + // 模拟删除操作 + setSportsData(sportsData.filter(item => item.id !== id)); + toast.success("删除成功"); + } catch (error) { + console.error('删除记录时出错:', error); + toast.error("删除失败"); + } + } + }); + }; + + const components = { + body: { + row: EditableRow, + cell: EditableCell, + }, + }; + + return ( +
+
+
+
+
+
成绩总览
+
+ setSearchValue(e.target.value)} + className="pl-10 w-full border" + /> + +
+ +
+ + {isLoading ? ( +
加载中...
+ ) : ( + 'editable-row'} + columns={mergedColumns} + dataSource={filteredData} + tableLayout="fixed" + rowKey="id" + pagination={{ + position: ["bottomCenter"], + className: "flex justify-center mt-4", + pageSize: 10, + }} + /> + )} + + + + + ); +} \ No newline at end of file diff --git a/apps/web/src/app/main/staffpage/page.tsx b/apps/web/src/app/main/staffpage/page.tsx index 6a9eeed..6a7f341 100644 --- a/apps/web/src/app/main/staffpage/page.tsx +++ b/apps/web/src/app/main/staffpage/page.tsx @@ -5,7 +5,6 @@ import _ from "lodash"; import { useMainContext } from "../layout/MainProvider"; import StaffTable from "./stafftable/page"; import StaffModal from "./staffmodal/page"; - export default function StaffMessage() { const {form, formValue, setFormValue, setVisible, setSearchValue, editingRecord} = useMainContext(); useEffect(()=>{ @@ -24,14 +23,12 @@ export default function StaffMessage() { console.log(editingRecord); setVisible(true); }; - const handleSearch = useCallback( _.debounce((value: string) => { setSearchValue(value); }, 500), [] ); - return (
diff --git a/apps/web/src/routes/index.tsx b/apps/web/src/routes/index.tsx index b7cb040..566bb2e 100755 --- a/apps/web/src/routes/index.tsx +++ b/apps/web/src/routes/index.tsx @@ -15,6 +15,7 @@ import Dashboard from "../app/main/home/page"; import WeekPlanPage from "../app/main/plan/weekplan/page"; import AdminLayout from "../components/layout/admin/AdminLayout"; import { adminRoute } from "./admin-route"; +import SportPage from "../app/main/sport/page"; interface CustomIndexRouteObject extends IndexRouteObject { name?: string; breadcrumb?: string; @@ -87,7 +88,7 @@ export const routes: CustomRouteObject[] = [ }, { path:"sportsassessment", - element: + element: } ] }, diff --git a/config/nginx/conf.d/web.conf b/config/nginx/conf.d/web.conf index 2dd9d9e..eb29fb7 100755 --- a/config/nginx/conf.d/web.conf +++ b/config/nginx/conf.d/web.conf @@ -100,7 +100,7 @@ server { # 仅供内部使用 internal; # 代理到认证服务 - proxy_pass http://192.168.252.77:3000/auth/file; + proxy_pass http://192.168.252.77:3001/auth/file; # 请求优化:不传递请求体 proxy_pass_request_body off;