supLink云服务

蓝卓supLink移动应用平台软件(简称supLink)在企业内部构建一个移动应用平台,实现与supOS工业操作系统数据的互联互通。做为supOS桌面应用在移动端的延伸和扩展,可以有效地实现工业生产过程的协同办公。无论何时何地,用户可以通过移动终端掌握工厂实时运行过程、生产安全预警、工业视频监控、工艺指标变化趋势、生产报表、工作流和RFID设备盘点等信息,进行任务下达、工作审批和事项跟踪等业务流程处理。

功能特点

  • 移动生产协同,平台提供生产过程的移动化画面监控、视频监控、趋势分析、报警查看与确认、工作流流程发起、待办处理以及已办管理等功能,快速高效地实现工业生产过程的协同办公,并可根据角色设置小程序权限、工作台展示管理。

  • 专业社交服务,通过平台提供的即时沟通、群聊、组织、公告、报警、工作流等功能,满足多组织环境下的消息管理,提供发送和接收文本、语音、图片、视频、文件等格式信息,在企业侧的现场操作内外协同、工作任务沟通等方面提升工作效率。

  • 应用集成管理,支持企业信息个性化设置,支持supOS桌面应用页面移动化展示、页面自适应设置,支持第三方应用接入,支持移动小程序的动态插拔与管理,可根据企业个性化需求实现不同业务域的管理。

  • 移动端多租户管理:根据supOS租户创建,快速同步部署移动端租户。通过移动端租户管理后台管理租户列表,提示租户状态与到期时间,并可自定义租户名称,支持在蓝卓云上开启服务。

