diff --git a/src/assets/css/pages/system/index.scss b/src/assets/css/pages/system/index.scss index f0a072a..1cf03d1 100644 --- a/src/assets/css/pages/system/index.scss +++ b/src/assets/css/pages/system/index.scss @@ -11,6 +11,7 @@ width: 200px; height: 360px; flex: 0 0 auto; + overflow: hidden !important; cursor: pointer; .common-card { diff --git a/src/assets/css/pages/system/tools/code.scss b/src/assets/css/pages/system/tools/code.scss new file mode 100644 index 0000000..69ffc34 --- /dev/null +++ b/src/assets/css/pages/system/tools/code.scss @@ -0,0 +1,20 @@ +[data-component=system-tools-code] { + padding: 30px; + + .card-box { + width: 100%; + height: 100%; + } + + .draggable-content { + position: fixed; + inset-inline-end: 48px; + inset-block-end: 48px; + + > * { + position: relative; + inset-inline-end: 0; + inset-block-end: 0; + } + } +} \ No newline at end of file diff --git a/src/assets/css/pages/system/tools/execute.scss b/src/assets/css/pages/system/tools/execute.scss new file mode 100644 index 0000000..c831c75 --- /dev/null +++ b/src/assets/css/pages/system/tools/execute.scss @@ -0,0 +1,8 @@ +[data-component=system-tools-execute] { + padding: 30px; + + .card-box { + width: 100%; + height: 100%; + } +} \ No newline at end of file diff --git a/src/assets/css/pages/tools/index.scss b/src/assets/css/pages/tools/index.scss index 8f0bcab..9ee637a 100644 --- a/src/assets/css/pages/tools/index.scss +++ b/src/assets/css/pages/tools/index.scss @@ -28,7 +28,7 @@ position: absolute; top: 10px; left: 10px; - width: 6em; + width: 8em; } .upgrade-bt { diff --git a/src/assets/svg/execute.svg b/src/assets/svg/execute.svg new file mode 100644 index 0000000..9cbf71a --- /dev/null +++ b/src/assets/svg/execute.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/constants/common.constants.ts b/src/constants/common.constants.ts index aada843..29052c6 100644 --- a/src/constants/common.constants.ts +++ b/src/constants/common.constants.ts @@ -80,7 +80,8 @@ export const TOOL_ILLEGAL_VERSION = 40050 export const TOOL_UNDER_REVIEW = 40051 export const TOOL_NOT_UNDER_REVIEW = 40052 export const TOOL_HAS_UNPUBLISHED_VERSION = 40053 -export const TOOL_HAS_BEEN_PUBLISHED = 40054 +export const TOOL_HAS_NOT_BEEN_PUBLISHED = 40054 +export const TOOL_HAS_BEEN_PUBLISHED = 40055 export const TOOL_SUBMIT_ERROR = 40060 export const TOOL_CANCEL_ERROR = 40061 diff --git a/src/global.d.ts b/src/global.d.ts index 1602afc..25f9d67 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -89,6 +89,23 @@ interface LoginParam { captchaCode: string } +interface UserWithInfoVo { + id: string + username: string + verified: boolean + locking: boolean + expiration: string + credentialsExpiration: string + enable: boolean + currentLoginTime: string + currentLoginIp: string + lastLoginTime: string + lastLoginIp: string + createTime: string + updateTime: string + userInfo: UserInfoVo +} + interface UserWithPowerInfoVo { id: string username: string @@ -532,7 +549,7 @@ interface ToolVo { icon: string description: string base: ToolBaseVo - author: UserInfoVo + author: UserWithInfoVo ver: string keywords: string[] categories: ToolCategoryVo[] @@ -570,3 +587,9 @@ interface ToolUpdateParam { categories?: string[] source?: string } + +interface ToolManagementGetParam extends PageParam { + searchType?: string + searchValue?: string + searchRegex?: boolean +} diff --git a/src/pages/System/Tools/Code.tsx b/src/pages/System/Tools/Code.tsx new file mode 100644 index 0000000..0f881b5 --- /dev/null +++ b/src/pages/System/Tools/Code.tsx @@ -0,0 +1,91 @@ +import { r_sys_tool_get_one } from '@/services/system.tsx' +import '@/assets/css/pages/system/tools/code.scss' +import { DATABASE_NO_RECORD_FOUND, DATABASE_SELECT_SUCCESS } from '@/constants/common.constants.ts' +import Playground from '@/components/Playground' +import { useState } from 'react' +import { IFiles } from '@/components/Playground/shared.ts' +import { base64ToFiles } from '@/components/Playground/files.ts' +import FitFullscreen from '@/components/common/FitFullscreen.tsx' +import Card from '@/components/common/Card.tsx' +import Draggable from 'react-draggable' +import Icon from '@ant-design/icons' + +const Code = () => { + const navigate = useNavigate() + const { id } = useParams() + const [loading, setLoading] = useState(false) + const [files, setFiles] = useState({}) + const [selectedFileName, setSelectedFileName] = useState('') + + const handleOnRunTool = () => { + navigate(`/system/tools/execute/${id}`) + } + + const render = (toolVo: ToolVo) => { + try { + setFiles(base64ToFiles(toolVo.source.data!)) + setSelectedFileName(toolVo.entryPoint) + } catch (e) { + void message.error('载入工具失败') + } + } + + const getTool = () => { + if (loading) { + return + } + setLoading(true) + void message.loading({ content: '加载中……', key: 'LOADING', duration: 0 }) + + void r_sys_tool_get_one(id!) + .then((res) => { + const response = res.data + switch (response.code) { + case DATABASE_SELECT_SUCCESS: + render(response.data!) + break + case DATABASE_NO_RECORD_FOUND: + void message.error('未找到指定工具') + setTimeout(() => { + navigate(-1) + }, 3000) + break + default: + void message.error('获取工具信息失败,请稍后重试') + } + }) + .finally(() => { + setLoading(false) + message.destroy('LOADING') + }) + } + + useEffect(() => { + getTool() + }, []) + + return ( + + + + + + +
+ } + onClick={handleOnRunTool} + /> +
+
+
+ ) +} + +export default Code diff --git a/src/pages/System/Tools/Execute.tsx b/src/pages/System/Tools/Execute.tsx new file mode 100644 index 0000000..1b13b1b --- /dev/null +++ b/src/pages/System/Tools/Execute.tsx @@ -0,0 +1,80 @@ +import FitFullscreen from '@/components/common/FitFullscreen.tsx' +import '@/assets/css/pages/system/tools/execute.scss' +import { base64ToFiles, base64ToStr, IMPORT_MAP_FILE_NAME } from '@/components/Playground/files.ts' +import { IImportMap } from '@/components/Playground/shared.ts' +import compiler from '@/components/Playground/compiler.ts' +import { DATABASE_NO_RECORD_FOUND, DATABASE_SELECT_SUCCESS } from '@/constants/common.constants.ts' +import { r_sys_tool_get_one } from '@/services/system.tsx' +import Card from '@/components/common/Card.tsx' +import Playground from '@/components/Playground' + +const Execute = () => { + const navigate = useNavigate() + const { id } = useParams() + const [loading, setLoading] = useState(false) + const [compiledCode, setCompiledCode] = useState('') + + const render = (toolVo: ToolVo) => { + try { + const baseDist = base64ToStr(toolVo.base.dist.data!) + const files = base64ToFiles(toolVo.source.data!) + const importMap = JSON.parse(files[IMPORT_MAP_FILE_NAME].value) as IImportMap + + void compiler + .compile(files, importMap, toolVo.entryPoint) + .then((result) => { + const output = result.outputFiles[0].text + setCompiledCode(`${output}\n${baseDist}`) + }) + .catch((reason) => { + void message.error(`编译失败:${reason}`) + }) + } catch (e) { + void message.error('载入工具失败') + } + } + + const getTool = () => { + if (loading) { + return + } + setLoading(true) + void message.loading({ content: '加载中……', key: 'LOADING', duration: 0 }) + + void r_sys_tool_get_one(id!) + .then((res) => { + const response = res.data + switch (response.code) { + case DATABASE_SELECT_SUCCESS: + render(response.data!) + break + case DATABASE_NO_RECORD_FOUND: + void message.error('未找到指定工具') + setTimeout(() => { + navigate(-1) + }, 3000) + break + default: + void message.error('获取工具信息失败,请稍后重试') + } + }) + .finally(() => { + setLoading(false) + message.destroy('LOADING') + }) + } + + useEffect(() => { + getTool() + }, []) + + return ( + + + + + + ) +} + +export default Execute diff --git a/src/pages/System/Tools/index.tsx b/src/pages/System/Tools/index.tsx index 44880c7..30a1112 100644 --- a/src/pages/System/Tools/index.tsx +++ b/src/pages/System/Tools/index.tsx @@ -1,14 +1,485 @@ -import Playground from '@/components/Playground' -import templates from '@/components/Playground/templates' +import { ChangeEvent, KeyboardEvent } from 'react' +import { + r_sys_tool_delete, + r_sys_tool_get, + r_sys_tool_off_shelve, + r_sys_tool_pass, + r_sys_tool_reject +} from '@/services/system' +import { + COLOR_BACKGROUND, + COLOR_ERROR_SECONDARY, + COLOR_PRODUCTION, + DATABASE_DELETE_SUCCESS, + DATABASE_SELECT_SUCCESS, + DATABASE_UPDATE_SUCCESS, + TOOL_NOT_UNDER_REVIEW +} from '@/constants/common.constants.ts' +import FlexBox from '@/components/common/FlexBox.tsx' +import Card from '@/components/common/Card.tsx' +import FitFullscreen from '@/components/common/FitFullscreen.tsx' +import HideScrollbar from '@/components/common/HideScrollbar.tsx' +import Icon from '@ant-design/icons' const Tools = () => { - const template = templates['base'] + const navigate = useNavigate() + const [modal, contextHolder] = AntdModal.useModal() + const [tableParams, setTableParams] = useState({ + pagination: { + current: 1, + pageSize: 20, + position: ['bottomCenter'], + showTotal: (total, range) => + `第 ${ + range[0] === range[1] ? `${range[0]}` : `${range[0]}~${range[1]}` + } 项 共 ${total} 项` + } + }) + const [toolData, setToolData] = useState([]) + const [isLoading, setIsLoading] = useState(false) + const [searchType, setSearchType] = useState('ALL') + const [searchValue, setSearchValue] = useState('') + const [isUseRegex, setIsUseRegex] = useState(false) + const [isRegexLegal, setIsRegexLegal] = useState(true) + const [form] = AntdForm.useForm<{ pass: boolean }>() + + const dataColumns: _ColumnsType = [ + { + dataIndex: 'icon', + title: '图标', + render: (value) => ( + }} + src={`data:image/svg+xml;base64,${value}`} + alt={'Avatar'} + /> + } + style={{ background: COLOR_BACKGROUND }} + /> + ), + width: '0', + align: 'center' + }, + { + title: '名称', + render: (_, record) => ( + {record.name} + ) + }, + { dataIndex: 'toolId', title: '工具 ID' }, + { dataIndex: 'ver', title: '版本' }, + { + title: '作者', + render: (_, record) => `${record.author.userInfo.nickname}(${record.author.username})` + }, + { + dataIndex: 'keywords', + title: '关键词', + render: (value: string[]) => value.map((item) => {item}) + }, + { + dataIndex: 'categories', + title: '类别', + render: (value: { name: string }[]) => + value.map((item) => {item.name}) + }, + { + dataIndex: 'review', + title: '状态', + width: '4em', + render: (value) => { + switch (value) { + case 'NONE': + return 编码 + case 'PROCESSING': + return 审核 + case 'REJECT': + return 驳回 + case 'PASS': + return 通过 + } + }, + filters: [ + { text: '编码', value: 'NONE' }, + { text: '审核', value: 'PROCESSING' }, + { text: '驳回', value: 'REJECT' }, + { text: '通过', value: 'PASS' } + ] + }, + { + title: '操作', + width: '12em', + align: 'center', + render: (_, record) => ( + <> + + + 查看 + + {record.review === 'PROCESSING' && ( + + 审核 + + )} + {record.review === 'PASS' && ( + + 下架 + + )} + + 删除 + + {' '} + + ) + } + ] + + const handleOnTableChange = ( + pagination: _TablePaginationConfig, + filters: Record, + sorter: _SorterResult | _SorterResult[] + ) => { + pagination = { ...tableParams.pagination, ...pagination } + if (Array.isArray(sorter)) { + setTableParams({ + pagination, + filters, + sortField: sorter.map((value) => value.field).join(',') + }) + } else { + setTableParams({ + pagination, + filters, + sortField: sorter.field, + sortOrder: sorter.order + }) + } + + if (pagination.pageSize !== tableParams.pagination?.pageSize) { + setToolData([]) + } + } + + const handleOnViewBtnClick = (value: ToolVo) => { + return () => { + navigate(`/system/tools/code/${value.id}`) + } + } + + const handleOnReviewBtnClick = (value: ToolVo) => { + return () => { + form.setFieldValue('pass', undefined) + void modal.confirm({ + title: '审核', + content: ( + + + + 通过 + 驳回 + + + + ), + onOk: () => + form.validateFields().then(() => { + return new Promise((resolve) => { + switch (form.getFieldValue('pass')) { + case true: + void r_sys_tool_pass(value.id).then((res) => { + const response = res.data + switch (response.code) { + case DATABASE_UPDATE_SUCCESS: + void message.success('更新成功') + getTool() + resolve() + break + case TOOL_NOT_UNDER_REVIEW: + void message.warning('工具处于非审核状态') + resolve() + break + default: + void message.error('更新失败,请稍后重试') + resolve() + } + }) + break + default: + void r_sys_tool_reject(value.id).then((res) => { + const response = res.data + switch (response.code) { + case DATABASE_UPDATE_SUCCESS: + void message.success('更新成功') + resolve() + break + case TOOL_NOT_UNDER_REVIEW: + void message.warning('工具处于非审核状态') + resolve() + break + default: + void message.error('更新失败,请稍后重试') + resolve() + } + }) + } + }) + }) + }) + } + } + + const handleOnOffShelveBtnClick = (value: ToolVo) => { + return () => { + modal + .confirm({ + title: '确定下架', + content: `确定下架工具 ${value.author.username}:${value.toolId}:${value.ver} 吗?` + }) + .then( + (confirmed) => { + if (confirmed) { + setIsLoading(true) + + void r_sys_tool_off_shelve(value.id) + .then((res) => { + const response = res.data + if (response.code === DATABASE_UPDATE_SUCCESS) { + void message.success('下架成功') + setTimeout(() => { + getTool() + }) + } else { + void message.error('下架失败,请稍后重试') + } + }) + .finally(() => { + setIsLoading(false) + }) + } + }, + () => {} + ) + } + } + + const handleOnDeleteBtnClick = (value: ToolVo) => { + return () => { + modal + .confirm({ + title: '确定删除', + content: `确定删除工具 ${value.author.username}:${value.toolId}:${value.ver} 吗?` + }) + .then( + (confirmed) => { + if (confirmed) { + setIsLoading(true) + + void r_sys_tool_delete(value.id) + .then((res) => { + const response = res.data + if (response.code === DATABASE_DELETE_SUCCESS) { + void message.success('删除成功') + setTimeout(() => { + getTool() + }) + } else { + void message.error('删除失败,请稍后重试') + } + }) + .finally(() => { + setIsLoading(false) + }) + } + }, + () => {} + ) + } + } + + const handleOnSearchValueChange = (e: ChangeEvent) => { + setSearchValue(e.target.value) + + if (isUseRegex) { + try { + RegExp(e.target.value) + setIsRegexLegal(!(e.target.value.includes('{}') || e.target.value.includes('[]'))) + } catch (e) { + setIsRegexLegal(false) + } + } else { + setIsRegexLegal(true) + } + } + + const handleOnSearchValueKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Enter') { + getTool() + } + } + + const handleOnSearchTypeChange = (value: string) => { + setSearchType(value) + } + + const handleOnUseRegexChange = (e: _CheckboxChangeEvent) => { + setIsUseRegex(e.target.checked) + if (e.target.checked) { + try { + RegExp(searchValue) + setIsRegexLegal(!(searchValue.includes('{}') || searchValue.includes('[]'))) + } catch (e) { + setIsRegexLegal(false) + } + } else { + setIsRegexLegal(true) + } + } + + const handleOnQueryBtnClick = () => { + getTool() + } + + const getTool = () => { + if (isLoading) { + return + } + + if (!isRegexLegal) { + void message.error('非法正则表达式') + return + } + setIsLoading(true) + + void r_sys_tool_get({ + currentPage: tableParams.pagination?.current, + pageSize: tableParams.pagination?.pageSize, + sortField: + tableParams.sortField && tableParams.sortOrder + ? (tableParams.sortField as string) + : undefined, + sortOrder: + tableParams.sortField && tableParams.sortOrder ? tableParams.sortOrder : undefined, + searchType, + searchValue: searchValue.trim().length ? searchValue : undefined, + searchRegex: isUseRegex ? isUseRegex : undefined, + ...tableParams.filters + }) + .then((res) => { + const response = res.data + switch (response.code) { + case DATABASE_SELECT_SUCCESS: + setToolData(response.data!.records) + setTableParams({ + ...tableParams, + pagination: { + ...tableParams.pagination, + total: response.data!.total + } + }) + break + default: + void message.error('获取失败,请稍后重试') + } + }) + .finally(() => { + setIsLoading(false) + }) + } + + useEffect(() => { + getTool() + }, [ + JSON.stringify(tableParams.filters), + JSON.stringify(tableParams.sortField), + JSON.stringify(tableParams.sortOrder), + JSON.stringify(tableParams.pagination?.pageSize), + JSON.stringify(tableParams.pagination?.current) + ]) + + const toolbar = ( + + + + } + suffix={ + <> + {!isRegexLegal && ( + 非法表达式 + )} + + .* + + + } + allowClear + value={searchValue} + onChange={handleOnSearchValueChange} + onKeyDown={handleOnSearchValueKeyDown} + status={isRegexLegal ? undefined : 'error'} + /> + + + + 查询 + + + + ) + + const table = ( + + + + ) + return ( - + <> + + + + {toolbar} + {table} + + + + {contextHolder} + ) } diff --git a/src/pages/System/User.tsx b/src/pages/System/User.tsx index 6836d4f..af9ee4b 100644 --- a/src/pages/System/User.tsx +++ b/src/pages/System/User.tsx @@ -77,7 +77,7 @@ const User = () => { const dataColumns: _ColumnsType = [ { dataIndex: 'username', - title: '用户', + title: '用户名', render: (value, record) => {value}, width: '0' }, @@ -249,7 +249,7 @@ const User = () => { } if (pagination.pageSize !== tableParams.pagination?.pageSize) { - setGroupData([]) + setUserData([]) } } @@ -584,7 +584,7 @@ const User = () => { } } - const handleOnSearchNameKeyDown = (e: KeyboardEvent) => { + const handleOnSearchValueKeyDown = (e: KeyboardEvent) => { if (e.key === 'Enter') { getUser() } @@ -936,7 +936,7 @@ const User = () => { allowClear value={searchValue} onChange={handleOnSearchValueChange} - onKeyDown={handleOnSearchNameKeyDown} + onKeyDown={handleOnSearchValueKeyDown} status={isRegexLegal ? undefined : 'error'} /> diff --git a/src/pages/SystemFramework.tsx b/src/pages/SystemFramework.tsx index f0e616c..1200286 100644 --- a/src/pages/SystemFramework.tsx +++ b/src/pages/SystemFramework.tsx @@ -25,7 +25,7 @@ const SystemFramework = () => { > {route.children?.map( (subRoute) => - subRoute && + subRoute.menu && subRoute.name && ( { void message.success( `创建工具 ${response.data!.name}<${response.data!.toolId}>:${response.data!.ver} 成功` ) - navigate(`/view/!/${response.data!.toolId}/${response.data!.ver}`) + navigate(`/edit/${response.data!.toolId}`) break case DATABASE_DUPLICATE_KEY: void message.warning('已存在相同 ID 的应用') diff --git a/src/pages/Tools/Edit.tsx b/src/pages/Tools/Edit.tsx index f6079f8..01d63d4 100644 --- a/src/pages/Tools/Edit.tsx +++ b/src/pages/Tools/Edit.tsx @@ -96,11 +96,15 @@ const Edit = () => { break case TOOL_UNDER_REVIEW: void message.error('保存失败:工具审核中') - navigate('/') + setTimeout(() => { + navigate(-1) + }, 3000) break case TOOL_HAS_BEEN_PUBLISHED: void message.error('保存失败:工具已发布') - navigate('/') + setTimeout(() => { + navigate(-1) + }, 3000) break default: void message.error('保存失败,请稍后重试') @@ -158,11 +162,15 @@ const Edit = () => { break case TOOL_UNDER_REVIEW: void message.error('保存失败:工具审核中') - navigate('/') + setTimeout(() => { + navigate(-1) + }, 3000) break case TOOL_HAS_BEEN_PUBLISHED: void message.error('保存失败:工具已发布') - navigate('/') + setTimeout(() => { + navigate(-1) + }, 3000) break default: void message.error('保存失败,请稍后重试') @@ -215,16 +223,22 @@ const Edit = () => { break case 'PROCESSING': void message.warning('工具审核中,请勿修改') - navigate('/') + setTimeout(() => { + navigate(-1) + }, 3000) break default: void message.warning('请先创建新版本后编辑工具') - navigate('/') + setTimeout(() => { + navigate(-1) + }, 3000) } break case DATABASE_NO_RECORD_FOUND: void message.error('未找到指定工具') - navigate('/') + setTimeout(() => { + navigate(-1) + }, 3000) break default: void message.error('获取工具信息失败,请稍后重试') diff --git a/src/pages/Tools/View.tsx b/src/pages/Tools/View.tsx index 7d1ae1e..7f15644 100644 --- a/src/pages/Tools/View.tsx +++ b/src/pages/Tools/View.tsx @@ -51,7 +51,9 @@ const View = () => { break case DATABASE_NO_RECORD_FOUND: void message.error('未找到指定工具') - navigate('/') + setTimeout(() => { + navigate(-1) + }, 3000) break default: void message.error('获取工具信息失败,请稍后重试') @@ -65,7 +67,9 @@ const View = () => { useEffect(() => { if (username === '!' && !getLoginStatus()) { - navigate('/') + setTimeout(() => { + navigate(-1) + }, 3000) return } if (username !== '!' && ver) { diff --git a/src/pages/Tools/index.tsx b/src/pages/Tools/index.tsx index f392793..c00eea4 100644 --- a/src/pages/Tools/index.tsx +++ b/src/pages/Tools/index.tsx @@ -284,9 +284,7 @@ const Tools = () => { switch (response.code) { case DATABASE_UPDATE_SUCCESS: void message.success('创建新版本成功') - navigate( - `/view/!/${response.data!.toolId}/${response.data!.ver}` - ) + navigate(`/edit/${response.data!.toolId}`) resolve() break case TOOL_ILLEGAL_VERSION: diff --git a/src/router/system.tsx b/src/router/system.tsx index 58158e1..b4ded5f 100644 --- a/src/router/system.tsx +++ b/src/router/system.tsx @@ -49,6 +49,20 @@ const system: RouteJsonObject[] = [ menu: true, autoHide: true }, + { + path: 'code/:id', + absolutePath: '/system/tools/code', + id: 'system-tools-code', + component: lazy(() => import('@/pages/System/Tools/Code')), + name: '查看工具' + }, + { + path: 'execute/:id', + absolutePath: '/system/tools/execute', + id: 'system-tools-execute', + component: lazy(() => import('@/pages/System/Tools/Execute')), + name: '运行工具' + }, { path: 'template', absolutePath: '/system/tools/template', diff --git a/src/services/system.tsx b/src/services/system.tsx index f26efad..db0cf72 100644 --- a/src/services/system.tsx +++ b/src/services/system.tsx @@ -19,7 +19,8 @@ import { URL_SYS_SETTINGS_SENSITIVE, URL_SYS_TOOL_CATEGORY, URL_SYS_TOOL_BASE, - URL_SYS_TOOL_TEMPLATE + URL_SYS_TOOL_TEMPLATE, + URL_SYS_TOOL } from '@/constants/urls.constants' import request from '@/services/index' @@ -154,3 +155,16 @@ export const r_sys_tool_template_update = (param: ToolTemplateAddEditParam) => export const r_sys_tool_template_delete = (id: string) => request.delete(`${URL_SYS_TOOL_TEMPLATE}/${id}`) + +export const r_sys_tool_get = (param: ToolManagementGetParam) => + request.get>(URL_SYS_TOOL, param) + +export const r_sys_tool_get_one = (id: string) => request.get(`${URL_SYS_TOOL}/${id}`) + +export const r_sys_tool_pass = (id: string) => request.post(`${URL_SYS_TOOL}/${id}`) + +export const r_sys_tool_reject = (id: string) => request.put(`${URL_SYS_TOOL}/${id}`) + +export const r_sys_tool_off_shelve = (id: string) => request.patch(`${URL_SYS_TOOL}/${id}`) + +export const r_sys_tool_delete = (id: string) => request.delete(`${URL_SYS_TOOL}/${id}`)