import React, { useState, useEffect, useCallback, useRef } from 'react'; import { Empty, message, Select, Input } from 'antd'; import { EditOutlined } from '@ant-design/icons'; import { Button, Dialog, Drawer } from 'tdesign-mobile-react'; import { setNavigationBar } from '@suplink/jssdk'; import { useNavigate } from 'react-router-dom'; import { URLData } from "../../util/deviceOption"; import { postData } from "../../util/requestMethod"; import _ from 'lodash'; import './index.css'; import UserUpdate from './UserUpdate'; const { Option } = Select; const Alarm = () => { const navigate = useNavigate(); const [totalList, setTotalList] = useState([]); const [loading, setLoading] = useState(false); const [loadingMore, setLoadingMore] = useState(false); const [drawerVisible, setDrawerVisible] = useState(false); const [editingUserId, setEditingUserId] = useState(null); const [editingUserData, setEditingUserData] = useState(null); // 查询条件状态 const [usernameInput, setUsernameInput] = useState(''); const [realNameInput, setRealNameInput] = useState(''); const [selectedRole, setSelectedRole] = useState(); const isLoadMoreRef = useRef(false); const searchParamsRef = useRef({}); const totalCountRef = useRef(0); const initializedRef = useRef(false); const isFirstLoadRef = useRef(true); const roleOptions = [ { label: '管理员', value: 'admin' }, { label: '操作员', value: 'operator' }, { label: '查看者', value: 'viewer' } ]; const [pagination, setPagination] = useState({ current: 1, pageSize: 10, hasMore: true }); // 构建查询参数 const buildSearchParams = useCallback(() => { const params = {}; if (usernameInput.trim()) { params.username = usernameInput.trim(); } if (realNameInput.trim()) { params.realName = realNameInput.trim(); } if (selectedRole) { params.role = selectedRole; } return params; }, [usernameInput, realNameInput, selectedRole]); // 查询人员数据 const getAlarmData = useCallback(async (isLoadMore = false, targetPage = null, searchParams = null) => { if ((!isLoadMore && loading) || (isLoadMore && loadingMore)) { return; } if (isLoadMore) { setLoadingMore(true); isLoadMoreRef.current = true; } else { setLoading(true); isLoadMoreRef.current = false; } const targetPageNum = targetPage || (isLoadMore ? pagination.current + 1 : 1); const currentSearchParams = searchParams !== null ? searchParams : buildSearchParams(); const params = { ...currentSearchParams, page: targetPageNum, per_page: pagination.pageSize }; try { const res = await postData(URLData.queryPreson, params); if (res && res.list) { const receivedDataCount = res.list.length; if (isLoadMore) { setTotalList(prevList => [...prevList, ...res.list]); setLoadingMore(false); } else { setTotalList(res.list); setLoading(false); } totalCountRef.current = res.total || 0; let hasMoreData = false; if (res.total !== undefined && res.total !== null) { const loadedCount = isLoadMore ? (totalList.length + receivedDataCount) : receivedDataCount; hasMoreData = loadedCount < res.total; } else { hasMoreData = receivedDataCount >= pagination.pageSize; } setPagination(prev => ({ ...prev, current: targetPageNum, hasMore: hasMoreData })); } else if (Array.isArray(res)) { setTotalList(res); setLoading(false); setLoadingMore(false); setPagination(prev => ({ ...prev, hasMore: false, current: 1 })); } else { setTotalList([]); setLoading(false); setLoadingMore(false); setPagination(prev => ({ ...prev, hasMore: false, current: 1 })); } } catch (error) { console.error('查询数据失败:', error); setLoading(false); setLoadingMore(false); message.error('数据加载失败'); } finally { isLoadMoreRef.current = false; } }, [pagination.pageSize, loading, loadingMore, totalList.length, buildSearchParams]); // 执行查询 const handleSearch = useCallback(() => { const currentSearchParams = buildSearchParams(); searchParamsRef.current = currentSearchParams; setPagination(prev => ({ ...prev, current: 1, hasMore: true })); getAlarmData(false, 1, currentSearchParams); }, [buildSearchParams, getAlarmData]); // 重置查询条件 const handleReset = useCallback(() => { setUsernameInput(''); setRealNameInput(''); setSelectedRole(''); searchParamsRef.current = {}; setPagination(prev => ({ ...prev, current: 1, hasMore: true })); setTimeout(() => { getAlarmData(false, 1, {}); }, 0); }, [getAlarmData]); // 修改用户 const handleEdit = (user) => { console.log('修改用户:', user); setEditingUserId(user.id); setEditingUserData(user); // 传递完整的用户数据 setDrawerVisible(true); }; // 删除用户 const handleDelete = (user) => { const updateData = { 'where': { id: user.id }, 'update': { dr: 1 } }; Dialog.confirm({ title: "确认删除", content: `确定删除用户 "${user.realName || user.username}" ?`, confirmBtn: { content: '确定', theme: 'danger', }, cancelBtn: '取消', onConfirm: async () => { const res = await postData(URLData.updatePerson, { "updateData": updateData }); if (res === '执行成功') { message.success('删除成功'); handleSearch(); } else { message.error('删除失败'); } } }); }; // 新增用户 const handleAdd = () => { navigate(`/useradd`) }; // 初始加载 useEffect(() => { setNavigationBar({ backButton: false, title: "人员管理" }); if (!initializedRef.current) { searchParamsRef.current = {}; getAlarmData(false, 1, {}); initializedRef.current = true; setTimeout(() => { isFirstLoadRef.current = false; }, 1000); } }, []); // 防抖搜索 const debouncedSearchRef = useRef( _.debounce((searchParams) => { if (!isLoadMoreRef.current && !isFirstLoadRef.current) { setPagination(prev => ({ ...prev, current: 1, hasMore: true })); getAlarmData(false, 1, searchParams); } }, 500) ); // 加载更多 const showMore = () => { if (pagination.hasMore && !loadingMore && !loading) { getAlarmData(true, pagination.current + 1, searchParamsRef.current); } } useEffect(() => { if (!isLoadMoreRef.current && initializedRef.current && !isFirstLoadRef.current) { const currentSearchParams = buildSearchParams(); searchParamsRef.current = currentSearchParams; debouncedSearchRef.current(currentSearchParams); } return () => { debouncedSearchRef.current.cancel(); }; }, [usernameInput, realNameInput, selectedRole, buildSearchParams]); // 处理 Drawer 关闭 const handleDrawerClose = () => { setDrawerVisible(false); // 延迟清空状态,确保动画期间组件不卸载 setTimeout(() => { setEditingUserId(null); setEditingUserData(null); }, 300); }; // 处理修改成功 const handleUpdateSuccess = () => { handleDrawerClose(); handleSearch(); // 刷新列表 message.success('用户信息更新成功'); }; // 角色映射 const roleMap = { 'admin': '管理员', 'operator': '操作员', 'viewer': '查看者' }; return ( <div className="user-content-box"> {/* 固定在顶部的查询条件和新增按钮 */} <div className="sticky-header"> <div className="user-add-btn-container"> <Button size="small" variant="outline" onClick={handleAdd} className="user-add-btn">+新增</Button> </div> <div className='ueser-search-form'> <div className='userinfo-select'> <span className='user-search-label'>用户名:</span> <Input value={usernameInput} placeholder="请输入用户名" onChange={(e) => setUsernameInput(e.target.value)} allowClear style={{ width: 260 }} /> </div> <div className='username-select'> <span className='username-search-label'>姓名:</span> <Input value={realNameInput} placeholder="请输入姓名" onChange={(e) => setRealNameInput(e.target.value)} allowClear style={{ width: 260 }} /> </div> <div className='userrole-select'> <span className='userrole-search-label'>所属角色:</span> <Select allowClear showSearch className='userinfo-select-dom' placeholder="请选择角色" value={selectedRole} onChange={setSelectedRole} optionFilterProp="children" filterOption={(input, option) => option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 } > {roleOptions.map((item) => ( <Option key={item.value} value={item.value}>{item.label}</Option> ))} </Select> </div> </div> </div> {/* 用户列表 */} <div className='user-list-box user-card-container'> {loading ? ( <div style={{ textAlign: 'center', padding: '50px' }}>加载中...</div> ) : totalList.length > 0 ? ( <> <div className="user-card-list"> {totalList.map((user, index) => ( <div key={user.id || index} className="user-card"> <div className="user-card-header"> <h3 className="user-card-name"> {user.realName || '-'} <span className={`user-card-role user-role-${user.role}`}> {roleMap[user.role] || user.role} </span> </h3> </div> <div className="user-card-body"> <div className="user-card-info"> <div className="info-item"> <span className="user-info-label">用户名:</span> <span className="user-info-value">{user.username || '-'}</span> </div> <div className="info-item"> <span className="user-info-label">部门:</span> <span className="user-info-value">{user.department || '-'}</span> </div> <div className="info-item"> <span className="user-info-label">手机号:</span> <span className="user-info-value">{user.phone || '-'}</span> </div> <div className="info-item"> <span className="user-info-label">邮箱:</span> <span className="user-info-value">{user.email || '-'}</span> </div> </div> </div> <div className="user-card-actions"> <Button variant="outline" size="small" onClick={() => handleEdit(user)} icon={<EditOutlined />} className="edit-btn" > 修改 </Button> <Button variant="outline" size="small" onClick={() => handleDelete(user)} className="delete-btn" > 删除 </Button> </div> </div> ))} </div> {pagination.hasMore ? ( <div className='load-more' onClick={showMore} style={{ cursor: loadingMore ? 'not-allowed' : 'pointer', opacity: loadingMore ? 0.6 : 1 }} > {loadingMore ? '加载中...' : '加载更多'} </div> ) : ( totalList.length >= pagination.pageSize && <div className='no-more'>--暂无更多数据--</div> )} </> ) : ( <Empty description="暂无数据" image={Empty.PRESENTED_IMAGE_SIMPLE} /> )} </div> {/* Drawer - 修改用户信息 */} <Drawer visible={drawerVisible} onClose={handleDrawerClose} destroyOnClose={true} placement="right" size="100%" header="修改用户信息" > <UserUpdate/> </Drawer> </div> ) }; export default Alarm; 以上代码中在Drawer引入UserUpdate子组件并未展示,应如何解决该问题
11-09
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值